[[ws-security]]
= WS-Security

include::./includes/attributes.adoc[]

The CXF framework's https://cxf.apache.org/docs/ws-security.html[WS-Security] implementation is based on https://ws.apache.org/wss4j/user_guide.html[WSS4J]. The example below shows how to integrate with WSS4J using interceptors.

To use WSS4J interceptors in your code, you should first add the Quarkus CXF WS-Security dependency.

[source,xml,subs=attributes+]
----
<dependency>
      <groupId>io.quarkiverse.cxf</groupId>
      <artifactId>quarkus-cxf-rt-ws-security</artifactId>
      <version>{quarkus-cxf-version}</version>
</dependency>
----

NOTE: Currently, only the programmatic WSS4JInterceptors are supported. Actions like Timestamp, UsernameToken, Signature, Encryption, etc., can be applied to the interceptors by passing the appropriate configuration properties.

[[ws-security-service]]
== Web Service Integration

Use the `WSS4JInInterceptor` to add WS-Security to your web service. You can update your `application.properties` file to include:

[source,properties]
----
quarkus.cxf.endpoint."/greeting-service".in-interceptors=org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor
----

Add the following to your producer class to instantiate the `WSS4JInInterceptor`.

[source,java]
----
    @Produces
    @ApplicationScoped
    public WSS4JInInterceptor getWSS4JInInterceptor() {
        Map<String,Object> inProps = new HashMap<String,Object>();
        inProps.put(ConfigurationConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        inProps.put(ConfigurationConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        inProps.put(ConfigurationConstants.PW_CALLBACK_CLASS, UsernameTokenPasswordServerCallback.class.getName());
        return new WSS4JInInterceptor(inProps);
    }
----

Finally, a sample `UsernameTokenPasswordServerCallback` class is provided below. Please refer to the https://cxf.apache.org/docs/ws-security.html[WS-Security] and https://ws.apache.org/wss4j/user_guide.html[WSS4J] documentation for more advanced needs.

[source,java]
----
import org.apache.wss4j.common.ext.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@RegisterForReflection
public class UsernameTokenPasswordServerCallback implements CallbackHandler {

    private Map<String, String> passwords = new HashMap();

    public UsernameTokenPasswordServerCallback() {
        passwords.put("joe", "wss4j");
    }

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            WSPasswordCallback pc = (WSPasswordCallback) callback;
            String pass = passwords.get(pc.getIdentifier());
            if (pass != null) {
                pc.setPassword(pass);
                return;
            }
        }
    }
}
----

[[ws-security-client]]
== Client Integration

The corresponding client implementation would be slightly different.Use the `WSS4JOutInterceptor` to add WS-Security to your SOAP client.You can update your `application.properties` file to include:

[source,properties]
----
quarkus.cxf.client."greeting-client".out-interceptors=org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor
----

Add the following to your producer class to instantiate the `WSS4JOutInterceptor`.

[source,java]
----
    @Produces
    @ApplicationScoped
    public WSS4JOutInterceptor getWSS4JOutInterceptor() {
        Map<String,Object> outProps = new HashMap<String,Object>();
        outProps.put(ConfigurationConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        outProps.put(ConfigurationConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        outProps.put(ConfigurationConstants.PW_CALLBACK_CLASS, UsernameTokenPasswordClientCallback.class.getName());
        outProps.put(ConfigurationConstants.USER, "joe");
        return new WSS4JOutInterceptor(outProps);
    }
----

Finally, a sample `UsernameTokenPasswordClientCallback` class is provided below. Please refer to the https://cxf.apache.org/docs/ws-security.html[WS-Security] and https://ws.apache.org/wss4j/user_guide.html[WSS4J] documentation for more advanced needs.

[source,java]
----
import org.apache.wss4j.common.ext.WSPasswordCallback;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;

@RegisterForReflection
public class UsernameTokenPasswordClientCallback implements CallbackHandler {

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            WSPasswordCallback wpc = (WSPasswordCallback) callback;
            if (wpc.getIdentifier().equals("joe")) {
                wpc.setPassword("wss4j");
                return;
            }
        }
    }
}
----

[[ws-security-native-mode]]
== Native Mode Support

Native mode is supported for WS-Security when implemented using the `quarkus-cxf-rt-ws-security` module as shown above.  This module will package the necessary libraries to compile a native executable successfully.