Generate web service client secure policy from .wsdl for java - java

I have been researching how to implement a web service client policies from a .wsdl file.
The policies of the web services implicates a signature and encryption using a .jks file with the necessary keys (asymmetric privateKey for signing, and a symmetric privateKey for encryption). The policy is: username:oracle/wss10_username_token_with_message_protection_service_policy.
I am able to make the .xsd files (request, response and service objects) using the wsimport tool for java (or with cxf or axis2). What i can't resolve is how to make the correct policy.
Is there any way to automatically generate the policies from the .wsdl or do i have to make them by myself

The username:oracle/wss10_username_token_with_message_protection_service_policy is solved with spring ws this way:
<!-- == Ougoing interceptor == -->
<bean id="loginOutgoingWss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="securementActions" value="Timestamp Signature Encrypt" />
<!-- == Set Outgoing Signature properties == -->
<property name="securementUsername" value="alias"/>
<property name="securementPassword" value="aliasPass"/>
<property name="securementSignatureKeyIdentifier" value="DirectReference"/>
<property name="securementSignatureCrypto" ref="cryptoFactoryBean" />
<property name="securementSignatureParts" value="{Element}{}Body;{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;" />
<!-- == Set Outgoing Encryption properties == -->
<property name="securementEncryptionUser" value="alias"/>
<property name="securementEncryptionCrypto" ref="cryptoFactoryBean" />
<property name="securementEncryptionKeyIdentifier" value="DirectReference"/>
<property name="securementEncryptionParts" value="{Content}{}Body;" />
</bean>
<!-- == Incoming interceptor == -->
<bean id="loginIncomingWss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor">
<property name="validationActions" value="Timestamp Signature Encrypt" />
<!-- == Set Validations Response, This validate signature and decrypts response == -->
<property name="validateResponse" value="true" />
<!-- The lower operation validation. Less time consume-->
<property name="validateRequest" value="false" />
<property name="enableSignatureConfirmation" value="false"/>
<!-- == Set Incoming Signature/Decryption keystore == -->
<property name="validationDecryptionCrypto" ref="cryptoFactoryBean" />
<property name="validationSignatureCrypto" ref="cryptoFactoryBean" />
<!-- Sets the {#link org.apache.ws.security.WSPasswordCallback} handler to use when validating messages -->
<property name="validationCallbackHandler">
<bean class="org.springframework.ws.soap.security.wss4j2.callback.KeyStoreCallbackHandler">
<property name="privateKeyPassword" value="aliasPass"/>
</bean>
</property>
</bean>

If you are using policies in WS-SecurityPolicy (1.1 or later) in your wsdl, no need to generate policies nor make them on client side with Apache CXF. With WS-SecurityPolicy, CXF's security runtime is policy driven.
1) You follow CXF's WSDL-first approach to generate the client code, using either wsdl2java command-line tool or Maven cxf-codegen-plugin (wsdl2java goal). This is described in CXF doc's How to develop a client.
2) Following CXF's doc on WS-SecurityPolicy usage, you configure the client security properties for the wsdl port you want to use, either using JAX-WS API (on the client's RequestContext) or Spring XML configuration. For the list of possible properties, there are the generic XML security ones and WS-Security-specific ones. Example with Spring XML for UsernameToken policy (from Glen Mazza's blog samples ):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItPort" createdFromAPI="true">
<!-- Use this for the UsernameToken Symmetric Binding w/X.509 for secret key derivation -->
<jaxws:properties>
<entry key="ws-security.username" value="alice"/>
<entry key="ws-security.callback-handler" value="client.ClientPasswordCallback"/>
<entry key="ws-security.encryption.properties" value="clientKeystore.properties"/>
<entry key="ws-security.encryption.username" value="myservicekey"/>
</jaxws:properties>
<!-- Use this for the UsernameToken Symmetric Binding w/UT password for secret key derivation -->
<!--jaxws:properties>
<entry key="ws-security.username" value="alice"/>
<entry key="ws-security.callback-handler" value="client.ClientPasswordCallback"/>
</jaxws:properties-->
</jaxws:client>
</beans>
Put this in /cxf.xml on the class path. Warning: the example is using a CallbackHandler subclass (client.ClientPasswordCallback in this example) to provide the password. So you'll need to provide your own implementation.
3) Back to CXF doc's How to develop a client - last part - in the application code, initialize the client using JAX-WS API with arguments: a) the location of the WSDL (URL) having the WS-SecurityPolicy policies (you already have that, as far as I understand); b) service and port's QNames to be used by the client, as defined in the WSDL:
final Service service = Service.create(wsdlLocation, SERVICE_QNAME);
final DoubleItPortType transportPort = service.getPort(PORT_QNAME, DoubleItPortType.class);
4) Make sure you have cxf-rt-ws-policy and cxf-rt-ws-security modules on the classpath at runtime to enable WS-SecurityPolicy support.

