From 85305a24fa0c4c3c010aba4997176998e3f8a1aa Mon Sep 17 00:00:00 2001 From: Christian Niessner <144779930+cn-at-osmit@users.noreply.github.com> Date: Tue, 18 Feb 2025 09:02:44 +0100 Subject: [PATCH 1/2] [spring-boot/shell] bump spring-boot 3.2.5 -> 3.3.8, spring-shell 2.2.5 -> 3.3.4 Signed-off-by: Christian Niessner <144779930+cn-at-osmit@users.noreply.github.com> --- README.md | 2 +- pom.xml | 10 +++++----- samples/basic/pom.xml | 2 +- samples/complete/pom.xml | 2 +- starter/pom.xml | 2 +- .../ssh/shell/ExtendedInteractiveShellRunner.java | 11 +++++------ .../github/fonimus/ssh/shell/SshShellRunnable.java | 2 +- .../ssh/shell/commands/actuator/ActuatorCommand.java | 3 ++- .../SshShellApplicationCustomAuthenticatorTest.java | 3 ++- .../ssh/shell/SshShellApplicationExclusionsTest.java | 7 +++++-- .../fonimus/ssh/shell/commands/ScriptCommandTest.java | 2 +- .../ssh/shell/commands/system/SystemCommandTest.java | 6 ++++++ .../shell/conf/SshShellSecurityConfigurationTest.java | 8 ++++---- .../shell/conf/SshShellSessionConfigurationTest.java | 11 +++++++++++ 14 files changed, 46 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index efd9034b..ad0b5202 100755 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ > Spring shell in spring boot application over ssh For more information please -visit `spring shell` [website](https://docs.spring.io/spring-shell/docs/3.0.3/docs/index.html). +visit `spring shell` [website](https://docs.spring.io/spring-shell/reference/3.3/index.html). * [Getting started](#getting-started) * [Commands](#commands) diff --git a/pom.xml b/pom.xml index 12af5efd..6f96c950 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ com.github.fonimus ssh-shell-spring-boot-parent - 3.1.1-SNAPSHOT + 3.2.0-SNAPSHOT pom @@ -55,9 +55,9 @@ 17 UTF-8 - 3.2.5 - 2.12.1 - 3.2.5 + 3.3.8 + 2.13.2 + 3.3.4 5.10.2 fonimus_ssh-shell-spring-boot @@ -192,7 +192,7 @@ maven-surefire-plugin - 3.2.5 + 3.5.0 diff --git a/samples/basic/pom.xml b/samples/basic/pom.xml index ba536f82..10cafb8c 100755 --- a/samples/basic/pom.xml +++ b/samples/basic/pom.xml @@ -19,7 +19,7 @@ ssh-shell-spring-boot-parent com.github.fonimus - 3.1.1-SNAPSHOT + 3.2.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/samples/complete/pom.xml b/samples/complete/pom.xml index bd8c57f2..125e6acc 100755 --- a/samples/complete/pom.xml +++ b/samples/complete/pom.xml @@ -19,7 +19,7 @@ ssh-shell-spring-boot-parent com.github.fonimus - 3.1.1-SNAPSHOT + 3.2.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/starter/pom.xml b/starter/pom.xml index aed7b55c..8f8d557e 100644 --- a/starter/pom.xml +++ b/starter/pom.xml @@ -19,7 +19,7 @@ ssh-shell-spring-boot-parent com.github.fonimus - 3.1.1-SNAPSHOT + 3.2.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/starter/src/main/java/com/github/fonimus/ssh/shell/ExtendedInteractiveShellRunner.java b/starter/src/main/java/com/github/fonimus/ssh/shell/ExtendedInteractiveShellRunner.java index da54ccc3..06658d84 100644 --- a/starter/src/main/java/com/github/fonimus/ssh/shell/ExtendedInteractiveShellRunner.java +++ b/starter/src/main/java/com/github/fonimus/ssh/shell/ExtendedInteractiveShellRunner.java @@ -36,15 +36,14 @@ public ExtendedInteractiveShellRunner(LineReader lineReader, PromptProvider prom } @Override - public void run(ApplicationArguments args) throws Exception { + public boolean run(String[] args) throws Exception { + if (args == null || args.length == 0) { + return false; + } shellContext.setInteractionMode(InteractionMode.INTERACTIVE); InputProvider inputProvider = new SshShellInputProvider(lineReader, promptProvider); shell.run(inputProvider); - } - - @Override - public boolean canRun(ApplicationArguments args) { - return false; + return true; } public static class SshShellInputProvider diff --git a/starter/src/main/java/com/github/fonimus/ssh/shell/SshShellRunnable.java b/starter/src/main/java/com/github/fonimus/ssh/shell/SshShellRunnable.java index aa150f77..8e242a86 100644 --- a/starter/src/main/java/com/github/fonimus/ssh/shell/SshShellRunnable.java +++ b/starter/src/main/java/com/github/fonimus/ssh/shell/SshShellRunnable.java @@ -157,7 +157,7 @@ public void run() { SSH_THREAD_CONTEXT.set(new SshContext(this, terminal, reader, authentication)); shellListenerService.onSessionStarted(session); - new InteractiveShellRunner(reader, promptProvider, shell, new DefaultShellContext()).run(null); + new InteractiveShellRunner(reader, promptProvider, shell, new DefaultShellContext()).run((String[]) null); shellListenerService.onSessionStopped(session); LOGGER.debug("{}: closing", session); quit(0); diff --git a/starter/src/main/java/com/github/fonimus/ssh/shell/commands/actuator/ActuatorCommand.java b/starter/src/main/java/com/github/fonimus/ssh/shell/commands/actuator/ActuatorCommand.java index 89e2a272..68f461bf 100644 --- a/starter/src/main/java/com/github/fonimus/ssh/shell/commands/actuator/ActuatorCommand.java +++ b/starter/src/main/java/com/github/fonimus/ssh/shell/commands/actuator/ActuatorCommand.java @@ -36,6 +36,7 @@ import org.springframework.boot.actuate.management.ThreadDumpEndpoint; import org.springframework.boot.actuate.metrics.MetricsEndpoint; import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint; +import org.springframework.boot.actuate.session.SessionsDescriptor; import org.springframework.boot.actuate.session.SessionsEndpoint; import org.springframework.boot.actuate.web.exchanges.HttpExchangesEndpoint; import org.springframework.boot.actuate.web.mappings.MappingsEndpoint; @@ -407,7 +408,7 @@ public Availability mappingsAvailability() { */ @ShellMethod(key = "sessions", value = "Display sessions endpoint.") @ShellMethodAvailability("sessionsAvailability") - public SessionsEndpoint.SessionsDescriptor sessions() { + public SessionsDescriptor sessions() { return applicationContext.getBean(SessionsEndpoint.class).sessionsForUsername(null); } diff --git a/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationCustomAuthenticatorTest.java b/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationCustomAuthenticatorTest.java index ed07acc6..102826d4 100644 --- a/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationCustomAuthenticatorTest.java +++ b/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationCustomAuthenticatorTest.java @@ -17,6 +17,7 @@ package com.github.fonimus.ssh.shell; import com.github.fonimus.ssh.shell.conf.SshShellPasswordConfigurationTest; +import com.github.fonimus.ssh.shell.conf.SshShellSessionConfigurationTest; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; @@ -27,7 +28,7 @@ import static com.github.fonimus.ssh.shell.SshHelperTest.*; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - classes = {SshShellApplicationCustomAuthenticatorTest.class, SshShellPasswordConfigurationTest.class}, + classes = {SshShellApplicationCustomAuthenticatorTest.class, SshShellPasswordConfigurationTest.class, SshShellSessionConfigurationTest.class}, properties = { "ssh.shell.port=2349", "management.endpoints.web.exposure.include=*", diff --git a/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationExclusionsTest.java b/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationExclusionsTest.java index 6fca6782..b230ebff 100644 --- a/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationExclusionsTest.java +++ b/starter/src/test/java/com/github/fonimus/ssh/shell/SshShellApplicationExclusionsTest.java @@ -16,6 +16,8 @@ package com.github.fonimus.ssh.shell; +import com.github.fonimus.ssh.shell.conf.SshShellPasswordConfigurationTest; +import com.github.fonimus.ssh.shell.conf.SshShellSessionConfigurationTest; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; @@ -24,8 +26,9 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = - SshShellApplicationExclusionsTest.class, properties = { +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + classes = {SshShellApplicationExclusionsTest.class, SshShellSessionConfigurationTest.class}, + properties = { "ssh.shell.port=2344", "ssh.shell.commands.actuator.excludes[0]=info", "ssh.shell.commands.actuator.excludes[1]=beans", diff --git a/starter/src/test/java/com/github/fonimus/ssh/shell/commands/ScriptCommandTest.java b/starter/src/test/java/com/github/fonimus/ssh/shell/commands/ScriptCommandTest.java index 3f843603..23fe5da7 100644 --- a/starter/src/test/java/com/github/fonimus/ssh/shell/commands/ScriptCommandTest.java +++ b/starter/src/test/java/com/github/fonimus/ssh/shell/commands/ScriptCommandTest.java @@ -49,7 +49,7 @@ public class ScriptCommandTest { @BeforeEach @SneakyThrows - void setUp() { + void setUp() throws Exception { shell = mock(ExtendedShell.class); Parser parser = mock(Parser.class); sshHelper = mock(SshShellHelper.class); diff --git a/starter/src/test/java/com/github/fonimus/ssh/shell/commands/system/SystemCommandTest.java b/starter/src/test/java/com/github/fonimus/ssh/shell/commands/system/SystemCommandTest.java index f56c7dc1..ab27f225 100644 --- a/starter/src/test/java/com/github/fonimus/ssh/shell/commands/system/SystemCommandTest.java +++ b/starter/src/test/java/com/github/fonimus/ssh/shell/commands/system/SystemCommandTest.java @@ -22,6 +22,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.io.PrintWriter; + import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.when; @@ -51,6 +53,10 @@ void threads() throws Exception { for (SystemCommand.ThreadColumn tc : SystemCommand.ThreadColumn.values()) { assertNotNull(command.threads(SystemCommand.ThreadAction.list, tc, true, true, null)); } + // Hint: We have to override the PrintWriterAccess otherwise Thread.printStackTrace() will fail with: + // java.lang.NullPointerException: Cannot enter synchronized block because "lock" is null + writer = new PrintWriter(PrintWriter.nullWriter()); //Hint: mock(PrintWriter.class); fails in Throwable.printStackTrace() + when(ter.writer()).thenReturn(writer); assertNotNull(command.threads(SystemCommand.ThreadAction.dump, SystemCommand.ThreadColumn.name, true, true, Thread.currentThread().getId())); assertThrows(IllegalArgumentException.class, diff --git a/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSecurityConfigurationTest.java b/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSecurityConfigurationTest.java index 0230ca1f..dbe094da 100644 --- a/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSecurityConfigurationTest.java +++ b/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSecurityConfigurationTest.java @@ -37,10 +37,10 @@ public class SshShellSecurityConfigurationTest { @Bean public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authManager) throws Exception { - http.authorizeHttpRequests() - .requestMatchers(EndpointRequest.to("info")).permitAll() - .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR") - .and().authenticationManager(authManager); + http.authorizeHttpRequests((authorizeHttpRequests) -> { + authorizeHttpRequests.requestMatchers(EndpointRequest.to("info")).permitAll(); + authorizeHttpRequests.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR"); + }).authenticationManager(authManager); return http.build(); } diff --git a/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSessionConfigurationTest.java b/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSessionConfigurationTest.java index cfdaea84..988f1088 100644 --- a/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSessionConfigurationTest.java +++ b/starter/src/test/java/com/github/fonimus/ssh/shell/conf/SshShellSessionConfigurationTest.java @@ -16,11 +16,16 @@ package com.github.fonimus.ssh.shell.conf; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.actuate.session.SessionsEndpoint; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import org.springframework.session.FindByIndexNameSessionRepository; +import org.springframework.session.SessionRepository; import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession; import org.springframework.transaction.PlatformTransactionManager; @@ -40,4 +45,10 @@ public EmbeddedDatabase dataSource() { public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } + + @Bean + @ConditionalOnMissingBean + SessionsEndpoint sessionEndpoint(SessionRepository sessionRepository, ObjectProvider> indexedSessionRepository) { + return new SessionsEndpoint(sessionRepository, (FindByIndexNameSessionRepository) indexedSessionRepository.getIfAvailable()); + } } From d102afc7a9adebda07a465d164f56f8654eac6c1 Mon Sep 17 00:00:00 2001 From: Christian Niessner <144779930+cn-at-osmit@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:58:40 +0100 Subject: [PATCH 2/2] [spring-boot/shell] bump spring-boot 3.3.8 -> 3.4.2, spring-shell 3.3.4 -> 3.4.0 Signed-off-by: Christian Niessner <144779930+cn-at-osmit@users.noreply.github.com> --- pom.xml | 6 +++--- samples/basic/pom.xml | 2 +- samples/complete/pom.xml | 2 +- starter/pom.xml | 2 +- .../com/github/fonimus/ssh/shell/commands/TasksCommand.java | 5 ++++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 6f96c950..00ced546 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ com.github.fonimus ssh-shell-spring-boot-parent - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT pom @@ -55,9 +55,9 @@ 17 UTF-8 - 3.3.8 + 3.4.2 2.13.2 - 3.3.4 + 3.4.0 5.10.2 fonimus_ssh-shell-spring-boot diff --git a/samples/basic/pom.xml b/samples/basic/pom.xml index 10cafb8c..5ef5a364 100755 --- a/samples/basic/pom.xml +++ b/samples/basic/pom.xml @@ -19,7 +19,7 @@ ssh-shell-spring-boot-parent com.github.fonimus - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/samples/complete/pom.xml b/samples/complete/pom.xml index 125e6acc..84daae2c 100755 --- a/samples/complete/pom.xml +++ b/samples/complete/pom.xml @@ -19,7 +19,7 @@ ssh-shell-spring-boot-parent com.github.fonimus - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/starter/pom.xml b/starter/pom.xml index 8f8d557e..46cffd70 100644 --- a/starter/pom.xml +++ b/starter/pom.xml @@ -19,7 +19,7 @@ ssh-shell-spring-boot-parent com.github.fonimus - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/starter/src/main/java/com/github/fonimus/ssh/shell/commands/TasksCommand.java b/starter/src/main/java/com/github/fonimus/ssh/shell/commands/TasksCommand.java index 9da7b86f..caadc825 100644 --- a/starter/src/main/java/com/github/fonimus/ssh/shell/commands/TasksCommand.java +++ b/starter/src/main/java/com/github/fonimus/ssh/shell/commands/TasksCommand.java @@ -28,6 +28,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.ApplicationContext; import org.springframework.core.task.TaskRejectedException; +import org.springframework.scheduling.SchedulingAwareRunnable; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; import org.springframework.scheduling.config.*; @@ -354,7 +355,9 @@ private static String getTrigger(IntervalTask task) { } private static String getTaskName(Runnable runnable) { - if (runnable instanceof ScheduledMethodRunnable) { + if (runnable instanceof SchedulingAwareRunnable sar) { + return sar.toString(); + } else if (runnable instanceof ScheduledMethodRunnable) { Method method = ((ScheduledMethodRunnable) runnable).getMethod(); return method.getDeclaringClass().getName() + "." + method.getName(); } else {