I have a Spring boot project using SOAP 1.2 and WS-Security, and I can't figure out why the response contains two DigestValue, as far as i understand it should be one only... This is the current ws-security configuration:
import java.io.IOException;
import java.util.List;
import org.apache.wss4j.common.crypto.Crypto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.WsConfigurationSupport;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.security.wss4j2.callback.KeyStoreCallbackHandler;
import org.springframework.ws.soap.security.wss4j2.support.CryptoFactoryBean;
#Configuration
public class WSSecurityConfig extends WsConfigurationSupport {
#Value("${wssecurity.key-store}")
private String keystoreLocation;
#Value("${wssecurity.key-store-password}")
private String keystorePassword;
#Value("${wssecurity.server-certificate-alias}")
private String serverCertificateAlias;
#Value("${wssecurity.server-certificate-password}")
private String serverCertificatePassword;
#Value("${wssecurity.client-public-key}")
private String clientPublicKeyAlias;
/***Definizione del WS-Security Interceptor***/
#Bean
public CustomEndpointInterceptor wssecurityEndpointInterceptor() throws Exception {
CustomEndpointInterceptor customSmartEndpointInterceptor = new CustomEndpointInterceptor();
// validate incoming request
customSmartEndpointInterceptor.setValidationActions( "Signature" );
CryptoFactoryBean bean = getCryptoFactoryBean();
Crypto crypto = bean.getObject();
customSmartEndpointInterceptor.setValidationSignatureCrypto( crypto );
customSmartEndpointInterceptor.setValidationDecryptionCrypto( getCryptoFactoryBean().getObject());
customSmartEndpointInterceptor.setValidationCallbackHandler( securityCallbackHandler() );
// sign the response
customSmartEndpointInterceptor.setSecurementActions( "Signature" );
customSmartEndpointInterceptor.setSecurementUsername( serverCertificateAlias );
customSmartEndpointInterceptor.setSecurementPassword( serverCertificatePassword );
customSmartEndpointInterceptor.setSecurementSignatureKeyIdentifier( "DirectReference" );
customSmartEndpointInterceptor.setSecurementSignatureCrypto( getCryptoFactoryBean().getObject() );
return customSmartEndpointInterceptor;
}
#Bean
public CryptoFactoryBean getCryptoFactoryBean() throws IOException {
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
cryptoFactoryBean.setKeyStorePassword( keystorePassword ); .
cryptoFactoryBean.setKeyStoreLocation( new ClassPathResource( keystoreLocation ) );
return cryptoFactoryBean;
}
#Override
public void addInterceptors( List<EndpointInterceptor> interceptors ) {
try {
CustomEndpointInterceptor interceptor = wssecurityEndpointInterceptor();
interceptors.add( interceptor );
} catch ( Exception e ) {
throw new RuntimeException( "could not initialize security interceptor" );
}
}
#Bean
public KeyStoreCallbackHandler securityCallbackHandler() {
KeyStoreCallbackHandler callbackHandler = new KeyStoreCallbackHandler();
callbackHandler.setPrivateKeyPassword( serverCertificatePassword );
return callbackHandler;
}
}
This is an example response:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<wsse:Security env:mustUnderstand="true" 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">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="X509-dfd95ba9-b1a1-49a6-8277-2075c101619e">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</wsse:BinarySecurityToken>
<ds:Signature Id="SIG-98b69df3-1410-42b0-8947-e6d9a07d15c3" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="env" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-7a0a7c84-5537-4311-8798-0445e88048f6">
<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>aWqZez1xvQv4hBRBXtMpJDHYWxw=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#SC-cb19653f-2eab-42a6-93cf-e66efab96f85">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="wsse env" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>7v6BHKD7kICPCPwPVPl7fZ57p7o=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>Fwi8qjIVMnpT8Kb1uqHuuwS4aVFUenVleZflrtTth3xVpRnvtKqHJYQlNf1kWUvpdFlQrVxnQX5Ob6dukmEBnYlmbfDMBN2IMnqTchpe9GD+fUNkT2mcdMwLuaUOCp4cXjWTGL/T4IiRqnT66N1Tb1SwA1VKwO4YqfRB48KDh0oP/tgmFogFBpPowEuEf3GwQKJsE5k7Cbuy3g4PtdJ8woBulJGSU5FL7evqNeJwSEXgmhOEOohsGjf2/Uzr3fR60OpZXv+aHIV3NgDYe4FSCM4l/CfE7sOfh0DL6xYTzXSQxN6LDEu0gH7P0GiBSFLH85mGPhruEAhnIk2agVLWfw==</ds:SignatureValue>
<ds:KeyInfo Id="KI-1645752f-47f1-45d7-b935-6c4060edbeea">
<wsse:SecurityTokenReference wsu:Id="STR-d21a6c25-bf5f-4530-8f25-b31fd9ba2e72">
<wsse:Reference URI="#X509-dfd95ba9-b1a1-49a6-8277-2075c101619e" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsse11:SignatureConfirmation Value="HLhw/SB6gct2G+tr5cW5S6HrX80O1cCEfdtBAd22CMWqBJPVvlSJtB04uxRxUoAnEWx88GmAlpl9Tb89x/gnw+6qIsf8VYej5GeQdJi9Y2XSTkPy5Auy2ZmnOtl1UFzEKrLFZochffRf7oKEJjNs4VcWF6CflnNL6Wg3dQ0GZw03/mMYphn/N07lCivUdy4nuEGEu6qsbF/OvNI/fIC8Y7gby79Ooc0gAmg7Riwv7vGBShhZxTLZ0n3cTmbol7FcZifZLQcVz9rUmIldnslDupyAQHJWlEUruYovk8NpEPNljKEMZO2EmOMFnM3mNu5wUnb75Dui2MRI7IYd8a8iEg==" wsu:Id="SC-cb19653f-2eab-42a6-93cf-e66efab96f85" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"/>
</wsse:Security>
</env:Header>
Why are there two different DigestValue in the response? Shouldn't it be only one?
Thanks in advance.
Ok, got it.
There is a flag used in springboot, set to TRUE by default (the flag is actually a default in WSS4J, used by springboot). This flag enables Signature Confirmation and it is the cause of the double DigestValue in the response.
In order to disable it, i just needed to add this line:
customSmartEndpointInterceptor.setEnableSignatureConfirmation( false );
inside my wssecurityEndpointInterceptor() method
Related
all.
I'm interacting with a webservice that's requires signature and policy.
I set up my CXF (3.1.6 wildfly bundled) with binding provider properties, callback handler, keystore ect.
bp.getRequestContext().put(SecurityConstants.CALLBACK_HANDLER, new PasswordCallbackHandler());
bp.getRequestContext().put(SecurityConstants.SIGNATURE_PROPERTIES, MyUtils.class.getClassLoader().getResource("crypto.properties"));
bp.getRequestContext().put(SecurityConstants.SIGNATURE_USERNAME, "client");
CXF takes care to provide all necessary policy defined in the wsdl.
The comunications goes well, I send the request and receive the expected response.
But at this point the CXF Policy validator throws an exception:
org.apache.cxf.ws.policy.PolicyException: These policy alternatives can not be satisfied:
{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}SignedParts: Soap Body is not SIGNED
at org.apache.cxf.ws.policy.AssertionInfoMap.checkEffectivePolicy(AssertionInfoMap.java:179)
at org.apache.cxf.ws.policy.PolicyVerificationInInterceptor.handle(PolicyVerificationInInterceptor.java:102)
at org.apache.cxf.ws.policy.AbstractPolicyInterceptor.handleMessage(AbstractPolicyInterceptor.java:44)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
This is the contract for the signed parts:
<sp:SignedParts>
<sp:Body />
<sp:Header Namespace="http://www.w3.org/2005/08/addressing" Name="ReplyTo" />
<sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="MessageID" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Namespace="http://www.w3.org/2005/08/addressing" Name="Action" />
<sp:Header Name="RelatesTo" Namespace="http://www.w3.org/2005/08/addressing" />
</sp:SignedParts>
This is received response:
...
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<exc14n:InclusiveNamespaces PrefixList="wsse S"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#_5002">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>IirHgSUh19ly5qpPiXKVfMB2tZ4=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#_5003">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>8SY6Wz36TUlZtY+31Z5EpESs5JM=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#_5004">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>yvxtMZ3SC++ZOv0RPS/Ge9ETGHA=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#_5005">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>t/slFuF8/W8sWGrrAuJTmtliCeU=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#_5006">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>Cjcz1r8PMjV/04CLrMDpNx+e3ks=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#_3">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<exc14n:InclusiveNamespaces PrefixList="wsu wsse S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>6htA73nOJBrYMteWrJ9pdag3cA8=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
...
</S:Header>
<S:Body>
<ns2:getCallResponse xmlns:ns2="http://somenamespace/Schemas/" wsu:Id="_5006">
As you can seen there is a reference to the signed part but the ID attribute is not at the body (like for the request) level but on the child tag.
I don't know if this can be the problem, if so is a server side problem but the service is legacy and there's no way to change it.
So my question is: how I can disable the incoming policy validator or the specific assertion on SoapBody?
Thanks
Following the Colm O hEigeartaigh help, this is the resolution implemented.
Properties setup:
// Policy ovveride
Map<QName, SecurityPolicyValidator> validatorMap = new HashMap<>();
validatorMap.put(new QName("http://schemas.xmlsoap.org/ws/2005/07/securitypolicy", "SignedParts"), new FakeSecuredPartsValidator());
bp.getRequestContext().put(SecurityConstants.POLICY_VALIDATOR_MAP, validatorMap);
Fake validator based on the original one in CXF:
public class FakeSecuredPartsValidator implements SecurityPolicyValidator {
private CoverageType coverageType = CoverageType.ENCRYPTED;
/**
* Return true if this SecurityPolicyValidator implementation is capable of validating a
* policy defined by the AssertionInfo parameter
*/
#Override
public boolean canValidatePolicy(AssertionInfo assertionInfo) {
if (coverageType == CoverageType.SIGNED) {
return assertionInfo.getAssertion() != null
&& (SP12Constants.SIGNED_PARTS.equals(assertionInfo.getAssertion().getName())
|| SP11Constants.SIGNED_PARTS.equals(assertionInfo.getAssertion().getName()));
} else {
return assertionInfo.getAssertion() != null
&& (SP12Constants.ENCRYPTED_PARTS.equals(assertionInfo.getAssertion().getName())
|| SP11Constants.ENCRYPTED_PARTS.equals(assertionInfo.getAssertion().getName()));
}
}
/**
* Validate policies, set all as validates
*/
#Override
public void validatePolicies(PolicyValidatorParameters parameters, Collection<AssertionInfo> ais) {
//
// SIGNED_PARTS and ENCRYPTED_PARTS only apply to non-Transport bindings
//
if (isTransportBinding(parameters.getAssertionInfoMap(), parameters.getMessage())) {
return;
}
// Set asserted = true for all Assertions
for (AssertionInfo ai : ais) {
if (ai.isAsserted()) {
// Secured Parts could already have been asserted by one of the other validators, if
// they are a child of a SupportingToken
continue;
}
ai.setAsserted(true);
}
}
private boolean isTransportBinding(AssertionInfoMap aim, Message message) {
AssertionInfo symAis = PolicyUtils.getFirstAssertionByLocalname(aim, SPConstants.SYMMETRIC_BINDING);
if (symAis != null) {
return false;
}
AssertionInfo asymAis = PolicyUtils.getFirstAssertionByLocalname(aim, SPConstants.ASYMMETRIC_BINDING);
if (asymAis != null) {
return false;
}
AssertionInfo transAis = PolicyUtils.getFirstAssertionByLocalname(aim, SPConstants.TRANSPORT_BINDING);
if (transAis != null) {
return true;
}
// No bindings, check if we are using TLS
TLSSessionInfo tlsInfo = message.get(TLSSessionInfo.class);
if (tlsInfo != null) {
// We don't need to check these policies for TLS
PolicyUtils.assertPolicy(aim, SP12Constants.ENCRYPTED_PARTS);
PolicyUtils.assertPolicy(aim, SP11Constants.ENCRYPTED_PARTS);
PolicyUtils.assertPolicy(aim, SP12Constants.SIGNED_PARTS);
PolicyUtils.assertPolicy(aim, SP11Constants.SIGNED_PARTS);
return true;
}
return false;
}
public CoverageType getCoverageType() {
return coverageType;
}
public void setCoverageType(CoverageType coverageType) {
this.coverageType = coverageType;
}
}
The service is not following the spec, the Body element itself must be signed, and not the child Element as in the request above. However, recent versions of CXF allow you to plug in custom validation logic via the "ws-security.policy.validator.map" JAX-WS property. This is a map which maps a QName to a SecurityPolicyValidator instance. So in your case you can map to SignedParts policy QName to a modified version of the default SecuredPartsPolicyValidator to change the validation logic.
In OpenSAML 2.5, I used the following code to generate a SAML Assertion with Security Certificate details:
Credential signingCredential = sign.getSigningCredential();
Signature signature = null;
try {
DefaultBootstrap.bootstrap();
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
signature = (Signature) Configuration.getBuilderFactory()
.getBuilder(Signature.DEFAULT_ELEMENT_NAME)
.buildObject(Signature.DEFAULT_ELEMENT_NAME);
signature.setSigningCredential(signingCredential);
// This is also the default if a null SecurityConfiguration is
// specified
SecurityConfiguration secConfig = Configuration
.getGlobalSecurityConfiguration();
try {
SecurityHelper.prepareSignatureParams(signature,
signingCredential, secConfig, null);
} catch (SecurityException e) {
e.printStackTrace();
} catch (org.opensaml.xml.security.SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SsoSamlWriter samlWriter = new SsoSamlWriter(ssoData);
Assertion assertion = samlWriter.buildSamlAssertion();
SAML msg extract:
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<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="#514131e4-8ef0-469c-b8b0-a185b874320e">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="xs" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>fmIxhw8sGFU/J3SWDk5BnBCKRog=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>HOHkf...pqj2w==</ds:SignatureValue>
<KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIID...6BS9K
L/SvOZxWrA==</ds:X509Certificate>
</ds:X509Data>
</KeyInfo>
</ds:Signature>
I am trying to update this code to OpenSAML 3.2 and I have been able to get the SAML msg generated, but I don;t know how to attach the detailed security cert data. Does anyone have a code example for adding the SignatureValue and X509Certificate details to the SAML Assertion?
OpenSAML 3.2 Code I have so far:
Credential signingCredential = sign.getSigningCredential();
SsoSamlWriter samlWriter = new SsoSamlWriter(ssoData);
Assertion assertion = samlWriter.buildSamlAssertion();
Signature signature = SAMLUtils.buildSAMLObject(Signature.class);
signature.setSigningCredential(signingCredential);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
// Need to supply an org.opensaml.security.credential.Credential;
signature.setSigningCredential(signingCredential);
assertion.setSignature(signature);
try {
XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(assertion).marshall(assertion);
} catch (MarshallingException e) {
throw new RuntimeException(e);
}
try {
Signer.signObject(signature);
} catch (SignatureException e) {
throw new RuntimeException(e);
}
// Wrap assertion in SAML Response
ResponseBuilder responseBuilder = new ResponseBuilder();
Response samlResponse = responseBuilder.buildObject();
// Build an Issuer object
Issuer issuer = SAMLUtils.buildSAMLObject(Issuer.class);
issuer.setValue(ssoIssuerName);
issuer.setSPProvidedID(ssoUrlSuffix);
// Add NameID element to assertion with Oasis Employee SSN
Subject subject = new SubjectBuilder().buildObject();
NameID nameID = new NameIDBuilder().buildObject();
nameID.setValue(empSsn);
nameID.setFormat(NameIDType.X509_SUBJECT);
subject.setNameID(nameID);
assertion.setSubject(subject);
String responseIdStr = UUID.randomUUID().toString();
assertion.setID(responseIdStr);
samlResponse.setID(responseIdStr);
samlResponse.setIssueInstant(new DateTime());
samlResponse.setIssuer(issuer);
samlResponse.setVersion(SAMLVersion.VERSION_20);
samlResponse.setStatus(samlWriter.createStatus());
samlResponse.getAssertions().add(assertion);
ResponseMarshaller marshaller = new ResponseMarshaller();
Element plain = marshaller.marshall(samlResponse);
String samlResponseStr = XMLHelper.nodeToString(plain);
// Remove ds: prefix from <ds:KeyInfo> elements
// stegre => Accomodate bug on CIC side, remove this line eventually
samlResponseStr = samlResponseStr.replaceAll("ds:KeyInfo", "KeyInfo");
System.out.println("");
System.out.println("SAML Response: ");
System.out.println(samlResponseStr);
System.out.println("");
Resulting SAML message:
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response ID="356498c8-036d-41b1-9602-89fa90e40331" IssueInstant="2016-10-12T15:15:23.987Z" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2:Issuer SPProvidedID="OasisAdvantage" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">OasisAdvantage</saml2:Issuer>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion ID="356498c8-036d-41b1-9602-89fa90e40331" IssueInstant="2016-10-12T15:15:20.442Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<saml2:Issuer SPProvidedID="OasisAdvantage">OasisAdvantage</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<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="#356498c8-036d-41b1-9602-89fa90e40331">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="xsd" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue/>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue/>
</ds:Signature>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">OasisUser</saml2:NameID>
</saml2:Subject>
<saml2:Conditions NotBefore="2016-10-12T15:15:20.442Z" NotOnOrAfter="2016-10-12T15:20:20.442Z"/>
<saml2:AuthnStatement AuthnInstant="2016-10-12T15:15:20.566Z" SessionNotOnOrAfter="2016-10-12T15:15:20.581Z">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement>
<saml2:Attribute Name="companyid">
<saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">OasisAdvantage</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</saml2p:Response>
The following code added the computed SignatureValue:
org.opensaml.saml.saml2.core.Response samlResponse = responseBuilder.buildObject();
// Compute and add SignatureValue element to Signature
XMLObjectProviderRegistrySupport.getMarshallerFactory()
.getMarshaller(samlResponse).marshall(samlResponse);
Signer.signObject(signature);
I'm using spring-ws (2.1.4) WebServiceTemplate with a custom WebServiceMessageCallback to insert the security header with a SAML which I will receive as a org.w3c.dom.Element and only create myself for testing.
I use webServiceTemplate.marshalSendAndReceive(request, new HeaderCallback(ctx, uri)) to marshal and send my request.
My issue is that the verification of the signature fails on the server side, the digests don't match. Comparing the output of the SAML before sending and after receiving I see that on the receiving side I have namespace declarations on elements that didn't have one before sending.
What I currently do in my callback:
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
super.doWithMessage(message);
Assert.isInstanceOf(SoapMessage.class, message);
SoapMessage soapMessage = (SoapMessage) message;
SoapHeaderElement securityHeader = soapMessage.getSoapHeader().addHeaderElement(WS_SECURITY_NAME);
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.transform(new DOMSource(assertion), securityHeader.getResult());
} catch (org.springframework.oxm.MarshallingException ex) {
throw new IOException(ex);
}
Does anyone know how I can insert an element into a SOAP XML making sure that the element will not be modified? Or is there a different approach to achieve this using Spring WebServiceTemplate?
I came across org.apache.ws.security.saml.ext.SAMLCallback which has a method setAssertionElement, however I did not find out how to get this working with the WebServiceTemplate (respectively Wss4jSecurityInterceptor) particularly considering that I need to pass in an existing SAML assertion as a parameter.
SAML XML before sending:
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" IssueInstant="2015-09-23T09:46:14.357Z" Version="2.0">
<saml2:Issuer>iTEST</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<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="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<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>rVbvzGr4LI/Kd0c+kuhqkupSY44=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>TIbtFHnqURfko94eqANDX8UEhw0HSI3xL0sAQ5GbhjVn2DicckzxpoJL3RVPF6KhLOkUPm5IgnF5At6Es69D48DLE+QvWvP0F7VmcdNJHRSnzIWYaJsXfNfDt2AXXM1kanp5Gq8nj1EsT6C8SlkO1x77C3vKkn1nLSNszEkukuhEzA8V7G+l6L65bIveA36IyYqjiVDKIMOIzHMF9qK03Um7qJHWoxvxSig1UPBINlBtDqyhbGW01OnoHP8qXK7bzuP6p3zbBDhhEYMyNV2P8GT8zX1+cv+JE6ghde4K9hyf6V+x6L218L1AOjACEJUkBrxw0q1uJAVGA1UNJPJbJQ==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIC1TCCAb2gAwIBAgIENFWkEzANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBpVEVTVDpjb21tdW5pdHlBMB4XDTE1MDkxMDE0NDcyMFoXDTI1MDkwNzE0NDcyMFowGzEZMBcGA1UEAxMQaVRFU1Q6Y29tbXVuaXR5QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMX9f6af8s8bqZSlSl7nZVmVz9sQuaxK/fYHwKcBCmeQGfx67K6Lrmg4ZkVlMxFPFAZta8i0UHVbFXD6hY4nD8skA+P1RjnHvk4KboBM2krtx7tSC8IzXmtb8sxXsfLKfu1Blqq0lX0kjPyvCIo4FLOSRE//AuKy8zeTSrKAX8tcZYo23mX8TWkp22Hd6O/x4IxuakWRB6fq8DxYWFsu9f1cnt2n3R+d/myrZ6XRVdpZhptWlZjzy90L2VOuHFC3kY8DvgSCdI3UgL+PzD7R3cKUytHlz04LO5cJue4kRaGbNOdgJoRdj4D24BsjpIZ9PCbzSw689N/hRftsUtO5PRECAwEAAaMhMB8wHQYDVR0OBBYEFBL153jJBGRArnJ5dSyHZGKC3vGcMA0GCSqGSIb3DQEBCwUAA4IBAQCWa0KtdISsQecjA3i4Kyr50oynOnas6YK9Jgb3LzJEU911JW4vX4rHmXEe64OkbIO/fpdCE30saTiBoLEFxrUx0xn+0wGvPMIBJZYncaZUUN9412XPEjYoj5DnFjFvdYqNsdNZ9cOs3sa5hRWufea+QFhSJKSG0nouwW1/5WT3/GYtKJZystL2N2q6pUqhwfP5x1JDELTcoiZZzbTkHOxFiz5iLMrZyDL8Bmb856pF7SzmD6NzLXpqiOwMjTeDWyJ3I9mZqDwoTwxC/e8wG42d486GKu3O/BbDkxEv5UDClMY2722oZKKhu3TdQLOIOLJChKgghjuEWOXb+mDdj/Qq</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject>
<saml2:NameID>authSigner</saml2:NameID>
</saml2:Subject>
</saml2:Assertion>
SAML XML after receiving:
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" IssueInstant="2015-09-23T09:46:14.357Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">iTEST</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:Reference URI="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">rVbvzGr4LI/Kd0c+kuhqkupSY44=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">TIbtFHnqURfko94eqANDX8UEhw0HSI3xL0sAQ5GbhjVn2DicckzxpoJL3RVPF6KhLOkUPm5IgnF5At6Es69D48DLE+QvWvP0F7VmcdNJHRSnzIWYaJsXfNfDt2AXXM1kanp5Gq8nj1EsT6C8SlkO1x77C3vKkn1nLSNszEkukuhEzA8V7G+l6L65bIveA36IyYqjiVDKIMOIzHMF9qK03Um7qJHWoxvxSig1UPBINlBtDqyhbGW01OnoHP8qXK7bzuP6p3zbBDhhEYMyNV2P8GT8zX1+cv+JE6ghde4K9hyf6V+x6L218L1AOjACEJUkBrxw0q1uJAVGA1UNJPJbJQ==</ds:SignatureValue>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">MIIC1TCCAb2gAwIBAgIENFWkEzANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBpVEVTVDpjb21tdW5pdHlBMB4XDTE1MDkxMDE0NDcyMFoXDTI1MDkwNzE0NDcyMFowGzEZMBcGA1UEAxMQaVRFU1Q6Y29tbXVuaXR5QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMX9f6af8s8bqZSlSl7nZVmVz9sQuaxK/fYHwKcBCmeQGfx67K6Lrmg4ZkVlMxFPFAZta8i0UHVbFXD6hY4nD8skA+P1RjnHvk4KboBM2krtx7tSC8IzXmtb8sxXsfLKfu1Blqq0lX0kjPyvCIo4FLOSRE//AuKy8zeTSrKAX8tcZYo23mX8TWkp22Hd6O/x4IxuakWRB6fq8DxYWFsu9f1cnt2n3R+d/myrZ6XRVdpZhptWlZjzy90L2VOuHFC3kY8DvgSCdI3UgL+PzD7R3cKUytHlz04LO5cJue4kRaGbNOdgJoRdj4D24BsjpIZ9PCbzSw689N/hRftsUtO5PRECAwEAAaMhMB8wHQYDVR0OBBYEFBL153jJBGRArnJ5dSyHZGKC3vGcMA0GCSqGSIb3DQEBCwUAA4IBAQCWa0KtdISsQecjA3i4Kyr50oynOnas6YK9Jgb3LzJEU911JW4vX4rHmXEe64OkbIO/fpdCE30saTiBoLEFxrUx0xn+0wGvPMIBJZYncaZUUN9412XPEjYoj5DnFjFvdYqNsdNZ9cOs3sa5hRWufea+QFhSJKSG0nouwW1/5WT3/GYtKJZystL2N2q6pUqhwfP5x1JDELTcoiZZzbTkHOxFiz5iLMrZyDL8Bmb856pF7SzmD6NzLXpqiOwMjTeDWyJ3I9mZqDwoTwxC/e8wG42d486GKu3O/BbDkxEv5UDClMY2722oZKKhu3TdQLOIOLJChKgghjuEWOXb+mDdj/Qq</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">authSigner</saml2:NameID>
</saml2:Subject>
</saml2:Assertion>
</wsse:Security>
EDIT: I found a way that does not add the additional namespaces. What I'm doing now is using the javax.xml.soap.SOAPMessage and importing the node:
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
super.doWithMessage(message);
Assert.isInstanceOf(SaajSoapMessage.class, message);
try {
SOAPMessage soapMessage = ((SaajSoapMessage) message).getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
if (soapEnvelope.getHeader() == null) {
soapEnvelope.addHeader();
}
SOAPHeaderElement securityElement = soapEnvelope.getHeader().addHeaderElement(WS_SECURITY_NAME);
securityElement.appendChild(soapPart.importNode(assertion, true));
} catch (SOAPException ex) {
throw new IOException(ex);
}
}
However, even though the diff shows no difference between the outputs the verification is still failing. At this point I'm not sure if I can trust the output and that doing it like that really did not change the SAML...
Any ideas what else could cause the digests not to match?
The following approach (which I already documented on my question as an edit) prevented additional namespaces from being added.
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
super.doWithMessage(message);
Assert.isInstanceOf(SaajSoapMessage.class, message);
try {
SOAPMessage soapMessage = ((SaajSoapMessage) message).getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
if (soapEnvelope.getHeader() == null) {
soapEnvelope.addHeader();
}
SOAPHeaderElement securityElement = soapEnvelope.getHeader().addHeaderElement(WS_SECURITY_NAME);
securityElement.appendChild(soapPart.importNode(assertion, true));
} catch (SOAPException ex) {
throw new IOException(ex);
}
}
I also got the SAML validation to work. It had nothing to do with the way the SAML was added to the SOAP message (also my original approach using Transformer- even though it adds the additional namespaces - validates now). Missing was the ID on the assertion.
Here's how my SAML looks now:
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_63ecd7ce7163507e56270edcd644494b" IssueInstant="2015-09-24T18:23:15.118Z" Version="2.0">
<saml2:Issuer>iTEST</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<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="#_63ecd7ce7163507e56270edcd644494b">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<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>yjlkSOIJC3qNYzEYfipGIwoAD9A=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>fIEp5aYFVesexZWAfMM+e8kcwe52nl54xMr92wtz2BZ3TIVkY6u5vfh8hA0q6hkzEEaHV5vM0cEXholekn4og41jhMn7XwmScggrbr/neYBMdE95GRz6Nv2Sc6PzqPTYeFp+Dylho7sy1yZtWAb3jiGm8zdHJIQuk6NNUZhnMPkZqjXpM68U9cRGojAmnczbRVl2couxDp5fErivKJgJuffN3FVBfCFrFOjGpVf00ukZxqJJ3RP+n7wXWl251W0i0KvWCZPCD5gzl69EzNFc78o8khzd26aLIeDFLBQr0BPnrC454dZZ/SSNeH52HtDstNJ6SBrWFAA8c8vnLSJ0fg==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIC1TCCAb2gAwIBAgIENFWkEzANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBpVEVTVDpjb21tdW5pdHlBMB4XDTE1MDkxMDE0NDcyMFoXDTI1MDkwNzE0NDcyMFowGzEZMBcGA1UEAxMQaVRFU1Q6Y29tbXVuaXR5QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMX9f6af8s8bqZSlSl7nZVmVz9sQuaxK/fYHwKcBCmeQGfx67K6Lrmg4ZkVlMxFPFAZta8i0UHVbFXD6hY4nD8skA+P1RjnHvk4KboBM2krtx7tSC8IzXmtb8sxXsfLKfu1Blqq0lX0kjPyvCIo4FLOSRE//AuKy8zeTSrKAX8tcZYo23mX8TWkp22Hd6O/x4IxuakWRB6fq8DxYWFsu9f1cnt2n3R+d/myrZ6XRVdpZhptWlZjzy90L2VOuHFC3kY8DvgSCdI3UgL+PzD7R3cKUytHlz04LO5cJue4kRaGbNOdgJoRdj4D24BsjpIZ9PCbzSw689N/hRftsUtO5PRECAwEAAaMhMB8wHQYDVR0OBBYEFBL153jJBGRArnJ5dSyHZGKC3vGcMA0GCSqGSIb3DQEBCwUAA4IBAQCWa0KtdISsQecjA3i4Kyr50oynOnas6YK9Jgb3LzJEU911JW4vX4rHmXEe64OkbIO/fpdCE30saTiBoLEFxrUx0xn+0wGvPMIBJZYncaZUUN9412XPEjYoj5DnFjFvdYqNsdNZ9cOs3sa5hRWufea+QFhSJKSG0nouwW1/5WT3/GYtKJZystL2N2q6pUqhwfP5x1JDELTcoiZZzbTkHOxFiz5iLMrZyDL8Bmb856pF7SzmD6NzLXpqiOwMjTeDWyJ3I9mZqDwoTwxC/e8wG42d486GKu3O/BbDkxEv5UDClMY2722oZKKhu3TdQLOIOLJChKgghjuEWOXb+mDdj/Qq</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject>
<saml2:NameID>authSigner</saml2:NameID>
</saml2:Subject>
</saml2:Assertion>
I am using CXF to consume a webservice
It involves signing the <SignedInfo> node with my private key and also encrypting the <soap:Body> node .
I am using WSS4JOutInterceptor to sign the soap message .
I am not able to figure out on how to specify WSS4J to sign the <SignedInfo> header node .
Also I want to put my custom Thumbprint in the header . Which I guess is used by the service provider to identify the public key they have to use .
Below is my Soap Header generated right now with the Java code I have used in the comments
<soap: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:mustUnderstand="1">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-3">
<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"/>
<!--
Have to transform body and message control block
Did it using
outProps.put(WSHandlerConstants.SIGNATURE_PARTS, "{Element} {http://schemas.xmlsoap.org/soap/envelope/}Body;{Element}{https://checkout.buckaroo.nl/PaymentEngine/}MessageControlBlock");
I am not sure wether us should be SIGNATUE_ or ENCRYPT_ PARTS
-->
<ds:Reference URI="#id-1">
<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>Ougg/udU=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#id-2">
<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>9cObhmiilqw=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<!--
Also have to generate a signature value which should be of the SignedInfo node
outProps.put(WSHandlerConstants.ACTION, "Signature");
outProps.put(WSHandlerConstants.SIG_PROP_FILE, "client_sign.properties");
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,ClientCallbackHandler.class.getName());
-->
<ds:SignatureValue>
no6CvOuwhLNGVOP1ByuICAVnSFTNq77QQttl4GIgHzatxr/ldna6yf36kufuzsHNx2n0Fp1k/05WZF9UPnzw=
</ds:SignatureValue>
<ds:KeyInfo Id="KI-AB3C213816422">
<wsse:SecurityTokenReference wsu:Id="STR-AB3C213816422">
<!--
Have to include my custom Thumbprint value here in wsse:KeyIdentifier node
outProps.put(WSHandlerConstants.SIG_KEY_ID, "Thumbprint");
-->
<wsse:KeyIdentifier
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1">
z9576mEB7M7uRGq1vXGxwX4w4A0=
</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
<!--
This block I have added manually using
List<Header> headersList = new ArrayList<Header>();
MessageControlBlock messageControlBlock = new MessageControlBlock();
messageControlBlock.setWebsiteKey("I6t2");
messageControlBlock.setCulture("123L");
ObjectFactory factory = new ObjectFactory();
JAXBElement<MessageControlBlock> messCtlBlock = factory.createMessageControlBlock(messageControlBlock);
JAXBContext context = JAXBContext.newInstance(https.checkout_buckaroo_nl.paymentengine.MessageControlBlock.class);
Header messageControlBlockElement = new Header(
new QName("https://checkout.buckaroo.nl/PaymentEngine/", "MessageControlBlock"),
messageControlBlock,
new JAXBDataBinding(context));
headersList.add(messageControlBlockElement);
provider.getRequestContext().put(Header.HEADER_LIST, headersList); -->
<MessageControlBlock xmlns="https://checkout.buckaroo.nl/PaymentEngine/"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="id-2">
<WebsiteKey>I6tNcjYiMt</WebsiteKey>
<Culture>nl-NL</Culture>
</MessageControlBlock>
</soap:Header>
**I have also tried to intercept the message so that I can get the header from soap envelope and can myself update the thumbprint value .
But I am not able to get the Signature value in the Interceptor .
**
public class HeaderInterceptor extends AbstractSoapInterceptor {
public HeaderInterceptor() {
super(Phase.PRE_PROTOCOL_ENDING);
getAfter().add(org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor.SAAJOutEndingInterceptor.class.getName());
}
public void handleMessage(SoapMessage message) throws Fault {
System.out.println("HeaderInterceptor");
List<Header> headers = message.getHeaders();
System.out.println("Version is " + message.getVersion());
Map<String, List<String>> headersw = CastUtils.cast((Map)message.get(Message.PROTOCOL_HEADERS));
System.out.println("Headers w is " + headersw);
message.getInterceptorChain().forEach(chain -> {
System.out.println(chain.getClass());
});
Header security = message.getHeader(
new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security")
);
System.out.println("Security header is " + security);
headers.stream().forEach(head ->{
System.out.println(head.getName().getLocalPart());
});
}
}
Output of above program is
Version is org.apache.cxf.binding.soap.Soap11#5404d5
Headers w is {Accept=[*/*], SOAPAction=["https://checkout.buckaroo.nl/PaymentEngine/CentralSoapGateway/InvoiceInfo"]}
class org.apache.cxf.jaxws.interceptors.HolderOutInterceptor
class org.apache.cxf.jaxws.interceptors.SwAOutInterceptor
class org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor
class org.apache.cxf.binding.soap.interceptor.SoapHeaderOutFilterInterceptor
class org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor
class org.apache.cxf.interceptor.MessageSenderInterceptor
class com.testapp.commons.MyLogInterceptor
class org.apache.cxf.interceptor.AttachmentOutInterceptor
class org.apache.cxf.interceptor.StaxOutInterceptor
class org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor
class org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor
class org.apache.cxf.interceptor.WrappedOutInterceptor
class org.apache.cxf.interceptor.BareOutInterceptor
class org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor$WSS4JOutInterceptorInternal
class org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor$SoapOutEndingInterceptor
class org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor$SAAJOutEndingInterceptor
**class com.testapp.commons.HeaderInterceptor**
class org.apache.cxf.interceptor.StaxOutEndingInterceptor
class org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor
Security header is null
MessageControlBlock
I'm connecting to a webservice with axis/rampart and was told to remove the InclusiveNamespaces as the prefixList was "" which is not allowed. How do I do that?
The part looks like
<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="wsa soapenv" />
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#Id-289005241">
<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>bla bla bla=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
Is it possible to configure axis/rampart to not print the inclusivenamespace when it's empty?
I'm using axis/rampart 1.6.2 and connecting to a .NET service
Any ideas how to archive this? Or how do I make it render a non empty prefixList ?
You have to add a custom handler to filter the unwanted xml tag.
custom handler:
package com.perre;
public class InclusiveNamespacesFilter extends AbstractHandler {
public InvocationResponse invoke(MessageContext ctx) throws AxisFault {
SOAPEnvelope msgEnvelope = ctx.getEnvelope();
SOAPHeader msgHeader = msgEnvelope.getHeader();
Iterator theDescendants = msgHeader.getDescendants(true);
while(theDescendants.hasNext()){
Object o = theDescendants.next();
//here, add your code to traverse DOM and get the node to filter
//...
Node aNode = ele.getElementsByTagName("ec:InclusiveNamespacesFilter").item(0);
if(aNode != null){
ele.removeChild(aNode);
}
}
return InvocationResponse.CONTINUE;
}
edit your axis2.xml and declare the handler:
<phase name="PostSecurity">
<handler name="FilterHandler" class="com.perre.InclusiveNamespacesFilter"/>
</phase>
You should be ready to go. Find more reading about custom handlers here.