ilmen_http/http/security/
service.rs1use anyhow::Context;
2use base64::{engine::general_purpose::URL_SAFE, Engine};
3use std::str;
4use crate::{http::HttpError, HTTPRequest, Route};
5
6pub fn apply_security(request: &HTTPRequest, route: Route, security: SecurityProtocol) -> Result<Route, HttpError> {
7 match security {
8 SecurityProtocol::None => Ok(()),
9 SecurityProtocol::Basic(validate_methode) => base_auth(request, validate_methode),
10 }.map(|_| route)
11}
12
13fn base_auth(request: &HTTPRequest, validate_methode: AuthMethod) -> Result<(), HttpError>{
14 let header_auth_value : Vec<String> = request.get_header("Authorization")
15 .ok_or(HttpError::UnauthorizedError("Missing header".to_string()))?
16 .1
17 .split(' ')
18 .map(str::to_owned)
19 .collect();
20
21 let is_basic_protocol = header_auth_value.first()
22 .ok_or(HttpError::UnauthorizedError("No protocol specified".to_string()))
23 .map(|protocol| protocol.eq(&"Basic"))?;
24
25 if !is_basic_protocol {
26 return Err(HttpError::UnauthorizedError("Wrong Protocol".to_string()));
27 }
28
29 header_auth_value
30 .get(1)
31 .context("No user password provided")
32 .and_then(decode_base64_auth)
33 .map_err(|e| HttpError::UnauthorizedError(e.to_string()))
34 .map(validate_methode)
35 .and_then(|is_valid_creds| {
36 match is_valid_creds {
37 true => Ok(()),
38 false => Err(HttpError::UnauthorizedError("Unauthorized".to_string())),
39 }
40 })
41}
42
43type Username = String;
44type Password = String;
45type AuthMethod = fn((Username, Password)) -> bool;
46
47fn decode_base64_auth(b64_value: &String) -> anyhow::Result<(String, String)>{
48 URL_SAFE.decode(b64_value)
49 .context("Authentication parameter is not base64 encrypted".to_string())
50 .and_then(|vect| String::from_utf8(vect).context("Could not parse from utf8"))
51 .map(|decoded | {
52 let splitter = decoded.split_once(':').unwrap_or(("", ""));
53 (splitter.0.to_string(), splitter.1.to_string())
54 })
55}
56
57#[derive(Clone)]
58pub enum SecurityProtocol {
59 None,
60 Basic(AuthMethod)
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn apply_basic_security_with_good_creds() {
69 let buffer = "GET rappel/1 HTTP/1.1\r\nAuthorization: Basic dG90bzp0YXRh\r\n\r\ntoto";
70
71 let request = HTTPRequest::try_from(buffer).unwrap();
72 let validate : AuthMethod= |_| true;
73
74 let result = apply_security(&request, Route::default(), SecurityProtocol::Basic(validate)).unwrap();
75 assert_eq!(result, Route::default())
76 }
77
78 #[test]
79 fn apply_basic_security_with_bad_creds() {
80 let buffer = "GET rappel/1 HTTP/1.1\r\nAuthorization: Basic dG90bzp0YXR1YWE=\r\n\r\ntoto";
81
82 let request = HTTPRequest::try_from(buffer).unwrap();
83
84 let validate : AuthMethod = |_| false;
85
86 let result = apply_security(&request, Route::default(), SecurityProtocol::Basic(validate)).unwrap_err();
87 assert_eq!(result, HttpError::UnauthorizedError("Unauthorized".to_string()))
88 }
89
90 #[test]
91 fn apply_basic_security_with_bad_protocol() {
92 let buffer = "GET rappel/1 HTTP/1.1\r\nAuthorization: Basics dG90bzp0YXR1YWE=\r\n\r\ntoto";
93
94 let request = HTTPRequest::try_from(buffer).unwrap();
95
96 let validate : AuthMethod = |_| false;
97
98 let result = apply_security(&request, Route::default(), SecurityProtocol::Basic(validate)).unwrap_err();
99 assert_eq!(result, HttpError::UnauthorizedError("Wrong Protocol".to_string()))
100 }
101}