153 lines
7.7 KiB
Java
153 lines
7.7 KiB
Java
package com.alttd.altitudeweb.config;
|
|
|
|
import com.alttd.altitudeweb.controllers.login.KeyPairService;
|
|
import com.alttd.altitudeweb.model.PermissionClaimDto;
|
|
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;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
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.annotation.web.configurers.AbstractHttpConfigurer;
|
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
import org.springframework.security.core.GrantedAuthority;
|
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
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.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
|
import org.springframework.security.web.SecurityFilterChain;
|
|
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
|
|
|
|
import java.security.KeyPair;
|
|
import java.security.interfaces.RSAPrivateKey;
|
|
import java.security.interfaces.RSAPublicKey;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Slf4j
|
|
@Configuration
|
|
@EnableWebSecurity
|
|
@RequiredArgsConstructor
|
|
public class SecurityConfig {
|
|
|
|
private final KeyPairService keyPairService;
|
|
private final SecurityAuthFailureHandler securityAuthFailureHandler;
|
|
|
|
@Value("${chat.allowed-ip}")
|
|
private String allowedIp;
|
|
|
|
@Bean
|
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
WebExpressionAuthorizationManager allowedIpCheck = new WebExpressionAuthorizationManager(
|
|
"hasIpAddress('%s')".formatted(allowedIp));
|
|
return http
|
|
.authorizeHttpRequests(
|
|
auth -> auth
|
|
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
|
.requestMatchers("/api/chat/send/**").access(allowedIpCheck)
|
|
.requestMatchers("/actuator/mappings").access(allowedIpCheck)
|
|
.requestMatchers("/api/form/**").authenticated()
|
|
.requestMatchers("/api/login/getUsername").authenticated()
|
|
.requestMatchers("/api/mail/**").authenticated()
|
|
.requestMatchers("/api/site/vote").authenticated()
|
|
.requestMatchers("/api/appeal").authenticated()
|
|
.requestMatchers("/api/chat/read/**").hasAnyAuthority(PermissionClaimDto.HEAD_MOD.getValue(), PermissionClaimDto.MOD.getValue())
|
|
.requestMatchers("/api/site/get-staff-playtime/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
|
.requestMatchers("/api/head_mod/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
|
.requestMatchers("/api/particles/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
|
.requestMatchers("/api/files/save/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
|
//TODO allow users access to their own folder
|
|
.requestMatchers("/api/files/download/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
|
.requestMatchers("/api/history/admin/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
|
.requestMatchers("/api/login/userLogin/**").permitAll()
|
|
.anyRequest().permitAll()
|
|
)
|
|
.csrf(AbstractHttpConfigurer::disable)
|
|
.oauth2ResourceServer(
|
|
oauth2 -> oauth2
|
|
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
|
|
.authenticationEntryPoint(securityAuthFailureHandler)
|
|
.accessDeniedHandler(securityAuthFailureHandler)
|
|
)
|
|
.exceptionHandling(
|
|
ex -> ex
|
|
.authenticationEntryPoint(securityAuthFailureHandler)
|
|
.accessDeniedHandler(securityAuthFailureHandler)
|
|
)
|
|
.sessionManagement(
|
|
session -> session
|
|
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
)
|
|
.build();
|
|
}
|
|
|
|
@Bean
|
|
public JwtEncoder jwtEncoder() {
|
|
KeyPair keyPair = keyPairService.getJwtSigningKeyPair();
|
|
JWK jwk = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic())
|
|
.privateKey((RSAPrivateKey) keyPair.getPrivate())
|
|
.build();
|
|
JWKSource<SecurityContext> jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk));
|
|
return new NimbusJwtEncoder(jwkSource);
|
|
}
|
|
|
|
@Bean
|
|
public JwtDecoder jwtDecoder() {
|
|
KeyPair keyPair = keyPairService.getJwtSigningKeyPair();
|
|
return NimbusJwtDecoder.withPublicKey((RSAPublicKey) keyPair.getPublic()).build();
|
|
}
|
|
|
|
|
|
|
|
@Bean
|
|
public JwtAuthenticationConverter jwtAuthenticationConverter() {
|
|
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
|
|
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
|
|
Map<String, Object> claims = jwt.getClaims();
|
|
|
|
Object authoritiesClaim = claims.get("authorities");
|
|
if (authoritiesClaim instanceof List<?> authorities) {
|
|
Collection<GrantedAuthority> authorityList = authorities.stream()
|
|
.map(Object::toString)
|
|
.map(SimpleGrantedAuthority::new)
|
|
.collect(Collectors.toList());
|
|
log.debug("Authorities found in authorities: {}", authorityList);
|
|
return authorityList;
|
|
}
|
|
|
|
Object scopeClaim = claims.get("scope");
|
|
if (scopeClaim instanceof String scopeString) {
|
|
Collection<GrantedAuthority> authorityList = Arrays.stream(scopeString.split(" "))
|
|
.map(scope -> new SimpleGrantedAuthority("SCOPE_" + scope))
|
|
.collect(Collectors.toList());
|
|
log.debug("Authorities found in authorities scope string: {}", authorityList);
|
|
return authorityList;
|
|
}
|
|
|
|
if (scopeClaim instanceof List<?> scopeList) {
|
|
Collection<GrantedAuthority> authorityList = scopeList.stream()
|
|
.map(Object::toString)
|
|
.map(scope -> new SimpleGrantedAuthority("SCOPE_" + scope))
|
|
.collect(Collectors.toList());
|
|
log.debug("Authorities found in authorities scope list: {}", authorityList);
|
|
return authorityList;
|
|
}
|
|
|
|
log.debug("No granted authorities found");
|
|
return Collections.emptyList();
|
|
});
|
|
return converter;
|
|
}
|
|
}
|