1mod digest_authenticator;
5
6pub use digest_authenticator::{DigestAccess, DigestParseError};
7
8#[cfg(test)]
9mod tests {
10 use std::convert::TryFrom;
11
12 use crate::DigestParseError;
13
14 #[test]
15 fn rfc2069() {
16 let rfc2069_test = r#"Digest realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41""#;
17 let mut d = rfc2069_test
18 .parse::<crate::digest_authenticator::DigestAccess>()
19 .unwrap();
20 d.set_username("Mufasa");
21 d.set_password("CircleOfLife");
22 let auth_str = d.generate_authorization("GET", "/dir/index.html", None, None);
23 assert_eq!(
24 auth_str.unwrap(),
25 r#"Digest username="Mufasa", realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", response="1949323746fe6a43ef61f9606e7febea", opaque="5ccc069c403ebaf9f0171e9517f40e41""#
26 );
27 }
28
29 #[test]
30 fn rfc2617() {
31 let rfc2617_test = r#"Digest realm="testrealm@host.com", qop="auth", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41""#;
32 let mut d = rfc2617_test
33 .parse::<crate::digest_authenticator::DigestAccess>()
34 .unwrap();
35 d.set_username("Mufasa");
36 d.set_password("Circle Of Life");
37 let auth_str = d.generate_authorization("GET", "/dir/index.html", None, Some("0a4f113b"));
38 assert_eq!(
39 auth_str.unwrap(),
40 r#"Digest username="Mufasa", realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", qop=auth, algorithm=MD5, nc=00000001, cnonce="0a4f113b", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41""#
41 );
42 }
43
44 #[test]
45 fn rfc7616_md5() {
46 let rfc7616_test = r#"Digest
47 realm="http-auth@example.org",
48 qop="auth, auth-int",
49 algorithm=MD5,
50 nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
51 opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS""#;
52
53 let mut d = rfc7616_test
54 .parse::<crate::digest_authenticator::DigestAccess>()
55 .unwrap();
56 d.set_username("Mufasa");
57 d.set_password("Circle of Life");
58 let auth_str = d.generate_authorization(
59 "GET",
60 "/dir/index.html",
61 None,
62 Some("f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ"),
63 );
64
65 assert_eq!(
66 auth_str.unwrap(),
67 r#"Digest username="Mufasa", realm="http-auth@example.org", nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", uri="/dir/index.html", qop=auth, algorithm=MD5, nc=00000001, cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", response="8ca523f5e9506fed4657c9700eebdbec", opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS""#
68 );
69 }
70
71 #[test]
72 fn rfc7616_sha256() {
73 let rfc7616_test = r#"Digest
74 realm="http-auth@example.org",
75 qop="auth, auth-int",
76 algorithm=SHA-256,
77 nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
78 opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS""#;
79
80 let mut d = rfc7616_test
81 .parse::<crate::digest_authenticator::DigestAccess>()
82 .unwrap();
83 d.set_username("Mufasa");
84 d.set_password("Circle of Life");
85 let auth_str = d.generate_authorization(
86 "GET",
87 "/dir/index.html",
88 None,
89 Some("f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ"),
90 );
91
92 assert_eq!(
93 auth_str.unwrap(),
94 r#"Digest username="Mufasa", realm="http-auth@example.org", nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", uri="/dir/index.html", qop=auth, algorithm=SHA-256, nc=00000001, cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", response="753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1", opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS""#
95 );
96 }
97
98 #[test]
99 fn rfc7616_userhash_512_256() {
100 let rfc7616_userhash_test = r#"Digest
101 realm="api@example.org",
102 qop="auth",
103 algorithm=SHA-512-256,
104 nonce="5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK",
105 opaque="HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS",
106 charset=UTF-8,
107 userhash=true"#;
108
109 let mut d = rfc7616_userhash_test
110 .parse::<crate::digest_authenticator::DigestAccess>()
111 .unwrap();
112 d.set_username("Jäsøn Doe");
113 d.set_password("Secret, or not?");
114 let auth_str = d.generate_authorization(
115 "GET",
116 "/doe.json",
117 None,
118 Some("NTg6RKcb9boFIAS3KrFK9BGeh+iDa/sm6jUMp2wds69v"),
119 );
120
121 assert_eq!(
123 auth_str.unwrap(),
124 r#"Digest username="793263caabb707a56211940d90411ea4a575adeccb7e360aeb624ed06ece9b0b", realm="api@example.org", nonce="5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK", uri="/doe.json", qop=auth, algorithm=SHA-512-256, nc=00000001, cnonce="NTg6RKcb9boFIAS3KrFK9BGeh+iDa/sm6jUMp2wds69v", response="3798d4131c277846293534c3edc11bd8a5e4cdcbff78b05db9d95eeb1cec68a5", opaque="HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS", userhash=true"#
125 );
126 }
127
128 #[test]
129 fn very_short_input() {
130 let short_input = "digest";
131 let r = short_input.parse::<crate::digest_authenticator::DigestAccess>();
132 assert!(r.is_err());
133 assert_eq!(r.unwrap_err(), DigestParseError::Length);
134 }
135
136 #[test]
137 fn short_input() {
138 let short_input = r#"Digest realm=1, nonce=1"#;
139 let r = short_input.parse::<crate::digest_authenticator::DigestAccess>();
140 assert!(r.is_err());
141 }
142
143 #[test]
144 fn incorrect_digest_input() {
145 let bad_input = "digestible Lorem ipsum ";
146 let r = bad_input.parse::<crate::digest_authenticator::DigestAccess>();
147 assert!(r.is_err());
148 assert_eq!(r.unwrap_err(), DigestParseError::InvalidEncoding);
149 }
150
151 #[test]
152 fn missing_realm_input() {
153 let bad_input = "digest Lorem \"ipsum\" dolor";
154 let r = bad_input.parse::<crate::digest_authenticator::DigestAccess>();
155 assert!(r.is_err());
156 assert_eq!(r.unwrap_err(), DigestParseError::MissingRealm);
157 }
158
159 #[test]
160 fn missing_nonce_input() {
161 let missing_nonce = r#"Digest realm="testrealm@host.com""#;
162 let r = missing_nonce.parse::<crate::digest_authenticator::DigestAccess>();
163 assert!(r.is_err());
164 assert_eq!(r.unwrap_err(), DigestParseError::MissingNonce);
165 }
166
167 #[test]
168 fn missing_unterminated_nonce_string_input() {
169 let unterminated_nonce = r#"Digest realm="testrealm@host.com", nonce="testing"#;
170 let r = unterminated_nonce.parse::<crate::digest_authenticator::DigestAccess>();
171 assert!(r.is_err());
172 assert_eq!(r.unwrap_err(), DigestParseError::MissingNonce);
173 }
174
175 #[test]
176 fn invalid_character_at_split() {
177 let invalid_char = r#"Digesţ realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41""#;
178 let r = invalid_char.parse::<crate::digest_authenticator::DigestAccess>();
179 assert!(r.is_err());
180 assert_eq!(r.unwrap_err(), DigestParseError::InvalidEncoding);
181 }
182
183 #[test]
184 #[cfg(feature = "from-headers")]
185 fn from_headers() {
186 const WWW_AUTH_VALUE: &str =
187 r#"Digest realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093""#;
188 let mut headers = http::HeaderMap::new();
189 let r = crate::digest_authenticator::DigestAccess::try_from(&headers);
190 assert!(r.is_err());
191 headers.insert(
192 http::header::WWW_AUTHENTICATE,
193 WWW_AUTH_VALUE.parse().unwrap(),
194 );
195 let r = crate::digest_authenticator::DigestAccess::try_from(&headers);
196 assert!(r.is_ok());
197 }
198}