From f3a225f35f40917c43f77dc40437fdca711d6f43 Mon Sep 17 00:00:00 2001 From: Christian Dupuis Date: Wed, 20 Nov 2013 17:14:46 +0100 Subject: [PATCH] Polish and rework default authentication method if a Spring Security AuthenticationManager is available In case a Spring Security AuthenticationManager is found in the app context the auto configuration will change default shell authentication method to auth against Spring Security. In addition shell access will get protected by the specific role configured in SecurityProperties.Management. Certainly this can be overridden by providing shell.auth and shell.auth.spring.roles. --- .../autoconfigure/CrshAutoConfiguration.java | 55 ++++++++++++++++--- .../CrshAutoConfigurationTests.java | 30 +++++++++- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java index d8654536300..9916efe17f4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfiguration.java @@ -44,8 +44,11 @@ import org.crsh.vfs.spi.AbstractFSDriver; import org.crsh.vfs.spi.FSDriver; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.properties.SecurityProperties; +import org.springframework.boot.actuate.properties.SecurityProperties.Management; import org.springframework.boot.actuate.properties.ShellProperties; import org.springframework.boot.actuate.properties.ShellProperties.CrshShellAuthenticationProperties; +import org.springframework.boot.actuate.properties.ShellProperties.CrshShellProperties; import org.springframework.boot.actuate.properties.ShellProperties.JaasAuthenticationProperties; import org.springframework.boot.actuate.properties.ShellProperties.KeyAuthenticationProperties; import org.springframework.boot.actuate.properties.ShellProperties.SimpleAuthenticationProperties; @@ -76,20 +79,32 @@ import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for embedding an extensible shell - * into a Spring Boot enabled application. By default a SSH daemon is started on port 2000 - * with a default username user and password (default password is logged - * during application startup). + * into a Spring Boot enabled application. By default a SSH daemon is started on port + * 2000. If the CRaSH Telnet plugin is available on the classpath, Telnet deamon will be + * launched on port 5000. * *

- * This configuration will auto detect the existence of a Spring Security - * {@link AuthenticationManager} and will delegate authentication requests for shell - * access to this detected instance if shell.auth: spring is set in the - * application properties. + * The default shell authentication method uses a username and password combination. If no + * configuration is provided the default username is 'user' and the password will be + * printed to console during application startup. Those default values can be overridden + * by using shell.auth.simple.username and + * shell.auth.simple.password. + * + *

+ * If a Spring Security {@link AuthenticationManager} is detected, this configuration will + * create a {@link CRaSHPlugin} to forward shell authentication requests to Spring + * Security. This authentication method will get enabled if shell.auth is set + * to spring or if no explicit shell.auth is provided and a + * {@link AuthenticationManager} is available. In the latter case shell access will be + * restricted to users having roles that match those configured in {@link Management}. + * Required roles can be overridden by shell.auth.spring.roles. * *

* To add customizations to the shell simply define beans of type {@link CRaSHPlugin} in * the application context. Those beans will get auto detected during startup and - * registered with the underlying shell infrastructure. + * registered with the underlying shell infrastructure. To configure plugins and the CRaSH + * infrastructure add beans of type {@link CrshShellProperties} to the application + * context. * *

* Additional shell commands can be implemented using the guide and documentation at shell.command_path_patterns in your application configuration. * * @author Christian Dupuis + * @see ShellProperties */ @Configuration @ConditionalOnClass({ PluginLifeCycle.class }) @@ -145,15 +161,36 @@ public class CrshAutoConfiguration { return bootstrapBean; } + /** + * Class to configure CRaSH to authenticate against Spring Security. + */ @Configuration @ConditionalOnBean({ AuthenticationManager.class }) + @AutoConfigureAfter(CrshAutoConfiguration.class) public static class AuthenticationManagerAdapterAutoConfiguration { + @Autowired(required = false) + private SecurityProperties securityProperties; + @Bean public CRaSHPlugin shellAuthenticationManager() { return new AuthenticationManagerAdapter(); } + @Bean + @ConditionalOnExpression("'${shell.auth:default_spring}' == 'default_spring'") + @ConditionalOnMissingBean({ CrshShellAuthenticationProperties.class }) + public CrshShellAuthenticationProperties springAuthenticationProperties() { + // In case no shell.auth property is provided fall back to Spring Security + // based authentication and get role to access shell from SecurityProperties. + SpringAuthenticationProperties authenticationProperties = new SpringAuthenticationProperties(); + if (this.securityProperties != null) { + authenticationProperties.setRoles(new String[] { this.securityProperties + .getManagement().getRole() }); + } + return authenticationProperties; + } + } /** @@ -238,7 +275,7 @@ public class CrshAutoConfiguration { @Autowired(required = false) private AccessDecisionManager accessDecisionManager; - private String[] roles = new String[] { "ROLE_ADMIN" }; + private String[] roles = new String[] { "ADMIN" }; @Override public boolean authenticate(String username, String password) throws Exception { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfigurationTests.java index 984d42b6b71..2e0d3a811b2 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/CrshAutoConfigurationTests.java @@ -190,7 +190,6 @@ public class CrshAutoConfigurationTests { this.context = new AnnotationConfigWebApplicationContext(); this.context.setEnvironment(env); this.context.setServletContext(new MockServletContext()); - this.context.register(SecurityConfiguration.class); this.context.register(CrshAutoConfiguration.class); this.context.refresh(); @@ -295,6 +294,35 @@ public class CrshAutoConfigurationTests { SecurityConfiguration.PASSWORD)); } + @Test + public void testSpringAuthenticationProviderAsDefaultConfiguration() throws Exception { + this.context = new AnnotationConfigWebApplicationContext(); + this.context.setServletContext(new MockServletContext()); + this.context.register(ManagementServerPropertiesAutoConfiguration.class); + this.context.register(SecurityAutoConfiguration.class); + this.context.register(SecurityConfiguration.class); + this.context.register(CrshAutoConfiguration.class); + this.context.refresh(); + + PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class); + + AuthenticationPlugin authenticationPlugin = null; + String authentication = lifeCycle.getConfig().getProperty("crash.auth"); + assertNotNull(authentication); + for (AuthenticationPlugin plugin : lifeCycle.getContext().getPlugins( + AuthenticationPlugin.class)) { + if (authentication.equals(plugin.getName())) { + authenticationPlugin = plugin; + break; + } + } + assertTrue(authenticationPlugin.authenticate(SecurityConfiguration.USERNAME, + SecurityConfiguration.PASSWORD)); + + assertFalse(authenticationPlugin.authenticate(UUID.randomUUID().toString(), + SecurityConfiguration.PASSWORD)); + } + @Configuration public static class SecurityConfiguration {