diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc index 632c87995d..c9df44e9c6 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc @@ -270,12 +270,13 @@ class MyUserDetailsResponseAuthenticationConverter implements Converter - UserDetails principal = this.userDetailsService.loadByUsername(username); <2> + String username = authentication.getName(); + UserDetails user = this.userDetailsService.loadUserByUsername(username); <2> String saml2Response = authentication.getSaml2Response(); Saml2ResponseAssertionAccessor assertion = new OpenSamlResponseAssertionAccessor( - saml2Response, CollectionUtils.getFirst(response.getAssertions())); - Collection authorities = principal.getAuthorities(); - return new Saml2AssertionAuthentication(userDetails, assertion, authorities); <3> + saml2Response, CollectionUtils.getFirst(responseToken.getResponse().getAssertions())); + Collection authorities = user.getAuthorities(); + return new Saml2AssertionAuthentication(user, assertion, authorities); <3> } } @@ -286,18 +287,19 @@ Kotlin:: [source,kotlin,role="secondary"] ---- @Component -open class MyUserDetailsResponseAuthenticationConverter(val delegate: ResponseAuthenticationConverter, - UserDetailsService userDetailsService): Converter { +open class MyUserDetailsResponseAuthenticationConverter(private val userDetailsService: UserDetailsService) : Converter { - @Override - open fun convert(responseToken: ResponseToken): Saml2Authentication { + private val delegate = ResponseAuthenticationConverter() + + override fun convert(responseToken: ResponseToken): Saml2Authentication { val authentication = this.delegate.convert(responseToken) <1> - val principal = this.userDetailsService.loadByUsername(username) <2> - val saml2Response = authentication.getSaml2Response() + val username = authentication.name + val userDetails = this.userDetailsService.loadUserByUsername(username) <2> + val saml2Response = authentication.saml2Response val assertion = OpenSamlResponseAssertionAccessor( - saml2Response, CollectionUtils.getFirst(response.getAssertions())) + saml2Response, responseToken.response.assertions.firstOrNull()) val authorities = principal.getAuthorities() - return Saml2AssertionAuthentication(userDetails, assertion, authorities) <3> + return Saml2AssertionAuthentication(userDetails, assertion, userDetails.authorities) <3> } } diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc index f661890753..be605e2f2e 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc @@ -215,7 +215,7 @@ If any signature is invalid, authentication fails. Also, if neither the response nor the assertions have signatures, authentication fails. Either the response or all the assertions must have signatures. -image:{icondir}/number_7.png[] Then, the provider xref:servlet/saml2/login/authentication.adoc#servlet-saml2login-opensamlauthenticationprovider-decryption[,]decrypts any `EncryptedID` or `EncryptedAttribute` elements]. +image:{icondir}/number_7.png[] Then, the provider xref:servlet/saml2/login/authentication.adoc#servlet-saml2login-opensamlauthenticationprovider-decryption[decrypts any `EncryptedID` or `EncryptedAttribute` elements]. If any decryptions fail, authentication fails. image:{icondir}/number_8.png[] Next, the provider validates each assertion's `ExpiresAt` and `NotBefore` timestamps, the `` and any `` conditions. @@ -1039,4 +1039,4 @@ You can see a completed example of this in {gh-samples-url}/servlet/spring-boot/ In the event that you are migrating from the Spring Security SAML Extension, there may be some benefit to configuring your application to use the SAML Extension URI defaults. -For more information on this, please see {gh-samples-url}/servlet/spring-boot/java/saml2/custom-urls[our `custom-urls` sample] and {gh-samples-url}/servlet/spring-boot/java/saml2/saml-extension-federation[our `saml-extension-federation` sample]. +For more information on this, please see {gh-samples-url}/servlet/spring-boot/java/saml2/saml-extension-urls[our `saml-extension-urls` sample] and {gh-samples-url}/servlet/spring-boot/java/saml2/saml-extension-federation[our `saml-extension-federation` sample]. diff --git a/docs/modules/ROOT/pages/servlet/saml2/logout.adoc b/docs/modules/ROOT/pages/servlet/saml2/logout.adoc index 27de151381..e9827195e6 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/logout.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/logout.adoc @@ -439,14 +439,14 @@ Java:: ---- @Bean public Saml2LogoutResponseResolver logoutResponseResolver(RelyingPartyRegistrationRepository registrations) { - OpenSaml5LogoutResponseResolver logoutRequestResolver = + OpenSaml5LogoutResponseResolver resolver = new OpenSaml5LogoutResponseResolver(registrations); - logoutRequestResolver.setParametersConsumer((parameters) -> { + resolver.setParametersConsumer((parameters) -> { if (checkOtherPrevailingConditions(parameters.getRequest())) { - parameters.getLogoutRequest().getStatus().getStatusCode().setCode(StatusCode.PARTIAL_LOGOUT); + parameters.getLogoutResponse().getStatus().getStatusCode().setCode(StatusCode.PARTIAL_LOGOUT); } }); - return logoutRequestResolver; + return resolver; } ---- @@ -456,13 +456,13 @@ Kotlin:: ---- @Bean open fun logoutResponseResolver(registrations: RelyingPartyRegistrationRepository?): Saml2LogoutResponseResolver { - val logoutRequestResolver = OpenSaml5LogoutResponseResolver(registrations) - logoutRequestResolver.setParametersConsumer { LogoutResponseParameters parameters -> - if (checkOtherPrevailingConditions(parameters.getRequest())) { - parameters.getLogoutRequest().getStatus().getStatusCode().setCode(StatusCode.PARTIAL_LOGOUT) + val resolver = OpenSaml5LogoutResponseResolver(registrations) + resolver.setParametersConsumer { parameters -> + if (checkOtherPrevailingConditions(parameters.request)) { + parameters.logoutResponse.status.statusCode.code = StatusCode.PARTIAL_LOGOUT } } - return logoutRequestResolver + return resolver } ---- ====== @@ -477,8 +477,8 @@ Java:: ---- http .saml2Logout((saml2) -> saml2 - .logoutRequest((request) -> request - .logoutRequestResolver(this.logoutRequestResolver) + .logoutResponse((request) -> request + .logoutResponseResolver(this.logoutResponseResolver) ) ); ---- @@ -489,8 +489,8 @@ Kotlin:: ---- http { saml2Logout { - logoutRequest { - logoutRequestResolver = this.logoutRequestResolver + logoutResponse { + logoutResponseResolver = logoutResponseResolver } } } @@ -513,12 +513,17 @@ public class MyOpenSamlLogoutRequestValidator implements Saml2LogoutRequestValid private final Saml2LogoutRequestValidator delegate = new OpenSaml5LogoutRequestValidator(); @Override - public Saml2LogoutRequestValidator logout(Saml2LogoutRequestValidatorParameters parameters) { + public Saml2LogoutValidatorResult validate(Saml2LogoutRequestValidatorParameters parameters) { // verify signature, issuer, destination, and principal name - Saml2LogoutValidatorResult result = delegate.authenticate(authentication); + Saml2LogoutValidatorResult result = delegate.validate(authentication); - LogoutRequest logoutRequest = // ... parse using OpenSAML + if(result.hasErrors()){ + return result; + } + // perform custom validation + + return result; } } ---- @@ -528,16 +533,21 @@ Kotlin:: [source,kotlin,role="secondary"] ---- @Component -open class MyOpenSamlLogoutRequestValidator: Saml2LogoutRequestValidator { +open class MyOpenSamlLogoutRequestValidator : Saml2LogoutRequestValidator { private val delegate = OpenSaml5LogoutRequestValidator() @Override - fun logout(parameters: Saml2LogoutRequestValidatorParameters): Saml2LogoutRequestValidator { + fun validate(parameters: Saml2LogoutRequestValidatorParameters): Saml2LogoutValidatorResult { // verify signature, issuer, destination, and principal name - val result = delegate.authenticate(authentication) + val result = delegate.validate(authentication) + + if (result.hasErrors()) { + return result + } - val logoutRequest: LogoutRequest = // ... parse using OpenSAML // perform custom validation + + return result } } ---- @@ -589,12 +599,17 @@ public class MyOpenSamlLogoutResponseValidator implements Saml2LogoutResponseVal private final Saml2LogoutResponseValidator delegate = new OpenSaml5LogoutResponseValidator(); @Override - public Saml2LogoutValidatorResult logout(Saml2LogoutResponseValidatorParameters parameters) { + public Saml2LogoutValidatorResult validate(Saml2LogoutResponseValidatorParameters parameters) { // verify signature, issuer, destination, and status - Saml2LogoutValidatorResult result = delegate.authenticate(parameters); + Saml2LogoutValidatorResult result = delegate.validate(parameters); + + if (result.hasErrors()) { + return result; + } - LogoutResponse logoutResponse = // ... parse using OpenSAML // perform custom validation + + return result; } } ---- @@ -604,16 +619,20 @@ Kotlin:: [source,kotlin,role="secondary"] ---- @Component -open class MyOpenSamlLogoutResponseValidator: Saml2LogoutResponseValidator { +open class MyOpenSamlLogoutResponseValidator : Saml2LogoutResponseValidator { private val delegate = OpenSaml5LogoutResponseValidator() - @Override - fun logout(parameters: Saml2LogoutResponseValidatorParameters): Saml2LogoutResponseValidator { + override fun validate(parameters: Saml2LogoutResponseValidatorParameters): Saml2LogoutValidatorResult { // verify signature, issuer, destination, and status - val result = delegate.authenticate(authentication) + val result = delegate.validate(authentication) - val logoutResponse: LogoutResponse = // ... parse using OpenSAML + if (result.hasErrors()) { + return result + } + // perform custom validation + + return result } } ---- @@ -630,7 +649,7 @@ Java:: http .saml2Logout((saml2) -> saml2 .logoutResponse((response) -> response - .logoutResponseAuthenticator(myOpenSamlLogoutResponseAuthenticator) + .logoutResponseValidator(myOpenSamlLogoutResponseValidator) ) ); ----