0% found this document useful (0 votes)
241 views

05 Spring Boot Rest Security

The document discusses securing Spring Boot REST APIs with Spring Security. It covers defining users and roles, protecting URLs based on roles, and storing user data in a database. It provides examples of configuring basic security and restricting access to endpoints based on roles.

Uploaded by

Chotu
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
241 views

05 Spring Boot Rest Security

The document discusses securing Spring Boot REST APIs with Spring Security. It covers defining users and roles, protecting URLs based on roles, and storing user data in a database. It provides examples of configuring basic security and restricting access to endpoints based on roles.

Uploaded by

Chotu
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 72

Spring Boot REST API


Security Overview
You will learn how to …
• Secure Spring Boot REST APIs

• Define users and roles

• Protect URLs based on role

• Store users, passwords and roles in DB (plain-text -> encrypted)

www.luv2code.com
Practical Results

• Cover the most common Spring Security tasks that you will need on daily projects

• Not an A to Z reference … for that you can see Spring Security Reference Manual

http://www.luv2code.com/spring-security-reference-manual

www.luv2code.com
Spring Security Model

• Spring Security defines a framework for security

• Implemented using Servlet filters in the background

• Two methods of securing an app: declarative and programmatic

www.luv2code.com
Spring Security with Servlet Filters

• Servlet Filters are used to pre-process / post-process web requests

• Servlet Filters can route web requests based on security logic

• Spring provides a bulk of security functionality with servlet filters

www.luv2code.com
Spring Security Overview
/mytopsecretstuff

Protected
Web
Resource
Web Spring
Browser Security
Filters
my app users
security passwords
configuration roles

www.luv2code.com
Spring Security in Action

Spring
Security
Filters

www.luv2code.com
Spring Security in Action
Does user have
authorized role?

Spring
Security
Filters
Check if user id and
password are valid

www.luv2code.com
Security Concepts

• Authentication

• Check user id and password with credentials stored in app / db

• Authorization

• Check to see if user has an authorized role

www.luv2code.com
Declarative Security

• Define application’s security constraints in configuration

• All Java config: @Configuration

• Provides separation of concerns between application code and security

www.luv2code.com
Programmatic Security

• Spring Security provides an API for custom application coding

• Provides greater customization for specific app requirements

www.luv2code.com
Enabling Spring Security
1. Edit pom.xml and add spring-boot-starter-security

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

2.This will automagically secure all endpoints for application

www.luv2code.com
Secured Endpoints
• Now when you access your application

• Spring Security will prompt for login


Check console logs
for password

Default user name: user

www.luv2code.com
Spring Security configuration
• You can override default user name and generated password

File: src/main/resources/application.properties

spring.security.user.name=scott
spring.security.user.password=test123

www.luv2code.com
Authentication and Authorization
• In-memory

• JDBC users
passwords
• LDAP roles

• Custom / Pluggable

• others …

We will cover password storage in DB as plain-text AND encrypted

www.luv2code.com
Configuring Basic Security

m
Our Users

User ID Password Roles


john test123 EMPLOYEE

mary test123 EMPLOYEE, MANAGER

susan test123 EMPLOYEE, MANAGER, ADMIN

We can give ANY names


for user roles

www.luv2code.com
Development Process
Step-
By-S
tep

1. Create Spring Security Configuration (@Configuration)

2. Add users, passwords and roles

www.luv2code.com
Step 1: Create Spring Security Configuration

File: DemoSecurityConfig.java

import org.springframework.context.annotation.Configuration;

