common webservice interceptor and UsernameTokenValidation compatible with Spring-WS and CXF - web-services

I have a scenario, where I want to configure a webservice security interceptor, and a UsernameTokenValidator and put this into say myws-security.jar. Which can be then be used by any webservice (be it CXF based or Spring-WS) that uses this jar. What would be the practice to deal with this scenario.
Would configuring an interceptor with org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor class , or org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor work for me in this case ?

In both Spring-WS and CXF, you typically do not provide your own WSS interceptor, you simply configure the provided interceptor with an appropriate callback handler. So in your case if you create an appropriate callback handler(based on the type of securement action), which needs to inherit from javax.security.auth.callback.CallbackHandler, this callback handler can be reused in Spring-WS and Apache CXF:
In Spring-WS you would do something along these lines:
<bean id="wss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationCallbackHandler" ref="callBackHandler" />
<property name="validationActions" value="UsernameToken" />
</bean>
And in Apache CXF:
<jaxws:endpoint address=".." id=".." implementor="#memberendpoint">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordDigest" />
<entry key="passwordCallbackRef">
<ref bean="callBackHandler" />
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
And the common callbackhandler should work for you in both cases

Related

Web service proxy server in Karaf with Camel and cxf adds 1000 to MTOM messages

I am creating new proxy for web services in Karaf 4.4.1 with Camel 3.18.1 and cxf 3.5.3.(I've tried it on older versions too 4.4.0, 3.18.0, 3.5.2). And it works fine, but I have a problem with MTOM attachments. For some reason it adds several times number 1000 into the message. And it is not every 1000 bytes. The spaces between them are different (from 377 to 4157 bytes). Here is picture of comparison of my incoming messages. The bad one goes through proxy and the good one don't:
comparsion 1
comparsion 2
Does anyone knows where is the mistake?
Here is my blueprint:
...
<camelcxf:cxfEndpoint id="SrvEndpoint">
<camelcxf:properties>
<entry key="dataFormat" value="CXF_MESSAGE" />
<entry key="ws-security.ut.no-callbacks" value="true"/>
<entry key="ws-security.validate.token" value="false"/>
<entry key="schema-validation-enabled" value="true" />
<entry key="lazyStartProducer" value="true" />
<entry key="mtom-enabled" value="true" />
</camelcxf:properties>
<camelcxf:inInterceptors>
<ref component-id="SrvWsSecInterceptor" />
<ref component-id="SrvAuthenticationInterceptor"/>
<ref component-id="SrvLoggingInInterceptor"/>
</camelcxf:inInterceptors>
<camelcxf:outInterceptors>
<ref component-id="SrvLoggingOutInterceptor"/>
</camelcxf:outInterceptors>
</camelcxf:cxfEndpoint>
<!-- this is the Camel route which proxies the real web service and forwards SOAP requests to it -->
<camelContext id="SrvRoute" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route>
<!-- CXF consumer using CXF_MESSAGE format -->
<from uri="cxf:bean:SrvEndpoint"/>
<!-- Need to remove the http headers which could confuse the http endpoint -->
<removeHeaders pattern="CamelHttp*"/>
<!-- Don't know why but if not set returns empty response header and body -->
<setProperty name="CamelCXFDataFormat"><constant>PAYLOAD</constant></setProperty>
<!-- send proxied request to real web service -->
<to uri="{{SrvProxy.target.url}}?throwExceptionOnFailure=false"/>
</route>
</camelContext>
I've tried to change dataFormat to PAYLOAD and clean it from authentication and validation but nothing helped.

CXF Transform feature

I am new to CXF,I have a requirement to drop few tags from the input XML .so I am using CXF Transform feature ,which should drop the version tag from my input XML ,I am able change but not drop. Kindly let me know how can I achieve it
<bean id="transformFeature" class="org.`enter code here`apache`enter code here`.cxf.feature.StaxTransformFeature">
<property name="inTransformElem`enter code here`ents">
<map>
<entry key="version" value=""/>
</map>
</property>
</bean>
You need to specify the namespace of the element. For example, if the version element has a namespace of http://www.example.org/test, you would need to configure the CXF transformation feature as follows:
<bean id="transformFeature" class="org.apache.cxf.feature.StaxTransformFeature">
<property name="inTransformElements">
<map>
<entry key="{http://www.example.org/test}version value=""/>
</map>
</property>
</bean>
You also need to add the feature to your jaxws:endpoint configuration, if you have not already done so.
<jaxws:endpoint ...>
<jaxws:features>
<ref bean="transformFeature" />
</jaxws:features>
</jaxws:endpoint>

Stateless Spring Security usage

I need your help with stateless Spring Security. I wrote service that authorize user, my security.xml:
<http use-expressions="true" create-session="stateless" entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/auth/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<custom-filter ref="myFilter" position="FORM_LOGIN_FILTER"/>
</http>
<beans:bean id="myFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailsService" />
</authentication-manager>
It hasn't state, thats why after my authentication, when I want get anything via another URL, it takes me 401 Unauthorized. I heard about token but I don't know how achieve this.
Maximus,
This is what I did in similar scenario:
Used OAuth - http://oauth.net/
There are multiple libraries that implement OAuth specifications
http://tools.ietf.org/html/rfc6749
Spring has an implementation that is easy to configure. There are two sample applications (server and client) from Spring for this. Tutorials are available at:
https://github.com/SpringSource/spring-security-oauth/wiki/tutorial
Sample working config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:ss="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<ss:http pattern="/test/customer/**" create-session="stateless"
access-decision-manager-ref="accessDecisionManager"
entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<ss:anonymous enabled="false" />
<ss:intercept-url pattern="/test/customer/welcome*"
access="ROLE_USER" />
<ss:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<ss:access-denied-handler ref="oauth2AccessDeniedHandler" />
</ss:http>
<ss:http pattern="/oauth/token" create-session="stateless"
entry-point-ref="oauthAuthenticationEntryPoint"
authentication-manager-ref="authenticationManager">
<ss:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<ss:anonymous enabled="false" />
<ss:custom-filter ref="clientCredentialsTokenEndpointFilter"
before="BASIC_AUTH_FILTER" />
<ss:access-denied-handler ref="oauth2AccessDeniedHandler" />
</ss:http>
<ss:authentication-manager alias="authenticationManager">
<ss:authentication-provider ref="myAuthenticationProvider" />
</ss:authentication-manager>
<oauth:resource-server id="resourceServerFilter" token-services-ref="tokenServices" />
<bean id="myAuthenticationProvider" class="com.sachin.test.ws.user.MyUserAuthenticationProvider" />
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="myCustomerAppRealm" />
</bean>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetailsService" />
</bean>
<oauth:authorization-server
client-details-service-ref="clientDetailsService" token-services-ref="tokenServices">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:client-details-service id="clientDetailsService">
<oauth:client client-id="admin"
authorized-grant-types="password,authorization_code,refresh_token,implicit,client_credentials"
authorities="ROLE_USER, ROLE_TRUSTED_CLIENT" scope="read,write,trust"
access-token-validity="60" />
</oauth:client-details-service>
<bean id="oauth2AccessDeniedHandler"
class="org.springframework.security.web.access.AccessDeniedHandlerImpl" />
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
</bean>
</beans>
Add this to web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
You'll need to read the specs for OAuth and Spring security to understand what I did. You may extend this code to use your DB for authentication and token sharing across multiple servers.
Hope this helps.

Handling multiple Rest web services using Spring and Castor

Would anyone be able to advise me on the best way of handling access to multiple Rest web services using Springs RestTemplate?
I know that the RestTemplate object has a message converter reference (MarshallingHttpMessageConverter) which in turn has a reference to an unmarshaller. In my case I am using the Spring Frameworks CastorMarshaller object with associated mapping file.
Normally I could have just added all my mappings to one Castor mapping file. However in my case all the web services are of this format (block below) with the < rows ... /> holding different entities depending on the service called.
<data>
<output>
<dataset>
<row id="" .... />
<row id="" .... />
<row id="" .... />
<row id="" .... />
<row id="" .... />
</dataset>
</output>
<nextUpdate><nextUpdate/>
</data>
The CastorMarshaller is injected into the MessageConverter which itself is injected into the RestTemplate in the application context configuration file.
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="castorMarshaller"/>
<property name="unmarshaller" ref="castorMarshaller"/>
<property name="supportedMediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<constructor-arg index="0" value="application"/>
<constructor-arg index="1" value="xml"/>
</bean>
<bean class="org.springframework.http.MediaType">
<constructor-arg index="0" value="text"/>
<constructor-arg index="1" value="xml"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:oxm-mapping-worldweather.xml"/>
</bean>
Possible options that I have been thinking about:
1 Create multiple RestTemplates for each Rest service.
2 Create multiple MessageConverters for the different services and change the message converters on the template when accessing a different service.
3 Create multiple CasterMarshaller objects for the different services and update the message converter with the new unmarshaller
What is the best way to approach handling multiple services like this with the same root and sub elements?
Thanks in advance
Sman UK
If specifying multiple mapping files is the issue then below is the solution.
Use mappingLocations property instead of mappingLocation as given below,
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocations">
<list>
<value>classpath:oxm-mapping-worldweather.xml</value>
<value>classpath:sample-mapping.xml</value>
</list>
</property>
</bean>

Configure a common webservice interceptor and usernameTokenValidator compatible with Spring-WS and CXF

Right now I have below configuration for one of my WS endpoints.
<jaxws:endpoint id="myService" implementor="#myServiceImpl" address="/myService">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<ref bean="myServiceInterceptor"/>
</jaxws:inInterceptors>
<jaxws:properties>
<entry key="ws-security.ut.validator" value-ref="myServiceUsernameTokenValidator"/>
<jaxws:properties>
</jaxws:endpoint>
<bean id=" myServiceInterceptor " 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>
Now I want to move this bean="myServiceInterceptor" and custom userNameToken Validator config (jaxws:properties) to a separate jar (say A). So that any spring WS using that jar A , can leverage same interceptor and customUseranameToken functionality.
My questions:
1) How do I setup/configure a generic webservice security interceptor rather than a cxf specific interceptor.
2) How can I setup a common <jaxws:properties> that can be used by all the endpoints.
Thanks!
MOST of the stuff could be configured at the Bus level and thus inherited by anything that uses that bus:
<cxf:bus>
<cxf:inInterceptors>....
<cxf:properties>....
</cxf:bus>