jax-rs rest webservice authentication and authorization - web-services

I have a web application that needs to allow users using different webclients (browser, native mobile app, etc) to register. After signing in they can access restricted content or their own content (like entries they create, etc).
What I did so far: I created a jax-rs rest webservice (I'm hosting my application on glassfish) that exposes the following methods:
register - user POST's his desired username/password/email/etc; if username/email is unique, an entry for this user is created in the database (I'm using Hibernate for persistence)
login - user POST's username and password. If they are ok a UUID is created and returned to the user (this will be used as a token for future requests). I have a table called logedusers, with userID, token, validSince as columns.
Here is where it gets confusing for me.
Let's say that I have another method, getUserEntries, that should return all the entries made by the user. To make this clearer, there will be a Entry table with the following fields: entryId, userId, text.
What is the best approach here?
What i do now, is I make a get request and pass in the token like this:
localhost:8080/myApp/getUserEntries?token=erf34c34
Afterwards, if the token is valid, I get the userID from the logedusers table and based on that userId, get all the entries and return them as json.
Something like this:
#GET
#Path("getUserEntries")
#Produces(MediaType.APPLICATION_JSON)
public Response getUserEntries(#QueryParam("token") String token) {
String userId=getUserIdFromToken(token);
if (userId == null){
return Response.status(Response.Status.UNAUTHORIZED).build();
} else {
//get some data associated with that userId, put it in the response object and send it back
return Response.ok().entity(response).build();
}
}
However, what happens if I have more methods that provide data if they are called by a valid user?
I'd have to do this check at the beginning of every method.
I want to make this authorization process transparent
So, two major questions here:
Is this design ok? The whole authenticate with user/pass, server creates and stores and sends token to the user, user sends token on future requests.
What do I do if i have many endpoints that need to determine the identity of the calling user? Can I mark them with some annotations, use some sort of security provider / authenticator (where I can add my own logic for validating - eg check to see if the token isn't older than 5 days, etc).
Thanks

Is this design ok? The whole authenticate with user/pass, server creates and stores and sends token to the user, user sends token on future requests.
It's somewhat OK. The conceptual level isn't too bad (provided you're OK with self-registration at all) but the interface needs a lot of tweaking. While yes, POST to register and login is correct, for the rest of your webapp you should be pulling the identity information out of the context if you need it, and using role-based access control at the method level where you can.
Note that your container has a whole set of authentication and authorization-support mechanisms built in. Use them.
What do I do if i have many endpoints that need to determine the identity of the calling user? Can I mark them with some annotations, use some sort of security provider / authenticator (where I can add my own logic for validating - eg check to see if the token isn't older than 5 days, etc).
Do they need the identity? Or do they just need to know that the user is allowed to access them? If the latter, the easiest method is to put a suitable #RolesAllowed annotation on the method, at which point (with suitable configuration; see the JEE5 security docs). If the former, you need to get the HttpServletRequest object for the current action and call its getUserPrincipal() method to get the user's identity (or null if they've not logged in yet). This SO question describes how to go about getting the request object; there are a few possible ways to do it but I recommend injection via a #Resource annotation.
What I wouldn't do is allow users to normally provide their own identity via a #QueryParam; that's just wildly open to abuse. You can allow them to ask about other users that way, but then you need to decide whether you are going to tell them anything or not based on whether the current user is permitted to know anything about the other user. That's the sort of complex security problem that comes up in a real app, and is a good point for needing the current verified user identity.

Related

Tronweb authentication

I want to build a webapp that uses the wallet address as account, but yet I want to store the user in my db to allow specifying a nickname.
The problem I'm dealing with is that I want to call different apis, where the user needs to be authenticated / authorized in order to gain access .
Since the authentication happens 100% client side in my case (through the tronlink extension and TronWeb), I don't see another way as to add supplementary authentication for my webapp specifically.
If the user logs in to my app with a different password (not using the private key of the wallet), it seems like bad user experience as the user needs to authenticate twice (through Tronweb AND my webapp with a password).
How do you solve this problem?
It seems that the way to handle this is to foresee a separate login flow for the web app after all.
Even when the user already has logged in into Tronlink, it needs to obtain a token to authenticate rest calls.
The way it would appear to work is by generating a random nonce and storing this nonce along with the public key in the User table.
The login flow then consists of signing the nonce in the front-end, and verifying the signature in the backend after which the token will be generated and returned.

Allowing temporary access to DynamoDB

I have a client app that connects to an Elastic Beanstalk server app. Some of my users need to register. But when the registration form loads it needs to get some data from DynamoDB so the user can choose between a few options.
The problem is that I set up my server in a way that any request to the server that is not authenticated (no auth tokens previously obtained by the client app from Cognito) gets denied. Of course, if a person is going to register they are not authenticated, which means they do not have access to the information from DynamoDB they need to register. It is only a couple of pieces of information I need, so it is very frustrating.
What I have thought about how to solve this:
Putting a long string of characters in the client app that gets sent to the server when a request is made for ONLY the couple of pieces of information I need. The server would also have that same string stored somewhere and would then compare them. If they match, then it returns the info requested. As I said, this would be done only for the 2 pieces of info I need, everything else would still be secure.
Leave the two routes public in my API that lead to the pieces of info I need (I know, it is a bad idea).
What would be the best way to go about this?
Assuming you're using cognito there is also a concept of an anonymous guest user which can have its own role assigned.
You can treat the anonymous guest user like a regular cognito user (it can have a role assigned), however you would scope its permissions down to the minimum it requires to perform these operations.
Alternatively use option 2, the API could call a Lambda that would return the necessary information simply reading the data. You would possibly want to look at caching the results as well to avoid your API Gateway endpoint being abused.

Scope of returned resource highly depandant on user role encoded in JWT token - is it RESTful?

I'm working on API that tries to stay in RESTful principles, although one requirement keeps bugging me.
We use JWT based authentication. Inside JWT claims we store roles of the user. Now our main GET endpoint (let's call it ListAllOffers for simplicity) behaves differently depending on what role the user have:
if API recognizes admin via JWT it responds with full list of Offers
if API recognizes ordinary user via JWT it responds with narrowed list of Offers (depending on relation in DB)
My concerns is: is it ok according to REST principles or any unwritten REST practices? I am used to modify response object according to argument from url, params from querystring or alternatively via header values. Altering JSON response basing JWT seems not explicit enough that is feels some kinda strange.
Bonus question: is it against any of REST principles how should this requirement be implemented.
You'll find lots of APIs have resources where the value changes depending on the authenticated user (see GitHub's API).
When it comes to REST the endpoint must always reference the same resource. However, you may choose to represent that resource in any way you wish. Masking some of the offers because the user is not an admin has not changed the resource only the representation you are giving to that user.
While the REST specification doesn't have any specific examples of changing representations due to authorisation it is still a worthwhile read.
If you are concerned about changing the representation implicitly there are a few options available that would make it more explicit whilst still following RESTful standards.
You could add a query parameter that explicitly requests only the current user's offers: /offers?show=mine.
If the offers are 'owner' by a user you could also do something like: /users/{username}/offers. Here a user would be authorised only for their own offers. An admin would of course be authorised for any.
Overall the key point is this: an endpoint must always represent the same resource but how it represents it is up to you.

Securing REST API without reinventing the wheel

When designing REST API is it common to authenticate a user first?
The typical use case I am looking for is:
User wants to get data. Sure cool we like to share! Get a public API key and read away!
User wants to store/update data... woah wait up! who are you, can you do this?
I would like to build it once and allow say a web-app, an android application or an iPhone application to use it.
A REST API appears to be a logical choice with requirements like this
To illustrate my question I'll use a simple example.
I have an item in a database, which has a rating attribute (integer 1 to 5).
If I understand REST correctly I would implement a GET request using the language of my choice that returns csv, xml or json like this:
http://example.com/product/getrating/{id}/
Say we pick JSON we return:
{
"id": "1",
"name": "widget1",
"attributes": { "rating": {"type":"int", "value":4} }
}
This is fine for public facing APIs. I get that part.
Where I have tons of question is how do I combine this with a security model? I'm used to web-app security where I have a session state identifying my user at all time so I can control what they can do no matter what they decide to send me. As I understand it this isn't RESTful so would be a bad solution in this case.
I'll try to use another example using the same item/rating.
If user "JOE" wants to add a rating to an item
This could be done using:
http://example.com/product/addrating/{id}/{givenRating}/
At this point I want to store the data saying that "JOE" gave product {id} a rating of {givenRating}.
Question: How do I know the request came from "JOE" and not "BOB".
Furthermore, what if it was for more sensible data like a user's phone number?
What I've got so far is:
1) Use the built-in feature of HTTP to authenticate at every request, either plain HTTP or HTTPS.
This means that every request now take the form of:
https://joe:joepassword#example.com/product/addrating/{id}/{givenRating}/
2) Use an approach like Amazon's S3 with private and public key: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
3) Use a cookie anyway and break the stateless part of REST.
The second approach appears better to me, but I am left wondering do I really have to re-invent this whole thing? Hashing, storing, generating the keys, etc all by myself?
This sounds a lot like using session in a typical web application and rewriting the entire stack yourself, which usually to me mean "You're doing it wrong" especially when dealing with security.
EDIT: I guess I should have mentioned OAuth as well.
Edit 5 years later
Use OAuth2!
Previous version
No, there is absolutely no need to use a cookie. It's not half as secure as HTTP Digest, OAuth or Amazon's AWS (which is not hard to copy).
The way you should look at a cookie is that it's an authentication token as much as Basic/Digest/OAuth/whichever would be, but less appropriate.
However, I don't feel using a cookie goes against RESTful principles per se, as long as the contents of the session cookie does not influence the contents of the resource you're returning from the server.
Cookies are evil, stop using them.
Don't worry about being "RESTful", worry about security. Here's how I do it:
Step 1: User hits authentication service with credentials.
Step 2: If credentials check out, return a fingerprint, session id, etc..., and pop them into shared memory for quick retrieval later or use a database if you don't mind adding a few milliseconds to your web service turnaround time.
Step 3: Add an entry point call to the top of every web service script that validates the fingerprint and session id for every web service request.
Step 4: If the fingerprint and session id aren't valid or have timed out redirect to authentication.
READ THIS:
RESTful Authentication
Edit 3 years later
I completely agree with Evert, use OAuth2 with HTTPS, and don't reinvent the wheel! :-)
By simpler REST APIs - not meant for 3rd party clients - JSON Web Tokens can be good as well.
Previous version
Use a cookie anyway and break the stateless part of REST.
Don't use sessions, with sessions your REST service won't be well scalable... There are 2 states here: application state (or client state or session s) and resource state. Application state contains the session data and it is maintained by the REST client. Resource state contains the resource properties and relations and is maintained by the REST service. You can decide very easy whether a particular variable is part of the application state or the resource state. If the amount of data increases with the number of active sessions, then it belongs to the application state. So for example user identity by the current session belongs to the application state, but the list of the users or user permissions belongs to the resource state.
So the REST client should store the identification factors and send them with every request. Don't confuse the REST client with the HTTP client. They are not the same. REST client can be on the server side too if it uses curl, or it can create for example a server side http only cookie which it can share with the REST service via CORS. The only thing what matters that the REST service has to authenticate by every request, so you have to send the credentials (username, password) with every request.
If you write a client side REST client, then this can be done with SSL + HTTP auth. In that case you can create a credentials -> (identity, permissions) cache on the server to make authentication faster. Be aware of that if you clear that cache, and the users send the same request, they will get the same response, just it will take a bit longer. You can compare this with sessions: if you clear the session store, then users will get a status: 401 unauthorized response...
If you write a server side REST client and you send identification factors to the REST service via curl, then you have 2 choices. You can use http auth as well, or you can use a session manager in your REST client but not in the REST service.
If somebody untrusted writes your REST client, then you have to write an application to authenticate the users and to give them the availability to decide whether they want to grant permissions to different clients or not. Oauth is an already existing solution for that. Oauth1 is more secure, oauth2 is less secure but simpler, and I guess there are several other solution for this problem... You don't have to reinvent this. There are complete authentication and authorization solutions using oauth, for example: the wso identity server.
Cookies are not necessarily bad. You can use them in a RESTful way until they hold client state and the service holds resource state only. For example you can store the cart or the preferred pagination settings in cookies...

Web-service authentication management

I'll have to develop some private web-services, so I need a way to authenticate the users in order for each service to be able to know if a request is valid and to maintain some session states.
I'd like to have a central authentication service with some simple operations like "logIn(login, password)" (that uses a directory like LDAP), "isValidSession(sessionID)" and "logOut(sessionID)". The "logIn" operation should generate a session ID, or something similar, that would allow a user to communicate further with the other services by using this token.
Then when a user tries to use an operation :
the user provides as the last parameter its session ID,
the operation asks the authentication server if the provided ID is valid,
if yes the operation retrieves user's session informations,
the operation proceeds and return the result.
Does it exist standard patterns and technologies to manage this kind of scenario ?
Thanks in advance for your help.
Before setting up something custom, have you considered something like OAuth at all?