How to set WS-SecurityPolicy in an inbound CXF service in Mule? - cxf

When configuring the service for handling UsernameToken and signatures, it's setup like this:
<service name="serviceName">
<inbound>
<cxf:inbound-endpoint address="someUrl" protocolConnector="httpsConnector" >
<cxf:inInterceptors>
<spring:bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<spring:bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<spring:constructor-arg>
<spring:map>
<spring:entry key="action" value="UsernameToken Timestamp Signature" />
<spring:entry key="passwordCallbackRef" value-ref="serverCallback" />
<spring:entry key="signaturePropFile" value="wssecurity.properties" />
</spring:map>
</spring:constructor-arg>
</spring:bean>
</cxf:inInterceptors>
</cxf:inbound-endpoint>
</inbound>
</service>
But how is it possible to create a policy of what algorithms that are allowed, and what parts of the message that should be signed?

You'd have to ask the Mule folks. Last I checked, they hadn't moved to CXF 2.2.x yet. If they ARE on 2.2.x, you could use the WS-SecPol support built into CXF.

Related

Apache Camel CXF - Error Illegal character ((CTRL-CHAR, code 31)

I have written a camel route that is basically a proxy for an https web service. Below is my route
Please note that the https service responds with gzip encoding !!
<camel:sslContextParameters id="sslContext">
<camel:trustManagers>
<camel:keyStore resource="certificates/cert.jks" type="jks"
password="test"/>
</camel:trustManagers>
</camel:sslContextParameters>
<cxf:cxfEndpoint id="source"
wsdlURL="wsdl/SampleService.wsdl"
serviceClass="com.sample"
address="http://localhost:9000/SampleService">
<cxf:properties>
<entry key="dataFormat" value="PAYLOAD"/>
</cxf:properties>
</cxf:cxfEndpoint>
<cxf:cxfEndpoint id="target"
wsdlURL="wsdl/target.wsdl"
serviceClass="com.sample1"
address="https://endpoint">
<cxf:properties>
<entry key="dataFormat" value="PAYLOAD"/>
</cxf:properties>
<cxf:features>
<bean class="org.apache.cxf.transport.common.gzip.GZIPFeature"/>
</cxf:features>
<cxf:inInterceptors>
<bean class="org.apache.cxf.transport.common.gzip.GZIPInInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean id="headerProcessor" class="com.sample.HeaderProcessor"/>
<bean id="defaultHostnameVerifier" class="com.sample.customHostNameVerifier"/>
<camel:camelContext xmlns="http://camel.apache.org/schema/spring" id="vediContext" streamCache="true">
<onException>
<exception>org.apache.cxf.binding.soap.SoapFault</exception>
<redeliveryPolicy maximumRedeliveries="0" redeliveryDelay="2000"/>
</onException>
<camel:route>
<camel:from uri="cxf:bean:source"/>
<camel:to uri="cxf:bean:target?sslContextParameters=#sslContext&hostnameVerifier=#defaultHostnameVerifier">
</camel:to>
</camel:route>
</camel:camelContext>
With this route, when I invoke the endpoint via SOAP UI, the first invocation is always successful, I get a valid response.
For any invocation after that, I always get the following exception :
<soap:Fault>
<faultcode xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">ns0:Client</faultcode>
<faultstring>Couldn't create SOAP message due to exception: XML reader error: com.ctc.wstx.exc.WstxUnexpectedCharException: Illegal character ((CTRL-CHAR, code 31))
at [row,col {unknown-source}]: [1,1]</faultstring>
</soap:Fault>
This issue was caused due to the payload size being pretty big. Raising another question to seek help around working with large SOAP payloads when working with Apache Camel.

cxf-rs-ws authorization under karaf

I'm trying to configure a cxf soap webservice with authorization and authentication to be deployed on Servicemix.
I configured the LDAP authentication module as follows:
<!-- Bean to allow the $[karaf.base] property to be correctly resolved -->
<ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
<jaas:config name="myRealm">
<jaas:module className="org.apache.karaf.jaas.modules.ldap.LDAPLoginModule" flags="required">
connection.url = ldap://srv-ldap:389
user.base.dn = ou=people,dc=intranet,dc=company,dc=com
user.filter = (uid=%u)
user.search.subtree = false
role.base.dn = ou=groups,dc=intranet,dc=company,dc=com
role.filter = (member:=uid=%u,ou=people,dc=intranet,dc=company,dc=com)
role.name.attribute = cn
role.search.subtree = true
authentication = simple
</jaas:module>
</jaas:config>
<service interface="org.apache.karaf.jaas.modules.BackingEngineFactory">
<bean class="org.apache.karaf.jaas.modules.properties.PropertiesBackingEngineFactory"/>
</service>
And here is the beans.xml file
<jaxws:endpoint id="myService"
implementor="com.myorg.services.impl.MyServiceWSImpl"
address="/myService">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
</map>
</constructor-arg>
</bean>
<ref bean="authenticationInterceptor" />
<ref bean="authorizationInterceptor" />
</jaxws:inInterceptors>
<jaxws:properties>
<entry key="ws-security.validate.token" value="false" />
</jaxws:properties>
</jaxws:endpoint>
<bean id="authenticationInterceptor"
class="org.apache.cxf.interceptor.security.JAASLoginInterceptor">
<property name="contextName" value="myRealm" />
</bean>
<bean id="authorizationInterceptor"
class="org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor">
<property name="securedObject" ref="securedBean"/>
</bean>
Finally, in my WebService implementation I annotated a method with #RolesAllowed.
#RolesAllowed("Role1")
public Department get(String name) throws IdMException {
return service.get(name);
}
The authentication interceptor is retrieving the user, authenticating it and retrieving the groups as RolePrincipal instances.
Then, in the authorization interceptor (SecureAnnotationsInterceptor), the method configuration is read, the expectedRoles are "Role1", but the SimpleAuthorizingInterceptor.isUserInRole method returns false.
I haven't found any example trying to do more or less the same and the few information I found was from the CXF documentation page http://cxf.apache.org/docs/security.html#Security-Authorization
I have to be missing something important, hope somebody could help me.
Thanks in advance and kind regards.
Your problem is because of Karaf's RolePricipal do not implements Group as CXF expected. Instead of it, it implements Pricipal so CXF thinks that 1st role name is a username. That is why "SimpleAuthorizingInterceptor.isUserInRole method returns false".
A solution is to wait for fixed versions of CXF (2.7.11 and 3.0.0).
If not possible to update to newer version, then an odd and temporary solution (simply workaround) is to add more than one role to a user in LDAP and to method.
You can find more about that bug here: CXF-5603

Number of requests in cxf service

I use mule CE 3.3.0. My project has the following:
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf" xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting"
xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:mule-ss="http://www.mulesoft.org/schema/mule/spring-security"
xmlns:ss="http://www.springframework.org/schema/security"
xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.3.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd
http://www.mulesoft.org/schema/mule/spring-security http://www.mulesoft.org/schema/mule/spring-security/3.3/mule-spring-security.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd ">
<global-property name="allowed" value="192.168.3.76,192.168.3.74,192.168.3.75" />
<configuration>
<expression-language>
<global-functions>
def parseIp(fullIp) {
return fullIp.substring(fullIp.indexOf('/') + 1, fullIp.indexOf(':'))
}
</global-functions>
</expression-language>
</configuration>
<http:connector name="httpConnector" doc:name="HTTP\HTTPS">
<service-overrides sessionHandler="org.mule.session.NullSessionHandler" />
</http:connector>
<mule-ss:security-manager>
<mule-ss:delegate-security-provider
name="memory-dao" delegate-ref="authenticationManager" />
</mule-ss:security-manager>
<spring:beans>
<ss:authentication-manager
xmlns:ss="http://www.springframework.org/schema/security" alias="authenticationManager">
<ss:authentication-provider>
<ss:user-service id="userService">
<ss:user name="weather" password="weather" authorities="ROLE_ADMIN" />
</ss:user-service>
</ss:authentication-provider>
</ss:authentication-manager>
</spring:beans>
<flow name="OML_News" doc:name="OML_News">
<http:inbound-endpoint host="localhost" port="9091"
path="iran/oml_news" exchange-pattern="request-response" doc:name="HTTP">
<mule-ss:http-security-filter realm="mule-realm" />
</http:inbound-endpoint>
<expression-filter
expression="#['${allowed}'.contains(parseIp(message.inboundProperties['MULE_REMOTE_CLIENT_ADDRESS']))]"
doc:name="Expression" />
<cxf:proxy-service
service="Weather"
wsdlLocation="http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl"
namespace="http://ws.cdyne.com/WeatherWS/"
validationEnabled="true" doc:name="SOAP">
</cxf:proxy-service>
<copy-properties propertyName="SOAPAction" doc:name="Property" />
<cxf:proxy-client doc:name="SOAP" />
<outbound-endpoint
address="http://wsf.cdyne.com/WeatherWS/Weather.asmx"
exchange-pattern="request-response" doc:name="Generic">
</outbound-endpoint>
</flow>
I launch a cxf service. There are some customers who use wsdl address in my cxf service and they implemented web services. Now I want that will be possible to determine how many users are using my wsdl address and each of them how many requests do send to my server? In fact, I want create a report system.
There are several ways you can do this, for example you can add a wiretap after your http inbound endpoint and invoke either a custom component that gather statistics in a database or more elegantly call a flow that does this.
<http:inbound-endpoint address="http://yourendpointaddress:8080/path" />
<wire-tap>
<vm:outbound-endpoint path="stats" />
</wire-tap>
And then
<flow name="statsFlow">
<vm:inbound-endpoint path="stats" />
<!-- gather stats from the headers -->
<jdbc:outbound-endpoint queryKey="insertStatsIntoDB" />
</flow>
This should gather statistics without affecting performance.

Is it possible to enable schema validation for inbound or outbound xml only in Apache CXF 2.5.2?

I have created a web service endpoint using Apache CXF 2.5.2, but I am having some issues with schema validation and MTOM interacting. If I enable MTOM and schema validation I must use the base64Binary type directly, however I am trying to conform to a fixed spec where the MTOM field also has a "contentType" attribute.
<jaxws:properties>
<entry key="mtom-enabled" value="true"/>
<entry key="schema-validation-enabled" value="true"/>
</jaxws:properties>
Is it possible to only enable schema validation for inbound or outbound messages? For example something like:
<entry key="schema-validation-enabled" value="inbound"/>
Alternatively is there an alternate way of achieving this, such as overriding the outbound message validation?
Thanks.
Since Apache CXF 3.0 this is sort of possible. You can't disable the validation on an in/outbound basis, but you can ignore the validation errors selectively (so you're still getting the performance hit).
You configure reader (inbound) & writer (outbound) validation event handlers in the CXF configuration.
<jaxws:properties>
<!-- Validation of the SOAP Message-->
<entry key="schema-validation-enabled" value="true" />
<entry key="jaxb-reader-validation-event-handler">
<bean class="com.example.cxf.InboundValidationEventHandler" />
</entry>
<entry key="jaxb-writer-validation-event-handler">
<bean class="com.example.cxf.OutboundValidationEventHandler" />
</entry>
</jaxws:properties>
Create the ValidationEventHandlers like this and return true. Returning true informs CXF to ignore a single validation error and continue validation.
package com.example.cxf;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
public class InboundValidationEventHandler implements ValidationEventHandler {
public boolean handleEvent(ValidationEvent event) {
String message = event.getMessage();
Throwable t = event.getLinkedException();
System.out.println("Ignoring Inbound Validation EVENT : " + message);
// ignore
return true;
}
}

