refactor: change the format of www-authenticate (#312)

This commit is contained in:
sigoden 2023-12-07 15:04:14 +08:00 committed by GitHub
parent 5c850256f4
commit 37800f630d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 17 deletions

View file

@ -1,7 +1,9 @@
use crate::{args::Args, server::Response, utils::unix_now};
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use base64::{engine::general_purpose, Engine as _}; use base64::{engine::general_purpose, Engine as _};
use headers::HeaderValue; use headers::HeaderValue;
use hyper::Method; use hyper::{header::WWW_AUTHENTICATE, Method};
use indexmap::IndexMap; use indexmap::IndexMap;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use md5::Context; use md5::Context;
@ -11,8 +13,6 @@ use std::{
}; };
use uuid::Uuid; use uuid::Uuid;
use crate::{args::Args, utils::unix_now};
const REALM: &str = "DUFS"; const REALM: &str = "DUFS";
const DIGEST_AUTH_TIMEOUT: u32 = 604800; // 7 days const DIGEST_AUTH_TIMEOUT: u32 = 604800; // 7 days
@ -258,17 +258,21 @@ impl AccessPerm {
} }
} }
pub fn www_authenticate(args: &Args) -> Result<HeaderValue> { pub fn www_authenticate(res: &mut Response, args: &Args) -> Result<()> {
let value = if args.auth.use_hashed_password { if args.auth.use_hashed_password {
format!("Basic realm=\"{}\"", REALM) let basic = HeaderValue::from_str(&format!("Basic realm=\"{}\"", REALM))?;
res.headers_mut().insert(WWW_AUTHENTICATE, basic);
} else { } else {
let nonce = create_nonce()?; let nonce = create_nonce()?;
format!( let digest = HeaderValue::from_str(&format!(
"Digest realm=\"{}\", nonce=\"{}\", qop=\"auth\", Basic realm=\"{}\"", "Digest realm=\"{}\", nonce=\"{}\", qop=\"auth\"",
REALM, nonce, REALM REALM, nonce
) ))?;
}; let basic = HeaderValue::from_str(&format!("Basic realm=\"{}\"", REALM))?;
Ok(HeaderValue::from_str(&value)?) res.headers_mut().append(WWW_AUTHENTICATE, digest);
res.headers_mut().append(WWW_AUTHENTICATE, basic);
}
Ok(())
} }
pub fn get_auth_user(authorization: &HeaderValue) -> Option<String> { pub fn get_auth_user(authorization: &HeaderValue) -> Option<String> {

View file

@ -21,7 +21,7 @@ use headers::{
}; };
use hyper::header::{ use hyper::header::{
HeaderValue, AUTHORIZATION, CONTENT_DISPOSITION, CONTENT_LENGTH, CONTENT_RANGE, CONTENT_TYPE, HeaderValue, AUTHORIZATION, CONTENT_DISPOSITION, CONTENT_LENGTH, CONTENT_RANGE, CONTENT_TYPE,
RANGE, WWW_AUTHENTICATE, RANGE,
}; };
use hyper::{Body, Method, StatusCode, Uri}; use hyper::{Body, Method, StatusCode, Uri};
use serde::Serialize; use serde::Serialize;
@ -1056,9 +1056,8 @@ impl Server {
fn auth_reject(&self, res: &mut Response) -> Result<()> { fn auth_reject(&self, res: &mut Response) -> Result<()> {
set_webdav_headers(res); set_webdav_headers(res);
res.headers_mut()
.append(WWW_AUTHENTICATE, www_authenticate(&self.args)?); www_authenticate(res, &self.args)?;
// set 401 to make the browser pop up the login box
*res.status_mut() = StatusCode::UNAUTHORIZED; *res.status_mut() = StatusCode::UNAUTHORIZED;
Ok(()) Ok(())
} }

View file

@ -10,7 +10,15 @@ use rstest::rstest;
fn no_auth(#[with(&["--auth", "user:pass@/:rw", "-A"])] server: TestServer) -> Result<(), Error> { fn no_auth(#[with(&["--auth", "user:pass@/:rw", "-A"])] server: TestServer) -> Result<(), Error> {
let resp = reqwest::blocking::get(server.url())?; let resp = reqwest::blocking::get(server.url())?;
assert_eq!(resp.status(), 401); assert_eq!(resp.status(), 401);
assert!(resp.headers().contains_key("www-authenticate")); let values: Vec<&str> = resp
.headers()
.get_all("www-authenticate")
.iter()
.map(|v| v.to_str().unwrap())
.collect();
assert!(values[0].starts_with("Digest"));
assert!(values[1].starts_with("Basic"));
let url = format!("{}file1", server.url()); let url = format!("{}file1", server.url());
let resp = fetch!(b"PUT", &url).body(b"abc".to_vec()).send()?; let resp = fetch!(b"PUT", &url).body(b"abc".to_vec()).send()?;
assert_eq!(resp.status(), 401); assert_eq!(resp.status(), 401);