[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ò <ilgro...@apache.org> Authored: Thu Aug 3 12:51:50 2017 +0200 Committer: Francesco Chicchiriccò <ilgro...@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