WS-securitypolicy in cxf-bc deploy in servicemix

I was wondering if it is possible to build a cxf-bc with WS-SecurityPolicy instead of just the WS-Security. WS-SecurityPolicy seems to be a more elegant solution since everything is in the WSDL. Examples welcome. :)
Well with David's help I got the CXF-BC to install and running on the ESB, but I can't seem to test it. It keeps coming back with:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}UsernameToken</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
My msg:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://nwec.faa.gov/wxrec/UserAccount/types">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/ws-securitypolicy-1.2.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-25" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>bob</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">bobspassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action>http://nwec.faa.gov/wxrec/UserAccount/UserAccountPortType/ApproveDenyAccountRequest</wsa:Action>
</soapenv:Header>
<soapenv:Body>
...
</soapenv:Body>
Here's the policy in the wsdl:
<wsp:Policy wsu:Id="UserAccountBindingPolicy" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:ExactlyOne>
<wsp:All>
<wsaw:UsingAddressing xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" wsp:Optional="true" />
<wsp:Policy >
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Always">
<wsp:Policy>
<sp:WssUsernameToken10 />
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
As of the resolution of https://issues.apache.org/activemq/browse/SMXCOMP-711 and https://issues.apache.org/activemq/browse/SMXCOMP-712 (servicemix-cxf-bc-2010.01) it should be possible and easy to do.
See http://fisheye6.atlassian.com/browse/servicemix/components/bindings/servicemix-cxf-bc/trunk/src/test/java/org/apache/servicemix/cxfbc/ws/security/CxfBcSecurityJAASTest.java?r=HEAD for an example. Specifically the testJAASPolicy method.
As for the error relating to asserting the UsernameToken assertion, you may want to try putting the UsernameToken assertion inside of a SupportingToken or binding assertion depending on what you want to do with the token. It looks like you just want a username and password to be passed in the message without any other security such as a cryptographic binding of the token to the message or encryption so a supporting token will likely fit your needs.
I also urge you to consider the following additional precautions when using a UsernameToken:
Cryptographically bind the token to the message using a signature.
Use a nonce and created timestamp and cache the token on the server to prevent replay
Consider encrypting the token (before signing if you also sign) using XML enc
Using TLS either in lieu of or in addition to the above suggestions
With david's and Freeman over at the servicemix-user mailing-list. I was able finally get the correct configuration to implement WS-Security Policy.
Here's my final beans.xml for the my BC
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxfbc="http://servicemix.apache.org/cxfbc/1.0" xmlns:util="http://www.springframework.org/schema/util"
xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:sec="http://cxf.apache.org/configuration/security"
xmlns:person="http://www.mycompany.com/ws-sec-proto"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://servicemix.apache.org/cxfbc/1.0
http://repo2.maven.org/maven2/org/apache/servicemix/servicemix-cxf-bc/2010.01/servicemix-cxf-bc-2010.01.xsd
http://cxf.apache.org/transports/http-jetty/configuration
http://cxf.apache.org/schemas/configuration/http-jetty.xsd
http://cxf.apache.oarg/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http.xml" />
<import resource="classpath:META-INF/cxf/osgi/cxf-extension-osgi.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-policy.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-ws-security.xml" />
<bean id="myPasswordCallback" class="com.mycompany.ServerPasswordCallback" />
<cxfbc:consumer wsdl="classpath:wsdl/person.wsdl"
targetService="person:PersonService" targetInterface="person:Person"
properties="#properties" delegateToJaas="false" >
<!-- not important for ws-security
<cxfbc:inInterceptors>
<bean class="com.mycompany.SaveSubjectInterceptor" />
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</cxfbc:inInterceptors>
-->
</cxfbc:consumer>
<util:map id="properties">
<entry>
<key>
<util:constant
static-field="org.apache.cxf.ws.security.SecurityConstants.CALLBACK_HANDLER" />
</key>
<ref bean="myPasswordCallback" />
</entry>
</util:map>
<httpj:engine-factory bus="cxf">
<httpj:engine port="9001">
<httpj:tlsServerParameters>
<sec:keyManagers keyPassword="password">
<sec:keyStore type="JKS" password="password" resource="certs/cherry.jks" />
</sec:keyManagers>
<sec:cipherSuitesFilter>
<sec:include>.*_WITH_3DES_.*</sec:include>
<sec:include>.*_WITH_DES_.*</sec:include>
<sec:exclude>.*_WITH_NULL_.*</sec:exclude>
<sec:exclude>.*_DH_anon_.*</sec:exclude>
</sec:cipherSuitesFilter>
<sec:clientAuthentication want="false"
required="false" />
</httpj:tlsServerParameters>
</httpj:engine>
</httpj:engine-factory>
<bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl" />
<bean class="org.apache.servicemix.common.osgi.EndpointExporter" />
</beans>
Full example can be found here but it may not be there after a while.

Resources