Spring Security 5.1 - Obtener simbólico de credenciales del cliente de flujo con WebClient

Darren Forsythe:

Estoy intentando conseguir un portador a través de un símbolo webclientcon la siguiente configuración para una prueba de integración de un servidor de recursos asegurado en una aplicación de servlet.

spring:
  security:
    oauth2:
      client:
        registration:
          idp:
            clientId: id
            clientSecret: secret
            authorization-grant-type: client_credentials
            scope: read
        provider:
          idp:
            authorization-uri: myidp/authorization.oauth2
            token-uri: myidp/token.oauth2
            user-info-uri: myidp/userinfo.openid
            user-name-attribute: name

Y frijoles,

    @Bean
    WebClient webClient(ClientRegistrationRepository clientRegistrations,
            OAuth2AuthorizedClientRepository authorizedClients) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
        // oauth.setDefaultOAuth2AuthorizedClient(true);
        // (optional) set a default ClientRegistration.registrationId
        // oauth.setDefaultClientRegistrationId("client-registration-id");
        return WebClient.builder().apply(oauth.oauth2Configuration()).build();
    }

y Autowiring la webclient a una prueba y decir que es como tal,

webClient.get().uri("http://localhost:" + port + "/web/it")
                .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("idp")).retrieve()
                .bodyToMono(String.class).block();

Es mi suposición de la función de intercambio, ya sea conseguiría un token de acceso si está disponible, o hacer una llamada para obtener uno nuevo desde el IDP. Sin embargo, siempre se producirá un error como el HttpSessionOAuth2AuthorizedClientRepositoryque el HttpServletRequestes nulo.

Con la prueba general que parece, esto alimenta en una configuración automática para configurar algunos granos para un proveedor de IDP.

@SpringBootTest(classes = WebITApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
@ActiveProfiles("web-it")
class WebJwtIt {

    @LocalServerPort
    private int port;

    @Autowired
    private WebClient webClient;

    @Test
    void testIdpJwt() {

        String response = webClient.get().uri("http://localhost:" + port + "/web/it")
                .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("ping")).retrieve()
                .bodyToMono(String.class).block();
        assertThat(response).isEqualTo("pass");
    }

    @RestController
    @SpringBootApplication
    @ImportAutoConfiguration(IdpAutoConfiguration.class)
    static class WebITApplication implements IdpSecurityAdapter {

              @Bean
    WebClient webClient(ClientRegistrationRepository clientRegistrations,
            OAuth2AuthorizedClientRepository authorizedClients) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
        // oauth.setDefaultOAuth2AuthorizedClient(true);
        // (optional) set a default ClientRegistration.registrationId
        // oauth.setDefaultClientRegistrationId("client-registration-id");
        return WebClient.builder().apply(oauth.oauth2Configuration()).build();
    }
        public static void main(String args[]) {

            new SpringApplicationBuilder().profiles("web-it").build().run(WebITApplication.class, args);
        }

        @GetMapping
        public String secured() {
            return "secured";
        }

        @GetMapping("/web/it")
        public String securedOne() {
            return "pass";
        }

        @Override
        public void configure(final HttpSecurity httpSecurity) throws IdpSecurityAdapterException {
            try {
                httpSecurity.oauth2Client();
            } catch (Exception e) {
                throw new IdpSecurityAdapterException("Failed to Configure Oauth2Client", e);
            }
        }

        @Override
        public IdpProvider getIdpProvider() {
            return IdpProvider.MyIdp;
        }
    }

¿Hay alguna forma para un cliente Web para obtener el token para mí y añadirlo a la solicitud? Sé que esto era posible con el spring-security-oauth:OAuthRestTemplatey la lectura de la documentación pensé que era posible con un cliente web.

Florent Cornes:

El problema aquí es que usted no está de instancias el cliente Web de la manera correcta.

Como usted está en el lado del cliente , usted no tiene acceso a una OAuth2AuthorizedClientRepository. Este bean se supone que debe estar vinculada a una Sever recurso en el que se acceda a utilizar la .oauth2Login()declaración de método en la HttpSecurityconfiguración. Estos detalles se explican en la primavera de Seguridad 5 OAuth2 de sesión .

Una vez más, usted está en el lado del cliente por lo que lo que necesita es una función de filtro de intercambio, lo que disparará una solicitud a un servidor de autorización para obtener un token JWT. Se puede utilizar el ServerOAuth2AuthorizedClientExchangeFilterFunctionlugar.

Es mejor utilizar una WebClientCustomizerpara agregar la función de filtro de intercambio en el filtro de cliente Web. Por qué ? Simplemente porque la inyección en la aplicación de un resorte WebClient.Builderle permitirá acceder a las métricas nativos vinculados a los intercambios web.

Por lo tanto, se va a construir su cliente Web utilizando una nueva instancia de un UnAuthenticatedServerOAuth2AuthorizedClientRepositorygrano de la siguiente manera:

// Use injection to get an in-memory reposiroty or client registrations
@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrations) {

    // Provides support for an unauthenticated user such as an application
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
            clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());

    // Build up a new WebClientCustomizer implementation to inject the oauth filter
    // function into the WebClient.Builder instance
    return new WebClientSecurityCustomizer(oauth);
}

Como usted está en el lado del cliente , no asocia a un usuario para su proceso, por eso no se puede utilizar cualquier repositorio cliente instanciation frijol autorizado. Compruebe en la documentación de la primavera de Seguridad: documentación de la primavera de Seguridad: Clase UnAuthenticatedServerOAuth2AuthorizedClientRepository .

Traté de resumir un caso de demostración en el siguiente proyecto de GitHub: GitHub - escenario de la primavera de Seguridad OAuth2 de máquina a máquina .

Espero que esto le da más puntos de vista sobre la configuración del cliente Web. Por favor, pregunte si tiene alguna pregunta.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=202374&siteId=1
Recomendado
Clasificación