Skip to content
Closed
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions config-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.xtrmetl.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

/**
* Defines the credential-free fail-closed HTTP posture for the reference-only Config Server.
*
* <p>The repository does not invent a production service identity. Until a deployment-owned
* authentication mechanism is selected and proven under issue #193, only health and info actuator
* endpoints are intentionally public and every configuration-resource request is denied. A future
* authenticated production profile must replace this reference-only posture through a separately
* reviewed security contract rather than weakening this default.</p>
*/
@Configuration(proxyBeanMethods = false)
public class ConfigServerSecurityConfiguration {

/**
* Builds the reference-only Config Server security chain.
*
* @param http Spring Security's servlet HTTP configuration builder
* @return the configured filter chain
* @throws Exception when Spring Security cannot build the filter chain
*/
@Bean
public SecurityFilterChain configServerSecurityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.httpBasic(httpBasic -> httpBasic.disable())
.formLogin(formLogin -> formLogin.disable())
.logout(logout -> logout.disable())
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(
"/actuator/health",
"/actuator/health/**",
"/actuator/info"
).permitAll()
.anyRequest().denyAll());
return http.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.xtrmetl.config;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* Verifies the fail-closed inbound HTTP boundary for the reference-only Config Server profile.
*/
@SpringBootTest(
classes = ConfigServerApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {
"spring.profiles.active=native",
"spring.cloud.config.server.native.search-locations=classpath:/",
"eureka.client.enabled=false"
}
)
class ConfigServerInboundSecurityTest {

@Autowired
private TestRestTemplate restTemplate;

@Test
void anonymousConfigurationReadIsDeniedWhileHealthRemainsPublic() {
ResponseEntity<String> configuration = restTemplate.getForEntity("/application/default", String.class);
ResponseEntity<String> health = restTemplate.getForEntity("/actuator/health", String.class);

assertEquals(HttpStatus.FORBIDDEN, configuration.getStatusCode());
assertEquals(HttpStatus.OK, health.getStatusCode());
}
}
Loading