mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-01 09:42:13 +00:00
Support No SingleLogoutServiceLocation
Closes gh-10674
This commit is contained in:
parent
18427b6411
commit
b9453da343
@ -87,7 +87,9 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver {
|
|||||||
spSsoDescriptor.getKeyDescriptors()
|
spSsoDescriptor.getKeyDescriptors()
|
||||||
.addAll(buildKeys(registration.getDecryptionX509Credentials(), UsageType.ENCRYPTION));
|
.addAll(buildKeys(registration.getDecryptionX509Credentials(), UsageType.ENCRYPTION));
|
||||||
spSsoDescriptor.getAssertionConsumerServices().add(buildAssertionConsumerService(registration));
|
spSsoDescriptor.getAssertionConsumerServices().add(buildAssertionConsumerService(registration));
|
||||||
spSsoDescriptor.getSingleLogoutServices().add(buildSingleLogoutService(registration));
|
if (registration.getSingleLogoutServiceLocation() != null) {
|
||||||
|
spSsoDescriptor.getSingleLogoutServices().add(buildSingleLogoutService(registration));
|
||||||
|
}
|
||||||
if (registration.getNameIdFormat() != null) {
|
if (registration.getNameIdFormat() != null) {
|
||||||
spSsoDescriptor.getNameIDFormats().add(buildNameIDFormat(registration));
|
spSsoDescriptor.getNameIDFormats().add(buildNameIDFormat(registration));
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,8 @@ public final class RelyingPartyRegistration {
|
|||||||
Assert.hasText(entityId, "entityId cannot be empty");
|
Assert.hasText(entityId, "entityId cannot be empty");
|
||||||
Assert.hasText(assertionConsumerServiceLocation, "assertionConsumerServiceLocation cannot be empty");
|
Assert.hasText(assertionConsumerServiceLocation, "assertionConsumerServiceLocation cannot be empty");
|
||||||
Assert.notNull(assertionConsumerServiceBinding, "assertionConsumerServiceBinding cannot be null");
|
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.notNull(providerDetails, "providerDetails cannot be null");
|
||||||
Assert.notEmpty(credentials, "credentials cannot be empty");
|
Assert.notEmpty(credentials, "credentials cannot be empty");
|
||||||
for (org.springframework.security.saml2.credentials.Saml2X509Credential c : credentials) {
|
for (org.springframework.security.saml2.credentials.Saml2X509Credential c : credentials) {
|
||||||
|
@ -111,6 +111,9 @@ final class OpenSamlLogoutRequestResolver {
|
|||||||
if (registration == null) {
|
if (registration == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (registration.getAssertingPartyDetails().getSingleLogoutServiceLocation() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
LogoutRequest logoutRequest = this.logoutRequestBuilder.buildObject();
|
LogoutRequest logoutRequest = this.logoutRequestBuilder.buildObject();
|
||||||
logoutRequest.setDestination(registration.getAssertingPartyDetails().getSingleLogoutServiceLocation());
|
logoutRequest.setDestination(registration.getAssertingPartyDetails().getSingleLogoutServiceLocation());
|
||||||
Issuer issuer = this.issuerBuilder.buildObject();
|
Issuer issuer = this.issuerBuilder.buildObject();
|
||||||
|
@ -132,6 +132,9 @@ final class OpenSamlLogoutResponseResolver {
|
|||||||
if (registration == null) {
|
if (registration == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (registration.getAssertingPartyDetails().getSingleLogoutServiceResponseLocation() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
String serialized = request.getParameter(Saml2ParameterNames.SAML_REQUEST);
|
String serialized = request.getParameter(Saml2ParameterNames.SAML_REQUEST);
|
||||||
byte[] b = Saml2Utils.samlDecode(serialized);
|
byte[] b = Saml2Utils.samlDecode(serialized);
|
||||||
LogoutRequest logoutRequest = parse(inflateIfRequired(registration, b));
|
LogoutRequest logoutRequest = parse(inflateIfRequired(registration, b));
|
||||||
|
@ -120,6 +120,12 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter {
|
|||||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
return;
|
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)) {
|
if (!isCorrectBinding(request, registration)) {
|
||||||
this.logger.trace("Did not process logout request since used incorrect binding");
|
this.logger.trace("Did not process logout request since used incorrect binding");
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
@ -120,6 +120,12 @@ public final class Saml2LogoutResponseFilter extends OncePerRequestFilter {
|
|||||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, error.toString());
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, error.toString());
|
||||||
return;
|
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)) {
|
if (!isCorrectBinding(request, registration)) {
|
||||||
this.logger.trace("Did not process logout request since used incorrect binding");
|
this.logger.trace("Did not process logout request since used incorrect binding");
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
@ -47,7 +47,9 @@ public class OpenSaml3LogoutRequestResolverTests {
|
|||||||
this.relyingPartyRegistrationResolver);
|
this.relyingPartyRegistrationResolver);
|
||||||
logoutRequestResolver.setParametersConsumer((parameters) -> parameters.getLogoutRequest().setID("myid"));
|
logoutRequestResolver.setParametersConsumer((parameters) -> parameters.getLogoutRequest().setID("myid"));
|
||||||
HttpServletRequest request = new MockHttpServletRequest();
|
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");
|
Authentication authentication = new TestingAuthenticationToken("user", "password");
|
||||||
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
|
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
|
||||||
Saml2LogoutRequest logoutRequest = logoutRequestResolver.resolve(request, authentication);
|
Saml2LogoutRequest logoutRequest = logoutRequestResolver.resolve(request, authentication);
|
||||||
|
@ -53,7 +53,10 @@ public class OpenSaml3LogoutResponseResolverTests {
|
|||||||
Consumer<LogoutResponseParameters> parametersConsumer = mock(Consumer.class);
|
Consumer<LogoutResponseParameters> parametersConsumer = mock(Consumer.class);
|
||||||
logoutResponseResolver.setParametersConsumer(parametersConsumer);
|
logoutResponseResolver.setParametersConsumer(parametersConsumer);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
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");
|
Authentication authentication = new TestingAuthenticationToken("user", "password");
|
||||||
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
|
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
|
||||||
request.setParameter(Saml2ParameterNames.SAML_REQUEST,
|
request.setParameter(Saml2ParameterNames.SAML_REQUEST,
|
||||||
|
@ -47,7 +47,9 @@ public class OpenSaml4LogoutRequestResolverTests {
|
|||||||
this.relyingPartyRegistrationResolver);
|
this.relyingPartyRegistrationResolver);
|
||||||
logoutRequestResolver.setParametersConsumer((parameters) -> parameters.getLogoutRequest().setID("myid"));
|
logoutRequestResolver.setParametersConsumer((parameters) -> parameters.getLogoutRequest().setID("myid"));
|
||||||
HttpServletRequest request = new MockHttpServletRequest();
|
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");
|
Authentication authentication = new TestingAuthenticationToken("user", "password");
|
||||||
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
|
given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
|
||||||
Saml2LogoutRequest logoutRequest = logoutRequestResolver.resolve(request, authentication);
|
Saml2LogoutRequest logoutRequest = logoutRequestResolver.resolve(request, authentication);
|
||||||
|
@ -53,7 +53,10 @@ public class OpenSaml4LogoutResponseResolverTests {
|
|||||||
Consumer<LogoutResponseParameters> parametersConsumer = mock(Consumer.class);
|
Consumer<LogoutResponseParameters> parametersConsumer = mock(Consumer.class);
|
||||||
logoutResponseResolver.setParametersConsumer(parametersConsumer);
|
logoutResponseResolver.setParametersConsumer(parametersConsumer);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
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");
|
Authentication authentication = new TestingAuthenticationToken("user", "password");
|
||||||
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
|
LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
|
||||||
request.setParameter(Saml2ParameterNames.SAML_REQUEST,
|
request.setParameter(Saml2ParameterNames.SAML_REQUEST,
|
||||||
|
@ -70,4 +70,13 @@ public class OpenSamlMetadataResolverTests {
|
|||||||
assertThat(metadata).contains("<md:NameIDFormat>format</md:NameIDFormat>");
|
assertThat(metadata).contains("<md:NameIDFormat>format</md:NameIDFormat>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void resolveWhenRelyingPartyNoLogoutThenMetadataMatches() {
|
||||||
|
RelyingPartyRegistration relyingPartyRegistration = TestRelyingPartyRegistrations.full()
|
||||||
|
.singleLogoutServiceLocation(null).nameIdFormat("format").build();
|
||||||
|
OpenSamlMetadataResolver openSamlMetadataResolver = new OpenSamlMetadataResolver();
|
||||||
|
String metadata = openSamlMetadataResolver.resolve(relyingPartyRegistration);
|
||||||
|
assertThat(metadata).doesNotContain("ResponseLocation");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -153,4 +153,20 @@ public class Saml2LogoutRequestFilterTests {
|
|||||||
verifyNoInteractions(this.logoutHandler);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.saml2.provider.service.web.RelyingPartyRegistrationResolver;
|
||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
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.ArgumentMatchers.any;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.BDDMockito.mock;
|
import static org.mockito.BDDMockito.mock;
|
||||||
@ -151,4 +152,23 @@ public class Saml2LogoutResponseFilterTests {
|
|||||||
verifyNoInteractions(this.logoutSuccessHandler);
|
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…
x
Reference in New Issue
Block a user