I'm trying to come up with the best way to do my own authentication in our Java REST API using the Jersey framework (v2.5.1) running on Tomcat 7.
The API will be accessed through our iOS application. In the iOS application we use Facebook authentication (using the Facebook SDK), and then we use the access token in every call to the REST API.
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
// Extract the access token from the HTTP header
// Look up in the database to see if we have a user with that token
// If there is a user found, proceed
// If we can't find a user, we are going to send the token to Facebook to get the user details. If the token is invalid, we throw an exception. If it is valid, we look up if we can match the Facebook details with an existing user. When we can't match, we create a new user.
}
}
This filter will be executed in every API request.
My questions:
Is this a correct workflow?
Should we contact Facebook every time to validate the token? This will cause a lot of overhead.
This filter is executed for every request. How can we exclude certain urls (some resources won't require authentication)? I was thinking of holding a set of urls in the filter class and see if the requested url matches one of the defined public urls (if so, don't do the authentication).
Thanks!
I think it might be better if you can provide this option to your user:
login / login using facebook account.
So you dont have to contact Facebook unless user choose to login using their FB account.
also, the authentication should be session based. session information can includes user, session key, valid time range, maybe source IP too. once the user has successfully logged in, a session is generated. then for every request you only have to check if the session key is still valid.
Related
So, we are implementing this special kind of authorization, where after logging in, user is presented with basic dashboard. When trying to get to another location, he is asked to authorize with password.
The thing is that in order to present the basic dashboard, some requests are sent and need to come with 200 response, while the rest just returns error message and redirects to authorization screen.
To summarize, we're gonna have 3 kinds of endpoints:
- blocked, until user authorizes
- allowed to return proper data for the first time while each consecutive request will require authorization
- no authorization required
I cannot find a way to overcome the 2nd type. Is there a way to record the number of requests sent per specific endpoint? Or is there any way to actually allow first unauthorized use and then required authorization?
One way would be to authenticate user without any role the first time that users access to yours controllers.
Then when he try again to access you could sent them to login process if user is logged without role.
To securize this methods could use the annotation below:
#Secure("IsAuthenticated()==false || (IsAuthenticated() && hasRole("WRITE"))")
To securize manually a user should use the SecurityContextHolder class
We're using spring security (Authorisation and Resource server ) in our project.
client sends a token request (/oauth/token) with the oauth2 parameters.
spring security app creates a token for the user and respond to the client with the access_token, refresh_token, custom user object (name, organisation, email etc) and authorities (Roles).
Client adds additional roles (say ROLE_CLIENT, ROLE_USER).
spring application will store the above roles for the given user.
Next time when client sends a token request, spring security returns the previously created token (not expired yet) along with the user and authority information. This authority information is not having the latest roles (added in step4).
Here spring security always using the existing token (as it is not expired) and returning the valid token. Is this the expected behaviour even though the user object is being modified?
It sounds like you need to revoke the access token when the users roles change if you want the next request to get a new access token with the new roles and not return an existing token with existing roles if it's still valid.
At the point where you update the users roles you'd likely want to revoke the token.
I haven't personally tested this but I found a guide for it here https://www.baeldung.com/spring-security-oauth-revoke-tokens so your milage may vary.
I want to add that this does not sound like the normal OAuth2 process and you may be breaking a few conventions here which might bite you later. That said, you don't have to follow a standard if you're confident in your proposed solution.
Edit: To clarify the users roles and access is normally part of a resource and not part of the token exchange. For example you have a normal OAuth2 request which generates a token which you can exchange for an access token, as you've laid out in steps 1 and 2. Then you'd normally take that access token and request user access information from a resource such as "userinfo" service or something similar.
Your security service can also be a resource server but the two steps should be seen as different. Then when you want to modify the users roles you do this again through a resource. This means the next time you invoke the resource it'll have the up to date information without needing to authenticate the user again.
I read through several q&a on stackoverflow for implementing rest authentication. And in one of those questions found a sample code as well.
https://github.com/philipsorst/angular-rest-springsecurity/blob/master/src/main/java/net/dontdrinkandroot/example/angularrestspringsecurity/rest/AuthenticationTokenProcessingFilter.java
Most of the answers talked about having an interceptor and filtering every request based on the auth header (a token and a user id or login id) and comparing it with the ones stored in the database.
I am implementing an Order management system.
And my url looks like http://myapi.com/customers/{customerId}/Orders/{OrderId}
Currently it is http and we're setting up the https soon.
In the URL, I get the customer ID and the order ID. I do a quick look up in the database with the order id and customer id and if it returns some rows, I return a JSON.
Questions I have:
To protect this endpoint, I can have a security interceptor. But every time I'll have to validate the request against the database. What are my alternatives (cache?) to validate or authorize each requests?
This rest end point is consumed by an android app(angular js)client and a website (a php client). For mobile, I should not re generate token each time the user logs in. So I have configured the token expiry to 30 days. However for the website, it is a session token. How should one handle this scenario?
What you need can be solved with Oauth.
Your backend (REST-API) will require authenticated access to your API operations. In turn, your clients/front-end will need to issue authenticated requests when communicating with the backend. This is achieved by sending access tokens.
Although this could seem complex, it will be very useful for you to take a look at Stormpath. We have a quite a straightforward solution for this. Please take a look at Using Stormpath for API Authentication.
As a summary, your solution will look like this:
You will use the Stormpath Java SDK to easily delegate all your user-management needs.
In your front, when the user presses the login button, your front end will send the credentials securely to your backend-end thorough its REST API.
2.1. By the way, Stormpath greatly enhances all the possibilities here. Instead of having your own login page, you can completely delegate the login/register functionality to Stormpath via its IDSite, or you can also delegate it to our Servlet Plugin. Stormpath also supports Google, Facebook, LinkedIn and Github login.
Your backend will then try to authenticate the user against the Stormpath Backend and will return an access token as a result:
/** This code will throw an Exception if the authentication fails */
public void postOAuthToken(HttpServletRequest request, HttpServletResponse response) {
Application application = client.getResource(applicationRestUrl, Application.class);
//Getting the authentication result
AccessTokenResult result = (AccessTokenResult) application.authenticateApiRequest(request);
//Here you can get all the user data stored in Stormpath
Account account = accessTokenResult.getAccount();
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
//Output the json of the Access Token
response.getWriter().print(token.toJson());
response.getWriter().flush();
}
Then, for every authenticated request, your backend will do:
/** This is your (now protected) exposed operation */
public void getOrder(HttpServletRequest request, HttpServletResponse response) {
Application application = client.getResource(applicationRestUrl, Application.class);
OauthAuthenticationResult result = (OauthAuthenticationResult) application.authenticateOauthRequest(request).execute();
System.out.println(result.getApiKey());
System.out.println(result.getAccount());
//Return what you need to return in the response
doGetOrder(request, response);
}
Please take a look here for more information
Hope that helps!
Disclaimer, I am an active Stormpath contributor.
I'm trying to access the HttpSession object (or similar API that let me fetch session attributes) from inside of a Google Cloud Endpoints backend method...
Reading this answer I've learn that I can inject a HttpRequest object as a parameter.
What I'm trying to do is retrieve a facebook access token previously stored by a Servlet.
Within the Development Web Server I can retrieve the HttpSession and get the desired attribute:
#ApiMethod
public MyResponse getResponse(HttpServletRequest req) {
String accessToken = (String) req.getSession().getAttribute("accessToken");
}
But, once I deploy my application to GAE, the retrieved access token is always null.
So is there a way to recover session attributes from inside api methods?
And if there isn't, how can I retrieve my access token from someplace else? Answers and comments in the mentioned question suggests the use of the data store, but I really can't think of a good natural candidate for a key... As far as GAE authentication mechanism is concerned my users aren't even logged in, I don't know how to retrieve the access_token of the current user from the Datastore / memcached or any other mechanism.
I've filed a feature request to support sessions in production, as I can confirm it's not working right now.
For now, I recommend you continue passing the access token on subsequent requests in a header. Header information is similarly available through the injected HttpServletRequest.
I know this has been asked already, but I am not able to get it to work.
Here is what I would like to get accomplished:
I am using Spring Security 3.2 to secure a REST-like service. No server side sessions.
I am not using basic auth, because that would mean that I need to store the user's password in a cookie on client side. Otherwise the user would need to login with each page refresh/ change. Storing a token is I guess the lesser evil.
A web client (browser, mobile app) calls a REST-like URL to login "/login" with username and password
The server authenticates the user and sends a token back to the client
The client stores the token and adds it to the http request header with each api call
The server checks the validity of the token and sends a response accordingly
I did not even look at the token generation part yet. I know it is backwards, but I wanted to get the token validation part implemented first.
I am trying to get this accomplished by using a custom filer (implementation of AbstractAuthenticationProcessingFilter), however I seem to have the wrong idea about it.
Defining it like this:
public TokenAuthenticationFilter() {
super("/");
}
will only trigger the filter for this exact URL.
I am sticking to some sample implementation, where it calls AbstractAuthenticationProcessingFilter#requiresAuthentication which does not accept wildcards.
I can of course alter that behavior, but this somehow makes me think that I am on the wrong path.
I also started implementing a custom AuthenticationProvider. Maybe that is the right thing?
Can someone give me a push into the right direction?
I think pre-auth filter is a better fit for your scenario.
Override AbstractPreAuthenticatedProcessingFilter's getPrincipal and getCredentials methods.
In case the token is not present in the header, return null from getPrincipal.
Flow:
User logs in for the first time, no header passed, so no
authentication object set in securityContext, normal authentication
process follows i.e. ExceptionTranslation filter redirtects the user
to /login page based on form-logon filter or your custom authenticationEntryPoint
After successful authentication, user requests secured url, pre-auth filter gets token from header authentication object set in
securityContext, if user have access he is allowed to access secured
url