mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-07 03:02:23 +00:00
SAML 2.0 Single Logout Uses Saml2AuthenticationInfo
This allows SLO to be triggered without the authentication principal needing to implement a given interface. Issue gh-10820
This commit is contained in:
parent
ffd6e3c0f7
commit
36c7b91fb9
@ -33,7 +33,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
|||||||
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutRequestValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutRequestValidator;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutResponseValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutResponseValidator;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml5LogoutRequestValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml5LogoutRequestValidator;
|
||||||
@ -531,10 +531,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
|||||||
@Override
|
@Override
|
||||||
public boolean matches(HttpServletRequest request) {
|
public boolean matches(HttpServletRequest request) {
|
||||||
Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
|
Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (authentication == null) {
|
return Saml2AuthenticationInfo.fromAuthentication(authentication) != null;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import org.springframework.beans.factory.xml.ParserContext;
|
|||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo;
|
||||||
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
|
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter;
|
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter;
|
||||||
@ -236,10 +236,7 @@ final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
@Override
|
@Override
|
||||||
public boolean matches(HttpServletRequest request) {
|
public boolean matches(HttpServletRequest request) {
|
||||||
Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
|
Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (authentication == null) {
|
return Saml2AuthenticationInfo.fromAuthentication(authentication) != null;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
||||||
|
@ -31,7 +31,7 @@ import org.springframework.util.CollectionUtils;
|
|||||||
* @author Clement Stoquart
|
* @author Clement Stoquart
|
||||||
* @since 5.2.2
|
* @since 5.2.2
|
||||||
*/
|
*/
|
||||||
public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal {
|
public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal, Saml2AuthenticationInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the first value of Saml2 token attribute by name
|
* Get the first value of Saml2 token attribute by name
|
||||||
@ -72,10 +72,12 @@ public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal {
|
|||||||
* @return the {@link RelyingPartyRegistration} identifier
|
* @return the {@link RelyingPartyRegistration} identifier
|
||||||
* @since 5.6
|
* @since 5.6
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
default String getRelyingPartyRegistrationId() {
|
default String getRelyingPartyRegistrationId() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
default List<String> getSessionIndexes() {
|
default List<String> getSessionIndexes() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2022 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.security.saml2.provider.service.authentication;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.opensaml.saml.saml2.core.SessionIndex;
|
||||||
|
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional SAML 2.0 authentication information
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* SAML 2.0 Single Logout requires that the {@link Authentication#getPrincipal()
|
||||||
|
* authenticated principal} or the {@link Authentication} itself implements this
|
||||||
|
* interface.
|
||||||
|
*
|
||||||
|
* @author Christian Schuster
|
||||||
|
*/
|
||||||
|
public interface Saml2AuthenticationInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link RelyingPartyRegistration} identifier
|
||||||
|
* @return the {@link RelyingPartyRegistration} identifier
|
||||||
|
*/
|
||||||
|
String getRelyingPartyRegistrationId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link SessionIndex} values of the authenticated principal
|
||||||
|
* @return the {@link SessionIndex} values of the authenticated principal
|
||||||
|
*/
|
||||||
|
List<String> getSessionIndexes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to obtain a {@link Saml2AuthenticationInfo} instance from an
|
||||||
|
* {@link Authentication}
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The result is either the {@link Authentication#getPrincipal() authenticated
|
||||||
|
* principal}, the {@link Authentication} itself, or {@code null}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Returning {@code null} indicates that the given {@link Authentication} does not
|
||||||
|
* represent a SAML 2.0 authentication.
|
||||||
|
* @param authentication the {@link Authentication}
|
||||||
|
* @return the {@link Saml2AuthenticationInfo} or {@code null} if unavailable
|
||||||
|
*/
|
||||||
|
static Saml2AuthenticationInfo fromAuthentication(Authentication authentication) {
|
||||||
|
if (authentication == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object principal = authentication.getPrincipal();
|
||||||
|
if (principal instanceof Saml2AuthenticationInfo) {
|
||||||
|
return (Saml2AuthenticationInfo) principal;
|
||||||
|
}
|
||||||
|
if (authentication instanceof Saml2AuthenticationInfo) {
|
||||||
|
return (Saml2AuthenticationInfo) authentication;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -42,7 +42,7 @@ import org.springframework.core.convert.converter.Converter;
|
|||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.saml2.core.OpenSamlInitializationService;
|
import org.springframework.security.saml2.core.OpenSamlInitializationService;
|
||||||
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||||
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
||||||
@ -149,9 +149,9 @@ final class BaseOpenSamlLogoutRequestResolver implements Saml2LogoutRequestResol
|
|||||||
NameID nameId = this.nameIdBuilder.buildObject();
|
NameID nameId = this.nameIdBuilder.buildObject();
|
||||||
nameId.setValue(authentication.getName());
|
nameId.setValue(authentication.getName());
|
||||||
logoutRequest.setNameID(nameId);
|
logoutRequest.setNameID(nameId);
|
||||||
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) {
|
Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication);
|
||||||
Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();
|
if (info != null) {
|
||||||
for (String index : principal.getSessionIndexes()) {
|
for (String index : info.getSessionIndexes()) {
|
||||||
SessionIndex sessionIndex = this.sessionIndexBuilder.buildObject();
|
SessionIndex sessionIndex = this.sessionIndexBuilder.buildObject();
|
||||||
sessionIndex.setValue(index);
|
sessionIndex.setValue(index);
|
||||||
logoutRequest.getSessionIndexes().add(sessionIndex);
|
logoutRequest.getSessionIndexes().add(sessionIndex);
|
||||||
@ -191,12 +191,9 @@ final class BaseOpenSamlLogoutRequestResolver implements Saml2LogoutRequestResol
|
|||||||
if (this.logger.isTraceEnabled()) {
|
if (this.logger.isTraceEnabled()) {
|
||||||
this.logger.trace("Attempting to resolve registrationId from " + authentication);
|
this.logger.trace("Attempting to resolve registrationId from " + authentication);
|
||||||
}
|
}
|
||||||
if (authentication == null) {
|
Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication);
|
||||||
return null;
|
if (info != null) {
|
||||||
}
|
return info.getRelyingPartyRegistrationId();
|
||||||
Object principal = authentication.getPrincipal();
|
|
||||||
if (principal instanceof Saml2AuthenticatedPrincipal) {
|
|
||||||
return ((Saml2AuthenticatedPrincipal) principal).getRelyingPartyRegistrationId();
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.security.saml2.core.OpenSamlInitializationService;
|
import org.springframework.security.saml2.core.OpenSamlInitializationService;
|
||||||
import org.springframework.security.saml2.core.Saml2Error;
|
import org.springframework.security.saml2.core.Saml2Error;
|
||||||
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||||
@ -130,11 +130,9 @@ final class BaseOpenSamlLogoutRequestValidatorParametersResolver
|
|||||||
if (registrationId != null) {
|
if (registrationId != null) {
|
||||||
return registrationId;
|
return registrationId;
|
||||||
}
|
}
|
||||||
if (authentication == null) {
|
Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication);
|
||||||
return null;
|
if (info != null) {
|
||||||
}
|
return info.getRelyingPartyRegistrationId();
|
||||||
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) {
|
|
||||||
return principal.getRelyingPartyRegistrationId();
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ import org.springframework.security.saml2.core.OpenSamlInitializationService;
|
|||||||
import org.springframework.security.saml2.core.Saml2Error;
|
import org.springframework.security.saml2.core.Saml2Error;
|
||||||
import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
||||||
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||||
@ -217,12 +217,9 @@ final class BaseOpenSamlLogoutResponseResolver implements Saml2LogoutResponseRes
|
|||||||
if (this.logger.isTraceEnabled()) {
|
if (this.logger.isTraceEnabled()) {
|
||||||
this.logger.trace("Attempting to resolve registrationId from " + authentication);
|
this.logger.trace("Attempting to resolve registrationId from " + authentication);
|
||||||
}
|
}
|
||||||
if (authentication == null) {
|
Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication);
|
||||||
return null;
|
if (info != null) {
|
||||||
}
|
return info.getRelyingPartyRegistrationId();
|
||||||
Object principal = authentication.getPrincipal();
|
|
||||||
if (principal instanceof Saml2AuthenticatedPrincipal) {
|
|
||||||
return ((Saml2AuthenticatedPrincipal) principal).getRelyingPartyRegistrationId();
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,8 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
|||||||
import org.springframework.security.saml2.core.Saml2Error;
|
import org.springframework.security.saml2.core.Saml2Error;
|
||||||
import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
||||||
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidator;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters;
|
||||||
@ -329,11 +329,9 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter {
|
|||||||
if (registrationId != null) {
|
if (registrationId != null) {
|
||||||
return registrationId;
|
return registrationId;
|
||||||
}
|
}
|
||||||
if (authentication == null) {
|
Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication);
|
||||||
return null;
|
if (info != null) {
|
||||||
}
|
return info.getRelyingPartyRegistrationId();
|
||||||
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) {
|
|
||||||
return principal.getRelyingPartyRegistrationId();
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,8 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.security.saml2.core.OpenSamlInitializationService;
|
import org.springframework.security.saml2.core.OpenSamlInitializationService;
|
||||||
import org.springframework.security.saml2.core.Saml2Error;
|
import org.springframework.security.saml2.core.Saml2Error;
|
||||||
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
import org.springframework.security.saml2.core.Saml2ParameterNames;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters;
|
import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||||
@ -144,11 +144,9 @@ public final class OpenSamlLogoutRequestValidatorParametersResolver
|
|||||||
if (registrationId != null) {
|
if (registrationId != null) {
|
||||||
return registrationId;
|
return registrationId;
|
||||||
}
|
}
|
||||||
if (authentication == null) {
|
Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication);
|
||||||
return null;
|
if (info != null) {
|
||||||
}
|
return info.getRelyingPartyRegistrationId();
|
||||||
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) {
|
|
||||||
return principal.getRelyingPartyRegistrationId();
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user