parsec_service/authenticators/direct_authenticator/
mod.rs1use super::{AdminList, Application, ApplicationIdentity, Authenticate};
12use crate::front::listener::ConnectionMetadata;
13use crate::utils::config::Admin;
14use log::error;
15use parsec_interface::operations::list_authenticators;
16use parsec_interface::requests::request::RequestAuth;
17use parsec_interface::requests::AuthType;
18use parsec_interface::requests::{ResponseStatus, Result};
19use parsec_interface::secrecy::ExposeSecret;
20use std::str;
21
22#[derive(Clone, Debug)]
24pub struct DirectAuthenticator {
25 admins: AdminList,
26}
27
28impl DirectAuthenticator {
29 pub fn new(admins: Vec<Admin>) -> Self {
31 DirectAuthenticator {
32 admins: admins.into(),
33 }
34 }
35}
36
37impl Authenticate for DirectAuthenticator {
38 fn describe(&self) -> Result<list_authenticators::AuthenticatorInfo> {
39 Ok(list_authenticators::AuthenticatorInfo {
40 description: String::from(
41 "Directly parses the authentication field as a UTF-8 string and uses that as the \
42 application identity. Should be used for testing only.",
43 ),
44 version_maj: 0,
45 version_min: 1,
46 version_rev: 0,
47 id: AuthType::Direct,
48 })
49 }
50
51 fn authenticate(
52 &self,
53 auth: &RequestAuth,
54 _: Option<ConnectionMetadata>,
55 ) -> Result<Application> {
56 if auth.buffer.expose_secret().is_empty() {
57 error!("The direct authenticator does not expect empty authentication values.");
58 Err(ResponseStatus::AuthenticationError)
59 } else {
60 match str::from_utf8(auth.buffer.expose_secret()) {
61 Ok(str) => {
62 let app_name = String::from(str);
63 let is_admin = self.admins.is_admin(&app_name);
64 Ok(Application {
65 identity: ApplicationIdentity {
66 name: app_name,
67 auth: AuthType::Direct.into(),
68 },
69 is_admin,
70 })
71 }
72 Err(_) => {
73 error!("Error parsing the authentication value as a UTF-8 string.");
74 Err(ResponseStatus::AuthenticationError)
75 }
76 }
77 }
78 }
79}
80
81#[cfg(test)]
82mod test {
83 use super::super::Authenticate;
84 use super::DirectAuthenticator;
85 use parsec_interface::requests::request::RequestAuth;
86 use parsec_interface::requests::ResponseStatus;
87
88 #[test]
89 fn successful_authentication() {
90 let authenticator = DirectAuthenticator {
91 admins: Default::default(),
92 };
93
94 let app_name = "app_name".to_string();
95 let req_auth = RequestAuth::new(app_name.clone().into_bytes());
96 let conn_metadata = None;
97
98 let application = authenticator
99 .authenticate(&req_auth, conn_metadata)
100 .expect("Failed to authenticate");
101
102 assert_eq!(application.identity.name, app_name);
103 assert!(!application.is_admin);
104 }
105
106 #[test]
107 fn failed_authentication() {
108 let authenticator = DirectAuthenticator {
109 admins: Default::default(),
110 };
111 let conn_metadata = None;
112 let status = authenticator
113 .authenticate(&RequestAuth::new(vec![0xff; 5]), conn_metadata)
114 .expect_err("Authentication should have failed");
115
116 assert_eq!(status, ResponseStatus::AuthenticationError);
117 }
118
119 #[test]
120 fn empty_auth() {
121 let authenticator = DirectAuthenticator {
122 admins: Default::default(),
123 };
124 let conn_metadata = None;
125 let status = authenticator
126 .authenticate(&RequestAuth::new(Vec::new()), conn_metadata)
127 .expect_err("Empty auth should have failed");
128
129 assert_eq!(status, ResponseStatus::AuthenticationError);
130 }
131
132 #[test]
133 fn admin_check() {
134 let admin_name = String::from("admin_name");
135 let admin = toml::from_str(&format!("name = '{}'", admin_name)).unwrap();
136 let authenticator = DirectAuthenticator {
137 admins: vec![admin].into(),
138 };
139
140 let app_name = "app_name".to_string();
141 let req_auth = RequestAuth::new(app_name.clone().into_bytes());
142 let conn_metadata = None;
143
144 let application = authenticator
145 .authenticate(&req_auth, conn_metadata)
146 .expect("Failed to authenticate");
147
148 assert_eq!(application.identity.name, app_name);
149 assert!(!application.is_admin);
150
151 let req_auth = RequestAuth::new(admin_name.clone().into_bytes());
152 let application = authenticator
153 .authenticate(&req_auth, conn_metadata)
154 .expect("Failed to authenticate");
155
156 assert_eq!(application.identity.name, admin_name);
157 assert!(application.is_admin);
158 }
159}