summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Wagenknecht2012-03-03 08:12:16 (EST)
committer Lazar Kirchev2012-03-03 08:14:08 (EST)
commitf8ceac0dbadd22dc7e587d0bc1cb0505e9fc4a93 (patch)
treed546501161ea42c398071540ae940582f9d784b5
parent7dcad19d3d9008f024ed6c247b67675ca56f3c7c (diff)
downloadrt.equinox.bundles-f8ceac0dbadd22dc7e587d0bc1cb0505e9fc4a93.zip
rt.equinox.bundles-f8ceac0dbadd22dc7e587d0bc1cb0505e9fc4a93.tar.gz
rt.equinox.bundles-f8ceac0dbadd22dc7e587d0bc1cb0505e9fc4a93.tar.bz2
Bug 366188 - Add support for 'authorized_keys' file to SSH consolev20120303-1314
allow custom public key authentication by using OSGi services Any bundle (with sufficient permission) may provide an authenticator by registering an OSGi service. If no specific authorized_keys file is configured (via system property) the OSGi service registry will be searched for available authenticators. The authorized_keys file authenticator is now a separate class.
-rw-r--r--bundles/org.eclipse.equinox.console.ssh/META-INF/MANIFEST.MF5
-rw-r--r--bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeysFileAuthenticator.java80
-rw-r--r--bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/ssh/SshServ.java68
3 files changed, 115 insertions, 38 deletions
diff --git a/bundles/org.eclipse.equinox.console.ssh/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.console.ssh/META-INF/MANIFEST.MF
index 9de3d86..ebd036d 100644
--- a/bundles/org.eclipse.equinox.console.ssh/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.console.ssh/META-INF/MANIFEST.MF
@@ -26,4 +26,7 @@ Import-Package: javax.security.auth;resolution:=optional,
org.osgi.framework;version="1.7.0",
org.osgi.service.cm;resolution:=optional,
org.osgi.util.tracker
-Export-Package: org.eclipse.equinox.console.jaas
+Export-Package: org.eclipse.equinox.console.internal.ssh;x-internal:=true,
+ org.eclipse.equinox.console.jaas,
+ org.eclipse.equinox.console.ssh;x-internal:=true,
+ org.eclipse.equinox.console.storage;x-internal:=true
diff --git a/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeysFileAuthenticator.java b/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeysFileAuthenticator.java
new file mode 100644
index 0000000..5abd2be
--- /dev/null
+++ b/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeysFileAuthenticator.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2012 Gunnar Wagenknecht and others.
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v1.0 which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Gunnar Wagenknecht - initial API and implementation
+ */
+package org.eclipse.equinox.console.internal.ssh;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+
+import org.apache.sshd.server.PublickeyAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * {@link PublickeyAuthenticator} which authenticates using a specified
+ * {@link #setAuthorizedKeysFile(String) authorized_keys} file.
+ */
+public class AuthorizedKeysFileAuthenticator implements PublickeyAuthenticator {
+ private String authorizedKeysFile;
+
+ public String getAuthorizedKeysFile() {
+ return authorizedKeysFile;
+ }
+
+ public void setAuthorizedKeysFile(String authorizedKeysFile) {
+ this.authorizedKeysFile = authorizedKeysFile;
+ }
+
+ public boolean authenticate(String username, PublicKey key, ServerSession session) {
+ String authorizedKeysFile = getAuthorizedKeysFile();
+ if(null == authorizedKeysFile) {
+ // TODO should use better logging than System.err?
+ System.err.println("No authorized_keys file configured!");
+ return false;
+ }
+ try {
+ // dynamically read key file at each login attempt
+ AuthorizedKeys keys = new AuthorizedKeys(authorizedKeysFile);
+ for (PublicKey authorizedKey : keys.getKeys()) {
+ if (isSameKey(authorizedKey, key)) {
+ return true;
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // TODO should use better logging than System.err?
+ System.err.println("Configured authorized_keys file not found! " + e.getMessage());
+ } catch (IOException e) {
+ // TODO should use better logging than System.err?
+ System.err.println("Please check authorized_keys file! " + e.getMessage());
+ }
+ return false;
+ }
+
+ private boolean isSameKey(PublicKey k1, PublicKey k2) throws IOException {
+ if ((k1 instanceof DSAPublicKey) && (k2 instanceof DSAPublicKey)) {
+ return isSameDSAKey((DSAPublicKey) k1, (DSAPublicKey) k2);
+ } else if ((k1 instanceof RSAPublicKey) && (k2 instanceof RSAPublicKey)) {
+ return isSameRSAKey((RSAPublicKey) k1, (RSAPublicKey) k2);
+ } else {
+ throw new IOException("Unsupported key types detected!");
+ }
+ }
+
+ private boolean isSameRSAKey(RSAPublicKey k1, RSAPublicKey k2) {
+ return k1.getPublicExponent().equals(k2.getPublicExponent()) && k1.getModulus().equals(k2.getModulus());
+ }
+
+ private boolean isSameDSAKey(DSAPublicKey k1, DSAPublicKey k2) {
+ return k1.getY().equals(k2.getY()) && k1.getParams().getG().equals(k2.getParams().getG()) && k1.getParams().getP().equals(k2.getParams().getP()) && k1.getParams().getQ().equals(k2.getParams().getQ());
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/ssh/SshServ.java b/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/ssh/SshServ.java
index 0927651..696cb8d 100644
--- a/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/ssh/SshServ.java
+++ b/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/ssh/SshServ.java
@@ -11,16 +11,15 @@
package org.eclipse.equinox.console.ssh;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.PublicKey;
-import java.security.interfaces.DSAPublicKey;
-import java.security.interfaces.RSAPublicKey;
import java.util.List;
-import org.eclipse.equinox.console.internal.ssh.AuthorizedKeys;
+import org.eclipse.equinox.console.internal.ssh.AuthorizedKeysFileAuthenticator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
import org.apache.felix.service.command.CommandProcessor;
import org.apache.sshd.SshServer;
@@ -35,8 +34,10 @@ import org.apache.sshd.server.session.ServerSession;
*
*/
public class SshServ extends Thread {
- private int port;
- private String host;
+
+ private final BundleContext context;
+ private final int port;
+ private final String host;
private SshServer sshServer = null;
private SshShellFactory shellFactory = null;
@@ -46,7 +47,8 @@ public class SshServ extends Thread {
private static final String EQUINOX_CONSOLE_DOMAIN = "equinox_console";
public SshServ(List<CommandProcessor> processors, BundleContext context, String host, int port) {
- this.host = host;
+ this.context = context;
+ this.host = host;
this.port = port;
shellFactory = new SshShellFactory(processors, context);
}
@@ -92,46 +94,38 @@ public class SshServ extends Thread {
}
private PublickeyAuthenticator createSimpleAuthorizedKeysAuthenticator() {
- // check if property is set
+ // use authorized keys file if property is set
final String authorizedKeysFile = System.getProperty(SSH_AUTHORIZED_KEYS_FILE_PROP);
- if (null == authorizedKeysFile)
- return null;
+ if (null != authorizedKeysFile) {
+ AuthorizedKeysFileAuthenticator authenticator = new AuthorizedKeysFileAuthenticator();
+ authenticator.setAuthorizedKeysFile(authorizedKeysFile);
+ return authenticator;
+ }
- // dynamically read key file at each login attempt
+ // fall back to dynamic provider based on available OSGi services
return new PublickeyAuthenticator() {
+
+ @Override
public boolean authenticate(String username, PublicKey key, ServerSession session) {
+ // find available services
try {
- AuthorizedKeys keys = new AuthorizedKeys(authorizedKeysFile);
- for (PublicKey authorizedKey : keys.getKeys()) {
- if (isSameKey(authorizedKey, key)) {
- return true;
+ 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 (FileNotFoundException e) {
- System.err.println("Configured authorized_keys file not found! " + e.getMessage());
- } catch (IOException e) {
- System.err.println("Please check authorized_keys file! " + e.getMessage());
+ } catch (InvalidSyntaxException e) {
+ // no filter is used
}
return false;
}
-
- private boolean isSameKey(PublicKey k1, PublicKey k2) throws IOException {
- if ((k1 instanceof DSAPublicKey) && (k2 instanceof DSAPublicKey)) {
- return isSameDSAKey((DSAPublicKey) k1, (DSAPublicKey) k2);
- } else if ((k1 instanceof RSAPublicKey) && (k2 instanceof RSAPublicKey)) {
- return isSameRSAKey((RSAPublicKey) k1, (RSAPublicKey) k2);
- } else {
- throw new IOException("Unsupported key types detected!");
- }
- }
-
- private boolean isSameRSAKey(RSAPublicKey k1, RSAPublicKey k2) {
- return k1.getPublicExponent().equals(k2.getPublicExponent()) && k1.getModulus().equals(k2.getModulus());
- }
-
- private boolean isSameDSAKey(DSAPublicKey k1, DSAPublicKey k2) {
- return k1.getY().equals(k2.getY()) && k1.getParams().getG().equals(k2.getParams().getG()) && k1.getParams().getP().equals(k2.getParams().getP()) && k1.getParams().getQ().equals(k2.getParams().getQ());
- }
};
}
}