In case if you missed it, here is the place to grab.
http://blog.rajithdelantha.com/2015/09/secure-your-rest-api-with-spring.html
Spring boot is one of the new inventions from Spring framework that makes developers' lives easier when building large scale applications. Here is a good place to grab the concepts.
If you check my previous post related to oauth2 security then you know there is a bit of configuration that needs to be done in Spring side. But on the other hand Spring boot will do all the hard work and we just need to tell them what to do by a simple annotation.
So this post is about how to configure Spring boot project with Spring security and Oauth2. Actually we can't really say configure because all most all configurations are done by Spring boot itself.
Source code : https://github.com/rajithd/spring-boot-oauth2
Step 1
For this project I'm using H2 in memory database. Because of that you don't need to create any database and tables as the creation happens at run time. But if you want this project to use MySQL as the data source then first create the database and then create the tables.
CREATE TABLE user (
username VARCHAR(50) NOT NULL PRIMARY KEY,
email VARCHAR(50),
password VARCHAR(500),
activated BOOLEAN DEFAULT FALSE,
activationkey VARCHAR(50) DEFAULT NULL,
resetpasswordkey VARCHAR(50) DEFAULT NULL
);
CREATE TABLE authority (
name VARCHAR(50) NOT NULL PRIMARY KEY
);
CREATE TABLE user_authority (
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL,
FOREIGN KEY (username) REFERENCES user (username),
FOREIGN KEY (authority) REFERENCES authority (name),
UNIQUE INDEX user_authority_idx_1 (username, authority)
);
CREATE TABLE oauth_access_token (
token_id VARCHAR(256) DEFAULT NULL,
token BLOB,
authentication_id VARCHAR(256) DEFAULT NULL,
user_name VARCHAR(256) DEFAULT NULL,
client_id VARCHAR(256) DEFAULT NULL,
authentication BLOB,
refresh_token VARCHAR(256) DEFAULT NULL
);
CREATE TABLE oauth_refresh_token (
token_id VARCHAR(256) DEFAULT NULL,
token BLOB,
authentication BLOB
);
- user table - system users
- authority - roles
- user_authority - many to many table for user and role
- oauth_access_token - to hold access_token
- oauth_refresh_token - to hold refresh_token
Add some seed data.
INSERT INTO user (username,email, password, activated) VALUES ('admin', 'admin@mail.me', 'b8f57d6d6ec0a60dfe2e20182d4615b12e321cad9e2979e0b9f81e0d6eda78ad9b6dcfe53e4e22d1', true);
INSERT INTO user (username,email, password, activated) VALUES ('user', 'user@mail.me', 'd6dfa9ff45e03b161e7f680f35d90d5ef51d243c2a8285aa7e11247bc2c92acde0c2bb626b1fac74', true);
INSERT INTO user (username,email, password, activated) VALUES ('rajith', 'rajith@abc.com', 'd6dfa9ff45e03b161e7f680f35d90d5ef51d243c2a8285aa7e11247bc2c92acde0c2bb626b1fac74', true);
INSERT INTO authority (name) VALUES ('ROLE_USER');
INSERT INTO authority (name) VALUES ('ROLE_ADMIN');
INSERT INTO user_authority (username,authority) VALUES ('rajith', 'ROLE_USER');
INSERT INTO user_authority (username,authority) VALUES ('user', 'ROLE_USER');
INSERT INTO user_authority (username,authority) VALUES ('admin', 'ROLE_USER');
INSERT INTO user_authority (username,authority) VALUES ('admin', 'ROLE_ADMIN');
Step 2
Configure WebSecurityAdapter
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/h2console/**")
.antMatchers("/api/register")
.antMatchers("/api/activate")
.antMatchers("/api/lostpassword")
.antMatchers("/api/resetpassword");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
private static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
}
Step 3
Configuration for Oauth2
@Configuration
public class OAuth2Configuration {
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
.disable()
.headers()
.frameOptions().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/hello/**").permitAll()
.antMatchers("/secure/**").authenticated();
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
.authorizedGrantTypes("password", "refresh_token")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800));
}
@Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
}
}
This is it. Try running Spring boot application by
mvn spring-boot:run
Then check your oauth2 security by executing following curls.
https://github.com/rajithd/spring-boot-oauth2