Correctly set "Destination" in AuthNRequest message

Fixes gh-7494
https://github.com/spring-projects/spring-security/issues/7494
This commit is contained in:
Filip Hanik 2019-09-30 09:42:52 -07:00
parent 69eacac514
commit 9731386de5
2 changed files with 58 additions and 21 deletions

View File

@ -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()
);
}

View File

@ -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<String, String> 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");