web-dev-qa-db-fra.com

Gérer les exceptions de sécurité dans Spring Boot Resource Server

Comment puis-je obtenir mon ResponseEntityExceptionHandler ou OAuth2ExceptionRenderer Personnalisé pour gérer les exceptions déclenchées par la sécurité Spring sur un serveur de ressources pur?

Nous avons mis en place un

@ControllerAdvice
@RestController
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

donc chaque fois qu'il y a une erreur sur le serveur de ressources, nous voulons qu'il réponde avec

{
  "message": "...",
  "type": "...",
  "status": 400
}

Le serveur de ressources utilise le paramètre application.properties:

security.oauth2.resource.userInfoUri: http://localhost:9999/auth/user

pour authentifier et autoriser une demande sur notre serveur d'authentification.

Cependant, toute erreur de sécurité du printemps contournera toujours notre gestionnaire d'exceptions à l'adresse

    @ExceptionHandler(InvalidTokenException.class)
    public ResponseEntity<Map<String, Object>> handleInvalidTokenException(InvalidTokenException e) {
        return createErrorResponseAndLog(e, 401);
    }

et produire soit

{
  "timestamp": "2016-12-14T10:40:34.122Z",
  "status": 403,
  "error": "Forbidden",
  "message": "Access Denied",
  "path": "/api/templates/585004226f793042a094d3a9/schema"
}

ou

{
  "error": "invalid_token",
  "error_description": "5d7e4ab5-4a88-4571-b4a4-042bce0a076b"
}

Alors, comment configurer la gestion des exceptions de sécurité pour un serveur de ressources? Tout ce que je trouve, ce sont des exemples sur la façon de personnaliser le serveur Auth en implémentant un OAuth2ExceptionRenderer Personnalisé. Mais je ne trouve pas où câbler cela à la chaîne de sécurité du serveur de ressources.

Notre seule configuration/installation est la suivante:

@SpringBootApplication
@Configuration
@ComponentScan(basePackages = {"our.packages"})
@EnableAutoConfiguration
@EnableResourceServer
15
Pete

Si vous utilisez @EnableResourceServer, Vous pouvez également trouver utile d'étendre ResourceServerConfigurerAdapter au lieu de WebSecurityConfigurerAdapter dans votre classe @Configuration. En procédant ainsi, vous pouvez simplement enregistrer un AuthenticationEntryPoint personnalisé en remplaçant configure(ResourceServerSecurityConfigurer resources) et en utilisant resources.authenticationEntryPoint(customAuthEntryPoint()) dans la méthode.

Quelque chose comme ça:

@Configuration
@EnableResourceServer
public class CommonSecurityConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(customAuthEntryPoint());
    }

    @Bean
    public AuthenticationEntryPoint customAuthEntryPoint(){
        return new AuthFailureHandler();
    }
}

Il existe également un joli OAuth2AuthenticationEntryPoint Qui peut être étendu (car il n'est pas définitif) et partiellement réutilisé lors de l'implémentation d'un AuthenticationEntryPoint personnalisé. En particulier, il ajoute des en-têtes "WWW-Authenticate" avec des détails liés aux erreurs.

6
Vladimir Salin

Vous ne pouvez pas utiliser les annotations du gestionnaire d'exceptions Spring MVC telles que @ControllerAdvice parce que les filtres de sécurité Spring interviennent bien avant Spring MVC.

3
so-random-dude

Si vous utilisez une URL de validation de jeton avec une configuration similaire à Configuration du serveur de ressources avec RemoteTokenServices dans Spring Security Oauth2 qui renvoie l'état HTTP 401 en cas de non autorisé:

@Primary
@Bean
public RemoteTokenServices tokenService() {
    RemoteTokenServices tokenService = new RemoteTokenServices();
    tokenService.setCheckTokenEndpointUrl("https://token-validation-url.com");
    tokenService.setTokenName("token");
    return tokenService;
}

L'implémentation de authenticationEntryPoint personnalisé comme décrit dans d'autres réponses ( https://stackoverflow.com/a/44372313/5962766 ) ne fonctionnera pas car RemoteTokenService use 400 status et lève des exceptions non gérées pour d'autres statuts comme 401:

public RemoteTokenServices() {
        restTemplate = new RestTemplate();
        ((RestTemplate) restTemplate).setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            // Ignore 400
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 400) {
                    super.handleError(response);
                }
            }
        });
}

Vous devez donc définir un RestTemplate personnalisé dans RemoteTokenServices config qui gérerait 401 sans lever d'exception:

@Primary
@Bean
public RemoteTokenServices tokenService() {
    RemoteTokenServices tokenService = new RemoteTokenServices();
    tokenService.setCheckTokenEndpointUrl("https://token-validation-url.com");
    tokenService.setTokenName("token");
    RestOperations restTemplate = new RestTemplate();
    restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
    ((RestTemplate) restTemplate).setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            // Ignore 400 and 401
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401) {
                    super.handleError(response);
                }
            }
        });
    }
    tokenService.setRestTemplate(restTemplate);
    return tokenService;
}

Et ajoutez une dépendance pour HttpComponentsClientHttpRequestFactory :

<dependency>
  <groupId>org.Apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
</dependency>
2
Justas

OAuth2ExceptionRenderer est destiné à un serveur d'autorisation. La bonne réponse est susceptible de le gérer comme détaillé dans cet article (c'est-à-dire, ignorer qu'il s'agit de oauth et le traiter comme tout autre mécanisme d'authentification de sécurité de printemps): https: // stackoverflow.com/a/26502321/5639571

Bien sûr, cela interceptera oauth exceptions liées (qui sont levées avant que vous n'atteigniez votre point de terminaison de ressource), mais toutes les exceptions se produisant dans votre point de terminaison de ressource nécessiteront toujours une méthode @ExceptionHandler.

1
Nikolai Luthman