Files
vpd-permission-poc/src/main/java/com/cloudhandson/vpdbackoffice/config/SecurityConfig.java
2026-07-22 14:29:42 +09:00

108 lines
4.3 KiB
Java

package com.cloudhandson.vpdbackoffice.config;
import java.util.ArrayList;
import java.util.List;
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(
HttpSecurity http,
BackofficeProperties properties,
UserDetailsService userDetailsService
) throws Exception {
if (properties.security().requireHttps()) {
http.requiresChannel(channel -> channel.anyRequest().requiresSecure());
}
var security = properties.security();
if (security.rememberMeConfigured()) {
http.rememberMe(rememberMe -> rememberMe
.key(security.rememberMeKey())
.userDetailsService(userDetailsService)
.rememberMeParameter("remember-me")
.rememberMeCookieName("VPD_REMEMBER_ME")
.tokenValiditySeconds(security.rememberMeValiditySeconds())
.useSecureCookie(true)
.alwaysRemember(true));
}
return http
.csrf(csrf -> csrf.ignoringRequestMatchers(
"/mcp", "/mcp/messages", "/mcp/*/messages"))
.headers(headers -> headers.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.maxAgeInSeconds(31_536_000)))
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/css/**", "/js/**", "/webjars/**",
"/mcp", "/mcp/sse", "/mcp/*/sse", "/mcp/messages", "/mcp/*/messages")
.permitAll()
.requestMatchers(HttpMethod.POST, "/login", "/logout").permitAll()
.requestMatchers(HttpMethod.POST,
"/probe",
"/vector-knowledge/search",
"/security-sql-scripts/explanation",
"/mcp-chatbot",
"/mcp-client-demo",
"/mcp-reasoning")
.authenticated()
.requestMatchers(HttpMethod.PUT, "/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.PATCH, "/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.POST, "/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.DELETE, "/**").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(login -> login
.loginPage("/login")
.permitAll())
.logout(logout -> logout.logoutSuccessUrl("/login?logout"))
.build();
}
@Bean
UserDetailsService userDetailsService(
BackofficeProperties properties,
PasswordEncoder passwordEncoder
) {
var security = properties.security();
String encodedPassword = security.adminPasswordHash() == null || security.adminPasswordHash().isBlank()
? passwordEncoder.encode(security.adminPassword())
: security.adminPasswordHash();
List<UserDetails> users = new ArrayList<>();
users.add(User.withUsername(security.adminUser())
.password(encodedPassword)
.roles("ADMIN")
.build());
if (security.guestConfigured()) {
String encodedGuestPassword = security.guestPasswordHash() == null || security.guestPasswordHash().isBlank()
? passwordEncoder.encode(security.guestPassword())
: security.guestPasswordHash();
users.add(User.withUsername(security.guestUser())
.password(encodedGuestPassword)
.roles("VIEWER")
.build());
}
return new InMemoryUserDetailsManager(users);
}
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}