@@ -179,6 +179,169 @@ public async Task WhenGetUserPermissions_ShouldReturnAssignedPermissions()
179179 }
180180 }
181181
182+ [ Fact ( DisplayName = "[e2e] - when GET /users/{id}/permissions should return both direct and inherited group permissions" ) ]
183+ public async Task WhenGetUserPermissions_ShouldReturnDirectAndInheritedPermissions ( )
184+ {
185+ /* arrange: authenticate user and get access token */
186+ var httpClient = factory . HttpClient . WithRealmHeader ( "master" ) ;
187+ var credentials = new AuthenticationCredentials
188+ {
189+ Username = "federation.testing.user" ,
190+ Password = "federation.testing.password"
191+ } ;
192+
193+ var authenticationResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity/authenticate" , credentials ) ;
194+ var authenticationResult = await authenticationResponse . Content . ReadFromJsonAsync < AuthenticationResult > ( ) ;
195+
196+ Assert . NotNull ( authenticationResult ) ;
197+ Assert . NotEmpty ( authenticationResult . AccessToken ) ;
198+
199+ httpClient . WithAuthorization ( authenticationResult . AccessToken ) ;
200+
201+ /* arrange: create a new user */
202+ var enrollmentCredentials = new IdentityEnrollmentCredentials
203+ {
204+ Username = $ "user.inherited.permissions.{ Guid . NewGuid ( ) } @email.com",
205+ Password = "TestPassword123!"
206+ } ;
207+
208+ var enrollmentResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity" , enrollmentCredentials ) ;
209+ var user = await enrollmentResponse . Content . ReadFromJsonAsync < UserDetailsScheme > ( ) ;
210+
211+ Assert . NotNull ( user ) ;
212+ Assert . Equal ( HttpStatusCode . Created , enrollmentResponse . StatusCode ) ;
213+
214+ /* arrange: create a direct permission */
215+ var directPermissionPayload = _fixture . Build < PermissionCreationScheme > ( )
216+ . With ( permission => permission . Name , $ "test.permission.direct.{ Guid . NewGuid ( ) } ")
217+ . Create ( ) ;
218+
219+ var directPermissionResponse = await httpClient . PostAsJsonAsync ( "api/v1/permissions" , directPermissionPayload ) ;
220+ var directPermission = await directPermissionResponse . Content . ReadFromJsonAsync < PermissionDetailsScheme > ( ) ;
221+
222+ Assert . NotNull ( directPermission ) ;
223+ Assert . Equal ( HttpStatusCode . Created , directPermissionResponse . StatusCode ) ;
224+
225+ /* arrange: assign direct permission to user */
226+ var assignDirectPermissionPayload = new AssignUserPermissionScheme
227+ {
228+ PermissionName = directPermission . Name
229+ } ;
230+
231+ var assignDirectPermissionResponse = await httpClient . PostAsJsonAsync ( $ "api/v1/users/{ user . Id } /permissions", assignDirectPermissionPayload ) ;
232+ Assert . Equal ( HttpStatusCode . NoContent , assignDirectPermissionResponse . StatusCode ) ;
233+
234+ /* arrange: create group and inherited permission */
235+ var groupPayload = _fixture . Build < GroupCreationScheme > ( )
236+ . With ( group => group . Name , $ "test-group-{ Guid . NewGuid ( ) } ")
237+ . Create ( ) ;
238+
239+ var groupResponse = await httpClient . PostAsJsonAsync ( "api/v1/groups" , groupPayload ) ;
240+ var group = await groupResponse . Content . ReadFromJsonAsync < GroupDetailsScheme > ( ) ;
241+
242+ Assert . NotNull ( group ) ;
243+ Assert . Equal ( HttpStatusCode . Created , groupResponse . StatusCode ) ;
244+
245+ var inheritedPermissionPayload = _fixture . Build < PermissionCreationScheme > ( )
246+ . With ( permission => permission . Name , $ "test.permission.inherited.{ Guid . NewGuid ( ) } ")
247+ . Create ( ) ;
248+
249+ var inheritedPermissionResponse = await httpClient . PostAsJsonAsync ( "api/v1/permissions" , inheritedPermissionPayload ) ;
250+ var inheritedPermission = await inheritedPermissionResponse . Content . ReadFromJsonAsync < PermissionDetailsScheme > ( ) ;
251+
252+ Assert . NotNull ( inheritedPermission ) ;
253+ Assert . Equal ( HttpStatusCode . Created , inheritedPermissionResponse . StatusCode ) ;
254+
255+ var assignGroupPermissionPayload = new AssignGroupPermissionScheme
256+ {
257+ PermissionName = inheritedPermission . Name
258+ } ;
259+
260+ var assignGroupPermissionResponse = await httpClient . PostAsJsonAsync ( $ "api/v1/groups/{ group . Id } /permissions", assignGroupPermissionPayload ) ;
261+ Assert . Equal ( HttpStatusCode . OK , assignGroupPermissionResponse . StatusCode ) ;
262+
263+ /* arrange: assign user to group */
264+ var assignUserToGroupPayload = new AssignUserToGroupScheme
265+ {
266+ GroupId = group . Id
267+ } ;
268+
269+ var assignUserToGroupResponse = await httpClient . PostAsJsonAsync ( $ "api/v1/users/{ user . Id } /groups", assignUserToGroupPayload ) ;
270+ Assert . Equal ( HttpStatusCode . NoContent , assignUserToGroupResponse . StatusCode ) ;
271+
272+ /* act: request user permissions */
273+ var response = await httpClient . GetAsync ( $ "api/v1/users/{ user . Id } /permissions") ;
274+ var permissions = await response . Content . ReadFromJsonAsync < IReadOnlyCollection < PermissionDetailsScheme > > ( ) ;
275+
276+ /* assert: should return both direct and inherited permissions */
277+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
278+ Assert . NotNull ( permissions ) ;
279+
280+ Assert . Contains ( permissions , permission => permission . Name == directPermission . Name ) ;
281+ Assert . Contains ( permissions , permission => permission . Name == inheritedPermission . Name ) ;
282+ }
283+
284+ [ Fact ( DisplayName = "[e2e] - when GET /users/{id}/permissions and user has no groups should still return direct permissions" ) ]
285+ public async Task WhenGetUserPermissionsWithUserWithoutGroups_ShouldReturnDirectPermissions ( )
286+ {
287+ /* arrange: authenticate user and get access token */
288+ var httpClient = factory . HttpClient . WithRealmHeader ( "master" ) ;
289+ var credentials = new AuthenticationCredentials
290+ {
291+ Username = "federation.testing.user" ,
292+ Password = "federation.testing.password"
293+ } ;
294+
295+ var authenticationResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity/authenticate" , credentials ) ;
296+ var authenticationResult = await authenticationResponse . Content . ReadFromJsonAsync < AuthenticationResult > ( ) ;
297+
298+ Assert . NotNull ( authenticationResult ) ;
299+ Assert . NotEmpty ( authenticationResult . AccessToken ) ;
300+
301+ httpClient . WithAuthorization ( authenticationResult . AccessToken ) ;
302+
303+ /* arrange: create a new user without assigning any groups */
304+ var enrollmentCredentials = new IdentityEnrollmentCredentials
305+ {
306+ Username = $ "user.no.groups.permissions.{ Guid . NewGuid ( ) } @email.com",
307+ Password = "TestPassword123!"
308+ } ;
309+
310+ var enrollmentResponse = await httpClient . PostAsJsonAsync ( "api/v1/identity" , enrollmentCredentials ) ;
311+ var user = await enrollmentResponse . Content . ReadFromJsonAsync < UserDetailsScheme > ( ) ;
312+
313+ Assert . NotNull ( user ) ;
314+ Assert . Equal ( HttpStatusCode . Created , enrollmentResponse . StatusCode ) ;
315+
316+ /* arrange: create and assign a direct permission */
317+ var permissionPayload = _fixture . Build < PermissionCreationScheme > ( )
318+ . With ( permission => permission . Name , $ "test.permission.direct.only.{ Guid . NewGuid ( ) } ")
319+ . Create ( ) ;
320+
321+ var permissionResponse = await httpClient . PostAsJsonAsync ( "api/v1/permissions" , permissionPayload ) ;
322+ var permission = await permissionResponse . Content . ReadFromJsonAsync < PermissionDetailsScheme > ( ) ;
323+
324+ Assert . NotNull ( permission ) ;
325+ Assert . Equal ( HttpStatusCode . Created , permissionResponse . StatusCode ) ;
326+
327+ var assignPermissionPayload = new AssignUserPermissionScheme
328+ {
329+ PermissionName = permission . Name
330+ } ;
331+
332+ var assignPermissionResponse = await httpClient . PostAsJsonAsync ( $ "api/v1/users/{ user . Id } /permissions", assignPermissionPayload ) ;
333+ Assert . Equal ( HttpStatusCode . NoContent , assignPermissionResponse . StatusCode ) ;
334+
335+ /* act: request user permissions */
336+ var response = await httpClient . GetAsync ( $ "api/v1/users/{ user . Id } /permissions") ;
337+ var permissions = await response . Content . ReadFromJsonAsync < IReadOnlyCollection < PermissionDetailsScheme > > ( ) ;
338+
339+ /* assert: endpoint should work and return direct permissions even without group membership */
340+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
341+ Assert . NotNull ( permissions ) ;
342+ Assert . Contains ( permissions , assigned => assigned . Name == permission . Name ) ;
343+ }
344+
182345 [ Fact ( DisplayName = "[e2e] - when GET /users/{id}/permissions with non-existent user should return 404 #ERROR-E6B32" ) ]
183346 public async Task WhenGetUserPermissionsWithNonExistentUser_ShouldReturnNotFound ( )
184347 {
0 commit comments