From 5ff651fe43e5416787b57895849bb26f61403b40 Mon Sep 17 00:00:00 2001 From: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:29:28 +0800 Subject: [PATCH] docker: require auth for Eureka on EUREKA_USERNAME (#3698) This allows the Eureka test image to accept EUREKA_USERNAME and EUREKA_PASSWORD to require authentication accordingly without requiring auth when they aren't set. This is important to test auth, but not break our tests that do not require auth. Signed-off-by: Adrian Cole Co-authored-by: Andriy Redko --- docker/test-images/zipkin-eureka/pom.xml | 9 +++ .../java/zipkin/test/EurekaProperties.java | 43 ++++++++++++++ .../main/java/zipkin/test/EurekaSecurity.java | 58 +++++++++++++++++++ .../main/java/zipkin/test/EurekaServer.java | 13 ++++- 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaProperties.java create mode 100644 docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaSecurity.java diff --git a/docker/test-images/zipkin-eureka/pom.xml b/docker/test-images/zipkin-eureka/pom.xml index f74b48da2f4..17fb74ae0bc 100644 --- a/docker/test-images/zipkin-eureka/pom.xml +++ b/docker/test-images/zipkin-eureka/pom.xml @@ -50,6 +50,15 @@ spring-cloud-starter-netflix-eureka-server + + org.springframework.security + spring-security-web + + + org.springframework.security + spring-security-config + + org.springframework.boot diff --git a/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaProperties.java b/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaProperties.java new file mode 100644 index 00000000000..28e7102a79a --- /dev/null +++ b/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaProperties.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015-2024 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin.test; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** Properties for configuring and building a {@link EurekaServer}. */ +@ConfigurationProperties("eureka") +class EurekaProperties { + + /** Optional username to require. */ + private String username; + + /** Optional password to require. */ + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaSecurity.java b/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaSecurity.java new file mode 100644 index 00000000000..8f032ef9de6 --- /dev/null +++ b/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaSecurity.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015-2024 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin.test; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +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.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; + +import static org.springframework.security.crypto.factory.PasswordEncoderFactories.createDelegatingPasswordEncoder; + +/** This enables security, particularly only BASIC auth, when {@code EUREKA_USERNAME} is set. */ +@Configuration +@ConditionalOnProperty("eureka.username") +@EnableConfigurationProperties(EurekaProperties.class) +@ImportAutoConfiguration(SecurityAutoConfiguration.class) +public class EurekaSecurity { + @Bean InMemoryUserDetailsManager userDetailsService(EurekaProperties props) { + PasswordEncoder encoder = createDelegatingPasswordEncoder(); + UserDetails user = User.withUsername(props.getUsername()) + .password(encoder.encode(props.getPassword())) + .roles("ADMIN") + .build(); + return new InMemoryUserDetailsManager(user); + } + + /** + * You have to disable CSRF to allow BASIC authenticating Eureka clients to operate. + *

+ * See Securing The Eureka Server + */ + @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf(csrf -> csrf.ignoringRequestMatchers("/eureka/**")); + http.authorizeHttpRequests(authz -> authz.requestMatchers("/eureka/**").authenticated()) + .httpBasic(Customizer.withDefaults()); + return http.build(); + } +} diff --git a/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaServer.java b/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaServer.java index c17cabc3eee..f07df867eee 100644 --- a/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaServer.java +++ b/docker/test-images/zipkin-eureka/src/main/java/zipkin/test/EurekaServer.java @@ -14,12 +14,23 @@ package zipkin.test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; +import org.springframework.context.annotation.Import; -@SpringBootApplication +/** + * This disables automatic security configuration, deferring to {@linkplain EurekaSecurity}. + * Doing so allows Eureka to start as if spring-security wasn't in the classpath. + */ +@SpringBootApplication( + exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class} +) @EnableEurekaServer +@Import(EurekaSecurity.class) public class EurekaServer { + public static void main(String[] args) { SpringApplication.run(EurekaServer.class, args); }