From 9b2ece9dbaf9c4347848c5b87c74385b54c4c9eb Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Fri, 28 Aug 2020 15:58:40 -0600 Subject: [PATCH] Remove SAML 2.0 Framework Tests Closes gh-8989 --- .../OpenSamlActionTestingSupport.java | 473 ---------------- .../Saml2LoginIntegrationTests.java | 503 ------------------ .../samples/config/SecurityConfigTests.java | 37 +- 3 files changed, 2 insertions(+), 1011 deletions(-) delete mode 100644 samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlActionTestingSupport.java delete mode 100644 samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/Saml2LoginIntegrationTests.java diff --git a/samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlActionTestingSupport.java b/samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlActionTestingSupport.java deleted file mode 100644 index bb94c9c78d..0000000000 --- a/samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlActionTestingSupport.java +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed 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 - * - * https://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.springframework.security.saml2.provider.service.authentication; - -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.cert.X509Certificate; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.crypto.SecretKey; - -import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty; -import org.apache.xml.security.algorithms.JCEMapper; -import org.apache.xml.security.encryption.XMLCipherParameters; -import org.joda.time.DateTime; -import org.joda.time.Duration; -import org.junit.Assert; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; -import org.opensaml.profile.action.EventIds; -import org.opensaml.profile.context.EventContext; -import org.opensaml.profile.context.ProfileRequestContext; -import org.opensaml.saml.common.SAMLObjectBuilder; -import org.opensaml.saml.common.SAMLVersion; -import org.opensaml.saml.saml2.core.Artifact; -import org.opensaml.saml.saml2.core.ArtifactResolve; -import org.opensaml.saml.saml2.core.ArtifactResponse; -import org.opensaml.saml.saml2.core.Assertion; -import org.opensaml.saml.saml2.core.AttributeQuery; -import org.opensaml.saml.saml2.core.AttributeStatement; -import org.opensaml.saml.saml2.core.AuthnRequest; -import org.opensaml.saml.saml2.core.AuthnStatement; -import org.opensaml.saml.saml2.core.Conditions; -import org.opensaml.saml.saml2.core.EncryptedAssertion; -import org.opensaml.saml.saml2.core.EncryptedID; -import org.opensaml.saml.saml2.core.Issuer; -import org.opensaml.saml.saml2.core.LogoutRequest; -import org.opensaml.saml.saml2.core.LogoutResponse; -import org.opensaml.saml.saml2.core.NameID; -import org.opensaml.saml.saml2.core.Response; -import org.opensaml.saml.saml2.core.Subject; -import org.opensaml.saml.saml2.core.SubjectConfirmation; -import org.opensaml.saml.saml2.core.SubjectConfirmationData; -import org.opensaml.saml.saml2.encryption.Encrypter; -import org.opensaml.security.credential.BasicCredential; -import org.opensaml.security.credential.Credential; -import org.opensaml.security.credential.CredentialSupport; -import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters; -import org.opensaml.xmlsec.encryption.support.EncryptionException; -import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters; - -import org.springframework.security.saml2.Saml2Exception; -import org.springframework.security.saml2.core.OpenSamlInitializationService; - -import static java.util.Arrays.asList; -import static org.opensaml.security.crypto.KeySupport.generateKey; - -/** - * Copied from OpenSAML Source Code Helper methods for creating/testing SAML 2 - * objects within profile action tests. When methods herein refer to mock objects they are - * always objects that have been created via Mockito unless otherwise noted. - */ -public class OpenSamlActionTestingSupport { - - static { - OpenSamlInitializationService.initialize(); - } - - /** ID used for all generated {@link Response} objects. */ - final static String REQUEST_ID = "request"; - - /** ID used for all generated {@link Response} objects. */ - final static String RESPONSE_ID = "response"; - - /** ID used for all generated {@link Assertion} objects. */ - final static String ASSERTION_ID = "assertion"; - - static EncryptedAssertion encryptAssertion(Assertion assertion, X509Certificate certificate) { - Encrypter encrypter = getEncrypter(certificate); - try { - Encrypter.KeyPlacement keyPlacement = Encrypter.KeyPlacement.valueOf("PEER"); - encrypter.setKeyPlacement(keyPlacement); - return encrypter.encrypt(assertion); - } - catch (EncryptionException e) { - throw new Saml2Exception("Unable to encrypt assertion.", e); - } - } - - static EncryptedID encryptNameId(NameID nameID, X509Certificate certificate) { - Encrypter encrypter = getEncrypter(certificate); - try { - Encrypter.KeyPlacement keyPlacement = Encrypter.KeyPlacement.valueOf("PEER"); - encrypter.setKeyPlacement(keyPlacement); - return encrypter.encrypt(nameID); - } - catch (EncryptionException e) { - throw new Saml2Exception("Unable to encrypt nameID.", e); - } - } - - static Encrypter getEncrypter(X509Certificate certificate) { - Credential credential = CredentialSupport.getSimpleCredential(certificate, null); - final String dataAlgorithm = XMLCipherParameters.AES_256; - final String keyAlgorithm = XMLCipherParameters.RSA_1_5; - SecretKey secretKey = generateKeyFromURI(dataAlgorithm); - BasicCredential dataCredential = new BasicCredential(secretKey); - DataEncryptionParameters dataEncryptionParameters = new DataEncryptionParameters(); - dataEncryptionParameters.setEncryptionCredential(dataCredential); - dataEncryptionParameters.setAlgorithm(dataAlgorithm); - - KeyEncryptionParameters keyEncryptionParameters = new KeyEncryptionParameters(); - keyEncryptionParameters.setEncryptionCredential(credential); - keyEncryptionParameters.setAlgorithm(keyAlgorithm); - - Encrypter encrypter = new Encrypter(dataEncryptionParameters, asList(keyEncryptionParameters)); - - return encrypter; - } - - static SecretKey generateKeyFromURI(String algoURI) { - try { - String jceAlgorithmName = JCEMapper.getJCEKeyAlgorithmFromURI(algoURI); - int keyLength = JCEMapper.getKeyLengthFromURI(algoURI); - return generateKey(jceAlgorithmName, keyLength, null); - } - catch (NoSuchAlgorithmException | NoSuchProviderException e) { - throw new Saml2Exception(e); - } - } - - /** - * Builds an empty response. The ID of the message is {@link #OUTBOUND_MSG_ID}, the - * issue instant is 1970-01-01T00:00:00Z and the SAML version is - * {@link SAMLVersion#VERSION_11}. - * @return the constructed response - */ - @Nonnull - static Response buildResponse() { - final SAMLObjectBuilder responseBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Response.DEFAULT_ELEMENT_NAME); - - final Response response = responseBuilder.buildObject(); - response.setID(OUTBOUND_MSG_ID); - response.setIssueInstant(DateTime.now()); - response.setVersion(SAMLVersion.VERSION_20); - - return response; - } - - /** - * Builds an empty artifact response. The ID of the message is - * {@link #OUTBOUND_MSG_ID}, the issue instant is 1970-01-01T00:00:00Z and the SAML - * version is {@link SAMLVersion#VERSION_11}. - * @return the constructed response - */ - @Nonnull - static ArtifactResponse buildArtifactResponse() { - final SAMLObjectBuilder responseBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(ArtifactResponse.DEFAULT_ELEMENT_NAME); - - final ArtifactResponse response = responseBuilder.buildObject(); - response.setID(OUTBOUND_MSG_ID); - response.setIssueInstant(DateTime.now()); - response.setVersion(SAMLVersion.VERSION_20); - - return response; - } - - /** - * Builds an {@link LogoutRequest}. If a {@link NameID} is given, it will be added to - * the constructed {@link LogoutRequest}. - * @param name the NameID to add to the request - * @return the built request - */ - @Nonnull - static LogoutRequest buildLogoutRequest(final @Nullable NameID name) { - final SAMLObjectBuilder issuerBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Issuer.DEFAULT_ELEMENT_NAME); - - final SAMLObjectBuilder reqBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(LogoutRequest.DEFAULT_ELEMENT_NAME); - - final Issuer issuer = issuerBuilder.buildObject(); - issuer.setValue(INBOUND_MSG_ISSUER); - - final LogoutRequest req = reqBuilder.buildObject(); - req.setID(REQUEST_ID); - req.setIssueInstant(DateTime.now()); - req.setIssuer(issuer); - req.setVersion(SAMLVersion.VERSION_20); - - if (name != null) { - req.setNameID(name); - } - - return req; - } - - /** - * Builds an empty logout response. The ID of the message is {@link #OUTBOUND_MSG_ID}, - * the issue instant is 1970-01-01T00:00:00Z and the SAML version is - * {@link SAMLVersion#VERSION_11}. - * @return the constructed response - */ - @Nonnull - static LogoutResponse buildLogoutResponse() { - final SAMLObjectBuilder responseBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(LogoutResponse.DEFAULT_ELEMENT_NAME); - - final LogoutResponse response = responseBuilder.buildObject(); - response.setID(OUTBOUND_MSG_ID); - response.setIssueInstant(DateTime.now()); - response.setVersion(SAMLVersion.VERSION_20); - - return response; - } - - /** - * Builds an empty assertion. The ID of the message is {@link #ASSERTION_ID}, the - * issue instant is 1970-01-01T00:00:00Z and the SAML version is - * {@link SAMLVersion#VERSION_11}. - * @return the constructed assertion - */ - @Nonnull - static Assertion buildAssertion() { - final SAMLObjectBuilder assertionBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Assertion.DEFAULT_ELEMENT_NAME); - - final Assertion assertion = assertionBuilder.buildObject(); - assertion.setID(ASSERTION_ID); - assertion.setIssueInstant(DateTime.now()); - assertion.setVersion(SAMLVersion.VERSION_20); - - return assertion; - } - - @Nonnull - static SubjectConfirmation buildSubjectConfirmation() { - final SAMLObjectBuilder subjectConfirmation = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(SubjectConfirmation.DEFAULT_ELEMENT_NAME); - - return subjectConfirmation.buildObject(); - } - - /** - * Builds an authentication statement. The authn instant is set to - * 1970-01-01T00:00:00Z. - * @return the constructed statement - */ - @Nonnull - static AuthnStatement buildAuthnStatement() { - final SAMLObjectBuilder statementBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(AuthnStatement.DEFAULT_ELEMENT_NAME); - - final AuthnStatement statement = statementBuilder.buildObject(); - statement.setAuthnInstant(DateTime.now()); - - return statement; - } - - /** - * Builds an empty attribute statement. - * @return the constructed statement - */ - @Nonnull - static AttributeStatement buildAttributeStatement() { - final SAMLObjectBuilder statementBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(AttributeStatement.DEFAULT_ELEMENT_NAME); - - final AttributeStatement statement = statementBuilder.buildObject(); - - return statement; - } - - /** - * Builds a {@link Subject}. If a principal name is given a {@link NameID}, whose - * value is the given principal name, will be created and added to the - * {@link Subject}. - * @param principalName the principal name to add to the subject - * @return the built subject - */ - @Nonnull - static Subject buildSubject(final @Nullable String principalName) { - final SAMLObjectBuilder subjectBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Subject.DEFAULT_ELEMENT_NAME); - final Subject subject = subjectBuilder.buildObject(); - - if (principalName != null) { - subject.setNameID(buildNameID(principalName)); - } - - return subject; - } - - @Nonnull - static SubjectConfirmationData buildSubjectConfirmationData(String localSpEntityId) { - final SAMLObjectBuilder subjectBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory() - .getBuilderOrThrow(SubjectConfirmationData.DEFAULT_ELEMENT_NAME); - final SubjectConfirmationData subject = subjectBuilder.buildObject(); - subject.setRecipient(localSpEntityId); - subject.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000))); - subject.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000))); - return subject; - } - - @Nonnull - static Conditions buildConditions() { - final SAMLObjectBuilder subjectBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Conditions.DEFAULT_ELEMENT_NAME); - final Conditions conditions = subjectBuilder.buildObject(); - conditions.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000))); - conditions.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000))); - return conditions; - } - - /** - * Builds a {@link NameID}. - * @param principalName the principal name to use in the NameID - * @return the built NameID - */ - @Nonnull - static NameID buildNameID(final @Nonnull @NotEmpty String principalName) { - final SAMLObjectBuilder nameIdBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(NameID.DEFAULT_ELEMENT_NAME); - final NameID nameId = nameIdBuilder.buildObject(); - nameId.setValue(principalName); - return nameId; - } - - /** - * Builds a {@link Issuer}. - * @param entityID the entity ID to use in the Issuer - * @return the built Issuer - */ - @Nonnull - static Issuer buildIssuer(final @Nonnull @NotEmpty String entityID) { - final SAMLObjectBuilder issuerBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Issuer.DEFAULT_ELEMENT_NAME); - final Issuer issuer = issuerBuilder.buildObject(); - issuer.setValue(entityID); - return issuer; - } - - /** - * Builds an {@link AttributeQuery}. If a {@link Subject} is given, it will be added - * to the constructed {@link AttributeQuery}. - * @param subject the subject to add to the query - * @return the built query - */ - @Nonnull - static AttributeQuery buildAttributeQueryRequest(final @Nullable Subject subject) { - final SAMLObjectBuilder issuerBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Issuer.DEFAULT_ELEMENT_NAME); - - final SAMLObjectBuilder queryBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(AttributeQuery.DEFAULT_ELEMENT_NAME); - - final Issuer issuer = issuerBuilder.buildObject(); - issuer.setValue(INBOUND_MSG_ISSUER); - - final AttributeQuery query = queryBuilder.buildObject(); - query.setID(REQUEST_ID); - query.setIssueInstant(DateTime.now()); - query.setIssuer(issuer); - query.setVersion(SAMLVersion.VERSION_20); - - if (subject != null) { - query.setSubject(subject); - } - - return query; - } - - /** - * Builds an {@link AuthnRequest}. - * @return the built request - */ - @Nonnull - static AuthnRequest buildAuthnRequest() { - final SAMLObjectBuilder issuerBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Issuer.DEFAULT_ELEMENT_NAME); - - final SAMLObjectBuilder requestBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(AuthnRequest.DEFAULT_ELEMENT_NAME); - - final Issuer issuer = issuerBuilder.buildObject(); - issuer.setValue(INBOUND_MSG_ISSUER); - - final AuthnRequest request = requestBuilder.buildObject(); - request.setID(REQUEST_ID); - request.setIssueInstant(DateTime.now()); - request.setIssuer(issuer); - request.setVersion(SAMLVersion.VERSION_20); - - return request; - } - - /** - * Builds a {@link ArtifactResolve}. - * @param artifact the artifact to add to the request - * @return the built request - */ - @Nonnull - static ArtifactResolve buildArtifactResolve(final @Nullable String artifact) { - final SAMLObjectBuilder requestBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(ArtifactResolve.DEFAULT_ELEMENT_NAME); - final ArtifactResolve request = requestBuilder.buildObject(); - request.setID(REQUEST_ID); - request.setIssueInstant(DateTime.now()); - request.setVersion(SAMLVersion.VERSION_11); - - if (artifact != null) { - final SAMLObjectBuilder artifactBuilder = (SAMLObjectBuilder) XMLObjectProviderRegistrySupport - .getBuilderFactory().getBuilderOrThrow(Artifact.DEFAULT_ELEMENT_NAME); - final Artifact art = artifactBuilder.buildObject(); - art.setArtifact(artifact); - request.setArtifact(art); - } - - return request; - } - - /** ID of the inbound message. */ - public final static String INBOUND_MSG_ID = "inbound"; - - /** Issuer of the inbound message. */ - public final static String INBOUND_MSG_ISSUER = "http://sp.example.org"; - - /** ID of the outbound message. */ - public final static String OUTBOUND_MSG_ID = "outbound"; - - /** Issuer of the outbound message. */ - public final static String OUTBOUND_MSG_ISSUER = "http://idp.example.org"; - - /** - * Checks that the request context contains an EventContext, and that the event - * content is as given. - * @param profileRequestContext the context to check - * @param event event to check - */ - static void assertEvent(@Nonnull final ProfileRequestContext profileRequestContext, - @Nonnull final Object event) { - EventContext ctx = profileRequestContext.getSubcontext(EventContext.class); - Assert.assertNotNull(ctx); - Assert.assertEquals(ctx.getEvent(), event); - } - - /** - * Checks that the given request context does not contain an EventContext (thus - * signaling a "proceed" event). - * @param profileRequestContext the context to check - */ - static void assertProceedEvent(@Nonnull final ProfileRequestContext profileRequestContext) { - EventContext ctx = profileRequestContext.getSubcontext(EventContext.class); - Assert.assertTrue(ctx == null || ctx.getEvent().equals(EventIds.PROCEED_EVENT_ID)); - } - -} diff --git a/samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/Saml2LoginIntegrationTests.java b/samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/Saml2LoginIntegrationTests.java deleted file mode 100644 index 3b6115f459..0000000000 --- a/samples/boot/saml2login/src/integration-test/java/org/springframework/security/saml2/provider/service/authentication/Saml2LoginIntegrationTests.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed 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 - * - * https://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.springframework.security.saml2.provider.service.authentication; - -import java.io.ByteArrayInputStream; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.security.KeyException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.UUID; -import javax.servlet.http.HttpSession; - -import net.shibboleth.utilities.java.support.component.ComponentInitializationException; -import net.shibboleth.utilities.java.support.xml.BasicParserPool; -import net.shibboleth.utilities.java.support.xml.SerializeSupport; -import net.shibboleth.utilities.java.support.xml.XMLParserException; -import org.hamcrest.Matcher; -import org.joda.time.DateTime; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.opensaml.core.xml.XMLObject; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; -import org.opensaml.core.xml.io.MarshallerFactory; -import org.opensaml.core.xml.io.MarshallingException; -import org.opensaml.core.xml.io.UnmarshallingException; -import org.opensaml.saml.common.SignableSAMLObject; -import org.opensaml.saml.saml2.core.Assertion; -import org.opensaml.saml.saml2.core.AuthnRequest; -import org.opensaml.saml.saml2.core.EncryptedAssertion; -import org.opensaml.saml.saml2.core.EncryptedID; -import org.opensaml.saml.saml2.core.Response; -import org.opensaml.saml.saml2.core.SubjectConfirmation; -import org.opensaml.saml.saml2.core.SubjectConfirmationData; -import org.opensaml.security.SecurityException; -import org.opensaml.security.credential.BasicCredential; -import org.opensaml.security.credential.Credential; -import org.opensaml.security.credential.CredentialSupport; -import org.opensaml.security.credential.UsageType; -import org.opensaml.security.crypto.KeySupport; -import org.opensaml.xmlsec.SignatureSigningParameters; -import org.opensaml.xmlsec.signature.support.SignatureConstants; -import org.opensaml.xmlsec.signature.support.SignatureException; -import org.opensaml.xmlsec.signature.support.SignatureSupport; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.util.AssertionErrors; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.ResultMatcher; -import org.springframework.util.MultiValueMap; -import org.springframework.web.util.UriComponentsBuilder; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.matchesRegex; -import static org.hamcrest.Matchers.startsWith; -import static org.springframework.security.saml2.provider.service.authentication.OpenSamlActionTestingSupport.buildConditions; -import static org.springframework.security.saml2.provider.service.authentication.OpenSamlActionTestingSupport.buildIssuer; -import static org.springframework.security.saml2.provider.service.authentication.OpenSamlActionTestingSupport.buildSubject; -import static org.springframework.security.saml2.provider.service.authentication.OpenSamlActionTestingSupport.buildSubjectConfirmation; -import static org.springframework.security.saml2.provider.service.authentication.OpenSamlActionTestingSupport.buildSubjectConfirmationData; -import static org.springframework.security.saml2.provider.service.authentication.OpenSamlActionTestingSupport.encryptNameId; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; -import static org.springframework.security.web.WebAttributes.AUTHENTICATION_EXCEPTION; -import static org.springframework.test.util.AssertionErrors.assertEquals; -import static org.springframework.test.util.AssertionErrors.assertTrue; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class Saml2LoginIntegrationTests { - - static final String LOCAL_SP_ENTITY_ID = "http://localhost:8080/saml2/service-provider-metadata/simplesamlphp"; - static final String USERNAME = "testuser@spring.security.saml"; - - @Autowired - MockMvc mockMvc; - - @SpringBootConfiguration - @EnableAutoConfiguration - public static class SpringBootApplicationTestConfig { - - } - - @Test - public void applicationAccessWhenSingleProviderAndUnauthenticatedThenRedirectsToAuthNRequest() throws Exception { - mockMvc.perform(get("http://localhost:8080/some/url")) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("http://localhost:8080/saml2/authenticate/simplesamlphp")); - } - - @Test - public void authenticateRequestWhenUnauthenticatedThenRespondsWithRedirectAuthNRequestXML() throws Exception { - mockMvc.perform(get("http://localhost:8080/saml2/authenticate/simplesamlphp")) - .andExpect(status().is3xxRedirection()) - .andExpect(header().string("Location", startsWith("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php?SAMLRequest="))); - } - - @Test - public void authenticateRequestWhenRelayStateThenRespondsWithRedirectAndEncodedRelayState() throws Exception { - mockMvc.perform( - get("http://localhost:8080/saml2/authenticate/simplesamlphp") - .param("RelayState", "relay state value with spaces") - .param("OtherParam", "OtherParamValue") - .param("OtherParam2", "OtherParamValue2") - ) - .andExpect(status().is3xxRedirection()) - .andExpect(header().string("Location", startsWith("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php?SAMLRequest="))) - .andExpect(header().string("Location", containsString("RelayState=relay%20state%20value%20with%20spaces"))) - //check order of parameters - .andExpect(header().string("Location", matchesRegex(".*\\?SAMLRequest\\=.*\\&RelayState\\=.*\\&SigAlg\\=.*\\&Signature\\=.*"))); - - } - - @Test - public void authenticateRequestWhenWorkingThenDestinationAttributeIsSet() throws Exception { - final String redirectedUrl = mockMvc.perform(get("http://localhost:8080/saml2/authenticate/simplesamlphp")) - .andExpect(status().is3xxRedirection()) - .andReturn() - .getResponse() - .getRedirectedUrl(); - MultiValueMap parameters = - UriComponentsBuilder.fromUriString(redirectedUrl).build(true).getQueryParams(); - String request = parameters.getFirst("SAMLRequest"); - AssertionErrors.assertNotNull("SAMLRequest parameter is missing", request); - request = URLDecoder.decode(request); - request = Saml2Utils.samlInflate(Saml2Utils.samlDecode(request)); - AuthnRequest authnRequest = (AuthnRequest) fromXml(request); - String destination = authnRequest.getDestination(); - assertEquals( - "Destination must match", - "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php", - destination - ); - String acsURL = authnRequest.getAssertionConsumerServiceURL(); - assertEquals( - "AssertionConsumerServiceURL must match", - "http://localhost:8080/login/saml2/sso/simplesamlphp", - acsURL - ); - - } - - - @Test - public void authenticateWhenResponseIsSignedThenItSucceeds() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - Response response = buildResponse(assertion); - signXmlObject(response, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/") - .andExpect(authenticated().withUsername(USERNAME)); - } - - @Test - public void authenticateWhenAssertionIsThenItSignedSucceeds() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - Response response = buildResponse(assertion); - signXmlObject(assertion, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/") - .andExpect(authenticated().withUsername(USERNAME)); - } - - @Test - public void authenticateWhenXmlObjectIsNotSignedThenItFails() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - Response response = buildResponse(assertion); - sendResponse(response, "/login?error") - .andExpect(unauthenticated()); - } - - @Test - public void authenticateWhenResponseIsSignedAndAssertionIsEncryptedThenItSucceeds() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - EncryptedAssertion encryptedAssertion = - OpenSamlActionTestingSupport.encryptAssertion(assertion, decodeCertificate(spCertificate)); - Response response = buildResponse(encryptedAssertion); - signXmlObject(response, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/") - .andExpect(authenticated().withUsername(USERNAME)); - } - - @Test - public void authenticateWhenResponseIsNotSignedAndAssertionIsEncryptedAndSignedThenItSucceeds() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - signXmlObject(assertion, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - EncryptedAssertion encryptedAssertion = - OpenSamlActionTestingSupport.encryptAssertion(assertion, decodeCertificate(spCertificate)); - Response response = buildResponse(encryptedAssertion); - sendResponse(response, "/") - .andExpect(authenticated().withUsername(USERNAME)); - } - - @Test - public void authenticateWhenResponseIsSignedAndNameIDisEncryptedThenItSucceeds() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - final EncryptedID nameId = encryptNameId(assertion.getSubject().getNameID(), decodeCertificate(spCertificate)); - assertion.getSubject().setEncryptedID(nameId); - assertion.getSubject().setNameID(null); - Response response = buildResponse(assertion); - signXmlObject(assertion, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/") - .andExpect(authenticated().withUsername(USERNAME)); - } - - @Test - public void authenticateWhenSignatureKeysDontMatchThenItFails() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - Response response = buildResponse(assertion); - signXmlObject(assertion, getSigningCredential(spCertificate, spPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/login?error") - .andExpect( - saml2AuthenticationExceptionMatcher( - "invalid_signature", - containsString("Invalid assertion [assertion] for SAML response") - ) - ); - } - - @Test - public void authenticateWhenNotOnOrAfterDontMatchThenItFails() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - assertion.getConditions().setNotOnOrAfter(DateTime.now().minusDays(1)); - Response response = buildResponse(assertion); - signXmlObject(assertion, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/login?error") - .andExpect( - saml2AuthenticationExceptionMatcher( - "invalid_assertion", - containsString("Invalid assertion [assertion] for SAML response") - ) - ); - } - - @Test - public void authenticateWhenNotOnOrBeforeDontMatchThenItFails() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - assertion.getConditions().setNotBefore(DateTime.now().plusDays(1)); - Response response = buildResponse(assertion); - signXmlObject(assertion, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/login?error") - .andExpect( - saml2AuthenticationExceptionMatcher( - "invalid_assertion", - containsString("Invalid assertion [assertion] for SAML response") - ) - ); - } - - @Test - public void authenticateWhenIssuerIsInvalidThenItFails() throws Exception { - Assertion assertion = buildAssertion(USERNAME); - Response response = buildResponse(assertion); - response.getIssuer().setValue("invalid issuer"); - signXmlObject(response, getSigningCredential(idpCertificate, idpPrivateKey, UsageType.SIGNING)); - sendResponse(response, "/login?error") - .andExpect(unauthenticated()) - .andExpect( - saml2AuthenticationExceptionMatcher( - "invalid_signature", - containsString( - "Invalid signature" - ) - ) - ); - } - - private ResultActions sendResponse( - Response response, - String redirectUrl) throws Exception { - String xml = toXml(response); - return mockMvc.perform(post("http://localhost:8080/login/saml2/sso/simplesamlphp") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param("SAMLResponse", Saml2Utils.samlEncode(xml.getBytes(UTF_8)))) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl(redirectUrl)); - } - - private Response buildResponse(Assertion assertion) { - Response response = buildResponse(); - response.getAssertions().add(assertion); - return response; - } - - private Response buildResponse(EncryptedAssertion assertion) { - Response response = buildResponse(); - response.getEncryptedAssertions().add(assertion); - return response; - } - - private Response buildResponse() { - Response response = OpenSamlActionTestingSupport.buildResponse(); - response.setID("_" + UUID.randomUUID().toString()); - response.setDestination("http://localhost:8080/login/saml2/sso/simplesamlphp"); - response.setIssuer(buildIssuer("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php")); - return response; - } - - private Assertion buildAssertion(String username) { - Assertion assertion = OpenSamlActionTestingSupport.buildAssertion(); - assertion.setIssueInstant(DateTime.now()); - assertion.setIssuer(buildIssuer("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php")); - assertion.setSubject(buildSubject(username)); - assertion.setConditions(buildConditions()); - - SubjectConfirmation subjectConfirmation = buildSubjectConfirmation(); - - // Default to bearer with basic valid confirmation data, but the test can change - // as appropriate - subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER); - final SubjectConfirmationData confirmationData = buildSubjectConfirmationData(LOCAL_SP_ENTITY_ID); - confirmationData.setRecipient("http://localhost:8080/login/saml2/sso/simplesamlphp"); - subjectConfirmation.setSubjectConfirmationData(confirmationData); - assertion.getSubject().getSubjectConfirmations().add(subjectConfirmation); - return assertion; - } - - protected Credential getSigningCredential(String certificate, String key, UsageType usageType) - throws CertificateException, KeyException { - PublicKey publicKey = decodeCertificate(certificate).getPublicKey(); - final PrivateKey privateKey = KeySupport.decodePrivateKey(key.getBytes(UTF_8), new char[0]); - BasicCredential cred = CredentialSupport.getSimpleCredential(publicKey, privateKey); - cred.setUsageType(usageType); - cred.setEntityId("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php"); - return cred; - } - - private void signXmlObject(SignableSAMLObject object, Credential credential) - throws MarshallingException, SecurityException, SignatureException { - SignatureSigningParameters parameters = new SignatureSigningParameters(); - parameters.setSigningCredential(credential); - parameters.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); - parameters.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256); - parameters.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); - SignatureSupport.signObject(object, parameters); - } - - private String toXml(XMLObject object) throws MarshallingException { - final MarshallerFactory marshallerFactory = XMLObjectProviderRegistrySupport.getMarshallerFactory(); - Element element = marshallerFactory.getMarshaller(object).marshall(object); - return SerializeSupport.nodeToString(element); - } - - private XMLObject fromXml(String xml) - throws XMLParserException, UnmarshallingException, ComponentInitializationException { - BasicParserPool parserPool = new BasicParserPool(); - parserPool.initialize(); - Document document = parserPool.parse(new ByteArrayInputStream(xml.getBytes(UTF_8))); - Element element = document.getDocumentElement(); - return XMLObjectProviderRegistrySupport.getUnmarshallerFactory().getUnmarshaller(element).unmarshall(element); - - } - - private X509Certificate decodeCertificate(String source) { - try { - final CertificateFactory factory = CertificateFactory.getInstance("X.509"); - return (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)) - ); - } catch (Exception e) { - throw new IllegalArgumentException(e); - } - } - - private String idpCertificate = "-----BEGIN CERTIFICATE-----\n" - + "MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\n" - + "VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\n" - + "VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX\n" - + "c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw\n" - + "aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ\n" - + "BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa\n" - + "BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD\n" - + "DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr\n" - + "QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62\n" - + "E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz\n" - + "2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW\n" - + "RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ\n" - + "nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5\n" - + "cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph\n" - + "iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5\n" - + "ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD\n" - + "AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO\n" - + "nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v\n" - + "ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\n" - + "xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\n" - + "V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\n" - + "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n" + "-----END CERTIFICATE-----\n"; - - private String idpPrivateKey = "-----BEGIN PRIVATE KEY-----\n" - + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4cn62E1xLqpN3\n" - + "4PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZX\n" - + "W+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHE\n" - + "fDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7h\n" - + "Z6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/T\n" - + "Xy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7\n" - + "I+J5lS8VAgMBAAECggEBAKyxBlIS7mcp3chvq0RF7B3PHFJMMzkwE+t3pLJcs4cZ\n" - + "nezh/KbREfP70QjXzk/llnZCvxeIs5vRu24vbdBm79qLHqBuHp8XfHHtuo2AfoAQ\n" - + "l4h047Xc/+TKMivnPQ0jX9qqndKDLqZDf5wnbslDmlskvF0a/MjsLU0TxtOfo+dB\n" - + "t55FW11cGqxZwhS5Gnr+cbw3OkHz23b9gEOt9qfwPVepeysbmm9FjU+k4yVa7rAN\n" - + "xcbzVb6Y7GCITe2tgvvEHmjB9BLmWrH3mZ3Af17YU/iN6TrpPd6Sj3QoS+2wGtAe\n" - + "HbUs3CKJu7bIHcj4poal6Kh8519S+erJTtqQ8M0ZiEECgYEA43hLYAPaUueFkdfh\n" - + "9K/7ClH6436CUH3VdizwUXi26fdhhV/I/ot6zLfU2mgEHU22LBECWQGtAFm8kv0P\n" - + "zPn+qjaR3e62l5PIlSYbnkIidzoDZ2ztu4jF5LgStlTJQPteFEGgZVl5o9DaSZOq\n" - + "Yd7G3XqXuQ1VGMW58G5FYJPtA1cCgYEAz5TPUtK+R2KXHMjUwlGY9AefQYRYmyX2\n" - + "Tn/OFgKvY8lpAkMrhPKONq7SMYc8E9v9G7A0dIOXvW7QOYSapNhKU+np3lUafR5F\n" - + "4ZN0bxZ9qjHbn3AMYeraKjeutHvlLtbHdIc1j3sxe/EzltRsYmiqLdEBW0p6hwWg\n" - + "tyGhYWVyaXMCgYAfDOKtHpmEy5nOCLwNXKBWDk7DExfSyPqEgSnk1SeS1HP5ctPK\n" - + "+1st6sIhdiVpopwFc+TwJWxqKdW18tlfT5jVv1E2DEnccw3kXilS9xAhWkfwrEvf\n" - + "V5I74GydewFl32o+NZ8hdo9GL1I8zO1rIq/et8dSOWGuWf9BtKu/vTGTTQKBgFxU\n" - + "VjsCnbvmsEwPUAL2hE/WrBFaKocnxXx5AFNt8lEyHtDwy4Sg1nygGcIJ4sD6koQk\n" - + "RdClT3LkvR04TAiSY80bN/i6ZcPNGUwSaDGZEWAIOSWbkwZijZNFnSGOEgxZX/IG\n" - + "yd39766vREEMTwEeiMNEOZQ/dmxkJm4OOVe25cLdAoGACOtPnq1Fxay80UYBf4rQ\n" - + "+bJ9yX1ulB8WIree1hD7OHSB2lRHxrVYWrglrTvkh63Lgx+EcsTV788OsvAVfPPz\n" - + "BZrn8SdDlQqalMxUBYEFwnsYD3cQ8yOUnijFVC4xNcdDv8OIqVgSk4KKxU5AshaA\n" + "xk6Mox+u8Cc2eAK12H13i+8=\n" - + "-----END PRIVATE KEY-----\n"; - - private String spCertificate = "-----BEGIN CERTIFICATE-----\n" + - "MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n" + - "VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n" + - "A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n" + - "DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n" + - "MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n" + - "MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n" + - "TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n" + - "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n" + - "vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n" + - "+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n" + - "y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n" + - "XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n" + - "qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n" + - "RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" + - "-----END CERTIFICATE-----"; - - private String spPrivateKey = "-----BEGIN PRIVATE KEY-----\n" + - "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n" + - "VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n" + - "cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n" + - "Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n" + - "x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n" + - "wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n" + - "vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n" + - "8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n" + - "oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n" + - "EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n" + - "KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n" + - "YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n" + - "9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" + - "INrtuLp4YHbgk1mi\n" + - "-----END PRIVATE KEY-----"; - - private static ResultMatcher saml2AuthenticationExceptionMatcher( - String code, - Matcher message - ) { - return (result) -> { - final HttpSession session = result.getRequest().getSession(false); - AssertionErrors.assertNotNull("HttpSession", session); - Object exception = session.getAttribute(AUTHENTICATION_EXCEPTION); - AssertionErrors.assertNotNull(AUTHENTICATION_EXCEPTION, exception); - if (!(exception instanceof Saml2AuthenticationException)) { - AssertionErrors.fail( - "Invalid exception type", - Saml2AuthenticationException.class, - exception.getClass().getName() - ); - } - Saml2AuthenticationException se = (Saml2AuthenticationException) exception; - assertEquals("SAML 2 Error Code", code, se.getError().getErrorCode()); - assertTrue("SAML 2 Error Description", message.matches(se.getError().getDescription())); - }; - } -} diff --git a/samples/javaconfig/saml2login/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java b/samples/javaconfig/saml2login/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java index 8a416b95c1..0e2bdba1d5 100644 --- a/samples/javaconfig/saml2login/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java +++ b/samples/javaconfig/saml2login/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java @@ -16,50 +16,17 @@ package org.springframework.security.samples.config; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter; -import org.springframework.security.web.FilterChainProxy; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.util.ReflectionTestUtils; - -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.Arrays; -import java.util.List; -import javax.servlet.Filter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SecurityConfig.class) public class SecurityConfigTests { - @Autowired - ApplicationContext context; - @Test public void securityConfigurationLoads() { } - - @Test - public void filterWhenLoginProcessingUrlIsSetInJavaConfigThenTheFilterHasIt() { - FilterChainProxy filterChain = context.getBean(FilterChainProxy.class); - Assert.assertNotNull(filterChain); - final List filters = filterChain.getFilters("/sample/jc/saml2/sso/test-id"); - Assert.assertNotNull(filters); - Saml2WebSsoAuthenticationFilter filter = (Saml2WebSsoAuthenticationFilter) filters - .stream() - .filter( - (f) -> f instanceof Saml2WebSsoAuthenticationFilter - ) - .findFirst() - .get(); - for (String field : Arrays.asList("requiresAuthenticationRequestMatcher")) { - final Object matcher = ReflectionTestUtils.getField(filter, field); - final Object pattern = ReflectionTestUtils.getField(matcher, "pattern"); - Assert.assertEquals("loginProcessingUrl mismatch", "/sample/jc/saml2/sso/{registrationId}", pattern); - } - } }