From c4d2b3cdfd472547843623f27439de6594debbc6 Mon Sep 17 00:00:00 2001 From: sudhakaropsmx Date: Mon, 21 Oct 2024 17:41:53 +0530 Subject: [PATCH] OP-22767: Bugfix for SAML2 Authentication Validation InResponseTo and Assertion disable flags --- .../saml/SamlSecurityConfiguration.java | 71 ++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/gate-saml/src/main/java/com/opsmx/spinnaker/gate/security/saml/SamlSecurityConfiguration.java b/gate-saml/src/main/java/com/opsmx/spinnaker/gate/security/saml/SamlSecurityConfiguration.java index 5213afdc21..f3743e9e96 100644 --- a/gate-saml/src/main/java/com/opsmx/spinnaker/gate/security/saml/SamlSecurityConfiguration.java +++ b/gate-saml/src/main/java/com/opsmx/spinnaker/gate/security/saml/SamlSecurityConfiguration.java @@ -16,6 +16,9 @@ package com.opsmx.spinnaker.gate.security.saml; +import static org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_ASSERTION; +import static org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_IN_RESPONSE_TO; + import com.netflix.spectator.api.Registry; import com.netflix.spinnaker.fiat.shared.FiatClientConfigurationProperties; import com.netflix.spinnaker.gate.config.AuthConfig; @@ -28,7 +31,9 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.opensaml.saml.saml2.core.Assertion; import org.springframework.beans.factory.annotation.Autowired; @@ -46,6 +51,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; @@ -90,6 +97,12 @@ public class SamlSecurityConfiguration { public static final String defaultFilterUrl = "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI; + @Value("${spring.security.saml2.validation.inresponseto:false}") + private boolean ignoreInResponseToValidation; + + @Value("${spring.security.saml2.validation.assertion:false}") + private boolean ignoreAssertionValidation; + @Bean public UserDetailsService userDetailsService() { return username -> { @@ -112,6 +125,14 @@ public RememberMeServices rememberMeServices(UserDetailsService userDetailsServi public OpenSaml4AuthenticationProvider authenticationProvider() { var authProvider = new OpenSaml4AuthenticationProvider(); authProvider.setResponseAuthenticationConverter(extractUserDetails()); + log.debug("ignoreAssertionValidation :{}", ignoreAssertionValidation); + if (ignoreAssertionValidation) { + authProvider.setAssertionValidator(removeAssertionError()); + } + log.debug("ignoreInResponseToValidation :{}", ignoreInResponseToValidation); + if (ignoreInResponseToValidation) { + authProvider.setResponseValidator(removeInResonseToError()); + } return authProvider; } @@ -208,7 +229,7 @@ public SecurityFilterChain samlFilterChain( return responseToken -> { List roles = new ArrayList<>(); - log.debug("responseToken : {}", responseToken); + log.debug("responseToken : {}", responseToken.getToken().getSaml2Response()); Saml2Authentication authentication = delegate.convert(responseToken); Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal(); @@ -276,6 +297,54 @@ public SecurityFilterChain samlFilterChain( }; } + private Converter + removeAssertionError() { + log.debug("**remove assertion error from Saml2ResponseValidatorResult Errors**"); + Converter + delegate = OpenSaml4AuthenticationProvider.createDefaultAssertionValidator(); + return assertionToken -> { + log.debug("responseToken : {}", assertionToken.getToken().getSaml2Response()); + Saml2ResponseValidatorResult result = delegate.convert(assertionToken); + result + .getErrors() + .forEach( + error -> + log.debug( + " error code :{} and description :{}", + error.getErrorCode(), + error.getDescription())); + Collection errors = + result.getErrors().stream() + .filter((error) -> !error.getErrorCode().equals(INVALID_ASSERTION)) + .collect(Collectors.toList()); + return Saml2ResponseValidatorResult.failure(errors); + }; + } + + private Converter + removeInResonseToError() { + log.debug("**remove InResonseTo error from Saml2ResponseValidatorResult Errors**"); + Converter + delegate = OpenSaml4AuthenticationProvider.createDefaultResponseValidator(); + return responseToken -> { + log.debug("responseToken : {}", responseToken.getToken().getSaml2Response()); + Saml2ResponseValidatorResult result = delegate.convert(responseToken); + result + .getErrors() + .forEach( + error -> + log.debug( + " error code :{} and description :{}", + error.getErrorCode(), + error.getDescription())); + Collection errors = + result.getErrors().stream() + .filter((error) -> !error.getErrorCode().equals(INVALID_IN_RESPONSE_TO)) + .collect(Collectors.toList()); + return Saml2ResponseValidatorResult.failure(errors); + }; + } + private void loginWithRoles(String username, List roles) { var id = registry.createId("fiat.login").withTag("type", "saml");