Skip to content

Commit 70ad3bf

Browse files
relay_state should not be included in signing calculation when it is null
Closes gh-13913
1 parent 19c4e42 commit 70ad3bf

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,12 @@ <T extends AbstractSaml2AuthenticationRequest> T resolve(HttpServletRequest requ
167167
.samlRequest(deflatedAndEncoded)
168168
.relayState(relayState);
169169
if (registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()) {
170-
Map<String, String> parameters = OpenSamlSigningUtils.sign(registration)
171-
.param(Saml2ParameterNames.SAML_REQUEST, deflatedAndEncoded)
172-
.param(Saml2ParameterNames.RELAY_STATE, relayState)
173-
.parameters();
170+
OpenSamlSigningUtils.QueryParametersPartial parametersPartial = OpenSamlSigningUtils.sign(registration)
171+
.param(Saml2ParameterNames.SAML_REQUEST, deflatedAndEncoded);
172+
if (relayState != null) {
173+
parametersPartial = parametersPartial.param(Saml2ParameterNames.RELAY_STATE, relayState);
174+
}
175+
Map<String, String> parameters = parametersPartial.parameters();
174176
builder.sigAlg(parameters.get(Saml2ParameterNames.SIG_ALG))
175177
.signature(parameters.get(Saml2ParameterNames.SIGNATURE));
176178
}

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

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818

1919
import org.junit.jupiter.api.BeforeEach;
2020
import org.junit.jupiter.api.Test;
21+
import org.mockito.Answers;
22+
import org.mockito.MockedStatic;
2123
import org.opensaml.xmlsec.signature.support.SignatureConstants;
2224

2325
import org.springframework.mock.web.MockHttpServletRequest;
2426
import org.springframework.security.saml2.Saml2Exception;
27+
import org.springframework.security.saml2.core.Saml2ParameterNames;
2528
import org.springframework.security.saml2.core.Saml2X509Credential;
2629
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
2730
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
@@ -32,6 +35,12 @@
3235

3336
import static org.assertj.core.api.Assertions.assertThat;
3437
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
38+
import static org.mockito.ArgumentMatchers.any;
39+
import static org.mockito.ArgumentMatchers.eq;
40+
import static org.mockito.Mockito.mockStatic;
41+
import static org.mockito.Mockito.never;
42+
import static org.mockito.Mockito.spy;
43+
import static org.mockito.Mockito.verify;
3544

3645
/**
3746
* Tests for {@link OpenSamlAuthenticationRequestResolver}
@@ -103,8 +112,8 @@ public void resolveAuthenticationRequestWhenSignedThenCredentialIsRequired() {
103112
.build();
104113
OpenSamlAuthenticationRequestResolver resolver = authenticationRequestResolver(registration);
105114
assertThatExceptionOfType(Saml2Exception.class)
106-
.isThrownBy(() -> resolver.resolve(request, (r, authnRequest) -> {
107-
}));
115+
.isThrownBy(() -> resolver.resolve(request, (r, authnRequest) -> {
116+
}));
108117
}
109118

110119
@Test
@@ -172,6 +181,58 @@ public void resolveAuthenticationRequestWhenSHA1SignRequestThenSigns() {
172181
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
173182
}
174183

184+
@Test
185+
public void resolveAuthenticationRequestWhenSignedAndRelayStateIsNullThenSignsWithoutRelayState() {
186+
try (MockedStatic<OpenSamlSigningUtils> openSamlSigningUtilsMockedStatic = mockStatic(
187+
OpenSamlSigningUtils.class, Answers.CALLS_REAL_METHODS)) {
188+
MockHttpServletRequest request = new MockHttpServletRequest();
189+
request.setPathInfo("/saml2/authenticate/registration-id");
190+
RelyingPartyRegistration registration = this.relyingPartyRegistrationBuilder
191+
.assertingPartyDetails((party) -> party.wantAuthnRequestsSigned(true))
192+
.build();
193+
OpenSamlSigningUtils.QueryParametersPartial queryParametersPartialSpy = spy(
194+
new OpenSamlSigningUtils.QueryParametersPartial(registration));
195+
openSamlSigningUtilsMockedStatic.when(() -> OpenSamlSigningUtils.sign(any()))
196+
.thenReturn(queryParametersPartialSpy);
197+
OpenSamlAuthenticationRequestResolver resolver = authenticationRequestResolver(registration);
198+
resolver.setRelayStateResolver((source) -> null);
199+
Saml2RedirectAuthenticationRequest result = resolver.resolve(request, (r, authnRequest) -> {
200+
});
201+
assertThat(result.getSamlRequest()).isNotEmpty();
202+
assertThat(result.getRelayState()).isNull();
203+
assertThat(result.getSigAlg()).isNotNull();
204+
assertThat(result.getSignature()).isNotNull();
205+
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
206+
verify(queryParametersPartialSpy, never()).param(eq(Saml2ParameterNames.RELAY_STATE), any());
207+
}
208+
}
209+
210+
@Test
211+
public void resolveAuthenticationRequestWhenSignedAndRelayStateIsEmptyThenSignsWithEmptyRelayState() {
212+
try (MockedStatic<OpenSamlSigningUtils> openSamlSigningUtilsMockedStatic = mockStatic(
213+
OpenSamlSigningUtils.class, Answers.CALLS_REAL_METHODS)) {
214+
MockHttpServletRequest request = new MockHttpServletRequest();
215+
request.setPathInfo("/saml2/authenticate/registration-id");
216+
RelyingPartyRegistration registration = this.relyingPartyRegistrationBuilder
217+
.assertingPartyDetails((party) -> party.wantAuthnRequestsSigned(true))
218+
.build();
219+
OpenSamlSigningUtils.QueryParametersPartial queryParametersPartialSpy = spy(
220+
new OpenSamlSigningUtils.QueryParametersPartial(registration));
221+
openSamlSigningUtilsMockedStatic.when(() -> OpenSamlSigningUtils.sign(any()))
222+
.thenReturn(queryParametersPartialSpy);
223+
OpenSamlAuthenticationRequestResolver resolver = authenticationRequestResolver(registration);
224+
resolver.setRelayStateResolver((source) -> "");
225+
Saml2RedirectAuthenticationRequest result = resolver.resolve(request, (r, authnRequest) -> {
226+
});
227+
assertThat(result.getSamlRequest()).isNotEmpty();
228+
assertThat(result.getRelayState()).isEmpty();
229+
assertThat(result.getSigAlg()).isNotNull();
230+
assertThat(result.getSignature()).isNotNull();
231+
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
232+
verify(queryParametersPartialSpy).param(eq(Saml2ParameterNames.RELAY_STATE), eq(""));
233+
}
234+
}
235+
175236
private OpenSamlAuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistration registration) {
176237
return new OpenSamlAuthenticationRequestResolver((request, id) -> registration);
177238
}

0 commit comments

Comments
 (0)