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 6b52a53947..951669c4c0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,6 +71,7 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.util.AntPathMatcher; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -215,10 +216,11 @@ public class CrshAutoConfiguration { @PostConstruct public void init() throws Exception { - FS commandFileSystem = createFileSystem(this.properties - .getCommandPathPatterns()); - FS configurationFileSystem = createFileSystem(this.properties - .getConfigPathPatterns()); + FS commandFileSystem = createFileSystem( + this.properties.getCommandPathPatterns(), + this.properties.getDisabledCommands()); + FS configurationFileSystem = createFileSystem( + this.properties.getConfigPathPatterns(), new String[0]); PluginDiscovery discovery = new BeanFactoryFilteringPluginDiscovery( this.resourceLoader.getClassLoader(), this.beanFactory, @@ -232,13 +234,14 @@ public class CrshAutoConfiguration { start(context); } - protected FS createFileSystem(String[] pathPatterns) throws IOException, - URISyntaxException { + protected FS createFileSystem(String[] pathPatterns, String[] filterPatterns) + throws IOException, URISyntaxException { Assert.notNull(pathPatterns, "PathPatterns must not be null"); + Assert.notNull(filterPatterns, "FilterPatterns must not be null"); FS fileSystem = new FS(); for (String pathPattern : pathPatterns) { fileSystem.mount(new SimpleFileSystemDriver(new DirectoryHandle( - pathPattern, this.resourceLoader))); + pathPattern, this.resourceLoader, filterPatterns))); } return fileSystem; } @@ -487,22 +490,36 @@ public class CrshAutoConfiguration { private final ResourcePatternResolver resourceLoader; - public DirectoryHandle(String name, ResourcePatternResolver resourceLoader) { + private final String[] filterPatterns; + + private final AntPathMatcher matcher = new AntPathMatcher(); + + public DirectoryHandle(String name, ResourcePatternResolver resourceLoader, + String[] filterPatterns) { super(name); this.resourceLoader = resourceLoader; + this.filterPatterns = filterPatterns; } public List members() throws IOException { Resource[] resources = this.resourceLoader.getResources(getName()); List files = new ArrayList(); for (Resource resource : resources) { - if (!resource.getURL().getPath().endsWith("/")) { + if (!resource.getURL().getPath().endsWith("/") && !shouldFilter(resource)) { files.add(new FileHandle(resource.getFilename(), resource)); } } return files; } + private boolean shouldFilter(Resource resource) { + for (String filterPattern : this.filterPatterns) { + if (this.matcher.match(filterPattern, resource.getFilename())) { + return true; + } + } + return false; + } } /** diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ShellProperties.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ShellProperties.java index b8cee69173..fd296f7cc0 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ShellProperties.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ShellProperties.java @@ -55,6 +55,8 @@ public class ShellProperties { private String[] configPathPatterns = new String[] { "classpath*:/crash/*" }; + private String[] disabledCommands = new String[] { "jpa*", "jdbc*", "jndi*" }; + private String[] disabledPlugins = new String[0]; private final Ssh ssh = new Ssh(); @@ -106,6 +108,15 @@ public class ShellProperties { return this.configPathPatterns; } + public void setDisabledCommands(String[] disabledCommands) { + Assert.notEmpty(disabledCommands); + this.disabledCommands = disabledCommands; + } + + public String[] getDisabledCommands() { + return this.disabledCommands; + } + public void setDisabledPlugins(String[] disabledPlugins) { Assert.notEmpty(disabledPlugins); this.disabledPlugins = disabledPlugins; 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 af4b41f6d7..9a01dc0d9b 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 @@ -132,7 +132,8 @@ public class CrshAutoConfigurationTests { PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class); - assertEquals("~/.ssh/id.pem", lifeCycle.getConfig().getProperty("crash.ssh.keypath")); + assertEquals("~/.ssh/id.pem", + lifeCycle.getConfig().getProperty("crash.ssh.keypath")); } @Test @@ -162,6 +163,24 @@ public class CrshAutoConfigurationTests { assertEquals(1, count); } + @Test + public void testDisabledCommandResolution() { + this.context = new AnnotationConfigWebApplicationContext(); + this.context.register(CrshAutoConfiguration.class); + this.context.refresh(); + + PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class); + + int count = 0; + Iterator resources = lifeCycle.getContext() + .loadResources("jdbc.groovy", ResourceKind.COMMAND).iterator(); + while (resources.hasNext()) { + count++; + resources.next(); + } + assertEquals(0, count); + } + @Test public void testAuthenticationProvidersAreInstalled() { this.context = new AnnotationConfigWebApplicationContext(); @@ -210,7 +229,8 @@ public class CrshAutoConfigurationTests { PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class); assertEquals("jaas", lifeCycle.getConfig().get("crash.auth")); - assertEquals("my-test-domain", lifeCycle.getConfig().get("crash.auth.jaas.domain")); + assertEquals("my-test-domain", lifeCycle.getConfig() + .get("crash.auth.jaas.domain")); } @Test @@ -258,7 +278,8 @@ public class CrshAutoConfigurationTests { } assertNotNull(authenticationPlugin); assertTrue(authenticationPlugin.authenticate("user", "password")); - assertFalse(authenticationPlugin.authenticate(UUID.randomUUID().toString(), "password")); + assertFalse(authenticationPlugin.authenticate(UUID.randomUUID().toString(), + "password")); } @Test @@ -284,9 +305,11 @@ public class CrshAutoConfigurationTests { break; } } - assertTrue(authenticationPlugin.authenticate(SecurityConfiguration.USERNAME, SecurityConfiguration.PASSWORD)); + assertTrue(authenticationPlugin.authenticate(SecurityConfiguration.USERNAME, + SecurityConfiguration.PASSWORD)); - assertFalse(authenticationPlugin.authenticate(UUID.randomUUID().toString(), SecurityConfiguration.PASSWORD)); + assertFalse(authenticationPlugin.authenticate(UUID.randomUUID().toString(), + SecurityConfiguration.PASSWORD)); } @Test @@ -311,9 +334,11 @@ public class CrshAutoConfigurationTests { break; } } - assertTrue(authenticationPlugin.authenticate(SecurityConfiguration.USERNAME, SecurityConfiguration.PASSWORD)); + assertTrue(authenticationPlugin.authenticate(SecurityConfiguration.USERNAME, + SecurityConfiguration.PASSWORD)); - assertFalse(authenticationPlugin.authenticate(UUID.randomUUID().toString(), SecurityConfiguration.PASSWORD)); + assertFalse(authenticationPlugin.authenticate(UUID.randomUUID().toString(), + SecurityConfiguration.PASSWORD)); } @Configuration diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ShellPropertiesTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ShellPropertiesTests.java index 73213385cd..11d1dda7f4 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ShellPropertiesTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ShellPropertiesTests.java @@ -121,6 +121,19 @@ public class ShellPropertiesTests { props.getDisabledPlugins()); } + @Test + public void testBindingDisabledCommands() { + ShellProperties props = new ShellProperties(); + RelaxedDataBinder binder = new RelaxedDataBinder(props, "shell"); + binder.setConversionService(new DefaultConversionService()); + binder.bind(new MutablePropertyValues(Collections.singletonMap( + "shell.disabled_commands", "pattern1, pattern2"))); + assertFalse(binder.getBindingResult().hasErrors()); + assertEquals(2, props.getDisabledCommands().length); + assertArrayEquals(new String[] { "pattern1", "pattern2" }, + props.getDisabledCommands()); + } + @Test public void testBindingSsh() { ShellProperties props = new ShellProperties();