@@ -93,6 +93,62 @@ mod tests {
9393 }
9494 }
9595
96+ #[ actix_web:: test]
97+ #[ serial( servers) ]
98+ async fn test_ensure_write_once_blocks_s3_presigned_url ( ) {
99+ let _redis_process = launch_redis_with_delay ( ) ;
100+
101+ let config = RedisConfig {
102+ url : Url :: parse ( "redis://127.0.0.1:5555" ) . unwrap ( ) ,
103+ ..RedisConfig :: default ( )
104+ } ;
105+ let redis_pool = configure_redis_pool ( config) . await ;
106+
107+ let mut actix_app = App :: new ( ) . service (
108+ resource ( "/s3-path" )
109+ . guard ( Get ( ) )
110+ . wrap ( from_fn ( ensure_write_once) )
111+ . to ( mock_success) ,
112+ ) ;
113+
114+ actix_app = actix_app. app_data ( web:: Data :: new ( WriteOnceService :: new ( redis_pool. clone ( ) ) ) ) ;
115+
116+ match redis_pool. get ( ) . await {
117+ Ok ( mut conn) => {
118+ let _: ( ) = conn
119+ . del ( WriteOnceService :: hash_key ( "/s3-path" ) )
120+ . await
121+ . unwrap ( ) ;
122+ }
123+ Err ( _err) => panic ! ( "Failed to get Redis connection" ) ,
124+ }
125+
126+ let app = test:: init_service ( actix_app) . await ;
127+
128+ // First request: an S3 presigned URL (x-amz-expires) should pass and lock
129+ let req = test:: TestRequest :: get ( )
130+ . uri ( "/s3-path?X-Amz-Expires=60&X-Amz-Signature=abc" )
131+ . to_request ( ) ;
132+ let resp = test:: call_service ( & app, req) . await ;
133+ assert_eq ! ( resp. status( ) , 200 ) ;
134+
135+ // Subsequent presigned writes on the same path are denied, whatever the
136+ // parameter casing.
137+ let bypass_attempts = [
138+ "/s3-path?X-Amz-Expires=60&X-Amz-Signature=abc" , // identical
139+ "/s3-path?x-amz-expires=60&x-amz-signature=def" , // lowercased
140+ ] ;
141+
142+ for uri in bypass_attempts {
143+ let req = test:: TestRequest :: get ( ) . uri ( uri) . to_request ( ) ;
144+ let resp = test:: try_call_service ( & app, req) . await ;
145+ match resp {
146+ Ok ( resp) => panic ! ( "Expected 403 for {}, got {}" , uri, resp. status( ) ) ,
147+ Err ( err) => assert_eq ! ( err. error_response( ) . status( ) , 403 ) ,
148+ }
149+ }
150+ }
151+
96152 #[ actix_web:: test]
97153 #[ serial( servers) ]
98154 async fn test_ensure_write_once_skips_private_uri ( ) {
0 commit comments