I have a web service client implemented in Spring-ws, using a Wss4jSecurityInterceptor for ws-security.
Calling the endpoint works, data is encrypted, signed and sent, but when the reply is received it is not decrypted. Instead JAXB's unmarshaller is called, resulting in an error like :
Error : org.springframework.oxm.jaxb.JaxbUnmarshallingFailureException:
JAXB unmarshalling exception: unexpected element
(uri:"http://www.w3.org/2001/04/xmlenc#", local:"EncryptedData").
Expected elements are...
Expected elements then goes on to list every data type in the xdd.
This is what my Wss4jSecurityIntercepter is configured with :
<!-- username / password for signing -->
<property name="enableSignatureConfirmation" value="false" />
<property name="securementUsername" value="${securementUsername}" />
<property name="securementSignatureKeyIdentifier" value="DirectReference" />
<property name="securementPassword" value="${keystore.password}" />
<property name="securementSignatureCrypto" ref="crypto" />
<!-- username (certificate) and keystore for encryption -->
<property name="securementEncryptionUser" value="${securementEncryptionUsername}" />
<property name="securementEncryptionKeyIdentifier" value="SKIKeyIdentifier" />
<property name="securementEncryptionCrypto" ref="crypto" />
<!-- validate incoming message signature and decrypt -->
<property name="validationActions" value="Signature Encrypt Timestamp" />
<property name="validationDecryptionCrypto" ref="crypto" />
<property name="validationSignatureCrypto" ref="crypto" />
<property name="validationCallbackHandler">
<bean
class="org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler">
<property name="privateKeyPassword" value="${keystore.password}" />
</bean>
</property>
Any idea what goes wrong ?
Thanks.
EDIT: This was caused by a ClientInterceptor that returned false on handleResponse, and was located before the wss4j interceptor, causing all Interceptor processing to stop.
Your root cause is probably related to the order in which the securement of the message was made from the other side:
The order of the actions is significant and is enforced by the
interceptor. The interceptor will reject an incoming SOAP message if
its security actions were performed in a different order than the one
specified by validationActions.
I would recommend that you increase your log level (Add log4j if you are not already using it to see why the interceptor was not able to decrypt the message.
Last but not least, you should implement validator to prevent your process to go further if the message was not decrypted.
Caused by misconfiguration of the Interceptors. (see EDIT in original question)
Related
I am updating the client of an existing SOAP webservice since the service provider has made some changes to thier security headers in the request.
The requirement is to digitally sign the Timestamp which should be present in the request header and the body should not be digitally signed. I am using XML config to create my SOAP request header and digitally sign the Timestamp.
I am basically using org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor as an interceptor. The problem is that Timestamp gets created in the request header however the SignatureValue and DigestValue tags are empty
I have referred https://docs.spring.io/spring-ws/site/reference/html/security.html#security-wss4j-digital-signatures
Versions:
Spring-ws-core --> 2.0.0.RELEASE
spring-ws-security --> 2.0.0.RELEASE
<bean id="wsClientSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="Timestamp Signature"/>
<property name="securementSignatureKeyIdentifier" value="DirectReference" />
<property name="securementUsername" value="username" />
<property name="securementPassword" value="keystorepassword" />
<property name="securementSignatureCrypto" ref="clientCrypto"/>
<property name="securementSignatureUser" value="username" />
<property name="securementSignatureParts" value="{}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp"/>
</bean>
<bean id="clientCrypto" class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="keystorepassword" />
<property name="keyStoreLocation" value="file:${key.store.location}"/>
<property name="keyStoreType" value="jks" />
<property name="keyStoreProvider" value="IBMJCE" />
</bean>
Though the timestamp gets added to the wsse:Security element in the header, the DigestValue and SignatureValue elements belonging to the xmlns:ds="http://www.w3.org/2000/09/xmldsig#" namespace are always empty
This does not happen if I only sign the Body
I also tried using another Interceptor XwsSecurityInterceptor but that does not work without the Wss4jSecurityInterceptor and gives me the same result when used with Wss4jSecurityInterceptor
<bean id="xwsSecurityInterceptor" class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="classpath:securityPolicy.xml"/>
<property name="callbackHandlers">
<list>
<ref bean="keyStoreHandler"/>
</list>
</property>
</bean>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="keystorepassword"/>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="file:${key.store.location}"/>
<property name="password" value="keystorepassword"/>
</bean>
After referring a number of IBM support posts, I have finally come to the solution and have received a QA signoff too on the implementation. I had to replace all my spring mvc config for creating SSL context with configurations on the WAS server itself.You can configure all this using either scripts or using the WAS console manually.
Steps:
Add an entry to ur applications web.xml.Please refer this post https://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/twbs_jaxwsclientdd.html
The link below will give you a step by step guide as to how to configure the request payload to have a signed timestamp on WAS server.
http://pglezen.github.io/was-config/html/signts.html#sec.signts.keystores.consumer
It basically focusses on :
Policy Set Creation:This will Specify the element or elements to be signed or encrypted in this message part.In our case its the timestamp in the header
Client Policy Set Bindings. If you are the provider you have to refer the provider Policy set bindings section.This involves creation of truststore and keystore required to configure your SSL context. Also has configurations for any proxy settings that you might require.
Finally take a JNDI reference of the service whereever you need to call a particular operation in the service.Refer https://www.ibm.com/support/knowledgecenter/SSAW57_9.0.5/com.ibm.websphere.nd.multiplatform.doc/ae/twbs_jaxwsclientdd.html
Once this done, Simply navigate to Services--> Service Clients and you should have your service refs visible there. You should now attach the Policy set and the bindings created above to the Service client references created in WAS due to point 1 above.You might have to write a script to attach the polict set and binding since after deployment you dont want to do this step manually
Please note: this solution came into picture sicne the version of WAS 8.5.5.16,spring -3.0.5.RELEASE and spring-ws-2.0.0.RELEASE did not support signing of timestamp in the request payload of the SOAP service request. Hope this helps someone !!
We have used Camel for routing between different destination using Spring with EMS messaging:
EMS Queues/TOpics hosted on tcp/http protocol working fine, whereease SSL causes following exception:
Error: Error occured while reading identity data: failed to decrypt safe contents entry: javax.crypto.BadPaddingException: Given final block not properly padded: url that returned this exceptio= ssl://random.host.com:41943
For normal spring tibco EMS SSL connection we need to set following by overriding ListenerContainer:
TibjmsSSL.setPassword(passwordCharArray);
How can we do with camel configuration:
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="userCredentialsConnectionFactory" />
<property name="transacted" value="false" />
<property name="concurrentConsumers" value="1" />
</property>
</bean>
This is my camel jms config
I tried overriding following with my own custom implementation by setting below property, it doesnt seem to override required functionality:
org.apache.camel.component.jms.JmsConfiguration.messageListenerContainerFactory
[Fixed]
Overrided doCreateConnection(String,String) method of import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter
and set required password in TibjmsSSL.setPassword(passwordCharArray)
I am trying to send emails through a Spring app using smtp.gmail.com (port 587). The problem is I am intermittently facing the following error.
org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException
The error does not appear all the times and mails are sent properly. But sometimes the error appears and mails are not sent. I have set the following to true https://www.google.com/settings/security/lesssecureapps
Following is the configuration
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="port" value="${mail.port}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
<property name="javaMailProperties">
<props>
<!-- Use SMTP-AUTH to authenticate to SMTP server -->
<prop key="mail.smtp.auth">true</prop>
<!-- Use TLS to encrypt communication with SMTP server -->
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
<bean id="mailService" class="com.server.service.impl.MailServiceImpl">
<property name="mailSender" ref="mailSender" />
<property name="customMailMessage" ref="customMailMessage" />
</bean>
the properties are given below
mail.transport.protocol=smtp
mail.host=smtp.gmail.com
mail.port=587
mail.username=******
mail.password=******
I believe it's either an unreliability in Gmail, or it's purposely failing to reduce the rate at which you're sending messages. You might try turning on JavaMail Session debugging to see if it provides additional information about the failure. The AuthenticationFailedException usually contains additional information about the failure, but Spring may be hiding that.
Let me preface this by saying I'm not well versed in Spring. I was thrown into a project at work and am trying to spin up as quickly as possible
With that in mind, I'm trying to implement spring security using Jasig's CAS and LDAP.
When I had loaded this set up from a local LDAP, things worked fine. However, since I've relocated it to the corporate LDAP, the webapp is no longer working.
At the moment, I can confirm this script successfully logs into LDAP and verifies the paths to the containers, however I get a server error before the page loads.
Code:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" >
<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<!-- The URL of the ldap server, along with the base path that all other ldap path will be relative to -->
<constructor-arg value="ldaps://141.161.99.74:636/dc=testing,dc=com"/>
<property name="userDn" value="uid=OdinAdmin,ou=Specials,dc=testing,dc=com" />
<property name="password" value="testpw" />
</bean>
<bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource"/>
<property name="userSearch" ref="ldapUserSearch"/>
</bean>
</constructor-arg>
<constructor-arg ref="authoritiesPopulator" /> <!-- Populates authorities in the UserDetails object -->
<property name="userDetailsContextMapper" ref="userDetailsMapper" /> <!-- Adds OWF groups to the UserDetails object -->
</bean>
<bean id="authoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource"/>
<constructor-arg value="ou=OdinRoles,ou=Odin,ou=Apps"/> <!-- search base for determining what roles a user has -->
<property name="groupRoleAttribute" value="cn"/>
<!-- the following properties are shown with their default values -->
<property name="rolePrefix" value="ROLE_"/>
<property name="convertToUpperCase" value="true"/>
<property name="searchSubtree" value="true"/>
</bean>
<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg value="ou=people" /> <!-- search base for finding User records -->
<constructor-arg value="(uid={0})" /> <!-- filter applied to entities under the search base in order to find a given user.
this default searches for an entity with a matching uid -->
<constructor-arg ref="contextSource" />
</bean>
<!-- Custom class that goes back to the ldap database to search for OWF group records and also adds
extra attributes from the user's ldap record to the UserDetails object.
The class implementation of this will likely need to be changed out for differnt setups -->
<bean id="userDetailsMapper" class="ozone.securitysample.authentication.ldap.OWFUserDetailsContextMapper">
<constructor-arg ref="contextSource" />
<constructor-arg value="ou=OdinGroups,ou=Odin,ou=Apps" /> <!-- search base for finding OWF group membership -->
<constructor-arg value="(uniqueMember={0})" /> <!-- filter that matches only groups that have the given username listed
as a "member" attribute -->
<property name="searchSubtree" value="true"/>
</bean>
<bean id="ldapUserService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
<constructor-arg ref="ldapUserSearch" />
<constructor-arg ref="authoritiesPopulator" />
<property name="userDetailsMapper" ref="userDetailsMapper" />
</bean>
</beans>
My question is, am I allowed to have the subcontainers in the constructor-arg values for group and role searches? In my previous version, everything was in the same container. That way I could just have all that included in my base-dn and just reference the specific OU within that. Ie. instead of
I'm not sure if that is causing the issue, but any insight would be greatly appreciated. Thanks!
Can you provide what exactly is the error you're getting and which part actually fails? There is quite a bit of configuration in there and it'd very much help us if we narrow it down to one error or so.
P.S: I wanted this to be a comment but I'm sorry, i'm not yet allowed to comment due to the restrictions of SO.
This issue actually was based on the application I was implementing. It required specific role names (ROLE_ADMIN, ROLE_USER) to function. I had to map the existing roles to these 2 through a custom Java class.
Thanks for the help!
I have a cluster of servers running a spring application. Some of the spring components need to be configured differently depending on the role their server is playing (primary, secondary, etc). I don't want to maintain separate spring config files for each role, rather I want to dynamically detect this when the application is started. Its almost like I want conditional bean instantiation (which doesn't exist in spring).
Q: What is the best way to achieve this type of configuration?
Example: Only the primary node in a cluster should create durable subscription to a JMS broker (which requires a globally unique JMS clientID). I can detect if the current host has this role by looking up the running server's hostname in a database and start this container manually (if my node happens to be primary); however, I don't want every node in the cluster to create a durable subscription (by instantiating this bean).
<bean id="auditrecordListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="1" />
<property name="clientID" value="${server-hostname}" />
<property name="durable" value="true" />
<!-- only started on the primary node: via application listener -->
<property name="autoStartup" value="false" />
</bean>
Note, however there is no ${server-hostname} property in the spring container (at least that I know of)
If your code already conditionally starts the appropriate services based on object properties, you can use utility methods in the following manner:
<!-- Factory methods to determine properties -->
<bean id="hostname" class="MyUtil" factory-method="determineHostName"/>
<bean id="isHost" class="MyUtil" factory-method="isHost"/>
<bean id="auditrecordListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="1" />
<property name="durable" value="true" />
<!-- Reference properties here -->
<property name="hostname" ref="hostname" />
<property name="autoStartup" ref="isHost" />
</bean>
To use a property of a singleton bean instead, use a PropertyPathFactoryBean:
<bean id="config" class="MyConfig"/>
<util:property-path id="hostname" path="config.hostname"/>
<util:property-path id="isHost" path="config.host"/>
You can implement a conditional instantiation logic
as a FactoryBean