Search code examples
apache-cameljettycxfjbossfuseblueprint-osgi

What is the correct way of setting up Basic Authentication for CXF/HTTP in JBoss Fuse?


I have been trying for quite some time now to set up Basic Authentication for all of my exposed web services but without any luck.

I am using JBoss Fuse 6.2.1 with the Karaf container (karaf-2.4.0.redhat-621117) and I currently have three integrations that are consuming from an equal amount of cxfEndpoints.

What I want to achieve is to prompt the users of said services with an auth-dialog when either calling the services or trying to view the WSDL. Note that I don't want to use ws-security which places the authentication in the Soap-envelope but rather on http-level.

I have been looking at the following documentation entries: [1]https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.2.1/html/Security_Guide/CamelJetty-BasicAuth.html

[2]http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html

[3]http://cxf.apache.org/docs/jetty-configuration.html

But I am confused as to which (if any) of these approaches I'm supposed to use. In fact, none of them has worked for me so far but that might be down to a user error on my behalf.

Below I will show what I have tried (and subsequently failed) to do:

Using a mix of [1] and [3]

blueprint.xml:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
    xmlns:cxf-core="http://cxf.apache.org/blueprint/core"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
    xsi:schemaLocation="
        http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd
        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/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">

    <bean id="loginService" class="org.eclipse.jetty.plus.jaas.JAASLoginService">
        <property name="name" value="karaf"/>
        <property name="loginModuleName" value="karaf"/>
        <property name="roleClassNames">
            <list>
                <value>org.apache.karaf.jaas.boot.principal.RolePrincipal</value>
            </list>
        </property>
    </bean>

    <bean id="identityService" class="org.eclipse.jetty.security.DefaultIdentityService"/>

    <bean id="constraint" class="org.eclipse.jetty.util.security.Constraint">
        <property name="name" value="BASIC"/>
        <property name="roles" value="Administrator"/>
        <property name="authenticate" value="true"/>
    </bean>

    <bean id="constraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
        <property name="constraint" ref="constraint"/>
        <property name="pathSpec" value="/*"/>
    </bean>

    <bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler">
        <property name="authenticator">
            <bean class="org.eclipse.jetty.security.authentication.BasicAuthenticator"/>
        </property>
        <property name="constraintMappings">
            <list>
                <ref bean="constraintMapping"/>
            </list>
        </property>
        <property name="loginService" ref="loginService"/>
        <property name="strict" value="false"/>
        <property name="identityService" ref="identityService"/>
    </bean>

    <httpj:engine-factory bus="cxf">
        <httpj:engine port="8181">
            <httpj:handlers>
                <ref component-id="securityHandler" />
            </httpj:handlers>
        </httpj:engine>
     </httpj:engine-factory>

</blueprint>

Using [2]

blueprint.xml:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
    xmlns:cxf-core="http://cxf.apache.org/blueprint/core"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
    xsi:schemaLocation="
        http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
        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/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">

    <http-conf:conduit name="http://localhost:8181/.*" xmlns:sec="http://cxf.apache.org/configuration/security">
        <http-conf:authorization>
            <sec:UserName>test</sec:UserName>
            <sec:Password>test</sec:Password>
            <sec:AuthorizationType>BASIC</sec:AuthorizationType>
        </http-conf:authorization>
    </http-conf:conduit>

</blueprint>

The cxfEndpoint used in both cases

<cxf:cxfEndpoint address="${address}" id="myWs" serviceClass="com.company.test.CxfService">
    <cxf:properties>
        <entry key="dataFormat" value="PAYLOAD" />
    </cxf:properties>
</cxf:cxfEndpoint>

The optimum would be to be able to leverage the JAAS but I would settle for something simpler to start with.

I should add that I'm not getting any errors with any of these, I'm just not being prompted to provide any credentials either when browsing http://localhost:8181/cxf or when calling the services through SoapUI.

I would greatly appreciate if someone could point me in the right direction.


Solution

  • I managed to find a viable solution so I'll post my findings with the hope that someone else will be helped by this at some point.

    blueprint.xml:

    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
        xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
        xmlns:cxf-core="http://cxf.apache.org/blueprint/core"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
        xsi:schemaLocation="
            http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd
            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/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
    
        <bean id="loginService" class="org.eclipse.jetty.plus.jaas.JAASLoginService">
            <property name="name" value="karaf"/>
            <property name="loginModuleName" value="karaf"/>
            <property name="roleClassNames">
                <list>
                    <value>org.apache.karaf.jaas.boot.principal.RolePrincipal</value>
                </list>
            </property>
        </bean>
    
        <bean id="identityService" class="org.eclipse.jetty.security.DefaultIdentityService"/>
    
        <bean id="constraint" class="org.eclipse.jetty.util.security.Constraint">
            <property name="name" value="BASIC"/>
            <property name="roles">
                <list>
                    <value>admin</value>
                </list>
            </property>
            <property name="authenticate" value="true"/>
        </bean>
    
        <bean id="constraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
            <property name="constraint" ref="constraint"/>
            <property name="pathSpec" value="/*"/>
        </bean>
    
        <bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler">
            <property name="authenticator">
                <bean class="org.eclipse.jetty.security.authentication.BasicAuthenticator"/>
            </property>
            <property name="constraintMappings">
                <list>
                    <ref component-id="constraintMapping"/>
                </list>
            </property>
            <property name="loginService" ref="loginService"/>
            <property name="strict" value="false"/>
            <property name="identityService" ref="identityService"/>
        </bean>
    
        <httpj:engine-factory bus="cxf">
            <httpj:engine port="8083">
                <httpj:handlers>
                    <ref component-id="securityHandler" />
                </httpj:handlers>
            </httpj:engine>
        </httpj:engine-factory>
    
        <cxf:cxfEndpoint address="http://localhost:8083/MyService" id="myWs" serviceClass="com.company.test.CxfService">
            <cxf:properties>
                <entry key="dataFormat" value="PAYLOAD" />
            </cxf:properties>
        </cxf:cxfEndpoint>
    
        ...
    
    </blueprint>
    

    It is also necessary to add the following to the pom.xml:

    <Import-Package>
        javax.security.auth,
        javax.security.auth.callback,
        javax.security.auth.login,
        javax.security.auth.spi,
        org.apache.karaf.jaas.modules,
        org.apache.karaf.jaas.boot.principal,
        org.eclipse.jetty.server,
        org.eclipse.jetty.plus.jaas;version=${jetty-version},
        org.eclipse.jetty.security;version=${jetty-version},
        *
    </Import-Package>
    

    org.eclipse.jetty.server is needed for the httpj:engine-factory to work. It would seem that you're not able to use the default port (8181) if you want to setup Basic Authentication. This solution instead sets up a custom jetty container on port 8083 (you can use a different port, just make sure that your cxfEndpoints are published on the same one.)