Enhanced CORS configuration for OAuth2 and role-based tab visibility in frontend:

- **Backend**: Added separate CORS settings for `/oauth2/token` endpoint with enhanced origin handling based on new `lcc.allowed_oauth_token_cors` property.
- **Frontend**: Updated `Config.vue` to conditionally display `nodesTab` and `bulkOperationsTab` based on user roles.
This commit is contained in:
Jan 2025-10-30 15:05:12 +01:00
parent e1791942cb
commit a289cce805
3 changed files with 77 additions and 48 deletions

View file

@ -90,12 +90,16 @@ export default {
tabs.push(this.materialsTab);
}
if (this.activeUserStore.isSuper || this.activeUserStore.isMaterial || this.activeUserStore.isPackaging || this.activeUserStore.isFreight) {
tabs.push(this.nodesTab);
}
if (this.activeUserStore.allowRates)
tabs.push(this.ratesTab);
if (this.activeUserStore.isSuper || this.activeUserStore.isMaterial || this.activeUserStore.isPackaging || this.activeUserStore.isFreight) {
tabs.push(this.bulkOperationsTab);
}
return tabs;

View file

@ -57,9 +57,12 @@ public class SecurityConfig {
@Value("${lcc.allowed_cors}")
private String allowedCors;
@Value("${lcc.allowed_oauth_token_cors:*}") // Default: alle Origins
private String oauthTokenCors;
@Bean
@Profile("!dev & !test") // Only active when NOT in dev profile
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtTokenService jwtTokenService) throws Exception {
public SecurityFilterChain prodSecurityFilterChain(HttpSecurity http, JwtTokenService jwtTokenService) throws Exception {
http
.cors(cors -> cors.configurationSource(prodCorsConfigurationSource())) // Production CORS
.authorizeHttpRequests(auth -> auth
@ -98,30 +101,31 @@ public class SecurityConfig {
return http.build();
}
@Bean
@Profile("dev | test")
public CorsConfigurationSource devCorsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(List.of("http://localhost:*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600L);
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Page-Count", "X-Current-Page"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
// Production CORS Configuration
@Bean
@Profile("!dev & !test")
public CorsConfigurationSource prodCorsConfigurationSource() {
// CORS for /oauth2/token
CorsConfiguration tokenConfiguration = new CorsConfiguration();
if ("*".equals(oauthTokenCors)) {
tokenConfiguration.setAllowedOriginPatterns(List.of("*"));
} else {
String[] tokenOrigins = oauthTokenCors.split(",");
for (int i = 0; i < tokenOrigins.length; i++) {
tokenOrigins[i] = tokenOrigins[i].trim();
}
if (tokenOrigins.length != 0) {
tokenConfiguration.setAllowedOrigins(Arrays.asList(tokenOrigins));
}
}
CorsConfiguration configuration = new CorsConfiguration();
if ("*".equals(allowedCors)) {
configuration.setAllowedOriginPatterns(List.of("*"));
} else {
// Parse comma-separated origins from property
String[] origins = allowedCors.split(",");
for (int i = 0; i < origins.length; i++) {
@ -131,6 +135,8 @@ public class SecurityConfig {
if (origins.length != 0) {
configuration.setAllowedOrigins(Arrays.asList(origins));
}
}
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true);
@ -138,30 +144,12 @@ public class SecurityConfig {
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Page-Count", "X-Current-Page"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
source.registerCorsConfiguration("/oauth2/token", tokenConfiguration);
return source;
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
// Für Entra ID Tokens
JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
converter.setAuthoritiesClaimName("scp");
converter.setAuthorityPrefix("SCOPE_");
JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
jwtConverter.setJwtGrantedAuthoritiesConverter(converter);
return jwtConverter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Profile("dev | test")
public SecurityFilterChain devSecurityFilterChain(HttpSecurity http, UserRepository userRepository, JwtTokenService jwtTokenService) throws Exception {
@ -188,6 +176,42 @@ public class SecurityConfig {
.build();
}
@Bean
@Profile("dev | test")
public CorsConfigurationSource devCorsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(List.of("http://localhost:*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600L);
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Page-Count", "X-Current-Page"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
// Für Entra ID Tokens
JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
converter.setAuthoritiesClaimName("scp");
converter.setAuthorityPrefix("SCOPE_");
JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
jwtConverter.setJwtGrantedAuthoritiesConverter(converter);
return jwtConverter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Profile("!dev & !test")
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService(UserRepository userRepository, GroupRepository groupRepository) {

View file

@ -23,3 +23,4 @@ spring.flyway.baseline-on-migrate=true
spring.sql.init.mode=never
lcc.allowed_cors=
lcc.allowed_oauth_token_cors=*