From 9ca8d0d14dabcbf77a0cdc7cb30fdd37fd905df3 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 24 Aug 2026 10:06:41 +0200 Subject: [PATCH] feat: add configuration properties and security config --- .../com/slotline/config/OpenApiConfig.java | 30 ++++++ .../com/slotline/config/SecurityConfig.java | 51 ++++++++++ .../slotline/config/SlotlineProperties.java | 96 +++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 src/main/java/com/slotline/config/OpenApiConfig.java create mode 100644 src/main/java/com/slotline/config/SecurityConfig.java create mode 100644 src/main/java/com/slotline/config/SlotlineProperties.java diff --git a/src/main/java/com/slotline/config/OpenApiConfig.java b/src/main/java/com/slotline/config/OpenApiConfig.java new file mode 100644 index 0000000..792a7a9 --- /dev/null +++ b/src/main/java/com/slotline/config/OpenApiConfig.java @@ -0,0 +1,30 @@ +package com.slotline.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OpenApiConfig { + + private static final String bearerScheme = "bearerAuth"; + + @Bean + public OpenAPI slotlineOpenApi() { + return new OpenAPI() + .info(new Info() + .title("slotline API") + .version("v1") + .description("Reservation platform with concurrency-safe slot booking")) + .addSecurityItem(new SecurityRequirement().addList(bearerScheme)) + .components(new Components().addSecuritySchemes(bearerScheme, + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT"))); + } +} diff --git a/src/main/java/com/slotline/config/SecurityConfig.java b/src/main/java/com/slotline/config/SecurityConfig.java new file mode 100644 index 0000000..7a7ae3a --- /dev/null +++ b/src/main/java/com/slotline/config/SecurityConfig.java @@ -0,0 +1,51 @@ +package com.slotline.config; + +import com.slotline.security.JwtAuthenticationFilter; +import com.slotline.security.RestAuthenticationHandlers; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +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; + +@Configuration +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http, + JwtAuthenticationFilter jwtAuthenticationFilter, + RestAuthenticationHandlers authHandlers) throws Exception { + http + .csrf(csrf -> csrf.disable()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(registry -> registry + .requestMatchers("/api/auth/**").permitAll() + .requestMatchers("/v3/api-docs", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll() + .requestMatchers("/api/organizations/**").hasRole("ADMIN") + .requestMatchers("/api/admin/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.POST, "/api/resource-groups/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.PUT, "/api/resource-groups/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.DELETE, "/api/resource-groups/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.GET, "/api/resource-groups/**").authenticated() + .requestMatchers(HttpMethod.POST, "/api/resources/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.PUT, "/api/resources/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.DELETE, "/api/resources/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.GET, "/api/resources/**").authenticated() + .requestMatchers("/api/reservations/**").authenticated() + .anyRequest().authenticated()) + .exceptionHandling(handling -> handling + .authenticationEntryPoint(authHandlers.authenticationEntryPoint()) + .accessDeniedHandler(authHandlers.accessDeniedHandler())) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/slotline/config/SlotlineProperties.java b/src/main/java/com/slotline/config/SlotlineProperties.java new file mode 100644 index 0000000..df75572 --- /dev/null +++ b/src/main/java/com/slotline/config/SlotlineProperties.java @@ -0,0 +1,96 @@ +package com.slotline.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.time.Duration; + +@ConfigurationProperties(prefix = "slotline") +public class SlotlineProperties { + + private final Jwt jwt = new Jwt(); + private final Admin admin = new Admin(); + private final Notifications notifications = new Notifications(); + + public Jwt getJwt() { + return jwt; + } + + public Admin getAdmin() { + return admin; + } + + public Notifications getNotifications() { + return notifications; + } + + public static class Jwt { + private String secret; + private Duration expiration = Duration.ofHours(12); + private String issuer = "slotline"; + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + public Duration getExpiration() { + return expiration; + } + + public void setExpiration(Duration expiration) { + this.expiration = expiration; + } + + public String getIssuer() { + return issuer; + } + + public void setIssuer(String issuer) { + this.issuer = issuer; + } + } + + public static class Admin { + private String username = "admin"; + private String password = "admin12345"; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + } + + public static class Notifications { + private final Webhook webhook = new Webhook(); + + public Webhook getWebhook() { + return webhook; + } + + public static class Webhook { + private String url; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + } + } +}