I am developing a Java web application using RESTful as web service. And now I want to apply Apache Shiro to secure my application. The mechanism is: after user logged in successfully, a token (combined from username, password and logged time) will be returned to client. Then every single REST request will attach this token to authenticate at server (no need to authorize). But now I dont know how to configure to accept this.
And by the way, could you please give me any sample about Shiro & RESTful integration? Thank you
If the REST application and the Java web application are the same Webapp, then you only need to check subject.isAuthenticated(). Use a session cookie without the password or username (it isn't a good idea to be passing around the password as it could be stolen).
Most of this behavior comes by default if both parts are in the same Webapp.
In your REST method you'd have something like:
Subject subject = SecurityUtils.getSubject();
if(subject == null || !subject.isAuthenticated()) {
return 401; // Not Authorized
}
Hope that helps.
In addition to the above response, you can send back a token (session-id) from your REST Server, post successful login. Your iOS/Android application will then need to store this, and send this with every REST request it makes. Here is sample of what your post login REST response can be:
session-start-timestamp: 1394683755389,
session-timeout: 1800000,
session-id: "068C8E0E289788A7ABC5FE47B2CC0D28"
The session-id will be maintained by your REST Server, and its TTL will be reset every time a new request with this id comes in.
On browsers, this id gets sent automatically. For your case, you would want to send it explicitly with each HTTP request (which is what REST request is)
Hope this helps
Related
I have a web application that provides several rest services (Jersey). Most of the endpoints are secured by BASIC authentification. Further more I use SSL for transport and demand POSTs for every call.
The clients/consumers are android apps.
So far so good. The only service that seems to be vulnerable is the registration. It's the 'first' service to call and a user does not exist yet. So I cannot use OAuth, etc. I also have to keep the endpoint easy accessible to enable the user to regster.
How do I secure this service, so it's not spammed by a bot flooding my database?
How about these?
Use a registration link with a token in the request parameter. Ensure that the tokens expire after sometime. You could create a token endpoint url as well for a client to get a valid token.
Use a custom header or a dynamic custom header in your request. Additionally, you could check for a dynamic custom header to validate the request's authenticity.
Use registration confirmation workflows, such as an email / text verification as soon the registration is done. Run a process every day to delete any user accounts, which are not validated in say x days.
I do not think you can really secure the registration URL in a HTTP way. IMHO, anyone who has the registration url can be a right guy trying to register. So if you ask me, option 3 is better than others.
I have implemented a Restful API for my simple application using Jersey, this API (Restful webservice) is protected by JAAS (Java Authentication and Authorization Service).
Now if user try to access a URL something like example.com/api/user/info/1, A popup(BASIC-Authentication) appears in browser to take input for username and password on successful login user is able to see the result (success).
so far so good.
Now I was thinking about the 3rd party application that will access my Restful web service. must authenticate before accessing any endpoint. (I know if an un-authenticated user will try to access my endpoint URLs JAAS will intercept that).
I am also aware that if I provide username and password in the request header, JAAS will automatically authenticate that as well.
Confusions:
1 - I do not want to embed username and password onto each request (I am not suer why, but I just don't want it (Please share your comments)) so that if I am accessing secure endpoint get authenticated automatically. I just want to authenticate a user and generate a token and then use that token in rest of the communication.
2 - I want to provide some endpoint for 3rd party applications to deliberately initiate the authentication process.
example.com/api/authenticate but the username and password still in header. and when endpoint's relative method is called it extract username and password from that request's header. I am aware of 2 annotations #QueryParam and #FormParam, but I want something like #HeaderParam.
Why? I think that is more secure way. (Is that right?)
#Path("authenticate")
public String authenticate( ) {
}
3 - I tried multiple techniques to login programmatically but none seems to work on Glassfish, so is it right its not possible on Glassfish? I am using Realm based JAAS.
4 - I am looking for some way once I have authenticated the user prorgammatically, add some information to the session. and in any other request get that information from session. (I am using Jersey based classes for endpoints and EJBs for business logic) - I know in EJBs through context we can lookup principal and then from that we can retrive the user record from database etc. but is there any thing Jersey Endpoint classes can add to the session and get them back in any other endpoint class?
5 - Is it enough for 3rd party application to save cookies returned by my Webservice and embed them in next request to have long lasting session for JAAS authenticated user (so that authentication process may not be required on each request)
I'm going to rewrite my previous question.
Glassfish redirects after form login to the last accessed resource, how do I go about to turn this off?
Our problem is that we get 415 in FF and IE because if I have a JSESSION cookie Glassfish will redirect to the last resource I tried to access but does not switch content type from (x-form-urlencoded).
Pseudo example (requests are the browsers' XMLHttpRequest):
GET /secure/resouce1 (json) -> Response "you're not logged in."
GET /login.xhtml
POST /j_secure (x-form-urlencoded) -> New location /secure/resource1 (x-form-urlencoded)
GET /secure/resource1 (x-form-urlencoded) <- HTTP ERROR 415 content type not JSON.
You will probably need to write a Filter to check for and catch that case. I like this tutorial (hoping the translation to English is understandable).
In my opinion it is better to use Basic or Digest authentication over SSL for RESTful services. Other options are including the credentials as part of the payload or creating a dedicated login service, which accepts credentials and returns a token. There are various reasons why form based authentication is less suitable for RESTful service: it requires a session, it does not use the existing HTTP Authorization and more.
If you need to call your RESTful service using AJAX then using a cookie for authentication can be a valid solution. They should only affect if the user can make a call, but not how the server responds.
If you would like to keep using form based authentication for your application I would suggest adding an additional JAAS authentication provider which will handle the RESTful services authentication. You can read more about it here.
Another option, which should be easier than JAAS, would be using Spring Security or Apache Shiro instead of the container based authentication.
Here is an example of configuring form based authentication with Spring Security. This post shows an example of how to secure RESTful services using Spring Security.
in your login page
reset the JSESSIONID cookie to prevent redirect last page
// login_form.jsp
Cookie jsess = new Cookie("JSESSIONID", null);
jsess.setMaxAge(0);
jsess.setPath(pageContext.getServletContext().getContextPath());
response.addCookie(jsess);
I've been learning spring-ws for little over a week and I've set up a simple web service.
I'm testing it using soapui and specifying a username and password in the request properties.
My web service has no security layer nor do I want to add one. I just need to pull the username and password out of the request to make requests to another service. I don't want to have to specify a username or password in my request body itself.
All I want to do is retrieve the username and password from the request from soapui. Does anyone know where the username and password are in the request? Are they in a http header or the soap header. The soap header appears to be empty in soapui.
I have tried writing my own interceptor to my endpoint and getting the soap header but it appears to be empty.
I have also tried retrieving them using SecurityContextHolder.getContext().getAuthentication();
but this returns null.
I also tried to interrogate the HttpServletRequest from my endpoint to see if the user details were in there, sadly not.
Does anyone have any ideas or good knowledge of this area?
Since there is not authentication in your application, your server does not prompt for authentication and the parameters you specify in soapUI are never used (not included in the http request). Furthermore there is not point using
SecurityContextHolder.getContext().getAuthentication()
since you don't have authentication, there is no authenticated user and it returns null as you said.
If you need username/password to access another resource, you should specify them as configuration parameters in your web service.
I'm hosting a REST web service in a Grails application, using Spring Security, i.e.:
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def save = {
println "Save Ride REST WebMethod called"
}
I'm calling it from an Android app. (Calling the unsecured service works just fine.)
To call the service, I'm manually building up a request (HttpUriRequest) and executing it with an HttpClient.
I'm wondering what the best practices are, and how to implement them... Specifically, should I:
Perform a login once, to retrieve a JSESSION_ID, then add a header containing it into the HttpUriRequest for each subsequent request?
Or (not sure how I would even do this) include the login and password directly on each request, foregoing the cookie/server-side session
I think I can get option 1 working, but am not sure if Spring Security permits (2), if that's the way to go... Thanks!
--also, there isn't any library I'm missing that would do all this for me is there? :)
Spring security does support both basic authentication and form based authentication (embedding the username/password in the URL).
A REST service is generally authenticated on each and every request, not normally by a session. The default spring security authentication (assuming you're on 3.x) should look for basic authentication parameters or form parameters (j_username and j_password) (in the form http://you.com/rest_service?j_username=xyz&j_password=abc).
Manually tacking the j_username/j_password onto the URL, adding them as post parameters (I believe), or setting the basic authentication username/password should all work to authenticate a REST service against the default Spring Security interceptors, right out of the box.
I will admit that I haven't tried this on REST services, though I do clearly recall reading exactly this in the docs as I did the same for basic page logins on spring security recently. Disclaimer over.
I think you can use a login-once-and-get-a-token method that's similar to how oauth works.
sending username and password across the network outside of secured channel(https/ssl) is a terrible idea. anyone on the network can sniff your request package and see the clear text password.
on the other hand, if you use a token method, since the token string is randomly generated, even the token is compromised, the worst case is someone can use the token accessing your REST API.
another solution is going through ssl tunnel(HTTPS). i have actually done a comparison and result shows: 80 requests/min(https) vs 300 requests/min(http)