Updated auth config
Some checks failed
Gitea/swiss-backend/pipeline/head There was a failure building this commit
Some checks failed
Gitea/swiss-backend/pipeline/head There was a failure building this commit
This commit is contained in:
44
src/main/java/nl/connectedit/swiss/auth/AuthController.java
Normal file
44
src/main/java/nl/connectedit/swiss/auth/AuthController.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package nl.connectedit.swiss.auth;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
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 org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/api/auth")
|
||||
public class AuthController {
|
||||
|
||||
private final JwtEncoder encoder;
|
||||
|
||||
public AuthController(JwtEncoder encoder) {
|
||||
this.encoder = encoder;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public String auth(Authentication authentication) {
|
||||
Instant now = Instant.now();
|
||||
long expiry = 36000L;
|
||||
String scope = authentication.getAuthorities().stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.collect(Collectors.joining(","));
|
||||
JwtClaimsSet claims = JwtClaimsSet.builder()
|
||||
.issuer("self")
|
||||
.issuedAt(now)
|
||||
.expiresAt(now.plusSeconds(expiry))
|
||||
.subject(authentication.getName())
|
||||
.claim("scope", scope)
|
||||
.build();
|
||||
return this.encoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
|
||||
}
|
||||
|
||||
}
|
||||
9
src/main/java/nl/connectedit/swiss/auth/Roles.java
Normal file
9
src/main/java/nl/connectedit/swiss/auth/Roles.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package nl.connectedit.swiss.auth;
|
||||
|
||||
public final class Roles {
|
||||
|
||||
public static final String USER = "USER";
|
||||
|
||||
private Roles() {
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,148 @@
|
||||
package nl.connectedit.swiss.config;
|
||||
|
||||
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 jakarta.servlet.DispatcherType;
|
||||
import nl.connectedit.swiss.auth.Roles;
|
||||
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.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
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.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
//@Configuration
|
||||
//@EnableWebSecurity
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
// @Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
private final RSAPublicKey key;
|
||||
private final RSAPrivateKey priv;
|
||||
|
||||
public SecurityConfig(@Value("${jwt.public.key}") RSAPublicKey key,
|
||||
@Value("${jwt.private.key}") RSAPrivateKey priv) {
|
||||
this.key = key;
|
||||
this.priv = priv;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
|
||||
// .authorizeHttpRequests(request -> {
|
||||
// request.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll();
|
||||
// request.requestMatchers("/error").permitAll();
|
||||
// });
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers("/api/auth"))
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
// Allow OPTIONS requests for CORS preflight
|
||||
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
||||
// Allow POST to /api/auth without JWT (Basic Auth will still be required)
|
||||
.requestMatchers(HttpMethod.POST, "/api/auth").permitAll()
|
||||
// All other requests require authentication
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.httpBasic(Customizer.withDefaults())
|
||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.exceptionHandling(exceptions -> exceptions
|
||||
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
|
||||
.accessDeniedHandler(new BearerTokenAccessDeniedHandler())
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
|
||||
// Allow your Angular app's origin(s)
|
||||
configuration.setAllowedOrigins(Arrays.asList(
|
||||
"http://localhost:4200",
|
||||
"http://localhost:8080",
|
||||
// Add your production URL here when deploying
|
||||
"https://badminton-toernooi.nl",
|
||||
"https://test.badminton-toernooi.nl"
|
||||
));
|
||||
|
||||
configuration.setAllowedMethods(Arrays.asList(
|
||||
"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"
|
||||
));
|
||||
|
||||
configuration.setAllowedHeaders(Arrays.asList(
|
||||
"Authorization",
|
||||
"Content-Type",
|
||||
"Accept"
|
||||
));
|
||||
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setMaxAge(3600L);
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
UserDetailsService users() {
|
||||
return new InMemoryUserDetailsManager(
|
||||
User.withUsername("bcholten")
|
||||
.password(passwordEncoder().encode("bcholten"))
|
||||
.roles(Roles.USER)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
JwtDecoder jwtDecoder() {
|
||||
return NimbusJwtDecoder.withPublicKey(this.key).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
JwtEncoder jwtEncoder() {
|
||||
JWK jwk = new RSAKey.Builder(this.key).privateKey(this.priv).build();
|
||||
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
|
||||
return new NimbusJwtEncoder(jwks);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtAuthenticationConverter jwtAuthenticationConverter() {
|
||||
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
|
||||
// Remove the SCOPE_ prefix
|
||||
grantedAuthoritiesConverter.setAuthorityPrefix("");
|
||||
|
||||
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
||||
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
|
||||
return jwtAuthenticationConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.auth.Roles;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.dto.PlayerDto;
|
||||
import nl.connectedit.swiss.mapper.PlayerMapper;
|
||||
@@ -12,6 +14,7 @@ import java.util.List;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RolesAllowed(Roles.USER)
|
||||
@RequiredArgsConstructor
|
||||
public class PlayerController {
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.auth.Roles;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.dto.TournamentRegistrationDto;
|
||||
import nl.connectedit.swiss.mapper.TournamentPlayerRegistrationMapper;
|
||||
@@ -20,6 +22,7 @@ import java.util.List;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RolesAllowed(Roles.USER)
|
||||
@RequiredArgsConstructor
|
||||
public class RegistrationController {
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@ package nl.connectedit.swiss.controller;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import nl.connectedit.swiss.auth.Roles;
|
||||
import nl.connectedit.swiss.domain.*;
|
||||
import nl.connectedit.swiss.domain.entity.Player;
|
||||
import nl.connectedit.swiss.domain.entity.Registration;
|
||||
@@ -39,6 +41,7 @@ import static nl.connectedit.swiss.domain.PlayerStrength.*;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RolesAllowed(Roles.USER)
|
||||
@RequiredArgsConstructor
|
||||
public class TestController {
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package nl.connectedit.swiss.controller;
|
||||
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import nl.connectedit.swiss.auth.Roles;
|
||||
import nl.connectedit.swiss.domain.TournamentStatus;
|
||||
import nl.connectedit.swiss.domain.entity.Tournament;
|
||||
import nl.connectedit.swiss.dto.ResultDto;
|
||||
@@ -20,6 +22,7 @@ import java.util.Objects;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RolesAllowed(Roles.USER)
|
||||
@RequiredArgsConstructor
|
||||
public class TournamentController {
|
||||
|
||||
|
||||
@@ -30,4 +30,10 @@ management:
|
||||
probes:
|
||||
enabled: true
|
||||
|
||||
security: true
|
||||
security: true
|
||||
|
||||
jwt:
|
||||
private:
|
||||
key: classpath:certs/private.pem
|
||||
public:
|
||||
key: classpath:certs/public.pem
|
||||
|
||||
Reference in New Issue
Block a user