Temporarily adding SSOValidatorResponse until we pick up CXF 3.1.13
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/c8748ba1 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/c8748ba1 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/c8748ba1 Branch: refs/heads/2_0_X Commit: c8748ba107bdda6ae4e8a3aec6dcf4cf9e25a3f6 Parents: fecfc6f Author: Colm O hEigeartaigh <cohei...@apache.org> Authored: Fri Aug 11 13:25:57 2017 +0100 Committer: Colm O hEigeartaigh <cohei...@apache.org> Committed: Fri Aug 11 13:35:24 2017 +0100 ---------------------------------------------------------------------- .../apache/syncope/core/logic/SAML2SPLogic.java | 3 +- .../core/logic/saml2/SAML2ReaderWriter.java | 1 - .../logic/saml2/SAMLSSOResponseValidator.java | 78 +++++++++--------- .../core/logic/saml2/SSOValidatorResponse.java | 84 ++++++++++++++++++++ 4 files changed, 125 insertions(+), 41 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java index 03576ab..0891f59 100644 --- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java +++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java @@ -19,6 +19,8 @@ package org.apache.syncope.core.logic; import org.apache.syncope.core.logic.saml2.SAML2UserManager; +import org.apache.syncope.core.logic.saml2.SSOValidatorResponse; + import com.fasterxml.uuid.Generators; import com.fasterxml.uuid.impl.RandomBasedGenerator; import java.io.OutputStream; @@ -37,7 +39,6 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer; import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier; -import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse; import org.apache.syncope.common.lib.AbstractBaseBean; import org.apache.syncope.common.lib.SyncopeClientException; import org.apache.syncope.common.lib.to.AttrTO; http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java index dba63cc..f530afb 100644 --- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java +++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java @@ -43,7 +43,6 @@ import javax.xml.transform.stream.StreamResult; import org.apache.commons.codec.binary.Base64; import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder; import org.apache.cxf.rs.security.saml.sso.SAMLProtocolResponseValidator; -import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse; import org.apache.cxf.staxutils.StaxUtils; import org.apache.syncope.common.lib.SSOConstants; import org.apache.syncope.common.lib.types.SAML2BindingType; http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java index a730140..a32ed09 100644 --- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java +++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java @@ -25,7 +25,6 @@ import java.util.logging.Logger; import org.w3c.dom.Element; import org.apache.cxf.common.logging.LogUtils; -import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse; import org.apache.cxf.rs.security.saml.sso.TokenReplayCache; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.common.saml.builder.SAML2Constants; @@ -39,9 +38,9 @@ import org.opensaml.saml.saml2.core.AuthnStatement; */ //CHECKSTYLE:OFF public class SAMLSSOResponseValidator { - + private static final Logger LOG = LogUtils.getL7dLogger(SAMLSSOResponseValidator.class); - + private String issuerIDP; private String assertionConsumerURL; private String clientAddress; @@ -51,7 +50,7 @@ public class SAMLSSOResponseValidator { private boolean enforceAssertionsSigned = true; private boolean enforceKnownIssuer = true; private TokenReplayCache<String> replayCache; - + /** * Enforce that Assertions contained in the Response must be signed (if the Response itself is not * signed). The default is true. @@ -59,14 +58,14 @@ public class SAMLSSOResponseValidator { public void setEnforceAssertionsSigned(boolean enforceAssertionsSigned) { this.enforceAssertionsSigned = enforceAssertionsSigned; } - + /** * Enforce that the Issuer of the received Response/Assertion is known. The default is true. */ public void setEnforceKnownIssuer(boolean enforceKnownIssuer) { this.enforceKnownIssuer = enforceKnownIssuer; } - + /** * Validate a SAML 2 Protocol Response * @param samlResponse @@ -86,7 +85,7 @@ public class SAMLSSOResponseValidator { LOG.fine("The Response must contain at least one Assertion"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // The Response must contain a Destination that matches the assertionConsumerURL if it is // signed String destination = samlResponse.getDestination(); @@ -95,12 +94,12 @@ public class SAMLSSOResponseValidator { LOG.fine("The Response must contain a destination that matches the assertion consumer URL"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + if (enforceResponseSigned && !samlResponse.isSigned()) { LOG.fine("The Response must be signed!"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // Validate Assertions org.opensaml.saml.saml2.core.Assertion validAssertion = null; Date sessionNotOnOrAfter = null; @@ -111,17 +110,17 @@ public class SAMLSSOResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } validateIssuer(assertion.getIssuer()); - + if (!samlResponse.isSigned() && enforceAssertionsSigned && assertion.getSignature() == null) { LOG.fine("The enclosed assertions in the SAML Response must be signed"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // Check for AuthnStatements and validate the Subject accordingly if (assertion.getAuthnStatements() != null && !assertion.getAuthnStatements().isEmpty()) { org.opensaml.saml.saml2.core.Subject subject = assertion.getSubject(); - org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf = + org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf = validateAuthenticationSubject(subject, assertion.getID(), postBinding); if (subjectConf != null) { validateAudienceRestrictionCondition(assertion.getConditions()); @@ -139,28 +138,29 @@ public class SAMLSSOResponseValidator { } } } - + if (validAssertion == null) { LOG.fine("The Response did not contain any Authentication Statement that matched " + "the Subject Confirmation criteria"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + SSOValidatorResponse validatorResponse = new SSOValidatorResponse(); validatorResponse.setResponseId(samlResponse.getID()); validatorResponse.setSessionNotOnOrAfter(sessionNotOnOrAfter); + validatorResponse.setOpensamlAssertion(validAssertion); if (samlResponse.getIssueInstant() != null) { validatorResponse.setCreated(samlResponse.getIssueInstant().toDate()); } - + Element assertionElement = validAssertion.getDOM(); Element clonedAssertionElement = (Element)assertionElement.cloneNode(true); validatorResponse.setAssertionElement(clonedAssertionElement); validatorResponse.setAssertion(DOM2Writer.nodeToString(clonedAssertionElement)); - + return validatorResponse; } - + /** * Validate the Issuer (if it exists) */ @@ -168,23 +168,23 @@ public class SAMLSSOResponseValidator { if (issuer == null) { return; } - + // Issuer value must match (be contained in) Issuer IDP if (enforceKnownIssuer && !issuerIDP.startsWith(issuer.getValue())) { - LOG.fine("Issuer value: " + issuer.getValue() + " does not match issuer IDP: " + LOG.fine("Issuer value: " + issuer.getValue() + " does not match issuer IDP: " + issuerIDP); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // Format must be nameid-format-entity if (issuer.getFormat() != null && !SAML2Constants.NAMEID_FORMAT_ENTITY.equals(issuer.getFormat())) { - LOG.fine("Issuer format is not null and does not equal: " + LOG.fine("Issuer format is not null and does not equal: " + SAML2Constants.NAMEID_FORMAT_ENTITY); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + /** * Validate the Subject (of an Authentication Statement). */ @@ -194,20 +194,20 @@ public class SAMLSSOResponseValidator { if (subject.getSubjectConfirmations() == null) { return null; } - + org.opensaml.saml.saml2.core.SubjectConfirmation validSubjectConf = null; // We need to find a Bearer Subject Confirmation method - for (org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf + for (org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf : subject.getSubjectConfirmations()) { if (SAML2Constants.CONF_BEARER.equals(subjectConf.getMethod())) { validateSubjectConfirmation(subjectConf.getSubjectConfirmationData(), id, postBinding); validSubjectConf = subjectConf; } } - + return validSubjectConf; } - + /** * Validate a (Bearer) Subject Confirmation */ @@ -218,7 +218,7 @@ public class SAMLSSOResponseValidator { LOG.fine("Subject Confirmation Data of a Bearer Subject Confirmation is null"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // Recipient must match assertion consumer URL String recipient = subjectConfData.getRecipient(); if (recipient == null || !recipient.equals(assertionConsumerURL)) { @@ -226,14 +226,14 @@ public class SAMLSSOResponseValidator { + assertionConsumerURL); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // We must have a NotOnOrAfter timestamp if (subjectConfData.getNotOnOrAfter() == null || subjectConfData.getNotOnOrAfter().isBeforeNow()) { LOG.fine("Subject Conf Data does not contain NotOnOrAfter or it has expired"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // Need to keep bearer assertion IDs based on NotOnOrAfter to detect replay attacks if (postBinding && replayCache != null) { if (replayCache.getId(id) == null) { @@ -246,7 +246,7 @@ public class SAMLSSOResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + // Check address if (subjectConfData.getAddress() != null && clientAddress != null && !subjectConfData.getAddress().equals(clientAddress)) { @@ -254,13 +254,13 @@ public class SAMLSSOResponseValidator { + " client address " + clientAddress); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // It must not contain a NotBefore timestamp if (subjectConfData.getNotBefore() != null) { LOG.fine("The Subject Conf Data must not contain a NotBefore timestamp"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // InResponseTo must match the AuthnRequest request Id if (requestId != null && !requestId.equals(subjectConfData.getInResponseTo())) { LOG.fine("The InResponseTo String does match the original request id " + requestId); @@ -269,9 +269,9 @@ public class SAMLSSOResponseValidator { LOG.fine("No InResponseTo String is allowed for the unsolicted case"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + } - + private void validateAudienceRestrictionCondition( org.opensaml.saml.saml2.core.Conditions conditions ) throws WSSecurityException { @@ -281,13 +281,13 @@ public class SAMLSSOResponseValidator { } List<AudienceRestriction> audienceRestrs = conditions.getAudienceRestrictions(); if (!matchSaml2AudienceRestriction(spIdentifier, audienceRestrs)) { - LOG.fine("Assertion does not contain unique subject provider identifier " + LOG.fine("Assertion does not contain unique subject provider identifier " + spIdentifier + " in the audience restriction conditions"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - - + + private boolean matchSaml2AudienceRestriction( String appliesTo, List<AudienceRestriction> audienceRestrictions ) { @@ -352,7 +352,7 @@ public class SAMLSSOResponseValidator { public void setSpIdentifier(String spIdentifier) { this.spIdentifier = spIdentifier; } - + public void setReplayCache(TokenReplayCache<String> replayCache) { this.replayCache = replayCache; } @@ -367,5 +367,5 @@ public class SAMLSSOResponseValidator { public void setEnforceResponseSigned(boolean enforceResponseSigned) { this.enforceResponseSigned = enforceResponseSigned; } - + } http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java ---------------------------------------------------------------------- diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java new file mode 100644 index 0000000..5eadaef --- /dev/null +++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java @@ -0,0 +1,84 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.core.logic.saml2; + +import java.util.Date; + +import org.w3c.dom.Element; +import org.opensaml.saml.saml2.core.Assertion; + +/** + * Some information that encapsulates a successful validation by the SAMLSSOResponseValidator + */ +public class SSOValidatorResponse { + private Date sessionNotOnOrAfter; + private Date created; + private String responseId; + private String assertion; + private Element assertionElement; + private Assertion opensamlAssertion; + + public String getAssertion() { + return assertion; + } + + public void setAssertion(final String assertion) { + this.assertion = assertion; + } + + public Date getSessionNotOnOrAfter() { + return sessionNotOnOrAfter; + } + + public void setSessionNotOnOrAfter(final Date sessionNotOnOrAfter) { + this.sessionNotOnOrAfter = sessionNotOnOrAfter; + } + + public String getResponseId() { + return responseId; + } + + public void setResponseId(final String responseId) { + this.responseId = responseId; + } + + public Element getAssertionElement() { + return assertionElement; + } + + public void setAssertionElement(final Element assertionElement) { + this.assertionElement = assertionElement; + } + + public Date getCreated() { + return created; + } + + public void setCreated(final Date created) { + this.created = created; + } + + public Assertion getOpensamlAssertion() { + return opensamlAssertion; + } + + public void setOpensamlAssertion(final Assertion opensamlAssertion) { + this.opensamlAssertion = opensamlAssertion; + } +}