In my grails cxf-client-demo project I needed a way to test if the simple username token authentication wss4j interceptors were working. I looked around the web for help on how to inject an inbound security interceptor into the grails cxf plugin. I found some example on how to do this with cxf 2.3.x versions, but when I was recently helping update the grails cxf plugin to use cxf 2.5.2, I found out they changed the way that username token was done.
Apache Cxf Security
All I have to say is good luck with using the sample code from the apache cxf security docs. Their code for 2.5.x is lacking and the code provided didn’t work and caused me a lot of ???? moments.
The cxf plugin wires up service factories that will match the name of your exposed service such as secureService with bean named secureServiceFactory. You will want to inject any interceptors onto that factory during application boot. For the following examples I use the BootStrap.groovy to inject these.
Grails Cxf Interceptor Injection 2.3.x
This is the “old” way of adding simple token authentication with 2.3.x.
Since the new apache cxf 2.4.x and 2.5.x use a Validator instead of the callback, here is how you would now inject that same check into the same service factory. I am using an anonymous UsernameTokenValidator class just like the anonymous callback in the previous example.
importorg.apache.cxf.ws.security.wss4j.WSS4JInInterceptorimportorg.apache.ws.security.WSConstantsimportorg.apache.ws.security.WSSecurityEngineimportorg.apache.ws.security.WSSecurityExceptionimportorg.apache.ws.security.handler.WSHandlerConstantsimportorg.apache.ws.security.validate.UsernameTokenValidatorimportorg.apache.ws.security.validate.Validatorimportjavax.xml.namespace.QNameclassBootStrap{defsecureServiceFactorydefinit={servletContext->Map<String,Object>inProps=[:]inProps.put(WSHandlerConstants.ACTION,WSHandlerConstants.USERNAME_TOKEN);inProps.put(WSHandlerConstants.PASSWORD_TYPE,WSConstants.PW_TEXT);Map<QName,Validator>validatorMap=newHashMap<QName,Validator>();validatorMap.put(WSSecurityEngine.USERNAME_TOKEN,newUsernameTokenValidator(){@OverrideprotectedvoidverifyPlaintextPassword(org.apache.ws.security.message.token.UsernameTokenusernameToken,org.apache.ws.security.handler.RequestDatadata)throwsorg.apache.ws.security.WSSecurityException{if(data.username=="wsuser"&&usernameToken.password=="secret"){println"username and password are correct!"}else{println"username and password are NOT correct..."thrownewWSSecurityException("user and/or password mismatch")}}});inProps.put(WSS4JInInterceptor.VALIDATOR_MAP,validatorMap);secureServiceFactory.getInInterceptors().add(newWSS4JInInterceptor(inProps))}defdestroy={}}
Conclusion
My frustrations really only apply to the username token authentication issue, but I haven’t tried getting the certificate or ldap authentication working on the server side in 2.5.2 yet. In general if you need in or out logging or security interceptors on your cxf plugin exposed services, the above mentioned is a pretty good way to get them on there. What you put into the properties of those interceptors to make them work is on you. Good Luck!