Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RESTful authentication for Java EE

I've been spending some time evaluating the options available for restfully authenticating a user in a Java EE application.

So, please suggest if the options listed below are valid along with the statements about advantages or disadvantages. It might be I'm missing details which might make an authentication method viable. Or it might be that there's another option which I've missed (again we're talking strictly java EE so no query authentication and what not unless it can be done in a EE compliant way )

1. DIGEST/BASIC authentication

 <security-constraint>
     <web-resource-collection>
        <web-resource-name>admin</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
     </web-resource-collection>
     <auth-constraint>
        <role-name>admin</role-name>
     </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>DIGEST/BASIC</auth-method>
    <realm-name>as-defined-secuity-realm</realm-name>
</login-config>

Advantages

  1. This is a REST friendly way of authenticating. You can send the authorisation credentials via an AJAX call. Once the user is authenticated, the browser will accompany any requests with the proper Authorization: Basic/Digest QWxhZGRpbjpvcGVuIHNlc2FtZQ== header. In case of bad credentials the user will be presented with the ugly browser login screen - if you can live with that then BASIC/DIGEST auth is the way for you.

  2. In the case of Digest the string passed to the server is an MD5 encrypted string, which is definetely more secure than Basic( which is a Base64 encoding of the 'user:password' string), but nevertheless decipherable. So in terms of security BASIC is pretty much as secure as FORM authentication and DIGEST is the most secure of them all. In conclusion if your site is entirely HTTPS (I mean entirely because if some resources are fetched via HTTP, your authorization headers for example will be visible to a third party) you are safe to go with BASIC/DIGEST.

  3. Easy to set up.

Disadvantages

  1. Logging out is tricky to implement. See here and here.Sure you have a nice AJAX request which authenticates the user, but you need to also have an ?AJAX? request which logs off the user - triggering the browser login window to appear again). BTW the nice servlet 3.0 request.logout() method does not work properly in this case.
  2. Session timeouts are very hard to implement. Session expiration does occur(it is the job of the servlet container), but the browser will send the authorization headers on the next request, triggering re-authentication.
  3. No personalized login page. None.
  4. Hard to keep track of authenticated sessions.

2. FORM based authentication

 <security-constraint>
     <web-resource-collection>
        <web-resource-name>admin</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
     </web-resource-collection>
     <auth-constraint>
        <role-name>admin</role-name>
     </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>as-defined-security-realm</realm-name>
    <form-login-config>
        <form-login-page>/auth/login.html</form-login-page>
        <form-error-page>/auth/error.html</form-error-page>
    </form-login-config>
</login-config>

Long story short, if user accesses a protected/* url, the login page is included in the response. So instead of the content the user expects he will get the login page configured in the form-login-page tag. If the password is OK he will be forwarded (302 Paged Moved Permanently) to the initially requested protected/* url. If password is NOK, the user will be forwarded (302 Paged Moved Permanently) to the error page.

Advantages

  1. Personalized login page - this one seems to be the most popular :)
  2. Logoff is easy to implement. One needs only invalidate the HttpSession or call the request.logout() method (Servlet 3.0).
  3. Session timeouts
  4. IF and ONLY If you accept having a separate page for login than this is the solution for you.

Disadvantages

  1. REST unfriendly (I'm not going to dig in the phylosophy of rest and the keeping server-side state is not RESTful debate. We're analyzing REST authentication in a JAVA EE way and server side state is always maintained for any authenticated subject). What is really bad about using FORM authentication is the fact that one cannot have consistent behavior across browsers. And it's all due to the 302 redirection which some browsers handle in AJAX response functions while others redirect the entire page (change URL in navigation bar). More details here and here. You cannot work around that 302 redirect so no FORM and REST authentication for you mister !!

3. Programmatic authentication

Set up a URL for authentication. Behind that URL you can have a servlet which instantiates a login module (JAAS way) and calls the HttpServletRequest.login(user,pass) method along with the credentials. It should generate a 401/403 response if login fails.

You can implement it by just specifying the security-constraints in your web.xml:

<security-constraint>
     <web-resource-collection>
        <web-resource-name>admin</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
     </web-resource-collection>
     <auth-constraint>
        <role-name>admin</role-name>
     </auth-constraint>
</security-constraint>

On the server side you simply need to set up a RESTFul service which authenticates a caller. Here is some sample code:

@Path("/auth")
@ApplicationPath("/rest")
public class AuthenticationRestFacade {

@POST
@Path("/login")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public User login(User loginInfo, @Context HttpServletRequest request) throws LoginException, ServletException {

    // nasty work-around for Catalina AuthenticatorBase to be able to 
    // change/create the session cookie 
    request.getSession();
    request.login(loginInfo.getName(), loginInfo.getPassword());

Advantages

  1. Personlized login page.
  2. AJAX/REST compatible
  3. Logout URL ( if a URL is set up to do so )
  4. Session timeouts ( container managed )
  5. You can return login data (username,email,roles,groups,etc.) in the response ( reaaaallly nice because you don't have to do another call after a successful login )

Disadvantages

  1. Needs a some bit of code writing.
  2. Needs the application to be able to handle 401/403 responses and display login window

To conclude, the best viable options :

  1. If you don't care about session timeouts or logouts --> DIGEST
  2. If the above does not work for you AND you don't needto have an embedded login page (or a modal panel-like page) and you are fine with one single page for authentication --> FORM
  3. If the above does not work for you and you want all the flexibility and the compatibility in the world go with the PROGRAMMATIC approach. You have to define login/logout URL and also your client code should be able to cope with 401/403 responses (not easy).

Really looking forward for you guys to suggest some viable alternative solutions. Because right now I would HATE to go with the PROGRAMMATIC approach

like image 858
victor Avatar asked May 23 '13 10:05

victor


People also ask

How do I authenticate a RESTful web service?

Use of basic authentication is specified as follows: The string "Basic " is added to the Authorization header of the request. The username and password are combined into a string with the format "username:password", which is then base64 encoded and added to the Authorization header of the request.

Which authentication is best for REST API?

OAuth (specifically, OAuth 2.0) is considered a gold standard when it comes to REST API authentication, especially in enterprise scenarios involving sophisticated web and mobile applications. OAuth 2.0 can support dynamic collections of users, permission levels, scope parameters and data types.

What is Java EE security standards?

Java EE security services provide a robust and easily configured security mechanism for authenticating users and authorizing access to application functions and associated data at many different layers. Java EE security services are separate from the security mechanisms of the operating system.


1 Answers

In my experience, it is hard to implement a system using Java EE authentication and authorisation service that would work for both REST services and Server side MVC like JSP or JSF at the same time. All my experience are leaning towards using Form based authentication for the MVC part and some sort of token authentication (OAuth, Kerberos, LTPA) for REST services. Using Form or Basic authentication for REST services was usually challenging to implement, although we did it and it works fine on two projects.

It also depends on the preferred server implementation.

like image 200
JernejZ5 Avatar answered Nov 15 '22 16:11

JernejZ5