Skip to content

Commit 18318f6

Browse files
committed
Add RelayStateResolver
Co-authored-by: ghaege <ghaege@qaepps.de> Closes gh-12538
1 parent 5b1710f commit 18318f6

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import jakarta.servlet.http.HttpServletRequest;
2424
import org.opensaml.saml.saml2.core.LogoutRequest;
2525

26+
import org.springframework.core.convert.converter.Converter;
2627
import org.springframework.security.core.Authentication;
2728
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
2829
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
@@ -34,6 +35,7 @@
3435
* OpenSAML 4
3536
*
3637
* @author Josh Cummings
38+
* @author Gerhard Haege
3739
* @since 5.6
3840
*/
3941
public final class OpenSaml4LogoutRequestResolver implements Saml2LogoutRequestResolver {
@@ -83,6 +85,16 @@ public void setClock(Clock clock) {
8385
this.clock = clock;
8486
}
8587

88+
/**
89+
* Use this {@link Converter} to compute the RelayState
90+
* @param relayStateResolver the {@link Converter} to use
91+
* @since 6.1
92+
*/
93+
public void setRelayStateResolver(Converter<HttpServletRequest, String> relayStateResolver) {
94+
Assert.notNull(relayStateResolver, "relayStateResolver cannot be null");
95+
this.logoutRequestResolver.setRelayStateResolver(relayStateResolver);
96+
}
97+
8698
public static final class LogoutRequestParameters {
8799

88100
private final HttpServletRequest request;

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@
3838
import org.opensaml.saml.saml2.core.impl.SessionIndexBuilder;
3939
import org.w3c.dom.Element;
4040

41+
import org.springframework.core.convert.converter.Converter;
4142
import org.springframework.security.core.Authentication;
4243
import org.springframework.security.saml2.Saml2Exception;
4344
import org.springframework.security.saml2.core.OpenSamlInitializationService;
@@ -74,6 +75,8 @@ final class OpenSamlLogoutRequestResolver {
7475

7576
private final RelyingPartyRegistrationResolver relyingPartyRegistrationResolver;
7677

78+
private Converter<HttpServletRequest, String> relayStateResolver = (request) -> UUID.randomUUID().toString();
79+
7780
/**
7881
* Construct a {@link OpenSamlLogoutRequestResolver}
7982
*/
@@ -95,6 +98,10 @@ final class OpenSamlLogoutRequestResolver {
9598
Assert.notNull(this.sessionIndexBuilder, "sessionIndexBuilder must be configured in OpenSAML");
9699
}
97100

101+
void setRelayStateResolver(Converter<HttpServletRequest, String> relayStateResolver) {
102+
this.relayStateResolver = relayStateResolver;
103+
}
104+
98105
/**
99106
* Prepare to create, sign, and serialize a SAML 2.0 Logout Request.
100107
*
@@ -140,7 +147,7 @@ Saml2LogoutRequest resolve(HttpServletRequest request, Authentication authentica
140147
if (logoutRequest.getID() == null) {
141148
logoutRequest.setID("LR" + UUID.randomUUID());
142149
}
143-
String relayState = UUID.randomUUID().toString();
150+
String relayState = this.relayStateResolver.convert(request);
144151
Saml2LogoutRequest.Builder result = Saml2LogoutRequest.withRelyingPartyRegistration(registration)
145152
.id(logoutRequest.getID());
146153
if (registration.getAssertingPartyDetails().getSingleLogoutServiceBinding() == Saml2MessageBinding.POST) {

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,9 +16,11 @@
1616

1717
package org.springframework.security.saml2.provider.service.web.authentication.logout;
1818

19+
import jakarta.servlet.http.HttpServletRequest;
1920
import org.junit.jupiter.api.BeforeEach;
2021
import org.junit.jupiter.api.Test;
2122

23+
import org.springframework.core.convert.converter.Converter;
2224
import org.springframework.mock.web.MockHttpServletRequest;
2325
import org.springframework.security.authentication.TestingAuthenticationToken;
2426
import org.springframework.security.core.Authentication;
@@ -32,6 +34,7 @@
3234
import static org.mockito.ArgumentMatchers.any;
3335
import static org.mockito.BDDMockito.given;
3436
import static org.mockito.Mockito.mock;
37+
import static org.mockito.Mockito.verify;
3538

3639
/**
3740
* Tests for {@link OpenSaml4LogoutRequestResolver}
@@ -67,6 +70,19 @@ public void setParametersConsumerWhenNullThenIllegalArgument() {
6770
.isThrownBy(() -> this.logoutRequestResolver.setParametersConsumer(null));
6871
}
6972

73+
@Test
74+
public void resolveWhenCustomRelayStateThenUses() {
75+
given(this.registrationResolver.resolve(any(), any())).willReturn(this.registration);
76+
Converter<HttpServletRequest, String> relayState = mock(Converter.class);
77+
given(relayState.convert(any())).willReturn("any-state");
78+
this.logoutRequestResolver.setRelayStateResolver(relayState);
79+
80+
Saml2LogoutRequest logoutRequest = this.logoutRequestResolver.resolve(givenRequest(), givenAuthentication());
81+
82+
assertThat(logoutRequest.getRelayState()).isEqualTo("any-state");
83+
verify(relayState).convert(any());
84+
}
85+
7086
private static Authentication givenAuthentication() {
7187
return new TestingAuthenticationToken("user", "password");
7288
}

0 commit comments

Comments
 (0)