@Configuration
public class DemoSecurityConfig {

// add our security configurations here …

www.luv2code.com
Spring Security Password Storage
• In Spring Security, passwords are stored using a specific format

{id}encodedPassword

ID Description
noop Plain text passwords

bcrypt BCrypt password hashing

… …

www.luv2code.com
Password Example
The encoding
The password
algorithm id

{noop}test123

Let’s Spring Security


know the passwords are
stored as plain text (noop)

www.luv2code.com
Step 2: Add users, passwords and roles
File: DemoSecurityConfig.java

@Configuration
public class DemoSecurityConfig {

@Bean
public InMemoryUserDetailsManager userDetailsManager() {

UserDetails john = User.builder()


.username("john")
.password("{noop}test123")
.roles("EMPLOYEE")
.build();

UserDetails mary = User.builder()


.username("mary")
.password("{noop}test123")
.roles("EMPLOYEE", "MANAGER")
.build();

UserDetails susan = User.builder()


We will add DB support in
.username("susan") later videos
.password("{noop}test123")
.roles("EMPLOYEE", "MANAGER", "ADMIN")
.build(); (plaintext and encrypted)
return new InMemoryUserDetailsManager(john, mary, susan);
}
}

www.luv2code.com
Restrict Access Based on Roles

m
Our Example

HTTP Method Endpoint CRUD Action Role


GET /api/employees Read all EMPLOYEE
GET /api/employees/{employeeId} Read single EMPLOYEE
POST /api/employees Create MANAGER
PUT /api/employees Update MANAGER
DELETE /api/employees/{employeeId} Delete employee ADMIN

www.luv2code.com
Restricting Access to Roles
• General Syntax Restrict access to a
given path
“/api/employees”

requestMatchers(<< add path to match on >>)


.hasRole(<< authorized role >>)

Single role “ADMIN”

www.luv2code.com
Restricting Access to Roles
Restrict access to a
Specify HTTP method: given path
GET, POST, PUT, DELETE … “/api/employees”

requestMatchers(<< add HTTP METHOD to match on >>, << add path to match on >>)
.hasRole(<< authorized roles >>)

Single role

www.luv2code.com
Restricting Access to Roles

requestMatchers(<< add HTTP METHOD to match on >>, << add path to match on >>)
.hasAnyRole(<< list of authorized roles >>)

Any role Comma-delimited list

www.luv2code.com
Authorize Requests for EMPLOYEE role

requestMatchers(HttpMethod.GET, "/api/employees").hasRole("EMPLOYEE")
requestMatchers(HttpMethod.GET, "/api/employees/**").hasRole("EMPLOYEE")

The ** syntax:
match on all sub-paths

www.luv2code.com
Authorize Requests for MANAGER role

requestMatchers(HttpMethod.POST, "/api/employees").hasRole("MANAGER")
requestMatchers(HttpMethod.PUT, "/api/employees").hasRole("MANAGER")

www.luv2code.com
Authorize Requests for ADMIN role

requestMatchers(HttpMethod.DELETE, "/api/employees/**").hasRole("ADMIN")

www.luv2code.com
Pull It Together
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http.authorizeHttpRequests(configurer ->
configurer
.requestMatchers(HttpMethod.GET, "/api/employees").hasRole("EMPLOYEE")
.requestMatchers(HttpMethod.GET, "/api/employees/**").hasRole("EMPLOYEE")
Use HTTP Basic .requestMatchers(HttpMethod.POST, "/api/employees").hasRole("MANAGER")
Authentication .requestMatchers(HttpMethod.PUT, "/api/employees").hasRole("MANAGER")
.requestMatchers(HttpMethod.DELETE, "/api/employees/**").hasRole("ADMIN"));

// use HTTP Basic authentication


http.httpBasic(Customizer.withDefaults());

return http.build();
}

www.luv2code.com
Cross-Site Request Forgery (CSRF)
• Spring Security can protect against CSRF attacks

• Embed additional authentication data/token into all HTML forms

• On subsequent requests, web app will verify token before processing

• Primary use case is traditional web applications (HTML forms etc …)

www.luv2code.com
When to use CSRF Protection?
• The Spring Security team recommends

• Use CSRF protection for any normal browser web requests

• Traditional web apps with HTML forms to add/modify data

• If you are building a REST API for non-browser clients

• you may want to disable CSRF protection

• In general, not required for stateless REST APIs

• That use POST, PUT, DELETE and/or PATCH

www.luv2code.com
Pull It Together
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http.authorizeHttpRequests(configurer ->
configurer
.requestMatchers(HttpMethod.GET, "/api/employees").hasRole("EMPLOYEE")
.requestMatchers(HttpMethod.GET, "/api/employees/**").hasRole("EMPLOYEE")
.requestMatchers(HttpMethod.POST, "/api/employees").hasRole("MANAGER")
.requestMatchers(HttpMethod.PUT, "/api/employees").hasRole("MANAGER")
.requestMatchers(HttpMethod.DELETE, "/api/employees/**").hasRole("ADMIN"));

// use HTTP Basic authentication


http.httpBasic(Customizer.withDefaults());

// disable Cross Site Request Forgery (CSRF) In general, CSRF is not required for
http.csrf(csrf -> csrf.disable());
stateless REST APIs that use
return http.build(); POST, PUT, DELETE and/or PATCH
}

www.luv2code.com
Spring Security
User Accounts Stored in Database

m
Database Access
• So far, our user accounts were hard coded in Java source code

• We want to add database access Advan


ced

www.luv2code.com
Recall Our User Roles

User ID Password Roles


john test123 EMPLOYEE

mary test123 EMPLOYEE, MANAGER

susan test123 EMPLOYEE, MANAGER, ADMIN

www.luv2code.com
Database Support in Spring Security Out-o
f-the-
box
• Spring Security can read user account info from database

