1use alloc::vec::Vec;
2
3use http::{
4 header::{AUTHORIZATION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, WWW_AUTHENTICATE},
5 HeaderMap,
6};
7
8use crate::{
9 challenge::Challenge,
10 challenges::{Challenges, ChallengesParseError, ChallengesWithSlice},
11 credentials::{Credentials, CredentialsParseError},
12};
13
14pub fn get_authorization(
18 header_map: &HeaderMap,
19) -> Option<Result<Credentials, CredentialsParseError>> {
20 header_map
21 .get(AUTHORIZATION)
22 .map(|x| Credentials::from_bytes(x.as_bytes()))
23}
24
25pub fn get_proxy_authorization(
26 header_map: &HeaderMap,
27) -> Option<Result<Credentials, CredentialsParseError>> {
28 header_map
29 .get(PROXY_AUTHORIZATION)
30 .map(|x| Credentials::from_bytes(x.as_bytes()))
31}
32
33pub fn set_authorization(
35 header_map: &mut HeaderMap,
36 credentials: &Credentials,
37) -> Result<(), http::header::InvalidHeaderValue> {
38 use alloc::string::ToString as _;
39
40 header_map.remove(AUTHORIZATION);
41 header_map.append(
42 AUTHORIZATION,
43 http::HeaderValue::from_str(credentials.to_string().as_str())?,
44 );
45 Ok(())
46}
47
48pub fn set_proxy_authorization(
49 header_map: &mut HeaderMap,
50 credentials: &Credentials,
51) -> Result<(), http::header::InvalidHeaderValue> {
52 use alloc::string::ToString as _;
53
54 header_map.remove(PROXY_AUTHORIZATION);
55 header_map.append(
56 PROXY_AUTHORIZATION,
57 http::HeaderValue::from_str(credentials.to_string().as_str())?,
58 );
59 Ok(())
60}
61
62#[cfg(feature = "scheme-basic")]
63pub fn set_authorization_with_basic(
64 header_map: &mut HeaderMap,
65 user_id: impl AsRef<str>,
66 password: impl AsRef<str>,
67) -> Result<(), http::header::InvalidHeaderValue> {
68 set_authorization(header_map, &Credentials::basic(user_id, password))
69}
70
71#[cfg(feature = "scheme-basic")]
72pub fn set_proxy_authorization_with_basic(
73 header_map: &mut HeaderMap,
74 user_id: impl AsRef<str>,
75 password: impl AsRef<str>,
76) -> Result<(), http::header::InvalidHeaderValue> {
77 set_proxy_authorization(header_map, &Credentials::basic(user_id, password))
78}
79
80#[cfg(feature = "scheme-bearer")]
82pub fn set_authorization_with_bearer(
83 header_map: &mut HeaderMap,
84 token: impl AsRef<str>,
85) -> Result<(), http::header::InvalidHeaderValue> {
86 set_authorization(header_map, &Credentials::bearer(token))
87}
88
89#[cfg(feature = "scheme-bearer")]
90pub fn set_proxy_authorization_with_bearer(
91 header_map: &mut HeaderMap,
92 token: impl AsRef<str>,
93) -> Result<(), http::header::InvalidHeaderValue> {
94 set_proxy_authorization(header_map, &Credentials::bearer(token))
95}
96
97pub fn get_www_authenticate(header_map: &HeaderMap) -> Result<Challenges, ChallengesParseError> {
101 let list = header_map
102 .get_all(WWW_AUTHENTICATE)
103 .into_iter()
104 .map(|x| Challenges::from_bytes(x.as_bytes()))
105 .collect::<Result<Vec<_>, _>>()?;
106 let list = list.into_iter().flat_map(|x| x.0).collect::<Vec<_>>();
107 Ok(Challenges::new(list))
108}
109
110pub fn get_proxy_authenticate(header_map: &HeaderMap) -> Result<Challenges, ChallengesParseError> {
111 let list = header_map
112 .get_all(PROXY_AUTHENTICATE)
113 .into_iter()
114 .map(|x| Challenges::from_bytes(x.as_bytes()))
115 .collect::<Result<Vec<_>, _>>()?;
116 let list = list.into_iter().flat_map(|x| x.0).collect::<Vec<_>>();
117 Ok(Challenges::new(list))
118}
119
120pub fn append_www_authenticate(
122 header_map: &mut HeaderMap,
123 challenge: &Challenge,
124) -> Result<(), http::header::InvalidHeaderValue> {
125 use alloc::string::ToString as _;
126
127 header_map.append(
128 WWW_AUTHENTICATE,
129 http::HeaderValue::from_str(challenge.to_string().as_str())?,
130 );
131 Ok(())
132}
133
134pub fn append_www_authenticate_with_multiple(
135 header_map: &mut HeaderMap,
136 challenges: &[Challenge],
137) -> Result<(), http::header::InvalidHeaderValue> {
138 use alloc::string::ToString as _;
139
140 header_map.append(
141 WWW_AUTHENTICATE,
142 http::HeaderValue::from_str(ChallengesWithSlice::new(challenges).to_string().as_str())?,
143 );
144 Ok(())
145}
146
147pub fn append_proxy_authenticate(
148 header_map: &mut HeaderMap,
149 challenge: &Challenge,
150) -> Result<(), http::header::InvalidHeaderValue> {
151 use alloc::string::ToString as _;
152
153 header_map.append(
154 PROXY_AUTHENTICATE,
155 http::HeaderValue::from_str(challenge.to_string().as_str())?,
156 );
157 Ok(())
158}
159
160pub fn append_proxy_authenticate_with_multiple(
161 header_map: &mut HeaderMap,
162 challenges: &[Challenge],
163) -> Result<(), http::header::InvalidHeaderValue> {
164 use alloc::string::ToString as _;
165
166 header_map.append(
167 PROXY_AUTHENTICATE,
168 http::HeaderValue::from_str(ChallengesWithSlice::new(challenges).to_string().as_str())?,
169 );
170 Ok(())
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[cfg(feature = "scheme-basic")]
178 #[test]
179 fn test_get_set_authorization() {
180 use crate::schemes::basic::{
181 DEMO_CREDENTIALS_PASSWORD_STR, DEMO_CREDENTIALS_STR, DEMO_CREDENTIALS_USER_ID_STR,
182 };
183
184 let mut map = HeaderMap::new();
186 assert!(get_authorization(&map).is_none());
187 map.append(AUTHORIZATION, DEMO_CREDENTIALS_STR.parse().unwrap());
188 let c = get_authorization(&map).map(|x| x.unwrap()).unwrap();
189 match c {
190 Credentials::Basic(c) => {
191 assert_eq!(c.user_id, DEMO_CREDENTIALS_USER_ID_STR.into());
192 assert_eq!(c.password, DEMO_CREDENTIALS_PASSWORD_STR.into());
193 }
194 x => panic!("{x:?}"),
195 }
196
197 let mut map = HeaderMap::new();
199 set_authorization_with_basic(
200 &mut map,
201 DEMO_CREDENTIALS_USER_ID_STR,
202 DEMO_CREDENTIALS_PASSWORD_STR,
203 )
204 .unwrap();
205 assert_eq!(map.get(AUTHORIZATION).unwrap(), DEMO_CREDENTIALS_STR);
206 }
207
208 #[cfg(feature = "scheme-basic")]
209 #[test]
210 fn test_get_set_proxy_authorization() {
211 use crate::schemes::basic::{
212 DEMO_CREDENTIALS_PASSWORD_STR, DEMO_CREDENTIALS_STR, DEMO_CREDENTIALS_USER_ID_STR,
213 };
214
215 let mut map = HeaderMap::new();
217 assert!(get_proxy_authorization(&map).is_none());
218 map.append(PROXY_AUTHORIZATION, DEMO_CREDENTIALS_STR.parse().unwrap());
219 let c = get_proxy_authorization(&map).map(|x| x.unwrap()).unwrap();
220 match c {
221 Credentials::Basic(c) => {
222 assert_eq!(c.user_id, DEMO_CREDENTIALS_USER_ID_STR.into());
223 assert_eq!(c.password, DEMO_CREDENTIALS_PASSWORD_STR.into());
224 }
225 x => panic!("{x:?}"),
226 }
227
228 let mut map = HeaderMap::new();
230 set_proxy_authorization_with_basic(
231 &mut map,
232 DEMO_CREDENTIALS_USER_ID_STR,
233 DEMO_CREDENTIALS_PASSWORD_STR,
234 )
235 .unwrap();
236 assert_eq!(map.get(PROXY_AUTHORIZATION).unwrap(), DEMO_CREDENTIALS_STR);
237 }
238
239 #[cfg(all(feature = "scheme-basic", feature = "scheme-bearer"))]
240 #[test]
241 fn test_get_append_www_authenticate() {
242 let mut map = HeaderMap::new();
244 assert!(get_www_authenticate(&map).unwrap().is_empty());
245
246 map.append(
248 WWW_AUTHENTICATE,
249 r#"Basic realm="foo", charset="UTF-8", Bearer realm="bar", scope="openid profile email""#
250 .parse()
251 .unwrap(),
252 );
253 let c = get_www_authenticate(&map).unwrap();
254 for (i, c) in c.iter().enumerate() {
255 match i {
256 0 => {
257 let c = c.as_basic().unwrap();
258 assert_eq!(c.realm, "foo".into());
259 assert_eq!(c.charset, Some("UTF-8".into()));
260 }
261 1 => {
262 let c = c.as_bearer().unwrap();
263 assert_eq!(c.realm, "bar".into());
264 assert_eq!(c.scope, Some("openid profile email".into()));
265 }
266 i => panic!("{i} {c:?}"),
267 }
268 }
269
270 map.clear();
272 map.append(
273 WWW_AUTHENTICATE,
274 r#"Basic realm="foo", charset="UTF-8""#.parse().unwrap(),
275 );
276 map.append(
277 WWW_AUTHENTICATE,
278 r#"Bearer realm="bar", scope="openid profile email""#
279 .parse()
280 .unwrap(),
281 );
282 let c = get_www_authenticate(&map).unwrap();
283 for (i, c) in c.iter().enumerate() {
284 match i {
285 0 => {
286 let c = c.as_basic().unwrap();
287 assert_eq!(c.realm, "foo".into());
288 assert_eq!(c.charset, Some("UTF-8".into()));
289 }
290 1 => {
291 let c = c.as_bearer().unwrap();
292 assert_eq!(c.realm, "bar".into());
293 assert_eq!(c.scope, Some("openid profile email".into()));
294 }
295 i => panic!("{i} {c:?}"),
296 }
297 }
298
299 map.clear();
301 append_www_authenticate(
302 &mut map,
303 &crate::schemes::basic::Challenge::new("foo").into(),
304 )
305 .unwrap();
306 let list = map
307 .get_all(WWW_AUTHENTICATE)
308 .into_iter()
309 .collect::<Vec<_>>();
310 assert_eq!(list.len(), 1);
311 assert_eq!(list[0], r#"Basic realm="foo""#);
312
313 map.clear();
315 append_www_authenticate_with_multiple(
316 &mut map,
317 &[
318 crate::schemes::basic::Challenge::new("foo").into(),
319 crate::schemes::bearer::Challenge::new("bar").into(),
320 ],
321 )
322 .unwrap();
323 let list = map
324 .get_all(WWW_AUTHENTICATE)
325 .into_iter()
326 .collect::<Vec<_>>();
327 assert_eq!(list.len(), 1);
328 assert_eq!(list[0], r#"Basic realm="foo", Bearer realm="bar""#);
329 }
330
331 #[cfg(all(feature = "scheme-basic", feature = "scheme-bearer"))]
332 #[test]
333 fn test_get_append_proxy_authenticate() {
334 let mut map = HeaderMap::new();
336 assert!(get_proxy_authenticate(&map).unwrap().is_empty());
337
338 map.append(
340 PROXY_AUTHENTICATE,
341 r#"Basic realm="foo", charset="UTF-8", Bearer realm="bar", scope="openid profile email""#
342 .parse()
343 .unwrap(),
344 );
345 let c = get_proxy_authenticate(&map).unwrap();
346 for (i, c) in c.iter().enumerate() {
347 match i {
348 0 => {
349 let c = c.as_basic().unwrap();
350 assert_eq!(c.realm, "foo".into());
351 assert_eq!(c.charset, Some("UTF-8".into()));
352 }
353 1 => {
354 let c = c.as_bearer().unwrap();
355 assert_eq!(c.realm, "bar".into());
356 assert_eq!(c.scope, Some("openid profile email".into()));
357 }
358 i => panic!("{i} {c:?}"),
359 }
360 }
361
362 map.clear();
364 map.append(
365 PROXY_AUTHENTICATE,
366 r#"Basic realm="foo", charset="UTF-8""#.parse().unwrap(),
367 );
368 map.append(
369 PROXY_AUTHENTICATE,
370 r#"Bearer realm="bar", scope="openid profile email""#
371 .parse()
372 .unwrap(),
373 );
374 let c = get_proxy_authenticate(&map).unwrap();
375 for (i, c) in c.iter().enumerate() {
376 match i {
377 0 => {
378 let c = c.as_basic().unwrap();
379 assert_eq!(c.realm, "foo".into());
380 assert_eq!(c.charset, Some("UTF-8".into()));
381 }
382 1 => {
383 let c = c.as_bearer().unwrap();
384 assert_eq!(c.realm, "bar".into());
385 assert_eq!(c.scope, Some("openid profile email".into()));
386 }
387 i => panic!("{i} {c:?}"),
388 }
389 }
390
391 map.clear();
393 append_proxy_authenticate(
394 &mut map,
395 &crate::schemes::basic::Challenge::new("foo").into(),
396 )
397 .unwrap();
398 let list = map
399 .get_all(PROXY_AUTHENTICATE)
400 .into_iter()
401 .collect::<Vec<_>>();
402 assert_eq!(list.len(), 1);
403 assert_eq!(list[0], r#"Basic realm="foo""#);
404
405 map.clear();
407 append_proxy_authenticate_with_multiple(
408 &mut map,
409 &[
410 crate::schemes::basic::Challenge::new("foo").into(),
411 crate::schemes::bearer::Challenge::new("bar").into(),
412 ],
413 )
414 .unwrap();
415 let list = map
416 .get_all(PROXY_AUTHENTICATE)
417 .into_iter()
418 .collect::<Vec<_>>();
419 assert_eq!(list.len(), 1);
420 assert_eq!(list[0], r#"Basic realm="foo", Bearer realm="bar""#);
421 }
422}