108 lines
4.3 KiB
Java
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();
|
|
}
|
|
}
|