PayloadValidatingInterceptor - validate only concrete wsdl - spring

I have one Spring WS servlet with two endpoints and two wsdl files. Requests/responses are being validated with PayloadValidatingInterceptor. Content of spring-ws-servlet.xml:
<context:component-scan base-package="cz.legend.mzv.spi.ws.ei.endpoints" />
<context:component-scan base-package="cz.legend.mzv.spi.ws.de.endpoints" />
<sws:annotation-driven />
<sws:static-wsdl id="entityImport" location="classpath:/wsdl/entityImport.wsdl" />
<sws:static-wsdl id="documentEvidence"
location="classpath:/wsdl/documentEvidence.wsdl" />
<oxm:jaxb2-marshaller id="jaxb2Marshaller"
contextPath="cz.legend.mzv.spi.ws.jaxb.generated" />
<bean id="endpointAdapter" class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
<constructor-arg ref="jaxb2Marshaller" />
</bean>
<sws:interceptors>
<bean
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema" value="classpath:/xsd/vums_spi_de.xsd" />
<property name="validateRequest" value="true" />
<property name="validateResponse" value="true" />
</bean>
</sws:interceptors>
Interceptor is applied on both services. I need the interceptor to be applied only on service described by documentEvidence.wsdl. One option is to make two separate spring servlets. But I want to use only one servlet.

Solution:
Alternatively, you can use or
elements to specify for which payload root name or SOAP action the
interceptor should apply:
<sws:interceptors>
<bean class="samples.MyGlobalInterceptor"/>
<sws:payloadRoot namespaceUri="http://www.example.com">
<bean class="samples.MyPayloadRootInterceptor"/>
</sws:payloadRoot>
<sws:soapAction value="http://www.example.com/SoapAction">
<bean class="samples.MySoapActionInterceptor1"/>
<ref bean="mySoapActionInterceptor2"/>
</sws:soapAction>
</sws:interceptors>

Related

Spring WebServiceTemplate Interceptor for adding security header

