LCOV - code coverage report
Current view: top level - sshd - SshUtil.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 35 60 58.3 %
Date: 2022-11-19 15:00:39 Functions: 7 8 87.5 %

          Line data    Source code
       1             : // Copyright (C) 2008 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.sshd;
      16             : 
      17             : import com.google.common.io.BaseEncoding;
      18             : import com.google.gerrit.entities.Account;
      19             : import com.google.gerrit.server.CurrentUser;
      20             : import com.google.gerrit.server.IdentifiedUser;
      21             : import com.google.gerrit.server.account.AccountSshKey;
      22             : import com.google.gerrit.sshd.BaseCommand.Failure;
      23             : import com.google.gerrit.sshd.SshScope.Context;
      24             : import java.io.BufferedReader;
      25             : import java.io.IOException;
      26             : import java.io.StringReader;
      27             : import java.security.NoSuchAlgorithmException;
      28             : import java.security.NoSuchProviderException;
      29             : import java.security.PublicKey;
      30             : import java.security.interfaces.DSAPublicKey;
      31             : import java.security.interfaces.RSAPublicKey;
      32             : import java.security.spec.InvalidKeySpecException;
      33             : import org.apache.sshd.common.SshException;
      34             : import org.apache.sshd.common.io.IoAcceptor;
      35             : import org.apache.sshd.common.io.IoSession;
      36             : import org.apache.sshd.common.keyprovider.KeyPairProvider;
      37             : import org.apache.sshd.common.session.helpers.AbstractSession;
      38             : import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
      39             : import org.apache.sshd.server.session.ServerSession;
      40             : 
      41             : /** Utilities to support SSH operations. */
      42           0 : public class SshUtil {
      43             :   /**
      44             :    * Parse a public key into its Java type.
      45             :    *
      46             :    * @param key the account key to parse.
      47             :    * @return the valid public key object.
      48             :    * @throws InvalidKeySpecException the key supplied is not a valid SSH key.
      49             :    * @throws NoSuchAlgorithmException the JVM is missing the key algorithm.
      50             :    * @throws NoSuchProviderException the JVM is missing the provider.
      51             :    */
      52             :   public static PublicKey parse(AccountSshKey key)
      53             :       throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
      54             :     try {
      55          16 :       final String s = key.encodedKey();
      56          16 :       if (s == null) {
      57           0 :         throw new InvalidKeySpecException("No key string");
      58             :       }
      59          16 :       final byte[] bin = BaseEncoding.base64().decode(s);
      60          16 :       return new ByteArrayBuffer(bin).getRawPublicKey();
      61           0 :     } catch (RuntimeException | SshException e) {
      62           0 :       throw new InvalidKeySpecException("Cannot parse key", e);
      63             :     }
      64             :   }
      65             : 
      66             :   /**
      67             :    * Convert an RFC 4716 style key to an OpenSSH style key.
      68             :    *
      69             :    * @param keyStr the key string to convert.
      70             :    * @return {@code keyStr} if conversion failed; otherwise the converted key, in OpenSSH key
      71             :    *     format.
      72             :    */
      73             :   public static String toOpenSshPublicKey(String keyStr) {
      74             :     try {
      75          16 :       final StringBuilder strBuf = new StringBuilder();
      76          16 :       final BufferedReader br = new BufferedReader(new StringReader(keyStr));
      77          16 :       String line = br.readLine(); // BEGIN SSH2 line...
      78          16 :       if (line == null || !line.equals("---- BEGIN SSH2 PUBLIC KEY ----")) {
      79          16 :         return keyStr;
      80             :       }
      81             : 
      82           0 :       while ((line = br.readLine()) != null) {
      83           0 :         if (line.indexOf(':') == -1) {
      84           0 :           strBuf.append(line);
      85           0 :           break;
      86             :         }
      87             :       }
      88             : 
      89           0 :       while ((line = br.readLine()) != null) {
      90           0 :         if (line.startsWith("---- ")) {
      91           0 :           break;
      92             :         }
      93           0 :         strBuf.append(line);
      94             :       }
      95             : 
      96           0 :       final PublicKey key =
      97           0 :           new ByteArrayBuffer(BaseEncoding.base64().decode(strBuf.toString())).getRawPublicKey();
      98           0 :       if (key instanceof RSAPublicKey) {
      99           0 :         strBuf.insert(0, KeyPairProvider.SSH_RSA + " ");
     100             : 
     101           0 :       } else if (key instanceof DSAPublicKey) {
     102           0 :         strBuf.insert(0, KeyPairProvider.SSH_DSS + " ");
     103             : 
     104             :       } else {
     105           0 :         return keyStr;
     106             :       }
     107             : 
     108           0 :       strBuf.append(' ');
     109           0 :       strBuf.append("converted-key");
     110           0 :       return strBuf.toString();
     111           0 :     } catch (IOException | RuntimeException e) {
     112           0 :       return keyStr;
     113             :     }
     114             :   }
     115             : 
     116             :   public static boolean success(
     117             :       final String username,
     118             :       final ServerSession session,
     119             :       final SshScope sshScope,
     120             :       final SshLog sshLog,
     121             :       final SshSession sd,
     122             :       final CurrentUser user) {
     123          17 :     if (sd.getUser() == null) {
     124          17 :       sd.authenticationSuccess(username, user);
     125             : 
     126             :       // If this is the first time we've authenticated this
     127             :       // session, record a login event in the log and add
     128             :       // a close listener to record a logout event.
     129             :       //
     130          17 :       Context ctx = sshScope.newContext(sd, null);
     131          17 :       Context old = sshScope.set(ctx);
     132             :       try {
     133          17 :         sshLog.onLogin();
     134             :       } finally {
     135          17 :         sshScope.set(old);
     136             :       }
     137             : 
     138          17 :       session.addCloseFutureListener(
     139             :           future -> {
     140          17 :             final Context ctx1 = sshScope.newContext(sd, null);
     141          17 :             final Context old1 = sshScope.set(ctx1);
     142             :             try {
     143          17 :               sshLog.onLogout();
     144             :             } finally {
     145          17 :               sshScope.set(old1);
     146             :             }
     147          17 :           });
     148             :     }
     149             : 
     150          17 :     return true;
     151             :   }
     152             : 
     153             :   public static IdentifiedUser createUser(
     154             :       final SshSession sd,
     155             :       final IdentifiedUser.GenericFactory userFactory,
     156             :       final Account.Id account) {
     157          16 :     return userFactory.create(sd.getRemoteAddress(), account);
     158             :   }
     159             : 
     160             :   public static void forEachSshSession(SshDaemon sshDaemon, SessionConsumer consumer)
     161             :       throws Failure {
     162           1 :     IoAcceptor ioAcceptor = sshDaemon.getIoAcceptor();
     163           1 :     if (ioAcceptor == null) {
     164           0 :       throw new Failure(1, "fatal: sshd no longer running");
     165             :     }
     166           1 :     ioAcceptor
     167           1 :         .getManagedSessions()
     168           1 :         .forEach(
     169             :             (id, ioSession) -> {
     170           1 :               AbstractSession abstractSession = AbstractSession.getSession(ioSession, true);
     171           1 :               if (abstractSession != null) {
     172           1 :                 SshSession sshSession = abstractSession.getAttribute(SshSession.KEY);
     173           1 :                 if (sshSession != null) {
     174           1 :                   consumer.accept(id, sshSession, abstractSession, ioSession);
     175             :                 }
     176             :               }
     177           1 :             });
     178           1 :   }
     179             : 
     180             :   @FunctionalInterface
     181             :   public interface SessionConsumer {
     182             :     public void accept(
     183             :         Long id, SshSession sshSession, AbstractSession abstractSession, IoSession ioSession);
     184             :   }
     185             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750