diff --git a/src/main/java/com/example/sshd/Boot.java b/src/main/java/com/example/sshd/Boot.java index 74bb9ef..35947ce 100644 --- a/src/main/java/com/example/sshd/Boot.java +++ b/src/main/java/com/example/sshd/Boot.java @@ -10,22 +10,22 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Boot { - private static final Logger logger = LoggerFactory.getLogger(Boot.class); + private static final Logger logger = LoggerFactory.getLogger(Boot.class); - @Autowired - protected SshServer sshd; + @Autowired + protected SshServer sshd; - public static void main(String[] args) throws Exception { - String configDirectory = "conf"; - if (args.length > 0) { - configDirectory = args[0]; - } - logger.info("config directory: {}", configDirectory); + public static void main(String[] args) throws Exception { + String configDirectory = "conf"; + if (args.length > 0) { + configDirectory = args[0]; + } + logger.info("config directory: {}", configDirectory); - if (new java.io.File(configDirectory).exists() && new java.io.File(configDirectory).isDirectory()) { - System.setProperty("spring.config.location", configDirectory + "/springboot.yml"); - System.setProperty("logging.config", configDirectory + "/log4j2.xml"); + if (new java.io.File(configDirectory).exists() && new java.io.File(configDirectory).isDirectory()) { + System.setProperty("spring.config.location", configDirectory + "/springboot.yml"); + System.setProperty("logging.config", configDirectory + "/log4j2.xml"); + } + SpringApplication.run(Boot.class, args); } - SpringApplication.run(Boot.class, args); - } } diff --git a/src/main/java/com/example/sshd/config/AppConfig.java b/src/main/java/com/example/sshd/config/AppConfig.java index 1ca9345..864cc21 100644 --- a/src/main/java/com/example/sshd/config/AppConfig.java +++ b/src/main/java/com/example/sshd/config/AppConfig.java @@ -29,42 +29,42 @@ import com.github.benmanes.caffeine.cache.Caffeine; @ImportResource("file:conf/scheduler.xml") public class AppConfig { - @Value("${xmpp-component.config-json}") - private String xmppComponentConfigJson; + @Value("${xmpp-component.config-json}") + private String xmppComponentConfigJson; - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public XmppComponentConfig xmppComponentConfig() throws StreamReadException, DatabindException, IOException { - return new ObjectMapper().readValue(new java.io.File(xmppComponentConfigJson), XmppComponentConfig.class); - } + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public XmppComponentConfig xmppComponentConfig() throws StreamReadException, DatabindException, IOException { + return new ObjectMapper().readValue(new java.io.File(xmppComponentConfigJson), XmppComponentConfig.class); + } - @Bean("userAdminCache") - public Cache userAdminCache() { - return Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build(); - } + @Bean("userAdminCache") + public Cache userAdminCache() { + return Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build(); + } - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Map remoteSessionMapping() { - return new ConcurrentHashMap<>(); - } + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Map remoteSessionMapping() { + return new ConcurrentHashMap<>(); + } - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Map ipInfoMapping() { - return new ConcurrentHashMap<>(); - } + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Map ipInfoMapping() { + return new ConcurrentHashMap<>(); + } - @Bean - public CloseableHttpAsyncClient asyncClient() { - final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().build(); - final CloseableHttpAsyncClient client = HttpAsyncClients.custom().setIOReactorConfig(ioReactorConfig).build(); - client.start(); - return client; - } + @Bean + public CloseableHttpAsyncClient asyncClient() { + final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().build(); + final CloseableHttpAsyncClient client = HttpAsyncClients.custom().setIOReactorConfig(ioReactorConfig).build(); + client.start(); + return client; + } - @Bean - public CloseableHttpClient httpClient() { - return HttpClients.createDefault(); - } + @Bean + public CloseableHttpClient httpClient() { + return HttpClients.createDefault(); + } } diff --git a/src/main/java/com/example/sshd/config/SshConfig.java b/src/main/java/com/example/sshd/config/SshConfig.java index a68ad48..e8b2259 100644 --- a/src/main/java/com/example/sshd/config/SshConfig.java +++ b/src/main/java/com/example/sshd/config/SshConfig.java @@ -29,72 +29,72 @@ import com.example.sshd.core.OnetimeCommand; @Configuration public class SshConfig { - private static final Logger loginLogger = LoggerFactory.getLogger("login"); - - @Value("${ssh-server.port}") - private int port; - - @Value("${ssh-server.private-key.location}") - private String pkLocation; - - @Value("${ssh-server.login.usernames:root}") - private String[] usernames; - - @Value("${ssh-server.hash-replies.location}") - private String hashReplies; - - @Value("${ssh-server.regex-mapping.location}") - private String regexMapping; - - @Autowired - ApplicationContext applicationContext; - - @Bean - public SshServer sshd() throws IOException, NoSuchAlgorithmException { - SshServer sshd = SshServer.setUpDefaultServer(); - sshd.setPort(port); - sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File(pkLocation).getPath(), "RSA", 2048)); - - sshd.setPasswordAuthenticator(new PasswordAuthenticator() { - @Override - public boolean authenticate(final String username, final String password, final ServerSession session) { - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - loginLogger.info("[{}] Login Attempt: username = {}, password = {}", remoteIpAddress, username, - password); - } else { - loginLogger.info("[{}] Login Attempt: username = {}, password = {}", - session.getIoSession().getRemoteAddress(), username, password); - } - return Arrays.asList(usernames).contains(username); - } - }); - sshd.setShellFactory(applicationContext.getBean(EchoShellFactory.class)); - sshd.setCommandFactory(command -> applicationContext.getBean(OnetimeCommand.class, command)); - - sshd.start(); - sshd.getSessionFactory().addListener(applicationContext.getBean(EchoSessionListener.class)); - return sshd; - } - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Properties hashReplies() throws IOException { - Properties prop = new Properties(); - File configFile = new File(hashReplies); - FileInputStream stream = new FileInputStream(configFile); - prop.load(stream); - return prop; - } - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Properties regexMapping() throws IOException { - Properties prop = new Properties(); - File configFile = new File(regexMapping); - FileInputStream stream = new FileInputStream(configFile); - prop.load(stream); - return prop; - } + private static final Logger loginLogger = LoggerFactory.getLogger("login"); + + @Value("${ssh-server.port}") + private int port; + + @Value("${ssh-server.private-key.location}") + private String pkLocation; + + @Value("${ssh-server.login.usernames:root}") + private String[] usernames; + + @Value("${ssh-server.hash-replies.location}") + private String hashReplies; + + @Value("${ssh-server.regex-mapping.location}") + private String regexMapping; + + @Autowired + ApplicationContext applicationContext; + + @Bean + public SshServer sshd() throws IOException, NoSuchAlgorithmException { + SshServer sshd = SshServer.setUpDefaultServer(); + sshd.setPort(port); + sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File(pkLocation).getPath(), "RSA", 2048)); + + sshd.setPasswordAuthenticator(new PasswordAuthenticator() { + @Override + public boolean authenticate(final String username, final String password, final ServerSession session) { + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + loginLogger.info("[{}] Login Attempt: username = {}, password = {}", remoteIpAddress, username, + password); + } else { + loginLogger.info("[{}] Login Attempt: username = {}, password = {}", + session.getIoSession().getRemoteAddress(), username, password); + } + return Arrays.asList(usernames).contains(username); + } + }); + sshd.setShellFactory(applicationContext.getBean(EchoShellFactory.class)); + sshd.setCommandFactory(command -> applicationContext.getBean(OnetimeCommand.class, command)); + + sshd.start(); + sshd.getSessionFactory().addListener(applicationContext.getBean(EchoSessionListener.class)); + return sshd; + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Properties hashReplies() throws IOException { + Properties prop = new Properties(); + File configFile = new File(hashReplies); + FileInputStream stream = new FileInputStream(configFile); + prop.load(stream); + return prop; + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Properties regexMapping() throws IOException { + Properties prop = new Properties(); + File configFile = new File(regexMapping); + FileInputStream stream = new FileInputStream(configFile); + prop.load(stream); + return prop; + } } diff --git a/src/main/java/com/example/sshd/config/XmppComponentConfig.java b/src/main/java/com/example/sshd/config/XmppComponentConfig.java index 8b63476..ccca2e1 100644 --- a/src/main/java/com/example/sshd/config/XmppComponentConfig.java +++ b/src/main/java/com/example/sshd/config/XmppComponentConfig.java @@ -8,71 +8,71 @@ import com.fasterxml.jackson.databind.ObjectMapper; public class XmppComponentConfig { - private static final Logger logger = LoggerFactory.getLogger(XmppComponentConfig.class); - - private String subdomainPrefix; - private String domain; - private String host; - private int port; - private String secretKey; - private boolean startEncrypted; - - public String getSubdomainPrefix() { - return subdomainPrefix; - } - - public void setSubdomainPrefix(String subdomainPrefix) { - this.subdomainPrefix = subdomainPrefix; - } - - public String getDomain() { - return domain; - } - - public void setDomain(String domain) { - this.domain = domain; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String getSecretKey() { - return secretKey; - } - - public void setSecretKey(String secretKey) { - this.secretKey = secretKey; - } - - public boolean isStartEncrypted() { - return startEncrypted; - } - - public void setStartEncrypted(boolean startEncrypted) { - this.startEncrypted = startEncrypted; - } - - @Override - @JsonIgnore - public String toString() { - try { - return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); - } catch (JsonProcessingException e) { - logger.error("convert to json error!", e); + private static final Logger logger = LoggerFactory.getLogger(XmppComponentConfig.class); + + private String subdomainPrefix; + private String domain; + private String host; + private int port; + private String secretKey; + private boolean startEncrypted; + + public String getSubdomainPrefix() { + return subdomainPrefix; + } + + public void setSubdomainPrefix(String subdomainPrefix) { + this.subdomainPrefix = subdomainPrefix; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public boolean isStartEncrypted() { + return startEncrypted; + } + + public void setStartEncrypted(boolean startEncrypted) { + this.startEncrypted = startEncrypted; + } + + @Override + @JsonIgnore + public String toString() { + try { + return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); + } catch (JsonProcessingException e) { + logger.error("convert to json error!", e); + } + return "{}"; } - return "{}"; - } } diff --git a/src/main/java/com/example/sshd/core/EchoSessionListener.java b/src/main/java/com/example/sshd/core/EchoSessionListener.java index 244382a..aecf521 100644 --- a/src/main/java/com/example/sshd/core/EchoSessionListener.java +++ b/src/main/java/com/example/sshd/core/EchoSessionListener.java @@ -17,66 +17,66 @@ import com.example.sshd.service.JdbcService; @Component public class EchoSessionListener implements SessionListener { - private static final Logger logger = LoggerFactory.getLogger(EchoSessionListener.class); - private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); + private static final Logger logger = LoggerFactory.getLogger(EchoSessionListener.class); + private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); - @Autowired - Map remoteSessionMapping; + @Autowired + Map remoteSessionMapping; - @Autowired - Map ipInfoMapping; + @Autowired + Map ipInfoMapping; - @Autowired - GeoIpLocator geoIpLocator; + @Autowired + GeoIpLocator geoIpLocator; - @Autowired - JdbcService jdbcService; + @Autowired + JdbcService jdbcService; - @Override - public void sessionCreated(Session session) { - logger.info("sessionCreated: {}", session); - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - if (remoteSessionMapping.containsKey(remoteIpAddress)) { - logger.info("kill old session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); - remoteSessionMapping.get(remoteIpAddress).close(false); - } - logger.info("new session: {} -> {}", remoteIpAddress, session); - remoteSessionMapping.put(remoteIpAddress, session); - if (!ipInfoMapping.containsKey(remoteIpAddress)) { - List> ipInfoList = jdbcService.getAllRemoteIpInfo(remoteIpAddress); - if (!ipInfoList.isEmpty()) { - ipInfoMapping.put(remoteIpAddress, (String) ipInfoList.get(0).get("remote_ip_info")); + @Override + public void sessionCreated(Session session) { + logger.info("sessionCreated: {}", session); + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + if (remoteSessionMapping.containsKey(remoteIpAddress)) { + logger.info("kill old session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); + remoteSessionMapping.get(remoteIpAddress).close(false); + } + logger.info("new session: {} -> {}", remoteIpAddress, session); + remoteSessionMapping.put(remoteIpAddress, session); + if (!ipInfoMapping.containsKey(remoteIpAddress)) { + List> ipInfoList = jdbcService.getAllRemoteIpInfo(remoteIpAddress); + if (!ipInfoList.isEmpty()) { + ipInfoMapping.put(remoteIpAddress, (String) ipInfoList.get(0).get("remote_ip_info")); + } + } } - } } - } - @Override - public void sessionEvent(Session session, Event event) { - logger.info("sessionEvent: {}, event: {}", session, event); - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress && event == Event.KexCompleted) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - if (!ipInfoMapping.containsKey(remoteIpAddress)) { - geoIpLocator.asyncUpdateIpLocationInfo(remoteIpAddress); - } else { - ipInfoLogger.debug("[{}] {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress)); - } + @Override + public void sessionEvent(Session session, Event event) { + logger.info("sessionEvent: {}, event: {}", session, event); + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress && event == Event.KexCompleted) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + if (!ipInfoMapping.containsKey(remoteIpAddress)) { + geoIpLocator.asyncUpdateIpLocationInfo(remoteIpAddress); + } else { + ipInfoLogger.debug("[{}] {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress)); + } + } } - } - @Override - public void sessionClosed(Session session) { - logger.info("sessionClosed: {}", session); - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - logger.info("removing session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); - remoteSessionMapping.remove(remoteIpAddress); - ipInfoMapping.remove(remoteIpAddress); + @Override + public void sessionClosed(Session session) { + logger.info("sessionClosed: {}", session); + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + logger.info("removing session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); + remoteSessionMapping.remove(remoteIpAddress); + ipInfoMapping.remove(remoteIpAddress); + } } - } } diff --git a/src/main/java/com/example/sshd/core/EchoShell.java b/src/main/java/com/example/sshd/core/EchoShell.java index cdc11bc..b961777 100644 --- a/src/main/java/com/example/sshd/core/EchoShell.java +++ b/src/main/java/com/example/sshd/core/EchoShell.java @@ -28,119 +28,119 @@ import com.example.sshd.service.ReplyService; @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class EchoShell implements Command, Runnable, SessionAware { - private static final Logger logger = LoggerFactory.getLogger(EchoShell.class); - - @Autowired - ReplyService replyUtil; - - @Autowired - Properties hashReplies; - - protected InputStream in; - protected OutputStream out; - protected OutputStream err; - protected ExitCallback callback; - protected Environment environment; - protected Thread thread; - protected ServerSession session; - - @Override - public void setInputStream(InputStream in) { - this.in = in; - } - - @Override - public void setOutputStream(OutputStream out) { - this.out = out; - } - - @Override - public void setErrorStream(OutputStream err) { - this.err = err; - } - - @Override - public void setExitCallback(ExitCallback callback) { - this.callback = callback; - } - - @Override - public void start(Environment env) throws IOException { - environment = env; - thread = new Thread(this, remoteIpAddress()); - logger.info("environment: {}, thread-name: {}", environment.getEnv(), thread.getName()); - thread.start(); - } - - protected String remoteIpAddress() { - String remoteIpAddress = ""; - - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - } else { - remoteIpAddress = session.getIoSession().getRemoteAddress().toString(); + private static final Logger logger = LoggerFactory.getLogger(EchoShell.class); + + @Autowired + ReplyService replyUtil; + + @Autowired + Properties hashReplies; + + protected InputStream in; + protected OutputStream out; + protected OutputStream err; + protected ExitCallback callback; + protected Environment environment; + protected Thread thread; + protected ServerSession session; + + @Override + public void setInputStream(InputStream in) { + this.in = in; + } + + @Override + public void setOutputStream(OutputStream out) { + this.out = out; + } + + @Override + public void setErrorStream(OutputStream err) { + this.err = err; + } + + @Override + public void setExitCallback(ExitCallback callback) { + this.callback = callback; + } + + @Override + public void start(Environment env) throws IOException { + environment = env; + thread = new Thread(this, remoteIpAddress()); + logger.info("environment: {}, thread-name: {}", environment.getEnv(), thread.getName()); + thread.start(); } - return remoteIpAddress; - } - - @Override - public void destroy() { - thread.interrupt(); - } - - @Override - public void run() { - String prompt = hashReplies.getProperty("prompt", "$ ").replace("{user}", environment.getEnv().get("USER")); - try { - out.write(prompt.getBytes()); - out.flush(); - - BufferedReader r = new BufferedReader(new InputStreamReader(in)); - String command = ""; - - while (!Thread.currentThread().isInterrupted()) { - int s = r.read(); - if (s == 13 || s == 10) { - - boolean containsExit = Arrays.asList(StringUtils.split(command, ";|&")).stream().map(cmd -> { - boolean wantsExit = false; - try { - wantsExit = replyUtil.replyToCommand(cmd.trim(), out, prompt, session); - out.flush(); - } catch (Exception e) { - logger.error("run error!", e); - } - return wantsExit; - }).reduce((a, b) -> a || b).get(); - if (containsExit) { - break; - } - command = ""; + protected String remoteIpAddress() { + String remoteIpAddress = ""; + + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + remoteIpAddress = remoteAddress.getAddress().getHostAddress(); } else { - logger.trace("input character: {}", s); - if (s == 127) { - if (command.length() > 0) { - command = command.substring(0, command.length() - 1); - out.write(s); + remoteIpAddress = session.getIoSession().getRemoteAddress().toString(); + } + return remoteIpAddress; + } + + @Override + public void destroy() { + thread.interrupt(); + } + + @Override + public void run() { + String prompt = hashReplies.getProperty("prompt", "$ ").replace("{user}", environment.getEnv().get("USER")); + try { + out.write(prompt.getBytes()); + out.flush(); + + BufferedReader r = new BufferedReader(new InputStreamReader(in)); + String command = ""; + + while (!Thread.currentThread().isInterrupted()) { + int s = r.read(); + if (s == 13 || s == 10) { + + boolean containsExit = Arrays.asList(StringUtils.split(command, ";|&")).stream().map(cmd -> { + boolean wantsExit = false; + try { + wantsExit = replyUtil.replyToCommand(cmd.trim(), out, prompt, session); + out.flush(); + } catch (Exception e) { + logger.error("run error!", e); + } + return wantsExit; + }).reduce((a, b) -> a || b).get(); + + if (containsExit) { + break; + } + command = ""; + } else { + logger.trace("input character: {}", s); + if (s == 127) { + if (command.length() > 0) { + command = command.substring(0, command.length() - 1); + out.write(s); + } + } else if (s >= 32 && s < 127) { + command += (char) s; + out.write(s); + } + } + out.flush(); } - } else if (s >= 32 && s < 127) { - command += (char) s; - out.write(s); - } + } catch (Exception e) { + logger.error("run error!", e); + } finally { + callback.onExit(0); } - out.flush(); - } - } catch (Exception e) { - logger.error("run error!", e); - } finally { - callback.onExit(0); } - } - @Override - public void setSession(ServerSession session) { - this.session = session; - } + @Override + public void setSession(ServerSession session) { + this.session = session; + } } \ No newline at end of file diff --git a/src/main/java/com/example/sshd/core/EchoShellFactory.java b/src/main/java/com/example/sshd/core/EchoShellFactory.java index ef98872..a00cd69 100644 --- a/src/main/java/com/example/sshd/core/EchoShellFactory.java +++ b/src/main/java/com/example/sshd/core/EchoShellFactory.java @@ -9,12 +9,12 @@ import org.springframework.stereotype.Component; @Component public class EchoShellFactory implements Factory { - @Autowired - ApplicationContext applicationContext; + @Autowired + ApplicationContext applicationContext; - @Override - public Command create() { - return (Command) applicationContext.getBean("echoShell"); - } + @Override + public Command create() { + return (Command) applicationContext.getBean("echoShell"); + } } \ No newline at end of file diff --git a/src/main/java/com/example/sshd/core/OnetimeCommand.java b/src/main/java/com/example/sshd/core/OnetimeCommand.java index b183ccd..ad22f68 100644 --- a/src/main/java/com/example/sshd/core/OnetimeCommand.java +++ b/src/main/java/com/example/sshd/core/OnetimeCommand.java @@ -13,29 +13,29 @@ import org.springframework.stereotype.Component; @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class OnetimeCommand extends EchoShell { - private static final Logger logger = LoggerFactory.getLogger(OnetimeCommand.class); + private static final Logger logger = LoggerFactory.getLogger(OnetimeCommand.class); - private String command; + private String command; - public OnetimeCommand(String cmd) { - command = cmd; - } + public OnetimeCommand(String cmd) { + command = cmd; + } - @Override - public void run() { - try { - Arrays.asList(StringUtils.split(command, ";|&")).stream().forEach(cmd -> { + @Override + public void run() { try { - replyUtil.replyToCommand(cmd.trim(), out, "", session); - out.flush(); + Arrays.asList(StringUtils.split(command, ";|&")).stream().forEach(cmd -> { + try { + replyUtil.replyToCommand(cmd.trim(), out, "", session); + out.flush(); + } catch (Exception e) { + logger.error("run error!", e); + } + }); } catch (Exception e) { - logger.error("run error!", e); + logger.error("run error!", e); + } finally { + callback.onExit(0); } - }); - } catch (Exception e) { - logger.error("run error!", e); - } finally { - callback.onExit(0); } - } } diff --git a/src/main/java/com/example/sshd/service/EchoComponent.java b/src/main/java/com/example/sshd/service/EchoComponent.java index c7ec3d4..7d5b01c 100644 --- a/src/main/java/com/example/sshd/service/EchoComponent.java +++ b/src/main/java/com/example/sshd/service/EchoComponent.java @@ -23,290 +23,290 @@ import jakarta.annotation.PostConstruct; @Component public class EchoComponent extends AbstractComponent { - private static final Logger logger = LoggerFactory.getLogger(EchoComponent.class); - public static final String CONST_OPERATION_ADD_USER = "adduser"; - public static final String CONST_OPERATION_CHANGE_USER_PASSWORD = "chgpasswd"; - public static final String CONST_OPERATION_DELETE_USER = "deluser"; - public static final String CONST_OPERATION_JMX_CLIENT = "jmx_client"; + private static final Logger logger = LoggerFactory.getLogger(EchoComponent.class); + public static final String CONST_OPERATION_ADD_USER = "adduser"; + public static final String CONST_OPERATION_CHANGE_USER_PASSWORD = "chgpasswd"; + public static final String CONST_OPERATION_DELETE_USER = "deluser"; + public static final String CONST_OPERATION_JMX_CLIENT = "jmx_client"; - @Autowired - XmppComponentConfig xmppComponentConfig; + @Autowired + XmppComponentConfig xmppComponentConfig; - @Autowired - ReplyService replyService; + @Autowired + ReplyService replyService; - @Autowired - JmxClientService jmxClientService; - - @Autowired - @Qualifier("userAdminCache") - private volatile Cache userAdminCache; + @Autowired + JmxClientService jmxClientService; - ExternalComponentManager externalComponentManager = null; + @Autowired + @Qualifier("userAdminCache") + private volatile Cache userAdminCache; - @PostConstruct - public void init() throws ComponentException { - logger.info("Starting up {} ...", xmppComponentConfig); - externalComponentManager = new ExternalComponentManager(xmppComponentConfig.getHost(), - xmppComponentConfig.getPort(), xmppComponentConfig.isStartEncrypted()); - externalComponentManager.setMultipleAllowed(xmppComponentConfig.getSubdomainPrefix(), false); - externalComponentManager.setServerName(xmppComponentConfig.getDomain()); - externalComponentManager.setSecretKey(xmppComponentConfig.getSubdomainPrefix(), - xmppComponentConfig.getSecretKey()); - externalComponentManager.addComponent(xmppComponentConfig.getSubdomainPrefix(), this, - xmppComponentConfig.getPort()); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - try { - externalComponentManager.removeComponent(xmppComponentConfig.getSubdomainPrefix()); - } catch (ComponentException e) { - e.printStackTrace(); - } - })); - } + ExternalComponentManager externalComponentManager = null; - @Override - public String getDescription() { - return "XMPP component for doing ECHO"; - } + @PostConstruct + public void init() throws ComponentException { + logger.info("Starting up {} ...", xmppComponentConfig); + externalComponentManager = new ExternalComponentManager(xmppComponentConfig.getHost(), + xmppComponentConfig.getPort(), xmppComponentConfig.isStartEncrypted()); + externalComponentManager.setMultipleAllowed(xmppComponentConfig.getSubdomainPrefix(), false); + externalComponentManager.setServerName(xmppComponentConfig.getDomain()); + externalComponentManager.setSecretKey(xmppComponentConfig.getSubdomainPrefix(), + xmppComponentConfig.getSecretKey()); + externalComponentManager.addComponent(xmppComponentConfig.getSubdomainPrefix(), this, + xmppComponentConfig.getPort()); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + externalComponentManager.removeComponent(xmppComponentConfig.getSubdomainPrefix()); + } catch (ComponentException e) { + e.printStackTrace(); + } + })); + } - @Override - public String getName() { - return this.getClass().getName(); - } + @Override + public String getDescription() { + return "XMPP component for doing ECHO"; + } - public void sendMessage(String fromJID, String toJID, String message) { - try { - Message outMsg = new Message(); - outMsg.setType(Message.Type.chat); - outMsg.setFrom(fromJID); - outMsg.setTo(toJID); - outMsg.setBody(replyService.executeShellCommand(message)); - externalComponentManager.sendPacket(this, outMsg); - logger.info("[sendMessage] -- SENT -- {}", outMsg); - } catch (Exception err) { - logger.error("[sendMessage] ", err); + @Override + public String getName() { + return this.getClass().getName(); } - } - - private void doEcho(final Message inMsg, String body) { - try { - Message outMsg = new Message(); - outMsg.setType(inMsg.getType()); - outMsg.setFrom(inMsg.getTo()); - if (StringUtils.endsWith(inMsg.getSubject(), "@" + xmppComponentConfig.getDomain())) { - outMsg.setTo(inMsg.getSubject()); - } else { - outMsg.setTo(inMsg.getFrom()); - } - outMsg.setSubject(inMsg.getSubject()); - outMsg.setBody(body == null ? inMsg.getBody() : body); - externalComponentManager.sendPacket(this, outMsg); - logger.info("[doEcho] -- SENT -- {}", outMsg); - } catch (Exception err) { - logger.error("[doEcho] ", err); + + public void sendMessage(String fromJID, String toJID, String message) { + try { + Message outMsg = new Message(); + outMsg.setType(Message.Type.chat); + outMsg.setFrom(fromJID); + outMsg.setTo(toJID); + outMsg.setBody(replyService.executeShellCommand(message)); + externalComponentManager.sendPacket(this, outMsg); + logger.info("[sendMessage] -- SENT -- {}", outMsg); + } catch (Exception err) { + logger.error("[sendMessage] ", err); + } } - } - protected void handleMessage(final Message inMsg) { - logger.info("[handleMessage] -- RECEIVED -- {}", inMsg); - try { - if (StringUtils.isNotBlank(inMsg.getBody())) { - String[] commandParts = StringUtils.split(inMsg.getBody().trim(), ' '); - switch (commandParts[0]) { - case CONST_OPERATION_ADD_USER: - if (commandParts.length == 3) - requestAddUserForm(inMsg); - else - doEcho(inMsg, "adduser "); - break; - case CONST_OPERATION_DELETE_USER: - if (commandParts.length == 2) - requestDeleteUserForm(inMsg); - else - doEcho(inMsg, "deluser "); - break; - case CONST_OPERATION_CHANGE_USER_PASSWORD: - if (commandParts.length == 3) - requestChangeUserPassword(inMsg); - else - doEcho(inMsg, "chgpasswd "); - break; - case CONST_OPERATION_JMX_CLIENT: - doEcho(inMsg, jmxClientService.process(commandParts)); - break; - default: - doEcho(inMsg, replyService.executeShellCommand(inMsg.getBody().trim())); - break; + private void doEcho(final Message inMsg, String body) { + try { + Message outMsg = new Message(); + outMsg.setType(inMsg.getType()); + outMsg.setFrom(inMsg.getTo()); + if (StringUtils.endsWith(inMsg.getSubject(), "@" + xmppComponentConfig.getDomain())) { + outMsg.setTo(inMsg.getSubject()); + } else { + outMsg.setTo(inMsg.getFrom()); + } + outMsg.setSubject(inMsg.getSubject()); + outMsg.setBody(body == null ? inMsg.getBody() : body); + externalComponentManager.sendPacket(this, outMsg); + logger.info("[doEcho] -- SENT -- {}", outMsg); + } catch (Exception err) { + logger.error("[doEcho] ", err); } - } - } catch (Exception err) { - logger.error("[handleMessage] ", err); } - } - @Override - protected void handleIQResult(IQ iq) { - try { - logger.debug("[handleIQResult] {} has received iq-result: {}", getName(), iq); - if (iq.getChildElement() != null) { - logger.debug("[{}] {}'s child-namespace: {}", iq.getID(), getName(), - iq.getChildElement().getNamespace()); - logger.debug("[{}] {}'s child-name: {}", iq.getID(), getName(), iq.getChildElement().getName()); - if (iq.getChildElement().getNamespace().equals(Namespace.get("http://jabber.org/protocol/commands")) - && iq.getChildElement().getName().equals("command")) { - Message inMsg = userAdminCache.getIfPresent(iq.getID()); - handleCommands(iq.getID(), inMsg, iq.getChildElement()); + protected void handleMessage(final Message inMsg) { + logger.info("[handleMessage] -- RECEIVED -- {}", inMsg); + try { + if (StringUtils.isNotBlank(inMsg.getBody())) { + String[] commandParts = StringUtils.split(inMsg.getBody().trim(), ' '); + switch (commandParts[0]) { + case CONST_OPERATION_ADD_USER: + if (commandParts.length == 3) + requestAddUserForm(inMsg); + else + doEcho(inMsg, "adduser "); + break; + case CONST_OPERATION_DELETE_USER: + if (commandParts.length == 2) + requestDeleteUserForm(inMsg); + else + doEcho(inMsg, "deluser "); + break; + case CONST_OPERATION_CHANGE_USER_PASSWORD: + if (commandParts.length == 3) + requestChangeUserPassword(inMsg); + else + doEcho(inMsg, "chgpasswd "); + break; + case CONST_OPERATION_JMX_CLIENT: + doEcho(inMsg, jmxClientService.process(commandParts)); + break; + default: + doEcho(inMsg, replyService.executeShellCommand(inMsg.getBody().trim())); + break; + } + } + } catch (Exception err) { + logger.error("[handleMessage] ", err); } - } - } catch (Exception err) { - logger.error("[handleIQResult] ", err); } - } - protected void handleCommands(String id, Message inMsg, Element command) throws InterruptedException { - String status = command.attributeValue("status"); - String node = command.attributeValue("node"); - String sessionid = command.attributeValue("sessionid"); - logger.debug("[{}] sessionid: {}, status: {}, node: {}", id, sessionid, status, node); - if (status.equals("executing")) { - if (node.equals("http://jabber.org/protocol/admin#add-user")) { - sendAddUserForm(sessionid, inMsg); - } else if (node.equals("http://jabber.org/protocol/admin#delete-user")) { - sendDeleteUserForm(sessionid, inMsg); - } else if (node.equals("http://jabber.org/protocol/admin#change-user-password")) { - sendChangeUserPasswordForm(sessionid, inMsg); - } - } else if (status.equals("completed")) { - doEcho(inMsg, "OK"); + @Override + protected void handleIQResult(IQ iq) { + try { + logger.debug("[handleIQResult] {} has received iq-result: {}", getName(), iq); + if (iq.getChildElement() != null) { + logger.debug("[{}] {}'s child-namespace: {}", iq.getID(), getName(), + iq.getChildElement().getNamespace()); + logger.debug("[{}] {}'s child-name: {}", iq.getID(), getName(), iq.getChildElement().getName()); + if (iq.getChildElement().getNamespace().equals(Namespace.get("http://jabber.org/protocol/commands")) + && iq.getChildElement().getName().equals("command")) { + Message inMsg = userAdminCache.getIfPresent(iq.getID()); + handleCommands(iq.getID(), inMsg, iq.getChildElement()); + } + } + } catch (Exception err) { + logger.error("[handleIQResult] ", err); + } } - } - public void requestAddUserForm(Message inMsg) { - try { - IQ addUserIq = new IQ(Type.set); - addUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); - addUserIq.setTo(xmppComponentConfig.getDomain()); - Element child = addUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); - child.addAttribute("action", "execute"); - child.addAttribute("node", "http://jabber.org/protocol/admin#add-user"); - userAdminCache.put(addUserIq.getID(), inMsg); - externalComponentManager.sendPacket(this, addUserIq); - logger.info("[requestAddUserForm] -- SENT -- {}", addUserIq); - } catch (Exception err) { - logger.error("[requestAddUserForm] ", err); + protected void handleCommands(String id, Message inMsg, Element command) throws InterruptedException { + String status = command.attributeValue("status"); + String node = command.attributeValue("node"); + String sessionid = command.attributeValue("sessionid"); + logger.debug("[{}] sessionid: {}, status: {}, node: {}", id, sessionid, status, node); + if (status.equals("executing")) { + if (node.equals("http://jabber.org/protocol/admin#add-user")) { + sendAddUserForm(sessionid, inMsg); + } else if (node.equals("http://jabber.org/protocol/admin#delete-user")) { + sendDeleteUserForm(sessionid, inMsg); + } else if (node.equals("http://jabber.org/protocol/admin#change-user-password")) { + sendChangeUserPasswordForm(sessionid, inMsg); + } + } else if (status.equals("completed")) { + doEcho(inMsg, "OK"); + } } - } - private void createFormTypeElement(Element x, String var, String type, String value) { - Element formType = x.addElement("field"); - formType.addAttribute("var", var); - if (type != null) { - formType.addAttribute("type", type); + public void requestAddUserForm(Message inMsg) { + try { + IQ addUserIq = new IQ(Type.set); + addUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); + addUserIq.setTo(xmppComponentConfig.getDomain()); + Element child = addUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); + child.addAttribute("action", "execute"); + child.addAttribute("node", "http://jabber.org/protocol/admin#add-user"); + userAdminCache.put(addUserIq.getID(), inMsg); + externalComponentManager.sendPacket(this, addUserIq); + logger.info("[requestAddUserForm] -- SENT -- {}", addUserIq); + } catch (Exception err) { + logger.error("[requestAddUserForm] ", err); + } } - formType.addElement("value").setText(value); - } - public void sendAddUserForm(String sessionId, Message inMsg) { - try { - String[] commandParts = StringUtils.split(inMsg.getBody(), ' '); - IQ addUserIq = new IQ(Type.set); - addUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); - addUserIq.setTo(xmppComponentConfig.getDomain()); - Element child = addUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); - child.addAttribute("node", "http://jabber.org/protocol/admin#add-user"); - child.addAttribute("sessionid", sessionId); - Element x = child.addElement("x", "jabber:x:data"); - x.addAttribute("type", "submit"); - createFormTypeElement(x, "FORM_TYPE", "hidden", "http://jabber.org/protocol/admin"); - createFormTypeElement(x, "accountjid", "jid-single", - commandParts[1] + "@" + xmppComponentConfig.getDomain()); - createFormTypeElement(x, "password", "text-private", commandParts[2]); - createFormTypeElement(x, "password-verify", "text-private", commandParts[2]); - userAdminCache.put(addUserIq.getID(), inMsg); - externalComponentManager.sendPacket(this, addUserIq); - logger.info("[sendAddUserForm] -- SENT -- {}", addUserIq); - } catch (Exception err) { - logger.error("[sendAddUserForm] ", err); + private void createFormTypeElement(Element x, String var, String type, String value) { + Element formType = x.addElement("field"); + formType.addAttribute("var", var); + if (type != null) { + formType.addAttribute("type", type); + } + formType.addElement("value").setText(value); } - } - public void requestDeleteUserForm(Message inMsg) { - try { - IQ deleteUserIq = new IQ(Type.set); - deleteUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); - deleteUserIq.setTo(xmppComponentConfig.getDomain()); - Element child = deleteUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); - child.addAttribute("action", "execute"); - child.addAttribute("node", "http://jabber.org/protocol/admin#delete-user"); - userAdminCache.put(deleteUserIq.getID(), inMsg); - externalComponentManager.sendPacket(this, deleteUserIq); - logger.info("[requestDeleteUserForm] -- SENT -- {}", deleteUserIq); - } catch (Exception err) { - logger.error("[requestDeleteUserForm] ", err); + public void sendAddUserForm(String sessionId, Message inMsg) { + try { + String[] commandParts = StringUtils.split(inMsg.getBody(), ' '); + IQ addUserIq = new IQ(Type.set); + addUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); + addUserIq.setTo(xmppComponentConfig.getDomain()); + Element child = addUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); + child.addAttribute("node", "http://jabber.org/protocol/admin#add-user"); + child.addAttribute("sessionid", sessionId); + Element x = child.addElement("x", "jabber:x:data"); + x.addAttribute("type", "submit"); + createFormTypeElement(x, "FORM_TYPE", "hidden", "http://jabber.org/protocol/admin"); + createFormTypeElement(x, "accountjid", "jid-single", + commandParts[1] + "@" + xmppComponentConfig.getDomain()); + createFormTypeElement(x, "password", "text-private", commandParts[2]); + createFormTypeElement(x, "password-verify", "text-private", commandParts[2]); + userAdminCache.put(addUserIq.getID(), inMsg); + externalComponentManager.sendPacket(this, addUserIq); + logger.info("[sendAddUserForm] -- SENT -- {}", addUserIq); + } catch (Exception err) { + logger.error("[sendAddUserForm] ", err); + } } - } - public void sendDeleteUserForm(String sessionId, Message inMsg) { - try { - String[] commandParts = StringUtils.split(inMsg.getBody(), ' '); - IQ deleteUserIq = new IQ(Type.set); - deleteUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); - deleteUserIq.setTo(xmppComponentConfig.getDomain()); - Element child = deleteUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); - child.addAttribute("node", "http://jabber.org/protocol/admin#delete-user"); - child.addAttribute("sessionid", sessionId); - Element x = child.addElement("x", "jabber:x:data"); - x.addAttribute("type", "submit"); - createFormTypeElement(x, "FORM_TYPE", "hidden", "http://jabber.org/protocol/admin"); - createFormTypeElement(x, "accountjids", "jid-single", - commandParts[1] + "@" + xmppComponentConfig.getDomain()); - userAdminCache.put(deleteUserIq.getID(), inMsg); - externalComponentManager.sendPacket(this, deleteUserIq); - logger.info("[sendDeleteUserForm] -- SENT -- {}", deleteUserIq); - } catch (Exception err) { - logger.error("[sendDeleteUserForm] ", err); + public void requestDeleteUserForm(Message inMsg) { + try { + IQ deleteUserIq = new IQ(Type.set); + deleteUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); + deleteUserIq.setTo(xmppComponentConfig.getDomain()); + Element child = deleteUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); + child.addAttribute("action", "execute"); + child.addAttribute("node", "http://jabber.org/protocol/admin#delete-user"); + userAdminCache.put(deleteUserIq.getID(), inMsg); + externalComponentManager.sendPacket(this, deleteUserIq); + logger.info("[requestDeleteUserForm] -- SENT -- {}", deleteUserIq); + } catch (Exception err) { + logger.error("[requestDeleteUserForm] ", err); + } } - } - public void requestChangeUserPassword(Message inMsg) { - try { - IQ changeUserPasswordIq = new IQ(Type.set); - changeUserPasswordIq - .setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); - changeUserPasswordIq.setTo(xmppComponentConfig.getDomain()); - Element child = changeUserPasswordIq.setChildElement("command", "http://jabber.org/protocol/commands"); - child.addAttribute("action", "execute"); - child.addAttribute("node", "http://jabber.org/protocol/admin#change-user-password"); - userAdminCache.put(changeUserPasswordIq.getID(), inMsg); - externalComponentManager.sendPacket(this, changeUserPasswordIq); - logger.info("[requestChangeUserPassword] -- SENT -- {}", changeUserPasswordIq); - } catch (Exception err) { - logger.error("[requestChangeUserPassword] ", err); + public void sendDeleteUserForm(String sessionId, Message inMsg) { + try { + String[] commandParts = StringUtils.split(inMsg.getBody(), ' '); + IQ deleteUserIq = new IQ(Type.set); + deleteUserIq.setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); + deleteUserIq.setTo(xmppComponentConfig.getDomain()); + Element child = deleteUserIq.setChildElement("command", "http://jabber.org/protocol/commands"); + child.addAttribute("node", "http://jabber.org/protocol/admin#delete-user"); + child.addAttribute("sessionid", sessionId); + Element x = child.addElement("x", "jabber:x:data"); + x.addAttribute("type", "submit"); + createFormTypeElement(x, "FORM_TYPE", "hidden", "http://jabber.org/protocol/admin"); + createFormTypeElement(x, "accountjids", "jid-single", + commandParts[1] + "@" + xmppComponentConfig.getDomain()); + userAdminCache.put(deleteUserIq.getID(), inMsg); + externalComponentManager.sendPacket(this, deleteUserIq); + logger.info("[sendDeleteUserForm] -- SENT -- {}", deleteUserIq); + } catch (Exception err) { + logger.error("[sendDeleteUserForm] ", err); + } } - } - public void sendChangeUserPasswordForm(String sessionId, Message inMsg) { - try { - String[] commandParts = StringUtils.split(inMsg.getBody(), ' '); - IQ changeUserPasswordIq = new IQ(Type.set); - changeUserPasswordIq - .setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); - changeUserPasswordIq.setTo(xmppComponentConfig.getDomain()); - Element child = changeUserPasswordIq.setChildElement("command", "http://jabber.org/protocol/commands"); - child.addAttribute("node", "http://jabber.org/protocol/admin#change-user-password"); - child.addAttribute("sessionid", sessionId); - Element x = child.addElement("x", "jabber:x:data"); - x.addAttribute("type", "submit"); - createFormTypeElement(x, "FORM_TYPE", "hidden", "http://jabber.org/protocol/admin"); - createFormTypeElement(x, "accountjid", "jid-single", - commandParts[1] + "@" + xmppComponentConfig.getDomain()); - createFormTypeElement(x, "password", "text-private", commandParts[2]); - userAdminCache.put(changeUserPasswordIq.getID(), inMsg); - externalComponentManager.sendPacket(this, changeUserPasswordIq); - logger.info("[sendChangeUserPasswordForm] -- SENT -- {}", changeUserPasswordIq); - } catch (Exception err) { - logger.error("[sendChangeUserPasswordForm] ", err); + public void requestChangeUserPassword(Message inMsg) { + try { + IQ changeUserPasswordIq = new IQ(Type.set); + changeUserPasswordIq + .setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); + changeUserPasswordIq.setTo(xmppComponentConfig.getDomain()); + Element child = changeUserPasswordIq.setChildElement("command", "http://jabber.org/protocol/commands"); + child.addAttribute("action", "execute"); + child.addAttribute("node", "http://jabber.org/protocol/admin#change-user-password"); + userAdminCache.put(changeUserPasswordIq.getID(), inMsg); + externalComponentManager.sendPacket(this, changeUserPasswordIq); + logger.info("[requestChangeUserPassword] -- SENT -- {}", changeUserPasswordIq); + } catch (Exception err) { + logger.error("[requestChangeUserPassword] ", err); + } + } + + public void sendChangeUserPasswordForm(String sessionId, Message inMsg) { + try { + String[] commandParts = StringUtils.split(inMsg.getBody(), ' '); + IQ changeUserPasswordIq = new IQ(Type.set); + changeUserPasswordIq + .setFrom(xmppComponentConfig.getSubdomainPrefix() + "." + xmppComponentConfig.getDomain()); + changeUserPasswordIq.setTo(xmppComponentConfig.getDomain()); + Element child = changeUserPasswordIq.setChildElement("command", "http://jabber.org/protocol/commands"); + child.addAttribute("node", "http://jabber.org/protocol/admin#change-user-password"); + child.addAttribute("sessionid", sessionId); + Element x = child.addElement("x", "jabber:x:data"); + x.addAttribute("type", "submit"); + createFormTypeElement(x, "FORM_TYPE", "hidden", "http://jabber.org/protocol/admin"); + createFormTypeElement(x, "accountjid", "jid-single", + commandParts[1] + "@" + xmppComponentConfig.getDomain()); + createFormTypeElement(x, "password", "text-private", commandParts[2]); + userAdminCache.put(changeUserPasswordIq.getID(), inMsg); + externalComponentManager.sendPacket(this, changeUserPasswordIq); + logger.info("[sendChangeUserPasswordForm] -- SENT -- {}", changeUserPasswordIq); + } catch (Exception err) { + logger.error("[sendChangeUserPasswordForm] ", err); + } } - } } diff --git a/src/main/java/com/example/sshd/service/GeoIpLocator.java b/src/main/java/com/example/sshd/service/GeoIpLocator.java index ff84d8b..a8976dd 100644 --- a/src/main/java/com/example/sshd/service/GeoIpLocator.java +++ b/src/main/java/com/example/sshd/service/GeoIpLocator.java @@ -22,74 +22,74 @@ import org.springframework.stereotype.Service; @Service public class GeoIpLocator { - private static final Logger logger = LoggerFactory.getLogger(GeoIpLocator.class); - private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); - - @Autowired - Map ipInfoMapping; - - @Autowired - JdbcService jdbcService; - - @Autowired - CloseableHttpAsyncClient asyncClient; - - @Autowired - CloseableHttpClient httpClient; - - @Value("${ssh-server.ip-info-api.url:http://ip-api.com/json/%s}") - private String ipInfoApiUrl; - - @Value("${ssh-server.ip-info-api.method:GET}") - private String ipInfoApiMethod; - - public String getIpLocationInfo(String remoteIpAddress) { - HttpGet httpGet = new HttpGet(String.format(ipInfoApiUrl, remoteIpAddress)); - try { - return httpClient.execute(httpGet, new HttpClientResponseHandler() { - - @Override - public String handleResponse(ClassicHttpResponse result) throws HttpException, IOException { - String body = new String(result.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); - logger.info("[{}] httpClient.execute completed, response code: {}, body: {}", remoteIpAddress, - result.getCode(), body); - ipInfoMapping.put(remoteIpAddress, body); - int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, body); - ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), - inserted); - return body; + private static final Logger logger = LoggerFactory.getLogger(GeoIpLocator.class); + private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); + + @Autowired + Map ipInfoMapping; + + @Autowired + JdbcService jdbcService; + + @Autowired + CloseableHttpAsyncClient asyncClient; + + @Autowired + CloseableHttpClient httpClient; + + @Value("${ssh-server.ip-info-api.url:http://ip-api.com/json/%s}") + private String ipInfoApiUrl; + + @Value("${ssh-server.ip-info-api.method:GET}") + private String ipInfoApiMethod; + + public String getIpLocationInfo(String remoteIpAddress) { + HttpGet httpGet = new HttpGet(String.format(ipInfoApiUrl, remoteIpAddress)); + try { + return httpClient.execute(httpGet, new HttpClientResponseHandler() { + + @Override + public String handleResponse(ClassicHttpResponse result) throws HttpException, IOException { + String body = new String(result.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); + logger.info("[{}] httpClient.execute completed, response code: {}, body: {}", remoteIpAddress, + result.getCode(), body); + ipInfoMapping.put(remoteIpAddress, body); + int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, body); + ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), + inserted); + return body; + } + + }); + } catch (IOException e) { + logger.error("[getIpLocationInfo] IO Exception has occurred!", e); + return null; } + } - }); - } catch (IOException e) { - logger.error("[getIpLocationInfo] IO Exception has occurred!", e); - return null; + public void asyncUpdateIpLocationInfo(String remoteIpAddress) { + asyncClient.execute(SimpleHttpRequest.create(ipInfoApiMethod, String.format(ipInfoApiUrl, remoteIpAddress)), + new FutureCallback() { + + @Override + public void completed(SimpleHttpResponse result) { + logger.info("[{}] asyncClient.execute completed, result: {}, content-type: {}, body: {}", + remoteIpAddress, result, result.getContentType(), result.getBodyText()); + ipInfoMapping.put(remoteIpAddress, result.getBodyText()); + int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, result.getBodyText()); + ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), + inserted); + } + + @Override + public void failed(Exception exception) { + logger.info("[{}] asyncClient.execute failed, exception: {}", remoteIpAddress, exception); + } + + @Override + public void cancelled() { + logger.info("[{}] asyncClient.execute cancelled.", remoteIpAddress); + } + }); } - } - - public void asyncUpdateIpLocationInfo(String remoteIpAddress) { - asyncClient.execute(SimpleHttpRequest.create(ipInfoApiMethod, String.format(ipInfoApiUrl, remoteIpAddress)), - new FutureCallback() { - - @Override - public void completed(SimpleHttpResponse result) { - logger.info("[{}] asyncClient.execute completed, result: {}, content-type: {}, body: {}", - remoteIpAddress, result, result.getContentType(), result.getBodyText()); - ipInfoMapping.put(remoteIpAddress, result.getBodyText()); - int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, result.getBodyText()); - ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), - inserted); - } - - @Override - public void failed(Exception exception) { - logger.info("[{}] asyncClient.execute failed, exception: {}", remoteIpAddress, exception); - } - - @Override - public void cancelled() { - logger.info("[{}] asyncClient.execute cancelled.", remoteIpAddress); - } - }); - } } diff --git a/src/main/java/com/example/sshd/service/JdbcService.java b/src/main/java/com/example/sshd/service/JdbcService.java index 70f9c46..883c580 100644 --- a/src/main/java/com/example/sshd/service/JdbcService.java +++ b/src/main/java/com/example/sshd/service/JdbcService.java @@ -16,59 +16,59 @@ import jakarta.annotation.PostConstruct; @Service public class JdbcService { - private static final String createRemoteIpLookupTableSql = "CREATE TABLE IF NOT EXISTS public.remote_ip_lookup (id BIGINT not null, " - + "remote_ip_address CHARACTER VARYING not null, remote_ip_info CHARACTER VARYING not null, PRIMARY KEY (id));"; - private static final String createRemoteIpLookupIndexSql = "CREATE INDEX IF NOT EXISTS public.remote_ip_lookup_idx ON " - + "public.remote_ip_lookup (remote_ip_address);"; + private static final String createRemoteIpLookupTableSql = "CREATE TABLE IF NOT EXISTS public.remote_ip_lookup (id BIGINT not null, " + + "remote_ip_address CHARACTER VARYING not null, remote_ip_info CHARACTER VARYING not null, PRIMARY KEY (id));"; + private static final String createRemoteIpLookupIndexSql = "CREATE INDEX IF NOT EXISTS public.remote_ip_lookup_idx ON " + + "public.remote_ip_lookup (remote_ip_address);"; - @Autowired - private JdbcTemplate jdbcTemplate; + @Autowired + private JdbcTemplate jdbcTemplate; - @PostConstruct - private void init() { - jdbcTemplate.execute(createRemoteIpLookupTableSql); - jdbcTemplate.execute(createRemoteIpLookupIndexSql); - } + @PostConstruct + private void init() { + jdbcTemplate.execute(createRemoteIpLookupTableSql); + jdbcTemplate.execute(createRemoteIpLookupIndexSql); + } - public String getRemoteIpInfo(String remoteIp) { - var result = jdbcTemplate.query( - "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", - new RowMapper() { - @Override - public String mapRow(ResultSet rs, int rowNum) throws SQLException { - return rs.getString(3); - } - }, remoteIp); - return result.isEmpty() ? null : result.get(0); - } + public String getRemoteIpInfo(String remoteIp) { + var result = jdbcTemplate.query( + "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", + new RowMapper() { + @Override + public String mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getString(3); + } + }, remoteIp); + return result.isEmpty() ? null : result.get(0); + } - public List> getAllRemoteIpInfo(String remoteIp) { - return jdbcTemplate.query( - "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", - new RowMapper>() { - @Override - public Map mapRow(ResultSet rs, int rowNum) throws SQLException { - return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), - "remote_ip_info", rs.getString(3)); - } - }, remoteIp); - } + public List> getAllRemoteIpInfo(String remoteIp) { + return jdbcTemplate.query( + "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", + new RowMapper>() { + @Override + public Map mapRow(ResultSet rs, int rowNum) throws SQLException { + return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), + "remote_ip_info", rs.getString(3)); + } + }, remoteIp); + } - public List> getAllRemoteIpInfo() { - return jdbcTemplate.query( - "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup order by id", - new RowMapper>() { - @Override - public Map mapRow(ResultSet rs, int rowNum) throws SQLException { - return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), - "remote_ip_info", rs.getString(3)); - } - }); - } + public List> getAllRemoteIpInfo() { + return jdbcTemplate.query( + "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup order by id", + new RowMapper>() { + @Override + public Map mapRow(ResultSet rs, int rowNum) throws SQLException { + return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), + "remote_ip_info", rs.getString(3)); + } + }); + } - public int insertRemoteIpInfo(String remoteIpAddress, String remoteIpInfo) { - return jdbcTemplate.update( - "INSERT INTO public.remote_ip_lookup (id, remote_ip_address, remote_ip_info) VALUES (?, ?, ?)", - System.currentTimeMillis(), remoteIpAddress, remoteIpInfo); - } + public int insertRemoteIpInfo(String remoteIpAddress, String remoteIpInfo) { + return jdbcTemplate.update( + "INSERT INTO public.remote_ip_lookup (id, remote_ip_address, remote_ip_info) VALUES (?, ?, ?)", + System.currentTimeMillis(), remoteIpAddress, remoteIpInfo); + } } diff --git a/src/main/java/com/example/sshd/service/JmxClientService.java b/src/main/java/com/example/sshd/service/JmxClientService.java index a832d46..88878c3 100644 --- a/src/main/java/com/example/sshd/service/JmxClientService.java +++ b/src/main/java/com/example/sshd/service/JmxClientService.java @@ -24,64 +24,64 @@ import org.springframework.stereotype.Service; @Service public class JmxClientService { - private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); + private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); - public String process(String[] args) { - // Example - // 1st parameter: service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi - // 2nd parameter: java.lang:type=Memory + public String process(String[] args) { + // Example + // 1st parameter: service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi + // 2nd parameter: java.lang:type=Memory - StringBuilder output = new StringBuilder(); - try { - if (args.length > 2) { - Runtime.getRuntime().freeMemory(); - JMXServiceURL url = new JMXServiceURL(args[1]); - JMXConnector jmxc = JMXConnectorFactory.connect(url, null); - MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + StringBuilder output = new StringBuilder(); + try { + if (args.length > 2) { + Runtime.getRuntime().freeMemory(); + JMXServiceURL url = new JMXServiceURL(args[1]); + JMXConnector jmxc = JMXConnectorFactory.connect(url, null); + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); - ObjectName mbeanName = new ObjectName(args[2]); + ObjectName mbeanName = new ObjectName(args[2]); - MBeanInfo info = mbsc.getMBeanInfo(mbeanName); - MBeanAttributeInfo[] attribute = info.getAttributes(); + MBeanInfo info = mbsc.getMBeanInfo(mbeanName); + MBeanAttributeInfo[] attribute = info.getAttributes(); - logger.info("[process] args.length: {}", args.length); - if (args.length > 3) { - for (MBeanAttributeInfo attr : attribute) { - List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); - if (args[3].equals(attr.getName())) { - Optional> opt = alist.stream().filter(a -> a.getName().equals(args[3])) - .map(a -> toMap((CompositeData) a.getValue())).findFirst(); - if (opt.isPresent()) { - output.append(attr.getName() + ": " + opt.get() + "\r\n"); - } + logger.info("[process] args.length: {}", args.length); + if (args.length > 3) { + for (MBeanAttributeInfo attr : attribute) { + List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); + if (args[3].equals(attr.getName())) { + Optional> opt = alist.stream().filter(a -> a.getName().equals(args[3])) + .map(a -> toMap((CompositeData) a.getValue())).findFirst(); + if (opt.isPresent()) { + output.append(attr.getName() + ": " + opt.get() + "\r\n"); + } + } + } + } else { + for (MBeanAttributeInfo attr : attribute) { + List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); + output.append(attr.getName() + ": " + alist + "\r\n"); + } + } + jmxc.close(); + } else { + output.append( + "Example: jmx_client service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi java.lang:type=Memory HeapMemoryUsage\r\n"); } - } - } else { - for (MBeanAttributeInfo attr : attribute) { - List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); - output.append(attr.getName() + ": " + alist + "\r\n"); - } + } catch (Exception e) { + logger.error("process cmd failed: {}", Arrays.asList(args), e); } - jmxc.close(); - } else { - output.append( - "Example: jmx_client service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi java.lang:type=Memory HeapMemoryUsage\r\n"); - } - } catch (Exception e) { - logger.error("process cmd failed: {}", Arrays.asList(args), e); + return output.toString(); } - return output.toString(); - } - public static Map toMap(CompositeData cd) { - if (cd == null) - throw new IllegalArgumentException("composite data should not be null"); - Map map = new HashMap(); - Set itemNames = cd.getCompositeType().keySet(); - for (String itemName : itemNames) { - Object item = cd.get(itemName); - map.put(itemName, item); + public static Map toMap(CompositeData cd) { + if (cd == null) + throw new IllegalArgumentException("composite data should not be null"); + Map map = new HashMap(); + Set itemNames = cd.getCompositeType().keySet(); + for (String itemName : itemNames) { + Object item = cd.get(itemName); + map.put(itemName, item); + } + return map; } - return map; - } } diff --git a/src/main/java/com/example/sshd/service/MessageSender.java b/src/main/java/com/example/sshd/service/MessageSender.java index 697d7f2..7aef3f3 100644 --- a/src/main/java/com/example/sshd/service/MessageSender.java +++ b/src/main/java/com/example/sshd/service/MessageSender.java @@ -4,36 +4,36 @@ import org.springframework.beans.factory.annotation.Autowired; public class MessageSender { - @Autowired - EchoComponent echoComponent; - - private String fromJID, toJID, message; - - public void sendMessage() { - echoComponent.sendMessage(fromJID, toJID, message); - } - - public String getFromJID() { - return fromJID; - } - - public void setFromJID(String fromJID) { - this.fromJID = fromJID; - } - - public String getToJID() { - return toJID; - } - - public void setToJID(String toJID) { - this.toJID = toJID; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } + @Autowired + EchoComponent echoComponent; + + private String fromJID, toJID, message; + + public void sendMessage() { + echoComponent.sendMessage(fromJID, toJID, message); + } + + public String getFromJID() { + return fromJID; + } + + public void setFromJID(String fromJID) { + this.fromJID = fromJID; + } + + public String getToJID() { + return toJID; + } + + public void setToJID(String toJID) { + this.toJID = toJID; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } } diff --git a/src/main/java/com/example/sshd/service/ReplyService.java b/src/main/java/com/example/sshd/service/ReplyService.java index dfebcc4..1f7c38b 100644 --- a/src/main/java/com/example/sshd/service/ReplyService.java +++ b/src/main/java/com/example/sshd/service/ReplyService.java @@ -25,126 +25,126 @@ import org.springframework.stereotype.Service; @Service public class ReplyService { - private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); - private static final Logger notFoundLogger = LoggerFactory.getLogger("not_found"); - - @Autowired - Properties hashReplies; - - @Autowired - Properties regexMapping; - - @Autowired - Map ipInfoMapping; - - @Autowired - JdbcService jdbcService; - - @Autowired - GeoIpLocator geoIpLocator; - - @Autowired - JmxClientService jmxClientService; - - public boolean replyToCommand(String command, OutputStream out, String prompt, ServerSession session) - throws IOException { - - String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase(); - if (StringUtils.equalsIgnoreCase(command.trim(), "my_geolocation")) { - logger.info("[{}] my_geolocation command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.get(Thread.currentThread().getName()), prompt) - .getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "whoami")) { - logger.info("[{}] whoami command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", session.getUsername(), prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "online_geolocations")) { - logger.info("[{}] online_geolocations command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.toString(), prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "jmx_client")) { - String remoteJmxResponse = jmxClientService.process(StringUtils.split(command.trim(), " ")); - logger.info("[{}] jmx_client command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", remoteJmxResponse, prompt).getBytes()); - - } else if (StringUtils.split(command.trim(), " ").length == 2 - && StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "get_geolocation")) { - String remoteIpInfo = StringUtils.getIfBlank( - jdbcService.getRemoteIpInfo(StringUtils.split(command.trim(), " ")[1]), - () -> geoIpLocator.getIpLocationInfo(StringUtils.split(command.trim(), " ")[1])); - logger.info("[{}] get_geolocation command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", remoteIpInfo, prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "all_geolocations")) { - logger.info("[{}] all_geolocations command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", jdbcService.getAllRemoteIpInfo(), prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "exit") - || StringUtils.equalsIgnoreCase(command.trim(), "quit")) { - logger.info("[{}] Exiting command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\nExiting...\r\n%s", prompt).getBytes()); - return true; - - } else if (hashReplies.containsKey(command.trim())) { - logger.info("[{}] Known command detected: {}", cmdHash, command.trim()); - String reply = hashReplies.getProperty(command.trim()).replace("\\r", "\r").replace("\\n", "\n") - .replace("\\t", "\t"); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - - } else if (hashReplies.containsKey(cmdHash)) { - logger.info("[{}] Known command-hash detected: {}", cmdHash, command.trim()); - String reply = hashReplies.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n").replace("\\t", - "\t"); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - - } else if (hashReplies.containsKey(String.format("base64(%s)", cmdHash))) { - logger.info("[{}] Known base64-hash detected: {}", cmdHash, command.trim()); - String reply = hashReplies.getProperty(String.format("base64(%s)", cmdHash)); - reply = new String(Base64.decodeBase64(reply)); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - - } else { - Optional> o = regexMapping.entrySet().stream() - .filter(e -> command.trim().matches(((String) e.getKey()))) - .map(e -> Pair.of((String) e.getKey(), (String) e.getValue())).findAny(); - if (o.isPresent()) { - String reply = hashReplies.getProperty(o.get().getRight(), "").replace("\\r", "\r").replace("\\n", "\n") - .replace("\\t", "\t"); - if (reply.isEmpty()) { - reply = executeShellCommand(command.trim()); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); + private static final Logger notFoundLogger = LoggerFactory.getLogger("not_found"); + + @Autowired + Properties hashReplies; + + @Autowired + Properties regexMapping; + + @Autowired + Map ipInfoMapping; + + @Autowired + JdbcService jdbcService; + + @Autowired + GeoIpLocator geoIpLocator; + + @Autowired + JmxClientService jmxClientService; + + public boolean replyToCommand(String command, OutputStream out, String prompt, ServerSession session) + throws IOException { + + String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase(); + if (StringUtils.equalsIgnoreCase(command.trim(), "my_geolocation")) { + logger.info("[{}] my_geolocation command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.get(Thread.currentThread().getName()), prompt) + .getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "whoami")) { + logger.info("[{}] whoami command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", session.getUsername(), prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "online_geolocations")) { + logger.info("[{}] online_geolocations command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.toString(), prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "jmx_client")) { + String remoteJmxResponse = jmxClientService.process(StringUtils.split(command.trim(), " ")); + logger.info("[{}] jmx_client command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", remoteJmxResponse, prompt).getBytes()); + + } else if (StringUtils.split(command.trim(), " ").length == 2 + && StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "get_geolocation")) { + String remoteIpInfo = StringUtils.getIfBlank( + jdbcService.getRemoteIpInfo(StringUtils.split(command.trim(), " ")[1]), + () -> geoIpLocator.getIpLocationInfo(StringUtils.split(command.trim(), " ")[1])); + logger.info("[{}] get_geolocation command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", remoteIpInfo, prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "all_geolocations")) { + logger.info("[{}] all_geolocations command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", jdbcService.getAllRemoteIpInfo(), prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "exit") + || StringUtils.equalsIgnoreCase(command.trim(), "quit")) { + logger.info("[{}] Exiting command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\nExiting...\r\n%s", prompt).getBytes()); + return true; + + } else if (hashReplies.containsKey(command.trim())) { + logger.info("[{}] Known command detected: {}", cmdHash, command.trim()); + String reply = hashReplies.getProperty(command.trim()).replace("\\r", "\r").replace("\\n", "\n") + .replace("\\t", "\t"); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + + } else if (hashReplies.containsKey(cmdHash)) { + logger.info("[{}] Known command-hash detected: {}", cmdHash, command.trim()); + String reply = hashReplies.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n").replace("\\t", + "\t"); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + + } else if (hashReplies.containsKey(String.format("base64(%s)", cmdHash))) { + logger.info("[{}] Known base64-hash detected: {}", cmdHash, command.trim()); + String reply = hashReplies.getProperty(String.format("base64(%s)", cmdHash)); + reply = new String(Base64.decodeBase64(reply)); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + } else { - logger.info("[{}] Known pattern detected: {} ({})", cmdHash, command.trim(), o.get()); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + Optional> o = regexMapping.entrySet().stream() + .filter(e -> command.trim().matches(((String) e.getKey()))) + .map(e -> Pair.of((String) e.getKey(), (String) e.getValue())).findAny(); + if (o.isPresent()) { + String reply = hashReplies.getProperty(o.get().getRight(), "").replace("\\r", "\r").replace("\\n", "\n") + .replace("\\t", "\t"); + if (reply.isEmpty()) { + reply = executeShellCommand(command.trim()); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + } else { + logger.info("[{}] Known pattern detected: {} ({})", cmdHash, command.trim(), o.get()); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + } + } else { + logger.info("[{}] Command not found: {}", cmdHash, command.trim()); + notFoundLogger.info("[{}] Command not found: {}", cmdHash, command.trim()); + out.write(String.format("\r\nCommand '%s' not found. Try 'exit'.\r\n%s", command.trim(), prompt) + .getBytes()); + } } - } else { - logger.info("[{}] Command not found: {}", cmdHash, command.trim()); - notFoundLogger.info("[{}] Command not found: {}", cmdHash, command.trim()); - out.write(String.format("\r\nCommand '%s' not found. Try 'exit'.\r\n%s", command.trim(), prompt) - .getBytes()); - } + return false; } - return false; - } - - public String executeShellCommand(String command) { - String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase(); - logger.info("[{}] Execute cmd for real: {}", cmdHash, command.trim()); - ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); - try { - CommandLine cmdLine = CommandLine.parse(command.trim()); - DefaultExecutor executor = DefaultExecutor.builder().get(); - PumpStreamHandler streamHandler = new PumpStreamHandler(tempOut); - executor.setStreamHandler(streamHandler); - int exitValue = executor.execute(cmdLine); - logger.info("[{}] Result: {} ({})", cmdHash, command.trim(), exitValue); - return new String(tempOut.toByteArray()).replace("\n", "\r\n"); - } catch (ExecuteException e) { - logger.info("[{}] Execute cmd failed: {}", cmdHash, command.trim(), e); - } catch (IOException e) { - logger.info("[{}] Execute cmd failed: {}", cmdHash, command.trim(), e); + + public String executeShellCommand(String command) { + String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase(); + logger.info("[{}] Execute cmd for real: {}", cmdHash, command.trim()); + ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); + try { + CommandLine cmdLine = CommandLine.parse(command.trim()); + DefaultExecutor executor = DefaultExecutor.builder().get(); + PumpStreamHandler streamHandler = new PumpStreamHandler(tempOut); + executor.setStreamHandler(streamHandler); + int exitValue = executor.execute(cmdLine); + logger.info("[{}] Result: {} ({})", cmdHash, command.trim(), exitValue); + return new String(tempOut.toByteArray()).replace("\n", "\r\n"); + } catch (ExecuteException e) { + logger.info("[{}] Execute cmd failed: {}", cmdHash, command.trim(), e); + } catch (IOException e) { + logger.info("[{}] Execute cmd failed: {}", cmdHash, command.trim(), e); + } + return null; } - return null; - } }