/* (non-Javadoc) * @see com.vmware.identity.samlservice.SamlValidator#validate(java.lang.Object) */ @Override public ValidationResult validate(AuthnRequestState t) { log.debug("Validating request {}", t); ValidationResult vr = null; try { Validate.notNull(t); HttpServletRequest httpRequest = t.getRequest(); Validate.notNull(httpRequest); AuthnRequest request = t.getAuthnRequest(); Validate.notNull(request); Validate.notNull(request.getIssuer()); IdmAccessor accessor = t.getIdmAccessor(); Validate.notNull(accessor); Validate.notNull(accessor.getTenant()); // Validate assertion consumer service first, if that is valid, we can send SAML replies try { boolean validateACSWithMetadata = !this.isRequestSigned(t); String acsUrl = accessor.getAcsForRelyingParty( request.getIssuer().getValue(), request.getAssertionConsumerServiceIndex(), request.getAssertionConsumerServiceURL(), request.getProtocolBinding(), validateACSWithMetadata); t.setAcsUrl(acsUrl); } catch (IllegalStateException e) { // set validation result to 400 log.debug("Caught illegal state exception while Validating {} returning 400", e.toString()); vr = new ValidationResult(HttpServletResponse.SC_BAD_REQUEST, e.getMessage(), null); } // Validate ID if (vr == null && request.getID() == null) { vr = new ValidationResult(OasisNames.REQUESTER); log.debug("Validation FAILED - Request ID is missing"); } // Validate version if (vr == null) { SAMLVersion version = request.getVersion(); if ((version.getMajorVersion() > Shared.REQUIRED_SAML_VERSION.getMajorVersion()) || version.getMajorVersion() == Shared.REQUIRED_SAML_VERSION.getMajorVersion() && version.getMinorVersion() > Shared.REQUIRED_SAML_VERSION.getMinorVersion()) { // version too high vr = new ValidationResult( OasisNames.VERSION_MISMATCH, OasisNames.REQUEST_VERSION_TOO_HIGH); log.debug("Validation FAILED - Version is too high"); } else if ((version.getMajorVersion() < Shared.REQUIRED_SAML_VERSION.getMajorVersion()) || version.getMajorVersion() == Shared.REQUIRED_SAML_VERSION.getMajorVersion() && version.getMinorVersion() < Shared.REQUIRED_SAML_VERSION.getMinorVersion()) { // version too low vr = new ValidationResult(OasisNames.VERSION_MISMATCH, OasisNames.REQUEST_VERSION_TOO_LOW); log.debug("Validation FAILED - Version is too low"); } } // Validate IssueInstant only if this is a new request (i.e. it had not pass been validated) if (vr == null && !t.isExistingRequest()) { DateTime dtPlus = request.getIssueInstant(); DateTime dtMinus = request.getIssueInstant(); DateTime instant = new DateTime(); long clockTolerance = accessor.getClockTolerance(); if (dtPlus == null) { vr = new ValidationResult(OasisNames.REQUESTER); log.debug("Validation FAILED - Issue Instant is missing"); } else { dtPlus = dtPlus.plus(clockTolerance); dtMinus = dtMinus.minus(clockTolerance); // dtPlus must be after now and dtMinus must be before now // in order to satisfy clock tolerance if (dtPlus.isBefore(instant) || dtMinus.isAfter(instant)) { vr = new ValidationResult(OasisNames.REQUESTER); log.debug("Validation FAILED - Issue Instant outside of clock tolerance"); log.debug("clockTolerance {}", clockTolerance); log.debug("now {}", instant); log.debug("dtPlus {}", dtPlus.toString()); log.debug("dtMinus {}", dtMinus.toString()); } } } // Destination URL skipped, this is already done by OpenSAML when parsing // validate scoping if presenet if (vr == null) { vr = validateScoping(t); } // signature must NOT be included if (vr == null) { if (request.getSignature() != null) { log.debug("Validation FAILED - Signature MUST NOT be present"); vr = new ValidationResult(OasisNames.REQUESTER, OasisNames.REQUEST_UNSUPPORTED); } } // ensure that we don't accept unsigned requests if configuration requires signing if (vr == null) { try { boolean mustBeSigned = accessor.getAuthnRequestsSignedForRelyingParty(request.getIssuer().getValue()); this.validateSigning(mustBeSigned, t); } catch (IllegalStateException e) { // set validation result to request denied log.error("Validation FAILED - unsigned request detected, signing required"); vr = new ValidationResult(OasisNames.RESPONDER, OasisNames.REQUEST_DENIED); } } // validate NameIDPolicy if present if (vr == null) { NameIDPolicy policy = request.getNameIDPolicy(); if (policy != null) { String format = policy.getFormat(); if (format != null && !format.equals(OasisNames.PERSISTENT) && !format.equals(OasisNames.EMAIL_ADDRESS) && !format.equals(SAMLNames.IDFORMAT_VAL_UPN.toString())) { log.error("Validation FAILED - unknown NameIDPolicy Format"); vr = new ValidationResult(OasisNames.REQUESTER, OasisNames.INVALID_NAMEID_POLICY); } } } // validate conditions if (vr == null) { Conditions conditions = request.getConditions(); if (conditions != null) { // notBefore processing DateTime notBefore = conditions.getNotBefore(); if (notBefore != null) { // no additional validation, we'll use whatever client wants t.setStartTime(notBefore.toDate()); } // delegable and renewable conditions for (Condition c : conditions.getConditions()) { if (c == null) { continue; } if (c instanceof RenewableType) { t.setRenewable(true); } if (c instanceof DelegableType) { t.setDelegable(true); } } } } if (vr == null) { computeSupportedAuthnTypes(t, request); } // validation done if (vr == null) { log.info("Authentication request validation succeeded"); vr = new ValidationResult(); // success // check if we need to convert a principal into emailAddress if (request.getNameIDPolicy() != null && request.getNameIDPolicy().getFormat() != null && request.getNameIDPolicy().getFormat().equals(OasisNames.EMAIL_ADDRESS)) { t.setIdentityFormat(OasisNames.IDENTITY_FORMAT_EMAIL_ADDRESS); } else { t.setIdentityFormat(OasisNames.IDENTITY_FORMAT_UPN); } } } catch (Exception e) { vr = new ValidationResult(HttpServletResponse.SC_BAD_REQUEST, "BadRequest", null); log.debug("Caught exception while Validating " + e.toString() + ", returning 400"); } return vr; }
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; }