|
15 | 15 | */
|
16 | 16 | package org.springframework.security.samples;
|
17 | 17 |
|
18 |
| -import org.springframework.beans.factory.annotation.Autowired; |
19 |
| -import org.springframework.boot.SpringBootConfiguration; |
20 |
| -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
21 |
| -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
22 |
| -import org.springframework.boot.test.context.SpringBootTest; |
23 |
| -import org.springframework.context.annotation.ComponentScan; |
24 |
| -import org.springframework.http.MediaType; |
25 |
| -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; |
26 |
| -import org.springframework.test.context.junit4.SpringRunner; |
27 |
| -import org.springframework.test.util.AssertionErrors; |
28 |
| -import org.springframework.test.web.servlet.MockMvc; |
29 |
| -import org.springframework.test.web.servlet.ResultActions; |
30 |
| -import org.springframework.test.web.servlet.ResultMatcher; |
31 |
| - |
| 18 | +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; |
| 19 | +import net.shibboleth.utilities.java.support.xml.BasicParserPool; |
32 | 20 | import net.shibboleth.utilities.java.support.xml.SerializeSupport;
|
| 21 | +import net.shibboleth.utilities.java.support.xml.XMLParserException; |
33 | 22 | import org.hamcrest.Matcher;
|
34 | 23 | import org.joda.time.DateTime;
|
35 | 24 | import org.junit.Test;
|
|
38 | 27 | import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
|
39 | 28 | import org.opensaml.core.xml.io.MarshallerFactory;
|
40 | 29 | import org.opensaml.core.xml.io.MarshallingException;
|
| 30 | +import org.opensaml.core.xml.io.UnmarshallingException; |
41 | 31 | import org.opensaml.saml.common.SignableSAMLObject;
|
42 | 32 | import org.opensaml.saml.saml2.core.Assertion;
|
| 33 | +import org.opensaml.saml.saml2.core.AuthnRequest; |
43 | 34 | import org.opensaml.saml.saml2.core.EncryptedAssertion;
|
44 | 35 | import org.opensaml.saml.saml2.core.EncryptedID;
|
45 | 36 | import org.opensaml.saml.saml2.core.Response;
|
|
55 | 46 | import org.opensaml.xmlsec.signature.support.SignatureConstants;
|
56 | 47 | import org.opensaml.xmlsec.signature.support.SignatureException;
|
57 | 48 | import org.opensaml.xmlsec.signature.support.SignatureSupport;
|
| 49 | +import org.springframework.beans.factory.annotation.Autowired; |
| 50 | +import org.springframework.boot.SpringBootConfiguration; |
| 51 | +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
| 52 | +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
| 53 | +import org.springframework.boot.test.context.SpringBootTest; |
| 54 | +import org.springframework.context.annotation.ComponentScan; |
| 55 | +import org.springframework.http.MediaType; |
| 56 | +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; |
| 57 | +import org.springframework.test.context.junit4.SpringRunner; |
| 58 | +import org.springframework.test.util.AssertionErrors; |
| 59 | +import org.springframework.test.web.servlet.MockMvc; |
| 60 | +import org.springframework.test.web.servlet.ResultActions; |
| 61 | +import org.springframework.test.web.servlet.ResultMatcher; |
| 62 | +import org.springframework.util.MultiValueMap; |
| 63 | +import org.springframework.web.util.UriComponentsBuilder; |
| 64 | +import org.w3c.dom.Document; |
58 | 65 | import org.w3c.dom.Element;
|
59 | 66 |
|
60 | 67 | import java.io.ByteArrayInputStream;
|
| 68 | +import java.net.URLDecoder; |
61 | 69 | import java.nio.charset.StandardCharsets;
|
62 | 70 | import java.security.KeyException;
|
63 | 71 | import java.security.PrivateKey;
|
|
78 | 86 | import static org.springframework.security.samples.OpenSamlActionTestingSupport.buildSubjectConfirmation;
|
79 | 87 | import static org.springframework.security.samples.OpenSamlActionTestingSupport.buildSubjectConfirmationData;
|
80 | 88 | import static org.springframework.security.samples.OpenSamlActionTestingSupport.encryptNameId;
|
| 89 | +import static org.springframework.security.samples.OpenSamlActionTestingSupport.inflate; |
81 | 90 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
82 | 91 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
|
83 | 92 | import static org.springframework.security.web.WebAttributes.AUTHENTICATION_EXCEPTION;
|
@@ -131,6 +140,29 @@ public void authenticateRequestWhenRelayStateThenRespondsWithRedirectAndEncodedR
|
131 | 140 | .andExpect(header().string("Location", containsString("RelayState=relay%20state%20value%20with%20spaces")));
|
132 | 141 | }
|
133 | 142 |
|
| 143 | + @Test |
| 144 | + public void authenticateRequestWhenWorkingThenDestinationAttributeIsSet() throws Exception { |
| 145 | + final String redirectedUrl = mockMvc.perform(get("http://localhost:8080/saml2/authenticate/simplesamlphp")) |
| 146 | + .andExpect(status().is3xxRedirection()) |
| 147 | + .andReturn() |
| 148 | + .getResponse() |
| 149 | + .getRedirectedUrl(); |
| 150 | + MultiValueMap<String, String> parameters = |
| 151 | + UriComponentsBuilder.fromUriString(redirectedUrl).build(true).getQueryParams(); |
| 152 | + String request = parameters.getFirst("SAMLRequest"); |
| 153 | + AssertionErrors.assertNotNull("SAMLRequest parameter is missing", request); |
| 154 | + request = URLDecoder.decode(request); |
| 155 | + request = inflate(OpenSamlActionTestingSupport.decode(request)); |
| 156 | + AuthnRequest authnRequest = (AuthnRequest) fromXml(request); |
| 157 | + String destination = authnRequest.getDestination(); |
| 158 | + assertEquals( |
| 159 | + "Destination must match", |
| 160 | + "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php", |
| 161 | + destination |
| 162 | + ); |
| 163 | + } |
| 164 | + |
| 165 | + |
134 | 166 | @Test
|
135 | 167 | public void authenticateWhenResponseIsSignedThenItSucceeds() throws Exception {
|
136 | 168 | Assertion assertion = buildAssertion(USERNAME);
|
@@ -248,7 +280,7 @@ public void authenticateWhenIssuerIsInvalidThenItFails() throws Exception {
|
248 | 280 | "invalid_issuer",
|
249 | 281 | containsString(
|
250 | 282 | "Response issuer 'invalid issuer' doesn't match "+
|
251 |
| - "'https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php'" |
| 283 | + "'https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php'" |
252 | 284 | )
|
253 | 285 | )
|
254 | 286 | );
|
@@ -330,6 +362,16 @@ private String toXml(XMLObject object) throws MarshallingException {
|
330 | 362 | return SerializeSupport.nodeToString(element);
|
331 | 363 | }
|
332 | 364 |
|
| 365 | + private XMLObject fromXml(String xml) |
| 366 | + throws XMLParserException, UnmarshallingException, ComponentInitializationException { |
| 367 | + BasicParserPool parserPool = new BasicParserPool(); |
| 368 | + parserPool.initialize(); |
| 369 | + Document document = parserPool.parse(new ByteArrayInputStream(xml.getBytes(UTF_8))); |
| 370 | + Element element = document.getDocumentElement(); |
| 371 | + return XMLObjectProviderRegistrySupport.getUnmarshallerFactory().getUnmarshaller(element).unmarshall(element); |
| 372 | + |
| 373 | + } |
| 374 | + |
333 | 375 | private X509Certificate decodeCertificate(String source) {
|
334 | 376 | try {
|
335 | 377 | final CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
|
0 commit comments