OAuth2.0 e registro de cliente dinâmico

OAuth2.0 and Dynamic Client Registration

1. Introdução

Neste tutorial, prepararemos um registro dinâmico de cliente com o OAuth2.0. O OAuth2.0 é uma estrutura de autorização que permite obter acesso limitado a contas de usuário em um serviço HTTP. O cliente OAuth2.0 é o aplicativo que deseja acessar a conta do usuário. Esse cliente pode ser um aplicativo Web externo, um agente de usuário ou apenas um cliente nativo.

Para obter o registro de cliente dinâmico, vamos armazenar as credenciais no banco de dados, em vez da configuração codificada. O aplicativo que vamos estender foi descrito inicialmente emSpring REST API + OAuth2 tutorial.

2. Dependências do Maven

Primeiro, configuraremos o seguinte conjunto de dependências:


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


    org.springframework
    spring-jdbc


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

Observe que estamos usandospring-jdbc porque vamos usar um banco de dados para armazenar os usuários recém-registrados com senhas.

3. OAuth2.0 Server Configuration

Primeiro, precisamos configurar nosso servidor de autorização OAuth2.0. A configuração principal está dentro da seguinte classe:

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

    // config
}

Existem algumas coisas importantes que precisamos configurar; vamos começar comClientDetailsServiceConfigurer:

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

    // ...
}

Isso garantirá que estamos usando persistência para obter as informações do cliente.

Vamos, é claro, configurar esta fonte de dados padrão:

@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;
}

E assim, agora, nosso aplicativo usará o banco de dados como fonte de clientes registrados, em vez dos típicos codificados em clientes de memória.

4. O Esquema DB

Vamos agora definir a estrutura SQL para armazenar nossos clientes 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)
);

Os campos mais importantes deoauth_client_details nos quais devemos nos concentrar são:

  • client_id - para armazenar a id de clientes recém-registrados

  • client_secret - para armazenar a senha dos clientes

  • access_token_validity - que indica se o cliente ainda é válido

  • authorities - para indicar quais funções são permitidas com um cliente específico

  • scope - ações permitidas, por exemplo, escrever status no Facebook etc.

  • authorized_grant_types, que fornece informações de como os usuários podem fazer login em um cliente específico (em nosso caso de exemplo, é um login de formulário com senha)

Observe que cada cliente tem um relacionamento de um para vários com os usuários, o que naturalmente significa quemultiple users can utilize a single client.

5. Vamos Persistir Alguns Clientes

Com a definição do esquema SQL, podemos finalmente criar alguns dados no sistema - e basicamente definir um cliente.

Vamos usar o seguinte scriptdata.sql - que Spring Boot irá executar por padrão - para inicializar o banco de dados:

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);

A descrição dos campos mais importantes emoauth_client_details é fornecida na seção anterior.

6. Teste

Para testar o registro de cliente dinâmico, precisamos executar os projetosspring-security-oauth-serverespring-security-oauth-resource, nas portas 8081 e 8082, respectivamente.

Agora, finalmente podemos escrever alguns testes ao vivo.

Vamos supor que registramos o cliente com id chamadofooClientIdPassword, que tem acesso para ler foos.

Primeiro, vamos tentar obter um token de acesso do servidor Auth, usando um cliente já definido:

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

    assertNotNull(accessToken);
}

E aqui está a lógica para obter o token de acesso:

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. Conclusão

Neste tutorial, aprendemos como registrar dinamicamente um número ilimitado de clientes com a estrutura OAuth2.0.

A implementação completa deste tutorial pode ser encontradaover on GitHub - este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.

Observe que, para testar, você precisará adicionar clientes ao banco de dados e que a configuração.inMemory() não será mais válida. Se você quiser usar a configuração antiga.inMemory(), há um segundo arquivo contendo a configuração com clientes codificados.