ssh_utils_lib/ssh/
key_session.rs

1use std::sync::Arc;
2use anyhow::Result;
3use async_trait::async_trait;
4use russh::keys::*;
5use russh::*;
6use tokio::net::ToSocketAddrs;
7use super::common::{default_ssh_config, SshChannel};
8use super::ssh_session::{AuthMethod, SshSession};
9
10pub struct Client {}
11
12// More SSH event handlers
13// can be defined in this trait
14// In this example, we're only using Channel, so these aren't needed.
15#[async_trait]
16impl client::Handler for Client {
17    type Error = russh::Error;
18
19    async fn check_server_key(
20        &mut self,
21        _server_public_key: &key::PublicKey,
22    ) -> Result<bool, Self::Error> {
23        Ok(true)
24    }
25}
26
27/// This struct is a convenience wrapper
28/// around a russh client
29/// that handles the input/output event loop
30pub struct KeySession {
31    session: client::Handle<Client>,
32}
33
34#[async_trait::async_trait]
35impl SshSession for KeySession {
36    async fn connect<A: ToSocketAddrs + Send>(
37        user: impl Into<String> + Send,
38        auth: impl Into<AuthMethod> + Send,
39        addrs: A,
40    ) -> Result<Self> {
41        let auth = auth.into();
42        let key_pair = match auth {
43            AuthMethod::Key(path) => path,
44            AuthMethod::Password(_) => anyhow::bail!("KeySession only supports key authentication"),
45        };
46
47        //let key_pair: key::KeyPair = load_secret_key(key_path, None)?;
48
49        let config = default_ssh_config();
50
51        let config = Arc::new(config);
52        let sh = Client {};
53
54        let mut session = client::connect(config, addrs, sh).await?;
55
56        // 使用公钥进行认证
57        let auth_res = session
58            .authenticate_publickey(user, Arc::new(key_pair))
59            .await?;
60
61        if !auth_res {
62            anyhow::bail!("public key authentication failed");
63        }
64
65        Ok(Self { session })
66    }
67
68    async fn call(&mut self, command: &str) -> Result<u32> {
69        let channel = self.session.channel_open_session().await?;
70        let mut ssh_channel = SshChannel::new(channel).await?;
71        ssh_channel.call(command).await
72    }
73
74    async fn close(&mut self) -> Result<()> {
75        self.session
76            .disconnect(Disconnect::ByApplication, "", "English")
77            .await?;
78        Ok(())
79    }
80}