Search code examples
javacxfjax-wscdiws-security

How to inject @AppConfigProperty in CallbackHandler of WSS4JOutInterceptor


For context: I have to make a call to one of our webservices(internal call from a batchjob) and pass in the username and password required(the webservice is protected with WS-Security)

My goal is to be able to inject the value of "username" into my InternalServicePasswordCallback(classname passed to WSS4JOutInterceptor) but the injected field is null. Injecting the same property works in another class managed by CDI.

This is most of the class that I'm trying to inject into, it contains no other constructors or public fields.

public class InternalServicePasswordCallback implements CallbackHandler {
    private static final String APP_PROPERTIES = "app.properties";
 
    @Inject
    @AppConfigProperty("USERNAME")
    private String username;
 
    public InternalServicePasswordCallback() {}
 
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {for (Callback callback : callbacks) {
        WSPasswordCallback wpc = (WSPasswordCallback) callback;
            if (wpc.getIdentifier().equals(properties.get(username))) {
                wpc.setPassword((String) properties.get(somepass));
                return;
            }
        }
}

I'm passing the InternalServicePasswordCallback class to the WSS4JOutInterceptor interceptor. And im testing by deploying the jboss application to my local server.

private void setEndPoint(Object port, String endPoint) {      
    BindingProvider bp = (BindingProvider) port;
    bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endPoint);
    Client client = ClientProxy.getClient(port);
     
    Map<String, Object> props = new HashMap<>();
    props.put(ConfigurationConstants.ACTION, ConfigurationConstants.USERNAME_TOKEN);
    props.put(ConfigurationConstants.PASSWORD_TYPE, WSS4JConstants.PW_TEXT);
    props.put(ConfigurationConstants.PW_CALLBACK_CLASS, InternalServicePasswordCallback.class.getName());
    props.put(ConfigurationConstants.USER, user);
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props);
    Endpoint endpoint = client.getEndpoint();
    endpoint.getOutInterceptors().add(wssOut);
     
    client.getOutInterceptors().add(new LoggingOutInterceptor(-1));
    client.getInInterceptors().add(new LoggingInInterceptor(-1));
}

Frameworks/tools used:

  • Application container/server: jboss-eap-7.3
  • Apache CXF version: 3.3.9
  • Java version: OpenJDK 11
  • Jakarta EE version:jakarta.enterprise.cdi-api:2.0.2.redhat-00002

My assumption is that jboss/weld CDI does not take care of the instantiation of the InternalServicePasswordCallback class and thus cant inject other managed beans into it, am I correct?

Thank you for your time!


Solution

  • The solution for me was to create a callback handler where I pass the username and password.

    After reading this article, I've created the UserToken Password callback handler class(client side) and updated the client code and configured the "out" interceptor(client side) where I specified the type of authentication.

    public class UTPasswordCallback implements CallbackHandler {
     
        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                WSPasswordCallback wpc = (WSPasswordCallback) callback;
                if (wpc.getIdentifier().equals("cxf")) {
                    wpc.setPassword("cxf");
                    return;
                }
            }
        }
    }
    
    public class HWClient {
     
        public static void main(String[] args) {
            HelloWorldService service = new HelloWorldService();
            HelloWorld hw = service.getHelloWorldPort();
             
            Client client = ClientProxy.getClient(hw);
            Endpoint endpoint = client.getEndpoint();
     
            Map props = new HashMap();
            props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
            props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
            props.put(WSHandlerConstants.PW_CALLBACK_CLASS, UTPasswordCallback.class.getName());
            props.put(WSHandlerConstants.USER, "cxf");
             
            WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props);
            endpoint.getOutInterceptors().add(wssOut);
        }
    }