Поддержка нескольких grant_type с Spring security в одном приложении

#spring #spring-boot #spring-security #oauth-2.0 #spring-security-oauth2

#spring #spring-boot #spring-безопасность #oauth-2.0 #spring-security-oauth2

Вопрос:

Легко ли настраивается в Spring Security, чтобы приложение использовало 2 разных grant_type?

Наше приложение Java BE предназначено для использования двумя разными пользователями через приложение Angular FE. Тип пользователя определяется как заголовок запроса:

  • Сотрудники: Должны проходить аутентификацию с помощью authorization_code.
  • Обычные пользователи в Интернете: они аутентифицируются через client_credentials.

Нам удалось определить это в application.properties:

 #employee user
spring.security.oauth2.client.registration.employee.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.employee.authorization-uri=https://saml.company.com/oauth/authorize
spring.security.oauth2.client.registration.employee.redirect-uri=https://appDomain.com/appContext/login/oauth2/code/employee
spring.security.oauth2.client.provider.employee.token-uri=https://saml.company.com/oauth/token
spring.security.oauth2.client.registration.employee.scope=theScope
spring.security.oauth2.client.registration.employee.client-id=CLIENT_ID1
spring.security.oauth2.client.registration.employee.client-secret=SECRET

#general user
spring.security.oauth2.client.registration.direct.authorization-grant-type=client_credentials
spring.security.oauth2.client.provider.direct.token-uri=https://saml.company.com/oauth/token
spring.security.oauth2.client.registration.direct.client-id=CLIENT_ID2
spring.security.oauth2.client.registration.direct.client-secret=SECRET
  

Основная проблема заключается в том, что неподтвержденные вызовы для обоих типов пользователей (сотрудники и обычные пользователи) перенаправляются на стандартную страницу Spring / login, на которой отображаются 2 HTML-ссылки привязки к двум различным потокам / grant_type.

Требуемое поведение является:

  • Для пользователя Employee прямое перенаправление на spring.security.oauth2.client.provider.employee.авторизация-uri для ввода его / ее учетных данных в IDP в соответствии с потоком authorization_code.
  • Для обычного пользователя BE должен обрабатывать поток client_credentials, поскольку нет взаимодействия с пользователем.

Мы пытались с помощью фильтров избежать перенаправления / login, но безрезультатно. Есть идеи?

Комментарии:

1. Вы могли бы написать пользовательскую страницу входа вместо страницы входа по умолчанию.

2. Какую версию spring security вы используете? Насколько я понимаю, эта конфигурация создает два клиента oauth2 в клиентском репозитории BE apps, чтобы у вашего приложения BE могло быть два клиента oauth2 для связи с внешними серверами ресурсов oauth2. это то, что вы здесь хотите?

Ответ №1:

Вы можете определить несколько WebSecurityConfigurerAdapter, как показано ниже, для каждого отдельного URI.

 @EnableWebSecurity
public class SecurityConfig {


@Configuration
@Order(1)
public static class SubscriptionWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        LOGGER.debug("SubscriptionWebSecurityConfigurerAdapter.configure start");
        // Enable CORS and disable CSRF
        http = http.cors().and().csrf().disable();

        // Set session management to stateless
        http = http
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and();


        // Set unauthorized requests exception handler
        http = http
                .exceptionHandling()
                .authenticationEntryPoint(
                        (request, response, ex) -> {
                            response.sendError(
                                    HttpServletResponse.SC_UNAUTHORIZED,
                                    ex.getMessage()
                            );
                        }
                )
                .and();

        http.authorizeRequests()
            .antMatchers("/subs**").permitAll()
                .and()  ;

        LOGGER.debug("SubscriptionWebSecurityConfigurerAdapter.configure end");
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers("/subs**");
    }
}

@Configuration
@Order(2)
public static class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        LOGGER.debug("ManagementWebSecurityConfigurerAdapter.configure start");
        http.antMatcher("/management/**")
            .authorizeRequests()
            .mvcMatchers("/management/monitoringService/taskmanagers").hasAnyRole("ADMIN", "OPERATOR")
            .mvcMatchers("/management/sendOperationReport").hasAnyRole("ADMIN", "OPERATOR", "CONSUMER")
            .anyRequest().permitAll();

        LOGGER.debug("ManagementWebSecurityConfigurerAdapter.configure end");
    }

}

@Order(3)
@Configuration
public static class WPSWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    private final String issuer;

    public WPSWebSecurityConfigurerAdapter(OAuth2ResourceServerProperties resourceServerProps) {
        this.issuer = resourceServerProps.getJwt().getIssuerUri();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        LOGGER.debug("WPSWebSecurityConfigurerAdapter.configure start");
        http.antMatcher("/wps/**")
            .authorizeRequests()
            .mvcMatchers("/wps/WebProcessingService").authenticated()
            .anyRequest().authenticated()
            .and().oauth2ResourceServer()
            .authenticationEntryPoint(new CustomOAuth2AuthenticationEntryPoint())
            .accessDeniedHandler(new CustomOAuth2AccessDeniedHandler())
            .jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());

        LOGGER.debug("WPSWebSecurityConfigurerAdapter.configure end");
    }

    @Bean
    JwtDecoder jwtDecoder() {
        LOGGER.debug("WPSWebSecurityConfigurerAdapter.jwtDecoder start");
        NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
        OAuth2TokenValidator<Jwt> validatorWithIssuer = JwtValidators.createDefaultWithIssuer(issuer);
        DelegatingOAuth2TokenValidator validator = new DelegatingOAuth2TokenValidator<>(validatorWithIssuer);
        jwtDecoder.setJwtValidator(validator);
        LOGGER.debug("WPSWebSecurityConfigurerAdapter.jwtDecoder end");
        return jwtDecoder;
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix("");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
}
  

}