If you have followed my Eclipse / GlassFish / Java EE 6 Cookbook, you have seen one single section, where the sample code was only sketched and never compiled. This was the “hypothetical security interceptor”. And of course when one writes down code from memory, it is invariably buggy.
Last week I wanted to use the code as base of the security interceptor of a system that we just develop, naturally it crashed, and it did so in a not exactly obvious way, thus I thought I should give you an update.
The security interceptor as shown in the cookbook is not really what I would use anyway, and I intend to write a follow-up tutorial explaining some of the things that I learned during our current project. There you will find a more detailed discussion of access control, and along with it, a more useful SecurityInterceptor.
Until that point, let me show you what the problem with the original code was. Here it is:
@Interceptor @Stateless public class SecurityInterceptor { @EJB SecurityEao sec; @EJB SecurityGuard guard; @AroundInvoke public Object intercept(InvocationContext ctx) throws Exception { Map<String, Object> contextData = ctx.getContextData(); Map<String, String> headers = contextData.get("javax.xml.ws.http.request.headers"); String secKey = headers.get("X-Portal-SecKey"); if (secKey == null) { throw new SecurityNoKeyException(); } SecInfo secInfo = eao.secInfoBySecKey(secKey); Method invokedMethod = ctx.getMethod(); if (guard.isInvocationForbidden(invokedMethod, secInfo)) { throw new SecurityViolationException(); } return ctx.proceed(); } } |
The wrong assumption is that contextData.get("javax.xml.ws.http.request.headers"); yields a Map<String, String>. That’s wrong, but it compiles. The method really yields a Map<String, List<String>>, because you can have more than one header of a certain name. Thus the correct code is something like
@Interceptor @Stateless public class SecurityInterceptor { @EJB SecurityEao sec; @EJB SecurityGuard guard; @SuppressWarnings("unchecked") @AroundInvoke public Object intercept(InvocationContext ctx) throws Exception { Map<String, Object> contextData = ctx.getContextData(); Map<String, List<String>> headers = (Map<String, List<String>>) contextData.get("javax.xml.ws.http.request.headers"); List<String> secCredentials = headers.get("X-Portal-Credentials"); if (secCredentials == null || secCredentials.isEmpty()) { throw new SecurityNoCredentialsException(); } SecInfo secInfo = sec.secInfoBySecCredentials(secCredentials); Method invokedMethod = ctx.getMethod(); if (!guard.isInvocationAllowed(invokedMethod, secInfo)) { throw new SecurityViolationException(); } return ctx.proceed(); } } |
I have already updated the tutorial.
