java使用jsch执行交互式命令(sudo command,不手动输入密码)解决方案

背景介绍

        项目需要连接到linux服务器,去获取服务器的品牌及型号,原有的实现是通过命令查/var/log/dmesg,但普适性着实不高,考虑使用dmidecode命令获取。

        但dmidecode默认需要root权限,我们项目不能使用root用户去连接服务器,且连接的用户只能使用交互式密码形式使用sudo命令,故有此文。

解决方式

        本文的解决方案参考了:使用JSch sudo示例和Channel.setPty在远程主机上运行sudo命令 - Thinbug

        代码如下,这里我使用了Ssh连接池去获取的Session,

        其中,需要注意的是,sudo要指定 -S 参数,该参数代表的含义是从标准输入读取密码: 

public void testJschPool(){
        SshConfig sshConfig = new SshConfig();
        sshConfig.setHost("192.168.52.121");
        sshConfig.setPort(22);
        sshConfig.setUsername("test");
        sshConfig.setPassword("root");
        try {
            Session session = SshPool.getInstance().getPool().borrowObject(sshConfig);
            try {
                ChannelExec exec = (ChannelExec)session.openChannel("exec");
                String command = "dmidecode -s system-manufacturer";
                exec.setCommand("sudo -S "+command);
                InputStream in = exec.getInputStream();
                OutputStream out = exec.getOutputStream();
                exec.connect();
                out.write(("root" + "\n").getBytes()); //这里是密码后跟了一个换行符
                out.flush();
                byte[] tmp=new byte[1024];
                while(true){
                    while(in.available()>0){
                        int i=in.read(tmp, 0, 1024);
                        if(i<0)break;
                        String s = new String(tmp, 0, i);
                        System.out.print(s);
                    }
                    if(exec.isClosed()){
                        System.out.println("exit-status: "+exec.getExitStatus());
                        break;
                    }
                    try{Thread.sleep(1000);}catch(Exception ee){}
                }
                exec.disconnect();
            } catch (JSchException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                SshPool.getInstance().getPool().returnObject(sshConfig,session);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

附:SshConfig配置类

import java.util.Objects;

public class SshConfig {
    private String host;
    private int port;
    private String username;
    private String password;
    private String knownHosts;
    private boolean ignoreHostKeyChecking = true;
    private String privateKey;
    private String passphrase;
    private String location;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public String getPassphrase() {
        return passphrase;
    }

    public void setPassphrase(String passphrase) {
        this.passphrase = passphrase;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getKnownHosts() {
        return knownHosts;
    }

    public void setKnownHosts(String knownHosts) {
        this.knownHosts = knownHosts;
    }

    public boolean isIgnoreHostKeyChecking() {
        return ignoreHostKeyChecking;
    }

    public void setIgnoreHostKeyChecking(boolean ignoreHostKeyChecking) {
        this.ignoreHostKeyChecking = ignoreHostKeyChecking;
    }

    public String getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(String privateKey) {
        this.privateKey = privateKey;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SshConfig sshConfig = (SshConfig) o;
        return port == sshConfig.port &&
                ignoreHostKeyChecking == sshConfig.ignoreHostKeyChecking &&
                Objects.equals(host, sshConfig.host) &&
                Objects.equals(username, sshConfig.username) &&
                Objects.equals(password, sshConfig.password) &&
                Objects.equals(knownHosts, sshConfig.knownHosts) &&
                Objects.equals(privateKey, sshConfig.privateKey) &&
                Objects.equals(passphrase, sshConfig.passphrase) &&
                Objects.equals(location, sshConfig.location);
    }

    @Override
    public int hashCode() {
        return Objects.hash(host, port, username, password, knownHosts, ignoreHostKeyChecking, privateKey, passphrase, location);
    }
}

附:SshPool连接池

import java.security.AccessController;
import java.security.PrivilegedAction;

import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
import org.apache.commons.pool2.KeyedObjectPool;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

public class SshPool {
    private GenericKeyedObjectPool<SshConfig, Session> pool;

    private static class SingletonHolder{
        public static final SshPool INSTANCE = new SshPool();
    }

    public static SshPool getInstance(){
        return SingletonHolder.INSTANCE;
    }

    private SshPool(){
        startPool();
    }

    public KeyedObjectPool<SshConfig,Session> getPool(){
        return pool;
    }


    /**
     * create Ssh Pool
     */
    public void startPool() {
        pool = AccessController.doPrivileged(
                new PrivilegedAction<GenericKeyedObjectPool<SshConfig, Session>>() {
                    @Override
                    public GenericKeyedObjectPool<SshConfig, Session> run() {
                        try {
                            return new GenericKeyedObjectPool<>(
                                    new SshPoolFactory(), new GenericKeyedObjectPoolConfig());
                        } catch (final Exception e) {
                            throw new SshPoolException("could not init pool.",
                                    e);
                        }
                    }
                });
    }

    private static class SshPoolFactory
            extends BaseKeyedPooledObjectFactory<SshConfig, Session> {

        @Override
        public Session create(final SshConfig config) throws Exception {
            final JSch jsch = new JSch();
            if (config.getKnownHosts() != null
                    && !config.getKnownHosts().isEmpty()) {
                jsch.setKnownHosts(config.getKnownHosts());
            }

            if (config.getPrivateKey() != null
                    && !config.getPrivateKey().isEmpty()) {
                if (config.getPassphrase() != null) {
                    jsch.addIdentity(config.getPrivateKey(),
                            config.getPassphrase());
                } else {
                    jsch.addIdentity(config.getPrivateKey());
                }
            }

            final Session session = jsch.getSession(config.getUsername(),
                    config.getHost(), config.getPort());
            if (config.getPassword() != null) {
                session.setPassword(config.getPassword());
            }
            if (config.isIgnoreHostKeyChecking()) {
                session.setConfig("StrictHostKeyChecking", "no");
            }

            session.connect();

            return session;
        }

        @Override
        public PooledObject<Session> wrap(final Session session) {
            return new DefaultPooledObject<>(session);
        }

        @Override
        public boolean validateObject(final SshConfig key,
                                      final PooledObject<Session> pooledObject) {
            return pooledObject.getObject().isConnected();
        }

        @Override
        public void destroyObject(final SshConfig key,
                                  final PooledObject<Session> pooledObject) {
            if (pooledObject != null) {
                pooledObject.getObject().disconnect();
            }
        }
    }

}

 

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值