Skip to content

Commit

Permalink
Api Rest Security
Browse files Browse the repository at this point in the history
  • Loading branch information
BraisCabo committed Mar 18, 2023
1 parent 9bcfde6 commit 955e908
Show file tree
Hide file tree
Showing 9 changed files with 697 additions and 0 deletions.
82 changes: 82 additions & 0 deletions code/backend/src/main/java/app/security/RestSecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package app.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import app.security.jwt.JwtRequestFilter;


@Configuration
@Order(1)
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
RepositoryUserDetailsService userDetailsService;

@Autowired
private PasswordEncoder passwordEncoder;

@Autowired
private JwtRequestFilter jwtRequestFilter;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}

//Expose AuthenticationManager as a Bean to be used in other services
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**");

http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/games/").hasRole("ADMIN");
http.authorizeRequests().antMatchers(HttpMethod.DELETE, "/api/games/**").hasRole("ADMIN");
http.authorizeRequests().antMatchers(HttpMethod.PUT, "/api/games/**").hasRole("ADMIN");

http.authorizeRequests().antMatchers(HttpMethod.DELETE, "/api/reviews/**").hasRole("USER");
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/reviews/**/**").hasRole("USER");

http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/users/me").hasRole("USER");
http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/users/**/moreCartGames/**").hasRole("USER");
http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/users/**/cart").hasRole("USER");
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/users/**/cart/**").hasRole("USER");
http.authorizeRequests().antMatchers(HttpMethod.DELETE, "/api/users/**/cart/**").hasRole("USER");
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/users/**/checkout").hasRole("USER");
http.authorizeRequests().antMatchers(HttpMethod.PUT, "/api/users/**").hasRole("USER");


// Other URLs can be accessed without authentication
http.authorizeRequests().anyRequest().permitAll();

// Disable CSRF protection (it is difficult to implement in REST APIs)
http.csrf().disable();

// Disable Http Basic Authentication
http.httpBasic().disable();

// Disable Form login Authentication
http.formLogin().disable();

// Avoid creating session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

// Add JWT Token filter
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
56 changes: 56 additions & 0 deletions code/backend/src/main/java/app/security/jwt/AuthResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package app.security.jwt;

public class AuthResponse {

private Status status;
private String message;
private String error;

public enum Status {
SUCCESS, FAILURE
}

public AuthResponse() {
}

public AuthResponse(Status status, String message) {
this.status = status;
this.message = message;
}

public AuthResponse(Status status, String message, String error) {
this.status = status;
this.message = message;
this.error = error;
}

public Status getStatus() {
return status;
}

public void setStatus(Status status) {
this.status = status;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getError() {
return error;
}

public void setError(String error) {
this.error = error;
}

@Override
public String toString() {
return "LoginResponse [status=" + status + ", message=" + message + ", error=" + error + "]";
}

}
27 changes: 27 additions & 0 deletions code/backend/src/main/java/app/security/jwt/JwtCookieManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package app.security.jwt;

import org.springframework.http.HttpCookie;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Component;

@Component
public class JwtCookieManager {

public static final String ACCESS_TOKEN_COOKIE_NAME = "AuthToken";
public static final String REFRESH_TOKEN_COOKIE_NAME = "RefreshToken";

public HttpCookie createAccessTokenCookie(String token, Long duration) {
String encryptedToken = SecurityCipher.encrypt(token);
return ResponseCookie.from(ACCESS_TOKEN_COOKIE_NAME, encryptedToken).maxAge(-1).httpOnly(true).path("/").build();
}

public HttpCookie createRefreshTokenCookie(String token, Long duration) {
String encryptedToken = SecurityCipher.encrypt(token);
return ResponseCookie.from(REFRESH_TOKEN_COOKIE_NAME, encryptedToken).maxAge(-1).httpOnly(true).path("/").build();
}

public HttpCookie deleteAccessTokenCookie() {
return ResponseCookie.from(ACCESS_TOKEN_COOKIE_NAME, "").maxAge(0).httpOnly(true).path("/").build();
}

}
106 changes: 106 additions & 0 deletions code/backend/src/main/java/app/security/jwt/JwtRequestFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package app.security.jwt;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

private static final Logger LOG = LoggerFactory.getLogger(JwtRequestFilter.class);

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private JwtTokenProvider jwtTokenProvider;

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

try {
String token = getJwtToken(request, true);

if (StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)) {

String username = jwtTokenProvider.getUsername(token);

UserDetails userDetails = userDetailsService.loadUserByUsername(username);

UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());

authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
LOG.error("Exception processing JWT Token",ex);
}

filterChain.doFilter(request, response);
}

private String getJwtToken(HttpServletRequest request, boolean fromCookie) {

if (fromCookie) {
return getJwtFromCookie(request);
} else {
return getJwtFromRequest(request);
}
}

private String getJwtFromRequest(HttpServletRequest request) {

String bearerToken = request.getHeader("Authorization");

if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {

String accessToken = bearerToken.substring(7);
if (accessToken == null) {
return null;
}

return SecurityCipher.decrypt(accessToken);
}
return null;
}

private String getJwtFromCookie(HttpServletRequest request) {

Cookie[] cookies = request.getCookies();

if (cookies == null) {
return "";
}

for (Cookie cookie : cookies) {
if (JwtCookieManager.ACCESS_TOKEN_COOKIE_NAME.equals(cookie.getName())) {
String accessToken = cookie.getValue();
if (accessToken == null) {
return null;
}

return SecurityCipher.decrypt(accessToken);
}
}
return null;
}
}
Loading

0 comments on commit 955e908

Please sign in to comment.