0% found this document useful (0 votes)
16 views12 pages

Secure REST APIs with Spring Boot

Security review by mistake

Uploaded by

ajayhumendra
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views12 pages

Secure REST APIs with Spring Boot

Security review by mistake

Uploaded by

ajayhumendra
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

===========================================

How to secure REST APIs using Spring Boot


============================================

-> Security is very important for every web application

-> To protect our application & application data we need to implement security
logic

-> Spring Security concept we can use to secure our web applications / REST APIs

-> To secure our spring boot application we need to add below starter in [Link]
file

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Note: When we add this dependency in [Link] file then by default our
application will be secured with basic authentication. It will generate random
password to access our application.

Note: Generated Random Password will be printed on console.

-> We need to use below credentials to access our application

Username : user

Password : <copy the pwd from console>

-> When we access our application url in browser then it will display "Login
Form" to authenticate our request.

-> To access secured REST API from postman, we need to set Auth values in
POSTMAN to send the request

Auth : Basic Auth


Username : user
Password : <copy-from-console>

=====================================================
How to override Spring Security Default Credentials
=====================================================

-> To override Default credentials we can configre security credentials in


[Link] file or [Link] file like below

[Link]=ashokit
[Link]=ashokit@123

-> After configuring credentials like above, we need to give above credentials
to access our application / api.
=====================================
How to secure specific URL Patterns
=====================================

-> When we add 'security-starter' in [Link] then it will apply security filter
for all the HTTP methods of our application.

-> But in reality we need to secure only few methods not all methods in our
application.

For Example

/ login-page --> security not required

/ transfer ---> security required

/ balance ---> security required

/about-us ---> security not required

-> In order to achieve above requirement we need to Customize Security


Configuration in our project like below

@Configuration
@EnableWebSecurity
public class SecurityConfigurer {

@Bean
public SecurityFilterChain securityFilter(HttpSecurity http) throws
Exception{

[Link]((request) -> request


.antMatchers("/","/login","/about", "/swagger-
[Link]").permitAll()
.anyRequest().authenticated()
).formLogin();

return [Link]();
}
}

==============================================
Spring Boot Security with JDBC Authentication
==============================================

Step-1 ) Setup Database tables with required data

-- users table structure

CREATE TABLE `users` (


`username` VARCHAR(50) NOT NULL,
`password` VARCHAR(120) NOT NULL,
`enabled` TINYINT(1) NOT NULL,
PRIMARY KEY (`username`)
);

-- authorities table structure


CREATE TABLE `authorities` (
`username` VARCHAR(50) NOT NULL,
`authority` VARCHAR(50) NOT NULL,
KEY `username` (`username`),
CONSTRAINT `authorities_ibfk_1` FOREIGN KEY (`username`)
REFERENCES `users` (`username`)
);

===================== Online Encrypt : [Link]


==============================

-- insert records into table

insert into users values ('admin',


'$2a$12$e9oIZjBeSJDryJ/P5p1Ep.WPzJ3f4.C2vHC/as1E22R25XXGpPYyG', 1);
insert into users values ('user',
'$2a$12$JQiGAJhdSOoTXAzIpbDxpemXcYHCmxYOnodLNBeNORH8J4FLxHGvK', 1);

insert into authorities values ('admin', 'ROLE_ADMIN');


insert into authorities values ('admin', 'ROLE_USER');
insert into authorities values ('user', 'ROLE_USER');

Step-2) Create Boot application with below dependencies

a) web-starter
b) security-starter
c) data-jdbc
d) mysql-connector
e) lombok
f) devtools

Step-3 ) Configure Data source properties in [Link] file

spring:
datasource:
driver-class-name: [Link]
password: AshokIT@123
url: jdbc:mysql://localhost:3306/sbms27
username: ashokit
jpa:
show-sql: true

Step-4) Create Rest Controller with Required methods

@RestController
public class UserRestController {

@GetMapping(value = "/admin")
public String admin() {
return "<h3>Welcome Admin :)</h3>";
}

@GetMapping(value = "/user")
public String user() {
return "<h3>Hello User :)</h3>";
}
@GetMapping(value = "/")
public String welcome() {
return "<h3>Welcome :)</h3>";
}

Step-5) Create Security Configuration class like below with Jdbc Authentication
Manager

package [Link];

import [Link];

import [Link];
import [Link];
import [Link];
import
[Link]
ationManagerBuilder;
import [Link];
import
[Link]
ty;
import [Link];
import [Link];

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

private static final String ADMIN = "ADMIN";


private static final String USER = "USER";

@Autowired
private DataSource dataSource;

@Autowired
public void authManager(AuthenticationManagerBuilder auth) throws
Exception {
[Link]()
.dataSource(dataSource)
.passwordEncoder(new BCryptPasswordEncoder())
.usersByUsernameQuery("select username,password,enabled from
users where username=?")
.authoritiesByUsernameQuery("select username,authority from
authorities where username=?");
}

@Bean
public SecurityFilterChain securityConfig(HttpSecurity http) throws
Exception {

[Link]( (req) -> req


.antMatchers("/admin").hasRole(ADMIN)
.antMatchers("/user").hasAnyRole(ADMIN,USER)
.antMatchers("/").permitAll()
.anyRequest().authenticated()
).formLogin();

return [Link]();
}

===========
OAuth 2.0
===========

1) Create Spring Boot application with below dependencies

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

2) Create OAuth app in [Link]

(Login --> Settings --> Developer Settings --> OAuth Apps --> Create App
--> Copy Client ID & Client Secret)

