Browse Source

Support No SingleLogoutServiceLocation

Closes gh-10674
pull/10808/head
Josh Cummings 4 years ago
parent
commit
c664fbc1a3
  1. 4
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolver.java
  2. 2
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.java
  3. 3
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestResolver.java
  4. 3
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutResponseResolver.java
  5. 6
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java
  6. 6
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseFilter.java
  7. 4
      saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolverTests.java
  8. 5
      saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolverTests.java
  9. 4
      saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolverTests.java
  10. 5
      saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java
  11. 9
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolverTests.java
  12. 16
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilterTests.java
  13. 20
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseFilterTests.java

4
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolver.java

@ -86,7 +86,9 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver { @@ -86,7 +86,9 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver {
spSsoDescriptor.getKeyDescriptors()
.addAll(buildKeys(registration.getDecryptionX509Credentials(), UsageType.ENCRYPTION));
spSsoDescriptor.getAssertionConsumerServices().add(buildAssertionConsumerService(registration));
spSsoDescriptor.getSingleLogoutServices().add(buildSingleLogoutService(registration));
if (registration.getSingleLogoutServiceLocation() != null) {
spSsoDescriptor.getSingleLogoutServices().add(buildSingleLogoutService(registration));
}
return spSsoDescriptor;
}

2
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.java

@ -106,6 +106,8 @@ public final class RelyingPartyRegistration { @@ -106,6 +106,8 @@ public final class RelyingPartyRegistration {
Assert.hasText(entityId, "entityId cannot be empty");
Assert.hasText(assertionConsumerServiceLocation, "assertionConsumerServiceLocation cannot be empty");
Assert.notNull(assertionConsumerServiceBinding, "assertionConsumerServiceBinding cannot be null");
Assert.isTrue(singleLogoutServiceLocation == null || singleLogoutServiceBinding != null,
"singleLogoutServiceBinding cannot be null when singleLogoutServiceLocation is set");
Assert.notNull(providerDetails, "providerDetails cannot be null");
Assert.notEmpty(credentials, "credentials cannot be empty");
for (org.springframework.security.saml2.credentials.Saml2X509Credential c : credentials) {

3
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestResolver.java

@ -111,6 +111,9 @@ final class OpenSamlLogoutRequestResolver { @@ -111,6 +111,9 @@ final class OpenSamlLogoutRequestResolver {
if (registration == null) {
return null;
}
if (registration.getAssertingPartyDetails().getSingleLogoutServiceLocation() == null) {
return null;
}
LogoutRequest logoutRequest = this.logoutRequestBuilder.buildObject();
logoutRequest.setDestination(registration.getAssertingPartyDetails().getSingleLogoutServiceLocation());
Issuer issuer = this.issuerBuilder.buildObject();

3
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutResponseResolver.java

@ -132,6 +132,9 @@ final class OpenSamlLogoutResponseResolver { @@ -132,6 +132,9 @@ final class OpenSamlLogoutResponseResolver {
if (registration == null) {
return null;
}
if (registration.getAssertingPartyDetails().getSingleLogoutServiceResponseLocation() == null) {
return null;
}
String serialized = request.getParameter(Saml2ParameterNames.SAML_REQUEST);
byte[] b = Saml2Utils.samlDecode(serialized);
LogoutRequest logoutRequest = parse(inflateIfRequired(registration, b));

6
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java

@ -120,6 +120,12 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter { @@ -120,6 +120,12 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
if (registration.getSingleLogoutServiceLocation() == null) {
this.logger.trace(
"Did not process logout request since RelyingPartyRegistration has not been configured with a logout request endpoint");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
if (!isCorrectBinding(request, registration)) {
this.logger.trace("Did not process logout request since used incorrect binding");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);

6
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseFilter.java

@ -120,6 +120,12 @@ public final class Saml2LogoutResponseFilter extends OncePerRequestFilter { @@ -120,6 +120,12 @@ public final class Saml2LogoutResponseFilter extends OncePerRequestFilter {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, error.toString());
return;
}
if (registration.getSingleLogoutServiceResponseLocation() == null) {
this.logger.trace(
"Did not process logout response since RelyingPartyRegistration has not been configured with a logout response endpoint");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
if (!isCorrectBinding(request, registration)) {
this.logger.trace("Did not process logout request since used incorrect binding");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);

4
saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolverTests.java

@ -47,7 +47,9 @@ public class OpenSaml3LogoutRequestResolverTests { @@ -47,7 +47,9 @@ public class OpenSaml3LogoutRequestResolverTests {
this.relyingPartyRegistrationResolver);
logoutRequestResolver.setParametersConsumer((parameters) -> parameters.getLogoutRequest().setID("myid"));
HttpServletRequest request = new MockHttpServletRequest();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration().build();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration()
.assertingPartyDetails((party) -> party.singleLogoutServiceLocation("https://ap.example.com/logout"))
.build();
Authentication authentication = new TestingAuthenticationToken("user", "password");
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
Saml2LogoutRequest logoutRequest = logoutRequestResolver.resolve(request, authentication);

5
saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolverTests.java

@ -53,7 +53,10 @@ public class OpenSaml3LogoutResponseResolverTests { @@ -53,7 +53,10 @@ public class OpenSaml3LogoutResponseResolverTests {
Consumer<LogoutResponseParameters> parametersConsumer = mock(Consumer.class);
logoutResponseResolver.setParametersConsumer(parametersConsumer);
MockHttpServletRequest request = new MockHttpServletRequest();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration().build();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration()
.assertingPartyDetails(
(party) -> party.singleLogoutServiceResponseLocation("https://ap.example.com/logout"))
.build();
Authentication authentication = new TestingAuthenticationToken("user", "password");
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
request.setParameter(Saml2ParameterNames.SAML_REQUEST,

4
saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolverTests.java

@ -47,7 +47,9 @@ public class OpenSaml4LogoutRequestResolverTests { @@ -47,7 +47,9 @@ public class OpenSaml4LogoutRequestResolverTests {
this.relyingPartyRegistrationResolver);
logoutRequestResolver.setParametersConsumer((parameters) -> parameters.getLogoutRequest().setID("myid"));
HttpServletRequest request = new MockHttpServletRequest();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration().build();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration()
.assertingPartyDetails((party) -> party.singleLogoutServiceLocation("https://ap.example.com/logout"))
.build();
Authentication authentication = new TestingAuthenticationToken("user", "password");
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
Saml2LogoutRequest logoutRequest = logoutRequestResolver.resolve(request, authentication);

5
saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java

@ -53,7 +53,10 @@ public class OpenSaml4LogoutResponseResolverTests { @@ -53,7 +53,10 @@ public class OpenSaml4LogoutResponseResolverTests {
Consumer<LogoutResponseParameters> parametersConsumer = mock(Consumer.class);
logoutResponseResolver.setParametersConsumer(parametersConsumer);
MockHttpServletRequest request = new MockHttpServletRequest();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration().build();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration()
.assertingPartyDetails(
(party) -> party.singleLogoutServiceResponseLocation("https://ap.example.com/logout"))
.build();
Authentication authentication = new TestingAuthenticationToken("user", "password");
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
request.setParameter(Saml2ParameterNames.SAML_REQUEST,

9
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolverTests.java

@ -61,4 +61,13 @@ public class OpenSamlMetadataResolverTests { @@ -61,4 +61,13 @@ public class OpenSamlMetadataResolverTests {
.contains("ResponseLocation=\"https://rp.example.org/logout/saml2/response\"");
}
@Test
public void resolveWhenRelyingPartyNoLogoutThenMetadataMatches() {
RelyingPartyRegistration relyingPartyRegistration = TestRelyingPartyRegistrations.full()
.singleLogoutServiceLocation(null).build();
OpenSamlMetadataResolver openSamlMetadataResolver = new OpenSamlMetadataResolver();
String metadata = openSamlMetadataResolver.resolve(relyingPartyRegistration);
assertThat(metadata).doesNotContain("ResponseLocation");
}
}

16
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilterTests.java

@ -153,4 +153,20 @@ public class Saml2LogoutRequestFilterTests { @@ -153,4 +153,20 @@ public class Saml2LogoutRequestFilterTests {
verifyNoInteractions(this.logoutHandler);
}
@Test
public void doFilterWhenNoRelyingPartyLogoutThen401() throws Exception {
Authentication authentication = new TestingAuthenticationToken("user", "password");
SecurityContextHolder.getContext().setAuthentication(authentication);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/logout/saml2/slo");
request.setServletPath("/logout/saml2/slo");
request.setParameter(Saml2ParameterNames.SAML_REQUEST, "request");
MockHttpServletResponse response = new MockHttpServletResponse();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.full().singleLogoutServiceLocation(null)
.build();
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
this.logoutRequestProcessingFilter.doFilterInternal(request, response, new MockFilterChain());
assertThat(response.getStatus()).isEqualTo(401);
verifyNoInteractions(this.logoutHandler);
}
}

20
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseFilterTests.java

@ -37,6 +37,7 @@ import org.springframework.security.saml2.provider.service.registration.TestRely @@ -37,6 +37,7 @@ import org.springframework.security.saml2.provider.service.registration.TestRely
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.mock;
@ -151,4 +152,23 @@ public class Saml2LogoutResponseFilterTests { @@ -151,4 +152,23 @@ public class Saml2LogoutResponseFilterTests {
verifyNoInteractions(this.logoutSuccessHandler);
}
@Test
public void doFilterWhenNoRelyingPartyLogoutThen401() throws Exception {
Authentication authentication = new TestingAuthenticationToken("user", "password");
SecurityContextHolder.getContext().setAuthentication(authentication);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/logout/saml2/slo");
request.setServletPath("/logout/saml2/slo");
request.setParameter(Saml2ParameterNames.SAML_RESPONSE, "response");
MockHttpServletResponse response = new MockHttpServletResponse();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.full().singleLogoutServiceLocation(null)
.singleLogoutServiceResponseLocation(null).build();
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration)
.samlRequest("request").build();
given(this.logoutRequestRepository.removeLogoutRequest(request, response)).willReturn(logoutRequest);
this.logoutResponseProcessingFilter.doFilterInternal(request, response, new MockFilterChain());
assertThat(response.getStatus()).isEqualTo(401);
verifyNoInteractions(this.logoutSuccessHandler);
}
}

Loading…
Cancel
Save