Spring shell in spring boot application over ssh
For more information please visit spring shell
website
or 2.0.1 reference documentation.
- Getting started
- Commands
- Post processors
- Parameter providers
- Custom authentication
- Command helper
- Banner
- Listeners
- Session Manager
- Tests
- Samples
- Release notes
<dependency>
<groupId>com.github.fonimus</groupId>
<artifactId>ssh-shell-spring-boot-starter</artifactId>
</dependency>
Note: auto configuration
SshShellAutoConfiguration
(active by default) can be deactivated by property ssh.shell.enable=false.
It means that the ssh server won't start and the commands won't be scanned. Unfortunately the application will still
load the spring-shell
auto configuration classes and display a shell at startup (shell:>). You can disable them with
following property:
spring:
autoconfigure:
exclude:
- org.springframework.shell.jline.JLineShellAutoConfiguration
- org.springframework.shell.SpringShellAutoConfiguration
- org.springframework.shell.jcommander.JCommanderParameterResolverAutoConfiguration
- org.springframework.shell.legacy.LegacyAdapterAutoConfiguration
- org.springframework.shell.standard.StandardAPIAutoConfiguration
- org.springframework.shell.standard.commands.StandardCommandsAutoConfiguration
Please check class: SshShellProperties.java for more information
ssh:
shell:
enable: true
# 'simple' or 'security'
authentication: simple
# if authentication set to 'security' the AuthenticationProvider bean name
# if not specified and only one AuthenticationProvider bean is present in the context, it will be used
auth-provider-bean-name:
# since 1.2.2, optional file containing authorized public keys (standard authorized_keys format, one key per line
# starting with 'ssh-rsa'), takes precedence over authentication (simple or not)
authorized-public-keys-file:
# since 1.5.5, optional spring resource containing authorized public keys (file:, classpath: , etc)
# note: in case of a non file resource, a temporary file is created with given content and deleted on process exit
# this is due to ssh external library which only accepts file in api
authorized-public-keys:
# for ssh helper 'confirm' method
confirmation-words:
- y
- yes
# since 1.4.0, set enable to false to disable following default commands
commands:
actuator:
create: true
enable: true
restricted: true
# empty by default
excludes:
- ...
authorized-roles:
- ACTUATOR
# since 1.4.0
jmx:
create: true
enable: true
restricted: true
authorized-roles:
- ADMIN
system:
create: true
enable: true
restricted: true
authorized-roles:
- ADMIN
# since 1.4.0
datasource:
create: true
enable: true
restricted: true
authorized-roles:
- ADMIN
excludes:
- datasource-update
postprocessors:
create: true
enable: true
restricted: false
# history and script added in 1.8.0
history:
create: true
enable: true
restricted: false
script:
create: true
enable: true
restricted: false
# since 1.3.0, command which allows you to list ssh sessions, and stop them
manage-sessions:
create: true
enable: false
restricted: true
authorized-roles:
- ADMIN
# since 1.5.0
tasks:
create: true
enable: false
restricted: true
authorized-roles:
- ADMIN
display-banner: true
# to use ExtendedFileValueProviderTest instead of spring shell FileValueProvider for all File option parameters
# if set to false, it still can be used via '@ShellOption(valueProvider = ExtendedFileValueProviderTest.class) File file'
extended-file-provider: true
history-file: <java.io.tmpdir>/sshShellHistory.log
# since 1.3.0, set to false to have one file per user (<history-directory>/sshShellHistory-<user>.log)
shared-history: true
# since 1.3.0, only if shared-history is set to false
history-directory: <java.io.tmpdir>
host: 127.0.0.1
host-key-file: <java.io.tmpdir>/hostKey.ser
# displayed in log if generated
password:
port: 2222
user: user
prompt:
# in enum: com.github.fonimus.ssh.shell.PromptColor (black, red, green, yellow, blue, magenta, cyan, white, bright)
color: white
text: 'shell>'
local:
# since 1.2.1, to let default local spring shell prompt when application starts
enable: false
-
Add
spring-boot-starter-actuator
dependency to get actuator commands -
Add
spring-boot-starter-security
dependency to configuressh.shell.authentication=security
with AuthenticationProvider
Some commands are disabled by default, it can be the whole group (like manage-sessions
), or just
one sub command (like datasource-update
in group datasource
).
To enable a group, set the enable property to true :
ssh:
shell:
commands:
manage-sessions:
enable: true
datasource:
excludes:
To un-exclude a sub command inside a group, set the excludes property to the new wanted array. To include all sub commands, set new empty array :
ssh:
shell:
commands:
datasource:
excludes:
You can write your command exactly the way you would do with spring shell
(For more information please visit spring shell
(website, reference documentation)
Instead of using org.springframework.shell.standard.ShellComponent
annotation, you should use com.github.fonimus.ssh.shell.commands.SshShellComponent
:
it is just a conditional @ShellComponent
with @ConditionalOnProperty
on property ssh.shell.enable
Example:
import org.springframework.shell.standard.ShellCommandGroup;
import org.springframework.shell.standard.ShellMethod;
import com.github.fonimus.ssh.shell.commands.SshShellComponent;
@SshShellComponent
@ShellCommandGroup("Test Commands")
public class TestCommands {
@ShellMethod("test command")
public String test() {
return "ok";
}
}
All commands group can be deactivated by enable property :
ssh:
shell:
commands:
<command>:
enable: true
Sub commands in group can be also filtered by includes and excludes properties :
ssh:
shell:
commands:
<command>:
includes:
- xxx
excludes:
- xxx
If org.springframework.boot:spring-boot-starter-actuator
dependency is present, actuator commands
will be available.
Command availability is also bind to endpoint activation.
management:
endpoint:
audit:
enabled: false
Activated by default if you have @EnableScheduling
,
these commands allow you to interact with spring boot scheduled tasks :
tasks-list
: List scheduled taskstasks-stop
: Stop one or all scheduled tasks or executiontasks-restart
: Restart one or all scheduled taskstasks-single
: Launch one execution of all or specified task(s)
Note: refresh parameter in tasks-list
will remove single executions.
Based on spring documentation org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.setScheduler
the task scheduler used for scheduled tasks will be :
If not specified, it will look for unique bean of type TaskScheduler
, or with name
taskScheduler
. Otherwise a local single-threaded will be created.
The TasksCommand
keep the same mechanism in order to be able to restart stopped scheduled tasks.
It also provides a setTaskScheduler()
in case you want to specify custom one.
Context | Task scheduler used in TaskCommand |
---|---|
No TaskScheduler bean in context |
Local single-threaded |
One TaskScheduler bean named ts in context |
ts bean |
Multiple TaskScheduler beans named ts1, ts2 in context |
Local single-threaded (could not find name taskScheduler) |
Multiple TaskScheduler beans named taskScheduler, ts2, ts3 in context |
taskScheduler bean |
Task scheduler specified in method SchedulingConfigurer#configureTasks |
Local single-threaded (not set in task) |
Task scheduler specified in method SchedulingConfigurer#configureTasks AND com.github.fonimus.ssh.shell.commands.TasksCommand.setTaskScheduler |
Scheduler manually set |
jmx-info
: Displays information about jmx mbean. Use -a option to query attribute values.jmx-invoke
: Invoke operation on object name.jmx-list
: List jmx mbeans.
system-env
: List system environment.system-properties
: List system properties.system-threads
: List jvm threads.
datasource-list
: List available datasourcesdatasource-properties
: Datasource properties command. Executes 'show variables'datasource-query
: Datasource query command.datasource-update
: Datasource update command.
postprocessors
: Display the available post processors
Note: since 1.0.6
Post processors can be used with '|' (pipe character) followed by the name of the post processor and the parameters. Also, custom ones can be added.
This specific post processor takes the key character '>'.
Example: echo test > /path/to/file.txt
This post processor, named pretty
takes an object and apply jackson pretty writer.
Example: info | pretty
This post processor, named json
allows you to find a specific path within a json object.
Caution: you need to have a json string. You can apply pretty
post processor before to do so.
Example: info | pretty | json /build/version
This post processor, named grep
allows you to find specific patterns within a string.
Examples: info | grep boot
,info | pretty | grep boot spring
This post processor, named highlight
allows you to highlight specific patterns within a string.
Examples: info | highlight boot
,info | pretty | highlight boot spring
To register a new json result post processor, you need to implement interface PostProcessor
Then register it within a spring configuration.
Example:
@Bean
public PostProcessor quotePostProcessor() {
return new PostProcessor<String>() {
@Override
public String getName() {
return "quote";
}
@Override
public String process(String result, List parameters) {
return "'" + result + "'";
}
};
}
Enumeration option parameters have auto completion by default.
Thanks to [ExtendedFileValueProvider.java](./starter/src/main/java/com/github/fonimus/ssh/shell/providers
/ExtendedFileValueProvider.java)
(or FileValueProvider is deactivated), auto completion is available
for java.io.File
option parameters.
To enable auto completion for a parameter, declare a valueProvider class.
Note: the value provider has to be in the spring context.
...
@ShellOption(valueProvider = CustomValuesProvider.class) String message
...
@Component
class CustomValuesProvider
extends ValueProviderSupport {
private final static String[] VALUES = new String[]{
"message1", "message2", "message3"
};
@Override
public List<CompletionProposal> complete(MethodParameter parameter, CompletionContext completionContext, String[] hints) {
return Arrays.stream(VALUES).map(CompletionProposal::new).collect(Collectors.toList());
}
}
Instead of setting user and password (or using generated one), you can implement your own SshShellAuthenticationProvider
.
Auto configuration will create default implementation only if there is not an existing one in the spring context.
Example:
import com.github.fonimus.ssh.shell.SshShellAuthenticationProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CustomPasswordConfiguration {
@Bean
public SshShellAuthenticationProvider sshShellAuthenticationProvider() {
return (user, pass, serverSession) -> user.equals(pass);
}
}
A com.github.fonimus.ssh.shell.SshShellHelper
bean is provided in context to help for additional functionalities.
You can either autowire it or inject it in a constructor:
import com.github.fonimus.ssh.shell.SshShellHelper;
@SshShellComponent
public class DemoCommand {
@Autowired
private SshShellHelper helper;
// or
public DemoCommand(SshShellHelper helper){
this.helper = helper;
}
}
@SshShellComponent
public class DemoCommand {
@Autowired
private SshShellHelper helper;
@ShellMethod("Print command")
public String print() {
boolean success = ...;
helper.print("Some message");
helper.print("Some black message", PromptColor.BLACK);
helper.printSuccess("Some success message");
return success ? helper.getSuccess("Some returned success message") : helper.getColored("Some returned blue message", PromptColor.BLUE);
}
}
@SshShellComponent
public class DemoCommand {
@Autowired
private SshShellHelper helper;
@ShellMethod("Welcome command")
public String welcome() {
String name = helper.read("What's your name ?");
return "Hello, '" + name + "' !";
}
}
Util confirm
method displays confirmation message and returns true
if response equals ignore case confirmation words.
Default confirmation words are [y
, yes
]:
You can specify if it is case sensitive and provide your own confirmation words.
@SshShellComponent
public class DemoCommand {
@Autowired
private SshShellHelper helper;
@ShellMethod("Confirmation command")
public String conf() {
return helper.confirm("Are you sure ?" [, true|false] [, "oui", "si", ...]) ? "Great ! Let's do it !" : "Such a shame ...";
}
}
A builder com.github.fonimus.ssh.shell.SimpleTableBuilder
is available to quickly set up print table.
Quick example:
helper.renderTable(SimpleTable.builder()
.column("col1")
.column("col2")
.column("col3")
.column("col4")
.line(Arrays.asList("line1 col1", "line1 col2", "line1 col3", "line1 col4"))
.line(Arrays.asList("line2 col1", "line2 col2", "line2 col3", "line2 col4"))
.line(Arrays.asList("line3 col1", "line3 col2", "line3 col3", "line3 col4"))
.line(Arrays.asList("line4 col1", "line4 col2", "line4 col3", "line4 col4"))
.line(Arrays.asList("line5 col1", "line5 col2", "line5 col3", "line5 col4"))
.line(Arrays.asList("line6 col1", "line6 col2", "line6 col3", "line6 col4"))
.build());
Result :
┌──────────┬──────────┬──────────┬──────────┐
│ col1 │ col2 │ col3 │ col4 │
├──────────┼──────────┼──────────┼──────────┤
│line1 col1│line1 col2│line1 col3│line1 col4│
├──────────┼──────────┼──────────┼──────────┤
│line2 col1│line2 col2│line2 col3│line2 col4│
├──────────┼──────────┼──────────┼──────────┤
│line3 col1│line3 col2│line3 col3│line3 col4│
├──────────┼──────────┼──────────┼──────────┤
│line4 col1│line4 col2│line4 col3│line4 col4│
├──────────┼──────────┼──────────┼──────────┤
│line5 col1│line5 col2│line5 col3│line5 col4│
├──────────┼──────────┼──────────┼──────────┤
│line6 col1│line6 col2│line6 col3│line6 col4│
└──────────┴──────────┴──────────┴──────────┘
Note: since 1.1.3
This method takes an interface to display lines at regular interval.
Every refresh delay (here 2 seconds), com.github.fonimus.ssh.shell.interactive.InteractiveInput.getLines
is called.
This can be used to display progress, monitoring, etc.
The interactive builder, Interactive.java allows you to build your interactive command.
This builder can also take key bindings to make specific actions, whose can be made by the following builder: KeyBinding.java.
@SshShellComponent
public class DemoCommand {
@Autowired
private SshShellHelper helper;
@ShellMethod("Interactive command")
public void interactive() {
KeyBinding binding = KeyBinding.builder()
.description("K binding example")
.key("k").input(() -> LOGGER.info("In specific action triggered by key 'k' !")).build();
Interactive interactive = Interactive.builder().input((size, currentDelay) -> {
LOGGER.info("In interactive command for input...");
List<AttributedString> lines = new ArrayList<>();
AttributedStringBuilder sb = new AttributedStringBuilder(size.getColumns());
sb.append("\nCurrent time", AttributedStyle.BOLD).append(" : ");
sb.append(String.format("%8tT", new Date()));
lines.add(sb.toAttributedString());
SecureRandom sr = new SecureRandom();
lines.add(new AttributedStringBuilder().append(helper.progress(sr.nextInt(100)),
AttributedStyle.DEFAULT.foreground(sr.nextInt(6) + 1)).toAttributedString());
lines.add(AttributedString.fromAnsi(SshShellHelper.INTERACTIVE_LONG_MESSAGE + "\n"));
return lines;
}).binding(binding).fullScreen(true|false).refreshDelay(5000).build();
helper.interactive(interactive);
}
}
Note: existing key bindings are:
q
: to quit interactive command and go back to shell+
: to increase refresh delay by 1000 milliseconds-
: to decrease refresh delay by 1000 milliseconds
If you are using AuthenticationProvider thanks to property ssh.shell.authentication=security
, you can check that connected user has right authorities for command.
The easiest way of doing it is thanks to ShellMethodAvailability
functionality. Example:
@SshShellComponent
public class DemoCommand {
@Autowired
private SshShellHelper helper;
@ShellMethod("Admin command")
@ShellMethodAvailability("adminAvailability")
public String admin() {
return "Finally an administrator !!";
}
public Availability adminAvailability() {
if (!helper.checkAuthorities(Collections.singletonList("ADMIN"))) {
return Availability.unavailable("admin command is only for an admin users !");
}
return Availability.available();
}
}
@SshShellComponent
public class DemoCommand {
@Autowired
private SshShellHelper helper;
@ShellMethod("Authentication command")
public SshAuthentication authentication() {
return helper.getAuthentication();
}
}
If a banner is found in spring context and display-banner
is set to true,
it will be used as welcome prompt message.
An interface is provided in order to receive events on ssh sessions : com.github.fonimus.ssh.shell.listeners .SshShellListener
.
Implement it and define a spring bean in order to receive events.
Example
@Bean
public SshShellListener sshShellListener() {
return event -> LOGGER.info("[listener] event '{}' [id={}, ip={}]",
event.getType(),
event.getSession().getServerSession().getIoSession().getId(),
event.getSession().getServerSession().getIoSession().getRemoteAddress());
}
Note: since 1.3.0`
A session manager bean is available and allows you to:
- list active sessions
- get information about one session
- stop a session
Note: you need to use @Lazy injection if you are using it in a command
Example
...
public MyCommand(@Lazy SshShellSessionManager sessionManager) {
this.sessionManager = sessionManager;
}
@ShellMethod("My command")
public String myCommand() {
sessionManager.listSessions();
...
}
...
If activated ssh.shell.commands.manage-sessions.enable=true
, the following commands are available :
manage-sessions-info
: Displays information about single sessionmanage-sessions-list
: Displays active sessionsmanage-sessions-stop
: Stop single specific session
It can be annoying to load ssh server during spring boot tests.
SshShellProperties
class provides constants to easily deactivate
the all ssh and spring shell auto configurations:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = { "ssh.shell.port=2346",
SshShellProperties.DISABLE_SSH_SHELL,
SshShellProperties.DISABLE_SPRING_SHELL_AUTO_CONFIG
})
@ExtendWith(SpringExtension.class)
public class ApplicationTest {}
-
Basic sample, no actuator, no security, no sessions
-
Complete sample, actuator, security dependencies and configurations
- Add built in commands
script
,history
andstacktrace
in the list of properties in order to configure them.
Note : If you choose to not create those commands, overridden commands will not be created but the spring-shell
autoconfiguration will still create its own built in commands that you can deactivate thanks to properties
spring.shell.command.<command-name>.enabled=false
(check org.springframework.shell.standard.commands.StandardCommandsAutoConfiguration for more information)
- Make post processors generic and be able to chain them #163
- Bump sshd-core from 2.7.0 to 2.8.0 #170
- Bump spring-boot.version from 2.5.5 to 2.5.6 #164
- Fix a NPE on
task-single
command.
- Added the command tasks-single to launch a single execution of a scheduled task
- Bump to spring boot 2.5.3
- Bump to spring boot 2.4.5
- Remove warn log at spring context stop
- Add
Next execution
column intask-list
table
- Fix potential circular dependency for
Windows
users - Fix classpath resource inside jar for authorized public keys file by using temporary file (ssh external library only accept files)
authorizedPublicKeysFile
becomesauthorizedPublicKeys
and is now a spring resource ; you can now use :ssh.shell.authorized-public-keys=<spring-resource-path>
(file:<path>
,classpath:<path>
, etc)ssh.shell.authorized-public-keys-file=<file-path>
- Rewrite script command to be usable in background with result file (options added to default command)
- Add
StoppableInteractiveInput
to be able to stop the interactive mode with specific condition
- Add option to create group commands
ssh.shell.commands.<command>.create
, which is true by default. Setting a group command create property to false :- won't create the associated commands in spring context
- won't display the associated commands in help
- the associated commands won't be accessible in shell
- Add option for path (groups, components, etc) in health endpoint
- Add tasks commands :
tasks-list
tasks-stop
tasks-restart
- Rename commands :
system-env
instead of jvm-envsystem-properties
instead of jvm-propertiessystem-threads
instead of threads
- Rework commands properties (check configuration chapter) to add the following :
includes
: to only include list of sub commands inside group (example:datasource-update
in group datasource)excludes
: to excludes some sub commands inside group (example:datasource-update
in group datasource)
- AnyOsFileValueProvider replaced by ExtendedFileValueProvider.java
- Do not add space after directory proposal (allows following directories directly)
- Supports Windows OS in addition to Unix
- Can be deactivated by
ssh.shell.extended-file-provider
- Bump to spring boot 2.3.3.RELEASE
- Bump to sshd 2.5.1
- Add method
SshShellHelper#getSshEnvironment()
to retrieve information about ssh environment - Fixed start app failure in case of
spring.main.lazy-initialization=true
- Fixed table rendering issue in
SshShellHelper
- Add jmx commands :
jmx-list
jmx-info
jmx-invoke
- Add datasource commands
datasource-list
datasource-properties
datasource-query
datasource-update
- Add completion for post processors
- Rework commands properties (check configuration chapter)
default-commands
becomescommands
- Instead of just activation boolean, each command now has the following properties :
enable
with default value set to true, except said otherwise in configrestricted
with default value set to true, except said otherwise in configauthorizedRoles
with default value initialized with ADMIN, except said otherwise in config
ssh.shell.actuator.*
properties moved tossh.shell.commands.actuator.*
- Bump to spring boot 2.3.0.RELEASE
- Add listeners mechanism
- Add session manager
- Add possibility to activate
manage-sessions-*
commands`
- Add possibility to activate
- Add possibility to have history per user (
ssh.shell.shared-history=false
)
- Bump to sshd 2.4.0
- Add property
ssh.shell.authorized-public-keys-file
to specify authorized public keys to login via ssh. This file is a standardauthorized_keys
format (one key per line, starting with ssh-rsa) - Add some methods in helper to help build table with
com.github.fonimus.ssh.shell.SimpleTableBuilder
- Add property
ssh.shell.prompt.local.enable
(false by default) to let default local spring shell prompt when application starts
- Bump to spring boot 2.2.0.RELEASE
- Audit and Http Trace actuator commands will be disabled by default, because endpoint will be by spring boot by default (check spring boot migration 2.2 for more info)
- Fix hanging terminal when unexpected runtime exception occurs
- Bump to spring boot 2.1.7.RELEASE
- Bump to sshd 2.3.0
- Add properties to exclude not wanted built-in commands
- Via properties
ssh.shell.default-commands.*
- Via properties
- Add
threads
,jvm-env
andjvm-properties
built-it commands
- AnyOsFileValueProvider.java
replaces
FileValueProvider
(spring shell default) by default- Supports Windows OS in addition to Unix
- Can be deactivated by
ssh.shell.any-os-file-provider
- Remove
static
from SshShellHelper methods (getColored, getBackgroundColored) - Add methods in SshShellHelper
terminalSize
to get terminal columns and rows capabilitiesprogress
to fill line with progress bar[========> ]
interactive
which takes an interface to display lines at regular interval- Check complete sample for a demo
- Fix option arguments with spaces, quotes, etc
- Update to
spring boot 2.1.3
- Update to
javadoc plugin 3.1.0
- Update to
sshd 2.2.0
- Update to
spring boot 2.1.0
- Avoid overriding bean definitions as it is now disabled by default
- New artifact identifier: ssh-shell-spring-boot-starter -> maven central link
- Add new post processor
highlight
- Fix various issues where ssh.shell.enable=false makes application fail to start
- Add new
@SshShellComponent
- Add post processor feature
pretty
grep
json
save
- Fix issue with terminal size which made autocomplete fail
- Make PrettyJsonResultHandler bean conditional on jackson ObjectMapper class
- Fix application start issue if banner is with configured with off mode
- Fix not working history
- Make history file location configurable
- Add authentication objects in ssh session context
- Add more user interactions in SshShellHelper
- Add spring security authentication provider for ssh connection
- Add spring security roles check
- Add user interactions (read, confirm)
- Bug fixes
- First stable release