| /******************************************************************************* |
| * Copyright (c) 2011, 2018 SAP AG and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Lazar Kirchev, SAP AG - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.equinox.console.ssh; |
| |
| import java.io.IOException; |
| import java.nio.file.Paths; |
| import java.util.List; |
| |
| import org.apache.felix.service.command.CommandProcessor; |
| import org.apache.sshd.server.SshServer; |
| import org.apache.sshd.server.auth.password.PasswordAuthenticator; |
| import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator; |
| import org.apache.sshd.server.jaas.JaasPasswordAuthenticator; |
| import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; |
| import org.eclipse.equinox.console.internal.ssh.AuthorizedKeysFileAuthenticator; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| |
| /** |
| * This class configures and start an ssh server |
| * |
| */ |
| public class SshServ extends Thread { |
| |
| private final BundleContext context; |
| private final int port; |
| private final String host; |
| private SshServer sshServer = null; |
| private SshShellFactory shellFactory = null; |
| |
| private static final String SSH_KEYSTORE_PROP = "ssh.server.keystore"; |
| private static final String SSH_KEYSTORE_PROP_DEFAULT = "hostkey.ser"; |
| private static final String SSH_AUTHORIZED_KEYS_FILE_PROP = "ssh.server.authorized_keys"; |
| private static final String SSH_CUSTOM_PUBLIC_KEY_AUTHENTICATION = "ssh.custom.publickeys.auth"; |
| private static final String EQUINOX_CONSOLE_DOMAIN = "equinox_console"; |
| |
| public SshServ(List<CommandProcessor> processors, BundleContext context, String host, int port) { |
| this.context = context; |
| this.host = host; |
| this.port = port; |
| shellFactory = new SshShellFactory(processors, context); |
| } |
| |
| @Override |
| public void run() throws RuntimeException { |
| sshServer = SshServer.setUpDefaultServer(); |
| if (host != null) { |
| sshServer.setHost(host); |
| } |
| sshServer.setPort(port); |
| sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get(System.getProperty(SSH_KEYSTORE_PROP, SSH_KEYSTORE_PROP_DEFAULT)))); |
| sshServer.setShellFactory(shellFactory); |
| sshServer.setPasswordAuthenticator(createJaasPasswordAuthenticator()); |
| sshServer.setPublickeyAuthenticator(createSimpleAuthorizedKeysAuthenticator()); |
| try { |
| sshServer.start(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| |
| public synchronized void stopSshServer() { |
| try { |
| sshServer.stop(true); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| public synchronized void addCommandProcessor(CommandProcessor processor) { |
| shellFactory.addCommandProcessor(processor); |
| } |
| |
| public synchronized void removeCommandProcessor(CommandProcessor processor) { |
| shellFactory.removeCommandProcessor(processor); |
| } |
| |
| private PasswordAuthenticator createJaasPasswordAuthenticator() { |
| JaasPasswordAuthenticator jaasPasswordAuthenticator = new JaasPasswordAuthenticator(); |
| jaasPasswordAuthenticator.setDomain(EQUINOX_CONSOLE_DOMAIN); |
| return jaasPasswordAuthenticator; |
| } |
| |
| private PublickeyAuthenticator createSimpleAuthorizedKeysAuthenticator() { |
| // use authorized keys file if property is set |
| final String authorizedKeysFile = System.getProperty(SSH_AUTHORIZED_KEYS_FILE_PROP); |
| if (null != authorizedKeysFile) { |
| AuthorizedKeysFileAuthenticator authenticator = new AuthorizedKeysFileAuthenticator(); |
| authenticator.setAuthorizedKeysFile(authorizedKeysFile); |
| return authenticator; |
| } |
| |
| final String customPublicKeysAuthentication = System.getProperty(SSH_CUSTOM_PUBLIC_KEY_AUTHENTICATION); |
| |
| // fall back to dynamic provider based on available OSGi services only if explicitly specified |
| if ("true".equals(customPublicKeysAuthentication)) { |
| return (username, key, session) -> { |
| // find available services |
| try { |
| for (ServiceReference<PublickeyAuthenticator> reference : context.getServiceReferences(PublickeyAuthenticator.class, null)) { |
| PublickeyAuthenticator authenticator = null; |
| try { |
| authenticator = context.getService(reference); |
| // first positive match wins; continue looking otherwise |
| if(authenticator.authenticate(username, key, session)) |
| return true; |
| } finally { |
| if(null != authenticator) |
| context.ungetService(reference); |
| } |
| } |
| } catch (InvalidSyntaxException e) { |
| // no filter is used |
| } |
| return false; |
| }; |
| } |
| |
| return null; |
| } |
| } |