@@ -508,4 +508,256 @@ public async Task WhenPostClientPermissionsWithDuplicatePermission_ShouldReturnC
508508 Assert . Equal ( HttpStatusCode . Conflict , secondResponse . StatusCode ) ;
509509 Assert . Equal ( ClientErrors . ClientAlreadyHasPermission , error ) ;
510510 }
511+
512+ [ Fact ( DisplayName = "[e2e] - when DELETE /clients/{id}/permissions/{permissionId} should revoke permission successfully" ) ]
513+ public async Task WhenDeleteClientPermission_ShouldRevokePermissionSuccessfully ( )
514+ {
515+ /* arrange: resolve required dependencies */
516+ var clientCollection = factory . Services . GetRequiredService < IClientCollection > ( ) ;
517+ var permissionCollection = factory . Services . GetRequiredService < IPermissionCollection > ( ) ;
518+
519+ /* arrange: authenticate user and get access token */
520+ var httpClient = factory . HttpClient . WithRealmHeader ( "master" ) ;
521+ var credentials = new AuthenticationCredentials
522+ {
523+ Username = "federation.testing.user" ,
524+ Password = "federation.testing.password"
525+ } ;
526+
527+ var authenticationResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity/authenticate" , credentials ) ;
528+ var authenticationResult = await authenticationResponse . Content . ReadFromJsonAsync < AuthenticationResult > ( ) ;
529+
530+ Assert . NotNull ( authenticationResult ) ;
531+ Assert . NotEmpty ( authenticationResult . AccessToken ) ;
532+
533+ httpClient . WithAuthorization ( authenticationResult . AccessToken ) ;
534+
535+ /* arrange: create a new client */
536+ var clientPayload = _fixture . Build < ClientCreationScheme > ( )
537+ . With ( client => client . Name , $ "test-client-{ Guid . NewGuid ( ) } ")
538+ . With ( client => client . Flows , [ Grant . ClientCredentials ] )
539+ . With ( client => client . RedirectUris , [ ] )
540+ . Create ( ) ;
541+
542+ var clientResponse = await httpClient . PostAsJsonAsync ( "api/v1/clients" , clientPayload ) ;
543+
544+ Assert . Equal ( HttpStatusCode . Created , clientResponse . StatusCode ) ;
545+
546+ var clientFilters = ClientFilters . WithSpecifications ( )
547+ . WithName ( clientPayload . Name )
548+ . Build ( ) ;
549+
550+ var clients = await clientCollection . GetClientsAsync ( clientFilters , CancellationToken . None ) ;
551+ var client = clients . FirstOrDefault ( ) ;
552+
553+ Assert . NotEmpty ( clients ) ;
554+ Assert . NotNull ( client ) ;
555+
556+ /* arrange: create a new permission */
557+ var permissionPayload = _fixture . Build < PermissionCreationScheme > ( )
558+ . With ( permission => permission . Name , $ "test.permission.{ Guid . NewGuid ( ) } ")
559+ . Create ( ) ;
560+
561+ var permissionResponse = await httpClient . PostAsJsonAsync ( "api/v1/permissions" , permissionPayload ) ;
562+
563+ Assert . Equal ( HttpStatusCode . Created , permissionResponse . StatusCode ) ;
564+
565+ var permissionFilters = PermissionFilters . WithSpecifications ( )
566+ . WithName ( permissionPayload . Name )
567+ . Build ( ) ;
568+
569+ var permissions = await permissionCollection . GetPermissionsAsync ( permissionFilters , CancellationToken . None ) ;
570+ var permission = permissions . FirstOrDefault ( ) ;
571+
572+ Assert . NotEmpty ( permissions ) ;
573+ Assert . NotNull ( permission ) ;
574+
575+ /* arrange: assign permission to client */
576+ var assignPayload = _fixture . Build < AssignClientPermissionScheme > ( )
577+ . With ( assignment => assignment . PermissionName , permission . Name )
578+ . Create ( ) ;
579+
580+ var assignResponse = await httpClient . PostAsJsonAsync ( $ "api/v1/clients/{ client . Id } /permissions", assignPayload ) ;
581+
582+ Assert . Equal ( HttpStatusCode . OK , assignResponse . StatusCode ) ;
583+
584+ /* act: send DELETE request to revoke permission from client */
585+ var response = await httpClient . DeleteAsync ( $ "api/v1/clients/{ client . Id } /permissions/{ permission . Id } ") ;
586+
587+ /* assert: response should be 204 No Content */
588+ Assert . Equal ( HttpStatusCode . NoContent , response . StatusCode ) ;
589+
590+ /* assert: verify permission is no longer in client's permissions list */
591+ var httpResponse = await httpClient . GetAsync ( $ "api/v1/clients/{ client . Id } /permissions") ;
592+ var assignedPermissions = await httpResponse . Content . ReadFromJsonAsync < IReadOnlyCollection < PermissionDetailsScheme > > ( ) ;
593+
594+ Assert . Equal ( HttpStatusCode . OK , httpResponse . StatusCode ) ;
595+
596+ Assert . NotNull ( assignedPermissions ) ;
597+ Assert . DoesNotContain ( assignedPermissions , current => current . Id == permission . Id ) ;
598+ }
599+
600+ [ Fact ( DisplayName = "[e2e] - when DELETE /clients/{id}/permissions/{permissionId} with non-existent client should return 404 #ERROR-2D943" ) ]
601+ public async Task WhenDeleteClientPermissionWithNonExistentClient_ShouldReturnNotFound ( )
602+ {
603+ /* arrange: authenticate user and get access token */
604+ var httpClient = factory . HttpClient . WithRealmHeader ( "master" ) ;
605+ var credentials = new AuthenticationCredentials
606+ {
607+ Username = "federation.testing.user" ,
608+ Password = "federation.testing.password"
609+ } ;
610+
611+ var authenticationResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity/authenticate" , credentials ) ;
612+ var authenticationResult = await authenticationResponse . Content . ReadFromJsonAsync < AuthenticationResult > ( ) ;
613+
614+ Assert . NotNull ( authenticationResult ) ;
615+ Assert . NotEmpty ( authenticationResult . AccessToken ) ;
616+
617+ httpClient . WithAuthorization ( authenticationResult . AccessToken ) ;
618+
619+ /* arrange: prepare request with a non-existent client ID */
620+ var nonExistentClientId = Guid . NewGuid ( ) . ToString ( ) ;
621+ var nonExistentPermissionId = Guid . NewGuid ( ) . ToString ( ) ;
622+
623+ /* act: send DELETE request for non-existent client */
624+ var response = await httpClient . DeleteAsync ( $ "api/v1/clients/{ nonExistentClientId } /permissions/{ nonExistentPermissionId } ") ;
625+ var error = await response . Content . ReadFromJsonAsync < Error > ( ) ;
626+
627+ /* assert: response should be 404 Not Found */
628+ Assert . NotNull ( error ) ;
629+
630+ Assert . Equal ( HttpStatusCode . NotFound , response . StatusCode ) ;
631+ Assert . Equal ( ClientErrors . ClientDoesNotExist , error ) ;
632+ }
633+
634+ [ Fact ( DisplayName = "[e2e] - when DELETE /clients/{id}/permissions/{permissionId} with non-existent permission should return 404 #ERROR-93697" ) ]
635+ public async Task WhenDeleteClientPermissionWithNonExistentPermission_ShouldReturnNotFound ( )
636+ {
637+ /* arrange: resolve required dependencies */
638+ var clientCollection = factory . Services . GetRequiredService < IClientCollection > ( ) ;
639+
640+ /* arrange: authenticate user and get access token */
641+ var httpClient = factory . HttpClient . WithRealmHeader ( "master" ) ;
642+ var credentials = new AuthenticationCredentials
643+ {
644+ Username = "federation.testing.user" ,
645+ Password = "federation.testing.password"
646+ } ;
647+
648+ var authenticationResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity/authenticate" , credentials ) ;
649+ var authenticationResult = await authenticationResponse . Content . ReadFromJsonAsync < AuthenticationResult > ( ) ;
650+
651+ Assert . NotNull ( authenticationResult ) ;
652+ Assert . NotEmpty ( authenticationResult . AccessToken ) ;
653+
654+ httpClient . WithAuthorization ( authenticationResult . AccessToken ) ;
655+
656+ /* arrange: create a new client */
657+ var clientPayload = _fixture . Build < ClientCreationScheme > ( )
658+ . With ( client => client . Name , $ "test-client-{ Guid . NewGuid ( ) } ")
659+ . With ( client => client . Flows , [ Grant . ClientCredentials ] )
660+ . With ( client => client . RedirectUris , [ ] )
661+ . Create ( ) ;
662+
663+ var clientResponse = await httpClient . PostAsJsonAsync ( "api/v1/clients" , clientPayload ) ;
664+
665+ Assert . Equal ( HttpStatusCode . Created , clientResponse . StatusCode ) ;
666+
667+ var clientFilters = ClientFilters . WithSpecifications ( )
668+ . WithName ( clientPayload . Name )
669+ . Build ( ) ;
670+
671+ var clients = await clientCollection . GetClientsAsync ( clientFilters , CancellationToken . None ) ;
672+ var client = clients . FirstOrDefault ( ) ;
673+
674+ Assert . NotEmpty ( clients ) ;
675+ Assert . NotNull ( client ) ;
676+
677+ /* arrange: prepare request with a non-existent permission ID */
678+ var nonExistentPermissionId = Guid . NewGuid ( ) . ToString ( ) ;
679+
680+ /* act: send DELETE request with non-existent permission */
681+ var response = await httpClient . DeleteAsync ( $ "api/v1/clients/{ client . Id } /permissions/{ nonExistentPermissionId } ") ;
682+ var error = await response . Content . ReadFromJsonAsync < Error > ( ) ;
683+
684+ /* assert: response should be 404 Not Found */
685+ Assert . NotNull ( error ) ;
686+
687+ Assert . Equal ( HttpStatusCode . NotFound , response . StatusCode ) ;
688+ Assert . Equal ( PermissionErrors . PermissionDoesNotExist , error ) ;
689+ }
690+
691+ [ Fact ( DisplayName = "[e2e] - when DELETE /clients/{id}/permissions/{permissionId} with permission not assigned should return 409 #ERROR-C2FB0" ) ]
692+ public async Task WhenDeleteClientPermissionWithPermissionNotAssigned_ShouldReturnConflict ( )
693+ {
694+ /* arrange: resolve required dependencies */
695+ var clientCollection = factory . Services . GetRequiredService < IClientCollection > ( ) ;
696+ var permissionCollection = factory . Services . GetRequiredService < IPermissionCollection > ( ) ;
697+
698+ /* arrange: authenticate user and get access token */
699+ var httpClient = factory . HttpClient . WithRealmHeader ( "master" ) ;
700+ var credentials = new AuthenticationCredentials
701+ {
702+ Username = "federation.testing.user" ,
703+ Password = "federation.testing.password"
704+ } ;
705+
706+ var authenticationResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity/authenticate" , credentials ) ;
707+ var authenticationResult = await authenticationResponse . Content . ReadFromJsonAsync < AuthenticationResult > ( ) ;
708+
709+ Assert . NotNull ( authenticationResult ) ;
710+ Assert . NotEmpty ( authenticationResult . AccessToken ) ;
711+
712+ httpClient . WithAuthorization ( authenticationResult . AccessToken ) ;
713+
714+ /* arrange: create a new client */
715+ var clientPayload = _fixture . Build < ClientCreationScheme > ( )
716+ . With ( client => client . Name , $ "test-client-{ Guid . NewGuid ( ) } ")
717+ . With ( client => client . Flows , [ Grant . ClientCredentials ] )
718+ . With ( client => client . RedirectUris , [ ] )
719+ . Create ( ) ;
720+
721+ var clientResponse = await httpClient . PostAsJsonAsync ( "api/v1/clients" , clientPayload ) ;
722+
723+ Assert . Equal ( HttpStatusCode . Created , clientResponse . StatusCode ) ;
724+
725+ var clientFilters = ClientFilters . WithSpecifications ( )
726+ . WithName ( clientPayload . Name )
727+ . Build ( ) ;
728+
729+ var clients = await clientCollection . GetClientsAsync ( clientFilters , CancellationToken . None ) ;
730+ var client = clients . FirstOrDefault ( ) ;
731+
732+ Assert . NotEmpty ( clients ) ;
733+ Assert . NotNull ( client ) ;
734+
735+ /* arrange: create a new permission without assigning it to the client */
736+ var permissionPayload = _fixture . Build < PermissionCreationScheme > ( )
737+ . With ( permission => permission . Name , $ "test.permission.{ Guid . NewGuid ( ) } ")
738+ . Create ( ) ;
739+
740+ var permissionResponse = await httpClient . PostAsJsonAsync ( "api/v1/permissions" , permissionPayload ) ;
741+ var permissionFilters = PermissionFilters . WithSpecifications ( )
742+ . WithName ( permissionPayload . Name )
743+ . Build ( ) ;
744+
745+ Assert . Equal ( HttpStatusCode . Created , permissionResponse . StatusCode ) ;
746+
747+ var permissions = await permissionCollection . GetPermissionsAsync ( permissionFilters , CancellationToken . None ) ;
748+ var permission = permissions . FirstOrDefault ( ) ;
749+
750+ Assert . NotEmpty ( permissions ) ;
751+ Assert . NotNull ( permission ) ;
752+
753+ /* act: send DELETE request for permission not assigned to client */
754+ var response = await httpClient . DeleteAsync ( $ "api/v1/clients/{ client . Id } /permissions/{ permission . Id } ") ;
755+ var error = await response . Content . ReadFromJsonAsync < Error > ( ) ;
756+
757+ /* assert: response should be 409 Conflict */
758+ Assert . NotNull ( error ) ;
759+
760+ Assert . Equal ( HttpStatusCode . Conflict , response . StatusCode ) ;
761+ Assert . Equal ( ClientErrors . PermissionNotAssigned , error ) ;
762+ }
511763}
0 commit comments