Summary

I have configured Spring Security with SAML2 (SP Initiated) and OAuth2 Client implementation for user authentication. Both mechanisms uses an IDP to authenticate the User.

I have also configured OAuth2 Resource Server that take JWT Tokens to authorize for the protected resources.

There are two points that I want to achieve:

1 - Use the SAML assertion as means of authentication in request to allow further processing. Validate SAML Assertion using the configured IDP configurations that authenticated the user in first place. 2 - Use SAML assertion to exchange it for JWT Token for the User using the OAuth2Client configurations.

Similar scenario has been reported at following: https://stackoverflow.com/q/76035118/8919671 https://stackoverflow.com/q/71766820/8919671

Security Configuration

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/", "/login")
                .permitAll().and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .saml2Login().defaultSuccessUrl("/dashboard")
                .and()
                .oauth2ResourceServer(oauth2 -> oauth2.jwt())
                .oauth2Login(
                        oauth2 -> oauth2.
                                defaultSuccessUrl("/dashboard", true)
                )
                .logout().logoutSuccessUrl("/login").and()
                .logout(logout -> logout
                        .deleteCookies("remove")
                        .invalidateHttpSession(true)
                        .logoutSuccessUrl("/login")
                        .logoutSuccessHandler(oidcLogoutSuccessHandler())
                )
                .saml2Logout(Customizer.withDefaults())
        ;
        return http.build();
    }

    private LogoutSuccessHandler oidcLogoutSuccessHandler() {
        OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler =
                new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);
        oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
        return oidcLogoutSuccessHandler;
    }

    @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
    String jwkSetURI;

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder
                .withJwkSetUri(jwkSetURI)
                .jwtProcessorCustomizer(customizer -> {
                    customizer.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("at+jwt")));
                })
                .build();
    }

Application Configurations in application.yml


provider:
  host: https://localhost:9443
spring:
  security:
    basic:
      enabled: false
    saml2:
    # Issuer: {baseUrl}/saml2/service-provider-metadata/wso2
    # Assertion Consumer URL: {baseUrl}/login/saml2/sso/wso2
    # SLO Response Accepting URL: {baseUrl}/logout/saml2/slo
    # SLO Request Accepting URL: {baseUrl}/logout/saml2/slo
      relyingparty:
        registration:
          wso2:
            signing:
              credentials:
                - private-key-location: classpath:saml2/local.key
                  certificate-location: classpath:saml2/local.crt
            singlelogout:
              binding: POST
              response-url: "{baseUrl}/logout/saml2/slo"
            assertingparty:
              #metadata-uri: classpath:saml2/metadata_okta_idp.xml
               metadata-uri: classpath:saml2/metadata_wso2_idp.xml
    # OAuth2 Resource Server Configurations
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: ${provider.host}/oauth2/token
          jwk-set-uri: ${provider.host}/oauth2/jwks
      client:
      #OAUTH2 Code Configurations
      # Authorization CallBack: ${baseUrl}/login/oauth2/code/{registrationId}
        registration:
          wso2:
            client-name: OAuth2 OIDC - WSO2 IS
            client-id: psr2YA51P......f2VvXUa
            client-secret: 5qhez......W4KEa
            authorization-grant-type: authorization_code
            scope: openid
            logout-callback: http://localhost:${server.port}/login
        provider:
          wso2:
            issuer-uri: ${provider.host}/oauth2/token

build.gradle


    // OAUTH2 Client
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    // OAUTH Resource Server
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'

    // saml2 dependencies
    constraints {
        implementation "org.opensaml:opensaml-core:4.2.0"
        implementation "org.opensaml:opensaml-saml-api:4.2.0"
        implementation "org.opensaml:opensaml-saml-impl:4.2.0"
    }
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
    implementation 'org.springframework.security:spring-security-saml2-service-provider'

Version

Spring Boot v2.7.10, Spring v5.3.26 OpenSAML: 4.2.0

Comment From: jzheaux

Thanks, @muhammad438, I responded to your SO question. I'll close this issue in favor of continuing the conversation over there.