Dynamic authentication
kresho May 9, 2005 7:25 AMMy application has an ejb 2.1 timer, which triggers some work. The work must be done using the same principal that requested the work. So, I start the timer with an info object that contains the principal's login and password. When the timer expires, I try to authenticate using principal data from the info object, and run the task. I understand that it is not possible to change principal during execution of a business method, so I use the same code that I use on the client to authenticate, create a new bean and run it's methods, thus making the ejbTimeout method a client to the container. Here is the code:
public void ejbTimeout(Timer timer) { final OptInfo info = (OptInfo)timer.getInfo(); try { Properties p = new Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.LoginInitialContextFactory"); p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); p.put(Context.PROVIDER_URL, "jnp://localhost:1099"); p.put(Context.SECURITY_PRINCIPAL, info.user.username); p.put(Context.SECURITY_CREDENTIALS, info.user.password); p.put(Context.SECURITY_PROTOCOL, "client-login"); InitialContext ctx = new InitialContext(p); Object home = ctx.lookup(WalkOptimizerHome.JNDI_NAME); WalkOptimizerHome optimizerHome = (WalkOptimizerHome)PortableRemoteObject.narrow(home, WalkOptimizerHome.class); WalkOptimizer optimizer = optimizerHome.create(); optimizer.runOptimization(info); } catch (NamingException e) { Category.getInstance("WalkOptimizer").error("login failed (naming): " + e.getMessage()); (remote): " + e.getMessage()); } catch (CreateException e) { Category.getInstance("WalkOptimizer").error("login failed (create): " + e.getMessage()); } catch (SessionException e) { Category.getInstance("WalkOptimizer").error("login failed (session): " + e.getMessage()); } }
Notice that I don't use the default InitialContext with properties supplied from the container, but force properties that would make the lookup be executed over the network. I also use the WalkOptimizer bean over the remote home and interface, hoping to hide the fact that these calls come from within the container. However, every time I get this in the log:
2005-05-09 12:55:25,803 ERROR [WalkOptimizer] login failed (remote): SecurityException; nested exception is: java.lang.SecurityException: Insufficient method permissions, runAsPrincipal=ejbTimeout, method=create, interface=HOME, requiredRoles=[admin], runAsRoles=[ejbTimeout]
I understand this means that the create call was made over the network (interface=HOME not LOCALHOME), but JBoss still communicated the current principal (ejbTimeout) behind my back, no matter what I specify in the InitialContext properties.
My core intention to postpone some work, but the work must still be executed by a principal that represents a logged-in user. Maybe this is a completely wrong approach - in this case please don't bother with my code, but point me in the correct direction.
I have carefully studied posts with similar titles, and all I see is some static security configuration that will make ejbTimeout or onMessage execute as some static principal, but this is not what I need.