tacacs_plus/
context.rs

1use tacacs_plus_protocol::{AuthenticationMethod, PrivilegeLevel, UserInformation};
2
3use super::ClientError;
4
5pub(super) struct InvalidContext(());
6
7impl From<InvalidContext> for ClientError {
8    fn from(_value: InvalidContext) -> Self {
9        ClientError::InvalidContext
10    }
11}
12
13/// Some information associated with all sessions, regardless of the action.
14#[derive(Clone, PartialEq, Eq, Hash, Debug)]
15pub struct SessionContext {
16    pub(super) user: String,
17    pub(super) port: String,
18    pub(super) remote_address: String,
19    pub(super) privilege_level: PrivilegeLevel,
20    authentication_method: Option<AuthenticationMethod>,
21}
22
23impl SessionContext {
24    pub(super) fn as_user_information(&self) -> Result<UserInformation<'_>, InvalidContext> {
25        UserInformation::new(
26            self.user.as_str(),
27            self.port
28                .as_str()
29                .try_into()
30                .map_err(|_| InvalidContext(()))?,
31            self.remote_address
32                .as_str()
33                .try_into()
34                .map_err(|_| InvalidContext(()))?,
35        )
36        .ok_or(InvalidContext(()))
37    }
38
39    /// Gets the authentication method for this context object, defaulting to [`NotSet`](tacacs_plus_protocol::AuthenticationMethod::NotSet).
40    ///
41    /// This should not be used within an authentication session.
42    pub(super) fn authentication_method(&self) -> AuthenticationMethod {
43        self.authentication_method
44            .unwrap_or(AuthenticationMethod::NotSet)
45    }
46}
47
48/// Builder for [`SessionContext`] objects.
49#[derive(Debug, Clone, PartialEq, Eq, Hash)]
50pub struct ContextBuilder {
51    user: String,
52    port: String,
53    remote_address: String,
54    privilege_level: PrivilegeLevel,
55    authentication_method: Option<AuthenticationMethod>,
56}
57
58// TODO: don't consume builder at each step
59impl ContextBuilder {
60    /// Creates a new builder with default values for the various fields.
61    pub fn new(user: String) -> Self {
62        Self {
63            user,
64            port: String::from("rust_client"),
65            remote_address: String::from("tacacs_plus_rs"),
66            privilege_level: Default::default(),
67            authentication_method: None,
68        }
69    }
70
71    /// Sets the port of the resulting context.
72    pub fn port(&mut self, port: String) -> &mut Self {
73        self.port = port;
74        self
75    }
76
77    /// Sets the remote address of the resulting context.
78    pub fn remote_address(&mut self, remote_address: String) -> &mut Self {
79        self.remote_address = remote_address;
80        self
81    }
82
83    /// Sets the privilege level of the resulting context.
84    pub fn privilege_level(&mut self, privilege_level: PrivilegeLevel) -> &mut Self {
85        self.privilege_level = privilege_level;
86        self
87    }
88
89    /// Sets the authentication method of the resulting context.
90    ///
91    /// Note that this field is ignored in an authentication session.
92    pub fn auth_method(&mut self, method: AuthenticationMethod) -> &mut Self {
93        self.authentication_method = Some(method);
94        self
95    }
96
97    /// Consumes this builder and turns it into a [`SessionContext`].
98    pub fn build(&self) -> SessionContext {
99        SessionContext {
100            user: self.user.clone(),
101            port: self.port.clone(),
102            remote_address: self.remote_address.clone(),
103            privilege_level: self.privilege_level,
104            authentication_method: self.authentication_method,
105        }
106    }
107}