diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/servlet/filter/Saml2WebSsoAuthenticationRequestFilter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/servlet/filter/Saml2WebSsoAuthenticationRequestFilter.java index f8357cd9a3..b68ec7b3fd 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/servlet/filter/Saml2WebSsoAuthenticationRequestFilter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/servlet/filter/Saml2WebSsoAuthenticationRequestFilter.java @@ -107,12 +107,7 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter String localSpEntityId = Saml2Utils.getServiceProviderEntityId(relyingParty, request); return new Saml2AuthenticationRequest( localSpEntityId, - Saml2Utils.resolveUrlTemplate( - relyingParty.getAssertionConsumerServiceUrlTemplate(), - Saml2Utils.getApplicationUri(request), - relyingParty.getRemoteIdpEntityId(), - relyingParty.getRegistrationId() - ), + relyingParty.getIdpWebSsoUrl(), relyingParty.getSigningCredentials() ); } diff --git a/samples/boot/saml2login/src/integration-test/java/org/springframework/security/samples/Saml2LoginIntegrationTests.java b/samples/boot/saml2login/src/integration-test/java/org/springframework/security/samples/Saml2LoginIntegrationTests.java index 091f4bb197..ce6b0a3d6c 100644 --- a/samples/boot/saml2login/src/integration-test/java/org/springframework/security/samples/Saml2LoginIntegrationTests.java +++ b/samples/boot/saml2login/src/integration-test/java/org/springframework/security/samples/Saml2LoginIntegrationTests.java @@ -15,21 +15,10 @@ */ package org.springframework.security.samples; -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.context.annotation.ComponentScan; -import org.springframework.http.MediaType; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; -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 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; @@ -38,8 +27,10 @@ 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; @@ -55,9 +46,26 @@ 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.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.context.annotation.ComponentScan; +import org.springframework.http.MediaType; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +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 org.w3c.dom.Document; import org.w3c.dom.Element; import java.io.ByteArrayInputStream; +import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.security.KeyException; import java.security.PrivateKey; @@ -78,6 +86,7 @@ import static org.springframework.security.samples.OpenSamlActionTestingSupport. import static org.springframework.security.samples.OpenSamlActionTestingSupport.buildSubjectConfirmation; import static org.springframework.security.samples.OpenSamlActionTestingSupport.buildSubjectConfirmationData; import static org.springframework.security.samples.OpenSamlActionTestingSupport.encryptNameId; +import static org.springframework.security.samples.OpenSamlActionTestingSupport.inflate; 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; @@ -131,6 +140,29 @@ public class Saml2LoginIntegrationTests { .andExpect(header().string("Location", containsString("RelayState=relay%20state%20value%20with%20spaces"))); } + @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 = inflate(OpenSamlActionTestingSupport.decode(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 + ); + } + + @Test public void authenticateWhenResponseIsSignedThenItSucceeds() throws Exception { Assertion assertion = buildAssertion(USERNAME); @@ -248,7 +280,7 @@ public class Saml2LoginIntegrationTests { "invalid_issuer", containsString( "Response issuer 'invalid issuer' doesn't match "+ - "'https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php'" + "'https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php'" ) ) ); @@ -330,6 +362,16 @@ public class Saml2LoginIntegrationTests { 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");