Skip to content

Commit 2fb8e66

Browse files
Kehrlannmarcusdacoregio
authored andcommitted
Saml2WebSsoAuthenticationFilter adds authentication details
Closes gh-7722
1 parent 84d173c commit 2fb8e66

File tree

4 files changed

+64
-1
lines changed

4 files changed

+64
-1
lines changed

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/servlet/filter/Saml2WebSsoAuthenticationFilter.java

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import javax.servlet.http.HttpServletRequest;
2020
import javax.servlet.http.HttpServletResponse;
2121

22+
import org.springframework.security.authentication.AbstractAuthenticationToken;
2223
import org.springframework.security.core.Authentication;
2324
import org.springframework.security.core.AuthenticationException;
2425
import org.springframework.security.saml2.core.Saml2Error;
@@ -109,6 +110,7 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
109110
"No relying party registration found");
110111
throw new Saml2AuthenticationException(saml2Error);
111112
}
113+
setDetails(request, authentication);
112114
this.authenticationRequestRepository.removeAuthenticationRequest(request, response);
113115
return getAuthenticationManager().authenticate(authentication);
114116
}
@@ -138,4 +140,11 @@ private void setAuthenticationRequestRepositoryIntoAuthenticationConverter(
138140
}
139141
}
140142

143+
private void setDetails(HttpServletRequest request, Authentication authentication) {
144+
if (AbstractAuthenticationToken.class.isAssignableFrom(authentication.getClass())) {
145+
Object details = this.authenticationDetailsSource.buildDetails(request);
146+
((AbstractAuthenticationToken) authentication).setDetails(details);
147+
}
148+
}
149+
141150
}

saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,12 @@ public Authentication authenticate(Authentication authentication) throws Authent
446446
String serializedResponse = token.getSaml2Response();
447447
Response response = parse(serializedResponse);
448448
process(token, response);
449-
return this.responseAuthenticationConverter.convert(new ResponseToken(response, token));
449+
AbstractAuthenticationToken authenticationResponse = this.responseAuthenticationConverter
450+
.convert(new ResponseToken(response, token));
451+
if (authenticationResponse != null) {
452+
authenticationResponse.setDetails(authentication.getDetails());
453+
}
454+
return authenticationResponse;
450455
}
451456
catch (Saml2AuthenticationException ex) {
452457
throw ex;

saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java

+15
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,21 @@ public void authenticateWhenDecryptionKeysAreWrongThenThrowAuthenticationExcepti
352352
.satisfies(errorOf(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData"));
353353
}
354354

355+
@Test
356+
public void authenticateWhenAuthenticationHasDetailsThenSucceeds() {
357+
Response response = response();
358+
Assertion assertion = assertion();
359+
assertion.getSubject().getSubjectConfirmations()
360+
.forEach((sc) -> sc.getSubjectConfirmationData().setAddress("10.10.10.10"));
361+
TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
362+
RELYING_PARTY_ENTITY_ID);
363+
response.getAssertions().add(assertion);
364+
Saml2AuthenticationToken token = token(response, verifying(registration()));
365+
token.setDetails("some-details");
366+
Authentication authentication = this.provider.authenticate(token);
367+
assertThat(authentication.getDetails()).isEqualTo("some-details");
368+
}
369+
355370
@Test
356371
public void writeObjectWhenTypeIsSaml2AuthenticationThenNoException() throws IOException {
357372
Response response = response();

saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/servlet/filter/Saml2WebSsoAuthenticationFilterTests.java

+34
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
import org.springframework.mock.web.MockFilterChain;
2626
import org.springframework.mock.web.MockHttpServletRequest;
2727
import org.springframework.mock.web.MockHttpServletResponse;
28+
import org.springframework.security.authentication.AuthenticationDetailsSource;
2829
import org.springframework.security.authentication.AuthenticationManager;
2930
import org.springframework.security.authentication.TestingAuthenticationToken;
3031
import org.springframework.security.core.Authentication;
3132
import org.springframework.security.saml2.core.Saml2ParameterNames;
3233
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
3334
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
35+
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
3436
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens;
3537
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
3638
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
@@ -40,11 +42,13 @@
4042
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
4143
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
4244
import org.springframework.security.web.authentication.AuthenticationConverter;
45+
import org.springframework.security.web.authentication.WebAuthenticationDetails;
4346
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
4447
import org.springframework.security.web.util.matcher.RequestMatcher;
4548

4649
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
4750
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
51+
import static org.assertj.core.api.Assertions.assertThatNoException;
4852
import static org.mockito.BDDMockito.given;
4953
import static org.mockito.Mockito.mock;
5054
import static org.mockito.Mockito.verify;
@@ -119,6 +123,36 @@ public void attemptAuthenticationWhenSavedAuthnRequestThenRemovesAuthnRequest()
119123
verify(authenticationRequestRepository).removeAuthenticationRequest(this.request, this.response);
120124
}
121125

126+
@Test
127+
public void attemptAuthenticationAddsDetails() {
128+
AuthenticationConverter authenticationConverter = mock(AuthenticationConverter.class);
129+
final Saml2AuthenticationToken token = TestSaml2AuthenticationTokens.token();
130+
given(authenticationConverter.convert(this.request)).willReturn(token);
131+
final AuthenticationDetailsSource authenticationDetailsSource = mock(AuthenticationDetailsSource.class);
132+
final WebAuthenticationDetails details = mock(WebAuthenticationDetails.class);
133+
given(authenticationDetailsSource.buildDetails(this.request)).willReturn(details);
134+
this.filter = new Saml2WebSsoAuthenticationFilter(authenticationConverter, "/some/other/path/{registrationId}");
135+
this.filter.setAuthenticationManager((authentication) -> null);
136+
this.filter.setAuthenticationDetailsSource(authenticationDetailsSource);
137+
this.request.setPathInfo("/some/other/path/idp-registration-id");
138+
this.filter.attemptAuthentication(this.request, this.response);
139+
Assertions.assertEquals(details, token.getDetails());
140+
}
141+
142+
@Test
143+
public void attemptAuthenticationWhenAuthenticationNotAbstractAuthenticationTokenDoesNotAddDetails() {
144+
AuthenticationConverter authenticationConverter = mock(AuthenticationConverter.class);
145+
final Authentication authenticationWithoutDetails = mock(Authentication.class);
146+
given(authenticationConverter.convert(this.request)).willReturn(authenticationWithoutDetails);
147+
final AuthenticationDetailsSource authenticationDetailsSource = mock(AuthenticationDetailsSource.class);
148+
this.filter = new Saml2WebSsoAuthenticationFilter(authenticationConverter, "/some/other/path/{registrationId}");
149+
this.filter.setAuthenticationManager((authentication) -> null);
150+
this.filter.setAuthenticationDetailsSource(authenticationDetailsSource);
151+
this.request.setPathInfo("/some/other/path/idp-registration-id");
152+
assertThatNoException().isThrownBy(() -> this.filter.attemptAuthentication(this.request, this.response));
153+
verifyNoInteractions(authenticationDetailsSource);
154+
}
155+
122156
@Test
123157
public void setAuthenticationRequestRepositoryWhenNullThenThrowsIllegalArgument() {
124158
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setAuthenticationRequestRepository(null))

0 commit comments

Comments
 (0)