1- use actix_http:: Request ;
21use actix_web:: {
3- body:: MessageBody ,
42 cookie:: Cookie ,
5- dev:: { Service , ServiceResponse } ,
63 http:: { header, StatusCode } ,
74 test,
85 web:: { self , Data } ,
@@ -12,7 +9,7 @@ use base64::Engine;
129use openidconnect:: url:: Url ;
1310use serde:: { Deserialize , Serialize } ;
1411use serde_json:: json;
15- use sqlpage:: { webserver:: http:: create_app, AppState } ;
12+ use sqlpage:: webserver:: http:: create_app;
1613use std:: collections:: HashMap ;
1714use std:: sync:: { Arc , Mutex } ;
1815use tokio:: sync:: oneshot;
@@ -251,29 +248,6 @@ impl FakeOidcProvider {
251248 }
252249}
253250
254- async fn make_request_with_session < S , B > (
255- app : & S ,
256- mut req : test:: TestRequest ,
257- cookies : & mut Vec < Cookie < ' static > > ,
258- ) -> ServiceResponse < B >
259- where
260- S : Service < Request , Response = ServiceResponse < B > , Error = actix_web:: Error > ,
261- B : MessageBody ,
262- {
263- for cookie in cookies. iter ( ) {
264- req = req. cookie ( cookie. clone ( ) ) ;
265- }
266- let resp = test:: call_service ( app, req. to_request ( ) ) . await ;
267-
268- for new_cookie in extract_set_cookies ( resp. headers ( ) ) {
269- cookies. retain ( |c| c. name ( ) != new_cookie. name ( ) ) ;
270- if !new_cookie. value ( ) . is_empty ( ) {
271- cookies. push ( new_cookie) ;
272- }
273- }
274- resp
275- }
276-
277251fn get_query_param ( url : & Url , name : & str ) -> String {
278252 url. query_pairs ( )
279253 . find ( |( k, _) | k == name)
@@ -282,10 +256,33 @@ fn get_query_param(url: &Url, name: &str) -> String {
282256 . to_string ( )
283257}
284258
285- async fn setup_oidc_test_state (
259+ macro_rules! request_with_cookies {
260+ ( $app: expr, $req: expr, $cookies: expr) => { {
261+ let mut req = $req;
262+ for cookie in $cookies. iter( ) {
263+ req = req. cookie( cookie. clone( ) ) ;
264+ }
265+ let resp = test:: call_service( & $app, req. to_request( ) ) . await ;
266+ for new_cookie in extract_set_cookies( resp. headers( ) ) {
267+ $cookies. retain( |c: & Cookie | c. name( ) != new_cookie. name( ) ) ;
268+ if !new_cookie. value( ) . is_empty( ) {
269+ $cookies. push( new_cookie) ;
270+ }
271+ }
272+ resp
273+ } } ;
274+ }
275+
276+ async fn setup_oidc_test (
286277 provider_mutator : impl FnOnce ( & mut ProviderState ) ,
287- ) -> ( Data < AppState > , FakeOidcProvider ) {
288- use actix_web:: web:: Data ;
278+ ) -> (
279+ impl actix_web:: dev:: Service <
280+ actix_http:: Request ,
281+ Response = actix_web:: dev:: ServiceResponse < impl actix_web:: body:: MessageBody > ,
282+ Error = actix_web:: Error ,
283+ > ,
284+ FakeOidcProvider ,
285+ ) {
289286 use sqlpage:: {
290287 app_config:: { test_database_url, AppConfig } ,
291288 AppState ,
@@ -316,74 +313,8 @@ async fn setup_oidc_test_state(
316313
317314 let config: AppConfig = serde_json:: from_str ( & config_json) . unwrap ( ) ;
318315 let app_state = AppState :: init ( & config) . await . unwrap ( ) ;
319- let app_data = Data :: new ( app_state) ;
320- ( app_data, provider)
321- }
322-
323- async fn perform_oidc_callback < S , B > (
324- app : & S ,
325- provider : & FakeOidcProvider ,
326- protected_path : & str ,
327- state_override : Option < String > ,
328- ) -> ( ServiceResponse < B > , Vec < Cookie < ' static > > )
329- where
330- S : Service < Request , Response = ServiceResponse < B > , Error = actix_web:: Error > ,
331- B : MessageBody ,
332- {
333- let mut cookies: Vec < Cookie < ' static > > = Vec :: new ( ) ;
334-
335- let req = test:: TestRequest :: get ( ) . uri ( protected_path) ;
336- let resp = make_request_with_session ( app, req, & mut cookies) . await ;
337- assert_eq ! ( resp. status( ) , StatusCode :: SEE_OTHER ) ;
338-
339- let location = resp. headers ( ) . get ( "location" ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
340- let auth_url = Url :: parse ( location) . unwrap ( ) ;
341-
342- let state = get_query_param ( & auth_url, "state" ) ;
343- let nonce = get_query_param ( & auth_url, "nonce" ) ;
344- let redirect_uri = get_query_param ( & auth_url, "redirect_uri" ) ;
345-
346- provider. store_auth_code ( "test_auth_code" . to_string ( ) , nonce) ;
347-
348- let callback_state = state_override. unwrap_or ( state) ;
349- let callback_url = format ! (
350- "{}?code=test_auth_code&state={}" ,
351- redirect_uri, callback_state
352- ) ;
353- let parsed_callback_url = Url :: parse ( & callback_url) . unwrap ( ) ;
354- let callback_req = test:: TestRequest :: get ( ) . uri ( & format ! (
355- "{}?{}" ,
356- parsed_callback_url. path( ) ,
357- parsed_callback_url. query( ) . unwrap_or_default( )
358- ) ) ;
359- let callback_resp = make_request_with_session ( app, callback_req, & mut cookies) . await ;
360- ( callback_resp, cookies)
361- }
362-
363- async fn simulate_oidc_login < S , B > (
364- app : & S ,
365- provider : & FakeOidcProvider ,
366- protected_path : & str ,
367- ) -> ServiceResponse < B >
368- where
369- S : Service < Request , Response = ServiceResponse < B > , Error = actix_web:: Error > ,
370- B : MessageBody ,
371- {
372- use actix_web:: { http:: StatusCode , test} ;
373-
374- let ( callback_resp, mut cookies) =
375- perform_oidc_callback ( app, provider, protected_path, None ) . await ;
376- assert_eq ! ( callback_resp. status( ) , StatusCode :: SEE_OTHER ) ;
377-
378- let final_location = callback_resp
379- . headers ( )
380- . get ( "location" )
381- . unwrap ( )
382- . to_str ( )
383- . unwrap ( ) ;
384- assert_eq ! ( final_location, protected_path) ;
385- let final_req = test:: TestRequest :: get ( ) . uri ( final_location) ;
386- make_request_with_session ( app, final_req, & mut cookies) . await
316+ let app = test:: init_service ( create_app ( Data :: new ( app_state) ) ) . await ;
317+ ( app, provider)
387318}
388319
389320#[ actix_web:: test]
@@ -411,21 +342,55 @@ async fn test_fake_provider_discovery() {
411342
412343#[ actix_web:: test]
413344async fn test_oidc_happy_path ( ) {
414- let ( app_data, provider) = setup_oidc_test_state ( |_| { } ) . await ;
415- let app = actix_web:: test:: init_service ( create_app ( app_data. clone ( ) ) ) . await ;
416- let final_resp = simulate_oidc_login ( & app, & provider, "/" ) . await ;
345+ let ( app, provider) = setup_oidc_test ( |_| { } ) . await ;
346+ let mut cookies: Vec < Cookie < ' static > > = Vec :: new ( ) ;
347+
348+ let resp = request_with_cookies ! ( app, test:: TestRequest :: get( ) . uri( "/" ) , cookies) ;
349+ assert_eq ! ( resp. status( ) , StatusCode :: SEE_OTHER ) ;
350+ let auth_url = Url :: parse ( resp. headers ( ) . get ( "location" ) . unwrap ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
351+
352+ let state = get_query_param ( & auth_url, "state" ) ;
353+ let nonce = get_query_param ( & auth_url, "nonce" ) ;
354+ let redirect_uri = get_query_param ( & auth_url, "redirect_uri" ) ;
355+ provider. store_auth_code ( "test_auth_code" . to_string ( ) , nonce) ;
356+
357+ let callback_uri = format ! (
358+ "{}?code=test_auth_code&state={}" ,
359+ Url :: parse( & redirect_uri) . unwrap( ) . path( ) ,
360+ state
361+ ) ;
362+ let callback_resp =
363+ request_with_cookies ! ( app, test:: TestRequest :: get( ) . uri( & callback_uri) , cookies) ;
364+ assert_eq ! ( callback_resp. status( ) , StatusCode :: SEE_OTHER ) ;
365+
366+ let final_resp = request_with_cookies ! ( app, test:: TestRequest :: get( ) . uri( "/" ) , cookies) ;
417367 assert_eq ! ( final_resp. status( ) , StatusCode :: OK ) ;
418368}
419369
420370async fn assert_oidc_login_fails (
421371 provider_mutator : impl FnOnce ( & mut ProviderState ) ,
422372 state_override : Option < String > ,
423373) {
424- let ( app_data, provider) = setup_oidc_test_state ( provider_mutator) . await ;
425- let app = actix_web:: test:: init_service ( create_app ( app_data. clone ( ) ) ) . await ;
374+ let ( app, provider) = setup_oidc_test ( provider_mutator) . await ;
375+ let mut cookies: Vec < Cookie < ' static > > = Vec :: new ( ) ;
376+
377+ let resp = request_with_cookies ! ( app, test:: TestRequest :: get( ) . uri( "/" ) , cookies) ;
378+ assert_eq ! ( resp. status( ) , StatusCode :: SEE_OTHER ) ;
379+ let auth_url = Url :: parse ( resp. headers ( ) . get ( "location" ) . unwrap ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
426380
427- let ( callback_resp, cookies) =
428- perform_oidc_callback ( & app, & provider, "/" , state_override) . await ;
381+ let state = get_query_param ( & auth_url, "state" ) ;
382+ let nonce = get_query_param ( & auth_url, "nonce" ) ;
383+ let redirect_uri = get_query_param ( & auth_url, "redirect_uri" ) ;
384+ provider. store_auth_code ( "test_auth_code" . to_string ( ) , nonce) ;
385+
386+ let callback_state = state_override. unwrap_or ( state) ;
387+ let callback_uri = format ! (
388+ "{}?code=test_auth_code&state={}" ,
389+ Url :: parse( & redirect_uri) . unwrap( ) . path( ) ,
390+ callback_state
391+ ) ;
392+ let callback_resp =
393+ request_with_cookies ! ( app, test:: TestRequest :: get( ) . uri( & callback_uri) , cookies) ;
429394
430395 assert_eq ! ( callback_resp. status( ) , StatusCode :: SEE_OTHER ) ;
431396 let location = callback_resp
0 commit comments