Recently, I have been playing with Spring WS with WS-Security. I just want to write down how it works. Do not except anything special, just simple example of basic security operations.
The example
We want to implement both client and server side. The client will sign the message, encrypt some part of it and add a timestamp. To make it more complex and real-life like we will sign the message using private key with alias “client” and encrypt the message using public key called “server”. Server will validate that the request is valid and will just sign the response using his key called “server”. Please note that I have picked Wss4j implementation because the configuration seemed to be easier than Xws.
Client
It’s easy to do configure client interceptor like this.
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <property name="interceptors"> <list> <ref local="wsClientSecurityInterceptor"/> </list> </property> ... </bean> <bean id="wsClientSecurityInterceptor" 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="" /> <property name="securementSignatureCrypto" ref="clientCrypto"/> <property name="securementEncryptionCrypto" ref="clientCrypto"/> <property name="securementEncryptionParts" value="{Content}{http://javacrumbs.net/calc}a"/> <!-- Key alias for encryption --> <property name="securementEncryptionUser" value="server"/> <!-- Validation config --> <property name="validationActions" value="Signature" /> <property name="validationSignatureCrypto" ref="clientCrypto"/> </bean> <bean id="clientCrypto" class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean"> <property name="keyStorePassword" value="mypasswd"/> <property name="keyStoreLocation" value="classpath:security/client-keystore.jks"/> </bean>
As you can see, there is nothing special. We just define which actions to take and properties. The only confusing part is, that key alias is defined as “securementUsername”.
Whit this configuration we will get following SOAP message.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"> <SOAP-ENV:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1"> <xenc:EncryptedKey Id="EncKeyId-F5114C147B958E706212759086159355" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> <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"> <ds:X509Data> <ds:X509IssuerSerial> <ds:X509IssuerName>CN=Test Server,OU=Test</ds:X509IssuerName> <ds:X509SerialNumber>1275904530</ds:X509SerialNumber> </ds:X509IssuerSerial> </ds:X509Data> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>fwFM7ShJ1xd7dTGrkh0410sTmW92OPB1q1fpzB21XFIe36siDDJWGgbw5B94yjmGK2YaPOWLb7cpVTYPzc9VUDs7Jc42CtrhT2H6eZ7CDiA60Ugz+qi2UyyfMDK6Vrdj9J68rij5P12AiBeTnd2wlhI29+71XbUpD5weHDHjMtQ= </xenc:CipherValue> </xenc:CipherData> <xenc:ReferenceList> <xenc:DataReference URI="#EncDataId-4" /> </xenc:ReferenceList> </xenc:EncryptedKey> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-2"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <ds:Reference URI="#id-3"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>AU9utUgz5RylYCRDUAO0JWM48kM=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> NHjjgpb9/alUOq50CqPKLcdYrp7edYdKJDNvIhh+2OAhYdDvZmD1qGsVKd1H9oKPF17uaF2Sv3aY 0le6BrvzVx3n2+nYYlHwAWlzBk7wsBt4vLll6q6juLCP+siupTIb1PeZDf3WrAbHUQh5oqjD6cZB Sc89pDspWRABQ8wPxYE= </ds:SignatureValue> <ds:KeyInfo Id="KeyId-F5114C147B958E706212759086157652"> <wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-F5114C147B958E706212759086157673" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ds:X509Data> <ds:X509IssuerSerial> <ds:X509IssuerName>CN=Lukas Krecan,OU=Test</ds:X509IssuerName> <ds:X509SerialNumber>1275900789</ds:X509SerialNumber> </ds:X509IssuerSerial> </ds:X509Data> </wsse:SecurityTokenReference> </ds:KeyInfo> </ds:Signature> <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-1"> <wsu:Created>2010-06-07T11:03:35.749Z</wsu:Created> <wsu:Expires>2010-06-07T11:08:35.749Z</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-3"> <ns2:plusRequest xmlns:ns2="http://javacrumbs.net/calc"> <ns2:a> <xenc:EncryptedData Id="EncDataId-4" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"> <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"> <wsse:Reference URI="#EncKeyId-F5114C147B958E706212759086159355" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" /> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>81TEtUhHXo6iZeAmYrtYlm2ObAqOBpjfzf2VOVUg4Hs= </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </ns2:a> <ns2:b>2</ns2:b> </ns2:plusRequest> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Server config
To configure server, you have to define Spring WS server interceptor like this (full example).
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"> <property name="interceptors"> <list> <ref local="wsServerSecurityInterceptor" /> </list> </property> </bean> <bean id="wsServerSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor"> <!-- Validation part --> <property name="validationActions" value="Timestamp Signature Encrypt"/> <property name="validationSignatureCrypto" ref="serverCrypto"/> <property name="validationDecryptionCrypto" ref="serverCrypto"/> <property name="validationCallbackHandler"> <bean class="org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler"> <property name="keyStore"> <bean class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean"> <property name="password" value="mypasswd"/> </bean> </property> <property name="privateKeyPassword" value=""/> </bean> </property> <!-- Sign the response --> <property name="securementActions" value="Signature" /> <property name="securementUsername" value="server" /> <property name="securementPassword" value="" /> <property name="securementSignatureCrypto" ref="serverCrypto"/> </bean> <bean id="serverCrypto" class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean"> <property name="keyStorePassword" value="mypasswd"/> <property name="keyStoreLocation" value="classpath:security/server-keystore.jks"/> </bean>
No surprise here neither. The response will look like this.
<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" SOAP-ENV:mustUnderstand="1"> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-6"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <ds:Reference URI="#id-7"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>hEdDfxM6Nfs62Jxe8EOsELCDtUk=</ds:DigestValue> </ds:Reference> <ds:Reference URI="#SigConf-5"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>TTSRri5KJqXeMJfjzXyVmUewPxc=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue> V5by3bOoGQNajfs7i9xQ+cbAqIkI0NS9N9FQlLb/dAuQfguE7jKRP9iypOeRLHCPr7g3BNg+NCrX 6YcgDQ0TfXNhdL00AmoEfDmWSNvIVNE49kZEn3Ji/RW4VtdEiV79VD7Vuay0YAYGo9DSQvzq3FP6 YEhfzfMqvfbWMdEKcO8= </ds:SignatureValue> <ds:KeyInfo Id="KeyId-F5114C147B958E706212759086160837"> <wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-F5114C147B958E706212759086160838" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <ds:X509Data> <ds:X509IssuerSerial> <ds:X509IssuerName>CN=Test Server,OU=Test</ds:X509IssuerName> <ds:X509SerialNumber>1275904530</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" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" Value="NHjjgpb9/alUOq50CqPKLcdYrp7edYdKJDNvIhh+2OAhYdDvZmD1qGsVKd1H9oKPF17uaF2Sv3aY0le6BrvzVx3n2+nYYlHwAWlzBk7wsBt4vLll6q6juLCP+siupTIb1PeZDf3WrAbHUQh5oqjD6cZBSc89pDspWRABQ8wPxYE=" wsu:Id="SigConf-5" /> </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-7"> <ns2:plusResponse xmlns:ns2="http://javacrumbs.net/calc"> <ns2:result>3</ns2:result> </ns2:plusResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
As we have seen it’s possible to configure WS-Security without much hassle. To learn more, visit the official Spring WS reference. You can download full example here.