Spring Ws Digital Certificate Authentication Wss4J
You can use digital certificates to secure your soap services. In this tutorial we explain certificate authentication, we show how to encrypt and decrypt your messages via digital certificates, we show how to sign and verify the digital signature, and we show how to add and verify the timestamp of the message.
Dependencies
In order to use apache’s Wss4j
implementation, we use the following dependencies. Make sure all these dependencies are on the class path. We also use the jaxb2-maven-plugin
to generate our java classes from an XSD schema.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.memorynotfound.spring.ws</groupId>
<artifactId>ws-security-certificate-wss4j-security-interceptor</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>SPRING-WS - ${project.artifactId}</name>
<url>https://memorynotfound.com</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-security</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ws.security</groupId>
<artifactId>wss4j</artifactId>
<version>1.6.19</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>src/main/resources/xsd</source>
</sources>
</configuration>
</plugin>
</plugins>
</build>
</project>
Spring WS Soap Server Endpoint
We are going to secure the following service using certificate authentication. We are also going to encrypt the content of this message, so that if we send this message over an unsecure channel, the data isn’t compromised. Note that this service isn’t aware of any security measurements. This is a great example of separation of concerns.
package com.memorynotfound.server;
import com.memorynotfound.beer.Beer;
import com.memorynotfound.beer.GetBeerRequest;
import com.memorynotfound.beer.GetBeerResponse;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
@Endpoint
public class BeerEndpoint {
public static final String NAMESPACE_URI = "https://memorynotfound.com/beer";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getBeerRequest")
@ResponsePayload
public GetBeerResponse getBeer(@RequestPayload GetBeerRequest request) {
GetBeerResponse beerResponse = new GetBeerResponse();
Beer beer = new Beer();
beer.setId(request.getId());
beer.setName("Beer name");
beerResponse.setBeer(beer);
return beerResponse;
}
}
Spring WS Certificate Authentication Server
Apache Wss4j
Ws-Security implementation does not need an external configuration file. It can be completely configured using properties. We secure our server using a Wss4jSecurityInterceptor
. In this interceptor we register both validation actions – for validating the incoming requests – and securement actions – for securing and encrypting the outgoing responses.
To validate the incoming request we register the Timestamp, Signature and Encrypt actions using the setValidationActions()
method. When the incoming request is validated, we process the request and finally send a response. But we want to encrypt the content of the response, we do this by setting the setSecurementEncryptionParts()
. The securementEncryptionParts property defines which parts of the message will be encrypted. Finally, we register the Signature and Encrypt securementActions
in order to sign and encrypt the outgoing response.
package com.memorynotfound.server;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor;
import org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler;
import org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
import java.io.IOException;
import java.util.List;
@EnableWs
@Configuration
public class SoapServerConfig extends WsConfigurerAdapter {
@Bean
public KeyStoreCallbackHandler securityCallbackHandler(){
KeyStoreCallbackHandler callbackHandler = new KeyStoreCallbackHandler();
callbackHandler.setPrivateKeyPassword("changeit");
return callbackHandler;
}
@Bean
public Wss4jSecurityInterceptor securityInterceptor() throws Exception {
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
// validate incoming request
securityInterceptor.setValidationActions("Timestamp Signature Encrypt");
securityInterceptor.setValidationSignatureCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setValidationDecryptionCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setValidationCallbackHandler(securityCallbackHandler());
// encrypt the response
securityInterceptor.setSecurementEncryptionUser("client-public");
securityInterceptor.setSecurementEncryptionParts("{Content}{https://memorynotfound.com/beer}getBeerResponse");
securityInterceptor.setSecurementEncryptionCrypto(getCryptoFactoryBean().getObject());
// sign the response
securityInterceptor.setSecurementActions("Signature Encrypt");
securityInterceptor.setSecurementUsername("server");
securityInterceptor.setSecurementPassword("changeit");
securityInterceptor.setSecurementSignatureCrypto(getCryptoFactoryBean().getObject());
return securityInterceptor;
}
@Bean
public CryptoFactoryBean getCryptoFactoryBean() throws IOException {
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
cryptoFactoryBean.setKeyStorePassword("changeit");
cryptoFactoryBean.setKeyStoreLocation(new ClassPathResource("server.jks"));
return cryptoFactoryBean;
}
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
try {
interceptors.add(securityInterceptor());
} catch (Exception e) {
throw new RuntimeException("could not initialize security interceptor");
}
}
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext appContext){
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(appContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
@Bean(name = "beers")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema){
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("BeersPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace(BeerEndpoint.NAMESPACE_URI);
wsdl11Definition.setSchema(schema);
return wsdl11Definition;
}
@Bean
public XsdSchema beersSchema(){
return new SimpleXsdSchema(new org.springframework.core.io.ClassPathResource("xsd/beers.xsd"));
}
}
Also note that we add the keystore of the server in order to validate and sign the request and responses using a digital certificate. The server.jks
is the server’s keystore and contains the private key of the server and public key of the client. Here is an example of how to create a public-private keystore using java keytool.
Running The Server
After we successfully configured the server to use digital certificates, we can start the server using spring boot using the following code.
package com.memorynotfound.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RunServer {
public static void main(String[] args) {
SpringApplication.run(RunServer.class);
}
}
Digital Certificate Authentication Client
We use the following code to make a request to the server. Again, the client isn’t aware of any security measurements. The security is implemented using interceptors, triggered before each request.
package com.memorynotfound.client;
import com.memorynotfound.beer.GetBeerRequest;
import com.memorynotfound.beer.GetBeerResponse;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
public class BeerClient extends WebServiceGatewaySupport {
public GetBeerResponse getBeer(GetBeerRequest request){
return (GetBeerResponse) getWebServiceTemplate()
.marshalSendAndReceive(request);
}
}
Configure Digital Certificate on the Client
We configure the client to add the Timestamp, Signature and Encrypt actions via the setSecurementActions()
method. This instructs the apache’s Wss4j
implementation to encrypt the message using a digital signature. We pass the keystore via the setSecurementSignatureCrypto()
method and also provide the certificate to use and the password of the keystore for signing the request. Next, we configure the interceptor to encrypt the outgoing message, by setting the securementEnryptionParts
and configuring it with a keystore and keypass.
package com.memorynotfound.client;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor;
import org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean;
import java.io.IOException;
@Configuration
public class SoapClientConfig {
@Bean
public Wss4jSecurityInterceptor securityInterceptor() throws Exception {
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
// set security actions
securityInterceptor.setSecurementActions("Timestamp Signature Encrypt");
// sign the request
securityInterceptor.setSecurementUsername("client");
securityInterceptor.setSecurementPassword("changeit");
securityInterceptor.setSecurementSignatureCrypto(getCryptoFactoryBean().getObject());
// encrypt the request
securityInterceptor.setSecurementEncryptionUser("server-public");
securityInterceptor.setSecurementEncryptionCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setSecurementEncryptionParts("{Content}{https://memorynotfound.com/beer}getBeerRequest");
securityInterceptor.setSecurementSignatureKeyIdentifier("DirectReference");
return securityInterceptor;
}
@Bean
public CryptoFactoryBean getCryptoFactoryBean() throws IOException {
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
cryptoFactoryBean.setKeyStorePassword("changeit");
cryptoFactoryBean.setKeyStoreLocation(new ClassPathResource("client.jks"));
return cryptoFactoryBean;
}
@Bean
public Jaxb2Marshaller getMarshaller(){
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.memorynotfound.beer");
return marshaller;
}
@Bean
public BeerClient getBeerClient() throws Exception {
BeerClient beerClient = new BeerClient();
beerClient.setMarshaller(getMarshaller());
beerClient.setUnmarshaller(getMarshaller());
beerClient.setDefaultUri("http://localhost:8080/ws/beers");
ClientInterceptor[] interceptors = new ClientInterceptor[]{securityInterceptor()};
beerClient.setInterceptors(interceptors);
return beerClient;
}
}
Running The Client
We bootstrap the application using spring, and send a simple request to the server.
package com.memorynotfound.client;
import com.memorynotfound.beer.GetBeerRequest;
import com.memorynotfound.beer.GetBeerResponse;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class RunClient {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SoapClientConfig.class);
BeerClient wsclient = context.getBean(BeerClient.class);
GetBeerRequest request = new GetBeerRequest();
request.setId(2);
GetBeerResponse resp = wsclient.getBeer(request);
System.out.println("response: " + resp);
}
}
Example Digital Certificate Signed and Encrypted Request
When we execute the previous client, the following request is sent to the server. We can see that inside the Security
element resides a EncryptedKey
, which is used to encrypt the content of the message. There is also a Signature
element. This element is used to sign the request. The Timestamp
element is also added in the request. Finally, the last thing to notice is that the content of the message is encrypted using the EncryptedKey
element.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" SOAP-ENV:mustUnderstand="1">
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="EK-C186347A7DA99F64F114594133713207">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" />
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=memorynotofund.com,OU=server-keystore,O=memorynotfound,L=antwerp,ST=antwerp,C=BE</ds:X509IssuerName>
<ds:X509SerialNumber>2055146281</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>FNwE0WMa6K5jAw5xm8oi4t/eNbQb3d27q9wKU0X0WPsoabjgbb7KP61Bkky+f5Ludei8ihKFAIglvUM/UuxSee4IUPkboil3WzEtJUnLuYrH0x5RNs2HMDilZcxYnigl6pwQ8wXgFeeEtO9xtXccSfJdQbXInIolu7w6MkMDuoCXTxcv0ptiB9MbSjYe1EWmGKagAjqz+TVn6UB0yXkHn9jfEm2XmIoG3lwXEq6tZ1f7WOeE3Yr/rWqIGPSUaXYdk1N8sQ5h8nJW+ThoNorFNEsM0BZa+C8QbXMrTfhg8+dhFmTH49Cc3OYI2n6L0sFaI62DU7SPZcw71kCuxAUKFg==</xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#ED-C186347A7DA99F64F114594133713328" />
</xenc:ReferenceList>
</xenc:EncryptedKey>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-C186347A7DA99F64F114594133711346">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="SOAP-ENV" />
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#id-C186347A7DA99F64F114594133711275">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>rYc2u8ueo1REBJCIUjf+plZKbFg=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>lisTwtaBC8ExltJDyc0rceGwLjzgXJGajnuj5ipjDwcfEAIIlYK4eaCfgPdO8IMpTIx08792nt004qsIBMLjSltheNEgNTCpNC3jRQtaLdmxHaCdyTxvLxDeB2wZD9RmdqVc49ktUz/42oPpoFJ8OgSUzJ7OwE2YtlTxwtycziCBPCcfUAIZK3OpJt0AOIaBAHMngwPyVYBP0KlxL5EKtoMOjQJBKbHxG3gMFnBu7l2uMGfenkrDlOVt+2AhiLQagwX/r/E6wxCTM/dYzpkHOovL+Dlki5Z0NoDMMLurq5zfd05KCU3KFZmJRzlaStfr/WD/t1K/GZCmA3AcNMMjFQ==</ds:SignatureValue>
<ds:KeyInfo Id="KI-C186347A7DA99F64F114594133711213">
<wsse:SecurityTokenReference wsu:Id="STR-C186347A7DA99F64F114594133711234">
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=memorynotfound.com,OU=client-keystore,O=memorynotfound,L=antwerp,ST=antwerp,C=BE</ds:X509IssuerName>
<ds:X509SerialNumber>465244230</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsu:Timestamp wsu:Id="TS-C186347A7DA99F64F114594133711071">
<wsu:Created>2016-03-31T08:36:11.106Z</wsu:Created>
<wsu:Expires>2016-03-31T08:41:11.106Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-C186347A7DA99F64F114594133711275">
<ns2:getBeerRequest xmlns:ns2="https://memorynotfound.com/beer">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-C186347A7DA99F64F114594133713328" Type="http://www.w3.org/2001/04/xmlenc#Content">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<ds:KeyInfo xmlns:ds="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" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
<wsse:Reference URI="#EK-C186347A7DA99F64F114594133713207" />
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>FTfVmbx9EZ5VkPvVREVu6PQk4aZJ+WC6da5lm9Y/LRqlgPebVg2VOKXK3tkslSAo</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</ns2:getBeerRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Example Digital Certificate Signed and Encrypted Response
When server successfully processed the request, it responds with the following output. Inside the Security
element there is also a EncryptedKey
, which is used to encrypt the content of the response message. Next element we see the Signature
, this element is used to sign the message. Finally, we see the SignatureConfirmation
which tells us the confirmation of the signature. Note that also the response is encrypted using the EncryptedKey
from the Security
element.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" SOAP-ENV:mustUnderstand="1">
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="EK-E5F0D4AD565E12F95C145941337142023">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" />
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=memorynotfound.com,OU=client-keystore,O=memorynotfound,L=antwerp,ST=antwerp,C=BE</ds:X509IssuerName>
<ds:X509SerialNumber>465244230</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>AKB4xz130Koe1AWOOnDezp6t+mC5PHBZgpbyH/2n6HIvefRNUT5p/hFlMkf8EiGW3L/r/YNl+R0S7f3ZwlIzriIGEHU/W7kc3oXAg1+DNchzRIz3A0PHvHVU5bwM7RvG/eyDOXxynWUrcZ0oOnDHN0jrSVdEw+ZKVUI0PSE4IrFvCFUrrJ2hsS75cFuEzYgSIyrtbr6fdOJjjH9Y8O2MSjcjOXLSFmF8+uPX4GFySc1sED/SXdTKeOhOWQUM7At1R9AXVfbGQmuJvUjVEYoU5GS7pyfoEgz0uA51rFgYJQYB69MOgbxPKsQhwWY3nV4r3x4Sc56YoJrr3xqzyu9JNg==</xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#ED-E5F0D4AD565E12F95C145941337142024" />
</xenc:ReferenceList>
</xenc:EncryptedKey>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-E5F0D4AD565E12F95C145941337141122">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="SOAP-ENV" />
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#id-E5F0D4AD565E12F95C145941337141021">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>YDqCsLmLtQz6DdtrRcaH3mIUV5I=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#SC-E5F0D4AD565E12F95C145941337141017">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="wsse SOAP-ENV" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>epH0Tdn18foc285Kj4Pt0fdl4To=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>cVDDU+7AgtZR6wtbWacEtn66X48axD4XiFu7z44U9Lx0tfht73J+cGoJoxnxsQ4XLuauDOD7bTVclldEy2L1mFgJYmDX0IBB68ANoMWaWlr7IrGAVeka3ct3dwf6LIeRtPqjzcoQdSVoSbjFUMjIxMtXKLrAgm1WZoFIAOWOwY5870MI27NrtZE5sYEBi2oRSCEK/R7bsbH/cC7nPMK3QfwgPhwHJU1wBPdg4MME8cCD7TGBf7YOKwy1m6d+2u8hbXp1N3+rh7Mdwpc/B9C4k1XjYv78UFxwD05zXY1dcjKgSk9h9doUx74Cti+Be/grmopcpZOUFtacCXdhrEtUkQ==</ds:SignatureValue>
<ds:KeyInfo Id="KI-E5F0D4AD565E12F95C145941337141019">
<wsse:SecurityTokenReference wsu:Id="STR-E5F0D4AD565E12F95C145941337141020">
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=memorynotofund.com,OU=server-keystore,O=memorynotfound,L=antwerp,ST=antwerp,C=BE</ds:X509IssuerName>
<ds:X509SerialNumber>2055146281</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsse11:SignatureConfirmation xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" Value="lisTwtaBC8ExltJDyc0rceGwLjzgXJGajnuj5ipjDwcfEAIIlYK4eaCfgPdO8IMpTIx08792nt004qsIBMLjSltheNEgNTCpNC3jRQtaLdmxHaCdyTxvLxDeB2wZD9RmdqVc49ktUz/42oPpoFJ8OgSUzJ7OwE2YtlTxwtycziCBPCcfUAIZK3OpJt0AOIaBAHMngwPyVYBP0KlxL5EKtoMOjQJBKbHxG3gMFnBu7l2uMGfenkrDlOVt+2AhiLQagwX/r/E6wxCTM/dYzpkHOovL+Dlki5Z0NoDMMLurq5zfd05KCU3KFZmJRzlaStfr/WD/t1K/GZCmA3AcNMMjFQ==" wsu:Id="SC-E5F0D4AD565E12F95C145941337141017" />
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-E5F0D4AD565E12F95C145941337141021">
<ns2:getBeerResponse xmlns:ns2="https://memorynotfound.com/beer">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-E5F0D4AD565E12F95C145941337142024" Type="http://www.w3.org/2001/04/xmlenc#Content">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<ds:KeyInfo xmlns:ds="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" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
<wsse:Reference URI="#EK-E5F0D4AD565E12F95C145941337142023" />
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>Y6oxCHVybeDMSge2OnMzEmINwo9pmHIJvVtdyMrVT5RK9lOiYpTwzQASbVxxoVIJokCuFwu4gzLnMEwrzdcLUA/hQQ8P4ACN1oTKcT4IBlx0isr38YNe5FTQ0gKRdVRl</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</ns2:getBeerResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
References
- KeyStoreCallbackHandler JavaDoc
- Wss4jSecurityInterceptor JavaDoc
- CryptoFactoryBean JavaDoc
- Spring Ws Reference Documentation
Great article, but I have a problem. The server is able to receive data from the client. //Server @PayloadRoot(namespace = NAMESPACE_URI, localPart = “getBeerRequest”) @ResponsePayload public GetBeerResponse getBeer(@RequestPayload GetBeerRequest request) { GetBeerResponse beerResponse = new GetBeerResponse(); Beer beer = new Beer(); beer.setId(request.getId()); beer.setName(“Duff Beer”); beerResponse.setBeer(beer); System.out.println(“ID: “+request.getId()); return beerResponse; } ID: 2 But the client is not being able to receive data from the server. //Client GetBeerResponse resp = wsclient.getBeer(request); System.out.println(“response: ” + resp); response: com.memorynotfound.beer.GetBeerResponse@396ef8b2 or GetBeerResponse resp = wsclient.getBeer(request); System.out.println(“response: ” + resp.getBeer()); response: null Both the server and the client are able to receive or send their… Read more »
You have to add the Bean securityCallbackHandler in the SoapClientConfig class
@Bean
public KeyStoreCallbackHandler securityCallbackHandler(){
KeyStoreCallbackHandler callbackHandler = new KeyStoreCallbackHandler();
callbackHandler.setPrivateKeyPassword(“changeit”);
return callbackHandler;
}
And modify the Bean securityInterceptor to
@Bean
public Wss4jSecurityInterceptor securityInterceptor() throws Exception {
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
// set security actions
securityInterceptor.setSecurementActions(“Timestamp Signature Encrypt”);
// sign the request
securityInterceptor.setSecurementUsername(“client”);
securityInterceptor.setSecurementPassword(“changeit”);
securityInterceptor.setSecurementSignatureCrypto(getCryptoFactoryBean().getObject());
// encrypt the request
securityInterceptor.setSecurementEncryptionUser(“server-public”);
securityInterceptor.setSecurementEncryptionCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setSecurementEncryptionParts(“{Content}{http://memorynotfound.com/beer}getBeerRequest”);
// sign the response
securityInterceptor.setValidationActions(“Signature Encrypt”);
securityInterceptor.setValidationSignatureCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setValidationDecryptionCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setValidationCallbackHandler(securityCallbackHandler());
return securityInterceptor;
}
Yes this worked and thanks for sharing this snippet.
How can I make this value read from the message information received in the service?
securityInterceptor.setSecurementEncryptionUser()
Where can I find the WSDL file for this example?
Where can I find the WSDL file for this example?
I am getting Cannot find SOAP wrapper for element [xenc:EncryptedData: null], when tried to encrypt the whole body. any suggestions.
Have you solved this issue? I’m still facing it today and nothing works.. idk
It is a best are that I got in the internet. Could you help me with this similar problem. I have posted a question on stackoverflow, though you could help me on that.
Link: https://stackoverflow.com/questions/63593636/wss-config-on-soap-call