1use crate::config::CtlConfig;
2use crate::http::{HttpRequest, HttpResponse};
3
4pub fn check_auth(req: &HttpRequest, config: &CtlConfig) -> Result<(), HttpResponse> {
7 if config.disable_auth {
8 return Ok(());
9 }
10
11 let expected = match &config.auth_token {
12 Some(t) => t.as_str(),
13 None => return Ok(()), };
15
16 let auth_header = req.headers.get("authorization");
17 match auth_header {
18 Some(val) => {
19 if let Some(token) = val.strip_prefix("Bearer ") {
20 if token == expected {
21 Ok(())
22 } else {
23 Err(HttpResponse::unauthorized("Invalid token"))
24 }
25 } else {
26 Err(HttpResponse::unauthorized("Expected Bearer token"))
27 }
28 }
29 None => Err(HttpResponse::unauthorized("Missing Authorization header")),
30 }
31}
32
33pub fn check_ws_auth(query: &str, config: &CtlConfig) -> Result<(), HttpResponse> {
35 if config.disable_auth {
36 return Ok(());
37 }
38
39 let expected = match &config.auth_token {
40 Some(t) => t.as_str(),
41 None => return Ok(()),
42 };
43
44 let params = crate::http::parse_query(query);
45 match params.get("token") {
46 Some(token) if token == expected => Ok(()),
47 _ => Err(HttpResponse::unauthorized("Missing or invalid token")),
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use std::collections::HashMap;
55
56 fn make_config(token: Option<&str>, disable: bool) -> CtlConfig {
57 CtlConfig {
58 auth_token: token.map(String::from),
59 disable_auth: disable,
60 ..CtlConfig::default()
61 }
62 }
63
64 fn make_req(auth_header: Option<&str>) -> HttpRequest {
65 let mut headers = HashMap::new();
66 if let Some(val) = auth_header {
67 headers.insert("authorization".into(), val.into());
68 }
69 HttpRequest {
70 method: "GET".into(),
71 path: "/api/info".into(),
72 query: String::new(),
73 headers,
74 body: Vec::new(),
75 }
76 }
77
78 #[test]
79 fn auth_disabled() {
80 let config = make_config(Some("secret"), true);
81 assert!(check_auth(&make_req(None), &config).is_ok());
82 }
83
84 #[test]
85 fn auth_no_token_configured() {
86 let config = make_config(None, false);
87 assert!(check_auth(&make_req(None), &config).is_ok());
88 }
89
90 #[test]
91 fn auth_valid_token() {
92 let config = make_config(Some("secret"), false);
93 assert!(check_auth(&make_req(Some("Bearer secret")), &config).is_ok());
94 }
95
96 #[test]
97 fn auth_invalid_token() {
98 let config = make_config(Some("secret"), false);
99 assert!(check_auth(&make_req(Some("Bearer wrong")), &config).is_err());
100 }
101
102 #[test]
103 fn auth_missing_header() {
104 let config = make_config(Some("secret"), false);
105 assert!(check_auth(&make_req(None), &config).is_err());
106 }
107
108 #[test]
109 fn ws_auth_valid() {
110 let config = make_config(Some("abc"), false);
111 assert!(check_ws_auth("token=abc", &config).is_ok());
112 }
113
114 #[test]
115 fn ws_auth_invalid() {
116 let config = make_config(Some("abc"), false);
117 assert!(check_ws_auth("token=xyz", &config).is_err());
118 }
119}