3) Configure GitHub OAuth App client id & client secret in [Link] file
like below

spring:
security:
oauth2:
client:
registration:
github:
clientId:
clientSecret:

4) Create Rest Controller with method

@RestController
public class WelcomeRestController {

@GetMapping("/")
public String welcome() {
return "Welcome to Ashok IT";
}
}

5) Run the application and test it.

=====================
Spring Boot with JWT
=====================

-> JWT stands for JSON Web Tokens


-> JSON Web Tokens are an open, industry standard RFC 7519 method for
representing claims securely between two parties.

-> JWT official Website : [Link]

-> Below is the sample JWT Token

token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6I
kpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5
c

-> JWT contains below 3 parts

1) Header
2) Payload
3) Signature

Note: JWT 3 parts will be seperated by using dot(.)

=========================================================
1) Create Spring Boot appliation with below dependencies
=========================================================
<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>[Link]</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

===================================================
2) Create Request and Response Binding Classes
===================================================
@Data

public class AuthenticationRequest implements Serializable {

private String username;


private String password;
}

public class AuthenticationResponse implements Serializable {

private final String jwt;

public AuthenticationResponse(String jwt) {


[Link] = jwt;
}

public String getJwt() {


return jwt;
}
}

=============================================================
3) Create UserDetailsService for credentials configuration
=============================================================

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

import [Link];

@Service
public class MyUserDetailsService implements UserDetailsService {

@Override
public UserDetails loadUserByUsername(String s) throws
UsernameNotFoundException {
return new User("admin",
"$2a$12$e9oIZjBeSJDryJ/P5p1Ep.WPzJ3f4.C2vHC/as1E22R25XXGpPYyG", new
ArrayList<>());
}
}

===================================================
4) Create JwtUtils class
===================================================
@Service
public class JwtUtil {

private String SECRET_KEY = "secret";

public String extractUsername(String token) {


return extractClaim(token, Claims::getSubject);
}

public Date extractExpiration(String token) {


return extractClaim(token, Claims::getExpiration);
}

public <T> T extractClaim(String token, Function<Claims, T> claimsResolver)


{
final Claims claims = extractAllClaims(token);
return [Link](claims);
}
private Claims extractAllClaims(String token) {
return
[Link]().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}

private Boolean isTokenExpired(String token) {


return extractExpiration(token).before(new Date());
}

public String generateToken(UserDetails userDetails) {


Map<String, Object> claims = new HashMap<>();
return createToken(claims, [Link]());
}

private String createToken(Map<String, Object> claims, String subject) {

return [Link]()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date([Link]()))
.setExpiration(new Date([Link]() + 1000 *
60 * 60 * 10))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}

public Boolean validateToken(String token, UserDetails userDetails) {


final String username = extractUsername(token);
return ([Link]([Link]()) && !
isTokenExpired(token));
}
}

===================================================
5) Create Filter class
===================================================

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

@Autowired
private MyUserDetailsService userDetailsService;

@Autowired
private JwtUtil jwtUtil;

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {

final String authorizationHeader = [Link]("Authorization");

String username = null;


String jwt = null;

if (authorizationHeader != null &&


[Link]("Bearer ")) {
jwt = [Link](7);
username = [Link](jwt);
}

if (username != null &&


[Link]().getAuthentication() == null) {

UserDetails userDetails =
[Link](username);

if ([Link](jwt, userDetails)) {

UsernamePasswordAuthenticationToken
usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, [Link]());
usernamePasswordAuthenticationToken
.setDetails(new
WebAuthenticationDetailsSource().buildDetails(request));

[Link]().setAuthentication(usernamePasswordAuthenticat
ionToken);
}
}
[Link](request, response);
}

====================================
6) Create WebSecurity Config class
====================================

package [Link];

import [Link];
import [Link];
import [Link];
import
[Link]
ationManagerBuilder;
import [Link];
import
[Link]
ty;
import
[Link]
igurerAdapter;
import [Link];
import [Link];
import [Link];
import [Link];
import
[Link]
lter;

import [Link];

@Configuaration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService myUserDetailsService;

@Autowired
private JwtRequestFilter jwtRequestFilter;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws
Exception {
[Link](myUserDetailsService);
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
{
return [Link]();
}

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
[Link]()
.disable()
.authorizeRequests()
.antMatchers("/authenticate")
.permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.and()
.sessionManagement()
.sessionCreationPolicy([Link]
LESS);

[Link](jwtRequestFilter,
[Link]);
}
}

==================================
7) create Rest Controller class
===================================

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import
[Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

import [Link];
import [Link];
import [Link];
import [Link];

@RestController
public class HelloRestController {

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
private JwtUtil jwtTokenUtil;

@Autowired
private MyUserDetailsService userDetailsService;

@RequestMapping({ "/hello" })
public String firstPage() {
return "Hello World";
}

@RequestMapping(value = "/authenticate", method = [Link])


public ResponseEntity<?> createAuthenticationToken(@RequestBody
AuthenticationRequest authenticationRequest)
throws Exception {

try {
[Link](new
UsernamePasswordAuthenticationToken(
[Link](),
[Link]()));
} catch (BadCredentialsException e) {
throw new Exception("Incorrect username or password", e);
}

final UserDetails userDetails =


[Link]([Link]());

final String jwt = [Link](userDetails);

return [Link](new AuthenticationResponse(jwt));


}
}
==================================
8) Run the application and Test it
===================================

You might also like