• By default, you have to follow Spring Security’s predefined table schemas

Spring JDBC
Security Code

www.luv2code.com
Customize Database Access with Spring Security

• Can also customize the table schemas

• Useful if you have custom tables specific to your project / custom

• You will be responsible for developing the code to access the data

• JDBC, JPA/Hibernate etc …

www.luv2code.com
Database Support in Spring Security Out-o
f-the-
box
• Follow Spring Security’s predefined table schemas

Spring JDBC
Security Code

www.luv2code.com
Development Process
Step-
By-S
tep
1. Develop SQL Script to set up database tables

2. Add database support to Maven POM file

3.Create JDBC properties file

4. Update Spring Security Configuration to use JDBC

www.luv2code.com
Default Spring Security Database Schema

“authorities” same as “roles”

www.luv2code.com
Step 1: Develop SQL Script to setup database tables

CREATE TABLE `users` (


`username` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
`enabled` tinyint NOT NULL,

PRIMARY KEY (`username`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

www.luv2code.com
Step 1: Develop SQL Script to setup database tables
The encoding algorithm id
The password

INSERT INTO `users`


VALUES
('john','{noop}test123',1),
('mary','{noop}test123',1),
('susan','{noop}test123',1);

Let’s Spring Security know the


passwords are stored as plain text
(noop)

www.luv2code.com
Step 1: Develop SQL Script to setup database tables

CREATE TABLE `authorities` (


`username` varchar(50) NOT NULL,
`authority` varchar(50) NOT NULL,

UNIQUE KEY `authorities_idx_1` (`username`,`authority`),

CONSTRAINT `authorities_ibfk_1`
FOREIGN KEY (`username`)
REFERENCES `users` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

www.luv2code.com
Step 1: Develop SQL Script to setup database tables
“authorities” same as “roles”

INSERT INTO `authorities`


VALUES
('john','ROLE_EMPLOYEE'),
('mary','ROLE_EMPLOYEE'),
('mary','ROLE_MANAGER'),
('susan','ROLE_EMPLOYEE'),
('susan','ROLE_MANAGER'),
('susan','ROLE_ADMIN');

Internally Spring Security uses


“ROLE_” prefix

www.luv2code.com
Step 2: Add Database Support to Maven POM file

<!-- MySQL -->


<dependency> JDBC Driver
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>

www.luv2code.com
Step 3: Create JDBC Properties File
File: application.properties
#
# JDBC connection properties
#
spring.datasource.url=jdbc:mysql://localhost:3306/employee_directory
spring.datasource.username=springstudent
spring.datasource.password=springstudent

www.luv2code.com
Step 4: Update Spring Security to use JDBC
Inject data source
Auto-configured by Spring Boot
@Configuration
public class DemoSecurityConfig {

@Bean
public UserDetailsManager userDetailsManager(DataSource dataSource) {

return new JdbcUserDetailsManager(dataSource);


} No longer
hard-coding users :-)

} Tell Spring Security to use
JDBC authentication
with our data source

www.luv2code.com
Spring Security
Password Encryption

© luv2code LLC
Password Storage
• So far, our user passwords are stored in plaintext … yikes!

• Ok for getting started … but not for production / real-time project :-(

www.luv2code.com © luv2code LLC


Password Storage - Best Practice Best P
ractic
e
• The best practice is store passwords in an encrypted format

Encrypted version of password

www.luv2code.com © luv2code LLC


Spring Security Team Recommendation

• Spring Security recommends using the popular bcrypt algorithm

• bcrypt

• Performs one-way encrypted hashing

• Adds a random salt to the password for additional protection

• Includes support to defeat brute force attacks

www.luv2code.com © luv2code LLC


Bcrypt Additional Information
• Why you should use bcrypt to hash passwords

www.luv2code.com/why-bcrypt

• Detailed bcrypt algorithm analysis

www.luv2code.com/bcrypt-wiki-page

• Password hashing - Best Practices

www.luv2code.com/password-hashing-best-practices

www.luv2code.com © luv2code LLC


How to Get a Bcrypt password

You have a plaintext password and you want to encrypt using bcrypt

• Option 1: Use a website utility to perform the encryption

• Option 2: Write Java code to perform the encryption

www.luv2code.com © luv2code LLC


How to Get a Bcrypt password - Website
• Visit: www.luv2code.com/generate-bcrypt-password

• Enter your plaintext password

• The website will generate a bcrypt password for you

www.luv2code.com © luv2code LLC


DEMO
www.luv2code.com © luv2code LLC
Development Process
Step-
By-S
tep

1. Run SQL Script that contains encrypted passwords

Modify DDL for password field, length should be 68

THAT’S IT … no need to change Java source code :-)

www.luv2code.com © luv2code LLC


Spring Security Password Storage
• In Spring Security, passwords are stored using a specific format

Password column must be at least 68 chars wide


{bcrypt}encodedPassword
{bcrypt} - 8 chars
encodedPassword - 60 chars

www.luv2code.com © luv2code LLC


Modify DDL for Password Field

CREATE TABLE `users` (


Password column must be at least 68 chars wide
`username` varchar(50) NOT NULL,
`password` char(68) NOT NULL, {bcrypt} - 8 chars
`enabled` tinyint NOT NULL, encodedPassword - 60 chars

PRIMARY KEY (`username`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

www.luv2code.com © luv2code LLC


Step 1: Develop SQL Script to setup database tables
The encoding
algorithm id
The encrypted password: fun123
INSERT INTO `users`
VALUES
(‘john','{bcrypt}$2a$10$qeS0HEh7urweMojsnwNAR.vcXJeXR1UcMRZ2WcGQl9YeuspUdgF.q',1),

Let’s Spring Security know the


passwords are stored as
encrypted passwords: bcrypt

www.luv2code.com © luv2code LLC


Step 1: Develop SQL Script to setup database tables
The encoding
algorithm id
The encrypted password: fun123
INSERT INTO `users`
VALUES
(‘john','{bcrypt}$2a$10$qeS0HEh7urweMojsnwNAR.vcXJeXR1UcMRZ2WcGQl9YeuspUdgF.q',1),

('mary','{bcrypt}$2a$04$eFytJDGtjbThXa80FyOOBuFdK2IwjyWefYkMpiBEFlpBwDH.5PM0K',1),

('susan','{bcrypt}$2a$04$eFytJDGtjbThXa80FyOOBuFdK2IwjyWefYkMpiBEFlpBwDH.5PM0K',1);

www.luv2code.com © luv2code LLC


Spring Security Login Process

User enters
plaintext password

Spring
REST
Security
Client
Filters

www.luv2code.com © luv2code LLC


Spring Security Login Process

Note:
The password from db is
NEVER decrypted

Because bcrypt is a
1. Retrieve password from db for the user one-way
encryption algorithm
2. Read the encoding algorithm id (bcrypt etc)

3. For case of bcrypt, encrypt plaintext password from login form (using salt from db password)

4. Compare encrypted password from login form WITH encrypted password from db

5. If there is a match, login successful

6. If no match, login NOT successful

www.luv2code.com © luv2code LLC


Spring Security
Custom Tables

© luv2code LLC
Default Spring Security Database Schema

www.luv2code.com © luv2code LLC


Custom Tables
• What if we have our own custom tables?

• Our own custom column names?

This is all custom


Nothing matches with default Spring Security table schema

www.luv2code.com © luv2code LLC


For Security Schema Customization
• Tell Spring how to query your custom tables

• Provide query to find user by user name

• Provide query to find authorities / roles by user name

www.luv2code.com © luv2code LLC


Development Process
Step-
By-S
tep
1. Create our custom tables with SQL

2. Update Spring Security Configuration


• Provide query to find user by user name

• Provide query to find authorities / roles by user name

www.luv2code.com © luv2code LLC


Step 1: Create our custom tables with SQL

This is all custom


Nothing matches with default Spring Security table schema

www.luv2code.com © luv2code LLC


Step 2: Update Spring Security Configuration

@Configuration
public class DemoSecurityConfig {

@Bean
public UserDetailsManager userDetailsManager(DataSource dataSource) {
JdbcUserDetailsManager theUserDetailsManager = new JdbcUserDetailsManager(dataSource);

theUserDetailsManager
.setUsersByUsernameQuery("select user_id, pw, active from members where user_id=?");

theUserDetailsManager
.setAuthoritiesByUsernameQuery("select user_id, role from roles where user_id=?");

return theUserDetailsManager;
}

www.luv2code.com © luv2code LLC


Step 2: Update Spring Security Configuration

@Configuration
public class DemoSecurityConfig {

@Bean
public UserDetailsManager userDetailsManager(DataSource dataSource) {
JdbcUserDetailsManager theUserDetailsManager = new JdbcUserDetailsManager(dataSource);

theUserDetailsManager How to find users


.setUsersByUsernameQuery("select user_id, pw, active from members where user_id=?");

theUserDetailsManager
.setAuthoritiesByUsernameQuery("select user_id, role from roles where user_id=?");
How to find roles
return theUserDetailsManager;
}


Question mark “?”
}
Parameter value will be the
user name from login

www.luv2code.com © luv2code LLC

You might also like