Search code examples
web-servicesapache-camelcxfapache-karafpax-web

Camel cxf pax-web Handle WS-Security Username token


I'm implementing a web service using camel cxf to be deployed in Karaf. I'm using the pax web that comes with karaf. I'm using the cxf codegen plugin in pom to do wsdl to java.

I'm defining the cxf uri and the routes in the RouteBuilder Java DSL. The blueprint.xml only has some beans and ref to the RouteBuilder.

final String cxfUri =
            String.format("cxf:%s?serviceClass=%s&wsdlURL=wsdl/Event.wsdl",
                    "/Event.jws", com.example.EventPortType.class.getCanonicalName());

I have setup ssl with the pax-web(jetty.xml). If i send the WSSE security headers with username and password, it generates a MustUnderstand soap fault.

<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" S:mustUnderstand="1">
  <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Id-LdZa8aaGdy7mWQWXLp_zpbfg">
    <wsse:Username>xxx</wsse:Username>
    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">xxx</wsse:Password>
  </wsse:UsernameToken>
</wsse:Security>

The input request cannot be changed. I get this exception.

<soap:Fault>
     <faultcode>soap:MustUnderstand</faultcode>
     <faultstring>MustUnderstand headers: [{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood.</faultstring>
  </soap:Fault>

How can i secure the cxf endpoint to authenticate the request?

Thank you.


Solution

  • you need to add a WSS4J interceptors to the exposed CXF service. You can provide your own PasswordCallback for the user validation, but I prefer to leverage the native JAAS. This is a blueprint example requiring the UsernameToken with any Karaf user (this is for exposing a camel-cxf routes, however the same principle applies to the pure CXF implementation). If you prefer Java based Camel route builders, you may add the interceptor beans to the context registry to use them. But - the blueprint (or spring config) allows you to more fine-grained control than simple endpoint parameters.

    <?xml version="1.0" encoding="UTF-8"?>
        <blueprint 
            xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns:cxf="http://cxf.apache.org/blueprint/core" 
            xmlns:camelcxf="http://camel.apache.org/schema/blueprint/cxf" 
            xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0" 
            xmlns:jaxws="http://cxf.apache.org/blueprint/jaxws"
            xsi:schemaLocation="
                http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
                http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd http://camel.apache.org/schema/blueprint 
                http://camel.apache.org/schema/blueprint/camel-blueprint.xsd http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0
                http://svn.apache.org/repos/asf/aries/trunk/blueprint/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd 
                http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
                http://cxf.apache.org/blueprint/jaxws       http://cxf.apache.org/schemas/blueprint/jaxws.xsd
                http://camel.apache.org/schema/blueprint/cxf http://camel.apache.org/schema/cxf/camel-cxf-2.7.5.xsd">
    
      <bean id="authenticationInterceptor" class="org.apache.cxf.interceptor.security.JAASLoginInterceptor">
                <property name="contextName" value="karaf"/>
                <property name="roleClassifier" value="RolePrincipal"/>
                <property name="roleClassifierType" value="classname"/>        
            </bean>
    
            <bean id="wsSecInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
                <argument>
                    <map>
                        <entry key="action" value="UsernameToken"/>
                        <entry key="passwordType" value="PasswordText"/>
                    </map>
                </argument>
            </bean>     
    
            <!-- ================  Apache Camel impl ======================= -->
             <camelcxf:cxfEndpoint id="testService2" 
                              address="/api/2.0/external/TestService"
                              xmlns:apogado="http://test.ws.apogado.com/v1_0/ws"
                              endpointName="apogado:AddressServicePort"
                              serviceName="apogado:AddressService"    
                              wsdlURL="classpath:/xsd/ws/TestService.wsdl"
        >
    
            <camelcxf:properties>
                <entry key="dataFormat" value="PAYLOAD" /> 
                <entry key="ws-security.ut.no-callbacks" value="true"/>
                <entry key="ws-security.validate.token" value="false"/>  
            </camelcxf:properties>  
            <camelcxf:inInterceptors>
                <ref component-id="wsSecInterceptor" />
                <ref component-id="authenticationInterceptor"/>  
            </camelcxf:inInterceptors>
            <camelcxf:features> 
            </camelcxf:features>
        </camelcxf:cxfEndpoint>
    
     <camelContext xmlns="http://camel.apache.org/schema/blueprint" id="testWsCtx" trace="true">
       <!-- your service implementation -->
       <route>
          <from uri="testService2" />
          <to uri="..." />
       <route>
    </camelContext>
     </blueprint>