OAuth2.0 et enregistrement de client dynamique

OAuth2.0 and Dynamic Client Registration

1. introduction

Dans ce tutoriel, nous allons préparer un enregistrement de client dynamique avec OAuth2.0. OAuth2.0 est un cadre d'autorisation permettant d'obtenir un accès limité aux comptes d'utilisateur sur un service HTTP. Le client OAuth2.0 est l'application qui souhaite accéder au compte de l'utilisateur. Ce client peut être une application Web externe, un agent utilisateur ou tout simplement un client natif.

Afin de réaliser une inscription client dynamique, nous allons stocker les informations d'identification dans la base de données au lieu d'une configuration codée en dur. L'application que nous allons étendre a été initialement décrite dansSpring REST API + OAuth2 tutorial.

2. Dépendances Maven

Nous allons d’abord configurer l’ensemble de dépendances suivant:


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


    org.springframework
    spring-jdbc


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

Notez que nous utilisonsspring-jdbc car nous allons utiliser une base de données pour stocker les nouveaux utilisateurs enregistrés avec des mots de passe.

3. OAuth2.0 Server Configuration

Premièrement, nous devons configurer notre serveur d’autorisation OAuth2.0. La configuration principale est à l'intérieur de la classe suivante:

@Configuration
@PropertySource({ "classpath:persistence.properties" })
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig
  extends AuthorizationServerConfigurerAdapter {

    // config
}

Il y a quelques éléments majeurs que nous devons configurer; commençons parClientDetailsServiceConfigurer:

@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
    clients.jdbc(dataSource())

    // ...
}

Cela garantira que nous utilisons la persistance pour obtenir les informations client.

Configurons bien sûr cette source de données standard:

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();

    dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
    dataSource.setUrl(env.getProperty("jdbc.url"));
    dataSource.setUsername(env.getProperty("jdbc.user"));
    dataSource.setPassword(env.getProperty("jdbc.pass"));
    return dataSource;
}

Ainsi, notre application utilisera désormais la base de données comme source de clients enregistrés, au lieu des clients classiques codés en dur dans la mémoire.

4. Le schéma DB

Définissons maintenant la structure SQL pour stocker nos clients OAuth:

create table oauth_client_details (
    client_id VARCHAR(256) PRIMARY KEY,
    resource_ids VARCHAR(256),
    client_secret VARCHAR(256),
    scope VARCHAR(256),
    authorized_grant_types VARCHAR(256),
    web_server_redirect_uri VARCHAR(256),
    authorities VARCHAR(256),
    access_token_validity INTEGER,
    refresh_token_validity INTEGER,
    additional_information VARCHAR(4096),
    autoapprove VARCHAR(256)
);

Les champs les plus importants desoauth_client_details sur lesquels nous devrions nous concentrer sont:

  • client_id - pour stocker l'ID des clients nouvellement enregistrés

  • client_secret - pour stocker le mot de passe des clients

  • access_token_validity - qui indique si le client est toujours valide

  • authorities - pour indiquer quels rôles sont autorisés avec un client particulier

  • scope - actions autorisées, par exemple écrire des statuts sur Facebook, etc.

  • authorized_grant_types, qui fournit des informations sur la manière dont les utilisateurs peuvent se connecter au client particulier (dans notre exemple, il s'agit d'un formulaire de connexion avec mot de passe)

Veuillez noter que chaque client a une relation un à plusieurs avec les utilisateurs, ce qui signifie naturellement quemultiple users can utilize a single client.

5. Persistons certains clients

Avec la définition du schéma SQL, nous pouvons enfin créer des données dans le système et définir un client.

Nous allons utiliser le scriptdata.sql suivant - que Spring Boot exécutera par défaut - pour initialiser la base de données:

INSERT INTO oauth_client_details
    (client_id, client_secret, scope, authorized_grant_types,
    web_server_redirect_uri, authorities, access_token_validity,
    refresh_token_validity, additional_information, autoapprove)
VALUES
    ("fooClientIdPassword", "secret", "foo,read,write,
    "password,authorization_code,refresh_token", null, null, 36000, 36000, null, true);

La description des champs les plus importants enoauth_client_details est fournie dans la section précédente.

6. Essai

Afin de tester l'enregistrement dynamique du client, nous devons exécuter les projetsspring-security-oauth-server etspring-security-oauth-resource, respectivement sur les ports 8081 et 8082.

Maintenant, nous pouvons enfin écrire quelques tests en direct.

Supposons que nous ayons enregistré un client avec l'ID nomméfooClientIdPassword, qui a un accès pour lire les foos.

Tout d'abord, nous allons essayer d'obtenir un jeton d'accès du serveur d'authentification, en utilisant un client déjà défini:

@Test
public void givenDBUser_whenRevokeToken_thenAuthorized() {
    String accessToken = obtainAccessToken("fooClientIdPassword", "john", "123");

    assertNotNull(accessToken);
}

Et voici la logique d'obtention du jeton d'accès:

private String obtainAccessToken(String clientId, String username, String password) {
    Map params = new HashMap();
    params.put("grant_type", "password");
    params.put("client_id", clientId);
    params.put("username", username);
    params.put("password", password);
    Response response = RestAssured.given().auth().preemptive()
      .basic(clientId, "secret").and().with().params(params).when()
      .post("http://localhost:8081/spring-security-oauth-server/oauth/token");
    return response.jsonPath().getString("access_token");
}

7. Conclusion

Dans ce tutoriel, nous avons appris à enregistrer de manière dynamique un nombre illimité de clients avec la structure OAuth2.0.

L'implémentation complète de ce didacticiel peut être trouvéeover on GitHub - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.

Veuillez noter que pour effectuer le test, vous devrez ajouter des clients dans la base de données et que la configuration de.inMemory() ne sera plus valide. Si vous souhaitez utiliser l'ancienne configuration.inMemory(), il existe un deuxième fichier contenant la configuration avec des clients codés en dur.