Spring OAuth2 : Multiple clients using jdbc

1. Scenario

Suppose you have a rest api for developers who can use your online services on their app. And of course it's not an open api that everyone can access. Each of them needs a client id and a secret to access your resource. What would you do? Give them the same in memory client id and secret?
Of course not. You wouldn't have any control over your api and your users(consumers who use your api's) then. You need to set up a mechanism to differentiate each of your consumers so that they can only access your api's if you want them to and control how much resources each of them can access.
Let's apply this mechanism in our code. We'll use database to store client inforamtions and use them when we need.

(FYI: Before proceeding to this article: Implementing OAuth2 in Spring Boot with Spring security. )

2. Create a model for Client

This class represents each of your OAuth2 clients.

@Entity
@Table(name = "oauth_client_details")
public class OAuth2Client extends BaseEntity {
    @Column(name = "client_id", nullable = false)
    private String clientId;
    @Column(name = "resource_ids")
    private String resourceIds;
    @Column(name = "client_secret", nullable = false)
    private String clientSecret;
    @Column(name = "scope", nullable = false)
    private String scope;
    @Column(name = "authorized_grant_types", nullable = false)
    private String grantTypes;
    @Column(name = "web_server_redirect_uri")
    private String webServerRedirectUri;
    @Column(name = "authorities", nullable = false)
    private String authorities;
    @Column(name = "access_token_validity", nullable = false)
    private Integer accessTokenValidity;
    @Column(name = "refresh_token_validity")
    private Long refreshTokenValidity;
    @Column(name = "additional_information", length = 4096)
    private String additionalInfo;
    @Column(name = "autoapprove")
    private String autoApprove;

    // Getters and Setters

}

Look, I've specified each column name with @Column(). These column names should exactly be same as it is here if you want to use jdbc datasource instead of using ClientDetailsService. We'll discuss about configuring ClientDetailsService in future.

3. Authorization Server configuration

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;

    @Qualifier("dataSource")
    @Autowired
    private DataSource dataSource;

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
//                .inMemory().withClient("android-client")
//                .authorizedGrantTypes("client-credentials", "password", "refresh_token")
//                .authorities("ROLE_CLIENT", "ROLE_ANDROID_CLIENT")
//                .scopes("read", "write", "trust")
//                .resourceIds("oauth2-resource")
//                .accessTokenValiditySeconds(5000)
//                .secret("android-secret").refreshTokenValiditySeconds(50000);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }
}

Here, on public void configure(ClientDetailsServiceConfigurer clients)
method we've used jdbc datasource for configuring OAuth2 client instead of in memory configurations (commented codes). Oh wait! We've used DataSource by autowiring it, but haven't configured it yet! Well, if you've specified datasource properties on application.properties file in spring boot, it's already configured. Otherwise you can configure your datasource by creating this bean on any class that has @Configuration annotation on it.

4. Configuring Datasource

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

    dataSource.setDriverClassName(this.datasourceDriverClassname);
    dataSource.setUrl(this.datasourceUrl);
    dataSource.setUsername(this.datasourceUsername);
    dataSource.setPassword(this.datasourcePassword);
    return dataSource;
}

You're ready to go.

5. Test if it works

Now, create a client by inserting a row on your database table (for testing purpose of course). I've added a sql insert query for it here.

INSERT INTO `oauth_client_details` (`id`, `created`, `last_updated`, `access_token_validity`, `additional_information`, `authorities`, `autoapprove`, `client_id`, `client_secret`, `authorized_grant_types`, `refresh_token_validity`, `resource_ids`, `scope`, `web_server_redirect_uri`) VALUES (1, '2017-11-20 13:14:37', NULL, 5000, NULL, 'ROLE_USER', NULL, '6nuajulfgbkfhm1umjr05clniu', '5gs0n2t7mij5mo2hhbck424c01', 'password,refresh_token', 1209600000, NULL, 'read,write,trust', NULL);

This will insert a client row on oauth_client_details table. Now you can use your client id and secret to get OAuth2 tokens from your api.

http://localhost:8080/oauth/token?grant_type=password&client_id=6nuajulfgbkfhm1umjr05clniu&client_secret=5gs0n2t7mij5mo2hhbck424c01&username=your_username&password=your_password




May be you should take a look at this article Implementing OAuth2 in Spring Boot with Spring security





Comments

Post a Comment

Popular posts from this blog

Deploy Spring Boot app in digitalocean cloud (or any cloud as long asyou have ssh access)

Upload large files : Spring Boot

User activity logging: Spring