public async Task WhenUserCanAdministerFundingStream_ShouldSucceed() { // Arrange string userId = Guid.NewGuid().ToString(); ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(Constants.ObjectIdentifierClaimType, userId) })); ISpecificationAuthorizationEntity specification = Substitute.For <ISpecificationAuthorizationEntity>(); specification.GetSpecificationId().Returns(WellKnownSpecificationId); AuthorizationHandlerContext authContext = CreateAuthenticationContext(principal, SpecificationActionTypes.CanAdministerFundingStream, specification); EffectiveSpecificationPermission actualPermission = new EffectiveSpecificationPermission { CanAdministerFundingStream = true }; IUsersApiClient usersApiClient = Substitute.For <IUsersApiClient>(); usersApiClient.GetEffectivePermissionsForUser(Arg.Is(userId), Arg.Is(WellKnownSpecificationId)).Returns(new ApiResponse <EffectiveSpecificationPermission>(HttpStatusCode.OK, actualPermission)); IOptions <PermissionOptions> options = Substitute.For <IOptions <PermissionOptions> >(); options.Value.Returns(actualOptions); IFeatureToggle features = Substitute.For <IFeatureToggle>(); features.IsRoleBasedAccessEnabled().Returns(true); SpecificationPermissionHandler authHandler = new SpecificationPermissionHandler(usersApiClient, options, features); // Act await authHandler.HandleAsync(authContext); // Assert authContext.HasSucceeded.Should().BeTrue(); }
public async Task WhenUserCanRefreshPublishedQaForSpecification_ShouldSucceed() { // Arrange string userId = Guid.NewGuid().ToString(); ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(Constants.ObjectIdentifierClaimType, userId) })); string specification = WellKnownSpecificationId; AuthorizationHandlerContext authContext = CreateAuthenticationContext(principal, SpecificationActionTypes.CanRefreshPublishedQa, specification); EffectiveSpecificationPermission actualPermission = new EffectiveSpecificationPermission { CanRefreshPublishedQa = true }; IUsersApiClient usersApiClient = Substitute.For <IUsersApiClient>(); usersApiClient.GetEffectivePermissionsForUser(Arg.Is(userId), Arg.Is(WellKnownSpecificationId)).Returns(new ApiResponse <EffectiveSpecificationPermission>(HttpStatusCode.OK, actualPermission)); IOptions <PermissionOptions> options = Substitute.For <IOptions <PermissionOptions> >(); options.Value.Returns(actualOptions); SpecificationPermissionHandler authHandler = new SpecificationPermissionHandler(usersApiClient, options); // Act await authHandler.HandleAsync(authContext); // Assert authContext.HasSucceeded.Should().BeTrue(); }
public async Task GetEffectivePermissionsForUser_WhenCachedEffectivePermissionFound_ThenOkResultReturned() { // Arrange ICacheProvider cacheProvider = CreateCacheProvider(); EffectiveSpecificationPermission cachedPermission = new EffectiveSpecificationPermission() { UserId = UserId, SpecificationId = SpecificationId, CanApproveFunding = true, CanCreateSpecification = true, CanMapDatasets = false, }; cacheProvider .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)) .Returns(cachedPermission); FundingStreamPermissionService service = CreateService(cacheProvider: cacheProvider); // Act IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId, null); // Assert result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeEquivalentTo(new EffectiveSpecificationPermission() { UserId = UserId, SpecificationId = SpecificationId, CanApproveFunding = true, CanCreateSpecification = true, CanMapDatasets = false, CanChooseFunding = false, CanEditCalculations = false, CanEditSpecification = false, CanPublishFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, CanDeleteSpecification = false }); await cacheProvider .Received(1) .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)); await cacheProvider .Received(0) .SetHashValue( Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId), Arg.Any <EffectiveSpecificationPermission>()); }
private bool HasPermission(SpecificationActionTypes requestedPermission, EffectiveSpecificationPermission actualPermissions) { if (actualPermissions == null) { return(false); } switch (requestedPermission) { case SpecificationActionTypes.CanApproveFunding: return(actualPermissions.CanApproveFunding); case SpecificationActionTypes.CanChooseFunding: return(actualPermissions.CanChooseFunding); case SpecificationActionTypes.CanEditCalculations: return(actualPermissions.CanEditCalculations); case SpecificationActionTypes.CanEditSpecification: return(actualPermissions.CanEditSpecification); case SpecificationActionTypes.CanMapDatasets: return(actualPermissions.CanMapDatasets); case SpecificationActionTypes.CanReleaseFunding: return(actualPermissions.CanReleaseFunding); case SpecificationActionTypes.CanRefreshFunding: return(actualPermissions.CanRefreshFunding); case SpecificationActionTypes.CanCreateQaTests: return(actualPermissions.CanCreateQaTests); case SpecificationActionTypes.CanEditQaTests: return(actualPermissions.CanEditQaTests); case SpecificationActionTypes.CanApproveSpecification: return(actualPermissions.CanApproveSpecification); case SpecificationActionTypes.CanAdministerFundingStream: return(actualPermissions.CanAdministerFundingStream); case SpecificationActionTypes.CanDeleteSpecification: return(actualPermissions.CanDeleteSpecification); case SpecificationActionTypes.CanDeleteCalculations: return(actualPermissions.CanDeleteCalculations); case SpecificationActionTypes.CanDeleteQaTests: return(actualPermissions.CanDeleteQaTests); default: return(false); } }
public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheButSpecificationNotFound_ThenPreconditionFailedResultReturned() { // Arrange ICacheProvider cacheProvider = CreateCacheProvider(); EffectiveSpecificationPermission cachedPermission = null; cacheProvider .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)) .Returns(cachedPermission); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); SpecificationSummary specificationSummary = null; specificationRepository .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(specificationSummary); FundingStreamPermissionService service = CreateService( specificationRepository: specificationRepository, cacheProvider: cacheProvider); // Act IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId, null); // Assert result .Should() .BeOfType <PreconditionFailedResult>() .Which .Value .Should() .Be("Specification not found"); await cacheProvider .Received(1) .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)); await cacheProvider .Received(0) .SetHashValue( Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId), Arg.Any <EffectiveSpecificationPermission>()); }
public async Task <IActionResult> GetEffectivePermissionsForUser(string userId, string specificationId) { if (string.IsNullOrWhiteSpace(userId)) { return(new BadRequestObjectResult($"{nameof(userId)} is empty or null")); } if (string.IsNullOrWhiteSpace(specificationId)) { return(new BadRequestObjectResult($"{nameof(specificationId)} is empty or null")); } EffectiveSpecificationPermission cachedPermissions = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetHashValue <EffectiveSpecificationPermission>($"{CacheKeys.EffectivePermissions}:{userId}", specificationId)); if (cachedPermissions != null) { return(new OkObjectResult(cachedPermissions)); } else { ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId)); if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null) { return(new PreconditionFailedResult("Specification not found")); } SpecModel.SpecificationSummary specification = specificationApiResponse.Content; List <FundingStreamPermission> permissionsForUser = new List <FundingStreamPermission>(); foreach (Reference fundingStream in specification.FundingStreams) { FundingStreamPermission permission = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetFundingStreamPermission(userId, fundingStream.Id)); if (permission != null) { permissionsForUser.Add(permission); } else { // Add permission for this funding stream with no permissions - used further down to calculate permissions (required for pessimistic permissions) permissionsForUser.Add(new FundingStreamPermission { UserId = userId, FundingStreamId = fundingStream.Id, CanApproveFunding = false, CanChooseFunding = false, CanCreateSpecification = false, CanEditCalculations = false, CanEditSpecification = false, CanMapDatasets = false, CanReleaseFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanDeleteCalculations = false, CanDeleteSpecification = false, CanDeleteQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, CanCreateTemplates = false, CanEditTemplates = false, CanDeleteTemplates = false, CanApproveTemplates = false, CanCreateProfilePattern = false, CanEditProfilePattern = false, CanDeleteProfilePattern = false, CanAssignProfilePattern = false, CanApplyCustomProfilePattern = false, CanApproveCalculations = false, CanApproveAnyCalculations = false, CanApproveAllCalculations = false }); } } EffectiveSpecificationPermission specificationPermissions = GeneratePermissions(permissionsForUser, specificationId, userId); string userPermissionHashKey = $"{CacheKeys.EffectivePermissions}:{userId}"; // Does the hash set for this user already exist - used to determine the timeout for the hash set below bool existingHashSetExists = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.HashSetExists(userPermissionHashKey)); // Cache effective permissions for the specification / user await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashValue(userPermissionHashKey, specificationId, specificationPermissions)); // If the hash set does not exist, then set an expiry for the whole hash set. This stops the users permissions being stored indefinitely if (!existingHashSetExists) { await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashExpiry(userPermissionHashKey, DateTime.UtcNow.AddHours(12))); } return(new OkObjectResult(specificationPermissions)); } }
public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheResultsAreQueriedWithMultipleFundingStreamAndNoPermissionsAreInRepository_ThenOkResultReturnedWithNoPermissions() { // Arrange IUserRepository userRepository = CreateUserRepository(); ISpecificationRepository specificationRepository = CreateSpecificationRepository(); ICacheProvider cacheProvider = CreateCacheProvider(); IMapper mapper = CreateMappingConfiguration(); EffectiveSpecificationPermission cachedPermission = null; cacheProvider .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)) .Returns(cachedPermission); SpecificationSummary specificationSummary = new SpecificationSummary() { Id = SpecificationId, FundingStreams = new List <Reference>() { new Reference("fs1", "Funding Stream 1"), new Reference("fs2", "Funding Stream 2") } }; specificationRepository .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(specificationSummary); FundingStreamPermission fs1Permission = null; userRepository .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs1")) .Returns(fs1Permission); FundingStreamPermission fs2Permission = null; userRepository .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs2")) .Returns(fs2Permission); FundingStreamPermissionService service = CreateService(userRepository, specificationRepository, cacheProvider: cacheProvider, mapper: mapper); // Act IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId, null); // Assert result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeEquivalentTo(new EffectiveSpecificationPermission() { UserId = UserId, SpecificationId = SpecificationId, CanApproveFunding = false, CanCreateSpecification = false, CanMapDatasets = false, CanChooseFunding = false, CanEditCalculations = false, CanEditSpecification = false, CanPublishFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, }); await cacheProvider .Received(1) .SetHashValue( Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId), Arg.Is <EffectiveSpecificationPermission>(p => !p.CanApproveFunding && !p.CanChooseFunding && !p.CanCreateSpecification && !p.CanEditCalculations && !p.CanEditSpecification && !p.CanMapDatasets && !p.CanPublishFunding && !p.CanAdministerFundingStream && !p.CanApproveSpecification && !p.CanCreateQaTests && !p.CanEditQaTests && !p.CanRefreshFunding && p.SpecificationId == SpecificationId && p.UserId == UserId )); }
public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheResultsAreQueriedWithMultipleFundingStreamAndUserHasPermissionsButNotAcrossAllFundingStreams_ThenOkResultReturnedWithPermissionsThatOnlyAllFundingStreamsHave() { // Arrange IUserRepository userRepository = CreateUserRepository(); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); ICacheProvider cacheProvider = CreateCacheProvider(); IMapper mapper = CreateMappingConfiguration(); EffectiveSpecificationPermission cachedPermission = null; cacheProvider .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId)) .Returns(cachedPermission); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary() { Id = SpecificationId, FundingStreams = new List <Reference>() { new Reference("fs1", "Funding Stream 1"), new Reference("fs2", "Funding Stream 2"), } }; specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); FundingStreamPermission fs1Permission = new FundingStreamPermission() { UserId = UserId, FundingStreamId = "fs1", CanChooseFunding = false, CanCreateSpecification = true, CanApproveFunding = false, CanEditCalculations = false, CanEditSpecification = false, CanMapDatasets = false, CanReleaseFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, CanCreateProfilePattern = false, CanEditProfilePattern = false, CanDeleteProfilePattern = false, CanAssignProfilePattern = false, CanApplyCustomProfilePattern = false, CanApproveCalculations = true, CanApproveAnyCalculations = false, CanApproveAllCalculations = false }; FundingStreamPermission fs2Permission = new FundingStreamPermission() { UserId = UserId, FundingStreamId = "fs1", CanChooseFunding = false, CanCreateSpecification = true, CanApproveFunding = true, CanEditCalculations = false, CanEditSpecification = false, CanMapDatasets = false, CanReleaseFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, CanCreateProfilePattern = false, CanEditProfilePattern = false, CanDeleteProfilePattern = false, CanAssignProfilePattern = false, CanApplyCustomProfilePattern = false, CanApproveCalculations = true, CanApproveAnyCalculations = false, CanApproveTemplates = false, CanCreateTemplates = false, CanDeleteCalculations = false, CanDeleteQaTests = false, CanDeleteSpecification = false, CanDeleteTemplates = false, CanEditTemplates = false, CanApproveAllCalculations = false }; userRepository .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs1")) .Returns(fs1Permission); userRepository .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs2")) .Returns(fs2Permission); FundingStreamPermissionService service = CreateService(userRepository, specificationsApiClient, cacheProvider: cacheProvider, mapper: mapper); // Act IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId); // Assert result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeEquivalentTo(new EffectiveSpecificationPermission() { UserId = UserId, SpecificationId = SpecificationId, CanApproveFunding = false, CanCreateSpecification = true, CanMapDatasets = false, CanChooseFunding = false, CanEditCalculations = false, CanEditSpecification = false, CanReleaseFunding = false, CanAdministerFundingStream = false, CanApproveSpecification = false, CanCreateQaTests = false, CanEditQaTests = false, CanRefreshFunding = false, CanApproveAnyCalculations = false, CanAssignProfilePattern = false, CanDeleteSpecification = false, CanDeleteQaTests = false, CanDeleteCalculations = false, CanApplyCustomProfilePattern = false, CanApproveCalculations = true, CanApproveAllCalculations = false }); await cacheProvider .Received(1) .SetHashValue( Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId), Arg.Is <EffectiveSpecificationPermission>(p => !p.CanApproveFunding && !p.CanChooseFunding && p.CanCreateSpecification && !p.CanEditCalculations && !p.CanEditSpecification && !p.CanMapDatasets && !p.CanReleaseFunding && !p.CanAdministerFundingStream && !p.CanApproveSpecification && !p.CanCreateQaTests && !p.CanEditQaTests && !p.CanRefreshFunding && p.SpecificationId == SpecificationId && p.UserId == UserId )); }