背景介绍
项目需要连接到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();
}
}
}
}