9

I want to pass authentication information to EJB stateless session beans when calling their methods from a Java web application (Wicket). The information consists of a user id and an authentication type (remember cookie or user/password) and is stored in the http session. One obvious solution is to add this as a parameter to all EJB methods, but this is cumbersome and I hope another solution exists.

The JNDI lookup of EJB beans is done via javax.naming.InitialContext#lookup(String) in the web tier.

Is there a portable way to add the authentication information to a calling context so it becomes available to the beans? I need this process to be available for callers both in the EJB layer (for an eventual web service endpoint) and in the web tier.

Some more information

I am using Java EE 6. CDI is not used and I would rather avoid implementing it.

Authentication is handled by the web tier with stateless beans validating remember cookies and user/password combinations. When a visitor first accesses the site, authentication with the remember cookie is tried. When eventually required, the user is asked to login with a username and password. As mentioned above, the authentication status is stored in the http session. I don’t use the Java EE security model based on realms because I couldn’t figure out how this authentication flow could be properly integrated.

The authorization scheme is based on dynamic roles similar to how Facebook determines authorization based on the link between 2 users and some preferences. Some actions also take into account the authentication type. For instance, modifying account settings requires user/password and the cookie is not enough. From what I understood, the Java EE standard groups and roles are not a good fit for this requirement.

Other related questions I found

EJB3 & How JAAS subject/principal is propagated to EJB Tier from servlet container?

Controlling the security Principle passed on a EJB call

Binding a User entity and a GlassFish Principal

Accessing the clients principal inside an ejb method

dynamic roles on a Java EE server

I hope my question is clear enough. If more information is required, I will gladly provide it.

edit

Fixed links. Add note about CDI.

Community
  • 1
  • 1
bernie
  • 8,077
  • 4
  • 45
  • 78
  • http://www.adam-bien.com/roller/abien/entry/how_to_pass_context_with describes an approach using thread local storage for sharing context information between layers. However, I am concerned that clustering and asynchronous method invocations will be problematic with such an approach. – bernie Nov 07 '11 at 17:04

1 Answers1

9

I think you should consider:

  1. Creating an interceptor for the authorization process. It will give you a common place for authorization despite from which layer the call was made from. You might check if the caller is allowed to invoke the method or if his session is still active (i.e. check it in the DB).

  2. In the interceptor you could pass some user-related data using InvocationContext#getContextData().put("user-related-data-name", someObj). In the caller EJB you can get this data using SessionContext#getContextData().

An example of passing contextual data using SessionContext can be found here

The last (and most interesting part) would be how to get the user credentials on the EJB layer. If you're saying about WebServices endpoint than I guess you need to provide some kind of boundary class or specify a methods which will take some sessionId for each call.

If it's about propagating HttpSession data from the Servlet to the EJB... It might be a long shot but I would think of using the CDI. Your Servlet might use a @SessionScoped bean which holds the user credentials and you inject the same @SessionScoped bean inside the interceptor.

I'm not sure if it's possible at all (injecting CDI beans in the interceptors or sharing @SessionScoped between Servlets and EJB's layers).

Piotr Nowicki
  • 16,436
  • 8
  • 54
  • 79
  • (Had to split my reply in 3...) Regarding 2, that is a good idea especially if I can pass context information without a method argument. Otherwise, I would have to use reflection on the argument list to find which one contains the auth info. – bernie Nov 07 '11 at 16:57
  • Regarding 1, there is one problem with interceptors though and a method signature like `removeTransaction(AuthenticationInfo authInfo, long personId, long transactionId)`. In this case, the authorization is dependant on `personId` but the interceptor does not obtain argument names but only argument types. Therefore, its only way to know whether to use argument #2 or #3 is to add meta-data somewhere which can get out of sync with the method declaration. This is not the case if the authorization is done as a method call in the body of `removeTransaction`. – bernie Nov 07 '11 at 17:01
  • As for CDI, I don’t currently use it and my perception of its lack of maturity, especially with regards to integration with my web framework (Wicket), doesn’t make me want to make the switch. I might be wrong however. Nevertheless, your idea is certainly an interesting one however. It allowed me to find http://stackoverflow.com/questions/2607019/threadlocal-and-singleton-in-ejb-container which gives some more insight. – bernie Nov 07 '11 at 17:01
  • AD 2. yes - AFAIR - it can be added without specyfing additional method parameters. AD 1. well, if you're afraid about that I can think of using custom annotation like @AuthorizationData; than in interceptor you could use InvocationContext#getMethod()#getParameterAnnotations(), then search for the parameter which has @AuthorizationData assigned and this will be the number of the parameter you want to get. – Piotr Nowicki Nov 07 '11 at 23:51
  • In my first reply, I was referring to the possibility of adding the context information for EJB method calls from the web layer. Your proposed solution with CDI might work, but it is not applicable for my case unfortunately. – bernie Nov 08 '11 at 13:54
  • I'll accept your answer since it's the closest to what I wanted. – bernie Nov 15 '11 at 16:13
  • Thanks @bernie. I have this marked as a 'favorite' as I wanted to do some spike-solution when I'll have some spare time. – Piotr Nowicki Nov 15 '11 at 16:53
  • 1
    @Bernie, I've added link to the page where I've shown how contextData could be used. Hope it'll be of any help to you. – Piotr Nowicki Nov 23 '11 at 18:03