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 {