/** * @param SAMLToken - SAML Assertion XML * @param contextAttributeName - SAML Attribute name containing Context data * @param verfiySignature * @return a base64 encoded string containing the context * @throws SAMLValidationException - if validation fails */ public static List<AttributeStatement> validate(byte[] SAMLToken, SAMLConfiguration samlConfig) throws SAMLValidationException { if (logger.isDebugEnabled()) { logger.debug("validate(byte[], SAMLConfiguration) - start"); // $NON-NLS-1$ } Decrypter samlDecrypter = samlConfig.getSamlDecrypter(); SignatureTrustEngine sigTrustEngine = samlConfig.getTrustEngine(); String myURI = samlConfig.getMyURI(); MessageReplayRule replayRule = samlConfig.getReplayRule(); BasicParserPool ppMgr = new BasicParserPool(); ppMgr.setNamespaceAware(true); VerifySignatureType verfiySignature = samlConfig.getVerifySignature(); List<AttributeStatement> attrStatements = null; if (SAMLToken != null) { try { InputStream in = new ByteArrayInputStream(SAMLToken); Document SAMLDoc; try { SAMLDoc = ppMgr.parse(in); } catch (XMLParserException e) { logger.error( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException("Error parsing SAML XML", true, e); } Element responseElement = SAMLDoc.getDocumentElement(); SAMLType samlType = SAMLType.Response; if (responseElement == null) { throw createSAMLValidationException( "Missing SAML Encrypted Assertion or Assertion or Assertion Response", true); } if (!"Response".equals(responseElement.getLocalName()) || !SAMLConstants.SAML20P_NS.equals(responseElement.getNamespaceURI())) { if (!"Assertion".equals(responseElement.getLocalName()) || !SAMLConstants.SAML20_NS.equals(responseElement.getNamespaceURI())) { if (!"EncryptedAssertion".equals(responseElement.getLocalName()) || !SAMLConstants.SAML20_NS.equals(responseElement.getNamespaceURI())) { throw createSAMLValidationException( "Missing or invalid SAML Encrypted Assertion or Assertion or Assertion Response", true); } else { samlType = SAMLType.EncryptedAssertion; } } else { samlType = SAMLType.Assertion; } } else { samlType = SAMLType.Response; } if (samlType == SAMLType.Response) { // Unmarshall SAML Assertion Response into an OpenSAML Java object. UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseElement); Response samlResponse; try { samlResponse = (Response) unmarshaller.unmarshall(responseElement); } catch (UnmarshallingException e) { logger.error( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException( "Error in unmarshalling SAML XML Document", true, e); } // Check the replay attack for Response if (replayRule != null) { BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); // messageContext.setInboundMessage(samlResponse); if (samlResponse.getIssuer() != null) messageContext.setInboundMessageIssuer(samlResponse.getIssuer().getValue()); messageContext.setInboundSAMLMessageId(samlResponse.getID()); try { replayRule.evaluate(messageContext); } catch (SecurityPolicyException e) { logger.error( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException("Possible Replay Attack for Response", false, e); } } // Validate the status code if (!StatusCode.SUCCESS_URI.equals(samlResponse.getStatus().getStatusCode().getValue())) { throw createSAMLValidationException("Invalid Status Code.", true); } boolean responseSignatureVerified = validateResponseSignature(samlResponse, sigTrustEngine, verfiySignature); // Get first encrypted Assertion, if not present get first unencrypted assertion int assertCount = samlResponse.getEncryptedAssertions().size(); if (assertCount == 0) { assertCount = samlResponse.getAssertions().size(); if (assertCount == 0) { throw createSAMLValidationException( "No Assertion or EncryptedAssertion found in received response", true); } else { for (Assertion samlAssertion : samlResponse.getAssertions()) { attrStatements = validateAssertion( samlAssertion, sigTrustEngine, myURI, replayRule, verfiySignature, responseSignatureVerified); break; // Use the first only } } } else { for (EncryptedAssertion samlEncryptedAssertion : samlResponse.getEncryptedAssertions()) { // Decryption Assertion samlAssertion = null; try { samlAssertion = samlDecrypter.decrypt(samlEncryptedAssertion); } catch (DecryptionException e) { logger.error( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException( "Error Decrypting Received Encrypted Assertion", true, e); } attrStatements = validateAssertion( samlAssertion, sigTrustEngine, myURI, replayRule, verfiySignature, responseSignatureVerified); break; // Use the first only } } } else if (samlType == SAMLType.EncryptedAssertion) { // Unmarshall SAML Encrypted Assertion into an OpenSAML Java object. UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseElement); EncryptedAssertion encryptedAssertion = null; try { encryptedAssertion = (EncryptedAssertion) unmarshaller.unmarshall(responseElement); } catch (UnmarshallingException e) { logger.error( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException( "Error in unmarshalling SAML XML Document", true, e); } boolean responseSignatureVerified = false; // Decryption Assertion samlAssertion = null; try { samlAssertion = samlDecrypter.decrypt(encryptedAssertion); } catch (DecryptionException e) { logger.error( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException( "Error Decrypting Received Encrypted Assertion", true, e); } attrStatements = validateAssertion( samlAssertion, sigTrustEngine, myURI, replayRule, verfiySignature, responseSignatureVerified); } else if (samlType == SAMLType.Assertion) { // Unmarshall SAML Assertion into an OpenSAML Java object. UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(responseElement); Assertion samlAssertion = null; try { samlAssertion = (Assertion) unmarshaller.unmarshall(responseElement); } catch (UnmarshallingException e) { logger.error( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException( "Error in unmarshalling SAML XML Document", true, e); } boolean responseSignatureVerified = false; attrStatements = validateAssertion( samlAssertion, sigTrustEngine, myURI, replayRule, verfiySignature, responseSignatureVerified); } } catch (SAMLValidationException e) { throw e; } } if (logger.isDebugEnabled()) { logger.debug( "validate(byte[], String, Decrypter, SignatureTrustEngine, String, MessageReplayRule, ParserPool, VerifySignatureType) - end"); //$NON-NLS-1$ } return attrStatements; }
private static List<AttributeStatement> validateAssertion( Assertion samlAssertion, SignatureTrustEngine sigTrustEngine, String myURI, MessageReplayRule replayRule, VerifySignatureType verifySignature, boolean responseSignatureVerified) throws SAMLValidationException { if (logger.isDebugEnabled()) { logger.debug( "validateAndExtractContext(Assertion, String, SignatureTrustEngine, String, MessageReplayRule, VerifySignatureType) - start"); //$NON-NLS-1$ } // Check the replay attack if (replayRule != null) { BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); // messageContext.setInboundMessage(samlResponse); if (samlAssertion.getIssuer() != null) messageContext.setInboundMessageIssuer(samlAssertion.getIssuer().getValue()); messageContext.setInboundSAMLMessageId(samlAssertion.getID()); try { replayRule.evaluate(messageContext); } catch (SecurityPolicyException e) { logger.error( "validateAndExtractContext(Assertion, String, SignatureTrustEngine, String, MessageReplayRule, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException("Possible Replay Attack for Assertion", false, e); } } if (verifySignature != VerifySignatureType.never) { Signature signature = samlAssertion.getSignature(); if (signature == null) { if (verifySignature == VerifySignatureType.force && !responseSignatureVerified) { throw createSAMLValidationException("Signature does exist in Assertion", true); } } else { verifySignature(signature, samlAssertion.getIssuer().getValue(), sigTrustEngine); } } DateTime dt = new DateTime(); // get subject (code below only processes first Subject confirmation) Subject subject = samlAssertion.getSubject(); SubjectSchemaValidator subjectSchemaValidator = new SubjectSchemaValidator(); try { subjectSchemaValidator.validate(subject); } catch (ValidationException e) { logger.error( "validateAndExtractContext(Assertion, String, SignatureTrustEngine, String, MessageReplayRule, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException("Subject validation failed: " + e.getMessage(), true, e); } List<SubjectConfirmation> subjectConfirmations = subject.getSubjectConfirmations(); for (SubjectConfirmation subjectConfirmation : subjectConfirmations) { SubjectConfirmationSchemaValidator subjectConfirmationSchemaValidator = new SubjectConfirmationSchemaValidator(); try { subjectConfirmationSchemaValidator.validate(subjectConfirmation); } catch (ValidationException e) { logger.error( "validateAndExtractContext(Assertion, String, SignatureTrustEngine, String, MessageReplayRule, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException( "Subject Confirmation validation failed: " + e.getMessage(), true, e); } SubjectConfirmationData subjectConfirmationData = subjectConfirmation.getSubjectConfirmationData(); try { subjectConfirmationSchemaValidator.validate(subjectConfirmation); } catch (ValidationException e) { logger.error( "validateAndExtractContext(Assertion, String, SignatureTrustEngine, String, MessageReplayRule, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException( "Subject Confirmation validation failed: " + e.getMessage(), true, e); } // verify the validity of time using clock skew, subjectConfirmationData.getNotBefore() and // subjectConfirmationData.getNotOnOrAfter()@ DateTime notBefore = subjectConfirmationData.getNotBefore(); DateTime notAfter = subjectConfirmationData.getNotOnOrAfter(); if (notBefore != null && dt.isBefore(notBefore)) { throw createSAMLValidationException("Subject confirmation expired.", true); } if (notAfter != null && (dt.equals(notAfter) || dt.isAfter(notAfter))) { throw createSAMLValidationException("Subject confirmation expired.", true); } } // validate conditions Conditions conditions = samlAssertion.getConditions(); // Validate the spec ConditionsSpecValidator conditionValidator = new ConditionsSpecValidator(); try { conditionValidator.validate(conditions); } catch (ValidationException e) { logger.error( "validateAndExtractContext(Assertion, String, SignatureTrustEngine, String, MessageReplayRule, VerifySignatureType)", e); //$NON-NLS-1$ throw createSAMLValidationException("Condition Validity Failed.", true, e); } // verify the validity of time using clock skew, conditions.getNotBefore() and // conditions.getNotOnOrAfter()@ DateTime notBefore = conditions.getNotBefore(); DateTime notAfter = conditions.getNotOnOrAfter(); if (notBefore != null && dt.isBefore(notBefore)) { throw createSAMLValidationException("Assertion expired.", true); } if (notAfter != null && (dt.equals(notAfter) || dt.isAfter(notAfter))) { throw createSAMLValidationException("Assertion expired.", true); } for (Condition condition : conditions.getConditions()) { if (condition instanceof AudienceRestriction) { if (myURI != null && myURI.length() > 0) { boolean audiencePresent = false; boolean iAmOneOfTheAudience = false; AudienceRestriction audienceRestriction = (AudienceRestriction) condition; for (Audience audience : audienceRestriction.getAudiences()) { audiencePresent = true; String audienceURI = audience.getAudienceURI(); if (myURI.equals(audienceURI)) { iAmOneOfTheAudience = true; break; } } if (!(audiencePresent && iAmOneOfTheAudience)) { throw createSAMLValidationException( "None of the audience is intended for me: " + myURI, false); } } } } List<AttributeStatement> asList = samlAssertion.getAttributeStatements(); if (logger.isDebugEnabled()) { logger.debug( "validateAndExtractContext(Assertion, String, SignatureTrustEngine, String, MessageReplayRule, VerifySignatureType) - end"); //$NON-NLS-1$ } return asList; }