Resolved conflicts

This commit is contained in:
harish
2024-08-22 10:54:32 +05:30
33 changed files with 863 additions and 144 deletions

View File

@@ -0,0 +1,111 @@
package net.gepafin.tendermanagement.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import net.gepafin.tendermanagement.config.jwt.JWTConfigurer;
import net.gepafin.tendermanagement.config.jwt.JWTFilter;
import net.gepafin.tendermanagement.config.jwt.TokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final TokenProvider tokenProvider;
@Autowired
public SecurityConfig(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer(MvcRequestMatcher.Builder mvc) {
return (web) -> web.ignoring()
.requestMatchers(mvc.pattern(HttpMethod.OPTIONS, "/**"))
.requestMatchers(new AntPathRequestMatcher("/i18n/**"))
.requestMatchers(new AntPathRequestMatcher("/content/**"))
.requestMatchers(new AntPathRequestMatcher("/swagger-ui/index.html"))
.requestMatchers(new AntPathRequestMatcher("/swagger-ui/**"));
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers(mvc.pattern(HttpMethod.POST, "/v1/user/login")).permitAll()
.requestMatchers(mvc.pattern(HttpMethod.POST, "/v1/user")).permitAll()
.requestMatchers("/swagger-ui/**").permitAll()
.requestMatchers("/v1/api-docs/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.apply(new JWTConfigurer(tokenProvider))
.and()
.addFilterBefore(new JWTFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.addServersItem(new Server().url("/"))
.addSecurityItem(new SecurityRequirement().addList("bearer-key"))
.components(new Components().addSecuritySchemes("bearer-key",
new SecurityScheme().type(SecurityScheme.Type.HTTP)
.scheme("bearer").bearerFormat("JWT")));
}
}

View File

@@ -0,0 +1,23 @@
package net.gepafin.tendermanagement.config.jwt;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class JWTConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
public static final String AUTHORIZATION_HEADER = "Authorization";
private TokenProvider tokenProvider;
public JWTConfigurer(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
public void configure(HttpSecurity http) throws Exception {
JWTFilter customFilter = new JWTFilter(tokenProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}

View File

@@ -0,0 +1,43 @@
package net.gepafin.tendermanagement.config.jwt;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import java.io.IOException;
public class JWTFilter extends GenericFilterBean {
private final TokenProvider tokenProvider;
public JWTFilter(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String token = resolveToken(httpServletRequest);
if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
if (authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
return StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ") ? bearerToken.substring(7) : null;
}
}

View File

@@ -0,0 +1,106 @@
package net.gepafin.tendermanagement.config.jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@Component
public class TokenProvider {
private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
@Value("${security.authentication.jwt.secret}")
private String secretKey;
@Value("${security.authentication.jwt.token-validity-in-seconds}")
private long tokenValidityInSeconds;
private SecretKey key;
@PostConstruct
public void init() {
this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
log.info("JWT Secret Key initialized.");
}
public String createToken(Authentication authentication, Boolean rememberMe) {
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
Long now;
Date validity;
if (Boolean.TRUE.equals(rememberMe)) {
now = DateUtils.addMonths(new Date(), 2).getTime();
validity = new Date(now);
log.info("Creating token with extended validity for 2 months.");
} else {
now = (new Date()).getTime();
validity = new Date(now + (this.tokenValidityInSeconds * 1000));
log.info("Creating token with standard validity of {} seconds.", this.tokenValidityInSeconds);
}
String token = Jwts.builder()
.setSubject(authentication.getName())
.claim("auth", authorities)
.signWith(key, SignatureAlgorithm.HS512)
.setExpiration(validity)
.compact();
log.debug("Generated token: {}", token);
return token;
}
public Authentication getAuthentication(String token) {
Claims claims = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
UserDetails principal = new User(claims.getSubject(), "", Collections.emptyList());
log.info("Authenticated user: {}", claims.getSubject());
return new UsernamePasswordAuthenticationToken(principal, token, ClaimsToAuthorities(claims.get("auth")));
}
private Collection<? extends GrantedAuthority> ClaimsToAuthorities(Object authClaim) {
Collection<? extends GrantedAuthority> authorities = authClaim == null || ((String) authClaim).isEmpty() ?
Collections.emptyList() :
Arrays.stream(((String) authClaim).split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
log.debug("Converted authorities from claims: {}", authorities);
return authorities;
}
public boolean validateToken(String authToken) {
try {
Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(authToken);
log.info("Token is valid.");
return true;
} catch (Exception e) {
log.error("Token validation failed: {}", e.getMessage());
return false;
}
}
}