Related

Multiple AssertionConsumerService in SP with differend 2nd level domains

I am implementing a multitenant application with the spring security saml extention.
I have a Service Provider (SP) for each tenant.
All SPs runs on the same server exposed with SP-specific 2nd level domain:
sp1.myapp.com/myapi/1/
sp1.myapp.com/myapi/2/
In each SP metadata file I have configured the tenant-specific AssertionConsumerService.
When I test the SSO Login, I get a KO on SP side when it gets the response of the Identity Provider (IDP).
On Log side i see only:
ERROR [BaseSAMLMessageDecoder] SAML message intended destination endpoint 'https://sp1.myapp.com/myapi/saml/SSO' did not match the recipient endpoint 'https://default.myapp.com/myapi/saml/SSO'
Where the 'https://default.myapp.com/myapi/saml/SSO' is the URL set as serverName of the load balancer context provider:
<bean id="lbContextProvider" class="org.springframework.security.saml.context.SAMLContextProviderLB" init-method="afterPropertiesSet">
<property name="metadata" ref="metadata" />
<property name="keyManager" ref="keyManager" />
<property name="scheme" value="https" />
<property name="serverName" value="default.myapp.com" />
<property name="contextPath" value="/myapi" />
<property name="serverPort" value="443" />
<property name="includeServerPortInRequestURL" value="true" />
</bean>
Question
In the docs.spring.io/spring-security-saml I see that
Service provider can now define multiple assertion consumer endpoints with same binding
How can I configure it?
Does it conflict with load balancer context provider?
Can I provide multiple AssertionConsumerService with different 2nd level domains without reproduction this conflict?
I already tested:
This question seems to be fixed with the LB, but anyone knows if I can provide multiple serverName to load balancer context provider (maybe with a dynamic pick)?
Disable the checking of the InResponseToField as suggested at ch.13 docs.spring.io/spring-security-saml and for this and this question.
Configure the defaultTargetUrl of the successRedirectHandler (where I am using a custom superclass of org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler) as suggested for this question. In addition this solution is not multitenant.
<bean id="successRedirectHandler" class="org.MySamlAuthenticationSuccessHandler"
init-method="afterPropertiesSet">
<property name="contextPath" value="/myapi" />
<property name="defaultTargetUrl" value="https://default.myapp.com/myapi/saml/SSO"/>
<property name="requireProxyWrapping" value="false"/>
</bean>
Customize SAMLContextProviderLB by extending SamlContextProviderLB.
In custom class, add constructor and initialize with default values.
Override getLocalAndPeerEntity/getLocalEntity/populateLocalEntityId. In each of this method set lbDomain based on domain in requestURL.
above approach worked for me.

SOAP KeyInfo failed to recognise by IIS Server and client is java

I am getting following error while consuming .Net Web Service from java Spring
Web Service uses Certificate based authentication.
I tried java(Server) to java(Client) working locally using HTTPS and without https
Even .Net Side Server and client working.
org.springframework.ws.soap.client.SoapFaultClientException: Referenced security token could not be retrieved --->
WSE590: Failed to resolve the following Key Info
<KeyInfo Id="KI-A65A1CE3CB2EB7AE6114286591136763" xmlns="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=VXX,OU=NXX,O=iXXX,L=Cty,ST=MH,C=IN</ds:X509IssuerName>
<ds:X509SerialNumber>1711043036</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</KeyInfo>.
I am using org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor
to intercept request and response.
I don't understand whats happening at .Net side as its developed by other team.
But .Net Team told request is not reached to applcation, IIS server itself not able to process this.
Please find .Net client calling code snippet.
// TODO: Replace with a valid path to your certificate
string certPath = #"C:\mypath\certClient1.cer";
Secured.TSRService objsecserv = new Secured.TSRService();
objsecserv.Url = #"https://xyz/service.asmx";
//objsecserv.Url = #"http://xyz:97/service.asmx";
objsecserv.ClientCertificates.Add(X509Certificate.CreateFromCertFile(certPath));
objsecserv.Timeout = Timeout.Infinite;
string strresult1 = objsecserv.GetCertDetails();
rtxtresult.Text = strresult1;
And Here is my java side code snippet
<bean id="countryWsClSecInterId" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="Timestamp Signature" /> <!-- Encrypt -->
<!-- Key alias for signature -->
<property name="securementUsername" value="client" />
<property name="securementPassword" value="mypasswd" />
<property name="securementSignatureCrypto" ref="countryCrypto"/>
<property name="securementEncryptionCrypto" ref="countryCrypto"/>
<!-- Key alias for encryption -->
<property name="securementEncryptionUser" value="server"/>
<!-- Validation config -->
<property name="validationActions" value="Signature" />
<property name="validationSignatureCrypto" ref="countryCrypto"/>
</bean>
Please guide me , I searched a lot and made changes according but nothing worked.

