feat(ssh): 支持设置首次连接认证策略.

支持更改首次连接认证策略, 以减少确认服务器密钥的工作量(尽管这可能导致后续连接不再安全).
This commit is contained in:
LamGC 2021-08-15 18:45:26 +08:00
parent dc9c349826
commit a83c09a787
Signed by: LamGC
GPG Key ID: 6C5AE2A913941E1D
2 changed files with 72 additions and 22 deletions

View File

@ -7,6 +7,8 @@ import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.config.keys.KeyUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.lang.NonNull;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.security.PublicKey; import java.security.PublicKey;
@ -19,6 +21,10 @@ public class OracleInstanceServerKeyVerifier implements ServerKeyVerifier {
private final static Logger log = LoggerFactory.getLogger(OracleInstanceServerKeyVerifier.class); private final static Logger log = LoggerFactory.getLogger(OracleInstanceServerKeyVerifier.class);
@Value("${oracle.ssh.firstConnection.authenticationPolicy}")
@NonNull
private static String firstConnectionPolicy;
private final ComputeInstance instance; private final ComputeInstance instance;
private final SshAuthInfo info; private final SshAuthInfo info;
@ -34,7 +40,7 @@ public class OracleInstanceServerKeyVerifier implements ServerKeyVerifier {
.verifyServerKey(clientSession, remoteAddress, serverKey); .verifyServerKey(clientSession, remoteAddress, serverKey);
} else { } else {
log.warn("首次连接实例 SSH, 需要用户确认服务器公钥是否可信..."); log.warn("首次连接实例 SSH, 需要用户确认服务器公钥是否可信...");
boolean result = confirm(remoteAddress, serverKey); boolean result = usePolicyConfirm(remoteAddress, serverKey);
if (result) { if (result) {
log.info("用户已确认服务器密钥可信, 将该密钥列入该实例下的信任密钥."); log.info("用户已确认服务器密钥可信, 将该密钥列入该实例下的信任密钥.");
info.setServerKey(serverKey); info.setServerKey(serverKey);
@ -46,7 +52,21 @@ public class OracleInstanceServerKeyVerifier implements ServerKeyVerifier {
} }
} }
public boolean confirm(SocketAddress address, PublicKey key) { private boolean usePolicyConfirm(SocketAddress address, PublicKey serverKey) {
FirstConnectionPolicy policy;
try {
policy = FirstConnectionPolicy.valueOf(firstConnectionPolicy.toUpperCase());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Unsupported policy: " + firstConnectionPolicy);
}
return policy.confirmFunction.confirm(this.instance, address, serverKey);
}
@SuppressWarnings("unused")
private enum FirstConnectionPolicy {
ACCEPT((instance, address, key) -> true),
REJECT((instance, address, key) -> false),
CONFIRM((instance, address, key) -> {
String fingerPrint = KeyUtils.getFingerPrint(key); String fingerPrint = KeyUtils.getFingerPrint(key);
log.warn("开始密钥认证流程... (InstanceId: {}, ServerAddress: {}, KeyFingerPrint: {})", log.warn("开始密钥认证流程... (InstanceId: {}, ServerAddress: {}, KeyFingerPrint: {})",
instance.getInstanceId(), address, fingerPrint); instance.getInstanceId(), address, fingerPrint);
@ -74,6 +94,28 @@ public class OracleInstanceServerKeyVerifier implements ServerKeyVerifier {
return "yes".trim().equalsIgnoreCase(input); return "yes".trim().equalsIgnoreCase(input);
} }
} while (true); } while (true);
});
private final PublicKeyConfirm confirmFunction;
FirstConnectionPolicy(PublicKeyConfirm confirmFunction) {
this.confirmFunction = confirmFunction;
}
}
@FunctionalInterface
private interface PublicKeyConfirm {
/**
* 确认密钥.
* @param instance 待认证的服务器所属计算实例.
* @param address 远程地址.
* @param serverKey 服务器密钥.
* @return 如果通过, 返回 {@code true}.
*/
boolean confirm(ComputeInstance instance, SocketAddress address, PublicKey serverKey);
} }
} }

View File

@ -1,8 +1,16 @@
oracle: oracle:
identity: identity:
# 身份配置文件的文件名匹配规则.
pattern: '.+\.oracle\.ini$' pattern: '.+\.oracle\.ini$'
location: "./identity/" # 身份配置文件夹路径.
location: './identity/'
script: script:
location: "./scripts/" # 脚本文件夹路径.
location: './scripts/'
ssh: ssh:
identityPath: "./config/ssh.config.json" # SSH 认证文件存储路径.
identityPath: './config/ssh-auth.json'
firstConnection:
# 首次连接认证策略
# 支持 inquiry(询问) accept(接受) reject(拒绝)
authenticationPolicy: 'inquiry'