通过 ssh.net 对每个命令进行第二因素验证
2nd factor verification on every command through ssh.net
我正在使用 SSH.NET 和以下代码连接到 Unix 服务器
ssh = new SshClient("myserver.univ.edu", Username, Password);
ssh.Connect();
连接成功,似乎没有产生异常。服务器设置为需要双因素身份验证,但我的 phone 上没有提示(将其用作物理 authenticator/OTP 设备)。但是连接似乎没问题。
然后我使用以下代码发出命令:
SshCommand NewLookup = ssh.CreateCommand("newlookup " + IpNameOrAddress.Text))
LogText.Text += NewLookup.Execute().Replace("\n", Environment.NewLine);
然后 然后 我得到了推送到我的 phone (第二因素验证请求)。一旦我通过 phone、 然后 接受了验证请求,命令就可以正常执行。这一切都可以,除了...
问题
对于每个后续命令,我都会收到 phone 的推送,因此如果我想将该连接用于 运行 多个命令,我必须坐在我的 phone 上点击"Accept" 每个命令。那么,如何避免对每个命令进行推送?
为了在 SSH.NET 的单个会话中发送多个命令,您可能需要使用 ShellStream
。这应该将您的 2FA 批准减少到仅向主持人开放会话。这对于不支持命令通道但支持 SSH 远程终端(例如,您可以对它们使用 putty)的设备(例如 HPE 交换机)以及命令更改 (shell ) 环境,因此您需要在作业期间保持会话打开。否则,SSH 命令通道是处理此问题的预期(也是更好)方式。
您可以在 NuDoc - SSH.NET and the GitHub Releases for the SSH.Net project include a Windows Help file 找到更多 SSH.NET 文档。
这是我写的一些代码,用于将 ShellStream
包装在另一个对象中,该对象保留 StreamReader
和 StreamWriter
并处理从 (n HP) 开关读取输入并过滤掉转义序列,以及阅读下一个提示:
public static class SshClientExt {
public static ExtShellStream CreateExtShellStream(this SshClient sc, string termName, uint rows, uint cols, uint width, uint height, int bufSize) =>
new ExtShellStream(sc.CreateShellStream(termName, rows, cols, width, height, bufSize));
}
public class ExtShellStream : IDisposable {
static Regex reEscVT100 = new Regex("\x1B\[[^A-Z]+[A-Z]", RegexOptions.Compiled);
static TimeSpan ReadTimeout = new TimeSpan(0, 0, 10);
ShellStream ssh;
StreamReader sr;
StreamWriter sw;
public ExtShellStream(ShellStream anSSH) {
ssh = anSSH;
sr = new StreamReader(ssh);
sw = new StreamWriter(ssh);
}
public List<string> ReadLines() {
// try to read all in
long prev;
do {
prev = ssh.Length;
Thread.Sleep(250);
} while (ssh.Length != prev);
"-".Repeat(40).Dump();
var ans = new List<string>();
while (true) {
var line = sr.ReadLine();
if (line != null) {
line = line.Remove(reEscVT100).TrimEnd();
$@"""{line}""".Dump();
if (line.EndsWith("#")) // stop when prompt appears
break;
else
ans.Add(line);
}
else
Thread.Sleep(500);
}
return ans;
}
public void DumpLines() => ReadLines();
public List<string> DoCommand(string cmd) {
sw.Write(cmd);
sw.Write("\r");
sw.Flush();
while (!ssh.DataAvailable)
Thread.Sleep(500);
return ReadLines().SkipWhile(l => l == cmd).ToList();
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing) {
if (!disposedValue) {
if (disposing) {
// prevent double dispose
// don't dispose of sr or sw: only disposable resource is ssh
ssh.Dispose();
}
disposedValue = true;
}
}
// This code added to correctly implement the disposable pattern.
public void Dispose() {
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}
#endregion
}
下面是一个示例函数,该函数将代码与 SSH.Net 一起用于从交换机检索配置信息的屏幕副本:
public static void RetrieveConfigFiles(IDFStack idf) {
using (var sshClient = new SshClient(idf.IPAddress, username, password)) {
sshClient.Connect();
using (var ssh = sshClient.CreateExtShellStream("dumb", 120, 80, 0, 0, 200000)) {
ssh.DumpLines();
ssh.DoCommand("no page");
File.WriteAllLines(idf.ConfigPath, ssh.DoCommand("show running-config structured"));
File.WriteAllLines(idf.StatusPath, ssh.DoCommand("show interfaces brief"));
File.WriteAllLines(idf.LLDPPath, ssh.DoCommand("show lldp info remote-device detail"));
}
sshClient.Disconnect();
}
}
我正在使用 SSH.NET 和以下代码连接到 Unix 服务器
ssh = new SshClient("myserver.univ.edu", Username, Password);
ssh.Connect();
连接成功,似乎没有产生异常。服务器设置为需要双因素身份验证,但我的 phone 上没有提示(将其用作物理 authenticator/OTP 设备)。但是连接似乎没问题。
然后我使用以下代码发出命令:
SshCommand NewLookup = ssh.CreateCommand("newlookup " + IpNameOrAddress.Text))
LogText.Text += NewLookup.Execute().Replace("\n", Environment.NewLine);
然后 然后 我得到了推送到我的 phone (第二因素验证请求)。一旦我通过 phone、 然后 接受了验证请求,命令就可以正常执行。这一切都可以,除了...
问题
对于每个后续命令,我都会收到 phone 的推送,因此如果我想将该连接用于 运行 多个命令,我必须坐在我的 phone 上点击"Accept" 每个命令。那么,如何避免对每个命令进行推送?
为了在 SSH.NET 的单个会话中发送多个命令,您可能需要使用 ShellStream
。这应该将您的 2FA 批准减少到仅向主持人开放会话。这对于不支持命令通道但支持 SSH 远程终端(例如,您可以对它们使用 putty)的设备(例如 HPE 交换机)以及命令更改 (shell ) 环境,因此您需要在作业期间保持会话打开。否则,SSH 命令通道是处理此问题的预期(也是更好)方式。
您可以在 NuDoc - SSH.NET and the GitHub Releases for the SSH.Net project include a Windows Help file 找到更多 SSH.NET 文档。
这是我写的一些代码,用于将 ShellStream
包装在另一个对象中,该对象保留 StreamReader
和 StreamWriter
并处理从 (n HP) 开关读取输入并过滤掉转义序列,以及阅读下一个提示:
public static class SshClientExt {
public static ExtShellStream CreateExtShellStream(this SshClient sc, string termName, uint rows, uint cols, uint width, uint height, int bufSize) =>
new ExtShellStream(sc.CreateShellStream(termName, rows, cols, width, height, bufSize));
}
public class ExtShellStream : IDisposable {
static Regex reEscVT100 = new Regex("\x1B\[[^A-Z]+[A-Z]", RegexOptions.Compiled);
static TimeSpan ReadTimeout = new TimeSpan(0, 0, 10);
ShellStream ssh;
StreamReader sr;
StreamWriter sw;
public ExtShellStream(ShellStream anSSH) {
ssh = anSSH;
sr = new StreamReader(ssh);
sw = new StreamWriter(ssh);
}
public List<string> ReadLines() {
// try to read all in
long prev;
do {
prev = ssh.Length;
Thread.Sleep(250);
} while (ssh.Length != prev);
"-".Repeat(40).Dump();
var ans = new List<string>();
while (true) {
var line = sr.ReadLine();
if (line != null) {
line = line.Remove(reEscVT100).TrimEnd();
$@"""{line}""".Dump();
if (line.EndsWith("#")) // stop when prompt appears
break;
else
ans.Add(line);
}
else
Thread.Sleep(500);
}
return ans;
}
public void DumpLines() => ReadLines();
public List<string> DoCommand(string cmd) {
sw.Write(cmd);
sw.Write("\r");
sw.Flush();
while (!ssh.DataAvailable)
Thread.Sleep(500);
return ReadLines().SkipWhile(l => l == cmd).ToList();
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing) {
if (!disposedValue) {
if (disposing) {
// prevent double dispose
// don't dispose of sr or sw: only disposable resource is ssh
ssh.Dispose();
}
disposedValue = true;
}
}
// This code added to correctly implement the disposable pattern.
public void Dispose() {
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}
#endregion
}
下面是一个示例函数,该函数将代码与 SSH.Net 一起用于从交换机检索配置信息的屏幕副本:
public static void RetrieveConfigFiles(IDFStack idf) {
using (var sshClient = new SshClient(idf.IPAddress, username, password)) {
sshClient.Connect();
using (var ssh = sshClient.CreateExtShellStream("dumb", 120, 80, 0, 0, 200000)) {
ssh.DumpLines();
ssh.DoCommand("no page");
File.WriteAllLines(idf.ConfigPath, ssh.DoCommand("show running-config structured"));
File.WriteAllLines(idf.StatusPath, ssh.DoCommand("show interfaces brief"));
File.WriteAllLines(idf.LLDPPath, ssh.DoCommand("show lldp info remote-device detail"));
}
sshClient.Disconnect();
}
}