actix_security_core/http/security/
authenticator.rs1use std::collections::HashMap;
7use std::sync::Arc;
8
9use actix_web::dev::ServiceRequest;
10use rand::distributions::Alphanumeric;
11use rand::{thread_rng, Rng};
12
13use crate::http::security::config::Authenticator;
14use crate::http::security::crypto::{NoOpPasswordEncoder, PasswordEncoder};
15use crate::http::security::user::User;
16
17#[cfg(feature = "http-basic")]
18use crate::http::security::http_basic::extract_basic_auth;
19
20pub struct MemoryAuthenticator {
39 users: HashMap<String, User>,
40 logged_users: HashMap<String, String>,
41 password_encoder: Arc<dyn PasswordEncoder>,
42}
43
44impl MemoryAuthenticator {
45 pub fn new() -> Self {
47 MemoryAuthenticator {
48 users: HashMap::new(),
49 logged_users: HashMap::new(),
50 password_encoder: Arc::new(NoOpPasswordEncoder),
51 }
52 }
53
54 pub fn password_encoder<E: PasswordEncoder + 'static>(mut self, encoder: E) -> Self {
66 self.password_encoder = Arc::new(encoder);
67 self
68 }
69
70 pub fn with_user(mut self, user: User) -> Self {
78 use std::collections::hash_map::Entry;
79 let user_name = user.get_username().to_string();
80 match self.users.entry(user_name) {
81 Entry::Occupied(e) => {
82 eprintln!("Warning: User {} already exists, skipping", e.key());
83 }
84 Entry::Vacant(e) => {
85 e.insert(user);
86 }
87 }
88 self
89 }
90
91 pub fn login(&mut self, user_name: String, password: String) -> Option<String> {
95 self.users.get(&user_name).and_then(|u| {
96 if self.password_encoder.matches(&password, u.get_password()) {
97 let id: String = thread_rng()
98 .sample_iter(&Alphanumeric)
99 .take(30)
100 .map(char::from)
101 .collect();
102 self.logged_users.insert(id.clone(), user_name);
103 Some(id)
104 } else {
105 None
106 }
107 })
108 }
109
110 pub fn logout(&mut self, id: &str) {
112 self.logged_users.remove(id);
113 }
114
115 pub(crate) fn verify_credentials(&self, username: &str, password: &str) -> Option<User> {
117 self.users.get(username).and_then(|user| {
118 if self.password_encoder.matches(password, user.get_password()) {
119 Some(user.clone())
120 } else {
121 None
122 }
123 })
124 }
125}
126
127impl Default for MemoryAuthenticator {
128 fn default() -> Self {
129 Self::new()
130 }
131}
132
133impl Clone for MemoryAuthenticator {
134 fn clone(&self) -> Self {
135 MemoryAuthenticator {
136 logged_users: self
137 .logged_users
138 .iter()
139 .map(|(k, v)| (k.clone(), v.clone()))
140 .collect(),
141 users: self
142 .users
143 .iter()
144 .map(|(k, v)| (k.clone(), v.clone()))
145 .collect(),
146 password_encoder: Arc::clone(&self.password_encoder),
147 }
148 }
149}
150
151impl Authenticator for MemoryAuthenticator {
152 fn get_user(&self, req: &ServiceRequest) -> Option<User> {
153 #[cfg(feature = "http-basic")]
155 if let Some(user) = extract_basic_auth(req, |username, password| {
156 self.verify_credentials(username, password)
157 }) {
158 return Some(user);
159 }
160
161 let user_name = req.headers().get("user_name")?.to_str().ok()?;
163 let password = req.headers().get("password")?.to_str().ok()?;
164 self.verify_credentials(user_name, password)
165 }
166}