I am trying IDP initiated login only on SAML2.0. I have an XML string of Signature block which I need to generate SignatureValue using OpenSAML.
Using Java Security I am able to do like below and able to return the generated Signature value but while I am sending to the service provider it is sending 401-Unauthorized, where I realized I need to use OpenSAML in place of java security package.
How can I generate SignatureValue from the below XML using OpenSAML?
Note: I do not have any POJO classes of my SOAP XML.
Signature Block:
<?xml version="1.0" encoding="UTF-8"?>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#Body-a23jlkasdjfo2urojsdklf">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>XXXXXXXXXXXXXXXXXXX</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue />
<KeyInfo>
<wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#SecurityToken-a23jlkasdjfo2urojsdklf" />
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
Java Code:
public static String generateSignatureValue(String signatureMessage, String signatureAlgorithm,
String privateKeyString)
throws Exception {
org.apache.xml.security.Init.init();
Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
byte[] canonXmlBytes = canon.canonicalize(signatureMessage.getBytes());
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString));
PrivateKey privateKey = kf.generatePrivate(keySpecPKCS8);
java.security.Signature rsaSha1Signature = java.security.Signature.getInstance(signatureAlgorithm);
rsaSha1Signature.initSign(privateKey);
rsaSha1Signature.update(canonXmlBytes);
byte[] signed2 = rsaSha1Signature.sign();
return Base64.getEncoder().encodeToString(signed2);
}
Related
I have the following SAML response that I need to decrypt and verify.
<saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-13b5261b-6429-4fc6-9df4-00ba4c956df4" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey Id="EK-cde830f3-5741-440c-a6a3-03d7fc29bec7">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</xenc:EncryptionMethod>
<ds:KeyInfo>
<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=Foo,OU=Ba,O=Foobaa,C=AU
</ds:X509IssuerName>
<ds:X509SerialNumber>161...39233</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>
OrjesuK...lOQ==
</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>
RHkpDrgRX0AJprMr...k62Q==
</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</saml:EncryptedAssertion>
I have access to the public and private keys used in encrypted and I am currently trying to decrypt it using the following code:
// Given here a EncryptedAssertion type populated from the above xml
// Open and initialise the Keystore
KeyStore ks = KeyStore.getInstance("PKCS12");
try (FileInputStream fileInputStream = new FileInputStream("keystoreUrl")) {
ks.load(fileInputStream, config.getBAMKeystorePassword().toCharArray());
}
PrivateKey certificate= (PrivateKey) ks.getKey("privateKeyAlias", null);
// Decrypt the encrypted assertion
BasicX509Credential cred = new BasicX509Credential();
cred.setPrivateKey(certificate);
StaticKeyInfoCredentialResolver resolver = new StaticKeyInfoCredentialResolver(cred);
Decrypter decrypter = new Decrypter(resolver, resolver, new InlineEncryptedKeyResolver());
decrypter.setRootInNewDocument(true);
Assertion decrypted = decrypter.decrypt(encryptedAssertion);
This however gives an exception of:
java.lang.IllegalArgumentException: Data decryption key may not be null
I've tried several different combinations of loading the key, but cannot locate the error. Is someone able to please help me in progressing?
I implementing a Spring-WS web service client and I send a request without unmarshaling because I am sending a ready-made signed (wssec) request with all SOAP wrappers.
For example:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<SOAP-ENV:Header>
<wsse:Security wsu:Id="Id-sec-98b44dc4123d94b309db4e47881c48c0cfde" SOAP-ENV:actor="http://smev.gosuslugi.ru/actors/smev">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="Id-sig-02747f3e4b2c3afbd9ee0c47b82df6ce1ce1">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102012-gostr34112012-256"/>
<Reference URI="#Id-wssecdata-d8392bad08e2095ea110d7ebdf6cb20b77f0" Id="Id-dataref-2f98695f5d03929ba61e8553e17275e99ea0">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256"/>
<DigestValue>DIGECT</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>SIG_VALUE</SignatureValue>
<KeyInfo Id="Id-keyinfo-60c321e68eba4e0b869013c3b661a255d39a">
<wsse:SecurityTokenReference wsu:Id="Id-strT8lVAuhyhE9ORsox">
<wsse:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#Id-bstKf4S_QPNjJpr839_"/>
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
<wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" wsu:Id="Id-bstKf4S_QPNjJpr839_">CERT</wsse:BinarySecurityToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body wsu:Id="Id-wssecdata-d8392bad08e2095ea110d7ebdf6cb20b77f0">
<Message/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
But according to the algorithm defined in the Spring-WS documentation, Spring-WS additionally wraps my request in envelopes by calling the createWebServiceMessage() in WebServiceTemplate.
The sent result is as follows:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<SOAP-ENV:Header>
<wsse:Security wsu:Id="Id-sec-98b44dc4123d94b309db4e47881c48c0cfde" SOAP-ENV:actor="http://smev.gosuslugi.ru/actors/smev">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="Id-sig-02747f3e4b2c3afbd9ee0c47b82df6ce1ce1">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102012-gostr34112012-256"/>
<Reference URI="#Id-wssecdata-d8392bad08e2095ea110d7ebdf6cb20b77f0" Id="Id-dataref-2f98695f5d03929ba61e8553e17275e99ea0">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256"/>
<DigestValue>DIGECT</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>SIG_VALUE</SignatureValue>
<KeyInfo Id="Id-keyinfo-60c321e68eba4e0b869013c3b661a255d39a">
<wsse:SecurityTokenReference wsu:Id="Id-strT8lVAuhyhE9ORsox">
<wsse:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#Id-bstKf4S_QPNjJpr839_"/>
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
<wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" wsu:Id="Id-bstKf4S_QPNjJpr839_">CERT</wsse:BinarySecurityToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body wsu:Id="Id-wssecdata-d8392bad08e2095ea110d7ebdf6cb20b77f0">
<Message/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And this is how I do it:
public void callWebService(String request) {
StreamSource source = new StreamSource(new StringReader(request));
StreamResult result = new StreamResult(System.out);
getWebServiceTemplate().sendSourceAndReceiveToResult(source, webServiceMessage -> {
SaajSoapMessage saajMessage = (SaajSoapMessage) webServiceMessage;
saajMessage.setSoapAction(SOAP_ACTION);
}, result);
It seems to me that using SAAJ will not help. How can I send my request? Thanks!
Found a solution on my own. It consists in build a new SAAJ message and replacing it with the old one. I hope someone will be helpful.
public void callWebService(String request) {
StreamSource source = new StreamSource(new StringReader(request));
StreamResult result = new StreamResult(System.out);
getWebServiceTemplate().sendSourceAndReceiveToResult(source, webServiceMessage -> {
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) webServiceMessage;
try {
SOAPPart soapPart = saajSoapMessage.getSaajMessage().getSOAPPart();
SOAPBody soapBody = soapPart.getEnvelope().getBody();
Document innerSoapBody = soapBody.extractContentAsDocument();
//Строим новое SAAJ-сообщение for webServiceMessage
MessageFactory soapMessageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = soapMessageFactory.createMessage();
soapMessage.getSOAPPart().setContent(new DOMSource(innerSoapBody));
((SaajSoapMessage) webServiceMessage).setSaajMessage(soapMessage);
} catch (SOAPException e) {
LOGGER.error("Can't rebuild WebServiceMessage in SMEV2 invoke!");
e.printStackTrace();
}
//Передаим корректный SOAP-Action.
saajSoapMessage.setSoapAction(SMEV2_SOAP_ACTION);
}, result);
I am able to create a SAMLResponse using OpenSAML, but as a sanity check I wanted to validate the signature. The recipient wants the Assertion to be signed but not the Response, which looks just fine:
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response ID="1111111111" Version="2.0"
xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2:Assertion Version="2.0"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<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#">H1M/MSp4KUwKryB9c99XvE6PWaU=
</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
npeqj35bPh06G6WcSBzfpaDEqVUzhEOgqARKB6NIowGcAoD6yHpmDYTJ0nXvS31cRFYxqWtCVIrX
e7abo3mpwfLI7FjpEawP+8IEaMi++b0hN1Xri/bprMNjxB7kldDGJc2WkbdVRAAIknQetxytd9gB
WGhP97zLyGPVK23orH/JF09bFgoqGPgd/14fuY5ksOJuFfuZD4rsCOxxicYrfMsJDnlUfz8n18Xw
Jj6vX/0SDoDknMz9h4kh1TU4tus0FvIAPYLNB7QV7Iarpd+5Q9R8mj+NJEviFH/DZlqE/NYrxRNt
iinOgOnz1x3dtnDr2O/BHIW55mlBFi0L6wJ7ow==
</ds:SignatureValue>
</ds:Signature>
</saml2:Assertion>
</saml2p:Response>
If I validate the signature before marshalling the response, it's valid:
protected static void testSignature(Credential credential) throws Exception {
DefaultBootstrap.bootstrap();
SignatureBuilder builder = new SignatureBuilder();
Signature signature = builder.buildObject();
signature.setSigningCredential(credential);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
Assertion assertion = new AssertionBuilder().buildObject();
assertion.setVersion(SAMLVersion.VERSION_20);
assertion.setSignature(signature);
AssertionMarshaller aMarsh = new AssertionMarshaller();
aMarsh.marshall(assertion);
Signer.signObject(signature);
Response response = new ResponseBuilder().buildObject();
response.setVersion(SAMLVersion.VERSION_20);
response.setID("1111111111");
response.getAssertions().add(assertion);
Signature sig = response.getAssertions().get(0).getSignature();
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
profileValidator.validate(sig);
SignatureValidator sigValidator = new SignatureValidator(credential);
sigValidator.validate(sig); //valid
}
However if I marshall the response by adding the following code, it comes back invalid even if I set the signature before marshalling:
...
Signature sig = response.getAssertions().get(0).getSignature();
ResponseMarshaller rMarsh = new ResponseMarshaller();
Element plain = rMarsh.marshall(response);
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
profileValidator.validate(sig);
SignatureValidator sigValidator = new SignatureValidator(credential);
sigValidator.validate(sig); //invalid
Lastly I tried to unmarshall the marshalled response, then read and validate the signature, and it still comes back invalid even though I can verify the response is the same as before marshalling/unmarshalling.
...
ResponseMarshaller rMarsh = new ResponseMarshaller();
Element plain = rMarsh.marshall(response);
String samlResponse1 = XMLHelper.nodeToString(plain);
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(plain);
XMLObject responseXmlObj = unmarshaller.unmarshall(plain);
Response newResponse = (Response) responseXmlObj;
plain = rMarsh.marshall(newResponse);
String samlResponse2 = XMLHelper.nodeToString(plain);
System.out.println(StringUtils.equals(samlResponse1, samlResponse2)); //true
Signature sig = newResponse.getAssertions().get(0).getSignature();
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
profileValidator.validate(sig);
SignatureValidator sigValidator = new SignatureValidator(credential);
sigValidator.validate(sig); //invalid
What's going on? Is there something I'm missing here?
Solved this. The Assertion requires an ID value that is different from the Response ID. I just needed to add the following line of code and it worked.
assertion.setID("1111111112");
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
Hi i need some infomation on saml 2.0 Authn Request . I want to sign my authn request with a openssl created *.pkcs8 file. I can do with a keystore file using java keytool . But I want to achieve the same using *.PKCS8 file generateing using the openssl. I have been struggling with this for some time . I am able to generate the xml with it .
// Authn Request ...
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="http://localhost:8080/sp/AssertionConsumerService" Destination="http://localhost:8080/idp/SingleSignOnService" ID="95cc3943-67dd-43ef-809b-2ccd8bd3e4e9" IssueInstant="2013-04-26T12:18:48.799Z" Version="2.0">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">sp</saml: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="#95cc3943-67dd-43ef-809b-2ccd8bd3e4e9">
<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 xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"
PrefixList="ds saml samlp"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>2HkVe/KnVzcMgneRUItjq2V/FEA=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
NjCxy8R3NjkN8B932FJolGTqtYTBBTLboHUo7ZqEXxICUW/ZhOV2Pwe+c4R0/TrPqBPVZBItlXyv
at3edIMrr7RlEFGy3rt7pPVRXUcmF6jtDZajCpwwaEKKD--REMOVED SOME CODE------------
egb8dua65WhY1KkugNPG4FWTVhtzul/CBo9a8vN/ZuXRbZQ6sUWbq1BFgC6Zmw8kr1aUNBwqRi7r
ZNPXcGVhXuFQTTV4Kuc1eiI1lgANKLTrkCBRSw==
</ds:SignatureValue>
</ds:Signature>
</samlp:AuthnRequest>
// END
I am not able to get the keyInfo and x509data and certificate values that i was able to get using the java keytool.
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>hZB2kOYypWs33Bs2BTaKZOKGig0CAwEAATANBgkqhkiG9w0BAQUFAAOB
gQB3Cfe0iTfrXY9E22TFy5b87kwpDKjLopNLtX3kqSUlfjnbN5tYN4zr91H5dZUkuFF83z7ztzKi
zkcxiMgVVQkU2X1bn5SdErvmS7aEcG8+5TdlO5bf+8as04u5qug+oQun5s1t9mSvaF7Ol5CX/gkp
EUTjXx28kldbY7ETgDUrSw==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
Also tell me is my Authn Request complete .
Also is the Authn request same for both the Artifact and POST(Assertion) saml message
PLS HELP !!!
How are you constructing your org.opensaml.xml.security.credential.Credential object ?
You can only load a private-key from PKCS8 file. You still need the public-key to fully construct the Credential object. If your public-key is stored in DER encoded bytes you can use the following code to create the Credential and use that to sign the request
/**
* Load privateKeyDerBytes from PKCS8 file and publicKeyDerBytes from .cer, .crt, .der files
*/
private static Credential getCredential(byte[] privateKeyDerBytes , byte[] publicKeyDerBytes) throws IOException
{
PrivateKey privateKey = PKCS8Key.parse(new DerValue( privateKeyDerBytes ));
PublicKey publicKey = X509Key.parse(new DerValue(publicKeyDerBytes));
BasicCredential basicCredential = new BasicCredential();
basicCredential.setUsageType(UsageType.SIGNING);
basicCredential.setPrivateKey(privateKey);
basicCredential.setPublicKey(publicKey);
return basicCredential;
}
public static void signAssertion(Assertion assertion , byte[] privateKeyDerBytes , byte[] publicKeyDerBytes) throws IOException, SecurityException
{
// get Credential
Credential credential = getCredential(privateKeyDerBytes, publicKeyDerBytes);
// create Signature
Signature signature = (Signature) Configuration.getBuilderFactory().getBuilder(
Signature.DEFAULT_ELEMENT_NAME).buildObject(
Signature.DEFAULT_ELEMENT_NAME);
signature.setSigningCredential(credential);
signature
.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature
.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
signature.setKeyInfo(getKeyInfo(credential));
assertion.setSignature(signature);
}
public static KeyInfo getKeyInfo(Credential credential)
throws SecurityException {
SecurityConfiguration secConfiguration = Configuration
.getGlobalSecurityConfiguration();
NamedKeyInfoGeneratorManager namedKeyInfoGeneratorManager = secConfiguration
.getKeyInfoGeneratorManager();
KeyInfoGeneratorManager keyInfoGeneratorManager = namedKeyInfoGeneratorManager
.getDefaultManager();
KeyInfoGeneratorFactory factory = keyInfoGeneratorManager
.getFactory(credential);
KeyInfoGenerator generator = factory.newInstance();
return generator.generate(credential);
}
You can use this to output the keyinfo
X509KeyInfoGeneratorFactory fact = new X509KeyInfoGeneratorFactory();
fact.setEmitEntityCertificate(true);
signature.setKeyInfo(fact.newInstance().generate(cred));