Am I correct in thinking that the goodness of Cloud Endpoints comes with the following limitations:
The REST Api cannot be deployed to a custom domain (it'll remain on appspot.com).
The only authentication supported is OAuth against Google accounts.
Corollary: it isn't currently possible to create a user login/session-tracking mechanism that is Google-accounts-agnostic (e.g., with email as username and a password).
Is there any plan to do away with these limitations and if so, what is the ETA?
Taking these item by item:
Currently, yes this is still the case. Keep in mind, our initial release is targeted at a same-party use-case, where the domain you're serving from basically doesn't matter (it's not user/developer-facing). If you want to use your API to drive a website, you can use your custom domain to have your user-facing content, and still make requests to your appspot domain using CORS. If you're building a mobile app, no one sees the domain at all.
Built-in support (i.e. using the User object) is limited to Google accounts, but you're free to build your own authentication scheme by checking the OAuth headers (or email/password if you must...)
(From the comments, regarding GA status). Endpoints is now GA.
(From the comments, regarding public APIs). Your APIs must be public, but you can limit the clients that can make requests. If you want to make a secret API, i.e. the existence of the API must itself be protected, that's not currently supported. I'd be curious to hear how popular a request this is, but I suspect it's not a blocker for most people.
Related
I am planning on hosting my REST API in a VM in a VNET where the only point of entry is via Azure API Management.
I have multiple back ends so the API Management will route to a different backend base url depending on the group the user is in and the backend will also return different data depending on the user making the call.
Since the Azure API Management can handle authorisation, JWT validation and setting headers etc what type of authorisation code should I put in my REST API application?
Should I try to validate the JWT again in my Java code or just parse the headers?
i.e. is it safe to code it as a public API and trust that the headers have been set correctly by API Management?
Or should I make a call to Azure Active Directory from the Spring controller every time to validate that the user does actually exist in the specified group and that the group specified is the one expected for this backend?
If so, how would I do that from Java and how would I inject an offline version when running locally?
Since your API will be inside a VNET it'll be protected as it is. But, there is really no reason to just have it open. The more layers of protection you can add the better your chances to whistand a potential attack.
So see whatever is most convenient to you. You can rely on APIM doing user authentication and authorization and avoid doing that in your backend API. But it would be a good idea to check if call made to your backend API is coming from APIM, and you can do that by sending credentials from APIM. The best option here would be client certificates: https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-mutual-certificates
But you can also send basic credentials: https://learn.microsoft.com/en-us/azure/api-management/api-management-authentication-policies#Basic
Background
I believe the recommended way to access Google services from Android is to use the Google APIs Client Library for Java (for some services play services is recommeneded too).
If you want to access your user's account, you use oauth2 to authenticate the user, but things seem less clear if you want to access your own services (eg. I want to access Google Cloud Storage belonging to my app engine project).
The problem with service accounts
What I see a lot of here is using service accounts, and I've used them server-side and found them to be a comparatively simple solution, but this requires you to deploy your private key so I don't think this could be right for public Android apps.
The solution: Public API access
If you go to the 'credentials' page of the cloud console:
https://console.developers.google.com/project/[your_project]/apiui/credential
it seems pretty clear that they expect you to use a 'public API access key' for the situation I'm describing. It appears that this is not OAUTH based.
I assume that I will still use the type 'GoogleCredential' for this, but in the documentation for the credential builder I don't see how to do this. The set client functions appear to relate to the oauth2 access (which uses client ID/secret).
The Question
How do I use the 'public API access' key to access Google services from an Android app.
Or, if I'm wrong about service accounts - and they really are the recommended solution, then please show me some evidence of this because it certainly apppears to me that they are not the right solution for publicly distributed apps.
The good news is that it's very much easier. You can either use a Service Account (ie. a brand new account dedicated to your app) or a regular account.
For a service account you embed the key in your app, for a regular account you embed a refresh token in your app. In both cases, be aware of the security risk and use the minimal scope necessary.
You can get a refresh token without writing any code by following the steps in How do I authorise an app (web or installed) without user intervention? (canonical ?)
I have read a lot of about the way to provide acces to a REST API and I still cannot come with a decision what to use.
In my case I am writing a REST API that will be used by the users of the mobile application(android&iOS), thus I do not provide or require access from third parties and this makes me think that I don't have to use OAuth.
However I have considerations about how to provide access of one user's account from multiple devices and how to provide offline access.
Another consideration I have is how should I restrict the API access, for example if using API Tokens what are the best practices for expiration and renewal of the tokens?
You have several topics in your question:
What are the benefits of OAuth2 for an internal API exposed on the Internet?
How should I manage tokens?
How can a user gain access via multiple devices?
How can a user have offline access?
I discuss these questions below.
Oauth2
OAuth2 offers a standardized protocol for several authentication schemes of varying complexity. One of the most complex use cases is the 'Authorization Code Grant' flow which allows a resource owner (user) to grant specific access to a client application via an intermediary, the Authorization server. This is what happens when you 'login using google'. The advantage of using OAuth2 over a homebrew solution is that the protocol is clear to all parties and less likely to contain fundamental flaws. A drawback can be that the protocol is not that flexible so some custom scenario's might be hard to support within the boundaries of OAuth2. If you don't have the immediate need for any of the typical OAuth2 scenario's (or a stakeholder demanding use of OAuth2) then I suggest not starting off with it, but to implement a simple token scheme yourself.
Managing tokens
The most common way to manage API access is by using tokens. A token is generated when the user logs in, typically with username and password over HTTPS. The token is persisted on the server and must be supplied by the app in each request. This is similar to the session ID used in web applications which is automatically generated and handled in-memory by the application container on the server and passed via a cookie or request parameter. An API token is typically handled by the security layer of the application itself, persisted in the database and passed via the 'Authorization' header.
A token should have an expiration date. One should decide on the best interval for this and whether token renewal is automatic (each time the user accesses the API) or explicit (force the user to re-enter credentials after expiration). This depends on the type of application and the level of security required. Tokens can also be revoked manually on the server.
Multiple devices
Each token can be associated with a specific user and device to allow access on multiple devices. This means each device must be uniquely identified, typically with the IMEI code. This makes it easy to revoke all tokens for a specific device or user at once.
Offline access
The typical way to offer offline access is to cache relevant data on the device. For example the Google Maps app allows you to make specific regions of the map available offline. To avoid (too) stale data you could keep track of the token's expiration date and invalidate the cached data after this date. An issue to be aware of is the handling of offline edits by the user. These edits have to be processed when the device comes online again. When simultaneous edits on the same data are encountered a strategy is needed to resolve the conflict, e.g.:
one edit overrides the other depending on the type of edit or the role of the user
the last edit is ignored or offered for resolution to the last editor
some types of edits might be 'merged' automatically
etc.
Another nice and simple strategy is to disallow all edits whilst offline.
There are 2 things you want to protect / authenticate
That the client app is authorized to use the service
That the user is authorized to access personal data
App authentication
A mobile application is an untrusted client. Even if you gave nobody access to the app source you must expect that any kind of authorization secret or mechanism is unsafe and can come from a hacked app or other malicious tool that emulates the behaviour of your apps.
For authenticating the app, all you can do is to have a client id, but not a client secret. E.g.
http://service.com/rest?client_id=android
Reply method(String client_id) {
if (!client_id in ["andoid", "ios"])
return Unauthorized();
}
You can change that schema to something a little harder to guess but anything you do boils down to the same security level.
User authentication
Protecting user data is crucial and luckily possible. The key difference is that the secret is not statically hardcoded into the app, it is only known to the user.
One "easy" way to authenticate users is to use other accounts they have. Schemas like http://openid.net/connect/faq/ allow you to do exactly that.
You basically delegate the authentication to some other service. and get a (per service) unique user id which you can use in your code as key to all user data. An attacker can not forge this since your server can authenticate that the token is valid by asking another service. Looks roughly like
http://service.com/rest?client_id=android&user_token=aasjkbn9nah9z23&user_auth_service=facebook
Reply method(String client_id, user_token, user_auth_service) {
if (!client_id in ["andoid", "ios"])
return Unauthorized();
authenticated_user_id = user_auth_service.getUserIdOrFail(user_token);
accessDatabase(authenticated_user_id);
}
An attacker can still use your service from some evil app but there is no way to access accounts he has no access to anyways.
And if you hardcode access tokens into the app, you better don't expire them or make sure to handle that case specifically in the app somehow. There are always users with outdated app versions.
I have two Java wepapps potentially on different domains/servers using Spring Security for authentication. The first is handling authentication locally storing users in the application database. For the second, I would like to authenticate users using the same users accounts than the first webapp with single sign on (if a user is authenticated in the first webapp, it shouldn't have to enter his info again in the second).
I identified three potential ways to do this but it doesn't seem very straightforward:
Shared cookies: Using a shared session cookie and the same database for the two applications. It seem relatively easy to do but the two webapps need to be on the same domain which isn't necessarily the case for my applications.
Directory service: Using a central directory service (LDAP) which would be used by the two webapps to handle authentication. It seem pretty heavy to implement and the users can't be stored in the first webapp database anymore. The existing users accounts would need to be migrated into the LDAP and it would not be possible to create new users using the first webapp.
OAuth: It seem to be be possible to make the first webapp handle external authentications requests by providing an OAuth api (like Google sign on kind of service). That would allow the second webapp to use this api to authenticate the users, but I'm not sure that the signin process would be totally transparent to handle single sign on. It doesn't seem very easy to implement either, as it would necessitate the development of a complete OAuth api in the first webapp.
I also looked at this service https://auth0.com that seem to provide an authentication api that can be interfaced with an external database, but I'm not sure that it can be interfaced with Spring Security and it also mandate the use of an online solution which isn't ideal. I'm not sure that it would handle single sign on either, only shared accounts.
Is there any other way to handle this use case that would be more straightforward?
CAS is a good candidate indeed as a SSO system for your need and it has several CAS clients for Spring Security. You can try for free a CAS server v4.0 at CAS in the cloud: http://www.casinthecloud.com...
As you mentioned, a shared cookie won't work across domains.
LDAP would give you shared credentials (single name/pw works for both systems), but not single sign on, and you notice you'll have provisioning issues.
Not knowing anything about Spring Security, odds are high you won't find a painless solution to this. Integrating SSO is fraught with workflow issues (user provisioning, password recovery, user profile maintenance, etc.)
We had a classic DB managed authentication scheme. Later, when we added LDAP support, we added the capability for "auto-provisioning". This basically consisted of having the application pull down the relevant demographics from the LDAP store during login, and simply updating fields each time user logged in. If the user didn't exist, we'd create one on the fly.
This worked well, because the rest of the application had no awareness of LDAP. It simply worked with the user profile we managed already and if it needed something from the DB, the data was there.
Later, when we integrated SSO, we just leveraged the existing LDAP logic to pull from the SSO server and do the same thing.
This workflow helped a lot with provisioning and management. We could maintained the authoritative source (LDAP, SSO), and the app just kept up. What it hindered was local editing of the user profile, so we simply disabled that. Let them view the profile, but they could go to the other systems portal for management. Inelegant, but it's a rare use case anyway, so we just muddled through it. We eventually worked out two way pushing and replication, etc. but it's a real pain if you don't need it.
You can look here if you want an overview of how to do cross domain SSO: Cross Domain Login - How to login a user automatically when transferred from one domain to another
For our SSO, we use SAML v2 Web Profile, but we ended up writing our most of our own code to pull it off.
But, bottom line, no matter what the web sites say, integrating this is non-trivial. The edge cases and workflow/help desk issues that surround it are legion. And it can be a bear to debug.
I'm trying to understand the concept and benefits of implementing OpenID in your project. And, since I'm a Java developer, I'm more or less equally interested in understanding its main Java implementation, openid4java.
My understanding is that OpenID is a standard for provisioning decentralized IDs in a uniform way. Now, if that is totally (or even slightly) incorrect, please correct me!
Assuming I'm still on track, I see that all sorts or organizations have been using OpenID, such as MySpace, who identifies each of their users with a URL matching http://www.myspace.com/username.
So how does OpenID work as a system? Does it just manifest itself as a network of "OpenID Servers" that, like DNS machines, coordinate and make sure all IDs in their system are unique and match a certain pattern? Or, is it just an algorithm to be used which, like GUID, produces globally-unique IDs for each client domain (such as MySpace).
I'm just not understanding how OpenID actually manifests itself, and how frameworks like openid4java ineract with that "manifestation". (What their uses are).
First, there are two sides of the OpenID communication - the provider and the consumer. The consumer is the application that tries to authenticate using OpenID, and the provider is the server to which the authentication request is sent.
Each provider has a so-called Endpoint - url that accepts authentication requests. You should know that URL in advance when supporting an OpenID provider. First you have to discover what is the endpoint for a given openId, and then exchange messages with that provider. This is all wrapped in openid4java ConsumerManager.
Then happens the authentication - you redirect the user to a provider url, where the user confirms he wants to login using his account (should be logged in), then the provider redirects back to you, and then you can get the requested information about the user (through another request)