Remove remote shell support
See gh-7044
This commit is contained in:
@@ -234,21 +234,6 @@
|
||||
<artifactId>tomcat-embed-el</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.shell</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.cli</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.embed.spring</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jolokia</groupId>
|
||||
<artifactId>jolokia-core</artifactId>
|
||||
@@ -334,11 +319,6 @@
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.connectors.telnet</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
|
||||
@@ -1,573 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.
|
||||
* 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 org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.crsh.auth.AuthenticationPlugin;
|
||||
import org.crsh.plugin.CRaSHPlugin;
|
||||
import org.crsh.plugin.PluginContext;
|
||||
import org.crsh.plugin.PluginDiscovery;
|
||||
import org.crsh.plugin.PluginLifeCycle;
|
||||
import org.crsh.plugin.PropertyDescriptor;
|
||||
import org.crsh.plugin.ServiceLoaderDiscovery;
|
||||
import org.crsh.vfs.FS;
|
||||
import org.crsh.vfs.spi.AbstractFSDriver;
|
||||
import org.crsh.vfs.spi.FSDriver;
|
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.CrshShellAuthenticationProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.CrshShellProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.JaasAuthenticationProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.KeyAuthenticationProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.SimpleAuthenticationProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.SpringAuthenticationProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.SpringVersion;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
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;
|
||||
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. If the CRaSH Telnet plugin is available on the classpath, Telnet daemon will be
|
||||
* launched on port 5000.
|
||||
* <p>
|
||||
* 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 {@code management.shell.auth.simple.username} and
|
||||
* {@code management.shell.auth.simple.password}.
|
||||
* <p>
|
||||
* 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
|
||||
* {@code management.shell.auth.type} is set to {@code spring} or if no explicit
|
||||
* {@code management.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 ManagementServerProperties}. Required roles can
|
||||
* be overridden by {@code management.shell.auth.spring.roles}.
|
||||
* <p>
|
||||
* 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. To configure plugins and the CRaSH
|
||||
* infrastructure add beans of type {@link CrshShellProperties} to the application
|
||||
* context.
|
||||
* <p>
|
||||
* Additional shell commands can be implemented using the guide and documentation at
|
||||
* <a href="http://www.crashub.org">crashub.org</a>. By default Boot will search for
|
||||
* commands using the following classpath scanning pattern {@code classpath*:/commands/**}
|
||||
* . To add different locations or override the default use
|
||||
* {@code management.shell.command-path-patterns} in your application configuration.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Matt Benson
|
||||
* @see ShellProperties
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(PluginLifeCycle.class)
|
||||
@EnableConfigurationProperties(ShellProperties.class)
|
||||
@AutoConfigureAfter({ SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class })
|
||||
@Deprecated
|
||||
public class CrshAutoConfiguration {
|
||||
|
||||
public static final String AUTH_PREFIX = ShellProperties.SHELL_PREFIX + ".auth";
|
||||
|
||||
private final ShellProperties properties;
|
||||
|
||||
public CrshAutoConfiguration(ShellProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(PluginLifeCycle.class)
|
||||
public CrshBootstrapBean shellBootstrap() {
|
||||
CrshBootstrapBean bootstrapBean = new CrshBootstrapBean();
|
||||
bootstrapBean.setConfig(this.properties.asCrshShellConfig());
|
||||
return bootstrapBean;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CrshAdditionalPropertiesConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = AUTH_PREFIX, name = "type", havingValue = "jaas")
|
||||
@ConditionalOnMissingBean(CrshShellAuthenticationProperties.class)
|
||||
public JaasAuthenticationProperties jaasAuthenticationProperties() {
|
||||
return new JaasAuthenticationProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = AUTH_PREFIX, name = "type", havingValue = "key")
|
||||
@ConditionalOnMissingBean(CrshShellAuthenticationProperties.class)
|
||||
public KeyAuthenticationProperties keyAuthenticationProperties() {
|
||||
return new KeyAuthenticationProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = AUTH_PREFIX, name = "type", havingValue = "simple", matchIfMissing = true)
|
||||
@ConditionalOnMissingBean(CrshShellAuthenticationProperties.class)
|
||||
public SimpleAuthenticationProperties simpleAuthenticationProperties() {
|
||||
return new SimpleAuthenticationProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to configure CRaSH to authenticate against Spring Security.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = AUTH_PREFIX, name = "type", havingValue = "spring", matchIfMissing = true)
|
||||
@ConditionalOnBean(AuthenticationManager.class)
|
||||
public static class AuthenticationManagerAdapterConfiguration {
|
||||
|
||||
private final ManagementServerProperties management;
|
||||
|
||||
public AuthenticationManagerAdapterConfiguration(
|
||||
ObjectProvider<ManagementServerProperties> managementProvider) {
|
||||
this.management = managementProvider.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManagerAdapter shellAuthenticationManager() {
|
||||
return new AuthenticationManagerAdapter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(CrshShellAuthenticationProperties.class)
|
||||
public SpringAuthenticationProperties springAuthenticationProperties() {
|
||||
// In case no management.shell.auth.type property is provided fall back to
|
||||
// Spring Security based authentication and get role to access shell from
|
||||
// ManagementServerProperties.
|
||||
// In case management.shell.auth.type is set to spring and roles are
|
||||
// configured using shell.auth.spring.roles the below default role will be
|
||||
// overridden by ConfigurationProperties.
|
||||
SpringAuthenticationProperties authenticationProperties = new SpringAuthenticationProperties();
|
||||
if (this.management != null) {
|
||||
List<String> roles = this.management.getSecurity().getRoles();
|
||||
authenticationProperties
|
||||
.setRoles(roles.toArray(new String[roles.size()]));
|
||||
}
|
||||
return authenticationProperties;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Bean used to bootstrap the CRaSH shell.
|
||||
*/
|
||||
public static class CrshBootstrapBean extends PluginLifeCycle {
|
||||
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Autowired
|
||||
private ShellProperties properties;
|
||||
|
||||
@Autowired
|
||||
private ResourcePatternResolver resourceLoader;
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
stop();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
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,
|
||||
this.properties.getDisabledPlugins());
|
||||
|
||||
PluginContext context = new PluginContext(discovery,
|
||||
createPluginContextAttributes(), commandFileSystem,
|
||||
configurationFileSystem, this.resourceLoader.getClassLoader());
|
||||
|
||||
context.refresh();
|
||||
start(context);
|
||||
}
|
||||
|
||||
protected FS createFileSystem(String[] pathPatterns, String[] filterPatterns) {
|
||||
Assert.notNull(pathPatterns, "PathPatterns must not be null");
|
||||
Assert.notNull(filterPatterns, "FilterPatterns must not be null");
|
||||
FS fileSystem = new FS();
|
||||
for (String pathPattern : pathPatterns) {
|
||||
try {
|
||||
fileSystem.mount(new SimpleFileSystemDriver(new DirectoryHandle(
|
||||
pathPattern, this.resourceLoader, filterPatterns)));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to mount file system for '" + pathPattern + "'", ex);
|
||||
}
|
||||
}
|
||||
return fileSystem;
|
||||
}
|
||||
|
||||
protected Map<String, Object> createPluginContextAttributes() {
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
String bootVersion = CrshAutoConfiguration.class.getPackage()
|
||||
.getImplementationVersion();
|
||||
if (bootVersion != null) {
|
||||
attributes.put("spring.boot.version", bootVersion);
|
||||
}
|
||||
attributes.put("spring.version", SpringVersion.getVersion());
|
||||
if (this.beanFactory != null) {
|
||||
attributes.put("spring.beanfactory", this.beanFactory);
|
||||
}
|
||||
if (this.environment != null) {
|
||||
attributes.put("spring.environment", this.environment);
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts a Spring Security {@link AuthenticationManager} for use with CRaSH.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class AuthenticationManagerAdapter extends
|
||||
CRaSHPlugin<AuthenticationPlugin> implements AuthenticationPlugin<String> {
|
||||
|
||||
private static final PropertyDescriptor<String> ROLES = PropertyDescriptor.create(
|
||||
"auth.spring.roles", "ADMIN",
|
||||
"Comma separated list of roles required to access the shell");
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired(required = false)
|
||||
@Qualifier("shellAccessDecisionManager")
|
||||
private AccessDecisionManager accessDecisionManager;
|
||||
|
||||
private String[] roles = new String[] { "ADMIN" };
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String username, String password) throws Exception {
|
||||
Authentication token = new UsernamePasswordAuthenticationToken(username,
|
||||
password);
|
||||
try {
|
||||
// Authenticate first to make sure credentials are valid
|
||||
token = this.authenticationManager.authenticate(token);
|
||||
}
|
||||
catch (AuthenticationException ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test access rights if a Spring Security AccessDecisionManager is installed
|
||||
if (this.accessDecisionManager != null && token.isAuthenticated()
|
||||
&& this.roles != null) {
|
||||
try {
|
||||
this.accessDecisionManager.decide(token, this,
|
||||
SecurityConfig.createList(this.roles));
|
||||
}
|
||||
catch (AccessDeniedException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return token.isAuthenticated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getCredentialType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationPlugin<String> getImplementation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "spring";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
String rolesPropertyValue = getContext().getProperty(ROLES);
|
||||
if (rolesPropertyValue != null) {
|
||||
this.roles = StringUtils
|
||||
.commaDelimitedListToStringArray(rolesPropertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<PropertyDescriptor<?>> createConfigurationCapabilities() {
|
||||
return Arrays.<PropertyDescriptor<?>>asList(ROLES);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ServiceLoaderDiscovery} to expose {@link CRaSHPlugin} Beans from Spring and
|
||||
* deal with filtering disabled plugins.
|
||||
*/
|
||||
private static class BeanFactoryFilteringPluginDiscovery
|
||||
extends ServiceLoaderDiscovery {
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
private final String[] disabledPlugins;
|
||||
|
||||
BeanFactoryFilteringPluginDiscovery(ClassLoader classLoader,
|
||||
ListableBeanFactory beanFactory, String[] disabledPlugins)
|
||||
throws NullPointerException {
|
||||
super(classLoader);
|
||||
this.beanFactory = beanFactory;
|
||||
this.disabledPlugins = disabledPlugins;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Iterable<CRaSHPlugin<?>> getPlugins() {
|
||||
List<CRaSHPlugin<?>> plugins = new ArrayList<CRaSHPlugin<?>>();
|
||||
|
||||
for (CRaSHPlugin<?> p : super.getPlugins()) {
|
||||
if (isEnabled(p)) {
|
||||
plugins.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<CRaSHPlugin> pluginBeans = this.beanFactory
|
||||
.getBeansOfType(CRaSHPlugin.class).values();
|
||||
for (CRaSHPlugin<?> pluginBean : pluginBeans) {
|
||||
if (isEnabled(pluginBean)) {
|
||||
plugins.add(pluginBean);
|
||||
}
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
protected boolean isEnabled(CRaSHPlugin<?> plugin) {
|
||||
Assert.notNull(plugin, "Plugin must not be null");
|
||||
|
||||
if (ObjectUtils.isEmpty(this.disabledPlugins)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<Class<?>> pluginClasses = ClassUtils.getAllInterfacesAsSet(plugin);
|
||||
pluginClasses.add(plugin.getClass());
|
||||
|
||||
for (Class<?> pluginClass : pluginClasses) {
|
||||
if (!isEnabled(pluginClass)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isEnabled(Class<?> pluginClass) {
|
||||
for (String disabledPlugin : this.disabledPlugins) {
|
||||
if (ClassUtils.getShortName(pluginClass).equalsIgnoreCase(disabledPlugin)
|
||||
|| ClassUtils.getQualifiedName(pluginClass)
|
||||
.equalsIgnoreCase(disabledPlugin)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FSDriver} to wrap Spring's {@link Resource} abstraction to CRaSH.
|
||||
*/
|
||||
private static class SimpleFileSystemDriver extends AbstractFSDriver<ResourceHandle> {
|
||||
|
||||
private final ResourceHandle root;
|
||||
|
||||
SimpleFileSystemDriver(ResourceHandle handle) {
|
||||
this.root = handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ResourceHandle> children(ResourceHandle handle)
|
||||
throws IOException {
|
||||
if (handle instanceof DirectoryHandle) {
|
||||
return ((DirectoryHandle) handle).members();
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModified(ResourceHandle handle) throws IOException {
|
||||
if (handle instanceof FileHandle) {
|
||||
return ((FileHandle) handle).getLastModified();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDir(ResourceHandle handle) throws IOException {
|
||||
return handle instanceof DirectoryHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name(ResourceHandle handle) throws IOException {
|
||||
return handle.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<InputStream> open(ResourceHandle handle) throws IOException {
|
||||
if (handle instanceof FileHandle) {
|
||||
return Collections.singletonList(((FileHandle) handle).openStream())
|
||||
.iterator();
|
||||
}
|
||||
return Collections.<InputStream>emptyList().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceHandle root() throws IOException {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Base for handles to Spring {@link Resource}s.
|
||||
*/
|
||||
private abstract static class ResourceHandle {
|
||||
|
||||
private final String name;
|
||||
|
||||
ResourceHandle(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ResourceHandle} for a directory.
|
||||
*/
|
||||
private static class DirectoryHandle extends ResourceHandle {
|
||||
|
||||
private final ResourcePatternResolver resourceLoader;
|
||||
|
||||
private final String[] filterPatterns;
|
||||
|
||||
private final AntPathMatcher matcher = new AntPathMatcher();
|
||||
|
||||
DirectoryHandle(String name, ResourcePatternResolver resourceLoader,
|
||||
String[] filterPatterns) {
|
||||
super(name);
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.filterPatterns = filterPatterns;
|
||||
}
|
||||
|
||||
public List<ResourceHandle> members() throws IOException {
|
||||
Resource[] resources = this.resourceLoader.getResources(getName());
|
||||
List<ResourceHandle> files = new ArrayList<ResourceHandle>();
|
||||
for (Resource resource : resources) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ResourceHandle} for a file backed by a Spring {@link Resource}.
|
||||
*/
|
||||
private static class FileHandle extends ResourceHandle {
|
||||
|
||||
private final Resource resource;
|
||||
|
||||
FileHandle(String name, Resource resource) {
|
||||
super(name);
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public InputStream openStream() throws IOException {
|
||||
return this.resource.getInputStream();
|
||||
}
|
||||
|
||||
public long getLastModified() {
|
||||
try {
|
||||
return this.resource.lastModified();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,547 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.
|
||||
* 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 org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration properties for the shell subsystem.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Phillip Webb
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@ConfigurationProperties(prefix = ShellProperties.SHELL_PREFIX, ignoreUnknownFields = true)
|
||||
@Deprecated
|
||||
public class ShellProperties {
|
||||
|
||||
public static final String SHELL_PREFIX = "management.shell";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ShellProperties.class);
|
||||
|
||||
private final Auth auth = new Auth();
|
||||
|
||||
@Autowired(required = false)
|
||||
private CrshShellProperties[] additionalProperties = new CrshShellProperties[] {
|
||||
new SimpleAuthenticationProperties() };
|
||||
|
||||
/**
|
||||
* Scan for changes and update the command if necessary (in seconds).
|
||||
*/
|
||||
private int commandRefreshInterval = -1;
|
||||
|
||||
/**
|
||||
* Patterns to use to look for commands.
|
||||
*/
|
||||
private String[] commandPathPatterns = new String[] { "classpath*:/commands/**",
|
||||
"classpath*:/crash/commands/**" };
|
||||
|
||||
/**
|
||||
* Patterns to use to look for configurations.
|
||||
*/
|
||||
private String[] configPathPatterns = new String[] { "classpath*:/crash/*" };
|
||||
|
||||
/**
|
||||
* Comma-separated list of commands to disable.
|
||||
*/
|
||||
private String[] disabledCommands = new String[] { "jpa*", "jdbc*", "jndi*" };
|
||||
|
||||
/**
|
||||
* Comma-separated list of plugins to disable. Certain plugins are disabled by default
|
||||
* based on the environment.
|
||||
*/
|
||||
private String[] disabledPlugins = new String[0];
|
||||
|
||||
private final Ssh ssh = new Ssh();
|
||||
|
||||
private final Telnet telnet = new Telnet();
|
||||
|
||||
public Auth getAuth() {
|
||||
return this.auth;
|
||||
}
|
||||
|
||||
public CrshShellProperties[] getAdditionalProperties() {
|
||||
return this.additionalProperties;
|
||||
}
|
||||
|
||||
public void setCommandRefreshInterval(int commandRefreshInterval) {
|
||||
this.commandRefreshInterval = commandRefreshInterval;
|
||||
}
|
||||
|
||||
public int getCommandRefreshInterval() {
|
||||
return this.commandRefreshInterval;
|
||||
}
|
||||
|
||||
public void setCommandPathPatterns(String[] commandPathPatterns) {
|
||||
Assert.notEmpty(commandPathPatterns, "CommandPathPatterns must not be empty");
|
||||
this.commandPathPatterns = commandPathPatterns;
|
||||
}
|
||||
|
||||
public String[] getCommandPathPatterns() {
|
||||
return this.commandPathPatterns;
|
||||
}
|
||||
|
||||
public void setConfigPathPatterns(String[] configPathPatterns) {
|
||||
Assert.notEmpty(configPathPatterns, "ConfigPathPatterns must not be empty");
|
||||
this.configPathPatterns = configPathPatterns;
|
||||
}
|
||||
|
||||
public String[] getConfigPathPatterns() {
|
||||
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;
|
||||
}
|
||||
|
||||
public String[] getDisabledPlugins() {
|
||||
return this.disabledPlugins;
|
||||
}
|
||||
|
||||
public Ssh getSsh() {
|
||||
return this.ssh;
|
||||
}
|
||||
|
||||
public Telnet getTelnet() {
|
||||
return this.telnet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a properties file configured from these settings that can be applied to a
|
||||
* CRaSH shell instance.
|
||||
* @return the CRaSH properties
|
||||
*/
|
||||
public Properties asCrshShellConfig() {
|
||||
Properties properties = new Properties();
|
||||
this.ssh.applyToCrshShellConfig(properties);
|
||||
this.telnet.applyToCrshShellConfig(properties);
|
||||
|
||||
for (CrshShellProperties shellProperties : this.additionalProperties) {
|
||||
shellProperties.applyToCrshShellConfig(properties);
|
||||
}
|
||||
|
||||
if (this.commandRefreshInterval > 0) {
|
||||
properties.put("crash.vfs.refresh_period",
|
||||
String.valueOf(this.commandRefreshInterval));
|
||||
}
|
||||
|
||||
// special handling for disabling Ssh and Telnet support
|
||||
List<String> dp = new ArrayList<String>(Arrays.asList(this.disabledPlugins));
|
||||
if (!this.ssh.isEnabled()) {
|
||||
dp.add("org.crsh.ssh.SSHPlugin");
|
||||
}
|
||||
if (!this.telnet.isEnabled()) {
|
||||
dp.add("org.crsh.telnet.TelnetPlugin");
|
||||
}
|
||||
this.disabledPlugins = dp.toArray(new String[dp.size()]);
|
||||
|
||||
validateCrshShellConfig(properties);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic validation of applied CRaSH shell configuration.
|
||||
* @param properties the properties to validate
|
||||
*/
|
||||
protected void validateCrshShellConfig(Properties properties) {
|
||||
getAuth().validateCrshShellConfig(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for CRaSH properties.
|
||||
*/
|
||||
public static abstract class CrshShellProperties {
|
||||
|
||||
/**
|
||||
* Apply the properties to a CRaSH configuration.
|
||||
* @param config the CRaSH configuration properties
|
||||
*/
|
||||
protected abstract void applyToCrshShellConfig(Properties config);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for Auth specific properties.
|
||||
*/
|
||||
public static abstract class CrshShellAuthenticationProperties
|
||||
extends CrshShellProperties {
|
||||
|
||||
}
|
||||
|
||||
public static class Auth {
|
||||
|
||||
/**
|
||||
* Authentication type. Auto-detected according to the environment (i.e. if Spring
|
||||
* Security is available, "spring" is used by default).
|
||||
*/
|
||||
private String type = "simple";
|
||||
|
||||
private boolean defaultAuth = true;
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
Assert.hasLength(type, "Auth type must not be empty");
|
||||
this.type = type;
|
||||
this.defaultAuth = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic validation of applied CRaSH shell configuration.
|
||||
* @param properties the properties to validate
|
||||
*/
|
||||
protected void validateCrshShellConfig(Properties properties) {
|
||||
String finalAuth = properties.getProperty("crash.auth");
|
||||
if (!this.defaultAuth && !this.type.equals(finalAuth)) {
|
||||
logger.warn(String.format(
|
||||
"Shell authentication fell back to method '%s' opposed to "
|
||||
+ "configured method '%s'. Please check your classpath.",
|
||||
finalAuth, this.type));
|
||||
}
|
||||
// Make sure we keep track of final authentication method
|
||||
this.type = finalAuth;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* SSH properties.
|
||||
*/
|
||||
public static class Ssh extends CrshShellProperties {
|
||||
|
||||
/**
|
||||
* Enable CRaSH SSH support.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Path to the SSH server key.
|
||||
*/
|
||||
private String keyPath;
|
||||
|
||||
/**
|
||||
* SSH port.
|
||||
*/
|
||||
private Integer port = 2000;
|
||||
|
||||
/**
|
||||
* Number of milliseconds after user will be prompted to login again.
|
||||
*/
|
||||
private Integer authTimeout = 600000;
|
||||
|
||||
/**
|
||||
* Number of milliseconds after which unused connections are closed.
|
||||
*/
|
||||
private Integer idleTimeout = 600000;
|
||||
|
||||
@Override
|
||||
protected void applyToCrshShellConfig(Properties config) {
|
||||
if (this.enabled) {
|
||||
config.put("crash.ssh.port", String.valueOf(this.port));
|
||||
config.put("crash.ssh.auth_timeout", String.valueOf(this.authTimeout));
|
||||
config.put("crash.ssh.idle_timeout", String.valueOf(this.idleTimeout));
|
||||
if (this.keyPath != null) {
|
||||
config.put("crash.ssh.keypath", this.keyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setKeyPath(String keyPath) {
|
||||
Assert.hasText(keyPath, "keyPath must have text");
|
||||
this.keyPath = keyPath;
|
||||
}
|
||||
|
||||
public String getKeyPath() {
|
||||
return this.keyPath;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
Assert.notNull(port, "port must not be null");
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public Integer getIdleTimeout() {
|
||||
return this.idleTimeout;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(Integer idleTimeout) {
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
public Integer getAuthTimeout() {
|
||||
return this.authTimeout;
|
||||
}
|
||||
|
||||
public void setAuthTimeout(Integer authTimeout) {
|
||||
this.authTimeout = authTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Telnet properties.
|
||||
*/
|
||||
public static class Telnet extends CrshShellProperties {
|
||||
|
||||
/**
|
||||
* Enable CRaSH telnet support. Enabled by default if the TelnetPlugin is
|
||||
* available.
|
||||
*/
|
||||
private boolean enabled = ClassUtils.isPresent("org.crsh.telnet.TelnetPlugin",
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
|
||||
/**
|
||||
* Telnet port.
|
||||
*/
|
||||
private Integer port = 5000;
|
||||
|
||||
@Override
|
||||
protected void applyToCrshShellConfig(Properties config) {
|
||||
if (this.enabled) {
|
||||
config.put("crash.telnet.port", String.valueOf(this.port));
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
Assert.notNull(port, "port must not be null");
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth specific properties for JAAS authentication.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = SHELL_PREFIX
|
||||
+ ".auth.jaas", ignoreUnknownFields = false)
|
||||
public static class JaasAuthenticationProperties
|
||||
extends CrshShellAuthenticationProperties {
|
||||
|
||||
/**
|
||||
* JAAS domain.
|
||||
*/
|
||||
private String domain = "my-domain";
|
||||
|
||||
@Override
|
||||
protected void applyToCrshShellConfig(Properties config) {
|
||||
config.put("crash.auth", "jaas");
|
||||
config.put("crash.auth.jaas.domain", this.domain);
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
Assert.hasText(domain, "domain must have text");
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth specific properties for key authentication.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = SHELL_PREFIX
|
||||
+ ".auth.key", ignoreUnknownFields = false)
|
||||
public static class KeyAuthenticationProperties
|
||||
extends CrshShellAuthenticationProperties {
|
||||
|
||||
/**
|
||||
* Path to the authentication key. This should point to a valid ".pem" file.
|
||||
*/
|
||||
private String path;
|
||||
|
||||
@Override
|
||||
protected void applyToCrshShellConfig(Properties config) {
|
||||
config.put("crash.auth", "key");
|
||||
if (this.path != null) {
|
||||
config.put("crash.auth.key.path", this.path);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
Assert.hasText(path, "path must have text");
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth specific properties for simple authentication.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = SHELL_PREFIX
|
||||
+ ".auth.simple", ignoreUnknownFields = false)
|
||||
public static class SimpleAuthenticationProperties
|
||||
extends CrshShellAuthenticationProperties {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(SimpleAuthenticationProperties.class);
|
||||
|
||||
private User user = new User();
|
||||
|
||||
@Override
|
||||
protected void applyToCrshShellConfig(Properties config) {
|
||||
config.put("crash.auth", "simple");
|
||||
config.put("crash.auth.simple.username", this.user.getName());
|
||||
config.put("crash.auth.simple.password", this.user.getPassword());
|
||||
if (this.user.isDefaultPassword()) {
|
||||
logger.info(String.format(
|
||||
"%n%nUsing default password for shell access: %s%n%n",
|
||||
this.user.getPassword()));
|
||||
}
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public static class User {
|
||||
|
||||
/**
|
||||
* Login user.
|
||||
*/
|
||||
private String name = "user";
|
||||
|
||||
/**
|
||||
* Login password.
|
||||
*/
|
||||
private String password = UUID.randomUUID().toString();
|
||||
|
||||
private boolean defaultPassword = true;
|
||||
|
||||
boolean isDefaultPassword() {
|
||||
return this.defaultPassword;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
Assert.hasLength(name, "name must have text");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
if (password.startsWith("${") && password.endsWith("}")
|
||||
|| !StringUtils.hasLength(password)) {
|
||||
return;
|
||||
}
|
||||
this.password = password;
|
||||
this.defaultPassword = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth specific properties for Spring authentication.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = SHELL_PREFIX
|
||||
+ ".auth.spring", ignoreUnknownFields = false)
|
||||
public static class SpringAuthenticationProperties
|
||||
extends CrshShellAuthenticationProperties {
|
||||
|
||||
/**
|
||||
* Comma-separated list of required roles to login to the CRaSH console.
|
||||
*/
|
||||
private String[] roles = new String[] { "ADMIN" };
|
||||
|
||||
@Override
|
||||
protected void applyToCrshShellConfig(Properties config) {
|
||||
config.put("crash.auth", "spring");
|
||||
config.put("crash.auth.spring.roles",
|
||||
StringUtils.arrayToCommaDelimitedString(this.roles));
|
||||
}
|
||||
|
||||
public void setRoles(String[] roles) {
|
||||
// 'roles' can be null. This means no special to access right to connect to
|
||||
// shell is required.
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public String[] getRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -253,27 +253,6 @@
|
||||
"name": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "management.shell.auth.type",
|
||||
"values": [
|
||||
{
|
||||
"value": "simple",
|
||||
"description": "Use a simple user/password based authentication."
|
||||
},
|
||||
{
|
||||
"value": "spring",
|
||||
"description": "Integrate with Spring Security."
|
||||
},
|
||||
{
|
||||
"value": "key",
|
||||
"description": "Use a Key-based authentication."
|
||||
},
|
||||
{
|
||||
"value": "jaas",
|
||||
"description": "Use JAAS authentication."
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.CacheStatisticsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.
|
||||
* 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 org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.crsh.auth.AuthenticationPlugin;
|
||||
import org.crsh.auth.JaasAuthenticationPlugin;
|
||||
import org.crsh.lang.impl.java.JavaLanguage;
|
||||
import org.crsh.lang.spi.Language;
|
||||
import org.crsh.plugin.PluginContext;
|
||||
import org.crsh.plugin.PluginLifeCycle;
|
||||
import org.crsh.plugin.ResourceKind;
|
||||
import org.crsh.telnet.term.processor.ProcessorIOHandler;
|
||||
import org.crsh.telnet.term.spi.TermIOHandler;
|
||||
import org.crsh.vfs.Resource;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.boot.testutil.Matched;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.access.vote.UnanimousBased;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.isA;
|
||||
|
||||
/**
|
||||
* Tests for {@link CrshAutoConfiguration}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Andreas Ahlenstorf
|
||||
* @author Eddú Meléndez
|
||||
* @author Matt Benson
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Deprecated
|
||||
public class CrshAutoConfigurationTests {
|
||||
|
||||
private AnnotationConfigWebApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabledPlugins() throws Exception {
|
||||
load("management.shell.disabled_plugins="
|
||||
+ "termIOHandler, org.crsh.auth.AuthenticationPlugin, javaLanguage");
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle).isNotNull();
|
||||
assertThat(lifeCycle.getContext().getPlugins(TermIOHandler.class))
|
||||
.filteredOn(Matched.<TermIOHandler>when(isA(ProcessorIOHandler.class)))
|
||||
.isEmpty();
|
||||
assertThat(lifeCycle.getContext().getPlugins(AuthenticationPlugin.class))
|
||||
.filteredOn(Matched
|
||||
.<AuthenticationPlugin>when(isA(JaasAuthenticationPlugin.class)))
|
||||
.isEmpty();
|
||||
assertThat(lifeCycle.getContext().getPlugins(Language.class))
|
||||
.filteredOn(Matched.<Language>when(isA(JavaLanguage.class))).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributes() throws Exception {
|
||||
load();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
Map<String, Object> attributes = lifeCycle.getContext().getAttributes();
|
||||
assertThat(attributes.containsKey("spring.version")).isTrue();
|
||||
assertThat(attributes.containsKey("spring.beanfactory")).isTrue();
|
||||
assertThat(attributes.get("spring.beanfactory"))
|
||||
.isEqualTo(this.context.getBeanFactory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSshConfiguration() {
|
||||
load("management.shell.ssh.enabled=true", "management.shell.ssh.port=3333");
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle.getConfig().getProperty("crash.ssh.port")).isEqualTo("3333");
|
||||
assertThat(lifeCycle.getConfig().getProperty("crash.ssh.auth_timeout"))
|
||||
.isEqualTo("600000");
|
||||
assertThat(lifeCycle.getConfig().getProperty("crash.ssh.idle_timeout"))
|
||||
.isEqualTo("600000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSshConfigurationWithKeyPath() {
|
||||
load("management.shell.ssh.enabled=true",
|
||||
"management.shell.ssh.key_path=~/.ssh/id.pem");
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle.getConfig().getProperty("crash.ssh.keypath"))
|
||||
.isEqualTo("~/.ssh/id.pem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSshConfigurationCustomTimeouts() {
|
||||
load("management.shell.ssh.enabled=true",
|
||||
"management.shell.ssh.auth-timeout=300000",
|
||||
"management.shell.ssh.idle-timeout=400000");
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle.getConfig().getProperty("crash.ssh.auth_timeout"))
|
||||
.isEqualTo("300000");
|
||||
assertThat(lifeCycle.getConfig().getProperty("crash.ssh.idle_timeout"))
|
||||
.isEqualTo("400000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommandResolution() {
|
||||
load();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
int count = 0;
|
||||
Iterator<Resource> resources = lifeCycle.getContext()
|
||||
.loadResources("login", ResourceKind.LIFECYCLE).iterator();
|
||||
while (resources.hasNext()) {
|
||||
count++;
|
||||
resources.next();
|
||||
}
|
||||
assertThat(count).isEqualTo(1);
|
||||
count = 0;
|
||||
resources = lifeCycle.getContext()
|
||||
.loadResources("sleep.groovy", ResourceKind.COMMAND).iterator();
|
||||
while (resources.hasNext()) {
|
||||
count++;
|
||||
resources.next();
|
||||
}
|
||||
assertThat(count).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabledCommandResolution() {
|
||||
load();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
int count = 0;
|
||||
Iterator<Resource> resources = lifeCycle.getContext()
|
||||
.loadResources("jdbc.groovy", ResourceKind.COMMAND).iterator();
|
||||
while (resources.hasNext()) {
|
||||
count++;
|
||||
resources.next();
|
||||
}
|
||||
assertThat(count).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationProvidersAreInstalled() {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityConfiguration.class);
|
||||
this.context.register(CrshAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
PluginContext pluginContext = lifeCycle.getContext();
|
||||
int count = 0;
|
||||
Iterator<AuthenticationPlugin> plugins = pluginContext
|
||||
.getPlugins(AuthenticationPlugin.class).iterator();
|
||||
while (plugins.hasNext()) {
|
||||
count++;
|
||||
plugins.next();
|
||||
}
|
||||
assertThat(count).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultAuthenticationProvider() {
|
||||
MockEnvironment env = new MockEnvironment();
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setEnvironment(env);
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(CrshAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle.getConfig().get("crash.auth")).isEqualTo("simple");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJaasAuthenticationProvider() {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"management.shell.auth.type=jaas",
|
||||
"management.shell.auth.jaas.domain=my-test-domain");
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityConfiguration.class);
|
||||
this.context.register(CrshAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle.getConfig().get("crash.auth")).isEqualTo("jaas");
|
||||
assertThat(lifeCycle.getConfig().get("crash.auth.jaas.domain"))
|
||||
.isEqualTo("my-test-domain");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyAuthenticationProvider() {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"management.shell.auth.type=key",
|
||||
"management.shell.auth.key.path=~/test.pem");
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityConfiguration.class);
|
||||
this.context.register(CrshAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle.getConfig().get("crash.auth")).isEqualTo("key");
|
||||
assertThat(lifeCycle.getConfig().get("crash.auth.key.path"))
|
||||
.isEqualTo("~/test.pem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleAuthenticationProvider() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"management.shell.auth.type=simple",
|
||||
"management.shell.auth.simple.user.name=user",
|
||||
"management.shell.auth.simple.user.password=password");
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityConfiguration.class);
|
||||
this.context.register(CrshAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
assertThat(lifeCycle.getConfig().get("crash.auth")).isEqualTo("simple");
|
||||
AuthenticationPlugin<String> authenticationPlugin = null;
|
||||
String authentication = lifeCycle.getConfig().getProperty("crash.auth");
|
||||
assertThat(authentication).isNotNull();
|
||||
for (AuthenticationPlugin plugin : lifeCycle.getContext()
|
||||
.getPlugins(AuthenticationPlugin.class)) {
|
||||
if (authentication.equals(plugin.getName())) {
|
||||
authenticationPlugin = plugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertThat(authenticationPlugin).isNotNull();
|
||||
assertThat(authenticationPlugin.authenticate("user", "password")).isTrue();
|
||||
assertThat(authenticationPlugin.authenticate(UUID.randomUUID().toString(),
|
||||
"password")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringAuthenticationProvider() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"management.shell.auth.type=spring");
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityConfiguration.class);
|
||||
this.context.register(CrshAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
PluginLifeCycle lifeCycle = this.context.getBean(PluginLifeCycle.class);
|
||||
AuthenticationPlugin<String> authenticationPlugin = null;
|
||||
String authentication = lifeCycle.getConfig().getProperty("crash.auth");
|
||||
assertThat(authentication).isNotNull();
|
||||
for (AuthenticationPlugin plugin : lifeCycle.getContext()
|
||||
.getPlugins(AuthenticationPlugin.class)) {
|
||||
if (authentication.equals(plugin.getName())) {
|
||||
authenticationPlugin = plugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertThat(authenticationPlugin.authenticate(SecurityConfiguration.USERNAME,
|
||||
SecurityConfiguration.PASSWORD)).isTrue();
|
||||
assertThat(authenticationPlugin.authenticate(UUID.randomUUID().toString(),
|
||||
SecurityConfiguration.PASSWORD)).isFalse();
|
||||
}
|
||||
|
||||
@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<String> authenticationPlugin = null;
|
||||
String authentication = lifeCycle.getConfig().getProperty("crash.auth");
|
||||
assertThat(authentication).isNotNull();
|
||||
for (AuthenticationPlugin plugin : lifeCycle.getContext()
|
||||
.getPlugins(AuthenticationPlugin.class)) {
|
||||
if (authentication.equals(plugin.getName())) {
|
||||
authenticationPlugin = plugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertThat(authenticationPlugin.authenticate(SecurityConfiguration.USERNAME,
|
||||
SecurityConfiguration.PASSWORD)).isTrue();
|
||||
assertThat(authenticationPlugin.authenticate(UUID.randomUUID().toString(),
|
||||
SecurityConfiguration.PASSWORD)).isFalse();
|
||||
}
|
||||
|
||||
private void load(String... environment) {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context, environment);
|
||||
this.context.register(CrshAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class SecurityConfiguration {
|
||||
|
||||
public static final String USERNAME = UUID.randomUUID().toString();
|
||||
|
||||
public static final String PASSWORD = UUID.randomUUID().toString();
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
return new AuthenticationManager() {
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
if (authentication.getName().equals(USERNAME)
|
||||
&& authentication.getCredentials().equals(PASSWORD)) {
|
||||
authentication = new UsernamePasswordAuthenticationToken(
|
||||
authentication.getPrincipal(),
|
||||
authentication.getCredentials(), Collections
|
||||
.singleton(new SimpleGrantedAuthority("ADMIN")));
|
||||
}
|
||||
else {
|
||||
throw new BadCredentialsException(
|
||||
"Invalid username and password");
|
||||
}
|
||||
return authentication;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccessDecisionManager shellAccessDecisionManager() {
|
||||
List<AccessDecisionVoter<?>> voters = new ArrayList<AccessDecisionVoter<?>>();
|
||||
RoleVoter voter = new RoleVoter();
|
||||
voter.setRolePrefix("");
|
||||
voters.add(voter);
|
||||
return new UnanimousBased(voters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.
|
||||
* 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 org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.crsh.plugin.PluginLifeCycle;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.CrshShellProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.JaasAuthenticationProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.KeyAuthenticationProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.SimpleAuthenticationProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.ShellProperties.SpringAuthenticationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ShellProperties}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Deprecated
|
||||
public class ShellPropertiesTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingAuth() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.auth.type=spring");
|
||||
assertThat(props.getAuth().getType()).isEqualTo("spring");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingAuthIfEmpty() {
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("Auth type must not be empty");
|
||||
load(ShellProperties.class, "management.shell.auth.type= ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingCommandRefreshInterval() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.command-refresh-interval=1");
|
||||
assertThat(props.getCommandRefreshInterval()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingCommandPathPatterns() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.command-path-patterns=pattern1, pattern2");
|
||||
assertThat(props.getCommandPathPatterns().length).isEqualTo(2);
|
||||
Assert.assertArrayEquals(new String[] { "pattern1", "pattern2" },
|
||||
props.getCommandPathPatterns());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingConfigPathPatterns() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.config-path-patterns=pattern1, pattern2");
|
||||
assertThat(props.getConfigPathPatterns().length).isEqualTo(2);
|
||||
Assert.assertArrayEquals(new String[] { "pattern1", "pattern2" },
|
||||
props.getConfigPathPatterns());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingDisabledPlugins() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.disabled-plugins=pattern1, pattern2");
|
||||
assertThat(props.getDisabledPlugins().length).isEqualTo(2);
|
||||
assertThat(props.getDisabledPlugins()).containsExactly("pattern1", "pattern2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingDisabledCommands() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.disabled-commands=pattern1, pattern2");
|
||||
assertThat(props.getDisabledCommands()).containsExactly("pattern1", "pattern2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingSsh() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.ssh.enabled=true", "management.shell.ssh.port=2222",
|
||||
"management.shell.ssh.key-path=~/.ssh/test.pem");
|
||||
Properties p = props.asCrshShellConfig();
|
||||
assertThat(p.get("crash.ssh.port")).isEqualTo("2222");
|
||||
assertThat(p.get("crash.ssh.keypath")).isEqualTo("~/.ssh/test.pem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingSshIgnored() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.ssh.enabled=false", "management.shell.ssh.port=2222",
|
||||
"management.shell.ssh.key-path=~/.ssh/test.pem");
|
||||
Properties p = props.asCrshShellConfig();
|
||||
assertThat(p.get("crash.ssh.port")).isNull();
|
||||
assertThat(p.get("crash.ssh.keypath")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingTelnet() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.telnet.enabled=true",
|
||||
"management.shell.telnet.port=2222");
|
||||
Properties p = props.asCrshShellConfig();
|
||||
assertThat(p.get("crash.telnet.port")).isEqualTo("2222");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingTelnetIgnored() {
|
||||
ShellProperties props = load(ShellProperties.class,
|
||||
"management.shell.telnet.enabled=false",
|
||||
"management.shell.telnet.port=2222");
|
||||
Properties p = props.asCrshShellConfig();
|
||||
assertThat(p.get("crash.telnet.port")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingJaas() {
|
||||
JaasAuthenticationProperties props = load(JaasAuthenticationProperties.class,
|
||||
"management.shell.auth.jaas.domain=my-test-domain");
|
||||
Properties p = new Properties();
|
||||
props.applyToCrshShellConfig(p);
|
||||
assertThat(p.get("crash.auth.jaas.domain")).isEqualTo("my-test-domain");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingKey() {
|
||||
KeyAuthenticationProperties props = load(KeyAuthenticationProperties.class,
|
||||
"management.shell.auth.key.path=~/.ssh/test.pem");
|
||||
Properties p = new Properties();
|
||||
props.applyToCrshShellConfig(p);
|
||||
assertThat(p.get("crash.auth.key.path")).isEqualTo("~/.ssh/test.pem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingKeyIgnored() {
|
||||
KeyAuthenticationProperties props = load(KeyAuthenticationProperties.class);
|
||||
Properties p = new Properties();
|
||||
props.applyToCrshShellConfig(p);
|
||||
assertThat(p.get("crash.auth.key.path")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingSimple() {
|
||||
SimpleAuthenticationProperties props = load(SimpleAuthenticationProperties.class,
|
||||
"management.shell.auth.simple.user.name=username123",
|
||||
"management.shell.auth.simple.user.password=password123");
|
||||
Properties p = new Properties();
|
||||
props.applyToCrshShellConfig(p);
|
||||
assertThat(p.get("crash.auth.simple.username")).isEqualTo("username123");
|
||||
assertThat(p.get("crash.auth.simple.password")).isEqualTo("password123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPasswordAutoGeneratedIfUnresolvedPlaceholder() {
|
||||
SimpleAuthenticationProperties security = load(
|
||||
SimpleAuthenticationProperties.class,
|
||||
"management.shell.auth.simple.user.password=${ADMIN_PASSWORD}");
|
||||
assertThat(security.getUser().isDefaultPassword()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPasswordAutoGeneratedIfEmpty() {
|
||||
SimpleAuthenticationProperties security = load(
|
||||
SimpleAuthenticationProperties.class,
|
||||
"management.shell.auth.simple.user.password=");
|
||||
assertThat(security.getUser().isDefaultPassword()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingSpring() {
|
||||
SpringAuthenticationProperties props = load(SpringAuthenticationProperties.class,
|
||||
"management.shell.auth.spring.roles=role1,role2");
|
||||
Properties p = new Properties();
|
||||
props.applyToCrshShellConfig(p);
|
||||
assertThat(p.get("crash.auth.spring.roles")).isEqualTo("role1,role2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomShellProperties() throws Exception {
|
||||
MockEnvironment env = new MockEnvironment();
|
||||
env.setProperty("management.shell.auth.type", "simple");
|
||||
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
|
||||
ctx.setEnvironment(env);
|
||||
ctx.setServletContext(new MockServletContext());
|
||||
ctx.register(TestShellConfiguration.class);
|
||||
ctx.register(CrshAutoConfiguration.class);
|
||||
ctx.refresh();
|
||||
|
||||
PluginLifeCycle lifeCycle = ctx.getBean(PluginLifeCycle.class);
|
||||
String uuid = lifeCycle.getConfig().getProperty("test.uuid");
|
||||
assertThat(uuid).isEqualTo(TestShellConfiguration.uuid);
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
private <T> T load(Class<T> type, String... environment) {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(ctx, environment);
|
||||
ctx.register(TestConfiguration.class);
|
||||
ctx.refresh();
|
||||
this.context = ctx;
|
||||
return this.context.getBean(type);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({ ShellProperties.class,
|
||||
JaasAuthenticationProperties.class, KeyAuthenticationProperties.class,
|
||||
SimpleAuthenticationProperties.class, SpringAuthenticationProperties.class })
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class TestShellConfiguration {
|
||||
|
||||
public static String uuid = UUID.randomUUID().toString();
|
||||
|
||||
@Bean
|
||||
public CrshShellProperties testProperties() {
|
||||
return new CrshShellProperties() {
|
||||
|
||||
@Override
|
||||
protected void applyToCrshShellConfig(Properties config) {
|
||||
config.put("test.uuid", uuid);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,12 +51,6 @@ public class ReproIntegrationTests {
|
||||
assertThat(this.cli.getOutput()).contains("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shellDependencies() throws Exception {
|
||||
this.cli.run("crsh.groovy");
|
||||
assertThat(this.cli.getHttpOutput()).contains("{\"message\":\"Hello World\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dataJpaDependencies() throws Exception {
|
||||
this.cli.run("data-jpa.groovy");
|
||||
@@ -67,7 +61,7 @@ public class ReproIntegrationTests {
|
||||
public void jarFileExtensionNeeded() throws Exception {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("is not a JAR file");
|
||||
this.cli.jar("secure.groovy", "crsh.groovy");
|
||||
this.cli.jar("secure.groovy");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package org.test
|
||||
|
||||
@Grab("spring-boot-starter-remote-shell")
|
||||
|
||||
@RestController
|
||||
class SampleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public def hello() {
|
||||
[message: "Hello World"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
<commons-pool2.version>2.4.2</commons-pool2.version>
|
||||
<couchbase-client.version>2.2.8</couchbase-client.version>
|
||||
<couchbase-cache-client.version>2.0.0</couchbase-cache-client.version>
|
||||
<crashub.version>1.3.2</crashub.version>
|
||||
<derby.version>10.12.1.1</derby.version>
|
||||
<dom4j.version>1.6.1</dom4j.version>
|
||||
<dropwizard-metrics.version>3.1.2</dropwizard-metrics.version>
|
||||
@@ -442,11 +441,6 @@
|
||||
<artifactId>spring-boot-starter-jta-narayana</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-remote-shell</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
@@ -1454,47 +1448,6 @@
|
||||
<artifactId>janino</artifactId>
|
||||
<version>${janino.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.cli</artifactId>
|
||||
<version>${crashub.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.connectors.ssh</artifactId>
|
||||
<version>${crashub.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.connectors.telnet</artifactId>
|
||||
<version>${crashub.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.embed.spring</artifactId>
|
||||
<version>${crashub.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.plugins.cron</artifactId>
|
||||
<version>${crashub.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.plugins.mail</artifactId>
|
||||
<version>${crashub.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.shell</artifactId>
|
||||
<version>${crashub.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
|
||||
@@ -348,22 +348,6 @@
|
||||
<artifactId>groovy-templates</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.cli</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.shell</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
|
||||
@@ -1042,26 +1042,6 @@ content into your application; rather pick only the properties that you need.
|
||||
management.info.git.enabled=true # Enable git info.
|
||||
management.info.git.mode=simple # Mode to use to expose git information.
|
||||
|
||||
# REMOTE SHELL ({sc-spring-boot-actuator}/autoconfigure/ShellProperties.{sc-ext}[ShellProperties])
|
||||
management.shell.auth.type=simple # Authentication type. Auto-detected according to the environment.
|
||||
management.shell.auth.jaas.domain=my-domain # JAAS domain.
|
||||
management.shell.auth.key.path= # Path to the authentication key. This should point to a valid ".pem" file.
|
||||
management.shell.auth.simple.user.name=user # Login user.
|
||||
management.shell.auth.simple.user.password= # Login password.
|
||||
management.shell.auth.spring.roles=ADMIN # Comma-separated list of required roles to login to the CRaSH console.
|
||||
management.shell.command-path-patterns=classpath*:/commands/**,classpath*:/crash/commands/** # Patterns to use to look for commands.
|
||||
management.shell.command-refresh-interval=-1 # Scan for changes and update the command if necessary (in seconds).
|
||||
management.shell.config-path-patterns=classpath*:/crash/* # Patterns to use to look for configurations.
|
||||
management.shell.disabled-commands=jpa*,jdbc*,jndi* # Comma-separated list of commands to disable.
|
||||
management.shell.disabled-plugins= # Comma-separated list of plugins to disable. Certain plugins are disabled by default based on the environment.
|
||||
management.shell.ssh.auth-timeout = # Number of milliseconds after user will be prompted to login again.
|
||||
management.shell.ssh.enabled=true # Enable CRaSH SSH support.
|
||||
management.shell.ssh.idle-timeout = # Number of milliseconds after which unused connections are closed.
|
||||
management.shell.ssh.key-path= # Path to the SSH server key.
|
||||
management.shell.ssh.port=2000 # SSH port.
|
||||
management.shell.telnet.enabled=false # Enable CRaSH telnet support. Enabled by default if the TelnetPlugin is available.
|
||||
management.shell.telnet.port=5000 # Telnet port.
|
||||
|
||||
# TRACING ({sc-spring-boot-actuator}/trace/TraceProperties.{sc-ext}[TraceProperties])
|
||||
management.trace.include=request-headers,response-headers,cookies,errors # Items to be included in the trace.
|
||||
|
||||
|
||||
@@ -124,7 +124,6 @@ When you're ready to push your Spring Boot application to production, we've got
|
||||
* *Connection options:*
|
||||
<<production-ready-features.adoc#production-ready-monitoring, HTTP>> |
|
||||
<<production-ready-features.adoc#production-ready-jmx, JMX>> |
|
||||
<<production-ready-features.adoc#production-ready-remote-shell, SSH>>
|
||||
* *Monitoring:*
|
||||
<<production-ready-features.adoc#production-ready-metrics, Metrics>> |
|
||||
<<production-ready-features.adoc#production-ready-auditing, Auditing>> |
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
--
|
||||
Spring Boot includes a number of additional features to help you monitor and manage your
|
||||
application when it's pushed to production. You can choose to manage and monitor your
|
||||
application using HTTP endpoints, with JMX or even by remote shell (SSH or Telnet).
|
||||
Auditing, health and metrics gathering can be automatically applied to your application.
|
||||
application using HTTP endpoints or with JMX. Auditing, health and metrics gathering can
|
||||
be automatically applied to your application.
|
||||
|
||||
Actuator HTTP endpoints are only available with a Spring MVC-based application. In
|
||||
particular, it will not work with Jersey <<howto.adoc#howto-use-actuator-with-jersey,
|
||||
@@ -802,148 +802,6 @@ If you are using Jolokia but you don't want Spring Boot to configure it, simply
|
||||
|
||||
|
||||
|
||||
[[production-ready-remote-shell]]
|
||||
== Monitoring and management using a remote shell (deprecated)
|
||||
Spring Boot supports an integrated Java shell called '`CRaSH`'. You can use CRaSH to
|
||||
`ssh` or `telnet` into your running application. To enable remote shell support, add
|
||||
the following dependency to your project:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-remote-shell</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
TIP: If you want to also enable telnet access you will additionally need a dependency
|
||||
on `org.crsh:crsh.shell.telnet`.
|
||||
|
||||
NOTE: CRaSH requires to run with a JDK as it compiles commands on the fly. If a basic
|
||||
`help` command fails, you are probably running with a JRE.
|
||||
|
||||
|
||||
[[production-ready-connecting-to-the-remote-shell]]
|
||||
=== Connecting to the remote shell
|
||||
By default the remote shell will listen for connections on port `2000`. The default user
|
||||
is `user` and the default password will be randomly generated and displayed in the log
|
||||
output. If your application is using Spring Security, the shell will use
|
||||
<<boot-features-security, the same configuration>> by default. If not, a simple
|
||||
authentication will be applied and you should see a message like this:
|
||||
|
||||
[indent=0]
|
||||
----
|
||||
Using default password for shell access: ec03e16c-4cf4-49ee-b745-7c8255c1dd7e
|
||||
----
|
||||
|
||||
Linux and OSX users can use `ssh` to connect to the remote shell, Windows users can
|
||||
download and install http://www.putty.org/[PuTTY].
|
||||
|
||||
[indent=0,subs="attributes"]
|
||||
----
|
||||
$ ssh -p 2000 user@localhost
|
||||
|
||||
user@localhost's password:
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
:: Spring Boot :: (v{spring-boot-version}) on myhost
|
||||
----
|
||||
|
||||
Type `help` for a list of commands. Spring Boot provides `metrics`, `beans`, `autoconfig`
|
||||
and `endpoint` commands.
|
||||
|
||||
|
||||
|
||||
[[production-ready-remote-shell-credentials]]
|
||||
==== Remote shell credentials
|
||||
You can use the `management.shell.auth.simple.user.name` and
|
||||
`management.shell.auth.simple.user.password` properties to configure custom connection
|
||||
credentials. It is also possible to use a '`Spring Security`' `AuthenticationManager` to
|
||||
handle login duties. See the
|
||||
{dc-spring-boot-actuator}/autoconfigure/CrshAutoConfiguration.{dc-ext}[`CrshAutoConfiguration`]
|
||||
and {dc-spring-boot-actuator}/autoconfigure/ShellProperties.{dc-ext}[`ShellProperties`]
|
||||
Javadoc for full details.
|
||||
|
||||
|
||||
|
||||
[[production-ready-extending-the-remote-shell]]
|
||||
=== Extending the remote shell
|
||||
The remote shell can be extended in a number of interesting ways.
|
||||
|
||||
|
||||
|
||||
[[production-ready-remote-commands]]
|
||||
==== Remote shell commands
|
||||
You can write additional shell commands using Groovy or Java (see the CRaSH documentation
|
||||
for details). By default Spring Boot will search for commands in the following locations:
|
||||
|
||||
* `+classpath*:/commands/**+`
|
||||
* `+classpath*:/crash/commands/**+`
|
||||
|
||||
TIP: You can change the search path by settings a `shell.command-path-patterns` property.
|
||||
|
||||
NOTE: If you are using an executable archive, any classes that a shell command depends
|
||||
upon must be packaged in a nested jar rather than directly in the executable jar or war.
|
||||
|
||||
Here is a simple '`hello`' command that could be loaded from
|
||||
`src/main/resources/commands/hello.groovy`
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
package commands
|
||||
|
||||
import org.crsh.cli.Command
|
||||
import org.crsh.cli.Usage
|
||||
import org.crsh.command.InvocationContext
|
||||
|
||||
class hello {
|
||||
|
||||
@Usage("Say Hello")
|
||||
@Command
|
||||
def main(InvocationContext context) {
|
||||
return "Hello"
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
Spring Boot adds some additional attributes to `InvocationContext` that you can access
|
||||
from your command:
|
||||
|
||||
[cols="2,3"]
|
||||
|===
|
||||
| Attribute Name | Description
|
||||
|
||||
|`spring.boot.version`
|
||||
|The version of Spring Boot
|
||||
|
||||
|`spring.version`
|
||||
|The version of the core Spring Framework
|
||||
|
||||
|`spring.beanfactory`
|
||||
|Access to the Spring `BeanFactory`
|
||||
|
||||
|`spring.environment`
|
||||
|Access to the Spring `Environment`
|
||||
|===
|
||||
|
||||
|
||||
|
||||
[[production-ready-remote-shell-plugins]]
|
||||
==== Remote shell plugins
|
||||
In addition to new commands, it is also possible to extend other CRaSH shell features.
|
||||
All Spring Beans that extend `org.crsh.plugin.CRaSHPlugin` will be automatically
|
||||
registered with the shell.
|
||||
|
||||
For more information please refer to the http://www.crashub.org/[CRaSH reference
|
||||
documentation].
|
||||
|
||||
|
||||
|
||||
[[production-ready-metrics]]
|
||||
== Metrics
|
||||
Spring Boot Actuator includes a metrics service with '`gauge`' and '`counter`' support.
|
||||
|
||||
@@ -29,7 +29,7 @@ boolean isTechnicalStarter(def starter) {
|
||||
}
|
||||
|
||||
boolean isProductionStarter(def starter) {
|
||||
starter.name in ['spring-boot-starter-actuator', 'spring-boot-starter-remote-shell']
|
||||
starter.name in ['spring-boot-starter-actuator']
|
||||
}
|
||||
|
||||
boolean isStarter(def dependencies) {
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
#server.port=8080
|
||||
#management.port=8080
|
||||
management.address=127.0.0.1
|
||||
management.shell.ssh.enabled=true
|
||||
management.shell.ssh.port=2222
|
||||
#management.shell.telnet.enabled=false
|
||||
#management.shell.telnet.port=1111
|
||||
management.shell.auth.type=spring
|
||||
#management.shell.auth.type=key
|
||||
#management.shell.auth.key.path=${user.home}/test/id_rsa.pub.pem
|
||||
#management.shell.auth.type=simple
|
||||
|
||||
endpoints.shutdown.enabled=true
|
||||
server.tomcat.basedir=target/tomcat
|
||||
|
||||
@@ -23,10 +23,6 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-remote-shell</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
service.name=Phil
|
||||
|
||||
management.shell.ssh.enabled=true
|
||||
management.shell.ssh.port=2222
|
||||
management.shell.auth.type=simple
|
||||
management.shell.auth.simple.user.password=password
|
||||
|
||||
@@ -35,10 +35,6 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-remote-shell</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
@@ -48,20 +44,6 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.connectors.telnet</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency> -->
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
# logging.level.org.springframework.security=DEBUG
|
||||
management.address=127.0.0.1
|
||||
#management.port=8181
|
||||
management.shell.ssh.enabled=true
|
||||
management.shell.ssh.port=2222
|
||||
#management.shell.telnet.enabled=false
|
||||
#management.shell.telnet.port=1111
|
||||
management.shell.auth.type=spring
|
||||
#management.shell.auth.type=key
|
||||
#management.shell.auth.key.path=${user.home}/test/id_rsa.pub.pem
|
||||
#management.shell.auth.type=simple
|
||||
|
||||
management.info.build.mode=full
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
<module>spring-boot-starter-social-facebook</module>
|
||||
<module>spring-boot-starter-social-twitter</module>
|
||||
<module>spring-boot-starter-social-linkedin</module>
|
||||
<module>spring-boot-starter-remote-shell</module>
|
||||
<module>spring-boot-starter-test</module>
|
||||
<module>spring-boot-starter-thymeleaf</module>
|
||||
<module>spring-boot-starter-tomcat</module>
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starters</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-starter-remote-shell</artifactId>
|
||||
<name>spring-boot-starter-remote-shell (DEPRECATED)</name>
|
||||
<description>Starter for using the CRaSH remote shell to monitor and manage your
|
||||
application over SSH. Deprecated since 1.5</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.cli</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.connectors.ssh</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.connectors.telnet</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.embed.spring</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<groupId>org.springframework</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.plugins.cron</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.plugins.mail</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.crashub</groupId>
|
||||
<artifactId>crash.shell</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.basepom.maven</groupId>
|
||||
<artifactId>duplicate-finder-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>duplicate-dependencies</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<ignoredResourcePatterns>
|
||||
<ignoredResourcePattern>crash/crash.properties</ignoredResourcePattern>
|
||||
</ignoredResourcePatterns>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.
|
||||
* 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 org.springframework.boot.starter.remote.shell;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} to print a deprecation warning about
|
||||
* the starter.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@Configuration
|
||||
@Deprecated
|
||||
public class RemoteShellStarterDeprecatedWarningAutoConfiguration {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(RemoteShellStarterDeprecatedWarningAutoConfiguration.class);
|
||||
|
||||
@PostConstruct
|
||||
public void logWarning() {
|
||||
logger.warn("spring-boot-starter-remote-shell is deprecated since Spring Boot " +
|
||||
"1.5 and will be removed in Spring Boot 2.0");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.boot.starter.remote.shell.RemoteShellStarterDeprecatedWarningAutoConfiguration
|
||||
@@ -1 +0,0 @@
|
||||
provides: crash.cli,crash.shell,crash.plugins.cron,crash.embed.spring,crash.connectors.ssh
|
||||
@@ -1,29 +0,0 @@
|
||||
package commands
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint
|
||||
|
||||
class autoconfig {
|
||||
|
||||
@Usage("Display auto configuration report from ApplicationContext")
|
||||
@Command
|
||||
void main(InvocationContext context) {
|
||||
context.attributes['spring.beanfactory'].getBeansOfType(AutoConfigurationReportEndpoint.class).each { name, endpoint ->
|
||||
def report = endpoint.invoke()
|
||||
out.println "Endpoint: " + name + "\n\nPositive Matches:\n================\n"
|
||||
report.positiveMatches.each { key, list ->
|
||||
out.println key + ":"
|
||||
list.each { mandc ->
|
||||
out.println " " + mandc.condition + ": " + mandc.message
|
||||
}
|
||||
}
|
||||
out.println "\nNegative Matches\n================\n"
|
||||
report.negativeMatches.each { key, list ->
|
||||
out.println key + ":"
|
||||
list.each { mandc ->
|
||||
out.println " " + mandc.condition + ": " + mandc.message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package commands
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.BeansEndpoint
|
||||
|
||||
class beans {
|
||||
|
||||
@Usage("Display beans in ApplicationContext")
|
||||
@Command
|
||||
def main(InvocationContext context) {
|
||||
def result = [:]
|
||||
context.attributes['spring.beanfactory'].getBeansOfType(BeansEndpoint.class).each { name, endpoint ->
|
||||
result.put(name, endpoint.invoke())
|
||||
}
|
||||
result.size() == 1 ? result.values()[0] : result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package commands
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint
|
||||
import org.springframework.boot.actuate.endpoint.jmx.*
|
||||
|
||||
@Usage("Invoke actuator endpoints")
|
||||
class endpoint {
|
||||
|
||||
@Usage("List all available and enabled actuator endpoints")
|
||||
@Command
|
||||
def list(InvocationContext context) {
|
||||
|
||||
context.attributes['spring.beanfactory'].getBeansOfType(Endpoint.class).each { name, endpoint ->
|
||||
if (endpoint.isEnabled()) {
|
||||
out.println name
|
||||
}
|
||||
}
|
||||
""
|
||||
}
|
||||
|
||||
@Usage("Invoke provided actuator endpoint")
|
||||
@Command
|
||||
def invoke(InvocationContext context, @Usage("The name of the Endpoint to invoke") @Required @Argument String name) {
|
||||
|
||||
// Don't require passed argument to end with 'Endpoint'
|
||||
if (!name.endsWith("Endpoint")) {
|
||||
name = name + "Endpoint"
|
||||
}
|
||||
|
||||
context.attributes['spring.beanfactory'].getBeansOfType(Endpoint.class).each { n, endpoint ->
|
||||
if (n.equals(name) && endpoint.isEnabled()) {
|
||||
|
||||
EndpointMBean mbean = context.attributes['spring.beanfactory'].getBean(EndpointMBeanExporter.class).getEndpointMBean(name, endpoint)
|
||||
if (mbean instanceof DataEndpointMBean) {
|
||||
out.println mbean.getData()
|
||||
}
|
||||
else {
|
||||
out.println mbean.endpoint.invoke()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
""
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
welcome = { ->
|
||||
|
||||
def environment = crash.context.attributes['spring.environment']
|
||||
def propertyResolver = new org.springframework.boot.bind.RelaxedPropertyResolver(environment, "spring.main.");
|
||||
def beanFactory = crash.context.attributes['spring.beanfactory']
|
||||
|
||||
if (!propertyResolver.getProperty("show-banner", Boolean.class, Boolean.TRUE)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Try to print using the banner interface
|
||||
if (beanFactory != null) {
|
||||
try {
|
||||
def banner = beanFactory.getBean("springBootBanner")
|
||||
def out = new java.io.ByteArrayOutputStream()
|
||||
banner.printBanner(environment, null, new java.io.PrintStream(out))
|
||||
return out.toString()
|
||||
} catch (Exception ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve hostname
|
||||
def hostName;
|
||||
try {
|
||||
hostName = java.net.InetAddress.getLocalHost().getHostName();
|
||||
}
|
||||
catch (java.net.UnknownHostException ignore) {
|
||||
hostName = "localhost";
|
||||
}
|
||||
|
||||
// Get Spring Boot version from context
|
||||
def version = crash.context.attributes.get("spring.boot.version")
|
||||
|
||||
return """\
|
||||
. ____ _ __ _ _
|
||||
/\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\
|
||||
( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\
|
||||
\\\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
:: Spring Boot :: (v$version) on $hostName
|
||||
""";
|
||||
}
|
||||
|
||||
prompt = { ->
|
||||
return "> ";
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package commands
|
||||
|
||||
import org.crsh.text.ui.UIBuilder
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint
|
||||
|
||||
class metrics {
|
||||
|
||||
@Usage("Display metrics provided by Spring Boot")
|
||||
@Command
|
||||
public void main(InvocationContext context) {
|
||||
|
||||
context.takeAlternateBuffer();
|
||||
try {
|
||||
while (!Thread.interrupted()) {
|
||||
out.cls()
|
||||
out.show(new UIBuilder().table(columns:[1]) {
|
||||
header {
|
||||
table(columns:[1], separator: dashed) {
|
||||
header(bold: true, fg: black, bg: white) { label("metrics"); }
|
||||
}
|
||||
}
|
||||
row {
|
||||
table(columns:[1, 1]) {
|
||||
header(bold: true, fg: black, bg: white) {
|
||||
label("NAME")
|
||||
label("VALUE")
|
||||
}
|
||||
|
||||
context.attributes['spring.beanfactory'].getBeansOfType(MetricsEndpoint.class).each { name, metrics ->
|
||||
metrics.invoke().each { k, v ->
|
||||
row {
|
||||
label(k)
|
||||
label(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
out.flush();
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
context.releaseAlternateBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2016 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.
|
||||
@@ -101,12 +101,8 @@ class DefaultLogbackConfiguration {
|
||||
config.logger("org.apache.coyote.http11.Http11NioProtocol", Level.WARN);
|
||||
config.logger("org.apache.sshd.common.util.SecurityUtils", Level.WARN);
|
||||
config.logger("org.apache.tomcat.util.net.NioSelectorPool", Level.WARN);
|
||||
config.logger("org.crsh.plugin", Level.WARN);
|
||||
config.logger("org.crsh.ssh", Level.WARN);
|
||||
config.logger("org.eclipse.jetty.util.component.AbstractLifeCycle", Level.ERROR);
|
||||
config.logger("org.hibernate.validator.internal.util.Version", Level.WARN);
|
||||
config.logger("org.springframework.boot.actuate.autoconfigure."
|
||||
+ "CrshAutoConfiguration", Level.WARN);
|
||||
config.logger("org.springframework.boot.actuate.endpoint.jmx", null, false,
|
||||
debugRemapAppender);
|
||||
config.logger("org.thymeleaf", null, false, debugRemapAppender);
|
||||
|
||||
@@ -13,7 +13,6 @@ java.util.logging.ConsoleHandler.level = ALL
|
||||
|
||||
org.hibernate.validator.internal.util.Version.level = WARNING
|
||||
org.apache.coyote.http11.Http11NioProtocol.level = WARNING
|
||||
org.crsh.plugin.level = WARNING
|
||||
org.apache.tomcat.util.net.NioSelectorPool.level = WARNING
|
||||
org.apache.catalina.startup.DigesterFactory.level = SEVERE
|
||||
org.apache.catalina.util.LifecycleBase.level = SEVERE
|
||||
|
||||
@@ -6,7 +6,6 @@ java.util.logging.ConsoleHandler.level = ALL
|
||||
|
||||
org.hibernate.validator.internal.util.Version.level = WARNING
|
||||
org.apache.coyote.http11.Http11NioProtocol.level = WARNING
|
||||
org.crsh.plugin.level = WARNING
|
||||
org.apache.tomcat.util.net.NioSelectorPool.level = WARNING
|
||||
org.apache.catalina.startup.DigesterFactory.level = SEVERE
|
||||
org.apache.catalina.util.LifecycleBase.level = SEVERE
|
||||
|
||||
@@ -25,11 +25,8 @@
|
||||
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
|
||||
<logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
|
||||
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
|
||||
<Logger name="org.crsh.plugin" level="warn" />
|
||||
<logger name="org.crsh.ssh" level="warn"/>
|
||||
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
|
||||
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
|
||||
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
|
||||
<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
|
||||
<logger name="org.thymeleaf" level="warn"/>
|
||||
<Root level="info">
|
||||
|
||||
@@ -17,11 +17,8 @@
|
||||
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
|
||||
<logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
|
||||
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
|
||||
<Logger name="org.crsh.plugin" level="warn" />
|
||||
<logger name="org.crsh.ssh" level="warn"/>
|
||||
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
|
||||
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
|
||||
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
|
||||
<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
|
||||
<logger name="org.thymeleaf" level="warn"/>
|
||||
<Root level="info">
|
||||
|
||||
@@ -21,11 +21,8 @@ initialization performed by Boot
|
||||
<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
|
||||
<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
|
||||
<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
|
||||
<logger name="org.crsh.plugin" level="WARN"/>
|
||||
<logger name="org.crsh.ssh" level="WARN"/>
|
||||
<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
|
||||
<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
|
||||
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="WARN"/>
|
||||
<logger name="org.springframework.boot.actuate.endpoint.jmx" additivity="false">
|
||||
<appender-ref ref="DEBUG_LEVEL_REMAPPER"/>
|
||||
</logger>
|
||||
|
||||
Reference in New Issue
Block a user