1use std::future::Future;
4
5use bytes::Bytes;
6
7pub trait GssEncUpgrade<Stream> {
12 type SecuredStream;
14 type Error;
16
17 fn upgrade(
19 self,
20 stream: Stream,
21 ) -> impl Future<Output = Result<Self::SecuredStream, Self::Error>>;
22}
23
24#[derive(Clone, Eq, PartialEq)]
26pub enum TokenStep {
27 Continue(Bytes),
29 Complete(Option<Bytes>),
31}
32
33impl std::fmt::Debug for TokenStep {
34 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 Self::Continue(token) => formatter
37 .debug_tuple("Continue")
38 .field(&format_args!("[REDACTED; {} bytes]", token.len()))
39 .finish(),
40 Self::Complete(token) => formatter
41 .debug_tuple("Complete")
42 .field(&token.as_ref().map(Bytes::len))
43 .finish(),
44 }
45 }
46}
47
48pub trait TokenAuthEngine {
50 type Error;
52
53 fn initial(&mut self) -> Result<TokenStep, Self::Error>;
59
60 fn step(&mut self, peer_token: &[u8]) -> Result<TokenStep, Self::Error>;
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 struct ExampleEngine(bool);
73
74 impl TokenAuthEngine for ExampleEngine {
75 type Error = std::convert::Infallible;
76
77 fn initial(&mut self) -> Result<TokenStep, Self::Error> {
78 Ok(TokenStep::Continue(Bytes::from_static(b"initial")))
79 }
80
81 fn step(&mut self, peer_token: &[u8]) -> Result<TokenStep, Self::Error> {
82 self.0 = true;
83 Ok(TokenStep::Complete(Some(Bytes::copy_from_slice(
84 peer_token,
85 ))))
86 }
87 }
88
89 #[test]
90 fn recursive_token_engine_is_not_coupled_to_platform_credentials() {
91 let mut engine = ExampleEngine(false);
92 assert!(matches!(engine.initial().unwrap(), TokenStep::Continue(_)));
93 assert_eq!(
94 engine.step(b"challenge").unwrap(),
95 TokenStep::Complete(Some(Bytes::from_static(b"challenge")))
96 );
97 assert!(engine.0);
98 }
99}