The main steps involved in Digest authentication are as follows:
Lots of little nuances: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization#digest
Quite untested:
use ring::digest; fn calculate_digest(username: &str, realm: &str, password: &str, method: &str, uri: &str, nonce: &str, cnonce: &str) -> String { let ha1 = format!("{}:{}:{}", username, realm, password); let ha1_digest = digest::digest(&digest::MD5, ha1.as_bytes()); let ha2 = format!("{}:{}", method, uri); let ha2_digest = digest::digest(&digest::MD5, ha2.as_bytes()); let response = format!("{:x}:{nonce}:{nc}:{cnonce}:{qop}:{ha2}", ha1_digest, nonce, "00000001", cnonce, "auth", ha2_digest); let response_digest = digest::digest(&digest::MD5, response.as_bytes()); format!("{:x}", response_digest) } fn main() { let username = "alice"; let realm = "realm"; let password = "password"; let method = "GET"; let uri = "/path"; let nonce = "1234567890"; let cnonce = "0987654321"; let digest = calculate_digest(username, realm, password, method, uri, nonce, cnonce); println!("Digest: {}", digest); }The main pain point is the extra request to get the
WWW-Authenticate
header with the realm and stuff. I wonder if this can be done in a separate step or something (e.g. have the value ready before sync).
Baikal supports digest auth.
Digest auth requires a round trip before the real request, so the auth mechanism needs to provide an
async
function. This function takes the original request and applies auth to it.In case of basic auth, the above function merely adds a header.
In case of digest auth, the above function does a separate http request to determine the realm and other data, and the adds the header to the original request.