Simple Single Sign-On avec Spring Security OAuth2

Authentification unique simple avec Spring Security OAuth2

1. Vue d'ensemble

Dans ce didacticiel, nous allons expliquer comment implémenter SSO - Single Sign On - à l'aide de Spring Security OAuth et Spring Boot.

Nous utiliserons trois applications distinctes:

  • Un serveur d'autorisation - qui est le mécanisme d'authentification central

  • Deux applications clientes: les applications utilisant l'authentification unique

En termes très simples, lorsqu'un utilisateur tente d'accéder à une page sécurisée dans l'application cliente, il est redirigé pour s'authentifier en premier, via le serveur d'authentification.

Et nous allons utiliser le type d'octroiAuthorization Code hors d'OAuth2 pour piloter la délégation d'authentification.

Lectures complémentaires:

Spring Security 5 - Connexion à OAuth2

Apprenez à authentifier les utilisateurs avec Facebook, Google ou d'autres informations d'identification à l'aide de OAuth2 dans Spring Security 5.

Read more

Nouveautés dans Spring Security OAuth2 - Verify Claims

Introduction pratique rapide au nouveau support de vérification des revendications dans Spring Security OAuth.

Read more

Une connexion secondaire à Facebook avec Spring Social

Voici un aperçu de la mise en œuvre d’une authentification Facebook à côté d’une application Spring standard de connexion par formulaire.

Read more

 

Avant de commencer - une note importante. Gardez à l'esprit quethe Spring Security core team is in the process of implementing a new OAuth2 stack - avec certains aspects déjà sortis et d'autres encore en cours.

Voici une courte vidéo qui vous donnera un aperçu de cet effort:

 

Très bien, allons-y.

2. L'application client

Commençons par notre application client; nous allons, bien sûr, utiliser Spring Boot pour minimiser la configuration:

2.1. Dépendances Maven

Tout d'abord, nous aurons besoin des dépendances suivantes dans nospom.xml:


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-security


    org.springframework.security.oauth.boot
    spring-security-oauth2-autoconfigure
    2.0.1.RELEASE


    org.springframework.boot
    spring-boot-starter-thymeleaf


    org.thymeleaf.extras
    thymeleaf-extras-springsecurity4

2.2. Configuration de sécurité

Ensuite, la partie la plus importante, la configuration de la sécurité de notre application cliente:

@Configuration
@EnableOAuth2Sso
public class UiSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**")
          .authorizeRequests()
          .antMatchers("/", "/login**")
          .permitAll()
          .anyRequest()
          .authenticated();
    }
}

La partie centrale de cette configuration est, bien sûr, l'annotation@EnableOAuth2Sso que nous utilisons pour activer l'authentification unique.

Notez que nous devons étendre lesWebSecurityConfigurerAdapter - sans cela, tous les chemins seront sécurisés - de sorte que les utilisateurs seront redirigés pour se connecter lorsqu'ils essaieront d'accéder à n'importe quelle page. Dans notre cas, les pages d'index et de connexion sont les seules pages accessibles sans authentification.

Enfin, nous avons également défini un beanRequestContextListener pour gérer les portées des requêtes.

Et lesapplication.yml:

server:
    port: 8082
    servlet:
        context-path: /ui
    session:
      cookie:
        name: UISESSION
security:
  basic:
    enabled: false
  oauth2:
    client:
      clientId: SampleClientId
      clientSecret: secret
      accessTokenUri: http://localhost:8081/auth/oauth/token
      userAuthorizationUri: http://localhost:8081/auth/oauth/authorize
    resource:
      userInfoUri: http://localhost:8081/auth/user/me
spring:
  thymeleaf:
    cache: false

Quelques notes rapides:

  • nous avons désactivé l'authentification de base par défaut

  • accessTokenUri est l'URI pour obtenir les jetons d'accès

  • userAuthorizationUri est l'URI d'autorisation vers laquelle les utilisateurs seront redirigés

  • userInfoUri l'URI du point de terminaison de l'utilisateur pour obtenir les détails de l'utilisateur actuel

Notez également que, dans notre exemple, nous avons déployé notre serveur d'autorisations, mais nous pouvons bien entendu également utiliser d'autres fournisseurs tiers, tels que Facebook ou GitHub.

2.3. L'extrémité avant

Voyons maintenant la configuration frontale de notre application cliente. Nous n'allons pas nous concentrer sur cela ici, principalement parce que nousalready covered in on the site.

Notre application client a ici un front-end très simple; voici lesindex.html:

Spring Security SSO

Login

Et lessecuredPage.html:

Secured Page

Welcome, Name

La pagesecuredPage.html nécessitait que les utilisateurs soient authentifiés. Si un utilisateur non authentifié tente d'accéder àsecuredPage.html, il sera d'abord redirigé vers la page de connexion.

3. Le serveur d'authentification

Parlons maintenant de notre serveur d’autorisation ici.

3.1. Dépendances Maven

Tout d'abord, nous devons définir les dépendances dans nospom.xml:


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.security.oauth
    spring-security-oauth2
    2.3.3.RELEASE

3.2. Configuration OAuth

Il est important de comprendre que nous allons exécuter ici le serveur d’autorisation et le serveur de ressources en une seule unité déployable.

Commençons par la configuration de notre serveur de ressources, qui sert également d’application de démarrage principale:

@SpringBootApplication
@EnableResourceServer
public class AuthorizationServerApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(AuthorizationServerApplication.class, args);
    }
}

Ensuite, nous configurerons notre serveur d'autorisation:

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Override
    public void configure(
      AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()")
          .checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
          .withClient("SampleClientId")
          .secret(passwordEncoder.encode("secret"))
          .authorizedGrantTypes("authorization_code")
          .scopes("user_info")
          .autoApprove(true)
          .redirectUris(
            "http://localhost:8082/ui/login","http://localhost:8083/ui2/login");
    }
}

Notez que nous n'activons qu'un client simple utilisant le type de subventionauthorization_code.

Notez également commentautoApprove est défini sur true afin que nous ne soyons pas redirigés et promus pour approuver manuellement les étendues.

3.3. Configuration de sécurité

Tout d'abord, nous allons désactiver l'authentification de base par défaut, via nosapplication.properties:

server.port=8081
server.servlet.context-path=/auth

Passons maintenant à la configuration et définissons un mécanisme de connexion par formulaire simple:

@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers()
          .antMatchers("/login", "/oauth/authorize")
          .and()
          .authorizeRequests()
          .anyRequest().authenticated()
          .and()
          .formLogin().permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("john")
            .password(passwordEncoder().encode("123"))
            .roles("USER");
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

Notez que nous avons utilisé une simple authentification en mémoire, mais nous pouvons simplement la remplacer par unuserDetailsService personnalisé.

3.4. Point de terminaison de l'utilisateur

Enfin, nous allons créer notre point de terminaison utilisateur que nous avons utilisé précédemment dans notre configuration:

@RestController
public class UserController {
    @GetMapping("/user/me")
    public Principal user(Principal principal) {
        return principal;
    }
}

Naturellement, cela renverra les données utilisateur avec une représentation JSON.

4. Conclusion

Dans ce rapide tutoriel, nous nous sommes concentrés sur la mise en œuvre de Single Sign On à l'aide de Spring Security Oauth2 et de Spring Boot.

Comme toujours, le code source complet peut être trouvéover on GitHub.