You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2017/08/03 10:54:39 UTC
[1/2] syncope git commit: [SYNCOPE-1185] SAMLSSOResponseValidator in
action
Repository: syncope
Updated Branches:
refs/heads/2_0_X fc682bf5b -> 4dcc0db48
refs/heads/master e3467bf4b -> e624f369d
[SYNCOPE-1185] SAMLSSOResponseValidator in action
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/4dcc0db4
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/4dcc0db4
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/4dcc0db4
Branch: refs/heads/2_0_X
Commit: 4dcc0db48dfa1bf9231038d6b0837e2d21bef7a8
Parents: fc682bf
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Aug 3 12:51:50 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Aug 3 12:51:50 2017 +0200
----------------------------------------------------------------------
.../saml2lsp/agent/AbstractSAML2SPServlet.java | 10 +-
.../ext/saml2lsp/agent/AssertionConsumer.java | 7 +-
.../syncope/ext/saml2lsp/agent/Logout.java | 6 +-
.../common/lib/to/SAML2ReceivedResponseTO.java | 31 ++
.../saml/sso/SAMLSSOResponseValidator.java | 369 +++++++++++++++++++
.../apache/syncope/core/logic/SAML2SPLogic.java | 33 +-
.../core/logic/saml2/SAML2ReaderWriter.java | 25 +-
fit/core-reference/pom.xml | 2 -
.../apache/syncope/fit/core/SAML2ITCase.java | 73 ++--
.../src/test/resources/stsrealm_a.jks | Bin 2061 -> 0 bytes
10 files changed, 497 insertions(+), 59 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
index d84bcd7..ecc14fe 100644
--- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
+++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
@@ -76,7 +76,12 @@ public abstract class AbstractSAML2SPServlet extends HttpServlet {
}
}
- protected SAML2ReceivedResponseTO extract(final InputStream response) throws IOException {
+ protected SAML2ReceivedResponseTO extract(
+ final String spEntityID,
+ final String urlContext,
+ final String clientAddress,
+ final InputStream response) throws IOException {
+
String strForm = IOUtils.toString(response);
MultivaluedMap<String, String> params = JAXRSUtils.getStructuredParams(strForm, "&", false, false);
@@ -90,6 +95,9 @@ public abstract class AbstractSAML2SPServlet extends HttpServlet {
LOG.debug("Received Relay State: {}", relayState);
SAML2ReceivedResponseTO receivedResponseTO = new SAML2ReceivedResponseTO();
+ receivedResponseTO.setSpEntityID(spEntityID);
+ receivedResponseTO.setUrlContext(urlContext);
+ receivedResponseTO.setClientAddress(clientAddress);
receivedResponseTO.setSamlResponse(samlResponse);
receivedResponseTO.setRelayState(relayState);
return receivedResponseTO;
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
index 698aa7f..a2fec3a 100644
--- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
+++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
@@ -25,6 +25,7 @@ import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.to.SAML2LoginResponseTO;
import org.apache.syncope.common.rest.api.service.SAML2SPService;
@@ -42,7 +43,11 @@ public class AssertionConsumer extends AbstractSAML2SPServlet {
getAttribute(Constants.SYNCOPE_ANONYMOUS_CLIENT);
try {
SAML2LoginResponseTO responseTO = anonymous.getService(SAML2SPService.class).
- validateLoginResponse(extract(request.getInputStream()));
+ validateLoginResponse(extract(
+ StringUtils.substringBefore(request.getRequestURL().toString(), "/saml2sp"),
+ "saml2sp",
+ request.getRemoteAddr(),
+ request.getInputStream()));
request.getSession(true).setAttribute(Constants.SAML2SPJWT, responseTO.getAccessToken());
request.getSession(true).setAttribute(Constants.SAML2SPJWT_EXPIRE, responseTO.getAccessTokenExpiryTime());
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
index a8fe481..8008b0c 100644
--- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
+++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
@@ -125,7 +125,11 @@ public class Logout extends AbstractSAML2SPServlet {
throws ServletException, IOException {
// process POST binding logout response
- SAML2ReceivedResponseTO receivedResponse = extract(request.getInputStream());
+ SAML2ReceivedResponseTO receivedResponse = extract(
+ StringUtils.substringBefore(request.getRequestURL().toString(), "/saml2sp"),
+ "saml2sp",
+ request.getRemoteAddr(),
+ request.getInputStream());
doLogout(receivedResponse, request, response);
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
index 3d5d9b4..4ea2dec 100644
--- a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
+++ b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
@@ -20,6 +20,7 @@ package org.apache.syncope.common.lib.to;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.AbstractBaseBean;
@XmlRootElement(name = "saml2ReceivedResponse")
@@ -28,10 +29,40 @@ public class SAML2ReceivedResponseTO extends AbstractBaseBean {
private static final long serialVersionUID = 6102419133516694822L;
+ private String spEntityID;
+
+ private String urlContext;
+
+ private String clientAddress;
+
private String samlResponse;
private String relayState;
+ public String getSpEntityID() {
+ return spEntityID;
+ }
+
+ public void setSpEntityID(final String spEntityID) {
+ this.spEntityID = StringUtils.appendIfMissing(spEntityID, "/");
+ }
+
+ public String getUrlContext() {
+ return urlContext;
+ }
+
+ public void setUrlContext(final String urlContext) {
+ this.urlContext = urlContext;
+ }
+
+ public String getClientAddress() {
+ return clientAddress;
+ }
+
+ public void setClientAddress(final String clientAddress) {
+ this.clientAddress = clientAddress;
+ }
+
public String getSamlResponse() {
return samlResponse;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/ext/saml2sp/logic/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java b/ext/saml2sp/logic/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java
new file mode 100644
index 0000000..bff1fd8
--- /dev/null
+++ b/ext/saml2sp/logic/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLSSOResponseValidator.java
@@ -0,0 +1,369 @@
+/**
+ * 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.cxf.rs.security.saml.sso;
+
+import java.util.Date;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.builder.SAML2Constants;
+import org.apache.wss4j.common.util.DOM2Writer;
+import org.opensaml.saml.saml2.core.AudienceRestriction;
+import org.opensaml.saml.saml2.core.AuthnStatement;
+
+/**
+ * Validate a SAML 2.0 Protocol Response according to the Web SSO profile. The Response
+ * should be validated by the SAMLProtocolResponseValidator first.
+ */
+//CHECKSTYLE:OFF
+public class SAMLSSOResponseValidator {
+
+ private static final Logger LOG = LogUtils.getL7dLogger(SAMLSSOResponseValidator.class);
+
+ private String issuerIDP;
+ private String assertionConsumerURL;
+ private String clientAddress;
+ private String requestId;
+ private String spIdentifier;
+ private boolean enforceResponseSigned;
+ 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.
+ */
+ 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
+ * @param postBinding
+ * @return a SSOValidatorResponse object
+ * @throws WSSecurityException
+ */
+ public SSOValidatorResponse validateSamlResponse(
+ org.opensaml.saml.saml2.core.Response samlResponse,
+ boolean postBinding
+ ) throws WSSecurityException {
+ // Check the Issuer
+ validateIssuer(samlResponse.getIssuer());
+
+ // The Response must contain at least one Assertion.
+ if (samlResponse.getAssertions() == null || samlResponse.getAssertions().isEmpty()) {
+ 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();
+ if (samlResponse.isSigned()
+ && (destination == null || !destination.equals(assertionConsumerURL))) {
+ 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;
+ for (org.opensaml.saml.saml2.core.Assertion assertion : samlResponse.getAssertions()) {
+ // Check the Issuer
+ if (assertion.getIssuer() == null) {
+ LOG.fine("Assertion Issuer must not be null");
+ 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 =
+ validateAuthenticationSubject(subject, assertion.getID(), postBinding);
+ if (subjectConf != null) {
+ validateAudienceRestrictionCondition(assertion.getConditions());
+ validAssertion = assertion;
+ // Store Session NotOnOrAfter
+ for (AuthnStatement authnStatment : assertion.getAuthnStatements()) {
+ if (authnStatment.getSessionNotOnOrAfter() != null) {
+ sessionNotOnOrAfter = authnStatment.getSessionNotOnOrAfter().toDate();
+ }
+ }
+ // Fall back to the SubjectConfirmationData NotOnOrAfter if we have no session NotOnOrAfter
+ if (sessionNotOnOrAfter == null) {
+ sessionNotOnOrAfter = subjectConf.getSubjectConfirmationData().getNotOnOrAfter().toDate();
+ }
+ }
+ }
+ }
+
+ 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);
+ 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)
+ */
+ private void validateIssuer(org.opensaml.saml.saml2.core.Issuer issuer) throws WSSecurityException {
+ 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: "
+ + 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: "
+ + SAML2Constants.NAMEID_FORMAT_ENTITY);
+ throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
+ }
+ }
+
+ /**
+ * Validate the Subject (of an Authentication Statement).
+ */
+ private org.opensaml.saml.saml2.core.SubjectConfirmation validateAuthenticationSubject(
+ org.opensaml.saml.saml2.core.Subject subject, String id, boolean postBinding
+ ) throws WSSecurityException {
+ 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
+ : subject.getSubjectConfirmations()) {
+ if (SAML2Constants.CONF_BEARER.equals(subjectConf.getMethod())) {
+ validateSubjectConfirmation(subjectConf.getSubjectConfirmationData(), id, postBinding);
+ validSubjectConf = subjectConf;
+ }
+ }
+
+ return validSubjectConf;
+ }
+
+ /**
+ * Validate a (Bearer) Subject Confirmation
+ */
+ private void validateSubjectConfirmation(
+ org.opensaml.saml.saml2.core.SubjectConfirmationData subjectConfData, String id, boolean postBinding
+ ) throws WSSecurityException {
+ if (subjectConfData == null) {
+ 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)) {
+ LOG.fine("Recipient " + recipient + " does not match assertion consumer URL "
+ + 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) {
+ Date expires = subjectConfData.getNotOnOrAfter().toDate();
+ Date currentTime = new Date();
+ long ttl = expires.getTime() - currentTime.getTime();
+ replayCache.putId(id, ttl / 1000L);
+ } else {
+ LOG.fine("Replay attack with token id: " + id);
+ throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
+ }
+ }
+
+ // Check address
+ if (subjectConfData.getAddress() != null && clientAddress != null
+ && !subjectConfData.getAddress().equals(clientAddress)) {
+ LOG.fine("Subject Conf Data address " + subjectConfData.getAddress() + " does match"
+ + " 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);
+ throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
+ } else if (requestId == null && subjectConfData.getInResponseTo() != null) {
+ 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 {
+ if (conditions == null) {
+ LOG.fine("Conditions are null");
+ throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
+ }
+ List<AudienceRestriction> audienceRestrs = conditions.getAudienceRestrictions();
+ if (!matchSaml2AudienceRestriction(spIdentifier, audienceRestrs)) {
+ 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
+ ) {
+ boolean oneMatchFound = false;
+ if (audienceRestrictions != null && !audienceRestrictions.isEmpty()) {
+ for (AudienceRestriction audienceRestriction : audienceRestrictions) {
+ if (audienceRestriction.getAudiences() != null) {
+ boolean matchFound = false;
+ for (org.opensaml.saml.saml2.core.Audience audience : audienceRestriction.getAudiences()) {
+ if (appliesTo.equals(audience.getAudienceURI())) {
+ matchFound = true;
+ oneMatchFound = true;
+ break;
+ }
+ }
+ if (!matchFound) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return oneMatchFound;
+ }
+
+ public String getIssuerIDP() {
+ return issuerIDP;
+ }
+
+ public void setIssuerIDP(String issuerIDP) {
+ this.issuerIDP = issuerIDP;
+ }
+
+ public String getAssertionConsumerURL() {
+ return assertionConsumerURL;
+ }
+
+ public void setAssertionConsumerURL(String assertionConsumerURL) {
+ this.assertionConsumerURL = assertionConsumerURL;
+ }
+
+ public String getClientAddress() {
+ return clientAddress;
+ }
+
+ public void setClientAddress(String clientAddress) {
+ this.clientAddress = clientAddress;
+ }
+
+ public String getRequestId() {
+ return requestId;
+ }
+
+ public void setRequestId(String requestId) {
+ this.requestId = requestId;
+ }
+
+ public String getSpIdentifier() {
+ return spIdentifier;
+ }
+
+ public void setSpIdentifier(String spIdentifier) {
+ this.spIdentifier = spIdentifier;
+ }
+
+ public void setReplayCache(TokenReplayCache<String> replayCache) {
+ this.replayCache = replayCache;
+ }
+
+ public boolean isEnforceResponseSigned() {
+ return enforceResponseSigned;
+ }
+
+ /**
+ * Enforce whether a SAML Response must be signed.
+ */
+ public void setEnforceResponseSigned(boolean enforceResponseSigned) {
+ this.enforceResponseSigned = enforceResponseSigned;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/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 28a1ef0..a9b63ed 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
@@ -117,7 +117,6 @@ import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator;
import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Component;
import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
@@ -176,6 +175,10 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
@Resource(name = "syncopeJWTSSOProviderDelegate")
private JwsSignatureVerifier jwsSignatureVerifier;
+ private String getAssertionConsumerURL(final String spEntityID, final String urlContext) {
+ return spEntityID + urlContext + "/assertion-consumer";
+ }
+
@PreAuthorize("hasRole('" + StandardEntitlement.ANONYMOUS + "')")
public void getMetadata(final String spEntityID, final String urlContext, final OutputStream os) {
check();
@@ -209,7 +212,7 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
AssertionConsumerService assertionConsumerService = new AssertionConsumerServiceBuilder().buildObject();
assertionConsumerService.setIndex(bindingType.ordinal());
assertionConsumerService.setBinding(bindingType.getUri());
- assertionConsumerService.setLocation(spEntityID + urlContext + "/assertion-consumer");
+ assertionConsumerService.setLocation(getAssertionConsumerURL(spEntityID, urlContext));
spSSODescriptor.getAssertionConsumerServices().add(assertionConsumerService);
spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor);
@@ -450,24 +453,19 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
throw sce;
}
- // 3. further checks:
- // 3a. the SAML Reponse's InResponseTo
- if (!relayState.getJwtClaims().getSubject().equals(samlResponse.getInResponseTo())) {
- throw new IllegalArgumentException("Unmatching request ID: " + samlResponse.getInResponseTo());
- }
- // 3b. the SAML Response status
- if (!StatusCode.SUCCESS.equals(samlResponse.getStatus().getStatusCode().getValue())) {
- throw new BadCredentialsException("The SAML IdP replied with "
- + samlResponse.getStatus().getStatusCode().getValue());
- }
-
- // 4. validate the SAML response and, if needed, decrypt the provided assertion(s)
+ // 3. validate the SAML response and, if needed, decrypt the provided assertion(s)
SAML2IdPEntity idp = getIdP(samlResponse.getIssuer().getValue());
if (idp.getConnObjectKeyItem() == null) {
throw new IllegalArgumentException("No mapping provided for SAML 2.0 IdP '" + idp.getId() + "'");
}
try {
- saml2rw.validate(samlResponse, idp.getTrustStore());
+ saml2rw.validate(
+ samlResponse,
+ idp,
+ getAssertionConsumerURL(response.getSpEntityID(), response.getUrlContext()),
+ response.getClientAddress(),
+ relayState.getJwtClaims().getSubject(),
+ response.getSpEntityID());
} catch (Exception e) {
LOG.error("While validating AuthnResponse", e);
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unknown);
@@ -475,7 +473,7 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
throw sce;
}
- // 5. prepare the result: find matching user (if any) and return the received attributes
+ // 4. prepare the result: find matching user (if any) and return the received attributes
SAML2LoginResponseTO responseTO = new SAML2LoginResponseTO();
responseTO.setIdp(idp.getId());
responseTO.setSloSupported(idp.getSLOLocation(idp.getBindingType()) != null);
@@ -541,7 +539,8 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
responseTO.setUsername(userDAO.find(matchingUsers.get(0)).getUsername());
responseTO.setNameID(nameID.getValue());
- // 6. generate JWT for further access
+
+ // 5. generate JWT for further access
Map<String, Object> claims = new HashMap<>();
claims.put(JWT_CLAIM_IDP_ENTITYID, idp.getId());
claims.put(JWT_CLAIM_NAMEID_FORMAT, nameID.getFormat());
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/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 0698b38..17386ea 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
@@ -28,7 +28,6 @@ import java.io.Writer;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
-import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
@@ -44,8 +43,10 @@ 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.SAMLSSOResponseValidator;
import org.apache.cxf.staxutils.StaxUtils;
import org.apache.syncope.common.lib.SSOConstants;
+import org.apache.syncope.common.lib.types.SAML2BindingType;
import org.apache.syncope.core.logic.init.SAML2SPLoader;
import org.apache.wss4j.common.crypto.Merlin;
import org.apache.wss4j.common.ext.WSSecurityException;
@@ -91,6 +92,8 @@ public class SAML2ReaderWriter {
private SAMLProtocolResponseValidator protocolValidator;
+ private SAMLSSOResponseValidator ssoResponseValidator;
+
private SAMLSPCallbackHandler callbackHandler;
public void init() {
@@ -109,6 +112,8 @@ public class SAML2ReaderWriter {
protocolValidator = new SAMLProtocolResponseValidator();
protocolValidator.setKeyInfoMustBeAvailable(true);
+ ssoResponseValidator = new SAMLSSOResponseValidator();
+
callbackHandler = new SAMLSPCallbackHandler(loader.getKeyPass());
}
@@ -205,14 +210,28 @@ public class SAML2ReaderWriter {
return Base64.encodeBase64String(deflatedBytes);
}
- public void validate(final Response samlResponse, final KeyStore idpTrustStore) throws WSSecurityException {
+ public void validate(
+ final Response samlResponse,
+ final SAML2IdPEntity idp,
+ final String assertionConsumerURL,
+ final String clientAddress,
+ final String requestId,
+ final String spEntityID)
+ throws WSSecurityException {
+
// validate the SAML response and, if needed, decrypt the provided assertion(s)
Merlin crypto = new Merlin();
crypto.setKeyStore(loader.getKeyStore());
- crypto.setTrustStore(idpTrustStore);
+ crypto.setTrustStore(idp.getTrustStore());
protocolValidator.validateSamlResponse(samlResponse, crypto, callbackHandler);
+ ssoResponseValidator.setAssertionConsumerURL(assertionConsumerURL);
+ ssoResponseValidator.setIssuerIDP(idp.getId());
+ ssoResponseValidator.setRequestId(requestId);
+ ssoResponseValidator.setSpIdentifier(spEntityID);
+ ssoResponseValidator.validateSamlResponse(samlResponse, idp.getBindingType() == SAML2BindingType.POST);
+
if (LOG.isDebugEnabled()) {
try {
StringWriter writer = new StringWriter();
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index ac7ddcf..de491a3 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -363,7 +363,6 @@ under the License.
<filtering>true</filtering>
<excludes>
<exclude>keystore</exclude>
- <exclude>**/*.jks</exclude>
</excludes>
</testResource>
<testResource>
@@ -371,7 +370,6 @@ under the License.
<filtering>false</filtering>
<includes>
<include>keystore</include>
- <include>**/*.jks</include>
</includes>
</testResource>
<testResource>
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
index a61b00c..e3cb7e0 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
@@ -198,8 +198,7 @@ public class SAML2ITCase extends AbstractITCase {
// Get a valid login request for the Fediz realm
SAML2SPService saml2Service = anonymous.getService(SAML2SPService.class);
- SAML2RequestTO loginRequest =
- saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
+ SAML2RequestTO loginRequest = saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
assertNotNull(loginRequest);
assertEquals("https://localhost:8443/fediz-idp/saml/up", loginRequest.getIdpServiceAddress());
@@ -209,11 +208,13 @@ public class SAML2ITCase extends AbstractITCase {
// Check a null relaystate
SAML2ReceivedResponseTO response = new SAML2ReceivedResponseTO();
+ response.setSpEntityID("http://recipient.apache.org/");
+ response.setUrlContext("saml2sp");
try {
saml2Service.validateLoginResponse(response);
fail("Failure expected on no Relay State");
- } catch (SyncopeClientException ex) {
- assertTrue(ex.getMessage().contains("No Relay State was provided"));
+ } catch (SyncopeClientException e) {
+ assertTrue(e.getMessage().contains("No Relay State was provided"));
}
// Check a null Response
@@ -221,16 +222,17 @@ public class SAML2ITCase extends AbstractITCase {
try {
saml2Service.validateLoginResponse(response);
fail("Failure expected on no SAML Response");
- } catch (SyncopeClientException ex) {
- assertTrue(ex.getMessage().contains("No SAML Response was provided"));
+ } catch (SyncopeClientException e) {
+ assertTrue(e.getMessage().contains("No SAML Response was provided"));
}
// Create a SAML Response using WSS4J
- Document doc = DOMUtils.newDocument();
JwsJwtCompactConsumer relayState = new JwsJwtCompactConsumer(response.getRelayState());
String inResponseTo = relayState.getJwtClaims().getSubject();
org.opensaml.saml.saml2.core.Response samlResponse = createResponse(inResponseTo);
+
+ Document doc = DOMUtils.newDocument();
Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
String responseStr = DOM2Writer.nodeToString(responseElement);
@@ -242,26 +244,27 @@ public class SAML2ITCase extends AbstractITCase {
}
@Test
- @org.junit.Ignore
- public void testUnsignedAssertionInLoginResponse() throws Exception {
+ public void unsignedAssertionInLoginResponse() throws Exception {
Assume.assumeTrue(SAML2SPDetector.isSAML2SPAvailable());
// Get a valid login request for the Fediz realm
SAML2SPService saml2Service = anonymous.getService(SAML2SPService.class);
- SAML2RequestTO loginRequest =
- saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
+ SAML2RequestTO loginRequest = saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
assertNotNull(loginRequest);
SAML2ReceivedResponseTO response = new SAML2ReceivedResponseTO();
+ response.setSpEntityID("http://recipient.apache.org/");
+ response.setUrlContext("saml2sp");
response.setRelayState(loginRequest.getRelayState());
// Create a SAML Response using WSS4J
- Document doc = DOMUtils.newDocument();
JwsJwtCompactConsumer relayState = new JwsJwtCompactConsumer(response.getRelayState());
String inResponseTo = relayState.getJwtClaims().getSubject();
org.opensaml.saml.saml2.core.Response samlResponse =
createResponse(inResponseTo, false, SAML2Constants.CONF_SENDER_VOUCHES);
+
+ Document doc = DOMUtils.newDocument();
Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
String responseStr = DOM2Writer.nodeToString(responseElement);
@@ -270,35 +273,35 @@ public class SAML2ITCase extends AbstractITCase {
try {
saml2Service.validateLoginResponse(response);
fail("Failure expected on an unsigned Assertion");
- } catch (SyncopeClientException ex) {
- // expected
+ } catch (SyncopeClientException e) {
+ assertNotNull(e);
}
}
@Test
- @org.junit.Ignore
- public void testLoginResponseWrappingAttack() throws Exception {
+ public void loginResponseWrappingAttack() throws Exception {
Assume.assumeTrue(SAML2SPDetector.isSAML2SPAvailable());
// Get a valid login request for the Fediz realm
SAML2SPService saml2Service = anonymous.getService(SAML2SPService.class);
- SAML2RequestTO loginRequest =
- saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
+ SAML2RequestTO loginRequest = saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
assertNotNull(loginRequest);
SAML2ReceivedResponseTO response = new SAML2ReceivedResponseTO();
+ response.setSpEntityID("http://recipient.apache.org/");
+ response.setUrlContext("saml2sp");
response.setRelayState(loginRequest.getRelayState());
// Create a SAML Response using WSS4J
- Document doc = DOMUtils.newDocument();
JwsJwtCompactConsumer relayState = new JwsJwtCompactConsumer(response.getRelayState());
String inResponseTo = relayState.getJwtClaims().getSubject();
org.opensaml.saml.saml2.core.Response samlResponse = createResponse(inResponseTo);
- Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
- doc.appendChild(responseElement);
+ Document doc = DOMUtils.newDocument();
+ Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
assertNotNull(responseElement);
+ doc.appendChild(responseElement);
// Get Assertion Element
Element assertionElement =
@@ -329,9 +332,12 @@ public class SAML2ITCase extends AbstractITCase {
// Validate the SAML Response
response.setSamlResponse(Base64.encodeBase64String(responseStr.getBytes()));
- SAML2LoginResponseTO loginResponse = saml2Service.validateLoginResponse(response);
- assertNotNull(loginResponse.getAccessToken());
- assertEquals("puccini", loginResponse.getNameID());
+ try {
+ saml2Service.validateLoginResponse(response);
+ fail("Failure expected on an unsigned Assertion");
+ } catch (SyncopeClientException e) {
+ assertNotNull(e);
+ }
}
private org.opensaml.saml.saml2.core.Response createResponse(final String inResponseTo) throws Exception {
@@ -343,9 +349,8 @@ public class SAML2ITCase extends AbstractITCase {
Status status = SAML2PResponseComponentBuilder.createStatus(
SAMLProtocolResponseValidator.SAML2_STATUSCODE_SUCCESS, null);
- org.opensaml.saml.saml2.core.Response response =
- SAML2PResponseComponentBuilder.createSAMLResponse(
- inResponseTo, "urn:org:apache:cxf:fediz:idp:realm-A", status);
+ org.opensaml.saml.saml2.core.Response response = SAML2PResponseComponentBuilder.createSAMLResponse(
+ inResponseTo, "urn:org:apache:cxf:fediz:idp:realm-A", status);
response.setDestination("http://recipient.apache.org");
// Create an AuthenticationAssertion
@@ -356,9 +361,9 @@ public class SAML2ITCase extends AbstractITCase {
SubjectConfirmationDataBean subjectConfirmationData = new SubjectConfirmationDataBean();
subjectConfirmationData.setAddress("http://apache.org");
- subjectConfirmationData.setInResponseTo("12345");
+ subjectConfirmationData.setInResponseTo(inResponseTo);
subjectConfirmationData.setNotAfter(new DateTime().plusMinutes(5));
- subjectConfirmationData.setRecipient("http://recipient.apache.org");
+ subjectConfirmationData.setRecipient("http://recipient.apache.org/saml2sp/assertion-consumer");
callbackHandler.setSubjectConfirmationData(subjectConfirmationData);
ConditionsBean conditions = new ConditionsBean();
@@ -366,7 +371,7 @@ public class SAML2ITCase extends AbstractITCase {
conditions.setNotAfter(new DateTime().plusMinutes(5));
AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
- audienceRestriction.setAudienceURIs(Collections.singletonList("http://service.apache.org"));
+ audienceRestriction.setAudienceURIs(Collections.singletonList("http://recipient.apache.org/"));
conditions.setAudienceRestrictions(Collections.singletonList(audienceRestriction));
callbackHandler.setConditions(conditions);
@@ -377,12 +382,12 @@ public class SAML2ITCase extends AbstractITCase {
if (signAssertion) {
Crypto issuerCrypto = new Merlin();
KeyStore keyStore = KeyStore.getInstance("JKS");
- ClassLoader loader = Loader.getClassLoader(SAML2ITCase.class);
- InputStream input = Merlin.loadInputStream(loader, "stsrealm_a.jks");
- keyStore.load(input, "storepass".toCharArray());
+ ClassLoader loader = Loader.getClassLoader(getClass());
+ InputStream input = Merlin.loadInputStream(loader, "keystore");
+ keyStore.load(input, "changeit".toCharArray());
((Merlin) issuerCrypto).setKeyStore(keyStore);
- assertion.signAssertion("realma", "realma", issuerCrypto, false);
+ assertion.signAssertion("sp", "changeit", issuerCrypto, false);
}
response.getAssertions().add(assertion.getSaml2());
http://git-wip-us.apache.org/repos/asf/syncope/blob/4dcc0db4/fit/core-reference/src/test/resources/stsrealm_a.jks
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/stsrealm_a.jks b/fit/core-reference/src/test/resources/stsrealm_a.jks
deleted file mode 100644
index fde2928..0000000
Binary files a/fit/core-reference/src/test/resources/stsrealm_a.jks and /dev/null differ
[2/2] syncope git commit: [SYNCOPE-1185] SAMLSSOResponseValidator in
action
Posted by il...@apache.org.
[SYNCOPE-1185] SAMLSSOResponseValidator in action
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/e624f369
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/e624f369
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/e624f369
Branch: refs/heads/master
Commit: e624f369d6a2df12ddc516e6b50ff5cb9d30747b
Parents: e3467bf
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Aug 3 12:51:50 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Aug 3 12:53:58 2017 +0200
----------------------------------------------------------------------
.../saml2lsp/agent/AbstractSAML2SPServlet.java | 10 ++-
.../ext/saml2lsp/agent/AssertionConsumer.java | 7 +-
.../syncope/ext/saml2lsp/agent/Logout.java | 6 +-
.../common/lib/to/SAML2ReceivedResponseTO.java | 31 ++++++++
.../apache/syncope/core/logic/SAML2SPLogic.java | 33 ++++----
.../core/logic/saml2/SAML2ReaderWriter.java | 25 +++++-
fit/core-reference/pom.xml | 2 -
.../apache/syncope/fit/core/SAML2ITCase.java | 76 ++++++++++---------
.../src/test/resources/stsrealm_a.jks | Bin 2061 -> 0 bytes
9 files changed, 130 insertions(+), 60 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
index d84bcd7..ecc14fe 100644
--- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
+++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AbstractSAML2SPServlet.java
@@ -76,7 +76,12 @@ public abstract class AbstractSAML2SPServlet extends HttpServlet {
}
}
- protected SAML2ReceivedResponseTO extract(final InputStream response) throws IOException {
+ protected SAML2ReceivedResponseTO extract(
+ final String spEntityID,
+ final String urlContext,
+ final String clientAddress,
+ final InputStream response) throws IOException {
+
String strForm = IOUtils.toString(response);
MultivaluedMap<String, String> params = JAXRSUtils.getStructuredParams(strForm, "&", false, false);
@@ -90,6 +95,9 @@ public abstract class AbstractSAML2SPServlet extends HttpServlet {
LOG.debug("Received Relay State: {}", relayState);
SAML2ReceivedResponseTO receivedResponseTO = new SAML2ReceivedResponseTO();
+ receivedResponseTO.setSpEntityID(spEntityID);
+ receivedResponseTO.setUrlContext(urlContext);
+ receivedResponseTO.setClientAddress(clientAddress);
receivedResponseTO.setSamlResponse(samlResponse);
receivedResponseTO.setRelayState(relayState);
return receivedResponseTO;
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
index 698aa7f..a2fec3a 100644
--- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
+++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
@@ -25,6 +25,7 @@ import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.to.SAML2LoginResponseTO;
import org.apache.syncope.common.rest.api.service.SAML2SPService;
@@ -42,7 +43,11 @@ public class AssertionConsumer extends AbstractSAML2SPServlet {
getAttribute(Constants.SYNCOPE_ANONYMOUS_CLIENT);
try {
SAML2LoginResponseTO responseTO = anonymous.getService(SAML2SPService.class).
- validateLoginResponse(extract(request.getInputStream()));
+ validateLoginResponse(extract(
+ StringUtils.substringBefore(request.getRequestURL().toString(), "/saml2sp"),
+ "saml2sp",
+ request.getRemoteAddr(),
+ request.getInputStream()));
request.getSession(true).setAttribute(Constants.SAML2SPJWT, responseTO.getAccessToken());
request.getSession(true).setAttribute(Constants.SAML2SPJWT_EXPIRE, responseTO.getAccessTokenExpiryTime());
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
index a8fe481..8008b0c 100644
--- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
+++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/Logout.java
@@ -125,7 +125,11 @@ public class Logout extends AbstractSAML2SPServlet {
throws ServletException, IOException {
// process POST binding logout response
- SAML2ReceivedResponseTO receivedResponse = extract(request.getInputStream());
+ SAML2ReceivedResponseTO receivedResponse = extract(
+ StringUtils.substringBefore(request.getRequestURL().toString(), "/saml2sp"),
+ "saml2sp",
+ request.getRemoteAddr(),
+ request.getInputStream());
doLogout(receivedResponse, request, response);
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
index 3d5d9b4..4ea2dec 100644
--- a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
+++ b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2ReceivedResponseTO.java
@@ -20,6 +20,7 @@ package org.apache.syncope.common.lib.to;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.AbstractBaseBean;
@XmlRootElement(name = "saml2ReceivedResponse")
@@ -28,10 +29,40 @@ public class SAML2ReceivedResponseTO extends AbstractBaseBean {
private static final long serialVersionUID = 6102419133516694822L;
+ private String spEntityID;
+
+ private String urlContext;
+
+ private String clientAddress;
+
private String samlResponse;
private String relayState;
+ public String getSpEntityID() {
+ return spEntityID;
+ }
+
+ public void setSpEntityID(final String spEntityID) {
+ this.spEntityID = StringUtils.appendIfMissing(spEntityID, "/");
+ }
+
+ public String getUrlContext() {
+ return urlContext;
+ }
+
+ public void setUrlContext(final String urlContext) {
+ this.urlContext = urlContext;
+ }
+
+ public String getClientAddress() {
+ return clientAddress;
+ }
+
+ public void setClientAddress(final String clientAddress) {
+ this.clientAddress = clientAddress;
+ }
+
public String getSamlResponse() {
return samlResponse;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/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 28a1ef0..a9b63ed 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
@@ -117,7 +117,6 @@ import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator;
import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Component;
import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
@@ -176,6 +175,10 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
@Resource(name = "syncopeJWTSSOProviderDelegate")
private JwsSignatureVerifier jwsSignatureVerifier;
+ private String getAssertionConsumerURL(final String spEntityID, final String urlContext) {
+ return spEntityID + urlContext + "/assertion-consumer";
+ }
+
@PreAuthorize("hasRole('" + StandardEntitlement.ANONYMOUS + "')")
public void getMetadata(final String spEntityID, final String urlContext, final OutputStream os) {
check();
@@ -209,7 +212,7 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
AssertionConsumerService assertionConsumerService = new AssertionConsumerServiceBuilder().buildObject();
assertionConsumerService.setIndex(bindingType.ordinal());
assertionConsumerService.setBinding(bindingType.getUri());
- assertionConsumerService.setLocation(spEntityID + urlContext + "/assertion-consumer");
+ assertionConsumerService.setLocation(getAssertionConsumerURL(spEntityID, urlContext));
spSSODescriptor.getAssertionConsumerServices().add(assertionConsumerService);
spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor);
@@ -450,24 +453,19 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
throw sce;
}
- // 3. further checks:
- // 3a. the SAML Reponse's InResponseTo
- if (!relayState.getJwtClaims().getSubject().equals(samlResponse.getInResponseTo())) {
- throw new IllegalArgumentException("Unmatching request ID: " + samlResponse.getInResponseTo());
- }
- // 3b. the SAML Response status
- if (!StatusCode.SUCCESS.equals(samlResponse.getStatus().getStatusCode().getValue())) {
- throw new BadCredentialsException("The SAML IdP replied with "
- + samlResponse.getStatus().getStatusCode().getValue());
- }
-
- // 4. validate the SAML response and, if needed, decrypt the provided assertion(s)
+ // 3. validate the SAML response and, if needed, decrypt the provided assertion(s)
SAML2IdPEntity idp = getIdP(samlResponse.getIssuer().getValue());
if (idp.getConnObjectKeyItem() == null) {
throw new IllegalArgumentException("No mapping provided for SAML 2.0 IdP '" + idp.getId() + "'");
}
try {
- saml2rw.validate(samlResponse, idp.getTrustStore());
+ saml2rw.validate(
+ samlResponse,
+ idp,
+ getAssertionConsumerURL(response.getSpEntityID(), response.getUrlContext()),
+ response.getClientAddress(),
+ relayState.getJwtClaims().getSubject(),
+ response.getSpEntityID());
} catch (Exception e) {
LOG.error("While validating AuthnResponse", e);
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unknown);
@@ -475,7 +473,7 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
throw sce;
}
- // 5. prepare the result: find matching user (if any) and return the received attributes
+ // 4. prepare the result: find matching user (if any) and return the received attributes
SAML2LoginResponseTO responseTO = new SAML2LoginResponseTO();
responseTO.setIdp(idp.getId());
responseTO.setSloSupported(idp.getSLOLocation(idp.getBindingType()) != null);
@@ -541,7 +539,8 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
responseTO.setUsername(userDAO.find(matchingUsers.get(0)).getUsername());
responseTO.setNameID(nameID.getValue());
- // 6. generate JWT for further access
+
+ // 5. generate JWT for further access
Map<String, Object> claims = new HashMap<>();
claims.put(JWT_CLAIM_IDP_ENTITYID, idp.getId());
claims.put(JWT_CLAIM_NAMEID_FORMAT, nameID.getFormat());
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/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 429c088..1852a39 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
@@ -28,7 +28,6 @@ import java.io.Writer;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
-import java.security.KeyStore;
import java.util.Base64;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -44,8 +43,10 @@ import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
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.SAMLSSOResponseValidator;
import org.apache.cxf.staxutils.StaxUtils;
import org.apache.syncope.common.lib.SSOConstants;
+import org.apache.syncope.common.lib.types.SAML2BindingType;
import org.apache.syncope.core.logic.init.SAML2SPLoader;
import org.apache.wss4j.common.crypto.Merlin;
import org.apache.wss4j.common.ext.WSSecurityException;
@@ -91,6 +92,8 @@ public class SAML2ReaderWriter {
private SAMLProtocolResponseValidator protocolValidator;
+ private SAMLSSOResponseValidator ssoResponseValidator;
+
private SAMLSPCallbackHandler callbackHandler;
public void init() {
@@ -109,6 +112,8 @@ public class SAML2ReaderWriter {
protocolValidator = new SAMLProtocolResponseValidator();
protocolValidator.setKeyInfoMustBeAvailable(true);
+ ssoResponseValidator = new SAMLSSOResponseValidator();
+
callbackHandler = new SAMLSPCallbackHandler(loader.getKeyPass());
}
@@ -205,14 +210,28 @@ public class SAML2ReaderWriter {
return Base64.getEncoder().encodeToString(deflatedBytes);
}
- public void validate(final Response samlResponse, final KeyStore idpTrustStore) throws WSSecurityException {
+ public void validate(
+ final Response samlResponse,
+ final SAML2IdPEntity idp,
+ final String assertionConsumerURL,
+ final String clientAddress,
+ final String requestId,
+ final String spEntityID)
+ throws WSSecurityException {
+
// validate the SAML response and, if needed, decrypt the provided assertion(s)
Merlin crypto = new Merlin();
crypto.setKeyStore(loader.getKeyStore());
- crypto.setTrustStore(idpTrustStore);
+ crypto.setTrustStore(idp.getTrustStore());
protocolValidator.validateSamlResponse(samlResponse, crypto, callbackHandler);
+ ssoResponseValidator.setAssertionConsumerURL(assertionConsumerURL);
+ ssoResponseValidator.setIssuerIDP(idp.getId());
+ ssoResponseValidator.setRequestId(requestId);
+ ssoResponseValidator.setSpIdentifier(spEntityID);
+ ssoResponseValidator.validateSamlResponse(samlResponse, idp.getBindingType() == SAML2BindingType.POST);
+
if (LOG.isDebugEnabled()) {
try {
StringWriter writer = new StringWriter();
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 0772ccb..5762a33 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -363,7 +363,6 @@ under the License.
<filtering>true</filtering>
<excludes>
<exclude>keystore</exclude>
- <exclude>**/*.jks</exclude>
</excludes>
</testResource>
<testResource>
@@ -371,7 +370,6 @@ under the License.
<filtering>false</filtering>
<includes>
<include>keystore</include>
- <include>**/*.jks</include>
</includes>
</testResource>
<testResource>
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
index 68626d0..f0cd386 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java
@@ -165,7 +165,8 @@ public class SAML2ITCase extends AbstractITCase {
Assume.assumeTrue(SAML2SPDetector.isSAML2SPAvailable());
Optional<SAML2IdPTO> ssoCircleOpt =
- saml2IdPService.list().stream().filter(o -> "https://idp.ssocircle.com".equals(o.getEntityID())).findFirst();
+ saml2IdPService.list().stream().filter(o -> "https://idp.ssocircle.com".equals(o.getEntityID())).
+ findFirst();
assertTrue(ssoCircleOpt.isPresent());
SAML2IdPTO ssoCircle = ssoCircleOpt.get();
@@ -195,8 +196,7 @@ public class SAML2ITCase extends AbstractITCase {
// Get a valid login request for the Fediz realm
SAML2SPService saml2Service = anonymous.getService(SAML2SPService.class);
- SAML2RequestTO loginRequest =
- saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
+ SAML2RequestTO loginRequest = saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
assertNotNull(loginRequest);
assertEquals("https://localhost:8443/fediz-idp/saml/up", loginRequest.getIdpServiceAddress());
@@ -206,11 +206,13 @@ public class SAML2ITCase extends AbstractITCase {
// Check a null relaystate
SAML2ReceivedResponseTO response = new SAML2ReceivedResponseTO();
+ response.setSpEntityID("http://recipient.apache.org/");
+ response.setUrlContext("saml2sp");
try {
saml2Service.validateLoginResponse(response);
fail("Failure expected on no Relay State");
- } catch (SyncopeClientException ex) {
- assertTrue(ex.getMessage().contains("No Relay State was provided"));
+ } catch (SyncopeClientException e) {
+ assertTrue(e.getMessage().contains("No Relay State was provided"));
}
// Check a null Response
@@ -218,16 +220,17 @@ public class SAML2ITCase extends AbstractITCase {
try {
saml2Service.validateLoginResponse(response);
fail("Failure expected on no SAML Response");
- } catch (SyncopeClientException ex) {
- assertTrue(ex.getMessage().contains("No SAML Response was provided"));
+ } catch (SyncopeClientException e) {
+ assertTrue(e.getMessage().contains("No SAML Response was provided"));
}
// Create a SAML Response using WSS4J
- Document doc = DOMUtils.newDocument();
JwsJwtCompactConsumer relayState = new JwsJwtCompactConsumer(response.getRelayState());
String inResponseTo = relayState.getJwtClaims().getSubject();
org.opensaml.saml.saml2.core.Response samlResponse = createResponse(inResponseTo);
+
+ Document doc = DOMUtils.newDocument();
Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
String responseStr = DOM2Writer.nodeToString(responseElement);
@@ -239,26 +242,27 @@ public class SAML2ITCase extends AbstractITCase {
}
@Test
- @org.junit.Ignore
- public void testUnsignedAssertionInLoginResponse() throws Exception {
+ public void unsignedAssertionInLoginResponse() throws Exception {
Assume.assumeTrue(SAML2SPDetector.isSAML2SPAvailable());
// Get a valid login request for the Fediz realm
SAML2SPService saml2Service = anonymous.getService(SAML2SPService.class);
- SAML2RequestTO loginRequest =
- saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
+ SAML2RequestTO loginRequest = saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
assertNotNull(loginRequest);
SAML2ReceivedResponseTO response = new SAML2ReceivedResponseTO();
+ response.setSpEntityID("http://recipient.apache.org/");
+ response.setUrlContext("saml2sp");
response.setRelayState(loginRequest.getRelayState());
// Create a SAML Response using WSS4J
- Document doc = DOMUtils.newDocument();
JwsJwtCompactConsumer relayState = new JwsJwtCompactConsumer(response.getRelayState());
String inResponseTo = relayState.getJwtClaims().getSubject();
org.opensaml.saml.saml2.core.Response samlResponse =
createResponse(inResponseTo, false, SAML2Constants.CONF_SENDER_VOUCHES);
+
+ Document doc = DOMUtils.newDocument();
Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
String responseStr = DOM2Writer.nodeToString(responseElement);
@@ -267,35 +271,35 @@ public class SAML2ITCase extends AbstractITCase {
try {
saml2Service.validateLoginResponse(response);
fail("Failure expected on an unsigned Assertion");
- } catch (SyncopeClientException ex) {
- // expected
+ } catch (SyncopeClientException e) {
+ assertNotNull(e);
}
}
@Test
- @org.junit.Ignore
- public void testLoginResponseWrappingAttack() throws Exception {
+ public void loginResponseWrappingAttack() throws Exception {
Assume.assumeTrue(SAML2SPDetector.isSAML2SPAvailable());
// Get a valid login request for the Fediz realm
SAML2SPService saml2Service = anonymous.getService(SAML2SPService.class);
- SAML2RequestTO loginRequest =
- saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
+ SAML2RequestTO loginRequest = saml2Service.createLoginRequest(ADDRESS, "urn:org:apache:cxf:fediz:idp:realm-A");
assertNotNull(loginRequest);
SAML2ReceivedResponseTO response = new SAML2ReceivedResponseTO();
+ response.setSpEntityID("http://recipient.apache.org/");
+ response.setUrlContext("saml2sp");
response.setRelayState(loginRequest.getRelayState());
// Create a SAML Response using WSS4J
- Document doc = DOMUtils.newDocument();
JwsJwtCompactConsumer relayState = new JwsJwtCompactConsumer(response.getRelayState());
String inResponseTo = relayState.getJwtClaims().getSubject();
org.opensaml.saml.saml2.core.Response samlResponse = createResponse(inResponseTo);
- Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
- doc.appendChild(responseElement);
+ Document doc = DOMUtils.newDocument();
+ Element responseElement = OpenSAMLUtil.toDom(samlResponse, doc);
assertNotNull(responseElement);
+ doc.appendChild(responseElement);
// Get Assertion Element
Element assertionElement =
@@ -326,9 +330,12 @@ public class SAML2ITCase extends AbstractITCase {
// Validate the SAML Response
response.setSamlResponse(java.util.Base64.getEncoder().encodeToString(responseStr.getBytes()));
- SAML2LoginResponseTO loginResponse = saml2Service.validateLoginResponse(response);
- assertNotNull(loginResponse.getAccessToken());
- assertEquals("puccini", loginResponse.getNameID());
+ try {
+ saml2Service.validateLoginResponse(response);
+ fail("Failure expected on an unsigned Assertion");
+ } catch (SyncopeClientException e) {
+ assertNotNull(e);
+ }
}
private org.opensaml.saml.saml2.core.Response createResponse(final String inResponseTo) throws Exception {
@@ -340,9 +347,8 @@ public class SAML2ITCase extends AbstractITCase {
Status status = SAML2PResponseComponentBuilder.createStatus(
SAMLProtocolResponseValidator.SAML2_STATUSCODE_SUCCESS, null);
- org.opensaml.saml.saml2.core.Response response =
- SAML2PResponseComponentBuilder.createSAMLResponse(
- inResponseTo, "urn:org:apache:cxf:fediz:idp:realm-A", status);
+ org.opensaml.saml.saml2.core.Response response = SAML2PResponseComponentBuilder.createSAMLResponse(
+ inResponseTo, "urn:org:apache:cxf:fediz:idp:realm-A", status);
response.setDestination("http://recipient.apache.org");
// Create an AuthenticationAssertion
@@ -353,9 +359,9 @@ public class SAML2ITCase extends AbstractITCase {
SubjectConfirmationDataBean subjectConfirmationData = new SubjectConfirmationDataBean();
subjectConfirmationData.setAddress("http://apache.org");
- subjectConfirmationData.setInResponseTo("12345");
+ subjectConfirmationData.setInResponseTo(inResponseTo);
subjectConfirmationData.setNotAfter(new DateTime().plusMinutes(5));
- subjectConfirmationData.setRecipient("http://recipient.apache.org");
+ subjectConfirmationData.setRecipient("http://recipient.apache.org/saml2sp/assertion-consumer");
callbackHandler.setSubjectConfirmationData(subjectConfirmationData);
ConditionsBean conditions = new ConditionsBean();
@@ -363,7 +369,7 @@ public class SAML2ITCase extends AbstractITCase {
conditions.setNotAfter(new DateTime().plusMinutes(5));
AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
- audienceRestriction.setAudienceURIs(Collections.singletonList("http://service.apache.org"));
+ audienceRestriction.setAudienceURIs(Collections.singletonList("http://recipient.apache.org/"));
conditions.setAudienceRestrictions(Collections.singletonList(audienceRestriction));
callbackHandler.setConditions(conditions);
@@ -374,12 +380,12 @@ public class SAML2ITCase extends AbstractITCase {
if (signAssertion) {
Crypto issuerCrypto = new Merlin();
KeyStore keyStore = KeyStore.getInstance("JKS");
- ClassLoader loader = Loader.getClassLoader(SAML2ITCase.class);
- InputStream input = Merlin.loadInputStream(loader, "stsrealm_a.jks");
- keyStore.load(input, "storepass".toCharArray());
+ ClassLoader loader = Loader.getClassLoader(getClass());
+ InputStream input = Merlin.loadInputStream(loader, "keystore");
+ keyStore.load(input, "changeit".toCharArray());
((Merlin) issuerCrypto).setKeyStore(keyStore);
- assertion.signAssertion("realma", "realma", issuerCrypto, false);
+ assertion.signAssertion("sp", "changeit", issuerCrypto, false);
}
response.getAssertions().add(assertion.getSaml2());
http://git-wip-us.apache.org/repos/asf/syncope/blob/e624f369/fit/core-reference/src/test/resources/stsrealm_a.jks
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/stsrealm_a.jks b/fit/core-reference/src/test/resources/stsrealm_a.jks
deleted file mode 100644
index fde2928..0000000
Binary files a/fit/core-reference/src/test/resources/stsrealm_a.jks and /dev/null differ