We have a central RESTful webservices application that exposes data to many different clients (parsers, web applications, touch applications, etc). The clients have different means for authenticating users, some LDAP, others not. Regardless, the RESTful application leaves the authentication of the end-user to the client, and simply authenticates the client making the request. The client will have a username and password in LDAP, along with a list of acceptable IP addresses from which the client can access the RESTful application.
Here is the tricky part: the RESTful application must audit every request with the end-user's username. Furthermore, in certain circumstances (depending on the client) the RESTful application will need the end-user's username and password for accessing a third-party application. So, every request from the client will have authentication credentials for the client itself and the end-user accessing the client.
Here comes the question. Would it be best to put the client's credentials in Basic Auth, and pass the end-user's credentials via an encrypted SALT request parameter? Or, should the client put both sets of credentials in the Basic Auth (i.e. system~username:systempwd~userpwd) and parse them out into two sets of tokens that are then authenticated. Or, another solution that is better than either of these two?
This sounds pretty much like OAuth2's "Resource Owner Password Credentials Grant" - see https://www.rfc-editor.org/rfc/rfc6749#section-4.3. You pass application/client credentials in the Authorization header and client information in the body encoded using x-www-url-encoded. Do that once at the beginning of the session and then depend on a bearer token in the authorization header after that. All of that is described in the RFC. Remember to use SSL/TLS to encrypt the credentials.
Related
I have two servers.
Server A - this is whole bussines logic and API for mobile application.
Server B - in simply words, this is a webpage.
And now, I need to authenticate user on B but, by the 'user-data' from A.
E.G.
On A server I have user with loggin/password. And I need to use this same login/password on B server. There is some nice solution for that? Or just use tokens?
Presumed that you have an authentication mechanism in your server A.
You have to use your server A as an Identity provider. Request to your B-server should have a session header. If this session is not valid in B-server then you have to ask for credential from the web user and forward this request to your Identity Provider(Server-A). If Server-A can identify the given credential, initiate a session in server-B for this user for a particular time frame. You have to manage this session in the Server-B.
When this user logged out from server-B just destroy the session.
tokens should be fine such as a bearer token on the Authorization header. There are different strategies such as opaque tokens vs JWTs, etc.
I actually did a write up on API authentication tutorial and security holes:
https://www.moesif.com/blog/technical/restful-apis/Authorization-on-RESTful-APIs/
Django Oauth Toolkit docs don't describe the redirect uris, authorization grant type, or client type fields when registering your application.
The tutorial says to set client type to confidential, grant type to password, and leave uris blank.
What do the other options do?
e.g. What is client type public vs confidential? What do the grant type password, credentials, authorization, implicit do? And what are the redirect uris for?
I have found sparse information about them but no actual explanations as they pertain to django rest framework and django oauth toolkit.
You'll get answer to all your questions once you read about Oauth2 Protocol from here
But I'll try to answer your questions in brief:
I'll be using the words client and Resource Server frequently. In Oauth2 protocol, client means the system which accesses resources, data or service. (It could be your mobile app or javascript app consuming REST API's of your API Backend (or Resource Server) . If you have implemented Facebook login in your mobile/JS apps, chances are, your API backend requests Facebook for user's information. In that case your API backend is being a client and Facebook is Resource Server)
Client Types:
Client type is either confidential or public depending on whether that client can keep it's client_secret a secret. (For example, an AngularJS app cannot keep it's client_secret hidden, since anyone can do "Inspect Element" in a browser and search for it, so such a client has to be registered as public.)
Authorization Grant Types:
There are four kinds of Authorization Grant Types in Oauth2 protocol.
Authorization Code:
In this grant type, the client requests for an authorization code first, then exchanges that authorization code for an access token. It's a two step procedure. Use this if the client is an outsider (more on it in Resource-owner password based).
Implicit:
Usually used along with public client_type. Instead of a two-step procedure above, the client gets access token in one go.
Resource-owner password based:
This is used when there is a high degree of trust between client and Resource Server. This is the case between your API backend and your Mobile app. (There is high degree of trust between your API backend and Javascript app too, but since it cannot keep it's client_secret a secret, you have to use Implicit Grant type with it). Facebook or Google etc. will never give you this kind of Authorization Grant because, for them, your API backend is an outsider.
Client Credentials:
It is least commonly used. Please read about it in above mentioned document.
Redirect URI's:
Now, as far as Redirect URI's are concerned, they are needed only in Authorization Code or Implicit grant types (Not sure about Client Credentials one, somebody please enlighten me on this in comments).
Redirect URI is given so that the Resource Server knows where to send the access token. Imagine if you are implementing Facebook login. In that case you will go to developers.facebook.com and register your application (like you did with django-oauth-toolkit), while registering your application, you will specify a Redirect URI.
Specifying a Redirect URI is a way of saying. "Hey Facebook, send the access token on this URI". So if you set Redirect URI something like https://your_domain_name.com/token/facebook/, Facebook will redirect to your specified Redirect URI at the end of Oauth2 process and give Access Token in the form of GET parameter, like https://your_domain_name.com/token/facebook/?token=some_long_string&some=other_parameters.
I am developing several Web Services that will be accessed by a mobile application. I have several requirements:
Each user will need to sign in with their own User ID and Password (the same User ID and Password they use to sign into the website).
Every Web Service request will need to be authenticated to ensure that the request is coming from the mobile app(s).
Every Web Service request will need to authenticate the user, since there is user-specific fucntionality built in, and access will need to be blocked if the user's account is disabled.
Let's assume that OAuth is not an option.
In order to ensure that Web Service requests are coming only from the mobile app(s), I am planning to use HTTP Basic Authentication in IIS (the mobile app(s) will need to have a User Account setup in Windows Server and the mobile app will need to store the User Name & Password and pass these in the header).
Next is the User Authentication for each Web Service request. Would it be suitable to encrypt the User ID, Password, and some shared secret key (a "pepper", of sort) with AES-256, pass that encrypted string as a parameter with each request (over HTTPS, of course), and then decrypt and parse it on the server to authenticate? This is the existing plan, but something just doesnt seem right about it - like it's not "secure enough".
What else can I do to properly authenticate users for Web Service requests?
I recently went through this problem and asked opinions from a group of senior people about how they solve the problem. Opinions were varied, but one consistent feeling is that your level of security depends on the use case of your application. Are you doing online banking or storing medical records? Then your security needs may be quite high. Social networking? Maybe not so much.
Basic Authentication is generally fine when encrypted over SSL, ColdFusion works well with it. If you use Basic Auth, make sure to encrypt your traffic with 1024-bit keys or better. Don't authenticate every request with username/password - that's unnecessary. Authenticate the first request, set a session token, and rely on the session token for your identification of users.
Set a polling mechanism from the client to the server to keep the session alive - set the session timeout to 30 minutes and the polling frequency at 25 minutes, for example. Otherwise you may need to re-authenticate expired sessions. Again, how you approach this part of the solution depends on your paranoia level, which depends on what kind of data/app you are dealing with.
Cookies, and therefore sessions, should work fine in iOS apps. If you use sessions to verify identity after authentication, make sure your session cookies are memory-only (set at the server level).
Check the SSL implementation of your server against the Qualysis SSL Test:
https://www.ssllabs.com/ssltest/
The report will give you a surprising amount of detail about the strength of your SSL implementation.
Lastly, consider implementing two-factor authentication to combat password theft.
If you ignore the SSL advice and plan on encrypting your password and communicating over an insecure channel, look at the Kerberos protocol for a well-known example of how to authenticate securely:
http://en.wikipedia.org/wiki/Kerberos_%28protocol%29
Yes, you can use Basic Authentication but that means the client will need to store the username/password in plain text, and also send them over in plain text. Sending part is sort of fine if it's under HTTPS, but storing username/password in plain text may not be a good idea, unless you're using some secure key store.
Let's assume you have decided that Basic Authentication is the way to go, and you want to make use of the official CF way of supporting that, then you can use CFLOGIN.name & CFLOGIN.password. You may also check out Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion. In the remote cfc side, always validate the username/password, or return some sort of token and asks the client to use that token going forward. The token can be cfid+cftoken if you like, or even roll your own that never expires. If you use cfid+cftoken, and send them over as cookie or in body along with your web service call, I believe you can resume the session if you so choose.
I have an internal-facing RESTful web service. There are various client applications using the service, and the client apps themselves have end users. The web service needs to authorize requests based on the end user identities.
The question: What are the typical options for authenticating the end user here? That is, I want to authenticate the user, not the client application. (I don't mind if authenticating the client application is part of the scheme, but ultimately I need to know that the end user is who I think he or she is.)
One possible scheme, for example, would be to have per-client system accounts, and then have the client simply assert the user's identity (e.g. in an HTTP request header, say). So we authenticate the client application and delegate user authentication to the client. I don't think this is a very strong scheme, though, because it depends too much on keeping the system account credentials secret. I have seen too many examples of people e-mailing system account credentials around to put much faith in this sort of approach.
Another approach might be to have the client app, upon user login, use the user's credentials to get a token from the API, and then use that token for subsequent API requests. That way the authentication is user-specific without requiring the client app to hang onto the username/password credentials.
Anyway I'd like to have a better sense for the range of options I should be considering here.
The problem that you describe with "delegated authentication" is a real one. It means that a "client application" using it's credentials has access to the whole breadth of user data. This access can be used maliciously (for example a "semi-trusted" app harvesting api data) or negligently (for example an app accidentally exposing a Direct Object Reference Vulnerability - https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References)
Probably the most prevalent "token based" scheme is OAuth2 (http://oauth.net/2/), and the precursor, OAuth, which many sites choose to continue to use.
OAuth2 has a number of roles:
resource owner (the user in your case)
resource server (your api)
client (the apps you talk about)
authorization server (not clear who or what would fulfil this role in your case)
The basic scheme is that the resource owner authenticates using their credentials directly with the authorization server. They are then asked if they want to grant some information (which may just be a persistent identifier, or a description of the information exposed by your api) to some client. When they accept an 'auth code' is sent to the client and they use that (combined with their own credentials) to receive an 'access token'. This access token can then be used to authenticate against the resource server (which can check it's authenticity back against the authorization server).
Normally the way this is used is that the authorization server and the resource server are owned and managed by the same entity (for example google and facebook would fulfil this role) and then clients are independently managed.
The scheme can also be used internally within an organisation without the "explicit grant" which can still at least confirm that a specific end-user is present before releasing any data from an api.
I have server with some resources; until now all these resources were requested through a browser by a human user, and the authentication was made with an username/password method, that generates a cookie with a token (to have the session open for some time).
Right now the system requires that other servers make GET requests to this resource server but they have to authenticate to get them. We have been using a list of authorized IPs but having two authentication methods makes the code more complex.
My questions are:
Is there any standard method or pattern to authenticate human users and servers using the same code?
If there is not, are the methods I'm using now the right ones or is there a better / more standard way to accomplish what I need?
Thanks in advance for any suggestion.
I have used a combination of basic authentication and cookies in my web services before. In basic authentication you pass the user name/password encoded in the HTTP header where it looks something like this.
Authorization: Basic QWxhZGluOnNlc2FtIG9wZW4=
The string after the word "Basic" is the encoded user name and password that is separated by a colon. The REST API can grab this information from the HTTP header and perform authentication and authorization. If authentication fails I return an HTTP Unauthorized error and if they are authenticated but are not authorized I return an HTTP Forbidden error to distinguish between failure to authentication versus authorization. If it is a web client and the person is authenticated then I pass the following in the HTTP header with a request.
Authorization: Cookie
This tells the web service to get the cookie from the HTTP request and use it for authorization instead of doing the authentication process over again.
This will allow clients that are not web browsers to use the same techniques. The client can always use basic authentication for every request, or they can use basic authentication on the initial request and maintain cookies thereafter. This technique also works well for Single Page Applications (SPAs) where you do not have a separate login page.
Note: Encoding the user name and password is not good enough security; you still want to use HTTPS/SSL to secure the communications channel.