11use base64:: { engine:: general_purpose:: STANDARD , Engine as _} ;
22use fastly:: http:: { header, StatusCode } ;
33use fastly:: { Request , Response } ;
4- use sha2:: { Digest as _, Sha256 } ;
5- use subtle:: ConstantTimeEq as _;
64
75use crate :: settings:: Settings ;
86
@@ -32,19 +30,7 @@ pub fn enforce_basic_auth(settings: &Settings, req: &Request) -> Option<Response
3230 None => return Some ( unauthorized_response ( ) ) ,
3331 } ;
3432
35- // Hash before comparing to normalise lengths — `ct_eq` on raw byte slices
36- // short-circuits when lengths differ, which would leak credential length.
37- // SHA-256 produces fixed-size digests so the comparison is truly constant-time.
38- //
39- // Note: constant-time guarantees are best-effort on WASM targets because the
40- // runtime optimiser/JIT may re-introduce variable-time paths. This is an
41- // inherent limitation of all constant-time code in managed runtimes.
42- let username_match = Sha256 :: digest ( handler. username . expose ( ) . as_bytes ( ) )
43- . ct_eq ( & Sha256 :: digest ( username. as_bytes ( ) ) ) ;
44- let password_match = Sha256 :: digest ( handler. password . expose ( ) . as_bytes ( ) )
45- . ct_eq ( & Sha256 :: digest ( password. as_bytes ( ) ) ) ;
46-
47- if bool:: from ( username_match & password_match) {
33+ if handler. username == username && handler. password == password {
4834 None
4935 } else {
5036 Some ( unauthorized_response ( ) )
@@ -90,19 +76,24 @@ mod tests {
9076 use base64:: engine:: general_purpose:: STANDARD ;
9177 use fastly:: http:: { header, Method } ;
9278
93- use crate :: test_support:: tests:: create_test_settings;
79+ use crate :: test_support:: tests:: crate_test_settings_str;
80+
81+ fn settings_with_handlers ( ) -> Settings {
82+ let config = crate_test_settings_str ( ) ;
83+ Settings :: from_toml ( & config) . expect ( "should parse settings with handlers" )
84+ }
9485
9586 #[ test]
9687 fn no_challenge_for_non_protected_path ( ) {
97- let settings = create_test_settings ( ) ;
88+ let settings = settings_with_handlers ( ) ;
9889 let req = Request :: new ( Method :: GET , "https://example.com/open" ) ;
9990
10091 assert ! ( enforce_basic_auth( & settings, & req) . is_none( ) ) ;
10192 }
10293
10394 #[ test]
10495 fn challenge_when_missing_credentials ( ) {
105- let settings = create_test_settings ( ) ;
96+ let settings = settings_with_handlers ( ) ;
10697 let req = Request :: new ( Method :: GET , "https://example.com/secure" ) ;
10798
10899 let response = enforce_basic_auth ( & settings, & req) . expect ( "should challenge" ) ;
@@ -115,7 +106,7 @@ mod tests {
115106
116107 #[ test]
117108 fn allow_when_credentials_match ( ) {
118- let settings = create_test_settings ( ) ;
109+ let settings = settings_with_handlers ( ) ;
119110 let mut req = Request :: new ( Method :: GET , "https://example.com/secure/data" ) ;
120111 let token = STANDARD . encode ( "user:pass" ) ;
121112 req. set_header ( header:: AUTHORIZATION , format ! ( "Basic {token}" ) ) ;
@@ -124,20 +115,19 @@ mod tests {
124115 }
125116
126117 #[ test]
127- fn challenge_when_both_credentials_wrong ( ) {
128- let settings = create_test_settings ( ) ;
118+ fn challenge_when_credentials_mismatch ( ) {
119+ let settings = settings_with_handlers ( ) ;
129120 let mut req = Request :: new ( Method :: GET , "https://example.com/secure/data" ) ;
130- let token = STANDARD . encode ( "wrong :wrong" ) ;
121+ let token = STANDARD . encode ( "user :wrong" ) ;
131122 req. set_header ( header:: AUTHORIZATION , format ! ( "Basic {token}" ) ) ;
132123
133- let response = enforce_basic_auth ( & settings, & req)
134- . expect ( "should challenge when both username and password are wrong" ) ;
124+ let response = enforce_basic_auth ( & settings, & req) . expect ( "should challenge" ) ;
135125 assert_eq ! ( response. get_status( ) , StatusCode :: UNAUTHORIZED ) ;
136126 }
137127
138128 #[ test]
139129 fn challenge_when_scheme_is_not_basic ( ) {
140- let settings = create_test_settings ( ) ;
130+ let settings = settings_with_handlers ( ) ;
141131 let mut req = Request :: new ( Method :: GET , "https://example.com/secure" ) ;
142132 req. set_header ( header:: AUTHORIZATION , "Bearer token" ) ;
143133
@@ -147,7 +137,7 @@ mod tests {
147137
148138 #[ test]
149139 fn allow_admin_path_with_valid_credentials ( ) {
150- let settings = create_test_settings ( ) ;
140+ let settings = settings_with_handlers ( ) ;
151141 let mut req = Request :: new ( Method :: POST , "https://example.com/admin/keys/rotate" ) ;
152142 let token = STANDARD . encode ( "admin:admin-pass" ) ;
153143 req. set_header ( header:: AUTHORIZATION , format ! ( "Basic {token}" ) ) ;
@@ -160,7 +150,7 @@ mod tests {
160150
161151 #[ test]
162152 fn challenge_admin_path_with_wrong_credentials ( ) {
163- let settings = create_test_settings ( ) ;
153+ let settings = settings_with_handlers ( ) ;
164154 let mut req = Request :: new ( Method :: POST , "https://example.com/admin/keys/rotate" ) ;
165155 let token = STANDARD . encode ( "admin:wrong" ) ;
166156 req. set_header ( header:: AUTHORIZATION , format ! ( "Basic {token}" ) ) ;
@@ -172,35 +162,11 @@ mod tests {
172162
173163 #[ test]
174164 fn challenge_admin_path_with_missing_credentials ( ) {
175- let settings = create_test_settings ( ) ;
165+ let settings = settings_with_handlers ( ) ;
176166 let req = Request :: new ( Method :: POST , "https://example.com/admin/keys/rotate" ) ;
177167
178168 let response = enforce_basic_auth ( & settings, & req)
179169 . expect ( "should challenge admin path with missing credentials" ) ;
180170 assert_eq ! ( response. get_status( ) , StatusCode :: UNAUTHORIZED ) ;
181171 }
182-
183- #[ test]
184- fn challenge_when_username_wrong_password_correct ( ) {
185- let settings = create_test_settings ( ) ;
186- let mut req = Request :: new ( Method :: GET , "https://example.com/secure/data" ) ;
187- let token = STANDARD . encode ( "wrong:pass" ) ;
188- req. set_header ( header:: AUTHORIZATION , format ! ( "Basic {token}" ) ) ;
189-
190- let response = enforce_basic_auth ( & settings, & req)
191- . expect ( "should challenge when only username is wrong" ) ;
192- assert_eq ! ( response. get_status( ) , StatusCode :: UNAUTHORIZED ) ;
193- }
194-
195- #[ test]
196- fn challenge_when_username_correct_password_wrong ( ) {
197- let settings = create_test_settings ( ) ;
198- let mut req = Request :: new ( Method :: GET , "https://example.com/secure/data" ) ;
199- let token = STANDARD . encode ( "user:wrong" ) ;
200- req. set_header ( header:: AUTHORIZATION , format ! ( "Basic {token}" ) ) ;
201-
202- let response = enforce_basic_auth ( & settings, & req)
203- . expect ( "should challenge when only password is wrong" ) ;
204- assert_eq ! ( response. get_status( ) , StatusCode :: UNAUTHORIZED ) ;
205- }
206172}
0 commit comments