Authorization working
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.mattrixwv.raidbuilder.config;
|
||||
|
||||
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
|
||||
@ConfigurationProperties(prefix = "rsa")
|
||||
public record RsaKeyProperties(RSAPublicKey publicKey, RSAPrivateKey privateKey){
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.mattrixwv.raidbuilder.config;
|
||||
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
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.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import com.nimbusds.jose.jwk.JWK;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfig{
|
||||
private final RsaKeyProperties rsaKeys;
|
||||
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder(){
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
|
||||
http
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.authorizeHttpRequests(auth -> {
|
||||
auth.requestMatchers("/auth/refresh").permitAll() //Permit refresh tokens
|
||||
.requestMatchers(HttpMethod.POST, "/auth/signup", "/auth/confirm").permitAll() //Permit signup operations
|
||||
.requestMatchers("/auth/forgot", "/auth/forgot/*").permitAll() //Permit forgot password operations
|
||||
.anyRequest().authenticated();
|
||||
})
|
||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
|
||||
.httpBasic(Customizer.withDefaults())
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public JwtEncoder jwtEncoder(){
|
||||
JWK jwk = new RSAKey.Builder(rsaKeys.publicKey()).privateKey(rsaKeys.privateKey()).build();
|
||||
|
||||
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
|
||||
|
||||
return new NimbusJwtEncoder(jwks);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtDecoder jwtDecoder(){
|
||||
return NimbusJwtDecoder.withPublicKey(rsaKeys.publicKey()).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.mattrixwv.raidbuilder.config;
|
||||
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
|
||||
|
||||
import com.mattrixwv.raidbuilder.entity.Account;
|
||||
import com.mattrixwv.raidbuilder.service.AccountPermissionService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class TokenService{
|
||||
private final JwtEncoder encoder;
|
||||
private final AccountPermissionService accountPermissionService;
|
||||
//Fields
|
||||
@Value("${jwt.accessTokenDuration}")
|
||||
private Duration accessTokenDuration;
|
||||
|
||||
|
||||
public String generateAccessToken(Account account){
|
||||
log.debug("Generating access token for account {}", account.getAccountId());
|
||||
|
||||
|
||||
String scope = accountPermissionService.getByAccountId(account.getAccountId()).stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(" "));
|
||||
|
||||
Instant now = Instant.now();
|
||||
JwtClaimsSet claims = JwtClaimsSet.builder()
|
||||
.issuer("self")
|
||||
.issuedAt(now)
|
||||
.expiresAt(now.plus(accessTokenDuration))
|
||||
.subject(account.getUsername())
|
||||
.claim("scope", scope)
|
||||
.build();
|
||||
|
||||
return encoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.mattrixwv.raidbuilder.config;
|
||||
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module;
|
||||
import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module.Feature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer{
|
||||
@Value("${allowedOrigins}")
|
||||
private String allowedOrigins;
|
||||
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(@NonNull CorsRegistry registry){
|
||||
log.debug("Adding CORS mappings: {}", allowedOrigins);
|
||||
|
||||
registry.addMapping("/**")
|
||||
.allowedOriginPatterns(allowedOrigins)
|
||||
.allowedMethods("GET", "PUT", "DELETE", "OPTIONS", "PATCH", "POST");
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper(){
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
log.debug("Starting mapping configuration");
|
||||
|
||||
//Make sure Jackson doesn't attempt lazy loading
|
||||
Hibernate6Module hibernate6Module = new Hibernate6Module();
|
||||
hibernate6Module.configure(Feature.FORCE_LAZY_LOADING, false);
|
||||
hibernate6Module.configure(Feature.USE_TRANSIENT_ANNOTATION, false);
|
||||
hibernate6Module.configure(Feature.REQUIRE_EXPLICIT_LAZY_LOADING_MARKER, true);
|
||||
hibernate6Module.configure(Feature.WRITE_MISSING_ENTITIES_AS_NULL, false);
|
||||
mapper.registerModule(hibernate6Module);
|
||||
|
||||
//Print dates as strings
|
||||
mapper.registerModule(new JavaTimeModule());
|
||||
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
mapper.findAndRegisterModules();
|
||||
|
||||
log.debug("Completed mapping configuration");
|
||||
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.mattrixwv.raidbuilder.config;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WebFilter extends OncePerRequestFilter{
|
||||
@Override
|
||||
public void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException{
|
||||
if(!request.getMethod().equalsIgnoreCase("OPTIONS")){
|
||||
setupMDC(request);
|
||||
}
|
||||
|
||||
//Continue to the controller
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
//Clear the MDC for the next request
|
||||
MDC.clear();
|
||||
}
|
||||
|
||||
private void setupMDC(HttpServletRequest request){
|
||||
//Get the requestId
|
||||
String requestId = request.getHeader("X-Request-Id");
|
||||
if(requestId != null){
|
||||
MDC.put("requestId", requestId);
|
||||
}
|
||||
|
||||
//Get IP address
|
||||
String forwardedFor = request.getHeader("X-Forwarded-For");
|
||||
if(forwardedFor != null){
|
||||
MDC.put("ip", forwardedFor.split(",")[0]);
|
||||
}
|
||||
|
||||
//Get all of the parameters in the request and print them in the log
|
||||
StringJoiner parameters = new StringJoiner(", ");
|
||||
request.getParameterMap().entrySet().forEach(entry -> {
|
||||
if(!entry.getKey().equals("_")){
|
||||
String key = entry.getKey();
|
||||
String value = "";
|
||||
if(entry.getValue().length > 1){
|
||||
StringJoiner joiner = new StringJoiner(", ", "[", "]");
|
||||
for(String str : entry.getValue()){
|
||||
joiner.add(str);
|
||||
}
|
||||
value = joiner.toString();
|
||||
}
|
||||
else{
|
||||
value = entry.getValue()[0];
|
||||
}
|
||||
parameters.add(key + "->" + value);
|
||||
}
|
||||
});
|
||||
if(parameters.length() > 0){
|
||||
log.info("Request parameters: {}", parameters);
|
||||
}
|
||||
|
||||
//Get the path
|
||||
MDC.put("url", request.getRequestURI());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user