I am trying to add a SOAP:Header with wss4j authentication for my outbound SOAP service.
Below is my WebServiceTemplate and interceptor configuration
<bean id="securityHeader"
class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="UsernameToken" />
<property name="securementUsername" value="uname" />
<property name="securementPassword" value="password#123" />
<property name="securementPasswordType" value="PasswordText" />
<property name="securementUsernameTokenElements" value="Nonce Created" />
</bean>`
<bean id="webService" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory" />
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
<!-- <property name="credentials" ref="credentials" /> -->
</bean>
</property>
<property name="interceptors">
<list>
<ref bean="securityHeader" />
</list>
</property>
<property name="defaultUri"
value="https://test.test.com/ws/service/test" />
<property name="marshaller" ref="fmarshaller" />
<property name="unmarshaller" ref="forwardunmarshaller" />
</bean>
But when the outbound call happens, its not adding the SOAP security header.webService.marshalSendAndReceive("http://localhost:8088/mockBinding",request);
Below changes did the trick for me.
Changing the SOAP version to 1.1
Defining the bean declaration inside interceptor instead of referencing it.
Use a web service message callback.

Spring factory-bean with property resolution

Is it possible to have property resolution on the factory-bean field of a Spring bean declaration?
Example:
<bean factory-bean="$APP{some.factory.bean}" factory-method="...">
Spring version: 3.2.4
Adding a PropertyPlaceholderConfigurer to your spring context should work:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:yourfile.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="false" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
</bean>
You can declare your propertyName in the file and then use it like:
<bean factory-bean="${propertyName}" factory-method="...">
Just encountered the same issue (using Spring 4.2.0). It seems that property resolution for factory beans does not work despite what they say in SPR-12638. I've ended up using ProxyFactoryBean as a workaround.
The desired configuration, which does not work:
<!-- The bean to be created: factory type determined in runtime -->
<bean id="..." factory-bean="factory-${factory.type}" factory-method="..." />
<!-- Possible factories -->
<bean id="factory-A" class="..." />
<bean id="factory-B" class="..." />
<bean id="factory-C" class="..." />
The workaround that I've found:
<!-- The bean to be created: use factory proxy -->
<bean id="..." factory-bean="factory-proxy" factory-method="..." />
<!-- The factory proxy: real factory type determined in runtime -->
<bean id="factory-proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="factory-${factory-type}" />
</bean>
<!-- Possible factories -->
<bean id="factory-A" class="..." />
<bean id="factory-B" class="..." />
<bean id="factory-C" class="..." />
Enjoy :)

JNDI access with Tomcat 7 and embedded HornetQ

I set up a new project with Tomcat 7.0 and an embedded HornetQ JMS server.
I used these 2 tutorials to help me:
http://www.javacodegeeks.com/2010/06/spring-3-hornetq-21-integration.html
http://wash-inside-out.blogspot.com/2010/08/hornetq-jms-integration-with-tomcat.html
But as it is mentioned in the tutos, the Tomcat JNDI repository is readonly (cannot find a way to write) and I configured a "separated" JNDI used by HornetQ, the messaging works, but Tomcat cannot access it.
Normally, in my other projects using Tomcat, I defined the datasource as a global resource in the server.xml and I map it in the context.xml. doing this, the definition of the datasource (jdbc url, credentials, etc...) are outside the application and can be managed by environment (dev, test, prod, ...) but I cannot find a way to do it with the other JNDI.
Currently, the datasource is defined in my application with an external property file for the parameters but I am not really satisfied with this solution.
Here is my Spring configuration:
<!-- enable autowire -->
<context:annotation-config />
<!-- enable transaction demarcation with annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="driverClassName" value="com.informix.jdbc.IfxDriver" />
<property name="url" value="${URL}" />
<property name="username" value="${user}" />
<property name="password" value="${password}" />
<property name="maxActive" value="50" />
<property name="maxIdle" value="10" />
<property name="maxWait" value="1000" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="300" />
<property name="logAbandoned" value="true" />
</bean>
<!-- HornetQ config -->
<bean name="namingServerImpl" class="org.jnp.server.NamingBeanImpl" init-method= "start" destroy-method="stop" >
<!-- configure HornetQ JNDI server not to use an existing JNDI service if available -->
<property name="useGlobalService" value="false" />
</bean>
<bean name="namingServer" class="org.jnp.server.Main" init-method="start" destroy-method="stop">
<property name="namingInfo" ref="namingServerImpl" />
<property name="port" value="1099" />
<property name="bindAddress" value="localhost" />
<property name="rmiPort" value="1098" />
<property name="rmiBindAddress" value="localhost" />
</bean>
<bean name="mbeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer" />
<bean name="fileConfiguration" class="org.hornetq.core.config.impl.FileConfiguration"
init-method="start" destroy-method="stop" />
<bean name="hornetQSecurityManagerImpl" class="org.hornetq.spi.core.security.HornetQSecurityManagerImpl" />
<!-- The core server -->
<bean name="hornetQServerImpl" class="org.hornetq.core.server.impl.HornetQServerImpl">
<constructor-arg index="0" ref="fileConfiguration" />
<constructor-arg index="1" ref="mbeanServer" />
<constructor-arg index="2" ref="hornetQSecurityManagerImpl" />
</bean>
<!-- The JMS server -->
<bean name="jmsServerManagerImpl" class="org.hornetq.jms.server.impl.JMSServerManagerImpl"
init-method="start" destroy-method="stop" depends-on="namingServer">
<constructor-arg ref="hornetQServerImpl" />
</bean>
<!-- to use HornetQ messaging service through Spring we can either create a connection factory, or lookup one from JNDI -->
<bean name="connectionFactory" class="org.hornetq.jms.client.HornetQConnectionFactory">
<constructor-arg index="0" type="boolean" value="false"/>
<constructor-arg index="1">
<bean class="org.hornetq.api.core.TransportConfiguration">
<constructor-arg index="0" type="java.lang.String" value="org.hornetq.integration.transports.netty.NettyConnectorFactory" />
<constructor-arg index="1">
<map key-type="java.lang.String" value-type="java.lang.Object">
<entry key="port" value="5445"></entry>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean id="notificationsQueue" class="org.springframework.jndi.JndiObjectFactoryBean" depends-on="jmsServerManagerImpl">
<property name="jndiName">
<value>/queue/Notifications</value>
</property>
</bean>
<bean id="inVMConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean" depends-on="jmsServerManagerImpl">
<property name="jndiName">
<value>/ConnectionFactory</value>
</property>
</bean>
How can I managed it in a better way, I mean, define the datasource on the server side as usual? Is there a configuration to tell Tomcat to use the external JNDI I defined or create a read/write repo?

Spring Security Role Hierarchy issues

I am trying to enable role hierarchy voting in Spring Security when authenticating using Waffle NTML but having some unknown issues in that the inherited roles do not appear as authorities on the principal as expected preventing hasRole expressions in both the intercept urls and using the authorize jsp taglibs.
I have been integrating waffle based on the following guide: https://github.com/dblock/waffle/blob/master/Docs/spring/SpringSecuritySingleSignOnFilter.md
This works within the application as expected on its own using the standard RoleVoter but the problem starts when I try to customise it to use the RoleHierarchyVoter which I have also tested on its own (using an LDAP Authentication Provider) and the role hierarchies work exactly as expected.
The config for the combined Waffle and RoleHierarchyVoter approach is as follows:
Waffle Specfic Config
<!-- windows authentication provider -->
<bean id="waffleWindowsAuthProvider" class="waffle.windows.auth.impl.WindowsAuthProviderImpl" />
<!-- collection of security filters -->
<bean id="negotiateSecurityFilterProvider" class="waffle.servlet.spi.NegotiateSecurityFilterProvider">
<constructor-arg ref="waffleWindowsAuthProvider" />
</bean>
<bean id="basicSecurityFilterProvider" class="waffle.servlet.spi.BasicSecurityFilterProvider">
<constructor-arg ref="waffleWindowsAuthProvider" />
</bean>
<bean id="waffleSecurityFilterProviderCollection" class="waffle.servlet.spi.SecurityFilterProviderCollection">
<constructor-arg>
<list>
<ref bean="negotiateSecurityFilterProvider" />
<ref bean="basicSecurityFilterProvider" />
</list>
</constructor-arg>
</bean>
<bean id="negotiateSecurityFilterEntryPoint" class="waffle.spring.NegotiateSecurityFilterEntryPoint">
<property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>
<!-- spring security filter -->
<bean id="waffleNegotiateSecurityFilter" class="waffle.spring.NegotiateSecurityFilter">
<property name="Provider" ref="waffleSecurityFilterProviderCollection" />
<property name="AllowGuestLogin" value="false" />
<property name="PrincipalFormat" value="fqn" />
<property name="RoleFormat" value="fqn" />
<property name="GrantedAuthorityFactory" ref="simpleGrantedAuthorityFactory" />
<!-- set the default granted authority to null as we don't need to assign a default role of ROLE_USER -->
<property name="defaultGrantedAuthority"><null/></property>
</bean>
<!-- custom granted authority factory so the roles created are based on the name rather than the fqn-->
<bean id="simpleGrantedAuthorityFactory" class="xx.yy.zz.SimpleGrantedAuthorityFactory">
<constructor-arg name="prefix" value="ROLE_"/>
<constructor-arg name="convertToUpperCase" value="true"/>
</bean>
Familiar Spring Security Config
<!-- declare the entry point ref as the waffle defined entry point -->
<sec:http use-expressions="true"
disable-url-rewriting="true"
access-decision-manager-ref="accessDecisionManager"
entry-point-ref="negotiateSecurityFilterEntryPoint" >
<sec:intercept-url pattern="/**" access="isAuthenticated()" requires-channel="any"/>
.
. access denied handlers, concurrency control, port mappings etc
.
<sec:custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER" />
</sec:http>
<!-- spring authentication provider -->
<sec:authentication-manager alias="authenticationProvider" />
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<ref bean="roleHierarchyVoter" />
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler">
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
<property name="roleHierarchy" ref="roleHierarchy"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_TEST_1 > ROLE_TEST_2
ROLE_TEST_2 > ROLE_TEST_3
ROLE_TEST_3 > ROLE_TEST_4
</value>
</property>
</bean>
<bean id="roleHierarchyVoter"
class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy"/>
</bean>
Managed to fix my issues which was down to an omission in my http namespace configuration which I found from hours of debugging the spring security source.
The issue was how the DefaultWebSecurityExpressionHandler was created. In the snipped above it had created it as inner bean inside the bean definition of the accessDecisionManager:
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler">
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
<property name="roleHierarchy" ref="roleHierarchy"/>
</bean>
</property>
</bean>
With this the role heirachies are used to determine whether access should be granted when processing rules defined as intercept urls such as:
<sec:intercept-url pattern="/**" access="isAuthenticated()" requires-channel="any"/>
But if you want to check authorisation using the JSP Authorize taglib as below (this is in freemarker) it will not work as the roleHeirachies do not get taken into account:
<#security.authorize access="hasRole('ROLE_TEST_1)">
<p>You have role 1</p>
</#security.authorize>
<#security.authorize access="hasRole('ROLE_TEST_4')">
<p>You have role 4</p>
</#security.authorize>
This is because the DefaultWebSecurityExpressionHandler created as an inner bean is only used within the access decision manager but for taglib expressions a NEW default bean will be created (which doesn't use the RoleHierarchy) unless an security http namespace expression-handler is defined.
So, to resolve my issues I created the bean DefaultWebSecurityExpressionHandler and referenced it within my WebExpressionVoter bean definition and also used it as the expression handler as follows:
<sec:http ... >
.
. access denied handlers, concurrency control, port mappings etc
.
<sec:expression-handler ref="defaultWebSecurityExpressionHandler" />
</sec:http>
<bean id="defaultWebSecurityExpressionHandler"
class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
<property name="roleHierarchy" ref="roleHierarchy"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<ref bean="roleHierarchyVoter" />
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler" ref="defaultWebSecurityExpressionHandler"/>
</bean>
</list>
</property>
</bean>
Making these changes ensures the roleHeirarchies are taken into account for both Web Security Expressions defined as intercept URLs via the http namespace and also expressions using the JSP Authorize taglib.

How do I set up custom Mongo formatters in Spring?

I've been at this for a few hours and haven't found anyone that's gotten this working yet. I want to persist a BigDecimal object in Mongo, but Mongo doesn't natively support BigDecimal. I followed Spring's docs here but no luck.
From what I can tell Spring isn't injecting my custom converter classes into Mongo when it's writing to the db. Here's what I have done:
My applicationContext-services.xml
...
<!-- Factory bean that creates the Mongo instance -->
<mongo:mongo
host="localhost"
port="1234" />
<mongo:db-factory
dbname="solar"
mongo-ref="mongo"/>
<mongo:mapping-converter>
<mongo:custom-converters>
<mongo:converter>
<bean class="com.mine.BigDecimalReadConverter"/>
</mongo:converter>
<mongo:converter>
<bean class="com.mine..BigDecimalWriteConverter"/>
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>
<!-- Use this post processor to translate any MongoExceptions thrown in #Repository annotated classes -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="mongoDbTest"
class="com.mine.MongoDbTest">
<property name="mongoTemplate">
<ref local="mongoTemplate" />
</property>
</bean>
The error I'm getting is:
java.lang.IllegalArgumentException: Multiple constructors with arguments found in class java.math.BigDecimal! Annotate one with #PreferedConstructor explicitly to select it to be used in persistence operations.
at org.springframework.data.mapping.PreferredConstructorDiscoverer.<init>(PreferredConstructorDiscoverer.java:81)
Try using this for converter support:
<bean id="mappingContext"
class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" lazy-init="true"/>
<bean id="defaultMongoTypeMapper"
class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper" lazy-init="true">
<constructor-arg name="typeKey"><null/></constructor-arg>
</bean>
<bean id="mappingMongoConverter"
class="org.springframework.data.mongodb.core.convert.MappingMongoConverter" lazy-init="true" >
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mappingContext" />
<property name="typeMapper" ref="defaultMongoTypeMapper" />
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate" lazy-init="true">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mongoConverter" ref="mappingMongoConverter" />
</bean>
Here is how I solved this. The order in which you define the beans matters. So my app.xml that I got it working with is:
<bean id="mappingContext" class="org.springframework.data.document.mongodb.mapping.MongoMappingContext"/>
<bean id="readConverter" class="com.mine.BigDecimalReadConverter"/>
<bean id="writeConverter" class="com.mine.BigDecimalWriteConverter"/>
<mongo:mapping-converter id="mappingConverter">
<mongo:custom-converters>
<mongo:converter ref="readConverter" />
<mongo:converter ref="writeConverter" />
</mongo:custom-converters>
</mongo:mapping-converter>
<!-- Factory bean that creates the Mongo instance -->
<mongo:mongo
host="${${environment}.mongodb.host}"
port="${${environment}.mongodb.port}" />
<mongo:db-factory
dbname="${${environment}.mongodb.databaseName}"
mongo-ref="mongo"/>
<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mongoConverter" ref="mappingConverter"/>
</bean>
<!-- Use this post processor to translate any MongoExceptions thrown in #Repository annotated classes -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

Resources