Reputation: 21
I have deployed and run spring SAML sample successfully. From SAML Response (IdP -> SP) shown below, can it be identified whether:
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" Destination="https://MY_SP/spring-security-saml2-sample/saml/SSO" ID="_22bf0c00-9cfa-5dbb-7af7-d34eec7d9b6f" InResponseTo="we3977191e5g4try1b3g52j4f84e43f" IssueInstant="2016-07-22T08:22:41.568Z" Version="2.0">
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://MY_ADFS_SERVER/adfs/services/trust</Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<EncryptedAssertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</e:EncryptionMethod>
<KeyInfo>
<ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=apollo, OU=R&D, O=RM5 Software Oy, L=Helsinki, S=Uusimaa, C=FI</ds:X509IssuerName>
<ds:X509SerialNumber>2343092425</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</KeyInfo>
<e:CipherData>
<e:CipherValue>Mpz3raT40LBmwUfzz+a52+ryijTMqVqtnk8T2YOJ27Xs/dS
jMZHShDfMGsD1wwXb2a2jGjpjCLgLWsZ1t8LWgxevSbmTZuGGSfAMhfdOwmJMijRYdKrHdiyn+syFUof
0MDMykI135ulCL9MGWVUvR1pNz+W+tZzQKcQ+is6USH4OGnUKiMSaow== </e:CipherValue>
</e:CipherData>
</e:EncryptedKey>
</KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>iefcMnnYFLtb
EObkQpItoZk4tRuMDX9dqt1DucK91ZZRigHeQ2DuUYe2FZpGtQ2vFVtS2ycXSnVR2V4wx4Vd2VeR/G3I
GHkqQ9GtOxv8RvkRtEbJTptmjoMT1t7ZNE4tn+hDmzMMK7Xy9f+xkk/z5IHvNKlscnsG/wXoRuMykKnJ
tODd0ILiVF/ygQqY477lxVFDlaa4HH/rcx+DZOcDFiFjiuLj41dF1rdG90XCmWvr2BfUTzYl3SHakoyK
AmmgesyCJQcHN54ckFiO/wvLttw09wdvC4sg92xlhhfGtQqMuvfT7YESOvHnC1FOEsf4CjoMaByZjwN2
QBRHPRJTBPjwmfVgTk+g==</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</EncryptedAssertion>
</samlp:Response>
From debug log of my SP server, right after the above SAML response is parsed, below is seen. This makes me confused whether the message and/or assertion has not been signed.
- Evaluating security policy of type 'org.opensaml.ws.security.provider.BasicSecurityPolicy' for decoded message
- Evaluating simple signature rule of type: org.opensaml.saml2.binding.security.SAML2HTTPPostSimpleSignRule
- HTTP request was not signed via simple signature mechanism, skipping
- SAML protocol message was not signed, skipping XML signature processing
- Successfully decoded message.
Upvotes: 2
Views: 11794
Reputation: 3110
Partial answer only. Source code diving. Inspired guessing.
I just googled around for the messages and tried to find the implementation. The original SVN server (I think svn.shibboleth.net) seems to have disappeared. There are just a few mirrors. But all the SVN commit comments seem to have been destroyed in the migration. At least in the mirrors that I found.
I ended up cloning this git repo: https://github.com/alexo/SAML-2.0/tree/master/java-opensaml2-main
You had 5 messages. I have numbered them M1 through M5.
Your log messages seem to be from these files:
// M1: Evaluating security policy of type
// 'org.opensaml.ws.security.provider.BasicSecurityPolicy'
// for decoded message
$ ag "Evaluating security policy of type"
java-openws/src/main/java/org/opensaml/ws/message/decoder/BaseMessageDecoder.java
82: log.debug("Evaluating security policy of type '{}' for decoded message", policy.getClass()
// M2: Evaluating simple signature rule of type:
// org.opensaml.saml2.binding.security.SAML2HTTPPostSimpleSignRule
$ ag "Evaluating simple signature rule of type:"
java-opensaml2/src/main/java/org/opensaml/common/binding/security/BaseSAMLSimpleSignatureSecurityPolicyRule.java
63: log.debug("Evaluating simple signature rule of type: {}", getClass().getName());
// M3: HTTP request was not signed via simple signature mechanism, skipping
$ ag "HTTP request was not signed via simple signature mechanism, skipping"
java-opensaml2/src/main/java/org/opensaml/common/binding/security/BaseSAMLSimpleSignatureSecurityPolicyRule.java
86: log.debug("HTTP request was not signed via simple signature mechanism, skipping");
// M4: SAML protocol message was not signed, skipping XML signature processing
$ ag "SAML protocol message was not signed, skipping XML signature processing"
java-opensaml2/src/main/java/org/opensaml/common/binding/security/SAMLProtocolMessageXMLSignatureSecurityPolicyRule.java
99: log.info("SAML protocol message was not signed, skipping XML signature processing");
// M5: Successfully decoded message.
$ ag "Successfully decoded message"
java-openws/src/main/java/org/opensaml/ws/message/decoder/BaseMessageDecoder.java
94: log.debug("Successfully decoded message.");
Details for individual log messages below.
Implementation seems to be this.
java-opensaml2/src/main/java/org/opensaml/common/binding/security/BaseSAMLSimpleSignatureSecurityPolicyRule.java
public void evaluate(MessageContext messageContext) throws SecurityPolicyException {
...
byte[] signature = getSignature(request);
if (signature == null || signature.length == 0) {
log.debug("HTTP request was not signed via simple signature mechanism, skipping");
return;
}
...
Implementation of getSignature(request) is in same file:
/**
* Extract the signature value from the request, in the form suitable for input into
* {@link SignatureTrustEngine#validate(byte[], byte[], String, CriteriaSet, Credential)}.
*
* Defaults to the Base64-decoded value of the HTTP request parameter named <code>Signature</code>.
*
* @param request the HTTP servlet request
* @return the signature value
* @throws SecurityPolicyException thrown if there is an error during request processing
*/
protected byte[] getSignature(HttpServletRequest request) throws SecurityPolicyException {
String signature = request.getParameter("Signature");
if (DatatypeHelper.isEmpty(signature)) {
return null;
}
return Base64.decode(signature);
}
So when you use the SAML protocol binding HTTP-Redirect
, which works via HTTP GET, then you will have a &Signature=...
as part of the URL. This gets checked here. It it's present. (Not sure where you would enforce that you NEED to have this present.)
And I GUESS it might also mean that when using HTTP POST it would look for a form field called Signature
in the body. Not sure.
Implementation seems to be this.
SAML-2.0/java-opensaml2-main/java-opensaml2/src/main/java/org/opensaml/common/binding/security/SAMLProtocolMessageXMLSignatureSecurityPolicyRule.java
public void evaluate(MessageContext messageContext) throws SecurityPolicyException {
if (!(messageContext instanceof SAMLMessageContext)) {
log.debug("Invalid message context type, this policy rule only supports SAMLMessageContext");
return;
}
SAMLMessageContext samlMsgCtx = (SAMLMessageContext) messageContext;
SAMLObject samlMsg = samlMsgCtx.getInboundSAMLMessage();
if (!(samlMsg instanceof SignableSAMLObject)) {
log.debug("Extracted SAML message was not a SignableSAMLObject, can not process signature");
return;
}
SignableSAMLObject signableObject = (SignableSAMLObject) samlMsg;
if (!signableObject.isSigned()) {
log.info("SAML protocol message was not signed, skipping XML signature processing");
return;
}
Signature signature = signableObject.getSignature();
performPreValidation(signature);
doEvaluate(signature, signableObject, samlMsgCtx);
}
SAML-2.0/java-opensaml2-main/java-xmltooling/src/main/java/org/opensaml/xml/signature/AbstractSignableXMLObject.java
public boolean isSigned() {
Element domElement = getDOM();
if (domElement == null) {
return false;
}
NodeList children = domElement.getChildNodes();
Element childElement;
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i).getNodeType() != Node.ELEMENT_NODE) {
continue;
}
childElement = (Element) children.item(i);
if (childElement.getNamespaceURI().equals(XMLConstants.XMLSIG_NS)
&& childElement.getLocalName().equals(Signature.DEFAULT_ELEMENT_LOCAL_NAME)) {
return true;
}
}
return false;
}
It just looks for any element in the xmldsig namespace. Anywhere in the whole XML document.
SAML-2.0/java-opensaml2-main/java-xmltooling/src/main/java/org/opensaml/xml/util/XMLConstants.java
public static final String XMLSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
SAML-2.0/java-opensaml2-main/java-xmltooling/src/main/java/org/opensaml/xml/signature/Signature.java
public static final String DEFAULT_ELEMENT_LOCAL_NAME = "Signature";
Your example XML file does not have any <Signature>
elements. That's why you get this message.
But I'm not sure if they are maybe inside the ENCRYPTED PORTION of the XML element.
Not sure how the processing flow works either. Maybe there is a decrypt step first and THEN it checks for <Signature>
elements? Don't know.
Upvotes: 0
Reputation: 4015
Response
is NOT signed.EncryptedAssertion
)Try setting WantAssertionsSigned="true"
in your SP metadata, exchange with IdP and check whether you receive signed SAML Response or not.
Reference: http://docs.spring.io/spring-security-saml/docs/current/reference/html/configuration-metadata.html
Upvotes: 0