WebSSOProfileConsumerImpl extends AbstractProfileBase implements WebSSOProfileConsumer { public SAMLCredential processAuthenticationResponse(SAMLMessageContext context) throws SAMLException, org.opensaml.xml.security.SecurityException, ValidationException, DecryptionException { AuthnRequest request = null; SAMLObject message = context.getInboundSAMLMessage(); if (!(message instanceof Response)) { throw new SAMLException("Message is not of a Response object type"); } Response response = (Response) message; StatusCode statusCode = response.getStatus().getStatusCode(); if (!StatusCode.SUCCESS_URI.equals(statusCode.getValue())) { StatusMessage statusMessage = response.getStatus().getStatusMessage(); String statusMessageText = null; if (statusMessage != null) { statusMessageText = statusMessage.getMessage(); } String finalStatusCode = statusCode.getValue(); while (statusCode.getStatusCode() != null){ finalStatusCode = statusCode.getStatusCode().getValue(); statusCode = statusCode.getStatusCode(); } throw new SAMLStatusException( finalStatusCode, "Response has invalid status code " + finalStatusCode + ", status message is " + statusMessageText ); } if (response.getSignature() != null && !context.isInboundSAMLMessageAuthenticated()) { log.debug("Verifying Response signature"); verifySignature(response.getSignature(), context.getPeerEntityId(), context.getLocalTrustEngine()); context.setInboundSAMLMessageAuthenticated(true); } DateTime time = response.getIssueInstant(); if (!isDateTimeSkewValid(getResponseSkew(), time)) { throw new SAMLException("Response issue time is either too old or with date in the future, skew " + getResponseSkew() + ", time " + time); } if (!context.getPeerExtendedMetadata().isSupportUnsolicitedResponse() && response.getInResponseTo() == null) { throw new SAMLException("Reception of Unsolicited Response messages (without InResponseToField) is disabled"); } SAMLMessageStorage messageStorage = context.getMessageStorage(); if (messageStorage != null && response.getInResponseTo() != null) { XMLObject xmlObject = messageStorage.retrieveMessage(response.getInResponseTo()); if (xmlObject == null) { throw new SAMLException("InResponseToField of the Response doesn't correspond to sent message " + response.getInResponseTo()); } else if (xmlObject instanceof AuthnRequest) { request = (AuthnRequest) xmlObject; } else { throw new SAMLException("Sent request was of different type than the expected AuthnRequest " + response.getInResponseTo()); } } verifyEndpoint(context.getLocalEntityEndpoint(), response.getDestination()); if (request != null) { AssertionConsumerService assertionConsumerService = (AssertionConsumerService) context.getLocalEntityEndpoint(); if (request.getAssertionConsumerServiceIndex() != null) { if (!request.getAssertionConsumerServiceIndex().equals(assertionConsumerService.getIndex())) { log.info("Response was received at a different endpoint index than was requested"); } } else { String requestedResponseURL = request.getAssertionConsumerServiceURL(); String requestedBinding = request.getProtocolBinding(); if (requestedResponseURL != null) { String responseLocation; if (assertionConsumerService.getResponseLocation() != null) { responseLocation = assertionConsumerService.getResponseLocation(); } else { responseLocation = assertionConsumerService.getLocation(); } if (!requestedResponseURL.equals(responseLocation)) { log.info("Response was received at a different endpoint URL {} than was requested {}", responseLocation, requestedResponseURL); } } if (requestedBinding != null) { if (!requestedBinding.equals(context.getInboundSAMLBinding())) { log.info("Response was received using a different binding {} than was requested {}", context.getInboundSAMLBinding(), requestedBinding); } } } } if (response.getIssuer() != null) { log.debug("Verifying issuer of the Response"); Issuer issuer = response.getIssuer(); verifyIssuer(issuer, context); } Assertion subjectAssertion = null; List<Attribute> attributes = new ArrayList<Attribute>(); List<Assertion> assertionList = response.getAssertions(); if (response.getEncryptedAssertions().size() > 0) { assertionList = new ArrayList<Assertion>(response.getAssertions().size() + response.getEncryptedAssertions().size()); assertionList.addAll(response.getAssertions()); List<EncryptedAssertion> encryptedAssertionList = response.getEncryptedAssertions(); for (EncryptedAssertion ea : encryptedAssertionList) { try { Assert.notNull(context.getLocalDecrypter(), "Can't decrypt Assertion, no decrypter is set in the context"); log.debug("Decrypting assertion"); Assertion decryptedAssertion = context.getLocalDecrypter().decrypt(ea); assertionList.add(decryptedAssertion); } catch (DecryptionException e) { log.debug("Decryption of received assertion failed, assertion will be skipped", e); } } } Exception lastError = null; for (Assertion assertion : assertionList) { if (assertion.getAuthnStatements().size() > 0) { try { verifyAssertion(assertion, request, context); subjectAssertion = assertion; log.debug("Validation of authentication statement in assertion {} was successful", assertion.getID()); break; } catch (Exception e) { log.debug("Validation of authentication statement in assertion failed, skipping", e); lastError = e; } } else { log.debug("Assertion {} did not contain any authentication statements, skipping", assertion.getID()); } } if (subjectAssertion == null) { throw new SAMLException("Response doesn't have any valid assertion which would pass subject validation", lastError); } for (Assertion assertion : assertionList) { if (assertion == subjectAssertion || isIncludeAllAttributes()) { for (AttributeStatement attStatement : assertion.getAttributeStatements()) { for (Attribute att : attStatement.getAttributes()) { log.debug("Including attribute {} from assertion {}", att.getName(), assertion.getID()); attributes.add(att); } for (EncryptedAttribute att : attStatement.getEncryptedAttributes()) { Assert.notNull(context.getLocalDecrypter(), "Can't decrypt Attribute, no decrypter is set in the context"); Attribute decryptedAttribute = context.getLocalDecrypter().decrypt(att); log.debug("Including decrypted attribute {} from assertion {}", decryptedAttribute.getName(), assertion.getID()); attributes.add(decryptedAttribute); } } } } NameID nameId = (NameID) context.getSubjectNameIdentifier(); if (nameId == null) { throw new SAMLException("NameID element must be present as part of the Subject in the Response message, please enable it in the IDP configuration"); } Serializable additionalData = processAdditionalData(context); if (isReleaseDOM()) { subjectAssertion.releaseDOM(); subjectAssertion.releaseChildrenDOM(true); } return new SAMLCredential(nameId, subjectAssertion, context.getPeerEntityMetadata().getEntityID(), context.getRelayState(), attributes, context.getLocalEntityId(), additionalData); } WebSSOProfileConsumerImpl();  WebSSOProfileConsumerImpl(SAMLProcessor processor, MetadataManager manager); @Override String getProfileIdentifier(); SAMLCredential processAuthenticationResponse(SAMLMessageContext context); long getMaxAuthenticationAge(); void setMaxAuthenticationAge(long maxAuthenticationAge); boolean isIncludeAllAttributes(); void setIncludeAllAttributes(boolean includeAllAttributes); boolean isReleaseDOM(); void setReleaseDOM(boolean releaseDOM);  }
@Test public void testUnsuccessfulStatusResponse() throws Exception { Response noPassiveStatusResponse = helper.getNoPassiveStatusResponse(); messageContext.setInboundSAMLMessage(noPassiveStatusResponse); try { profile.processAuthenticationResponse(messageContext); fail("Expected a SAMLStatusException exception"); } catch (SAMLStatusException x) { assertEquals( "Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:NoPassive, status message is null", x.getMessage() ); } }
@Test public void testCircularStatusCode() throws Exception { Response noPassiveStatusResponse = helper.getNoPassiveStatusResponse(); messageContext.setInboundSAMLMessage(noPassiveStatusResponse); try { profile.processAuthenticationResponse(messageContext); fail("Expected a SAMLStatusException exception"); } catch (SAMLStatusException x) { } }
@Test public void testValidResponse() throws Exception { messageContext.setInboundSAMLMessageAuthenticated(true); profile.processAuthenticationResponse(messageContext); }
@Test public void testValidResponseWithAttributesIncludeAllDisabled() throws Exception { Response validResponse = helper.getValidResponse(); validResponse.getAssertions().iterator().next().getAttributeStatements().add(helper.getAttributeStatement("assertion1", "value1")); Assertion attributeAssertion = helper.getValidAssertion(); attributeAssertion.getAttributeStatements().add(helper.getAttributeStatement("assertion2", "value2")); validResponse.getAssertions().add(attributeAssertion); messageContext.setInboundSAMLMessage(validResponse); messageContext.setInboundSAMLMessageAuthenticated(true); SAMLCredential samlCredential = profile.processAuthenticationResponse(messageContext); assertTrue(samlCredential.getAttributes().size() == 1); }
@Test(expected = SAMLException.class) public void testMissingAuthnStatement() throws Exception { Response validResponse = helper.getValidResponse(); validResponse.getAssertions().clear(); Assertion validAssertion = helper.getValidAssertion(); validAssertion.getAttributeStatements().add(helper.getAttributeStatement("assertion1", "value1")); validResponse.getAssertions().add(validAssertion); messageContext.setInboundSAMLMessage(validResponse); messageContext.setInboundSAMLMessageAuthenticated(true); profile.processAuthenticationResponse(messageContext); }
@Test(expected = SAMLException.class) public void testMissingSignature() throws Exception { profile.processAuthenticationResponse(messageContext); }
@Test(expected = SAMLException.class) public void testMissingResponse() throws Exception { messageContext.setInboundSAMLMessage(null); profile.processAuthenticationResponse(messageContext); }
@Test(expected = SAMLException.class) public void testInvalidResponseObject() throws Exception { SAMLObjectBuilder<AuthnRequest> builder = (SAMLObjectBuilder<AuthnRequest>) builderFactory.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME); AuthnRequest authnRequest = builder.buildObject(); messageContext.setInboundSAMLMessage(authnRequest); profile.processAuthenticationResponse(messageContext); }