Setting up CAS Jasig Server with database authentication

I am trying to setup Single Sign-On via a CAS server. I want to use database authentication as I have existing applications using spring security that authenticate through MySQL.
I am following the instructions on the official site, using their base maven overlay project as my starting point. Adding a database authentication handler seems straightforward from the instructions on the site - define the beans( db handler, password encoder and datasource) and add the handler to the list of handlers on the authenticationManager bean.
When I try to login on /cas/login, nothing happens. No query hits the database, as if the handler is not considered at all. The web page does not spit out an error about wrong credentials. The tomcat log does not give any errors or any signs of whats wrong and I am at a loss. What else do I need to setup?
My deployerConfigContext.xml is below. I have only edited/added stuff up to passwordEncoder. Everything else is from the default config that comes with the maven overlay project.
Thank you for your help and Happy New Year!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--
| The authentication manager defines security policy for authentication by specifying at a minimum
| the authentication handlers that will be used to authenticate credential. While the AuthenticationManager
| interface supports plugging in another implementation, the default PolicyBasedAuthenticationManager should
| be sufficient in most cases.
+-->
<bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
<constructor-arg>
<list>
<ref bean="dbAuthHandler" />
</list>
</constructor-arg>
<!-- Uncomment the metadata populator to allow clearpass to capture and cache the password
This switch effectively will turn on clearpass.
<property name="authenticationMetaDataPopulators">
<util:list>
<bean class="org.jasig.cas.extension.clearpass.CacheCredentialsMetaDataPopulator"
c:credentialCache-ref="encryptedMap" />
</util:list>
</property>
-->
<!--
| Defines the security policy around authentication. Some alternative policies that ship with CAS:
|
| * NotPreventedAuthenticationPolicy - all credential must either pass or fail authentication
| * AllAuthenticationPolicy - all presented credential must be authenticated successfully
| * RequiredHandlerAuthenticationPolicy - specifies a handler that must authenticate its credential to pass
-->
<property name="authenticationPolicy">
<bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />
</property>
</bean>
<!--
| TODO: Replace this component with one suitable for your enviroment.
|
| This component provides authentication for the kind of credential used in your environment. In most cases
| credential is a username/password pair that lives in a system of record like an LDAP directory.
| The most common authentication handler beans:
|
| * org.jasig.cas.authentication.LdapAuthenticationHandler
| * org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler
| * org.jasig.cas.adaptors.x509.authentication.handler.support.X509CredentialsAuthenticationHandler
| * org.jasig.cas.support.spnego.authentication.handler.support.JCIFSSpnegoAuthenticationHandler
-->
<bean id="dbAuthHandler" class="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler">
<property name="dataSource" ref="secureDataSource"></property>
<property name="passwordEncoder" ref="passwordEncoder"></property>
<property name="tableUsers" value="sec_user"></property>
<property name="fieldUser" value="username"></property>
<property name="fieldPassword" value="password"></property>
</bean>
<bean id="secureDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${secure.db.driver}"/>
<property name="url" value="${secure.db.url}"/>
<property name="username" value="${secure.db.username}"/>
<property name="password" value="${secure.db.password}"/>
<property name="maxActive" value="${secure.db.max.active}"/>
<property name="maxIdle" value="${secure.db.max.idle}"/>
<property name="minIdle" value="${secure.db.min.idle}"/>
<property name="testOnBorrow" value="${secure.db.testOnBorrow}"></property>
<property name="validationQuery" value="select 1"></property>
</bean>
<bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
<constructor-arg value="SHA256"></constructor-arg>
<property name="characterEncoding" value="UTF-8"></property>
</bean>
<!-- Required for proxy ticket mechanism -->
<bean id="proxyPrincipalResolver"
class="org.jasig.cas.authentication.principal.BasicPrincipalResolver" />
<!--
| Resolves a principal from a credential using an attribute repository that is configured to resolve
| against a deployer-specific store (e.g. LDAP).
-->
<bean id="primaryPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" >
<property name="attributeRepository" ref="attributeRepository" />
</bean>
<!--
Bean that defines the attributes that a service may return. This example uses the Stub/Mock version. A real implementation
may go against a database or LDAP server. The id should remain "attributeRepository" though.
+-->
<bean id="attributeRepository" class="org.jasig.services.persondir.support.StubPersonAttributeDao"
p:backingMap-ref="attrRepoBackingMap" />
<util:map id="attrRepoBackingMap">
<entry key="uid" value="uid" />
<entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
<entry key="groupMembership" value="groupMembership" />
</util:map>
<!--
Sample, in-memory data store for the ServiceRegistry. A real implementation
would probably want to replace this with the JPA-backed ServiceRegistry DAO
The name of this bean should remain "serviceRegistryDao".
+-->
<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"
p:registeredServices-ref="registeredServicesList" />
<util:list id="registeredServicesList">
<bean class="org.jasig.cas.services.RegexRegisteredService"
p:id="0" p:name="HTTP and IMAP" p:description="Allows HTTP(S) and IMAP(S) protocols"
p:serviceId="^(https?|imaps?)://.*" p:evaluationOrder="10000001" />
<!--
Use the following definition instead of the above to further restrict access
to services within your domain (including sub domains).
Note that example.com must be replaced with the domain you wish to permit.
This example also demonstrates the configuration of an attribute filter
that only allows for attributes whose length is 3.
-->
<!--
<bean class="org.jasig.cas.services.RegexRegisteredService">
<property name="id" value="1" />
<property name="name" value="HTTP and IMAP on example.com" />
<property name="description" value="Allows HTTP(S) and IMAP(S) protocols on example.com" />
<property name="serviceId" value="^(https?|imaps?)://([A-Za-z0-9_-]+\.)*example\.com/.*" />
<property name="evaluationOrder" value="0" />
<property name="attributeFilter">
<bean class="org.jasig.cas.services.support.RegisteredServiceRegexAttributeFilter" c:regex="^\w{3}$" />
</property>
</bean>
-->
</util:list>
<bean id="auditTrailManager" class="com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager" />
<bean id="healthCheckMonitor" class="org.jasig.cas.monitor.HealthCheckMonitor" p:monitors-ref="monitorsList" />
<util:list id="monitorsList">
<bean class="org.jasig.cas.monitor.MemoryMonitor" p:freeMemoryWarnThreshold="10" />
<!--
NOTE
The following ticket registries support SessionMonitor:
* DefaultTicketRegistry
* JpaTicketRegistry
Remove this monitor if you use an unsupported registry.
-->
<bean class="org.jasig.cas.monitor.SessionMonitor"
p:ticketRegistry-ref="ticketRegistry"
p:serviceTicketCountWarnThreshold="5000"
p:sessionCountWarnThreshold="100000" />
</util:list>
UPDATE:
For debugging purposes, here are two log files. One with the deployerConfig you see here, and one with the default one.
Mine: http://pastebin.com/9tRLPDq8
Default: http://pastebin.com/pxrUJMQG
In the default case I use wrong credentials on purpose. The most notable differences that I see are right before the audit(?) message:
Mine:
2015-01-02 09:58:15,515 DEBUG [org.springframework.webflow.execution.ActionExecutor] - <Executing [EvaluateAction#cdb588 expression = authenticationViaFormAction.submit(flowRequestContext, flowScope.credential, messageContext), resultExpression = [null]]>
2015-01-02 09:58:15,515 DEBUG [org.springframework.webflow.execution.AnnotatedAction] - <Putting action execution attributes map[[empty]]>
2015-01-02 09:58:15,515 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Returning cached instance of singleton bean 'authenticationViaFormAction'>
2015-01-02 09:58:15,517 INFO [org.perf4j.TimingLogger] - <start[1420221495517] time[0] tag[AUTHENTICATE]>
2015-01-02 09:58:15,518 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
...
Default:
2015-01-02 10:07:53,246 DEBUG [org.springframework.webflow.execution.AnnotatedAction] - <Putting action execution attributes map[[empty]]>
2015-01-02 10:07:53,246 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Returning cached instance of singleton bean 'authenticationViaFormAction'>
2015-01-02 10:07:53,266 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Returning cached instance of singleton bean 'auditTrailManagementAspect'>
2015-01-02 10:07:53,267 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Returning cached instance of singleton bean 'timingAspect'>
2015-01-02 10:07:53,272 DEBUG [org.jasig.cas.authentication.AcceptUsersAuthenticationHandler] - <admin was not found in the map.>
2015-01-02 10:07:53,272 INFO [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] - <AcceptUsersAuthenticationHandler failed authenticating admin+password>
2015-01-02 10:07:53,272 INFO [org.perf4j.TimingLogger] - <start[1420222073269] time[2] tag[AUTHENTICATE]>
2015-01-02 10:07:53,277 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
...
UPDATE 2:
I digged into the source a bit and compared the log messages to the expected ones. Looking at the authenticateInternal method, I do not see any of the log messages there when using the db handler, and I see them when I use the default handler. Assuming I actually reach this method, the only place where it can fail without a message appears to be for (final Credential credential : credentials) {...}.
Adding system info:
CAS 4.0.0
Tomcat 7
JDK 1.7
MySQL 5.5.22
UPDATE 3:
Well, it was looking at me right there all along...
WHO: audit:unknown
WHAT: java.security.NoSuchAlgorithmException: SHA256 MessageDigest not available**
ACTION: TICKET_GRANTING_TICKET_NOT_CREATED
APPLICATION: CAS
WHEN: Fri Jan 02 09:58:15 PST 2015
CLIENT IP ADDRESS: 0:0:0:0:0:0:0:1
SERVER IP ADDRESS: 0:0:0:0:0:0:0:1
Disclaimer: I'm the Chairman of CAS and founder of CAS in the cloud (https://www.casinthecloud.com).
Strange! The configuration looks good. Are you sure the overlay is properly built (overrided deployerConfigContext.xml file in the right directory)?
You should already have INFO logs in the cas.log file (https://github.com/Jasig/cas/blob/4.0.x/cas-server-webapp/src/main/resources/log4j.xml). Take a look at these logs...

Implementing Spring Switch User Filter with cas

I'm new to Spring security and cas.
In my project I have a cas(CenteralAuthenticationServer) server and a service server.
I want to implement Switch user filter for some users in my application.
Where I should put these lines?
<bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<property name="userDetailsService" ref="userDetailsService" />
<property name="switchUserUrl" value="/j_spring_security_switch_user" />
<property name="exitUserUrl" value="/j_spring_security_exit_user" />
<property name="targetUrl" value="/index.jsp" />
</bean>
In my cas project or in my web application?
Should I tell tomcat to use this filter in web.xml?
Is there any implementation example?
Should I create java class to implement this fitler?
Add it in your web application (dispatcher-servlet.xml). Check this example if you need.
switch user link

What is proper way to add encryption/decryption in spring-ws (wss4j)?

I have deployed 2 web apps, one representing web service and other representing ws client. When using SIGNING and TIMESTAMP-ing, everything works fine, client stamps message(but i think that he doesn't override the default 300s ttl), signs the message with his x509 cert, and sends it to ws. He, in the other hand, recives message and is able to valiadate timestamp and certificate/signature against clients trusted cert in his keystore.
Problem arises when i add Encrypt operation to my configuration. Client seems to be able to encrypt the message, but ws seems not to be intrested in decrypting the message. He just sees that there is no endpoint mapping for
[SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#}EncryptedData]
and throws
WebServiceTransportException: Not Found [404] exception.
SO can someone explain what I need to do in order to achieve timestamping,signing with x509 and encryption, again with x509?
part of server app-context:
<bean id="wss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<!-- valiadation -->
<property name="validationActions" value="Timestamp Signature Encrypt"/>
<property name="enableSignatureConfirmation" value="true"/>
<property name="validationSignatureCrypto">
<ref bean="keystore"/>
</property>
<property name="validationDecryptionCrypto">
<ref bean="keystore"/>
</property>
<property name="validationCallbackHandler">
<bean class="org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler">
<property name="privateKeyPassword" value="password"/>
</bean>
</property>
<!-- timestamp options -->
<property name="timestampStrict" value="true"/>
<property name="timeToLive" value="30"/>
<property name="timestampPrecisionInMilliseconds" value="true"/>
<!-- signing and encryption -->
<property name="securementActions" value="Timestamp Signature Encrypt"/>
<property name="securementUsername" value="wsserver"/>
<property name="securementPassword" value="password"/>
<property name="securementSignatureKeyIdentifier" value="DirectReference"/>
<property name="securementSignatureCrypto">
<ref bean="keystore"/>
</property>
<property name="securementEncryptionUser" value="wsclient"/>
<property name="securementEncryptionCrypto">
<ref bean="keystore"/>
</property>
</bean>
<!-- keystore -->
<bean id="keystore" class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
<property name="keyStorePassword" value="password"/>
<property name="keyStoreLocation" value="WEB-INF/MyTruststore.jks"/>
</bean>
<!-- interceptors -->
<sws:interceptors>
<ref bean="wss4jSecurityInterceptor"/>
<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema" value="/WEB-INF/person.xsd"/>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
<bean id ="loggingInterceptor" class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor">
</bean>
</sws:interceptors>
Client basicly uses the same config, except that he uses server public key for encryption, and his private key for decryption.
Keystores are ok, i guess, because signing works ok...Everything juust falls apart when i add Encrypt action, part of server log says:
DEBUG [org.springframework.ws.server.MessageTracing.recei ved] - Received request [SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#}EncryptedData]
DEBUG [org.springframework.ws.server.endpoint.mapping.Pay loadRootAnnotationMethodEndpointMapping] - Looking up endpoint for [{http://www.w3.org/2001/04/xmlenc#}EncryptedData]
DEBUG [org.springframework.ws.soap.server.SoapMessageDisp atcher] - Endpoint mapping [org.springframework.ws.server.endpoint.mapping.Pay loadRootAnnotationMethodEndpointMapping#30a14083] has no mapping for request
...
No endpoint mapping found for [SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#}EncryptedData]
org.springframework.ws.client.WebServiceTransportE xception: Not Found [404]
...
I think I must somehow instruct ws to decrypt SOAP body before it starts to look for an endpoint for message,but I don't know how. Suggestions?
Since your comments were helpful but kind of incomplete, I took a shoot of answering with a bit more of a detail.
In the spring tutorial, the endpoint method is annotated with #PayloadRoot: #PayloadRoot(localPart = "orderInput", namespace = "http://samples")
This works fine when the soap message is not encrypted. PayloadRootAnnotationMethodEndpointMapping is able to map to soap message to the corresponding method.
When the soap message is encrypted, the PayloadRootAnnotationMethodEndpointMapping is unable to map the soap message because The security interceptor did not have yet the time to decipher it. The solution is to replace #PayloadRoot with #SoapAction.
When a soap message is received, spring-ws calls first the PayloadRootAnnotationMethodEndpointMapping then SoapActionAnnotationMethodEndpointMapping. You can use both in order to be full compatible with non-spring client (axis for example or .net):
#PayloadRoot(localPart = "orderInput", namespace = "http://samples")
#SoapAction("http://samples/order")
Last but not least: If you are using a spring client with secured soap message, spring does not send soap action automatically. Your server will not be able to map the soap message with the appropriate action. In order to solve this problem, you should use a WebServiceMessageCallback:
ClientMessageCallBack callBack = new ClientMessageCallBack(
"http://samples/order");
Object output = wsTemplate.marshalSendAndReceive(inputObject, callBack);
where ClientMessageCallBack class is
public final class ClientMessageCallBack
implements WebServiceMessageCallback {
/**the soapAction to be appended to the soap message.*/
private String soapAction;
/**constructor.
* #param action the soapAction to be set.*/
public ClientMessageCallBack(final String action) {
this.soapAction = action;
}
#Override
public void doWithMessage(final WebServiceMessage message)
throws IOException, TransformerException {
if (message instanceof SoapMessage) {
SoapMessage soapMessage = (SoapMessage) message;
soapMessage.setSoapAction(soapAction);
}
}
}
this happens because you did not defined securementEncryptionParts property. It causes to encrypt whole body and made to this Error
Is there anyway to decrypt request before it triggers #Endpoint? issue is that client can not add soapaction.

Categories

Resources