-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Additional Students Methods (#60)
* Extend `UsersService` Added the `GetGroupsOfStudentAsync` and `GetSemestersOfStudentAsync` methods * Add authorization handler for enrollments * Register view enrollments policy * Update users controller tests * Introduce `IsTeacherOrAdministrator` policy * Update users endpoints tests * Change policies for users endpoints - Allowed all users to access GET method `api/users/teachers`. - Allowed access to GET method `api/users/students` for teachers. * Fix tests * Implement students enrollments endpoints
- Loading branch information
1 parent
82da81b
commit 63db8ad
Showing
10 changed files
with
584 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
EUniversity.Tests/Auth/ViewStudentEnrollmentsAuthorizationHandlerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using EUniversity.Auth; | ||
using EUniversity.Controllers; | ||
using EUniversity.Core.Policy; | ||
using IdentityModel; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Http.Features; | ||
using Microsoft.AspNetCore.Routing; | ||
using System.Security.Claims; | ||
|
||
namespace EUniversity.Tests.Auth; | ||
|
||
public class ViewStudentEnrollmentsAuthorizationHandlerTests | ||
{ | ||
private readonly string TestUserId = Guid.NewGuid().ToString(); | ||
private readonly string TestRouteStudentId = Guid.NewGuid().ToString(); | ||
|
||
private ClaimsPrincipal GetUser(string id, params string[] roles) | ||
{ | ||
List<Claim> claims =new() | ||
{ | ||
new(JwtClaimTypes.Subject, id) | ||
}; | ||
foreach (string role in roles) | ||
{ | ||
claims.Add(new(JwtClaimTypes.Role, role)); | ||
} | ||
ClaimsIdentity identity = new(claims, "Test"); | ||
return new ClaimsPrincipal(identity); | ||
} | ||
|
||
private AuthorizationHandlerContext GetHandlerContext(ClaimsPrincipal user) | ||
{ | ||
RouteValueDictionary routeValues = new() | ||
{ | ||
{ UsersController.StudentIdRouteKey, TestRouteStudentId } | ||
}; | ||
HttpContext httpContext = Substitute.For<HttpContext>(); | ||
var routeValuesFeature = Substitute.For<IRouteValuesFeature>(); | ||
routeValuesFeature.RouteValues.Returns(routeValues); | ||
|
||
httpContext.Features.Get<IRouteValuesFeature>().Returns(routeValuesFeature); | ||
|
||
IAuthorizationRequirement[] requirements = | ||
{ | ||
new ViewStudentEnrollmentsAuthorizationRequirement() | ||
}; | ||
|
||
return new(requirements, user, httpContext); | ||
} | ||
|
||
[Test] | ||
[TestCase(Roles.Administrator)] | ||
[TestCase(Roles.Teacher)] | ||
public async Task AdministratorOrTeacher_Succeeds(string role) | ||
{ | ||
// Arrange | ||
ClaimsPrincipal user = GetUser(TestUserId, role); | ||
AuthorizationHandlerContext context = GetHandlerContext(user); | ||
ViewStudentEnrollmentsAuthorizationHandler handler = new(); | ||
|
||
// Act | ||
await handler.HandleAsync(context); | ||
|
||
// Assert | ||
Assert.That(context.HasSucceeded); | ||
} | ||
|
||
[Test] | ||
public async Task UserAccessesOwnEnrollments_Succeeds() | ||
{ | ||
// Arrange | ||
ClaimsPrincipal user = GetUser(TestRouteStudentId); | ||
AuthorizationHandlerContext context = GetHandlerContext(user); | ||
ViewStudentEnrollmentsAuthorizationHandler handler = new(); | ||
|
||
// Act | ||
await handler.HandleAsync(context); | ||
|
||
// Assert | ||
Assert.That(context.HasSucceeded); | ||
} | ||
|
||
[Test] | ||
public async Task UserAccessesEnrollmentsOfAnotherUser_Fails() | ||
{ | ||
// Arrange | ||
ClaimsPrincipal user = GetUser(TestUserId); | ||
AuthorizationHandlerContext context = GetHandlerContext(user); | ||
ViewStudentEnrollmentsAuthorizationHandler handler = new(); | ||
|
||
// Act | ||
await handler.HandleAsync(context); | ||
|
||
// Assert | ||
Assert.That(context.HasFailed); | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
EUniversity/Auth/ViewStudentEnrollmentsAuthorizationHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
using Duende.IdentityServer.Extensions; | ||
using EUniversity.Controllers; | ||
using EUniversity.Core.Policy; | ||
using IdentityModel; | ||
using Microsoft.AspNetCore.Authorization; | ||
|
||
namespace EUniversity.Auth; | ||
|
||
/// <summary> | ||
/// Authorization handler that determines whether user can view students enrollments. | ||
/// Allows teachers and administrators to view all enrollments and other users to view | ||
/// only their own enrollments. | ||
/// </summary> | ||
public class ViewStudentEnrollmentsAuthorizationHandler : | ||
AuthorizationHandler<ViewStudentEnrollmentsAuthorizationRequirement> | ||
{ | ||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ViewStudentEnrollmentsAuthorizationRequirement requirement) | ||
{ | ||
if (!context.User.IsAuthenticated()) | ||
{ | ||
context.Fail(); | ||
return Task.CompletedTask; | ||
} | ||
// If user is either a teacher or an administrator, | ||
// he/she has an access to all enrollments | ||
if (context.User.HasClaim(JwtClaimTypes.Role, Roles.Teacher) || | ||
context.User.HasClaim(JwtClaimTypes.Role, Roles.Administrator)) | ||
{ | ||
context.Succeed(requirement); | ||
return Task.CompletedTask; | ||
} | ||
|
||
// Get an ID from route values | ||
if (context.Resource is not HttpContext httpContext) | ||
{ | ||
throw new InvalidOperationException("Cannot access HTTP context"); | ||
} | ||
object? routeId = httpContext.GetRouteValue(UsersController.StudentIdRouteKey) ?? | ||
throw new InvalidOperationException($"Cannot get route value of '{UsersController.StudentIdRouteKey}'"); | ||
// Each user can view his/her enrollments | ||
if (context.User.GetSubjectId() == routeId.ToString()) | ||
{ | ||
context.Succeed(requirement); | ||
return Task.CompletedTask; | ||
} | ||
|
||
context.Fail(); | ||
return Task.CompletedTask; | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
EUniversity/Auth/ViewStudentEnrollmentsAuthorizationRequirement.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
using Microsoft.AspNetCore.Authorization; | ||
|
||
namespace EUniversity.Auth; | ||
|
||
public class ViewStudentEnrollmentsAuthorizationRequirement : IAuthorizationRequirement | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.