Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@
import com.nyaysetu.backend.filter.RateLimitFilter;
import com.nyaysetu.backend.filter.XssSanitizationFilter;
import jakarta.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
Expand All @@ -27,9 +31,6 @@
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;
import java.util.List;

@Configuration
@EnableMethodSecurity
@RequiredArgsConstructor
Expand All @@ -50,7 +51,7 @@ public class SecurityConfig {

@PostConstruct
public void validateJwtSecretConfiguration() {
boolean isDev = java.util.Arrays.stream(environment.getActiveProfiles())
boolean isDev = Arrays.stream(environment.getActiveProfiles())
.anyMatch(profile -> profile.equalsIgnoreCase("dev") || profile.equalsIgnoreCase("test"));
String jwtSecretEnv = System.getenv("JWT_SECRET");
boolean isJwtSecretEnvMissing = jwtSecretEnv == null || jwtSecretEnv.trim().isEmpty();
Expand Down Expand Up @@ -86,19 +87,19 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration c
}

@Bean
public org.springframework.web.cors.CorsConfigurationSource corsConfigurationSource() {
org.springframework.web.cors.CorsConfiguration configuration = new org.springframework.web.cors.CorsConfiguration();
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();

// Use origins from application.properties / Env Var
if (allowedOrigins != null && !allowedOrigins.isEmpty()) {
java.util.List<String> origins = java.util.Arrays.stream(allowedOrigins.split(","))
List<String> origins = Arrays.stream(allowedOrigins.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(java.util.stream.Collectors.toList());
.collect(Collectors.toList());

if (origins.isEmpty()) {
// SAFE DEFAULT: Allow local development origins only
configuration.setAllowedOrigins(java.util.Arrays.asList(
configuration.setAllowedOrigins(Arrays.asList(
"http://localhost:5173",
"http://localhost:3000",
"http://localhost"
Expand All @@ -108,10 +109,9 @@ public org.springframework.web.cors.CorsConfigurationSource corsConfigurationSou
// Security: reject bare "*" — it allows any origin to make credentialed requests
boolean hasBareWildcard = origins.stream().anyMatch(o -> o.trim().equals("*"));
if (hasBareWildcard) {
java.util.logging.Logger.getLogger("SecurityConfig")
.warning("CORS_ALLOWED_ORIGINS contains bare '*'. "
logger.warn("CORS_ALLOWED_ORIGINS contains bare '*'. "
+ "This is unsafe with credentials. Falling back to localhost defaults.");
configuration.setAllowedOrigins(java.util.Arrays.asList(
configuration.setAllowedOrigins(Arrays.asList(
"http://localhost:5173",
"http://localhost:3000",
"http://localhost"
Expand All @@ -129,18 +129,18 @@ public org.springframework.web.cors.CorsConfigurationSource corsConfigurationSou
}
} else {
// SAFE DEFAULT: Allow local development origins only
configuration.setAllowedOrigins(java.util.Arrays.asList(
configuration.setAllowedOrigins(Arrays.asList(
"http://localhost:5173",
"http://localhost:3000",
"http://localhost"
));
configuration.setAllowCredentials(true);
}

configuration.setAllowedMethods(java.util.Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(java.util.Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));

org.springframework.web.cors.UrlBasedCorsConfigurationSource source = new org.springframework.web.cors.UrlBasedCorsConfigurationSource();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Expand All @@ -153,16 +153,10 @@ public SecurityFilterChain securityFilterChain(

http
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(csrf -> csrf.disable())
.csrf(AbstractHttpConfigurer::disable)
.headers(headers -> headers
.frameOptions(frame -> frame.deny())
.contentSecurityPolicy(csp -> csp
// Strict CSP for API responses. Mirrors the
// frontend nginx.conf policy so that any
// HTML/error page Spring serves (e.g. the
// default whitelabel error pages) is also
// protected. Adjust directives here when you
// adjust them in nginx.conf.
.policyDirectives(
"default-src 'self'; " +
"script-src 'self'; " +
Expand All @@ -182,7 +176,6 @@ public SecurityFilterChain securityFilterChain(
"geolocation=(), microphone=(), camera=(), payment=()"))
)
.authorizeHttpRequests(auth -> auth

// ── Public endpoints ──────────────────────────────────────────────
.requestMatchers(
"/api/v1/auth/register",
Expand Down Expand Up @@ -290,4 +283,4 @@ public SecurityFilterChain securityFilterChain(

return http.build();
}
}
}
Loading