javasoapcxfmoxy

Aache-CXF WS client with eclipse MOXY JAXBContextFactory doesn't send security header


I use Apache-CXF WS for SOAP client. Side SOAP endpoint has security (username/password) requirement. Also I use org.eclipse.persistence.eclipselink for changing an JAXBContextFactory, because default factory generates redundant namespaces in request.

With default JAXB client sends username token in header:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  
  <soap:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soap:mustUnderstand="1">
      <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-5ec36563-1289-4272-a820-2df93385246a">
        <wsse:Username>username</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soap:Header>

  <soap:Body>
   ...
  </soap:Body>
</soap:Envelope>

But with MOXY JAXBContextFactory client doesn't send security header:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  >> NO HEADER <<

  <soap:Body>
    ...
  </soap:Body>
</soap:Envelope>

I tried to find some info in documentation, but no success.

My CXF SOAP client configuration:

<jaxws:client id="side_service_client"
        wsdlLocation="side_service.wsdl"
        serviceClass="com.example.SideService"
        address="${side_service_url}"
        xmlns:bfns="http://www.example.com/side_service/"
        serviceName="bfns:side_service">

        <jaxws:properties>
            <entry key="security.username" value="${sideServiceUsername}"/>
            <entry key="security.password" value="${sideServicePassword}"/>
            <entry key="schema-validation-enabled" value="false"/>
        </jaxws:properties>
</jaxws:client>

Apache CXF version - 3.4.10 org.eclipse.persistence.eclipselink version - 2.6.9

Maybe someone has already encountered such a problem and knows the direction of the solution?

Thankls for any answers =)


Solution

  • I was found solution for my question.

    1. Add cxf-rt-ws-policy dependency to my project:
    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-ws-policy</artifactId>
       <version>${apache.cxf.version}</version>
    </dependency>
    
    1. Created and added out interceptor:

    ServerPasswordCallback.java

    package com.your.domain.configuration;
    
    import java.io.IOException;
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    import org.apache.wss4j.common.ext.WSPasswordCallback;
    
    /**
     * Setup username token to outbound message manually.
     */
    public class ServerPasswordCallback implements CallbackHandler {
    
        @Override
        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
            pc.setPassword("YOUR_PASSWORD_VALUE");
        }
    }
    

    springAppContext.xml

    ...
    <bean id="myPasswordCallback" class="com.your.domain.configuration.ServerPasswordCallback"/>
    
    <jaxws:client id="some_client"
           wsdlLocation="some_client.wsdl"
           serviceClass="com.your.domain.ServiceClass"
           address="${addressUrl}">
    
           ...
    
           <jaxws:outInterceptors>
                <bean id="securityInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
                    <constructor-arg>
                        <map>
                            <entry key="action" value="UsernameToken"/>
                            <entry key="passwordType" value="PasswordText"/>
                            <entry key="user" value="YOUR_USERNAME"/>
                            <entry key="passwordCallbackRef" value-ref="myPasswordCallback"/>
                        </map>
                    </constructor-arg>
                </bean>
            </jaxws:outInterceptors>
    
           ...
    
    </jaxws:client>
    ...