You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2012/04/03 08:01:51 UTC
svn commit: r1308713 - in /karaf/trunk/shell/ssh/src:
main/java/org/apache/karaf/shell/ssh/ main/resources/OSGI-INF/blueprint/
test/ test/java/ test/java/org/ test/java/org/apache/
test/java/org/apache/karaf/ test/java/org/apache/karaf/shell/ test/java...
Author: jbonofre
Date: Tue Apr 3 06:01:50 2012
New Revision: 1308713
URL: http://svn.apache.org/viewvc?rev=1308713&view=rev
Log:
[KARAF-32] Add support of SSH key authentication
Added:
karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafPublickeyAuthenticator.java
karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java
karaf/trunk/shell/ssh/src/test/
karaf/trunk/shell/ssh/src/test/java/
karaf/trunk/shell/ssh/src/test/java/org/
karaf/trunk/shell/ssh/src/test/java/org/apache/
karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/
karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/shell/
karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/
karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/TestAuthorizedKeysParsing.java
karaf/trunk/shell/ssh/src/test/resources/
karaf/trunk/shell/ssh/src/test/resources/org/
karaf/trunk/shell/ssh/src/test/resources/org/apache/
karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/
karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/shell/
karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/shell/ssh/
karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/shell/ssh/authorized_keys
Modified:
karaf/trunk/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml
Added: karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafPublickeyAuthenticator.java
URL: http://svn.apache.org/viewvc/karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafPublickeyAuthenticator.java?rev=1308713&view=auto
==============================================================================
--- karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafPublickeyAuthenticator.java (added)
+++ karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafPublickeyAuthenticator.java Tue Apr 3 06:01:50 2012
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.ssh;
+
+import org.apache.mina.util.Base64;
+import org.apache.sshd.server.PublickeyAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.*;
+
+/**
+ * A public key authenticator, which reads an OpenSSL2 <code>authorized_keys</code> file.
+ */
+public class KarafPublickeyAuthenticator implements PublickeyAuthenticator {
+
+ private static final transient Logger LOGGER = LoggerFactory.getLogger(KarafPublickeyAuthenticator.class);
+
+ private String authorizedKeys;
+ private boolean active;
+
+ public static final class AuthorizedKey {
+
+ private final String alias;
+ private final String format;
+ private final PublicKey publicKey;
+
+ public AuthorizedKey(String alias, String format, PublicKey publicKey) {
+ super();
+ this.alias = alias;
+ this.format = format;
+ this.publicKey = publicKey;
+ }
+
+ public String getAlias() {
+ return this.alias;
+ }
+
+ public String getFormat() {
+ return this.format;
+ }
+
+ public PublicKey getPublicKey() {
+ return this.publicKey;
+ }
+
+ }
+
+ private static final class PublicKeyComparator implements Comparator<PublicKey> {
+
+ public int compare(PublicKey a, PublicKey b) {
+ if (a instanceof DSAPublicKey) {
+ if (b instanceof DSAPublicKey) {
+ DSAPublicKey da = (DSAPublicKey) a;
+ DSAPublicKey db = (DSAPublicKey) b;
+ int r = da.getParams().getG().compareTo(db.getParams().getG());
+ if (r != 0) {
+ return r;
+ }
+ r = da.getParams().getP().compareTo(db.getParams().getP());
+ if (r != 0) {
+ return r;
+ }
+ r = da.getParams().getQ().compareTo(db.getParams().getQ());
+ if (r != 0) {
+ return r;
+ }
+ return da.getY().compareTo(db.getY());
+ } else {
+ return -1;
+ }
+ } else if (a instanceof RSAPublicKey) {
+ if (b instanceof RSAPublicKey) {
+ RSAPublicKey da = (RSAPublicKey) a;
+ RSAPublicKey db = (RSAPublicKey) b;
+ int r = da.getPublicExponent().compareTo(db.getPublicExponent());
+ if (r != 0) {
+ return r;
+ }
+ return da.getModulus().compareTo(db.getModulus());
+ } else {
+ return -1;
+ }
+ } else {
+ throw new IllegalArgumentException("Only RSA and DAS keys are supported.");
+ }
+ }
+ }
+
+ private final class AuthorizedKeysProvider extends TimerTask {
+
+ private Map<PublicKey, AuthorizedKey> keys;
+ private Long lastModificationDate;
+ private Boolean fileAvailable;
+
+ @Override
+ public void run() {
+ try {
+ File af = new File(KarafPublickeyAuthenticator.this.authorizedKeys);
+ if (af.exists()) {
+ Long newModificationDate = Long.valueOf(af.lastModified());
+ if ((this.fileAvailable != null && !this.fileAvailable.booleanValue()) || !newModificationDate.equals(this.lastModificationDate)) {
+ LOGGER.info("Parsing authorized keys file {}...", KarafPublickeyAuthenticator.this.authorizedKeys);
+ this.fileAvailable = Boolean.TRUE;
+ this.lastModificationDate = newModificationDate;
+ Map<PublicKey, AuthorizedKey> newKeys = KarafPublickeyAuthenticator.parseAuthorizedKeys(new FileInputStream(af));
+ this.setKeys(newKeys);
+ LOGGER.info("Successfully parsed {} keys from file {}", newKeys.size(), KarafPublickeyAuthenticator.this.authorizedKeys);
+ }
+ } else {
+ if (this.fileAvailable != null && this.fileAvailable.booleanValue()) {
+ LOGGER.info("Authorized keys file {} disappeared, will recheck every minute", KarafPublickeyAuthenticator.this.authorizedKeys);
+ } else if (this.fileAvailable == null) {
+ LOGGER.info("Authorized keys file {} does not exist, will recheck every minute", KarafPublickeyAuthenticator.this.authorizedKeys);
+ }
+ this.fileAvailable = Boolean.FALSE;
+ this.lastModificationDate = null;
+ this.setKeys(null);
+ }
+ } catch (Throwable e) {
+ LOGGER.error("Error parsing authorized keys file {}", KarafPublickeyAuthenticator.this.authorizedKeys, e);
+ this.fileAvailable = Boolean.FALSE;
+ this.lastModificationDate = null;
+ this.setKeys(null);
+ }
+ }
+
+ private synchronized void setKeys(Map<PublicKey, AuthorizedKey> keys) {
+ this.keys = keys;
+ }
+
+ public synchronized AuthorizedKey getKey(PublicKey publicKey) {
+ if (this.keys == null) {
+ return null;
+ }
+ return this.keys.get(publicKey);
+ }
+
+ }
+
+ private Timer parseAuthorizedKeysTimer;
+ private AuthorizedKeysProvider authorizedKeysProvider;
+
+ private static final int getInt(byte[] b, int pos) {
+ return (((int) b[pos] & 0xff) << 24) +
+ (((int) b[pos+1] & 0xff) << 16) +
+ (((int) b[pos+2] & 0xff) << 8) +
+ ((int) b[pos+3] & 0xff);
+ }
+
+ /**
+ * Parse an <code>authorized_keys</code> file in OpenSSH style.
+ *
+ * @param is the input stream to read.
+ * @return a map of authorized public keys.
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeySpecException
+ */
+ public static final Map<PublicKey, AuthorizedKey> parseAuthorizedKeys(InputStream is) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ try {
+ Base64 decoder = new Base64();
+
+ KeyFactory rsaKeyGen = KeyFactory.getInstance("RSA");
+ KeyFactory dsaKeyGen = KeyFactory.getInstance("DSA");
+
+ LineNumberReader reader = new LineNumberReader(new InputStreamReader(is, "UTF-8"));
+
+ Map<PublicKey, AuthorizedKey> ret = new TreeMap<PublicKey, AuthorizedKey>(new PublicKeyComparator());
+
+ String line;
+
+ while ((line = reader.readLine()) != null) {
+ String[] tokens = line.split("[ \\t]+", 3);
+ if (tokens.length != 3) {
+ throw new IOException("Authorized keys file line " + reader.getLineNumber() + " does not contain 3 tokens.");
+ }
+ byte[] rawKey = decoder.decode(tokens[1].getBytes("UTF-8"));
+ if (getInt(rawKey, 0) != 7 || !new String(rawKey, 4, 7, "UTF-8").equals(tokens[0])) {
+ throw new IOException("Authorized keys file line " + reader.getLineNumber() + " contains a key with a format that does not match the first token.");
+ }
+ PublicKey pk;
+ if (tokens[0].equals("ssh-dss")) {
+ int pos = 11;
+
+ int n = getInt(rawKey, pos);
+ pos += 4;
+ BigInteger p = new BigInteger(1, Arrays.copyOfRange(rawKey, pos, pos + n));
+ pos += n;
+
+ n = getInt(rawKey, pos);
+ pos += 4;
+ BigInteger q = new BigInteger(1, Arrays.copyOfRange(rawKey, pos, pos + n));
+ pos += n;
+
+ n = getInt(rawKey, pos);
+ pos += 4;
+ BigInteger g = new BigInteger(1, Arrays.copyOfRange(rawKey, pos, pos + n));
+ pos += n;
+
+ n = getInt(rawKey, pos);
+ pos += 4;
+ BigInteger y = new BigInteger(1, Arrays.copyOfRange(rawKey, pos, pos + n));
+ pos += n;
+
+ if (pos != rawKey.length) {
+ throw new IOException("Authorized keys file line " + reader.getLineNumber() + " contains a DSA key with extra garbage.");
+ }
+
+ DSAPublicKeySpec ps = new DSAPublicKeySpec(y, p, q, g);
+ pk = dsaKeyGen.generatePublic(ps);
+ } else if (tokens[0].equals("ssh-rsa")) {
+ int pos = 11;
+
+ int n = getInt(rawKey, pos);
+ pos += 4;
+ BigInteger e = new BigInteger(1, Arrays.copyOfRange(rawKey, pos, pos + n));
+ pos += n;
+
+ n = getInt(rawKey, pos);
+ pos += 4;
+ BigInteger modulus = new BigInteger(1, Arrays.copyOfRange(rawKey, pos, pos + n));
+ pos += n;
+
+ if (pos != rawKey.length) {
+ throw new IOException("Authorized keys file line " + reader.getLineNumber() + " contains a RSA key with extra garbage.");
+ }
+
+ RSAPublicKeySpec ps = new RSAPublicKeySpec(modulus, e);
+ pk = rsaKeyGen.generatePublic(ps);
+ } else {
+ throw new IOException("Authorized keys file line " + reader.getLineNumber() + " does not start with ssh-dss or ssh-rsa.");
+ }
+
+ ret.put(pk, new AuthorizedKey(tokens[2], tokens[0], pk));
+ }
+ return ret;
+ } finally {
+ is.close();
+ }
+ }
+
+ public boolean authenticate(String username, PublicKey publicKey, ServerSession session) {
+ AuthorizedKey ak = this.authorizedKeysProvider.getKey(publicKey);
+ if (ak == null) {
+ LOGGER.error("Failed authenticate of user {} from {} with unknown public key.", username, session.getIoSession().getRemoteAddress());
+ return false;
+ }
+ LOGGER.info("Successful authentication of user {} from {} with public key {}.", new Object[]{ username, session.getIoSession().getRemoteAddress(), ak.getAlias() });
+ return true;
+ }
+
+ public void setAuthorizedKeys(String path) {
+ this.authorizedKeys = path;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+
+ public void startTimer() {
+ if (this.active) {
+ this.parseAuthorizedKeysTimer = new Timer();
+ this.authorizedKeysProvider = new AuthorizedKeysProvider();
+ this.parseAuthorizedKeysTimer.schedule(this.authorizedKeysProvider, 10, 60000L);
+ }
+ }
+
+ public void stopTimer() {
+ if (this.parseAuthorizedKeysTimer != null) {
+ this.parseAuthorizedKeysTimer.cancel();
+ this.parseAuthorizedKeysTimer = null;
+ }
+ }
+
+}
Added: karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java
URL: http://svn.apache.org/viewvc/karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java?rev=1308713&view=auto
==============================================================================
--- karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java (added)
+++ karaf/trunk/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java Tue Apr 3 06:01:50 2012
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.ssh;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.server.UserAuth;
+import org.apache.sshd.server.auth.UserAuthPassword;
+import org.apache.sshd.server.auth.UserAuthPublicKey;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.container.Converter;
+import org.osgi.service.blueprint.container.ReifiedType;
+
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * <p>A factory for user authentication factories to set on
+ * {@link SshServer#setUserAuthFactories(java.util.List)} based on a
+ * comma-separated list of authentication methods.</p>
+ *
+ * <p>Currently, the following methods are supported:</p>
+ * <ul>
+ * <li><code>password</code>
+ * Password authentication against a given JAAS domain.</p></li>
+ * <li><code>publickey</code>
+ * Public key authentication against an OpenSSH <code>authorized_keys</code> file.</p></li>
+ * </ul>
+ * </p>
+ */
+public class UserAuthFactoriesFactory {
+
+ public static final String PASSWORD_METHOD = "password";
+ public static final String PUBLICKEY_METHOD = "publickey";
+
+ private Set<String> methodSet;
+ private List<NamedFactory<UserAuth>> factories;
+
+ public static Converter getConverter() {
+ return new Converter();
+ }
+
+ /**
+ * This blueprint type converter silently converts instances of
+ * <code>Class X implements NameFactory</code>
+ * to the reified type <code>cNameFactory</code>
+ * and therefore helps blueprint to set the returned factories on
+ * {@link SshServerAction#setUserAuthFactories(List)} without complaining
+ * about type conversion errors.
+ */
+ public static class Converter implements org.osgi.service.blueprint.container.Converter {
+
+ public boolean canConvert(Object sourceObject, ReifiedType targetType) {
+ return NamedFactory.class.isAssignableFrom(sourceObject.getClass())
+ && UserAuth.class.equals(((ParameterizedType) sourceObject.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0])
+ && NamedFactory.class.equals(targetType.getRawClass())
+ && UserAuth.class.equals(targetType.getActualTypeArgument(0).getRawClass());
+ }
+
+ public Object convert(Object sourceObject, ReifiedType targetType) throws Exception {
+ return sourceObject;
+ }
+
+ }
+
+ public void setAuthMethods(String methods) {
+ this.methodSet = new HashSet<String>();
+ this.factories = new ArrayList<NamedFactory<UserAuth>>();
+ String[] ams = methods.split(",");
+ for (String am : ams) {
+ if (PASSWORD_METHOD.equals(am)) {
+ this.factories.add(new UserAuthPassword.Factory());
+ } else if (PUBLICKEY_METHOD.equals(am)) {
+ this.factories.add(new UserAuthPublicKey.Factory());
+ } else {
+ throw new ComponentDefinitionException("Invalid authentication method " + am + " specified");
+ }
+ this.methodSet.add(am);
+ }
+ }
+
+ public List<NamedFactory<UserAuth>> getFactories() {
+ return factories;
+ }
+
+ public boolean isPublickeyEnabled() {
+ return this.methodSet.contains(PUBLICKEY_METHOD);
+ }
+
+ public boolean isPasswordEnabled() {
+ return this.methodSet.contains(PASSWORD_METHOD);
+ }
+
+}
Modified: karaf/trunk/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml?rev=1308713&r1=1308712&r2=1308713&view=diff
==============================================================================
--- karaf/trunk/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml (original)
+++ karaf/trunk/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml Tue Apr 3 06:01:50 2012
@@ -25,6 +25,7 @@
<type-converters>
<bean class="org.apache.karaf.shell.ssh.ShellFactoryImpl" factory-method="getConverter" />
+ <bean class="org.apache.karaf.shell.ssh.UserAuthFactoriesFactory" factory-method="getConverter" />
</type-converters>
<ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]">
@@ -41,6 +42,8 @@
<cm:property name="sshRealm" value="karaf"/>
<cm:property name="sshRole" value="$[karaf.admin.role]"/>
<cm:property name="hostKey" value="${karaf.base}/etc/host.key"/>
+ <cm:property name="authorizedKeys" value="${karaf.base}/etc/authorized_keys"/>
+ <cm:property name="authMethods" value="password,publickey"/>
</cm:default-properties>
</cm:property-placeholder>
@@ -64,6 +67,10 @@
<bean id="sshClient" class="org.apache.sshd.SshClient" factory-method="setUpDefaultClient" scope="prototype">
</bean>
+ <bean id="userAuthFactoriesFactory" class="org.apache.karaf.shell.ssh.UserAuthFactoriesFactory">
+ <property name="authMethods" value="${authMethods}"/>
+ </bean>
+
<bean id="sshServer" class="org.apache.sshd.SshServer" factory-method="setUpDefaultServer" scope="prototype">
<property name="port" value="${sshPort}"/>
<property name="host" value="${sshHost}"/>
@@ -83,9 +90,13 @@
</property>
<property name="keyPairProvider" ref="keyPairProvider"/>
<property name="passwordAuthenticator" ref="passwordAuthenticator"/>
+ <property name="publickeyAuthenticator" ref="publickeyAuthenticator"/>
<property name="fileSystemFactory">
<bean class="org.apache.karaf.shell.ssh.KarafFileSystemFactory"/>
</property>
+ <property name="userAuthFactories">
+ <bean factory-ref="userAuthFactoriesFactory" factory-method="getFactories"/>
+ </property>
</bean>
<bean id="keyPairProvider" class="org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider">
@@ -96,6 +107,14 @@
<property name="role" value="${sshRole}"/>
</bean>
+ <bean id="publickeyAuthenticator" class="org.apache.karaf.shell.ssh.KarafPublickeyAuthenticator"
+ init-method="startTimer" destroy-method="stopTimer">
+ <property name="authorizedKeys" value="${authorizedKeys}"/>
+ <property name="active">
+ <bean factory-ref="userAuthFactoriesFactory" factory-method="isPublickeyEnabled"/>
+ </property>
+ </bean>
+
<bean id="sshServerFactory" class="org.apache.karaf.shell.ssh.SshServerFactory" init-method="start"
destroy-method="stop" activation="eager">
<argument ref="sshServer"/>
Added: karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/TestAuthorizedKeysParsing.java
URL: http://svn.apache.org/viewvc/karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/TestAuthorizedKeysParsing.java?rev=1308713&view=auto
==============================================================================
--- karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/TestAuthorizedKeysParsing.java (added)
+++ karaf/trunk/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/TestAuthorizedKeysParsing.java Tue Apr 3 06:01:50 2012
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.ssh;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Map;
+
+/**
+ * Test parsing an authorized_keys file.
+ */
+public class TestAuthorizedKeysParsing extends TestCase {
+
+ public void testAuthorizedKeysParsing() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
+ InputStream is = TestAuthorizedKeysParsing.class.getClassLoader().getResourceAsStream("org/apache/karaf/shell/ssh/authorized_keys");
+ Map<PublicKey, KarafPublickeyAuthenticator.AuthorizedKey> keys = KarafPublickeyAuthenticator.parseAuthorizedKeys(is);
+ assertEquals(2, keys.size());
+ for (Map.Entry<PublicKey, KarafPublickeyAuthenticator.AuthorizedKey> e : keys.entrySet()) {
+ assertSame(e.getKey(), e.getValue().getPublicKey());
+ assertTrue("ssh-dss".equals(e.getValue().getFormat()) || "ssh-rsa".equals(e.getValue().getFormat()));
+
+ if ("ssh-dss".equals(e.getValue().getFormat())) {
+ assertTrue(e.getKey() instanceof DSAPublicKey);
+ assertEquals("dsa-test", e.getValue().getAlias());
+ }
+ if ("ssh-rsa".equals(e.getValue().getFormat())) {
+ assertTrue(e.getKey() instanceof RSAPublicKey);
+ assertEquals("rsa-test", e.getValue().getAlias());
+ }
+ }
+ }
+
+}
Added: karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/shell/ssh/authorized_keys
URL: http://svn.apache.org/viewvc/karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/shell/ssh/authorized_keys?rev=1308713&view=auto
==============================================================================
--- karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/shell/ssh/authorized_keys (added)
+++ karaf/trunk/shell/ssh/src/test/resources/org/apache/karaf/shell/ssh/authorized_keys Tue Apr 3 06:01:50 2012
@@ -0,0 +1,2 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dsa-test
+ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRbYYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= rsa-test
\ No newline at end of file