distant_auth/handler/methods/
static_key.rs

1use std::fmt::Display;
2use std::io;
3
4use async_trait::async_trait;
5use log::*;
6
7use crate::handler::AuthMethodHandler;
8use crate::msg::{Challenge, ChallengeResponse, Error, Info, Verification, VerificationResponse};
9
10/// Implementation of [`AuthMethodHandler`] that answers challenge requests using a static
11/// [`HeapSecretKey`]. All other portions of method authentication are handled by another
12/// [`AuthMethodHandler`].
13pub struct StaticKeyAuthMethodHandler<K> {
14    key: K,
15    handler: Box<dyn AuthMethodHandler>,
16}
17
18impl<K> StaticKeyAuthMethodHandler<K> {
19    /// Creates a new [`StaticKeyAuthMethodHandler`] that responds to challenges using a static
20    /// `key`. All other requests are passed to the `handler`.
21    pub fn new<T: AuthMethodHandler + 'static>(key: K, handler: T) -> Self {
22        Self {
23            key,
24            handler: Box::new(handler),
25        }
26    }
27
28    /// Creates a new [`StaticKeyAuthMethodHandler`] that responds to challenges using a static
29    /// `key`. All other requests are passed automatically, meaning that verification is always
30    /// approvide and info/errors are ignored.
31    pub fn simple(key: K) -> Self {
32        Self::new(key, {
33            struct __AuthMethodHandler;
34
35            #[async_trait]
36            impl AuthMethodHandler for __AuthMethodHandler {
37                async fn on_challenge(&mut self, _: Challenge) -> io::Result<ChallengeResponse> {
38                    unreachable!("on_challenge should be handled by StaticKeyAuthMethodHandler");
39                }
40
41                async fn on_verification(
42                    &mut self,
43                    _: Verification,
44                ) -> io::Result<VerificationResponse> {
45                    Ok(VerificationResponse { valid: true })
46                }
47
48                async fn on_info(&mut self, _: Info) -> io::Result<()> {
49                    Ok(())
50                }
51
52                async fn on_error(&mut self, _: Error) -> io::Result<()> {
53                    Ok(())
54                }
55            }
56
57            __AuthMethodHandler
58        })
59    }
60}
61
62#[async_trait]
63impl<K> AuthMethodHandler for StaticKeyAuthMethodHandler<K>
64where
65    K: Display + Send,
66{
67    async fn on_challenge(&mut self, challenge: Challenge) -> io::Result<ChallengeResponse> {
68        trace!("on_challenge({challenge:?})");
69        let mut answers = Vec::new();
70        for question in challenge.questions.iter() {
71            // Only challenges with a "key" label are allowed, all else will fail
72            if question.label != "key" {
73                return Err(io::Error::new(
74                    io::ErrorKind::InvalidInput,
75                    "Only 'key' challenges are supported",
76                ));
77            }
78            answers.push(self.key.to_string());
79        }
80        Ok(ChallengeResponse { answers })
81    }
82
83    async fn on_verification(
84        &mut self,
85        verification: Verification,
86    ) -> io::Result<VerificationResponse> {
87        trace!("on_verify({verification:?})");
88        self.handler.on_verification(verification).await
89    }
90
91    async fn on_info(&mut self, info: Info) -> io::Result<()> {
92        trace!("on_info({info:?})");
93        self.handler.on_info(info).await
94    }
95
96    async fn on_error(&mut self, error: Error) -> io::Result<()> {
97        trace!("on_error({error:?})");
98        self.handler.on_error(error).await
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use test_log::test;
105
106    use super::*;
107    use crate::msg::{ErrorKind, Question, VerificationKind};
108
109    #[test(tokio::test)]
110    async fn on_challenge_should_fail_if_non_key_question_received() {
111        let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key"));
112
113        handler
114            .on_challenge(Challenge {
115                questions: vec![Question::new("test")],
116                options: Default::default(),
117            })
118            .await
119            .unwrap_err();
120    }
121
122    #[test(tokio::test)]
123    async fn on_challenge_should_answer_with_stringified_key_for_key_questions() {
124        let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key"));
125
126        let response = handler
127            .on_challenge(Challenge {
128                questions: vec![Question::new("key")],
129                options: Default::default(),
130            })
131            .await
132            .unwrap();
133        assert_eq!(response.answers.len(), 1, "Wrong answer set received");
134        assert!(!response.answers[0].is_empty(), "Empty answer being sent");
135    }
136
137    #[test(tokio::test)]
138    async fn on_verification_should_leverage_fallback_handler() {
139        let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key"));
140
141        let response = handler
142            .on_verification(Verification {
143                kind: VerificationKind::Host,
144                text: "host".to_string(),
145            })
146            .await
147            .unwrap();
148        assert!(response.valid, "Unexpected result from fallback handler");
149    }
150
151    #[test(tokio::test)]
152    async fn on_info_should_leverage_fallback_handler() {
153        let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key"));
154
155        handler
156            .on_info(Info {
157                text: "info".to_string(),
158            })
159            .await
160            .unwrap();
161    }
162
163    #[test(tokio::test)]
164    async fn on_error_should_leverage_fallback_handler() {
165        let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key"));
166
167        handler
168            .on_error(Error {
169                kind: ErrorKind::Error,
170                text: "text".to_string(),
171            })
172            .await
173            .unwrap();
174    }
175}