diff options
Diffstat (limited to 'java/com/google/gerrit/sshd/SshUtil.java')
-rw-r--r-- | java/com/google/gerrit/sshd/SshUtil.java | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/java/com/google/gerrit/sshd/SshUtil.java b/java/com/google/gerrit/sshd/SshUtil.java new file mode 100644 index 0000000000..ce354224b5 --- /dev/null +++ b/java/com/google/gerrit/sshd/SshUtil.java @@ -0,0 +1,162 @@ +// Copyright (C) 2008 The Android Open Source Project +// +// Licensed 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 com.google.gerrit.sshd; + +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.account.AccountSshKey; +import com.google.gerrit.sshd.SshScope.Context; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import org.apache.commons.codec.binary.Base64; +import org.apache.sshd.common.SshException; +import org.apache.sshd.common.future.CloseFuture; +import org.apache.sshd.common.future.SshFutureListener; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import org.apache.sshd.server.session.ServerSession; +import org.eclipse.jgit.lib.Constants; + +/** Utilities to support SSH operations. */ +public class SshUtil { + /** + * Parse a public key into its Java type. + * + * @param key the account key to parse. + * @return the valid public key object. + * @throws InvalidKeySpecException the key supplied is not a valid SSH key. + * @throws NoSuchAlgorithmException the JVM is missing the key algorithm. + * @throws NoSuchProviderException the JVM is missing the provider. + */ + public static PublicKey parse(AccountSshKey key) + throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException { + try { + final String s = key.encodedKey(); + if (s == null) { + throw new InvalidKeySpecException("No key string"); + } + final byte[] bin = Base64.decodeBase64(Constants.encodeASCII(s)); + return new ByteArrayBuffer(bin).getRawPublicKey(); + } catch (RuntimeException | SshException e) { + throw new InvalidKeySpecException("Cannot parse key", e); + } + } + + /** + * Convert an RFC 4716 style key to an OpenSSH style key. + * + * @param keyStr the key string to convert. + * @return {@code keyStr} if conversion failed; otherwise the converted key, in OpenSSH key + * format. + */ + public static String toOpenSshPublicKey(String keyStr) { + try { + final StringBuilder strBuf = new StringBuilder(); + final BufferedReader br = new BufferedReader(new StringReader(keyStr)); + String line = br.readLine(); // BEGIN SSH2 line... + if (line == null || !line.equals("---- BEGIN SSH2 PUBLIC KEY ----")) { + return keyStr; + } + + while ((line = br.readLine()) != null) { + if (line.indexOf(':') == -1) { + strBuf.append(line); + break; + } + } + + while ((line = br.readLine()) != null) { + if (line.startsWith("---- ")) { + break; + } + strBuf.append(line); + } + + final PublicKey key = + new ByteArrayBuffer(Base64.decodeBase64(Constants.encodeASCII(strBuf.toString()))) + .getRawPublicKey(); + if (key instanceof RSAPublicKey) { + strBuf.insert(0, KeyPairProvider.SSH_RSA + " "); + + } else if (key instanceof DSAPublicKey) { + strBuf.insert(0, KeyPairProvider.SSH_DSS + " "); + + } else { + return keyStr; + } + + strBuf.append(' '); + strBuf.append("converted-key"); + return strBuf.toString(); + } catch (IOException | RuntimeException e) { + return keyStr; + } + } + + public static boolean success( + final String username, + final ServerSession session, + final SshScope sshScope, + final SshLog sshLog, + final SshSession sd, + final CurrentUser user) { + if (sd.getUser() == null) { + sd.authenticationSuccess(username, user); + + // If this is the first time we've authenticated this + // session, record a login event in the log and add + // a close listener to record a logout event. + // + Context ctx = sshScope.newContext(null, sd, null); + Context old = sshScope.set(ctx); + try { + sshLog.onLogin(); + } finally { + sshScope.set(old); + } + + session.addCloseFutureListener( + new SshFutureListener<CloseFuture>() { + @Override + public void operationComplete(CloseFuture future) { + final Context ctx = sshScope.newContext(null, sd, null); + final Context old = sshScope.set(ctx); + try { + sshLog.onLogout(); + } finally { + sshScope.set(old); + } + } + }); + } + + return true; + } + + public static IdentifiedUser createUser( + final SshSession sd, + final IdentifiedUser.GenericFactory userFactory, + final Account.Id account) { + return userFactory.create(sd.getRemoteAddress(), account); + } +} |