Skip to content

Store Clients and Users' Credentials to DB

Wuyi Chen edited this page Jul 3, 2019 · 25 revisions

Overview

For clients and users' credentials, you can store them into memory or database. It is better to store in a database rather than hard-coded in code. If you want to add a new client after starting the authentication service, you can insert a new record to the database rather than changing the code.


Set dependencies

For connecting the database, you need to set the dependencies for JDBC connections.

build.gradle

dependencies {
    compile group: 'org.springframework.boot',           name: 'spring-boot-starter-data-jpa', version: '1.5.0.RELEASE'
    compile group: 'org.springframework.boot',           name: 'spring-boot-autoconfigure',    version: '1.5.0.RELEASE'
    compile group: 'mysql',                              name: 'mysql-connector-java',         version: '5.1.38'
}

Create DB schema

You need to create tables for storing clients' details and users' details to the database.

For clients

For storing clients' details, you need to create the following tables:

  • oauth_client_details

You need to create the schema.sql into the resources directory.

schema.sql

CREATE TABLE oauth_client_details (
  client_id                VARCHAR(256) PRIMARY KEY,  -- the id of the client
  resource_ids             VARCHAR(256),
  client_secret            VARCHAR(256),              -- the password of the client
  scope                    VARCHAR(256),              -- the types of the client can get the access token from the service, separated by comma (,)
  authorized_grant_types   VARCHAR(256),              -- the list of the authorization grant types, separated by comma (,)
  web_server_redirect_uri  VARCHAR(256),
  authorities              VARCHAR(256),              -- the list of roles for the client
  access_token_validity    INTEGER,                   -- the expiry of an access token, by second
  refresh_token_validity   INTEGER,                   -- the expiry of a refresh token, by second
  additional_information   VARCHAR(4096),
  autoapprove              VARCHAR(256)              
);

You can also create client records when you start the authentication service, you can also insert new clients to the database when the service is running. For example

schema.sql

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
    ('eagleeye', 'thisissecret', 'webclient,mobileclient', 'refresh_token,password,client_credentials', 
    null, null, 
    36000, 36000, 
    null, true);

For users

For storing users' details, you need to create the following tables:

  • users
  • authorities (for roles)

You can add the SQL statements in schema.sql for creating those tables.

schema.sql

CREATE TABLE users (
  username  VARCHAR(256)  NOT NULL  PRIMARY KEY,
  password  VARCHAR(256)  NOT NULL,
  enabled   BOOLEAN       NOT NULL
);
  
CREATE TABLE authorities (
  username   VARCHAR(256),
  authority  VARCHAR(256)
);

You can also create user records with authorities when you start the authentication service, you can also insert new users and authorities to the database when the service is running. For example

schema.sql

INSERT INTO users(username,password,enabled) VALUES ('john.carnell',    'password1', true);
INSERT INTO users(username,password,enabled) VALUES ('william.woodward','password2', true);

INSERT INTO authorities(username,authority) VALUES ('john.carnell',    'ADMIN');
INSERT INTO authorities(username,authority) VALUES ('john.carnell',    'USER');
INSERT INTO authorities(username,authority) VALUES ('william.woodward','ADMIN');

Note that if you don't use any password encoder, you need to store plain text in the password column.

Configure Spring to validate credentials with DB

If you want to store credentials in DB and also validate clients and users with DB to give access tokens, you need to configure Spring to do them with DB rather than memory.

For clients

OAuth2Config.java

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private DataSource dataSource;                            // autowire the DataSource for building the connection with DB

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    	clients.jdbc(dataSource);                             // specify Spring to use JDBC (DB) for client's authentication
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                 .userDetailsService(userDetailsService);
    }
}

For users

WebSecurityConfigurer.java

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;                         // autowire the DataSource for building the connection with DB
	
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);  // specify Spring to use JDBC (DB) for client's authentication
    }
}

Encode password

Without password encoders, any password will be stored as plain text in the database, and it is not a good practice for security. Spring supports several types of password encoder so that any password can be stored as encrypted text in the database.

Select a password encoder

There are several password encoders in Spring Security (Deprecated password encoders are not listed):

Package Class Description
org.springframework.security.crypto.bcrypt BCryptPasswordEncoder BCrypt strong hashing
org.springframework.security.crypto.password Pbkdf2PasswordEncoder PBKDF2 with a configurable number of iterations and a random 8-byte random salt value
org.springframework.security.crypto.scrypt SCryptPasswordEncoder SCrypt hashing
org.springframework.security.crypto.password DelegatingPasswordEncoder A password encoder that delegates to another PasswordEncoder based upon a prefixed identifier (format: {password_encoder_name}encrypted_password)

Set the password encoder

You can set the password encoder for clients and users. This is an example of setting BCryptPasswordEncoder at user level.

WebSecurityConfigurer.java

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
	
    private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();            // define password encoder
    
    /* omit other lines */

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    	auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder);  // set password encoder
    }
}

Get the encrypted password

In the database, you need to store the encrypted password based on the password encoder you chose. There are several ways to get the encrypted password:

Way 1: Write a small program to generate the encrypted password

You can create a Java class with the main function so that you can run it independently for generating the encrypted password.

public class Run {
    public static void main(String[] args) {
        BCryptPasswordEncoder passwordEncoder   = new BCryptPasswordEncoder();
        String                encryptedPassword = passwordEncoder.encode("password1");
        System.out.println(encryptedPassword);
    }
}

Way 2: Use online password encryptor to generate the encrypted password

You can use online tools to generate an encrypted password.

Encoder Tool
BCryptPasswordEncoder https://www.devglan.com/online-tools/bcrypt-hash-generator
Pbkdf2PasswordEncoder https://8gwifi.org/pbkdf.jsp
SCryptPasswordEncoder https://8gwifi.org/scrypt.jsp

Way 3: You can create an API endpoint to encrypt the password

You can create an API endpoint to encrypt the password based on the password encoder you chose.

Way 4: You can create an API endpoint for managing clients and users

You can create an API endpoint for adding clients and users. Before inserting a new client or a user into the database, you can encrypt the password.


References

Clone this wiki locally