@@ -10,9 +10,16 @@ import (
10
10
"fmt"
11
11
"net/http"
12
12
"net/http/httptest"
13
+ "net/url"
14
+ "sync"
13
15
"testing"
14
16
"time"
15
17
18
+ "github.com/stretchr/testify/assert"
19
+ "github.com/tidwall/gjson"
20
+
21
+ "github.com/ory/hydra/driver"
22
+
16
23
"github.com/ory/x/pointerx"
17
24
18
25
"github.com/ory/hydra/v2/x"
@@ -276,3 +283,269 @@ func TestGetLoginRequestWithDuplicateAccept(t *testing.T) {
276
283
require .Contains (t , result2 .RedirectTo , "login_verifier" )
277
284
})
278
285
}
286
+
287
+ func TestRevokeConsentSession (t * testing.T ) {
288
+ newWg := func (add int ) * sync.WaitGroup {
289
+ var wg sync.WaitGroup
290
+ wg .Add (add )
291
+ return & wg
292
+ }
293
+
294
+ t .Run ("case=subject=subject-1,client=client-1,session=session-1,trigger_back_channel_logout=true" , func (t * testing.T ) {
295
+ conf := internal .NewConfigurationWithDefaults ()
296
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
297
+ backChannelWG := newWg (1 )
298
+ cl := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {"login-session-1" }, backChannelWG )
299
+ performLoginFlow (t , reg , "1" , cl )
300
+ performLoginFlow (t , reg , "2" , cl )
301
+ performDeleteConsentSession (t , reg , "client-1" , "login-session-1" , true )
302
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
303
+ require .Error (t , x .ErrNotFound , err )
304
+ require .Nil (t , c1 )
305
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
306
+ require .NoError (t , err )
307
+ require .NotNil (t , c2 )
308
+ backChannelWG .Wait ()
309
+ })
310
+
311
+ t .Run ("case=subject=subject-1,client=client-1,session=session-1,trigger_back_channel_logout=false" , func (t * testing.T ) {
312
+ conf := internal .NewConfigurationWithDefaults ()
313
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
314
+ backChannelWG := newWg (0 )
315
+ cl := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {}, backChannelWG )
316
+ performLoginFlow (t , reg , "1" , cl )
317
+ performLoginFlow (t , reg , "2" , cl )
318
+ performDeleteConsentSession (t , reg , "client-1" , "login-session-1" , false )
319
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
320
+ require .Error (t , x .ErrNotFound , err )
321
+ require .Nil (t , c1 )
322
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
323
+ require .NoError (t , err )
324
+ require .NotNil (t , c2 )
325
+ backChannelWG .Wait ()
326
+ })
327
+
328
+ t .Run ("case=subject=subject-1,client=client-1,trigger_back_channel_logout=true" , func (t * testing.T ) {
329
+ conf := internal .NewConfigurationWithDefaults ()
330
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
331
+ backChannelWG := newWg (2 )
332
+ cl := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {"login-session-1" , "login-session-2" }, backChannelWG )
333
+ performLoginFlow (t , reg , "1" , cl )
334
+ performLoginFlow (t , reg , "2" , cl )
335
+
336
+ performDeleteConsentSession (t , reg , "client-1" , nil , true )
337
+
338
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
339
+ require .Error (t , x .ErrNotFound , err )
340
+ require .Nil (t , c1 )
341
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
342
+ require .Error (t , x .ErrNotFound , err )
343
+ require .Nil (t , c2 )
344
+ backChannelWG .Wait ()
345
+ })
346
+
347
+ t .Run ("case=subject=subject-1,client=client-1,trigger_back_channel_logout=false" , func (t * testing.T ) {
348
+ conf := internal .NewConfigurationWithDefaults ()
349
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
350
+ backChannelWG := newWg (0 )
351
+ cl := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {}, backChannelWG )
352
+ performLoginFlow (t , reg , "1" , cl )
353
+ performLoginFlow (t , reg , "2" , cl )
354
+
355
+ performDeleteConsentSession (t , reg , "client-1" , nil , false )
356
+
357
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
358
+ require .Error (t , x .ErrNotFound , err )
359
+ require .Nil (t , c1 )
360
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
361
+ require .Error (t , x .ErrNotFound , err )
362
+ require .Nil (t , c2 )
363
+ backChannelWG .Wait ()
364
+ })
365
+
366
+ t .Run ("case=subject=subject-1,all=true,session=session-1,trigger_back_channel_logout=true" , func (t * testing.T ) {
367
+ conf := internal .NewConfigurationWithDefaults ()
368
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
369
+ backChannelWG := newWg (1 )
370
+ cl1 := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {"login-session-1" }, backChannelWG )
371
+ cl2 := createClientWithBackChannelEndpoint (t , reg , "client-2" , []string {}, backChannelWG )
372
+ performLoginFlow (t , reg , "1" , cl1 )
373
+ performLoginFlow (t , reg , "2" , cl2 )
374
+
375
+ performDeleteConsentSession (t , reg , nil , "login-session-1" , true )
376
+
377
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
378
+ require .Error (t , x .ErrNotFound , err )
379
+ require .Nil (t , c1 )
380
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
381
+ require .NoError (t , err )
382
+ require .NotNil (t , c2 )
383
+ backChannelWG .Wait ()
384
+ })
385
+
386
+ t .Run ("case=subject=subject-1,all=true,session=session-1,trigger_back_channel_logout=false" , func (t * testing.T ) {
387
+ conf := internal .NewConfigurationWithDefaults ()
388
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
389
+ backChannelWG := newWg (0 )
390
+ cl1 := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {}, backChannelWG )
391
+ cl2 := createClientWithBackChannelEndpoint (t , reg , "client-2" , []string {}, backChannelWG )
392
+ performLoginFlow (t , reg , "1" , cl1 )
393
+ performLoginFlow (t , reg , "2" , cl2 )
394
+
395
+ performDeleteConsentSession (t , reg , nil , "login-session-1" , false )
396
+
397
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
398
+ require .Error (t , x .ErrNotFound , err )
399
+ require .Nil (t , c1 )
400
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
401
+ require .NoError (t , err )
402
+ require .NotNil (t , c2 )
403
+ backChannelWG .Wait ()
404
+ })
405
+
406
+ t .Run ("case=subject=subject-1,all=true,trigger_back_channel_logout=true" , func (t * testing.T ) {
407
+ conf := internal .NewConfigurationWithDefaults ()
408
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
409
+ backChannelWG := newWg (2 )
410
+ cl1 := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {"login-session-1" }, backChannelWG )
411
+ cl2 := createClientWithBackChannelEndpoint (t , reg , "client-2" , []string {"login-session-2" }, backChannelWG )
412
+ performLoginFlow (t , reg , "1" , cl1 )
413
+ performLoginFlow (t , reg , "2" , cl2 )
414
+
415
+ performDeleteConsentSession (t , reg , nil , nil , true )
416
+
417
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
418
+ require .Error (t , x .ErrNotFound , err )
419
+ require .Nil (t , c1 )
420
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
421
+ require .Error (t , x .ErrNotFound , err )
422
+ require .Nil (t , c2 )
423
+ backChannelWG .Wait ()
424
+ })
425
+
426
+ t .Run ("case=subject=subject-1,all=true,trigger_back_channel_logout=false" , func (t * testing.T ) {
427
+ conf := internal .NewConfigurationWithDefaults ()
428
+ reg := internal .NewRegistryMemory (t , conf , & contextx.Default {})
429
+ backChannelWG := newWg (0 )
430
+ cl1 := createClientWithBackChannelEndpoint (t , reg , "client-1" , []string {}, backChannelWG )
431
+ cl2 := createClientWithBackChannelEndpoint (t , reg , "client-2" , []string {}, backChannelWG )
432
+ performLoginFlow (t , reg , "1" , cl1 )
433
+ performLoginFlow (t , reg , "2" , cl2 )
434
+
435
+ performDeleteConsentSession (t , reg , nil , nil , false )
436
+
437
+ c1 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-1" )
438
+ require .Error (t , x .ErrNotFound , err )
439
+ require .Nil (t , c1 )
440
+ c2 , err := reg .ConsentManager ().GetConsentRequest (context .Background (), "consent-challenge-2" )
441
+ require .Error (t , x .ErrNotFound , err )
442
+ require .Nil (t , c2 )
443
+ backChannelWG .Wait ()
444
+ })
445
+ }
446
+
447
+ func performDeleteConsentSession (t * testing.T , reg driver.Registry , client , loginSessionId interface {}, triggerBackChannelLogout bool ) {
448
+ conf := internal .NewConfigurationWithDefaults ()
449
+ h := NewHandler (reg , conf )
450
+ r := x .NewRouterAdmin (conf .AdminURL )
451
+ h .SetRoutes (r )
452
+ ts := httptest .NewServer (r )
453
+ defer ts .Close ()
454
+ c := & http.Client {}
455
+
456
+ u , _ := url .Parse (ts .URL + "/admin" + SessionsPath + "/consent" )
457
+ q := u .Query ()
458
+ q .Set ("subject" , "subject-1" )
459
+ if client != nil && len (client .(string )) != 0 {
460
+ q .Set ("client" , client .(string ))
461
+ } else {
462
+ q .Set ("all" , "true" )
463
+ }
464
+ if loginSessionId != nil && len (loginSessionId .(string )) != 0 {
465
+ q .Set ("login_session_id" , loginSessionId .(string ))
466
+ }
467
+ if triggerBackChannelLogout {
468
+ q .Set ("trigger_back_channel_logout" , "true" )
469
+ }
470
+ u .RawQuery = q .Encode ()
471
+ req , err := http .NewRequest (http .MethodDelete , u .String (), nil )
472
+
473
+ require .NoError (t , err )
474
+ _ , err = c .Do (req )
475
+ require .NoError (t , err )
476
+ }
477
+
478
+ func performLoginFlow (t * testing.T , reg driver.Registry , flowId string , cl * client.Client ) {
479
+ subject := "subject-1"
480
+ loginSessionId := "login-session-" + flowId
481
+ loginChallenge := "login-challenge-" + flowId
482
+ consentChallenge := "consent-challenge-" + flowId
483
+ requestURL := "http://192.0.2.1"
484
+
485
+ ls := & LoginSession {
486
+ ID : loginSessionId ,
487
+ Subject : subject ,
488
+ }
489
+ lr := & LoginRequest {
490
+ ID : loginChallenge ,
491
+ Subject : subject ,
492
+ Client : cl ,
493
+ RequestURL : requestURL ,
494
+ Verifier : "login-verifier-" + flowId ,
495
+ SessionID : sqlxx .NullString (loginSessionId ),
496
+ }
497
+ cr := & OAuth2ConsentRequest {
498
+ Client : cl ,
499
+ ID : consentChallenge ,
500
+ Verifier : consentChallenge ,
501
+ CSRF : consentChallenge ,
502
+ Subject : subject ,
503
+ LoginChallenge : sqlxx .NullString (loginChallenge ),
504
+ LoginSessionID : sqlxx .NullString (loginSessionId ),
505
+ }
506
+ hcr := & AcceptOAuth2ConsentRequest {
507
+ ConsentRequest : cr ,
508
+ ID : consentChallenge ,
509
+ WasHandled : true ,
510
+ HandledAt : sqlxx .NullTime (time .Now ().UTC ()),
511
+ }
512
+
513
+ require .NoError (t , reg .ConsentManager ().CreateLoginSession (context .Background (), ls ))
514
+ require .NoError (t , reg .ConsentManager ().CreateLoginRequest (context .Background (), lr ))
515
+ require .NoError (t , reg .ConsentManager ().CreateConsentRequest (context .Background (), cr ))
516
+ _ , err := reg .ConsentManager ().HandleConsentRequest (context .Background (), hcr )
517
+ require .NoError (t , err )
518
+ }
519
+
520
+ func createClientWithBackChannelEndpoint (t * testing.T , reg driver.Registry , clientId string , expectedBackChannelLogoutFlowIds []string , wg * sync.WaitGroup ) * client.Client {
521
+ return func (t * testing.T , key string , wg * sync.WaitGroup , cb func (t * testing.T , logoutToken gjson.Result )) * client.Client {
522
+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
523
+ defer wg .Done ()
524
+ require .NoError (t , r .ParseForm ())
525
+ lt := r .PostFormValue ("logout_token" )
526
+ assert .NotEmpty (t , lt )
527
+ token , err := reg .OpenIDJWTStrategy ().Decode (r .Context (), lt )
528
+ require .NoError (t , err )
529
+ var b bytes.Buffer
530
+ require .NoError (t , json .NewEncoder (& b ).Encode (token .Claims ))
531
+ cb (t , gjson .Parse (b .String ()))
532
+ }))
533
+ t .Cleanup (server .Close )
534
+ c := & client.Client {
535
+ LegacyClientID : clientId ,
536
+ BackChannelLogoutURI : server .URL ,
537
+ }
538
+ err := reg .ClientManager ().CreateClient (context .Background (), c )
539
+ require .NoError (t , err )
540
+ return c
541
+ }(t , clientId , wg , func (t * testing.T , logoutToken gjson.Result ) {
542
+ sid := logoutToken .Get ("sid" ).String ()
543
+ assert .Contains (t , expectedBackChannelLogoutFlowIds , sid )
544
+ for i , v := range expectedBackChannelLogoutFlowIds {
545
+ if v == sid {
546
+ expectedBackChannelLogoutFlowIds = append (expectedBackChannelLogoutFlowIds [:i ], expectedBackChannelLogoutFlowIds [i + 1 :]... )
547
+ break
548
+ }
549
+ }
550
+ })
551
+ }
0 commit comments