Search code examples
springspring-security

Spring security oauth2Login based on request matcher


New to spring security and i will like to apply different realm (realm1) login for certain pages and a different one for the rest of the pages (realm2): Tried:

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
            .authorizeHttpRequests( authorize -> authorize
                    .requestMatchers(AntPathRequestMatcher.antMatcher("/customers")).authenticated()
            )
            .oauth2Login().loginPage("/oauth2/authorization/realm1");

    http
            .csrf().disable()
            .authorizeHttpRequests( authorize -> authorize
                    .anyRequest().authenticated()
            )
            .oauth2Login().loginPage("/oauth2/authorization/realm2");

    return http.build();
}

@Bean
public ClientRegistrationRepository clientRepository() {

    return new InMemoryClientRegistrationRepository(realm1ClientRegistration(), realm2ClientRegistration());
}

private ClientRegistration realm1ClientRegistration() {

    return ClientRegistration.withRegistrationId("webeam")
            .clientId(realm1ClientId)
            .clientSecret(realm1ClientSecret)
            .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
            .scope("openid","groups", "profile", "email")
            .clientAuthenticationMethod(ClientAuthenticationMethod.POST)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .authorizationUri(issuerUrl+realm1+"authorize")
            .tokenUri(issuerUrl+realm1+"access_token")
            .userInfoUri(issuerUrl+realm1+"userinfo")
            .jwkSetUri(issuerUrl+realm1+"connect/jwk_uri")
            .userNameAttributeName(IdTokenClaimNames.SUB)
            .build();
}

private ClientRegistration realm2ClientRegistration() {

    return ClientRegistration.withRegistrationId("realm2")
            .clientId(realm2ClientId)
            .clientSecret(realm2ClientSecret)
            .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
            .scope("openid","groups", "profile", "email")
            .clientAuthenticationMethod(ClientAuthenticationMethod.POST)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .authorizationUri(issuerUrl+realm2+"authorize")
            .tokenUri(issuerUrl+realm2+"access_token")
            .userInfoUri(issuerUrl+realm2+"userinfo")
            .jwkSetUri(issuerUrl+realm2+"connect/jwk_uri")
            .userNameAttributeName(IdTokenClaimNames.SUB)
            .build();
}

But it seems like it ignores the matcher "/customers" and only defaults to one realm.

Thanks


Solution

  • I think your issue is that you keep overriding the login page value for each request and that is why you end up supporting a single realm. What I think may work for you is to have separate Spring configurations to support your 2 scenarios and make your intention clearer. For example:

    @Configuration
    public class SecurityConfiguration {
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SecurityFilterChain configurationScenario1(HttpSecurity http) throws Exception {
            return http
                    .securityMatcher("/customers/**")
                    .csrf(CsrfConfigurer::disable)
                    .authorizeHttpRequests(authorize -> authorize
                            .anyRequest().authenticated()
                    )
                    .oauth2Login(configurer -> configurer.loginPage("/oauth2/authorization/realm1"))
                    .build();
        }
    
        @Bean
        @Order(Ordered.LOWEST_PRECEDENCE)
        public SecurityFilterChain configurationScenario2(HttpSecurity http) throws Exception {
            NegatedRequestMatcher noCustomersMatcher = new NegatedRequestMatcher(new AntPathRequestMatcher("/customers/**"));
            return http
                    .securityMatcher(noCustomersMatcher)
                    .csrf(CsrfConfigurer::disable)
                    .authorizeHttpRequests(authorize -> authorize
                            .anyRequest().authenticated()
                    )
                    .oauth2Login(configurer -> configurer.loginPage("/oauth2/authorization/realm2"))
                    .build();
        }
    }
    

    NOTE 1: that configurationScenario1 makes use of .securityMatcher("/customers") to decide whether to execute rest of the configuration or go to the next configuration.

    NOTE 2: This configuration makes use of Spring Security 6, and you seem to be using Spring Security 5, just so you know that there are differences described here.