From f349b4808cce5e5531d4d2101593aa4c1b554784 Mon Sep 17 00:00:00 2001 From: Andreas Isnes Date: Fri, 9 Aug 2024 14:36:51 +0200 Subject: [PATCH] update policy factory --- .../Enums/PolicyAccountType.cs | 14 ++ .../Repositories/Interfaces/IPolicyFactory.cs | 24 ++ .../Interfaces/IPolicyRepository.cs | 117 +++++---- .../Interfaces/IMaskinportenSchemaService.cs | 18 +- .../Interfaces/IPolicyAdministrationPoint.cs | 12 +- .../Interfaces/IPolicyInformationPoint.cs | 7 +- .../Services/MaskinportenSchemaService.cs | 36 +-- .../Services/PolicyAdministrationPoint.cs | 91 +++---- .../Services/PolicyInformationPoint.cs | 10 +- .../Services/PolicyRetrievalPoint.cs | 16 +- ...ersistenceDependencyInjectionExtensions.cs | 38 +-- .../Policy/PolicyFactory.cs | 26 +- .../Policy/PolicyOptions.cs | 19 +- .../Policy/PolicyRepository.cs | 104 ++++++++ .../Policy/PolicyRepositoryV2.cs | 170 ------------- .../PolicyRepository.cs | 235 ------------------ .../Configuration/ConsoleTraceService.cs | 21 +- .../Controllers/DelegationsController.cs | 17 +- .../MaskinportenSchemaController.cs | 33 +-- .../PolicyInformationPointController.cs | 5 +- .../Controllers/RightsInternalController.cs | 10 +- src/Altinn.AccessManagement/Program.cs | 7 +- .../Altinn.AccessManagement.Tests.csproj | 4 + .../Altinn2RightsControllerTest.cs | 18 +- .../AuthorizedPartiesControllerTest.cs | 2 +- .../Controllers/DelegationsControllerTest.cs | 2 +- .../MaskinportenSchemaControllerTest.cs | 30 +-- .../PolicyInformationPointControllerTest.cs | 8 +- ...rceOwnerAuthorizedPartiesControllerTest.cs | 2 +- .../RightsInternalControllerTest.cs | 2 +- .../V2MaskinportenSchemaControllerTest.cs | 2 +- .../Fixtures/PostgresFixture.cs | 6 +- .../Fixtures/WebApplicationFixture.cs | 2 +- .../Mocks/PolicyFactoryMock.cs | 21 ++ .../Mocks/PolicyRepositoryMock.cs | 56 ++--- .../PolicyAdministrationPointTest.cs | 10 +- .../Resolvers/ResolverServiceCollection.cs | 2 +- .../Utils/SetupUtils.cs | 2 +- 38 files changed, 468 insertions(+), 731 deletions(-) create mode 100644 src/Altinn.AccessManagement.Core/Enums/PolicyAccountType.cs create mode 100644 src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyFactory.cs create mode 100644 src/Altinn.AccessManagement.Persistence/Policy/PolicyRepository.cs delete mode 100644 src/Altinn.AccessManagement.Persistence/Policy/PolicyRepositoryV2.cs delete mode 100644 src/Altinn.AccessManagement.Persistence/PolicyRepository.cs create mode 100644 test/Altinn.AccessManagement.Tests/Mocks/PolicyFactoryMock.cs diff --git a/src/Altinn.AccessManagement.Core/Enums/PolicyAccountType.cs b/src/Altinn.AccessManagement.Core/Enums/PolicyAccountType.cs new file mode 100644 index 000000000..aea0d673f --- /dev/null +++ b/src/Altinn.AccessManagement.Core/Enums/PolicyAccountType.cs @@ -0,0 +1,14 @@ +namespace Altinn.AccessManagement.Core.Enums +{ + /// + /// Storage Account + /// + public enum PolicyAccountType + { + ResourceRegister, + + Delegations, + + Metadata, + } +} \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyFactory.cs b/src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyFactory.cs new file mode 100644 index 000000000..067428fcc --- /dev/null +++ b/src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyFactory.cs @@ -0,0 +1,24 @@ +using Altinn.AccessManagement.Core.Enums; + +namespace Altinn.AccessManagement.Core.Repositories.Interfaces; + +/// +/// Create clients for interacting with files +/// +public interface IPolicyFactory +{ + /// + /// Creates a client for interacting with storage + /// + /// which storage account to write blob + /// path of the file + /// + IPolicyRepository Create(PolicyAccountType account, string filepath); + + /// + /// Creates a client for interacting with storage. assuming storage accoutn based on filename. + /// + /// path of the file + /// + IPolicyRepository Create(string filepath); +} \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyRepository.cs b/src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyRepository.cs index baa6bdeae..adfa6a5a3 100644 --- a/src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyRepository.cs +++ b/src/Altinn.AccessManagement.Core/Repositories/Interfaces/IPolicyRepository.cs @@ -1,72 +1,71 @@ using Azure; using Azure.Storage.Blobs.Models; -namespace Altinn.AccessManagement.Core.Repositories.Interfaces +namespace Altinn.AccessManagement.Core.Repositories.Interfaces; + +/// +/// Interface for operations on policy files. +/// +public interface IPolicyRepository { /// - /// Interface for operations on policy files. + /// Gets file stream for the policy file from blob storage, if it exists at the specified path. /// - public interface IPolicyRepository - { - /// - /// Gets file stream for the policy file from blob storage, if it exists at the specified path. - /// - /// The file path. - /// File stream of the policy file - Task GetPolicyAsync(string filepath); + /// cancellation token + /// File stream of the policy file + Task GetPolicyAsync(CancellationToken cancellationToken = default); - /// - /// Gets file stream for the specified version of a policy file from blob storage, if it exists at the specified path. - /// - /// The file path. - /// The blob storage version - /// File stream of the policy file - Task GetPolicyVersionAsync(string filepath, string version); + /// + /// Gets file stream for the specified version of a policy file from blob storage, if it exists at the specified path. + /// + /// The blob storage version + /// cancellation token + /// File stream of the policy file + Task GetPolicyVersionAsync(string version, CancellationToken cancellationToken = default); - /// - /// Writes a file stream to blobstorage to the specified path. - /// - /// The file path. - /// File stream of the policy file to be written - /// Azure response BlobContentInfo - Task> WritePolicyAsync(string filepath, Stream fileStream); + /// + /// Writes a file stream to blobstorage to the specified path. + /// + /// File stream of the policy file to be written + /// cancellation token + /// Azure response BlobContentInfo + Task> WritePolicyAsync(Stream fileStream = null, CancellationToken cancellationToken = default); - /// - /// Writes a file stream to blobstorage to the specified path, including the conditional check that the provided blob lease id is valid. - /// - /// The file path. - /// File stream of the policy file to be written - /// The blob lease id, required to be able to write after a lock - /// Azure response BlobContentInfo - Task> WritePolicyConditionallyAsync(string filepath, Stream fileStream, string blobLeaseId); + /// + /// Writes a file stream to blobstorage to the specified path, including the conditional check that the provided blob lease id is valid. + /// + /// File stream of the policy file to be written + /// The blob lease id, required to be able to write after a lock + /// cancellation token + /// Azure response BlobContentInfo + Task> WritePolicyConditionallyAsync(Stream fileStream, string blobLeaseId, CancellationToken cancellationToken = default); - /// - /// Deletes a specific version of a blob storage file if it exits on the specified path. - /// - /// The file path. - /// The blob storage version - /// - Task DeletePolicyVersionAsync(string filepath, string version); + /// + /// Deletes a specific version of a blob storage file if it exits on the specified path. + /// + /// The blob storage version + /// cancellation token + /// + Task DeletePolicyVersionAsync(string version, CancellationToken cancellationToken = default); - /// - /// Tries to acquire a blob lease on the base blob for the provided filepath. - /// - /// The file path of the base blob to aquire a blob lease on - /// The LeaseId if a release was possible, otherwise null - Task TryAcquireBlobLease(string filepath); + /// + /// Tries to acquire a blob lease on the base blob for the provided filepath. + /// + /// cancellation token + /// The LeaseId if a release was possible, otherwise null + Task TryAcquireBlobLease(CancellationToken cancellationToken = default); - /// - /// Releases a blob lease on the base blob for the provided filepath using the provided leaseId. - /// - /// The file path of the base blob to release - /// The lease id from to release - void ReleaseBlobLease(string filepath, string leaseId); + /// + /// Releases a blob lease on the base blob for the provided filepath using the provided leaseId. + /// + /// The lease id from to release + /// cancellation token + void ReleaseBlobLease(string leaseId, CancellationToken cancellationToken = default); - /// - /// Checks whether there exists a blob at the specified path - /// - /// The file path to check if a blob exists - /// Bool whether the blob exists or not - Task PolicyExistsAsync(string filepath); - } -} + /// + /// Checks whether there exists a blob at the specified path + /// + /// cancellation token + /// Bool whether the blob exists or not + Task PolicyExistsAsync(CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Core/Services/Interfaces/IMaskinportenSchemaService.cs b/src/Altinn.AccessManagement.Core/Services/Interfaces/IMaskinportenSchemaService.cs index 905fefaa7..2ceed7f77 100644 --- a/src/Altinn.AccessManagement.Core/Services/Interfaces/IMaskinportenSchemaService.cs +++ b/src/Altinn.AccessManagement.Core/Services/Interfaces/IMaskinportenSchemaService.cs @@ -13,22 +13,25 @@ public interface IMaskinportenSchemaService /// The user id of the authenticated user performing the delegation /// The authentication level of the authenticated user performing the delegation /// The model describing the right delegation check to perform + /// CancellationToken /// The result of the delegation status check - public Task DelegationCheck(int authenticatedUserId, int authenticatedUserAuthlevel, RightsDelegationCheckRequest request); + public Task DelegationCheck(int authenticatedUserId, int authenticatedUserAuthlevel, RightsDelegationCheckRequest request, CancellationToken cancellationToken = default); /// /// Gets all offered maskinporten schema delegations for a reportee /// /// reportee that delegated resources + /// CancellationToken /// list of delgations - public Task> GetOfferedMaskinportenSchemaDelegations(AttributeMatch party); + public Task> GetOfferedMaskinportenSchemaDelegations(AttributeMatch party, CancellationToken cancellationToken = default); /// /// Gets all received maskinporten schema delegations for a reportee /// /// reportee that delegated resources + /// CancellationToken /// list of delgations - public Task> GetReceivedMaskinportenSchemaDelegations(AttributeMatch party); + public Task> GetReceivedMaskinportenSchemaDelegations(AttributeMatch party, CancellationToken cancellationToken = default); /// /// Gets all the delegations for an admin or owner @@ -36,8 +39,9 @@ public interface IMaskinportenSchemaService /// the organisation number of the supplier org /// the organisation number of the consumer of the resource /// the scope of the resource + /// CancellationToken /// list of delgations - public Task> GetMaskinportenDelegations(string supplierOrg, string consumerOrg, string scope); + public Task> GetMaskinportenDelegations(string supplierOrg, string consumerOrg, string scope, CancellationToken cancellationToken = default); /// /// Performs the delegation on behalf of the from party @@ -45,15 +49,17 @@ public interface IMaskinportenSchemaService /// The user id of the authenticated user performing the delegation /// The authentication level of the authenticated user performing the delegation /// The delegation + /// CancellationToken /// The result of the delegation - public Task DelegateMaskinportenSchema(int authenticatedUserId, int authenticatedUserAuthlevel, DelegationLookup delegation); + public Task DelegateMaskinportenSchema(int authenticatedUserId, int authenticatedUserAuthlevel, DelegationLookup delegation, CancellationToken cancellationToken = default); /// /// Operation to revoke a maskinporten schema delegation /// /// The user id of the authenticated user deleting the delegation /// The delegation lookup model + /// CancellationToken /// The result of the deletion - public Task RevokeMaskinportenSchemaDelegation(int authenticatedUserId, DelegationLookup delegation); + public Task RevokeMaskinportenSchemaDelegation(int authenticatedUserId, DelegationLookup delegation, CancellationToken cancellationToken = default); } } diff --git a/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyAdministrationPoint.cs b/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyAdministrationPoint.cs index ed4fa1e12..3fc8010de 100644 --- a/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyAdministrationPoint.cs +++ b/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyAdministrationPoint.cs @@ -13,28 +13,32 @@ public interface IPolicyAdministrationPoint /// Unique identifier of the organisation responsible for the app. /// Application identifier which is unique within an organisation. /// A stream containing the content of the policy file + /// CancellationToken /// - Task WritePolicyAsync(string org, string app, Stream fileStream); + Task WritePolicyAsync(string org, string app, Stream fileStream, CancellationToken cancellationToken = default); /// /// Trys to sort and store the set of rules as delegation policy files in blob storage. /// /// The set of rules to be delegated + /// CancellationToken /// The list of rules with created Id and result status - Task> TryWriteDelegationPolicyRules(List rules); + Task> TryWriteDelegationPolicyRules(List rules, CancellationToken cancellationToken = default); /// /// Trys to sort and delete the set of rules matching the list of ruleMatches to delete from delegation policy files in blob storage. /// /// Entity to define which rules to be deleted + /// CancellationToken /// The list of rules with created Id and result status - Task> TryDeleteDelegationPolicyRules(List rulesToDelete); + Task> TryDeleteDelegationPolicyRules(List rulesToDelete, CancellationToken cancellationToken = default); /// /// Deletes a List of policies based on input list of matches to remove /// /// entity containing match for all the policies to delete + /// CancellationToken /// A list containing all the policies that is deleted - Task> TryDeleteDelegationPolicies(List policiesToDelete); + Task> TryDeleteDelegationPolicies(List policiesToDelete, CancellationToken cancellationToken = default); } } diff --git a/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyInformationPoint.cs b/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyInformationPoint.cs index e8ca3b3b4..7851b8bad 100644 --- a/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyInformationPoint.cs +++ b/src/Altinn.AccessManagement.Core/Services/Interfaces/IPolicyInformationPoint.cs @@ -14,8 +14,9 @@ public interface IPolicyInformationPoint /// the list of offeredby party ids /// the list of coveredby party ids /// the list of coveredby user ids + /// CancellationToken /// a list of rules that match the lists of org/apps, offeredby ids, and coveredby ids - Task> GetRulesAsync(List resourceIds, List offeredByPartyIds, List coveredByPartyIds, List coveredByUserIds); + Task> GetRulesAsync(List resourceIds, List offeredByPartyIds, List coveredByPartyIds, List coveredByUserIds, CancellationToken cancellationToken = default); /// /// Gets the all rights a user have for a given reportee and resource @@ -41,7 +42,7 @@ public interface IPolicyInformationPoint /// Party id of a user or organization /// The /// - Task> GetReceivedDelegationFromRepository(int partyId, CancellationToken cancellationToken); + Task> GetReceivedDelegationFromRepository(int partyId, CancellationToken cancellationToken = default); /// /// Finds all active offered delegations (not including maskinporten schema) from db, both directly delegated from the party or from it's main unit if the party is a subunit @@ -49,6 +50,6 @@ public interface IPolicyInformationPoint /// Party id of a user or organization /// The /// - Task> GetOfferedDelegationsFromRepository(int partyId, CancellationToken cancellationToken); + Task> GetOfferedDelegationsFromRepository(int partyId, CancellationToken cancellationToken = default); } } diff --git a/src/Altinn.AccessManagement.Core/Services/MaskinportenSchemaService.cs b/src/Altinn.AccessManagement.Core/Services/MaskinportenSchemaService.cs index d27b46e0c..b20f1b2bc 100644 --- a/src/Altinn.AccessManagement.Core/Services/MaskinportenSchemaService.cs +++ b/src/Altinn.AccessManagement.Core/Services/MaskinportenSchemaService.cs @@ -44,7 +44,7 @@ public MaskinportenSchemaService(ILogger logger, IDe } /// - public async Task DelegationCheck(int authenticatedUserId, int authenticatedUserAuthlevel, RightsDelegationCheckRequest request) + public async Task DelegationCheck(int authenticatedUserId, int authenticatedUserAuthlevel, RightsDelegationCheckRequest request, CancellationToken cancellationToken = default) { (DelegationCheckResponse result, ServiceResource resource, Party fromParty) = await ValidateDelegationCheckRequest(request); if (!result.IsValid) @@ -56,7 +56,7 @@ public async Task DelegationCheck(int authenticatedUser // Get all delegable rights RightsQuery rightsQuery = RightsHelper.GetRightsQuery(authenticatedUserId, fromParty.PartyId, resourceRegistryId); - List allDelegableRights = await _pip.GetRights(rightsQuery, getDelegableRights: true, returnAllPolicyRights: true); + List allDelegableRights = await _pip.GetRights(rightsQuery, getDelegableRights: true, returnAllPolicyRights: true, cancellationToken: cancellationToken); if (allDelegableRights == null || allDelegableRights.Count == 0) { result.Errors.Add("right[0].Resource", $"No delegable rights could be found for the resource: {resource}"); @@ -106,7 +106,7 @@ public async Task DelegationCheck(int authenticatedUser } /// - public async Task DelegateMaskinportenSchema(int authenticatedUserId, int authenticatedUserAuthlevel, DelegationLookup delegation) + public async Task DelegateMaskinportenSchema(int authenticatedUserId, int authenticatedUserAuthlevel, DelegationLookup delegation, CancellationToken cancellationToken = default) { (DelegationActionResult result, string resourceRegistryId, Party fromParty, Party toParty) = await ValidateMaskinportenDelegationModel(DelegationActionType.Delegation, delegation); if (!result.IsValid) @@ -116,14 +116,14 @@ public async Task DelegateMaskinportenSchema(int authent // Verify authenticated users delegable rights RightsQuery rightsQuery = RightsHelper.GetRightsQuery(authenticatedUserId, fromParty.PartyId, resourceRegistryId); - List usersDelegableRights = await _pip.GetRights(rightsQuery, getDelegableRights: true); + List usersDelegableRights = await _pip.GetRights(rightsQuery, getDelegableRights: true, cancellationToken: cancellationToken); if (usersDelegableRights == null || usersDelegableRights.Count == 0) { result.Errors.Add("right[0].Resource", $"Authenticated user does not have any delegable rights for the resource: {resourceRegistryId}"); return result; } - if (usersDelegableRights.Any(r => r.RightSources.Any(rs => rs.MinimumAuthenticationLevel > authenticatedUserAuthlevel))) + if (usersDelegableRights.Any(r => r.RightSources.Any(rs => rs.MinimumAuthenticationLevel > authenticatedUserAuthlevel))) { result.Errors.Add("right[0].Resource", $"Authenticated user does not meet the required security level requirement for resource: {resourceRegistryId}"); return result; @@ -143,7 +143,7 @@ public async Task DelegateMaskinportenSchema(int authent }); } - List delegationResult = await _pap.TryWriteDelegationPolicyRules(rulesToDelegate); + List delegationResult = await _pap.TryWriteDelegationPolicyRules(rulesToDelegate, cancellationToken); // Map response if (delegationResult.All(r => r.CreatedSuccessfully)) @@ -164,7 +164,7 @@ public async Task DelegateMaskinportenSchema(int authent } /// - public async Task> GetOfferedMaskinportenSchemaDelegations(AttributeMatch party) + public async Task> GetOfferedMaskinportenSchemaDelegations(AttributeMatch party, CancellationToken cancellationToken = default) { if (party.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SocialSecurityNumberAttribute) { @@ -174,7 +174,7 @@ public async Task> GetOfferedMaskinportenSchemaDelegations(Attr int offeredByPartyId = 0; if (party.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationNumberAttribute) { - Party offeredByParty = await _contextRetrievalService.GetPartyForOrganization(party.Value); + Party offeredByParty = await _contextRetrievalService.GetPartyForOrganization(party.Value, cancellationToken); offeredByPartyId = offeredByParty.PartyId; } else if (party.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute && (!int.TryParse(party.Value, out offeredByPartyId) || offeredByPartyId == 0)) @@ -186,7 +186,7 @@ public async Task> GetOfferedMaskinportenSchemaDelegations(Attr } /// - public async Task> GetReceivedMaskinportenSchemaDelegations(AttributeMatch party) + public async Task> GetReceivedMaskinportenSchemaDelegations(AttributeMatch party, CancellationToken cancellationToken = default) { if (party.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SocialSecurityNumberAttribute) { @@ -196,7 +196,7 @@ public async Task> GetReceivedMaskinportenSchemaDelegations(Att int coveredByPartyId = 0; if (party.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationNumberAttribute) { - Party coveredByParty = await _contextRetrievalService.GetPartyForOrganization(party.Value); + Party coveredByParty = await _contextRetrievalService.GetPartyForOrganization(party.Value, cancellationToken); coveredByPartyId = coveredByParty.PartyId; } else if (party.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute && (!int.TryParse(party.Value, out coveredByPartyId) || coveredByPartyId == 0)) @@ -208,12 +208,12 @@ public async Task> GetReceivedMaskinportenSchemaDelegations(Att } /// - public async Task> GetMaskinportenDelegations(string supplierOrg, string consumerOrg, string scope) + public async Task> GetMaskinportenDelegations(string supplierOrg, string consumerOrg, string scope, CancellationToken cancellationToken = default) { int consumerPartyId = 0; if (!string.IsNullOrEmpty(consumerOrg)) { - Party consumerParty = await _contextRetrievalService.GetPartyForOrganization(consumerOrg); + Party consumerParty = await _contextRetrievalService.GetPartyForOrganization(consumerOrg, cancellationToken); if (consumerParty == null) { throw new ArgumentException($"The specified consumerOrg: {consumerOrg}, is not a valid organization number", nameof(consumerOrg)); @@ -225,14 +225,14 @@ public async Task> GetMaskinportenDelegations(string supplierOr int supplierPartyId = 0; if (!string.IsNullOrEmpty(supplierOrg)) { - Party supplierParty = await _contextRetrievalService.GetPartyForOrganization(supplierOrg); + Party supplierParty = await _contextRetrievalService.GetPartyForOrganization(supplierOrg, cancellationToken); if (supplierParty == null) { throw new ArgumentException($"The specified supplierOrg: {supplierOrg}, is not a valid organization number", nameof(supplierOrg)); } supplierPartyId = supplierParty.PartyId; - } + } if (!RegexUtil.IsValidMaskinportenScope(scope)) { @@ -243,7 +243,7 @@ public async Task> GetMaskinportenDelegations(string supplierOr } /// - public async Task RevokeMaskinportenSchemaDelegation(int authenticatedUserId, DelegationLookup delegation) + public async Task RevokeMaskinportenSchemaDelegation(int authenticatedUserId, DelegationLookup delegation, CancellationToken cancellationToken = default) { (DelegationActionResult result, string resourceRegistryId, Party fromParty, Party toParty) = await ValidateMaskinportenDelegationModel(DelegationActionType.Revoke, delegation); if (!result.IsValid) @@ -253,7 +253,7 @@ public async Task RevokeMaskinportenSchemaDelegation(int List policiesToDelete = DelegationHelper.GetRequestToDeleteResourceRegistryService(authenticatedUserId, resourceRegistryId, fromParty.PartyId, toParty.PartyId); - await _pap.TryDeleteDelegationPolicies(policiesToDelete); + await _pap.TryDeleteDelegationPolicies(policiesToDelete, cancellationToken); return result; } @@ -368,7 +368,7 @@ private async Task> GetReceivedDelegations(int coveredByPartyId return await BuildDelegationsResponse(delegationChanges); } - private async Task> GetAllMaskinportenSchemaDelegations(int supplierPartyId, int consumerPartyId, string scopes) + private async Task> GetAllMaskinportenSchemaDelegations(int supplierPartyId, int consumerPartyId, string scopes, CancellationToken cancellationToken = default) { List delegations = new List(); @@ -378,7 +378,7 @@ private async Task> GetAllMaskinportenSchemaDelegations(int sup return delegations; } - List delegationChanges = await _delegationRepository.GetResourceRegistryDelegationChanges(resources.Select(d => d.Identifier).ToList(), consumerPartyId, supplierPartyId, ResourceType.MaskinportenSchema); + List delegationChanges = await _delegationRepository.GetResourceRegistryDelegationChanges(resources.Select(d => d.Identifier).ToList(), consumerPartyId, supplierPartyId, ResourceType.MaskinportenSchema, cancellationToken); if (delegationChanges.Count == 0) { return delegations; diff --git a/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs b/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs index 62e9b9147..e6a6f48af 100644 --- a/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs +++ b/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs @@ -1,6 +1,5 @@ using System.Net; using System.Text.Json; -using Altinn.AccessManagement.Core.Clients.Interfaces; using Altinn.AccessManagement.Core.Enums; using Altinn.AccessManagement.Core.Helpers; using Altinn.AccessManagement.Core.Models; @@ -21,7 +20,7 @@ public class PolicyAdministrationPoint : IPolicyAdministrationPoint { private readonly ILogger _logger; private readonly IPolicyRetrievalPoint _prp; - private readonly IPolicyRepository _policyRepository; + private readonly IPolicyFactory _policyFactory; private readonly IDelegationMetadataRepository _delegationRepository; private readonly IDelegationChangeEventQueue _eventQueue; private readonly int delegationChangeEventQueueErrorId = 911; @@ -30,21 +29,21 @@ public class PolicyAdministrationPoint : IPolicyAdministrationPoint /// Initializes a new instance of the class. /// /// The policy retrieval point. - /// The policy repository (blob storage). + /// The policy repository (blob storage). /// The delegation change repository (postgresql). /// The delegation change event queue service to post events for any delegation change. /// Logger instance. - public PolicyAdministrationPoint(IPolicyRetrievalPoint policyRetrievalPoint, IPolicyRepository policyRepository, IDelegationMetadataRepository delegationRepository, IDelegationChangeEventQueue eventQueue, ILogger logger) + public PolicyAdministrationPoint(IPolicyRetrievalPoint policyRetrievalPoint, IPolicyFactory policyFactory, IDelegationMetadataRepository delegationRepository, IDelegationChangeEventQueue eventQueue, ILogger logger) { _prp = policyRetrievalPoint; - _policyRepository = policyRepository; + _policyFactory = policyFactory; _delegationRepository = delegationRepository; _eventQueue = eventQueue; _logger = logger; } /// - public async Task WritePolicyAsync(string org, string app, Stream fileStream) + public async Task WritePolicyAsync(string org, string app, Stream fileStream, CancellationToken cancellationToken = default) { if (fileStream == null) { @@ -52,13 +51,13 @@ public async Task WritePolicyAsync(string org, string app, Stream fileStre } string filePath = PolicyHelper.GetAltinnAppsPolicyPath(org, app); - Response response = await _policyRepository.WritePolicyAsync(filePath, fileStream); + Response response = await _policyFactory.Create(filePath).WritePolicyAsync(fileStream, cancellationToken: cancellationToken); return response?.GetRawResponse()?.Status == (int)HttpStatusCode.Created; } /// - public async Task> TryWriteDelegationPolicyRules(List rules) + public async Task> TryWriteDelegationPolicyRules(List rules, CancellationToken cancellationToken = default) { List result = new List(); Dictionary> delegationDict = DelegationHelper.SortRulesByDelegationPolicyPath(rules, out List unsortables); @@ -69,7 +68,7 @@ public async Task> TryWriteDelegationPolicyRules(List rules) try { - writePolicySuccess = await WriteDelegationPolicyInternal(delegationPolicypath, delegationDict[delegationPolicypath]); + writePolicySuccess = await WriteDelegationPolicyInternal(delegationPolicypath, delegationDict[delegationPolicypath], cancellationToken); } catch (Exception ex) { @@ -103,13 +102,13 @@ public async Task> TryWriteDelegationPolicyRules(List rules) } /// - public async Task> TryDeleteDelegationPolicyRules(List rulesToDelete) + public async Task> TryDeleteDelegationPolicyRules(List rulesToDelete, CancellationToken cancellationToken = default) { List result = new List(); foreach (RequestToDelete deleteRequest in rulesToDelete) { - List currentRules = await DeleteRulesInPolicy(deleteRequest); + List currentRules = await DeleteRulesInPolicy(deleteRequest, cancellationToken); if (currentRules != null) { result.AddRange(currentRules); @@ -120,13 +119,13 @@ public async Task> TryDeleteDelegationPolicyRules(List - public async Task> TryDeleteDelegationPolicies(List policiesToDelete) + public async Task> TryDeleteDelegationPolicies(List policiesToDelete, CancellationToken cancellationToken = default) { List result = new List(); foreach (RequestToDelete policyToDelete in policiesToDelete) { - List currentRules = await DeleteAllRulesInPolicy(policyToDelete); + List currentRules = await DeleteAllRulesInPolicy(policyToDelete, cancellationToken); if (currentRules != null) { result.AddRange(currentRules); @@ -136,7 +135,7 @@ public async Task> TryDeleteDelegationPolicies(List return result; } - private async Task WriteDelegationPolicyInternal(string policyPath, List rules) + private async Task WriteDelegationPolicyInternal(string policyPath, List rules, CancellationToken cancellationToken = default) { if (!DelegationHelper.TryGetDelegationParamsFromRule(rules[0], out ResourceAttributeMatchType resourceMatchType, out string resourceId, out string org, out string app, out int offeredByPartyId, out Guid? fromUuid, out UuidType fromUuidType, out Guid? toUuid, out UuidType toUuidType, out int? coveredByPartyId, out int? coveredByUserId, out int? delegatedByUserId, out int? delegatedByPartyId, out DateTime delegatedDateTime) || resourceMatchType == ResourceAttributeMatchType.None) @@ -147,7 +146,7 @@ private async Task WriteDelegationPolicyInternal(string policyPath, List WriteDelegationPolicyInternal(string policyPath, List WriteDelegationPolicyInternal(string policyPath, List WriteDelegationPolicyInternal(string policyPath, List blobResponse = await _policyRepository.WritePolicyConditionallyAsync(policyPath, dataStream, leaseId); + Response blobResponse = await policyClient.WritePolicyConditionallyAsync(dataStream, leaseId, cancellationToken); Response httpResponse = blobResponse.GetRawResponse(); if (httpResponse.Status != (int)HttpStatusCode.Created) { @@ -252,10 +252,10 @@ private async Task WriteDelegationPolicyInternal(string policyPath, List WriteDelegationPolicyInternal(string policyPath, List WriteDelegationPolicyInternal(string policyPath, List> ProcessPolicyFile(string policyPath, ResourceAttributeMatchType resourceMatchType, string resourceId, RequestToDelete deleteRequest) + private async Task> ProcessPolicyFile(string policyPath, ResourceAttributeMatchType resourceMatchType, string resourceId, RequestToDelete deleteRequest, CancellationToken cancellationToken = default) { List currentRules = new List(); + var policyClient = _policyFactory.Create(policyPath); + string leaseId = await policyClient.TryAcquireBlobLease(cancellationToken); - string leaseId = await _policyRepository.TryAcquireBlobLease(policyPath); if (leaseId == null) { _logger.LogError("Could not acquire blob lease lock on delegation policy at path: {policyPath}", policyPath); @@ -306,7 +307,7 @@ private async Task> ProcessPolicyFile(string policyPath, ResourceAttr string coveredBy = DelegationHelper.GetCoveredByFromMatch(deleteRequest.PolicyMatch.CoveredBy, out int? coveredByUserId, out int? coveredByPartyId, out Guid? coveredByUuid, out UuidType coveredByUuidType); string offeredBy = deleteRequest.PolicyMatch.OfferedByPartyId.ToString(); - DelegationChange currentChange = await _delegationRepository.GetCurrentDelegationChange(resourceMatchType, resourceId, deleteRequest.PolicyMatch.OfferedByPartyId, coveredByPartyId, coveredByUserId, coveredByUuid, coveredByUuidType); + DelegationChange currentChange = await _delegationRepository.GetCurrentDelegationChange(resourceMatchType, resourceId, deleteRequest.PolicyMatch.OfferedByPartyId, coveredByPartyId, coveredByUserId, coveredByUuid, coveredByUuidType, cancellationToken); XacmlPolicy existingDelegationPolicy = null; if (currentChange.DelegationChangeType == DelegationChangeType.RevokeLast) @@ -315,7 +316,7 @@ private async Task> ProcessPolicyFile(string policyPath, ResourceAttr return null; } - existingDelegationPolicy = await _prp.GetPolicyVersionAsync(currentChange.BlobStoragePolicyPath, currentChange.BlobStorageVersionId); + existingDelegationPolicy = await _prp.GetPolicyVersionAsync(currentChange.BlobStoragePolicyPath, currentChange.BlobStorageVersionId, cancellationToken); foreach (string ruleId in deleteRequest.RuleIds) { @@ -341,7 +342,7 @@ private async Task> ProcessPolicyFile(string policyPath, ResourceAttr { // Write delegation policy to blob storage MemoryStream dataStream = PolicyHelper.GetXmlMemoryStreamFromXacmlPolicy(existingDelegationPolicy); - response = await _policyRepository.WritePolicyConditionallyAsync(policyPath, dataStream, leaseId); + response = await policyClient.WritePolicyConditionallyAsync(dataStream, leaseId, cancellationToken); } catch (Exception ex) { @@ -360,9 +361,9 @@ private async Task> ProcessPolicyFile(string policyPath, ResourceAttr PerformedByUserId = deleteRequest.DeletedByUserId, BlobStoragePolicyPath = policyPath, BlobStorageVersionId = response.Value.VersionId - }; + }; - change = await _delegationRepository.InsertDelegation(resourceMatchType, change); + change = await _delegationRepository.InsertDelegation(resourceMatchType, change, cancellationToken); if (change == null || (change.DelegationChangeId <= 0 && change.ResourceRegistryDelegationChangeId <= 0)) { // Comment: @@ -392,13 +393,13 @@ private async Task> ProcessPolicyFile(string policyPath, ResourceAttr } finally { - _policyRepository.ReleaseBlobLease(policyPath, leaseId); + policyClient.ReleaseBlobLease(leaseId); } return currentRules; } - private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDelete) + private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDelete, CancellationToken cancellationToken = default) { string coveredBy = DelegationHelper.GetCoveredByFromMatch(policyToDelete.PolicyMatch.CoveredBy, out int? coveredByUserId, out int? coveredByPartyId, out Guid? coveredByUuid, out UuidType coveredByUuidType); @@ -419,13 +420,14 @@ private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDe return null; } - if (!await _policyRepository.PolicyExistsAsync(policyPath)) + var policyClient = _policyFactory.Create(policyPath); + if (!await policyClient.PolicyExistsAsync(cancellationToken)) { _logger.LogWarning("No blob was found for the expected path: {policyPath} this must be removed without upading the database", policyPath); return null; } - string leaseId = await _policyRepository.TryAcquireBlobLease(policyPath); + string leaseId = await policyClient.TryAcquireBlobLease(cancellationToken); if (leaseId == null) { _logger.LogError("Could not acquire blob lease on delegation policy at path: {policyPath}", policyPath); @@ -442,7 +444,7 @@ private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDe return null; } - XacmlPolicy existingDelegationPolicy = await _prp.GetPolicyVersionAsync(currentChange.BlobStoragePolicyPath, currentChange.BlobStorageVersionId); + XacmlPolicy existingDelegationPolicy = await _prp.GetPolicyVersionAsync(currentChange.BlobStoragePolicyPath, currentChange.BlobStorageVersionId, cancellationToken); List currentPolicyRules = new List(); foreach (XacmlRule xacmlRule in existingDelegationPolicy.Rules) { @@ -455,7 +457,7 @@ private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDe try { MemoryStream dataStream = PolicyHelper.GetXmlMemoryStreamFromXacmlPolicy(existingDelegationPolicy); - response = await _policyRepository.WritePolicyConditionallyAsync(policyPath, dataStream, leaseId); + response = await policyClient.WritePolicyConditionallyAsync(dataStream, leaseId, cancellationToken); } catch (Exception ex) { @@ -472,10 +474,10 @@ private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDe CoveredByUserId = coveredByUserId, PerformedByUserId = policyToDelete.DeletedByUserId, BlobStoragePolicyPath = policyPath, - BlobStorageVersionId = response.Value.VersionId + BlobStorageVersionId = response.Value.VersionId }; - change = await _delegationRepository.InsertDelegation(resourceMatchType, change); + change = await _delegationRepository.InsertDelegation(resourceMatchType, change, cancellationToken); if (change == null || (change.DelegationChangeId <= 0 && change.ResourceRegistryDelegationChangeId <= 0)) { // Comment: @@ -506,11 +508,11 @@ private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDe } finally { - _policyRepository.ReleaseBlobLease(policyPath, leaseId); + policyClient.ReleaseBlobLease(leaseId); } } - private async Task> DeleteRulesInPolicy(RequestToDelete rulesToDelete) + private async Task> DeleteRulesInPolicy(RequestToDelete rulesToDelete, CancellationToken cancellationToken = default) { string coveredBy = DelegationHelper.GetCoveredByFromMatch(rulesToDelete.PolicyMatch.CoveredBy, out int? coveredByUserId, out int? coveredByPartyId, out Guid? coveredByUuid, out UuidType coveredByUuidType); @@ -532,13 +534,14 @@ private async Task> DeleteRulesInPolicy(RequestToDelete rulesToDelete return null; } - if (!await _policyRepository.PolicyExistsAsync(policyPath)) + var policyClient = _policyFactory.Create(policyPath); + if (!await policyClient.PolicyExistsAsync(cancellationToken)) { _logger.LogWarning("No blob was found for the expected path: {policyPath} this must be removed without updating the database", policyPath); return null; } - List currentRules = await ProcessPolicyFile(policyPath, resourceMatchType, resourceId, rulesToDelete); + List currentRules = await ProcessPolicyFile(policyPath, resourceMatchType, resourceId, rulesToDelete, cancellationToken); return currentRules; } diff --git a/src/Altinn.AccessManagement.Core/Services/PolicyInformationPoint.cs b/src/Altinn.AccessManagement.Core/Services/PolicyInformationPoint.cs index 4d9fd8eba..7faf69449 100644 --- a/src/Altinn.AccessManagement.Core/Services/PolicyInformationPoint.cs +++ b/src/Altinn.AccessManagement.Core/Services/PolicyInformationPoint.cs @@ -47,15 +47,15 @@ public PolicyInformationPoint(ILogger logger, IPolicyRe } /// - public async Task> GetRulesAsync(List resourceIds, List offeredByPartyIds, List coveredByPartyIds, List coveredByUserIds) + public async Task> GetRulesAsync(List resourceIds, List offeredByPartyIds, List coveredByPartyIds, List coveredByUserIds, CancellationToken cancellationToken = default) { List rules = new List(); - List delegationChanges = await _delegationRepository.GetAllCurrentAppDelegationChanges(offeredByPartyIds, resourceIds, coveredByPartyIds, coveredByUserIds); + List delegationChanges = await _delegationRepository.GetAllCurrentAppDelegationChanges(offeredByPartyIds, resourceIds, coveredByPartyIds, coveredByUserIds, cancellationToken); foreach (DelegationChange delegationChange in delegationChanges) { if (delegationChange.DelegationChangeType != DelegationChangeType.RevokeLast) { - XacmlPolicy policy = await _prp.GetPolicyVersionAsync(delegationChange.BlobStoragePolicyPath, delegationChange.BlobStorageVersionId); + XacmlPolicy policy = await _prp.GetPolicyVersionAsync(delegationChange.BlobStoragePolicyPath, delegationChange.BlobStorageVersionId, cancellationToken); rules.AddRange(GetRulesFromPolicyAndDelegationChange(policy.Rules, delegationChange)); } } @@ -147,7 +147,7 @@ public async Task> GetRights(RightsQuery rightsQuery, bool returnAll } /// - public async Task> GetReceivedDelegationFromRepository(int partyId, CancellationToken cancellationToken) + public async Task> GetReceivedDelegationFromRepository(int partyId, CancellationToken cancellationToken = default) { var party = await _contextRetrievalService.GetPartyAsync(partyId, cancellationToken); @@ -224,7 +224,7 @@ public async Task GetAllDelegations(DelegationChangeInput return result; } - private async Task> FindAllDelegations(int subjectUserId, int subjectPartyId, Guid subjectUuid, UuidType subjectUuidType, int reporteePartyId, string resourceId, ResourceAttributeMatchType resourceMatchType, CancellationToken cancellationToken) + private async Task> FindAllDelegations(int subjectUserId, int subjectPartyId, Guid subjectUuid, UuidType subjectUuidType, int reporteePartyId, string resourceId, ResourceAttributeMatchType resourceMatchType, CancellationToken cancellationToken = default) { if (resourceMatchType == ResourceAttributeMatchType.None) { diff --git a/src/Altinn.AccessManagement.Core/Services/PolicyRetrievalPoint.cs b/src/Altinn.AccessManagement.Core/Services/PolicyRetrievalPoint.cs index 6e82c0ea1..094bc6e23 100644 --- a/src/Altinn.AccessManagement.Core/Services/PolicyRetrievalPoint.cs +++ b/src/Altinn.AccessManagement.Core/Services/PolicyRetrievalPoint.cs @@ -14,19 +14,19 @@ namespace Altinn.AccessManagement.Core.Services /// public class PolicyRetrievalPoint : IPolicyRetrievalPoint { - private readonly IPolicyRepository _repository; + private readonly IPolicyFactory _policyFactory; private readonly IMemoryCache _memoryCache; private readonly CacheConfig _cacheConfig; /// /// Initializes a new instance of the class. /// - /// The policy Repository.. - /// The cache handler + /// The policy factory + /// The cache handler /// The cache config settings - public PolicyRetrievalPoint(IPolicyRepository policyRepository, IMemoryCache memoryCache, IOptions cacheConfig) + public PolicyRetrievalPoint(IPolicyFactory policyFactory, IMemoryCache memoryCache, IOptions cacheConfig) { - _repository = policyRepository; + _policyFactory = policyFactory; _memoryCache = memoryCache; _cacheConfig = cacheConfig.Value; } @@ -63,8 +63,8 @@ private async Task GetPolicyInternalAsync(string policyPath, string if (!_memoryCache.TryGetValue(policyPath + version, out XacmlPolicy policy)) { Stream policyBlob = string.IsNullOrEmpty(version) ? - await _repository.GetPolicyAsync(policyPath) : - await _repository.GetPolicyVersionAsync(policyPath, version); + await _policyFactory.Create(policyPath).GetPolicyAsync(cancellationToken) : + await _policyFactory.Create(policyPath).GetPolicyVersionAsync(version, cancellationToken); using (policyBlob) { policy = (policyBlob.Length > 0) ? PolicyHelper.ParsePolicy(policyBlob) : null; @@ -85,4 +85,4 @@ private void PutXacmlPolicyInCache(string policyPath, XacmlPolicy policy) _memoryCache.Set(policyPath, policy, cacheEntryOptions); } } -} +} \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Persistence/Extensions/PersistenceDependencyInjectionExtensions.cs b/src/Altinn.AccessManagement.Persistence/Extensions/PersistenceDependencyInjectionExtensions.cs index 5e7fbfde6..e3e9a3389 100644 --- a/src/Altinn.AccessManagement.Persistence/Extensions/PersistenceDependencyInjectionExtensions.cs +++ b/src/Altinn.AccessManagement.Persistence/Extensions/PersistenceDependencyInjectionExtensions.cs @@ -1,4 +1,5 @@ -using Altinn.AccessManagement.Core.Models; +using Altinn.AccessManagement.Core.Enums; +using Altinn.AccessManagement.Core.Models; using Altinn.AccessManagement.Core.Repositories.Interfaces; using Altinn.AccessManagement.Enums; using Altinn.AccessManagement.Persistence.Configuration; @@ -42,7 +43,7 @@ public static IServiceCollection AddAccessManagementPersistence( services.AddSingleton(); } - services.AdDelegationPolicyRepository(); + services.AddDelegationPolicyRepository(config); return services; } @@ -51,27 +52,8 @@ public static IServiceCollection AddAccessManagementPersistence( /// Registers a with the dependency injection container. /// /// The . - /// for further chaining. - public static IServiceCollection AdDelegationPolicyRepository( - this IServiceCollection services) - { - services.AddOptions() - .Validate(s => !string.IsNullOrEmpty(s.DelegationsAccountKey), "account key cannot be null or empty") - .Validate(s => !string.IsNullOrEmpty(s.DelegationsAccountName), "account name cannot be null or empty") - .Validate(s => !string.IsNullOrEmpty(s.DelegationsContainer), "container cannot be null or empty") - .Validate(s => !string.IsNullOrEmpty(s.DelegationsBlobEndpoint), "blob endpoint cannot be null or empty"); - - services.TryAddSingleton(); - - return services; - } - - /// - /// Registers a with the dependency injection container. - /// - /// The . /// The . - public static IServiceCollection AddDelegationPolicyRepositoryV2(this IServiceCollection services, IConfiguration configuration) + public static IServiceCollection AddDelegationPolicyRepository(this IServiceCollection services, IConfiguration configuration) { var config = new AzureStorageConfiguration(); @@ -79,12 +61,12 @@ public static IServiceCollection AddDelegationPolicyRepositoryV2(this IServiceCo .GetRequiredSection(nameof(AzureStorageConfiguration)) .Bind(config); - services.AddDelegationPolicyRepositoryV2(options => + services.AddDelegationPolicyRepository(options => { options.AddRange([ - new(AccountType.Delegations, config.DelegationsAccountName, config.DelegationsContainer, config.DelegationsBlobEndpoint, config.DelegationsAccountKey, config.BlobLeaseTimeout), - new(AccountType.Metadata, config.MetadataAccountName, config.MetadataContainer, config.MetadataBlobEndpoint, config.MetadataAccountKey, config.BlobLeaseTimeout), - new(AccountType.ResourceRegister, config.ResourceRegistryAccountName, config.ResourceRegistryContainer, config.ResourceRegistryBlobEndpoint, config.ResourceRegistryAccountKey, config.BlobLeaseTimeout), + new(PolicyAccountType.Delegations, config.DelegationsAccountName, config.DelegationsContainer, config.DelegationsBlobEndpoint, config.DelegationsAccountKey, config.BlobLeaseTimeout), + new(PolicyAccountType.Metadata, config.MetadataAccountName, config.MetadataContainer, config.MetadataBlobEndpoint, config.MetadataAccountKey, config.BlobLeaseTimeout), + new(PolicyAccountType.ResourceRegister, config.ResourceRegistryAccountName, config.ResourceRegistryContainer, config.ResourceRegistryBlobEndpoint, config.ResourceRegistryAccountKey, config.BlobLeaseTimeout), ]); }); @@ -92,12 +74,12 @@ public static IServiceCollection AddDelegationPolicyRepositoryV2(this IServiceCo } /// - /// Registers a with the dependency injection container. + /// Registers a with the dependency injection container. /// /// The . /// options for configuring blob service /// for further chaining. - public static IServiceCollection AddDelegationPolicyRepositoryV2(this IServiceCollection services, Action> configureOptions) + public static IServiceCollection AddDelegationPolicyRepository(this IServiceCollection services, Action> configureOptions) { var options = new List(); configureOptions(options); diff --git a/src/Altinn.AccessManagement.Persistence/Policy/PolicyFactory.cs b/src/Altinn.AccessManagement.Persistence/Policy/PolicyFactory.cs index c6784a3a8..7dfc109fb 100644 --- a/src/Altinn.AccessManagement.Persistence/Policy/PolicyFactory.cs +++ b/src/Altinn.AccessManagement.Persistence/Policy/PolicyFactory.cs @@ -1,3 +1,5 @@ +using Altinn.AccessManagement.Core.Enums; +using Altinn.AccessManagement.Core.Repositories.Interfaces; using Azure.Storage.Blobs; using Microsoft.Extensions.Azure; using Microsoft.Extensions.Options; @@ -19,7 +21,7 @@ public class PolicyFactory(IAzureClientFactory factory, IOpti public IOptionsFactory Options { get; } = options; /// - public IPolicyRepositoryV2 Create(AccountType account, string filepath) + public IPolicyRepository Create(PolicyAccountType account, string filepath) { var options = Options.Create(account.ToString()); var client = Factory @@ -27,20 +29,14 @@ public IPolicyRepositoryV2 Create(AccountType account, string filepath) .CreateBlobContainer(options.Container).Value .GetBlobClient(filepath); - return new PolicyRepositoryV2(client, options); + return new PolicyRepository(client, options); } -} -/// -/// Create clients for interacting with files -/// -public interface IPolicyFactory -{ - /// - /// Creates a client for interacting with storage - /// - /// which storage account to write blob - /// path of the file - /// - IPolicyRepositoryV2 Create(AccountType account, string filepath); + /// + public IPolicyRepository Create(string filepath) => filepath switch + { + var blob when blob.EndsWith("delegationpolicy.xml") => Create(PolicyAccountType.Delegations, filepath), + var blob when blob.EndsWith("resourcepolicy.xml") => Create(PolicyAccountType.ResourceRegister, filepath), + _ => Create(PolicyAccountType.Metadata, filepath), + }; } \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Persistence/Policy/PolicyOptions.cs b/src/Altinn.AccessManagement.Persistence/Policy/PolicyOptions.cs index e0e37258a..5814d5da9 100644 --- a/src/Altinn.AccessManagement.Persistence/Policy/PolicyOptions.cs +++ b/src/Altinn.AccessManagement.Persistence/Policy/PolicyOptions.cs @@ -1,17 +1,18 @@ using System.ComponentModel.DataAnnotations; +using Altinn.AccessManagement.Core.Enums; namespace Altinn.AccessManagement.Persistence.Policy; /// /// Options for configuring storage account /// -public class PolicyOptions(AccountType account, string accountName, string container, string uri, string key, int leaseAcquireTimeoutInSec = 3) +public class PolicyOptions(PolicyAccountType account, string accountName, string container, string uri, string key, int leaseAcquireTimeoutInSec = 3) { /// /// Specifies Storage Account. Mostly used as a symbol for consumer for making it simpler to targeting storage account /// [Required] - public AccountType Account { get; set; } = account; + public PolicyAccountType Account { get; set; } = account; /// /// AzureRM account name @@ -41,16 +42,4 @@ public class PolicyOptions(AccountType account, string accountName, string conta /// Timeout for some specific operations. Defaults to 3 seconds /// public TimeSpan LeaseAcquireTimeout { get; set; } = TimeSpan.FromSeconds(leaseAcquireTimeoutInSec); -} - -/// -/// Storage Account -/// -public enum AccountType -{ - ResourceRegister, - - Delegations, - - Metadata, -} +} \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Persistence/Policy/PolicyRepository.cs b/src/Altinn.AccessManagement.Persistence/Policy/PolicyRepository.cs new file mode 100644 index 000000000..93d6c0e31 --- /dev/null +++ b/src/Altinn.AccessManagement.Persistence/Policy/PolicyRepository.cs @@ -0,0 +1,104 @@ +using System.Diagnostics; +using Altinn.AccessManagement.Core.Repositories.Interfaces; +using Altinn.AccessManagement.Persistence.Configuration; +using Altinn.AccessManagement.Persistence.Extensions; +using Azure; +using Azure.Storage.Blobs; +using Azure.Storage.Blobs.Models; +using Azure.Storage.Blobs.Specialized; + +namespace Altinn.AccessManagement.Persistence.Policy; + +/// +public class PolicyRepository(BlobClient client, PolicyOptions options) : IPolicyRepository +{ + /// + /// Azure Blob Storage client + /// + public BlobClient Client { get; } = client; + + /// + /// Policy Options + /// + public PolicyOptions Options { get; } = options; + + private static async Task RoundTripper(Func> func) + { + using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); + try + { + return await func(); + } + catch (RequestFailedException ex) + { + activity.StopWithError(ex); + throw; + } + catch (Exception ex) + { + activity.StopWithError(ex); + throw; + } + } + + /// + public async Task DeletePolicyVersionAsync(string version, CancellationToken cancellationToken = default) + { + var result = await RoundTripper(async () => await Client.WithVersion(version).DeleteAsync(cancellationToken: cancellationToken)); + return result; + } + + /// + public async Task GetPolicyAsync(CancellationToken cancellationToken = default) + { + var result = await RoundTripper(async () => await Client.DownloadStreamingAsync(cancellationToken: cancellationToken)); + return result.Value.Content; + } + + /// + public async Task GetPolicyVersionAsync(string version, CancellationToken cancellationToken = default) + { + var result = await RoundTripper(async () => await Client.WithVersion(version).DownloadStreamingAsync(cancellationToken: cancellationToken)); + return result.Value.Content; + } + + /// + public async Task PolicyExistsAsync(CancellationToken cancellationToken = default) + { + return await RoundTripper(async () => await Client.ExistsAsync(cancellationToken: cancellationToken)); + } + + /// + public async void ReleaseBlobLease(string leaseId, CancellationToken cancellationToken = default) + { + await RoundTripper(async () => await Client.GetBlobLeaseClient(leaseId).ReleaseAsync(cancellationToken: cancellationToken)); + } + + /// + public async Task TryAcquireBlobLease(CancellationToken cancellationToken = default) + { + var result = await RoundTripper(async () => await Client.GetBlobLeaseClient().AcquireAsync(Options.LeaseAcquireTimeout, cancellationToken: cancellationToken)); + return result.Value.LeaseId; + } + + /// + public async Task> WritePolicyAsync(Stream fileStream = null, CancellationToken cancellationToken = default) + { + return await RoundTripper(async () => await Client.UploadAsync(fileStream ?? new MemoryStream(), true, cancellationToken)); + } + + /// + public async Task> WritePolicyConditionallyAsync(Stream fileStream, string blobLeaseId, CancellationToken cancellationToken = default) + { + return await RoundTripper(async () => await Client.UploadAsync( + fileStream, + new BlobUploadOptions() + { + Conditions = new() + { + LeaseId = blobLeaseId, + } + }, + cancellationToken)); + } +} \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Persistence/Policy/PolicyRepositoryV2.cs b/src/Altinn.AccessManagement.Persistence/Policy/PolicyRepositoryV2.cs deleted file mode 100644 index 8692f2888..000000000 --- a/src/Altinn.AccessManagement.Persistence/Policy/PolicyRepositoryV2.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System.Diagnostics; -using Altinn.AccessManagement.Persistence.Configuration; -using Altinn.AccessManagement.Persistence.Extensions; -using Azure; -using Azure.Storage.Blobs; -using Azure.Storage.Blobs.Models; -using Azure.Storage.Blobs.Specialized; - -namespace Altinn.AccessManagement.Persistence.Policy; - -/// -public class PolicyRepositoryV2(BlobClient client, PolicyOptions options) : IPolicyRepositoryV2 -{ - /// - /// Azure Blob Storage client - /// - public BlobClient Client { get; } = client; - - /// - /// Policy Options - /// - public PolicyOptions Options { get; } = options; - - private static async Task RoundTripper(Func> func) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - try - { - return await func(); - } - catch (RequestFailedException ex) - { - activity.StopWithError(ex); - throw; - } - catch (Exception ex) - { - activity.StopWithError(ex); - throw; - } - } - - /// - public async Task DeletePolicyVersionAsync(string version, CancellationToken cancellationToken = default) - { - var result = await RoundTripper(async () => await Client.WithVersion(version).DeleteAsync(cancellationToken: cancellationToken)); - return result; - } - - /// - public async Task GetPolicyAsync(CancellationToken cancellationToken = default) - { - var result = await RoundTripper(async () => await Client.DownloadStreamingAsync(cancellationToken: cancellationToken)); - return result.Value.Content; - } - - /// - public async Task GetPolicyVersionAsync(string version, CancellationToken cancellationToken = default) - { - var result = await RoundTripper(async () => await Client.WithVersion(version).DownloadStreamingAsync(cancellationToken: cancellationToken)); - return result.Value.Content; - } - - /// - public async Task PolicyExistsAsync(CancellationToken cancellationToken = default) - { - return await RoundTripper(async () => await Client.ExistsAsync(cancellationToken: cancellationToken)); - } - - /// - public async void ReleaseBlobLease(string leaseId, CancellationToken cancellationToken = default) - { - await RoundTripper(async () => await Client.GetBlobLeaseClient(leaseId).ReleaseAsync(cancellationToken: cancellationToken)); - } - - /// - public async Task TryAcquireBlobLease(CancellationToken cancellationToken = default) - { - var result = await RoundTripper(async () => await Client.GetBlobLeaseClient().AcquireAsync(Options.LeaseAcquireTimeout, cancellationToken: cancellationToken)); - return result.Value.LeaseId; - } - - /// - public async Task> WritePolicyAsync(Stream fileStream, CancellationToken cancellationToken = default) - { - return await RoundTripper(async () => await Client.UploadAsync(fileStream, true, cancellationToken)); - } - - /// - public async Task> WritePolicyConditionallyAsync(Stream fileStream, string blobLeaseId, CancellationToken cancellationToken = default) - { - return await RoundTripper(async () => await Client.UploadAsync( - fileStream, - new BlobUploadOptions() - { - Conditions = new() - { - LeaseId = blobLeaseId, - } - }, - cancellationToken)); - } -} - -/// -/// Interface for operations on policy files. -/// -public interface IPolicyRepositoryV2 -{ - /// - /// Gets file stream for the policy file from blob storage, if it exists at the specified path. - /// - /// cancellation token - /// File stream of the policy file - Task GetPolicyAsync(CancellationToken cancellationToken = default); - - /// - /// Gets file stream for the specified version of a policy file from blob storage, if it exists at the specified path. - /// - /// The blob storage version - /// cancellation token - /// File stream of the policy file - Task GetPolicyVersionAsync(string version, CancellationToken cancellationToken = default); - - /// - /// Writes a file stream to blobstorage to the specified path. - /// - /// File stream of the policy file to be written - /// cancellation token - /// Azure response BlobContentInfo - Task> WritePolicyAsync(Stream fileStream, CancellationToken cancellationToken = default); - - /// - /// Writes a file stream to blobstorage to the specified path, including the conditional check that the provided blob lease id is valid. - /// - /// File stream of the policy file to be written - /// The blob lease id, required to be able to write after a lock - /// cancellation token - /// Azure response BlobContentInfo - Task> WritePolicyConditionallyAsync(Stream fileStream, string blobLeaseId, CancellationToken cancellationToken = default); - - /// - /// Deletes a specific version of a blob storage file if it exits on the specified path. - /// - /// The blob storage version - /// cancellation token - /// - Task DeletePolicyVersionAsync(string version, CancellationToken cancellationToken = default); - - /// - /// Tries to acquire a blob lease on the base blob for the provided filepath. - /// - /// cancellation token - /// The LeaseId if a release was possible, otherwise null - Task TryAcquireBlobLease(CancellationToken cancellationToken = default); - - /// - /// Releases a blob lease on the base blob for the provided filepath using the provided leaseId. - /// - /// The lease id from to release - /// cancellation token - void ReleaseBlobLease(string leaseId, CancellationToken cancellationToken = default); - - /// - /// Checks whether there exists a blob at the specified path - /// - /// cancellation token - /// Bool whether the blob exists or not - Task PolicyExistsAsync(CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/Altinn.AccessManagement.Persistence/PolicyRepository.cs b/src/Altinn.AccessManagement.Persistence/PolicyRepository.cs deleted file mode 100644 index 9067ea8f3..000000000 --- a/src/Altinn.AccessManagement.Persistence/PolicyRepository.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Net; -using Altinn.AccessManagement.Core.Repositories.Interfaces; -using Altinn.AccessManagement.Persistence.Configuration; -using Altinn.AccessManagement.Persistence.Extensions; -using Azure; -using Azure.Storage; -using Azure.Storage.Blobs; -using Azure.Storage.Blobs.Models; -using Azure.Storage.Blobs.Specialized; -using Microsoft.Extensions.Options; -using OpenTelemetry.Trace; - -namespace Altinn.AccessManagement.Persistence -{ - /// - /// Repository for handling policy files - /// - [ExcludeFromCodeCoverage] - public class PolicyRepository : IPolicyRepository - { - private readonly AzureStorageConfiguration _storageConfig; - private readonly BlobContainerClient _metadataContainerClient; - private readonly BlobContainerClient _delegationsContainerClient; - private readonly BlobContainerClient _resourceRegisterContainerClient; - - /// - /// Initializes a new instance of the class - /// - /// The storage configuration for Azure Blob Storage. - public PolicyRepository(IOptions storageConfig) - { - _storageConfig = storageConfig.Value; - - StorageSharedKeyCredential metadataCredentials = new StorageSharedKeyCredential(_storageConfig.MetadataAccountName, _storageConfig.MetadataAccountKey); - BlobServiceClient metadataServiceClient = new BlobServiceClient(new Uri(_storageConfig.MetadataBlobEndpoint), metadataCredentials); - _metadataContainerClient = metadataServiceClient.GetBlobContainerClient(_storageConfig.MetadataContainer); - - StorageSharedKeyCredential delegationsCredentials = new StorageSharedKeyCredential(_storageConfig.DelegationsAccountName, _storageConfig.DelegationsAccountKey); - BlobServiceClient delegationsServiceClient = new BlobServiceClient(new Uri(_storageConfig.DelegationsBlobEndpoint), delegationsCredentials); - _delegationsContainerClient = delegationsServiceClient.GetBlobContainerClient(_storageConfig.DelegationsContainer); - - StorageSharedKeyCredential resourceRegisterCredentials = new StorageSharedKeyCredential(_storageConfig.ResourceRegistryAccountName, _storageConfig.ResourceRegistryAccountKey); - BlobServiceClient resourceRegisterServiceClient = new BlobServiceClient(new Uri(_storageConfig.ResourceRegistryBlobEndpoint), resourceRegisterCredentials); - _resourceRegisterContainerClient = resourceRegisterServiceClient.GetBlobContainerClient(_storageConfig.ResourceRegistryContainer); - } - - /// - public async Task GetPolicyAsync(string filepath) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - BlobClient blobClient = CreateBlobClient(filepath); - - return await GetBlobStreamInternal(blobClient); - } - - /// - public async Task GetPolicyVersionAsync(string filepath, string version) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - BlobClient blobClient = CreateBlobClient(filepath).WithVersion(version); - - return await GetBlobStreamInternal(blobClient); - } - - /// - public async Task> WritePolicyAsync(string filepath, Stream fileStream) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - BlobClient blobClient = CreateBlobClient(filepath); - - return await WriteBlobStreamInternal(blobClient, fileStream); - } - - /// - public async Task> WritePolicyConditionallyAsync(string filepath, Stream fileStream, string blobLeaseId) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - BlobClient blobClient = CreateBlobClient(filepath); - - BlobUploadOptions blobUploadOptions = new BlobUploadOptions() - { - Conditions = new BlobRequestConditions() - { - LeaseId = blobLeaseId - } - }; - - return await WriteBlobStreamInternal(blobClient, fileStream, blobUploadOptions); - } - - /// - public async Task TryAcquireBlobLease(string filepath) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - BlobClient blobClient = CreateBlobClient(filepath); - BlobLeaseClient blobLeaseClient = blobClient.GetBlobLeaseClient(); - - try - { - BlobLease blobLease = await blobLeaseClient.AcquireAsync(TimeSpan.FromSeconds(_storageConfig.BlobLeaseTimeout)); - return blobLease.LeaseId; - } - catch (RequestFailedException ex) - { - activity?.StopWithError(ex, $"Failed to acquire blob lease for policy file at {filepath}. RequestFailedException"); - } - catch (Exception ex) - { - activity?.StopWithError(ex, $"Failed to acquire blob lease for policy file at {filepath}. Unexpected error"); - } - - return null; - } - - /// - public async void ReleaseBlobLease(string filepath, string leaseId) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - BlobClient blobClient = CreateBlobClient(filepath); - BlobLeaseClient blobLeaseClient = blobClient.GetBlobLeaseClient(leaseId); - await blobLeaseClient.ReleaseAsync(); - } - - /// - public async Task PolicyExistsAsync(string filepath) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - try - { - BlobClient blobClient = CreateBlobClient(filepath); - return await blobClient.ExistsAsync(); - } - catch (RequestFailedException ex) - { - activity?.StopWithError(ex, $"Failed to check if blob exists for policy file at {filepath}. RequestFailedException"); - } - - return false; - } - - /// - public async Task DeletePolicyVersionAsync(string filepath, string version) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - try - { - BlobClient blockBlob = CreateBlobClient(filepath); - - return await blockBlob.WithVersion(version).DeleteAsync(); - } - catch (RequestFailedException ex) - { - var errorMsg = ex.Status == (int)HttpStatusCode.Forbidden && ex.ErrorCode == "OperationNotAllowedOnRootBlob" ? - $"Failed to delete version {version} of policy file at {filepath}. Not allowed to delete current version." : - $"Failed to delete version {version} of policy file at {filepath}. RequestFailedException"; - activity?.StopWithError(ex, errorMsg); - throw; - } - catch (Exception ex) - { - activity?.StopWithError(ex, $"Failed to delete version {version} of policy file at {filepath}. Unexpected error"); - throw; - } - } - - private BlobClient CreateBlobClient(string blobName) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - if (blobName.Contains("delegationpolicy.xml")) - { - activity?.AddEvent(new ActivityEvent("_delegationsContainerClient.GetBlobClient")); - return _delegationsContainerClient.GetBlobClient(blobName); - } - - if (blobName.Contains("resourcepolicy.xml")) - { - activity?.AddEvent(new ActivityEvent("_resourceRegisterContainerClient.GetBlobClient")); - return _resourceRegisterContainerClient.GetBlobClient(blobName); - } - - activity?.AddEvent(new ActivityEvent("_metadataContainerClient.GetBlobClient")); - return _metadataContainerClient.GetBlobClient(blobName); - } - - private async Task GetBlobStreamInternal(BlobClient blobClient) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - try - { - Stream memoryStream = new MemoryStream(); - - if (await blobClient.ExistsAsync()) - { - await blobClient.DownloadToAsync(memoryStream); - memoryStream.Position = 0; - - return memoryStream; - } - - return memoryStream; - } - catch (Exception ex) - { - activity?.StopWithError(ex, $"Failed to read policy file at {blobClient.Name}"); - throw; - } - } - - private async Task> WriteBlobStreamInternal(BlobClient blobClient, Stream fileStream, BlobUploadOptions blobUploadOptions = null) - { - using var activity = TelemetryConfig.ActivitySource.StartActivity(ActivityKind.Client); - try - { - if (blobUploadOptions != null) - { - return await blobClient.UploadAsync(fileStream, blobUploadOptions); - } - - return await blobClient.UploadAsync(fileStream, true); - } - catch (RequestFailedException ex) - { - activity?.StopWithError(ex, $"Failed to save policy file {blobClient.Name}. {(HttpStatusCode)ex.Status}"); - throw; - } - catch (Exception ex) - { - activity?.StopWithError(ex, $"Failed to save policy file {blobClient.Name}. Unexpected exception"); - throw; - } - } - } -} diff --git a/src/Altinn.AccessManagement/Configuration/ConsoleTraceService.cs b/src/Altinn.AccessManagement/Configuration/ConsoleTraceService.cs index b2ea7ea9d..22d90146e 100644 --- a/src/Altinn.AccessManagement/Configuration/ConsoleTraceService.cs +++ b/src/Altinn.AccessManagement/Configuration/ConsoleTraceService.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using Altinn.AccessManagement.Core.Models; using Yuniql.Extensibility; namespace Altinn.AccessManagement.Configuration @@ -7,7 +8,7 @@ namespace Altinn.AccessManagement.Configuration /// Copied from sample project. /// [ExcludeFromCodeCoverage] - public class ConsoleTraceService : ITraceService + public class ConsoleTraceService(ILogger logger) : ITraceService { /// public bool IsDebugEnabled { get; set; } = false; @@ -27,39 +28,31 @@ public class ConsoleTraceService : ITraceService /// public void Info(string message, object payload = null) { - var traceMessage = $"INF {DateTime.UtcNow.ToString("o")} {message}{Environment.NewLine}"; - Console.Write(traceMessage); + logger.LogInformation(message, payload); } /// public void Error(string message, object payload = null) { - var traceMessage = $"ERR {DateTime.UtcNow.ToString("o")} {message}{Environment.NewLine}"; - Console.Write(traceMessage); + logger.LogError(message, payload); } /// public void Debug(string message, object payload = null) { - if (IsDebugEnabled) - { - var traceMessage = $"DBG {DateTime.UtcNow.ToString("o")} {message}{Environment.NewLine}"; - Console.Write(traceMessage); - } + logger.LogDebug(message, payload); } /// public void Success(string message, object payload = null) { - var traceMessage = $"INF {DateTime.UtcNow.ToString("u")} {message}{Environment.NewLine}"; - Console.Write(traceMessage); + logger.LogInformation(message, payload); } /// public void Warn(string message, object payload = null) { - var traceMessage = $"WRN {DateTime.UtcNow.ToString("o")} {message}{Environment.NewLine}"; - Console.Write(traceMessage); + logger.LogInformation(message, payload); } } } diff --git a/src/Altinn.AccessManagement/Controllers/DelegationsController.cs b/src/Altinn.AccessManagement/Controllers/DelegationsController.cs index 66d9f5be6..4f512e5ff 100644 --- a/src/Altinn.AccessManagement/Controllers/DelegationsController.cs +++ b/src/Altinn.AccessManagement/Controllers/DelegationsController.cs @@ -39,6 +39,7 @@ public DelegationsController( /// Endpoint for adding one or more rules for the given app/offeredby/coveredby. This updates or creates a new delegated policy of type "DirectlyDelegated". DelegatedByUserId is included to store history information in 3.0. /// /// All rules to be delegated + /// CancellationToken /// Created /// Partial Content /// Bad Request @@ -46,7 +47,7 @@ public DelegationsController( [HttpPost] [Authorize(Policy = AuthzConstants.ALTINNII_AUTHORIZATION)] [Route("accessmanagement/api/v1/delegations/addrules")] - public async Task Post([FromBody] List rules) + public async Task Post([FromBody] List rules, CancellationToken cancellationToken) { if (rules == null || rules.Count < 1) { @@ -58,7 +59,7 @@ public async Task Post([FromBody] List rules) return BadRequest("Invalid model"); } - List delegationResults = await _pap.TryWriteDelegationPolicyRules(rules); + List delegationResults = await _pap.TryWriteDelegationPolicyRules(rules, cancellationToken); if (delegationResults.All(r => r.CreatedSuccessfully)) { @@ -83,7 +84,7 @@ public async Task Post([FromBody] List rules) [HttpPost] [Authorize(Policy = AuthzConstants.ALTINNII_AUTHORIZATION)] [Route("accessmanagement/api/v1/delegations/getrules")] - public async Task>> GetRules([FromBody] RuleQuery ruleQuery, [FromQuery] bool onlyDirectDelegations = false) + public async Task>> GetRules([FromBody] RuleQuery ruleQuery, CancellationToken cancellationToken, [FromQuery] bool onlyDirectDelegations = false) { List coveredByPartyIds = new List(); List coveredByUserIds = new List(); @@ -132,7 +133,7 @@ public async Task>> GetRules([FromBody] RuleQuery ruleQu return StatusCode(400, $"Unable to get the rules: Missing offeredby and coveredby values."); } - List rulesList = await _pip.GetRulesAsync(resourceIds, offeredByPartyIds, coveredByPartyIds, coveredByUserIds); + List rulesList = await _pip.GetRulesAsync(resourceIds, offeredByPartyIds, coveredByPartyIds, coveredByUserIds, cancellationToken); DelegationHelper.SetRuleType(rulesList, ruleQuery.OfferedByPartyId, ruleQuery.KeyRolePartyIds, ruleQuery.CoveredBy, ruleQuery.ParentPartyId); return Ok(rulesList); } @@ -147,14 +148,14 @@ public async Task>> GetRules([FromBody] RuleQuery ruleQu [HttpPost] [Authorize(Policy = AuthzConstants.ALTINNII_AUTHORIZATION)] [Route("accessmanagement/api/v1/delegations/deleterules")] - public async Task DeleteRule([FromBody] RequestToDeleteRuleList rulesToDelete) + public async Task DeleteRule([FromBody] RequestToDeleteRuleList rulesToDelete, CancellationToken cancellationToken) { if (!ModelState.IsValid) { return BadRequest(ModelState); } - List deletionResults = await _pap.TryDeleteDelegationPolicyRules(rulesToDelete); + List deletionResults = await _pap.TryDeleteDelegationPolicyRules(rulesToDelete, cancellationToken); int ruleCountToDelete = DelegationHelper.GetRulesCountToDeleteFromRequestToDelete(rulesToDelete); int deletionResultsCount = deletionResults.Count; @@ -185,14 +186,14 @@ public async Task DeleteRule([FromBody] RequestToDeleteRuleList ru [HttpPost] [Authorize(Policy = AuthzConstants.ALTINNII_AUTHORIZATION)] [Route("accessmanagement/api/v1/delegations/deletepolicy")] - public async Task DeletePolicy([FromBody] RequestToDeletePolicyList policiesToDelete) + public async Task DeletePolicy([FromBody] RequestToDeletePolicyList policiesToDelete, CancellationToken cancellationToken) { if (!ModelState.IsValid) { return BadRequest(ModelState); } - List deletionResults = await _pap.TryDeleteDelegationPolicies(policiesToDelete); + List deletionResults = await _pap.TryDeleteDelegationPolicies(policiesToDelete, cancellationToken); int countPolicies = DelegationHelper.GetPolicyCount(deletionResults); int policiesToDeleteCount = policiesToDelete.Count; diff --git a/src/Altinn.AccessManagement/Controllers/MaskinportenSchemaController.cs b/src/Altinn.AccessManagement/Controllers/MaskinportenSchemaController.cs index 3a5311187..cb721eb64 100644 --- a/src/Altinn.AccessManagement/Controllers/MaskinportenSchemaController.cs +++ b/src/Altinn.AccessManagement/Controllers/MaskinportenSchemaController.cs @@ -56,7 +56,7 @@ public MaskinportenSchemaController( [ProducesResponseType(400)] [ProducesResponseType(403)] [ProducesResponseType(500)] - public async Task>> GetMaskinportenDelegations([FromQuery] string? supplierOrg, [FromQuery] string? consumerOrg, [FromQuery] string scope) + public async Task>> GetMaskinportenDelegations([FromQuery] string? supplierOrg, [FromQuery] string? consumerOrg, [FromQuery] string scope, CancellationToken cancellationToken) { if (!MaskinportenSchemaAuthorizer.IsAuthorizedDelegationLookupAccess(scope, HttpContext.User)) { @@ -78,7 +78,7 @@ public async Task>> GetMaskinportenDeleg try { - List delegations = await _delegation.GetMaskinportenDelegations(supplierOrg, consumerOrg, scope); + List delegations = await _delegation.GetMaskinportenDelegations(supplierOrg, consumerOrg, scope, cancellationToken); List delegationsExternal = _mapper.Map>(delegations); return delegationsExternal; @@ -100,6 +100,7 @@ public async Task>> GetMaskinportenDeleg /// /// The reportee party /// Request model for user rights delegation check + /// CancellationToken /// Ok /// Bad Request /// Unauthorized @@ -114,7 +115,7 @@ public async Task>> GetMaskinportenDeleg [ProducesResponseType(401)] [ProducesResponseType(403)] [ProducesResponseType(500)] - public async Task>> DelegationCheck([FromRoute] string party, [FromBody] RightsDelegationCheckRequestExternal rightsDelegationCheckRequest) + public async Task>> DelegationCheck([FromRoute] string party, [FromBody] RightsDelegationCheckRequestExternal rightsDelegationCheckRequest, CancellationToken cancellationToken) { int authenticatedUserId = AuthenticationHelper.GetUserId(HttpContext); int authenticationLevel = AuthenticationHelper.GetUserAuthenticationLevel(HttpContext); @@ -126,7 +127,7 @@ public async Task>> Delega RightsDelegationCheckRequest rightDelegationStatusRequestInternal = _mapper.Map(rightsDelegationCheckRequest); rightDelegationStatusRequestInternal.From = reportee.SingleToList(); - DelegationCheckResponse delegationCheckResultInternal = await _delegation.DelegationCheck(authenticatedUserId, authenticationLevel, rightDelegationStatusRequestInternal); + DelegationCheckResponse delegationCheckResultInternal = await _delegation.DelegationCheck(authenticatedUserId, authenticationLevel, rightDelegationStatusRequestInternal, cancellationToken); if (!delegationCheckResultInternal.IsValid) { foreach (var error in delegationCheckResultInternal.Errors) @@ -165,17 +166,17 @@ public async Task>> Delega [ProducesResponseType(201)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task> MaskinportenScopeDelegation([FromRoute] string party, [FromBody] RightsDelegationRequestExternal delegation) + public async Task> MaskinportenScopeDelegation([FromRoute] string party, [FromBody] RightsDelegationRequestExternal delegation, CancellationToken cancellationToken) { int authenticatedUserId = AuthenticationHelper.GetUserId(HttpContext); int authenticationLevel = AuthenticationHelper.GetUserAuthenticationLevel(HttpContext); - + try { AttributeMatch reportee = IdentifierUtil.GetIdentifierAsAttributeMatch(party, HttpContext); DelegationLookup internalDelegation = _mapper.Map(delegation); internalDelegation.From = reportee.SingleToList(); - DelegationActionResult response = await _delegation.DelegateMaskinportenSchema(authenticatedUserId, authenticationLevel, internalDelegation); + DelegationActionResult response = await _delegation.DelegateMaskinportenSchema(authenticatedUserId, authenticationLevel, internalDelegation, cancellationToken); if (!response.IsValid) { @@ -188,7 +189,7 @@ public async Task> MaskinportenSc } RightsDelegationResponseExternal delegationResponse = _mapper.Map(response); - + return StatusCode(201, delegationResponse); } catch (Exception ex) @@ -217,12 +218,12 @@ public async Task> MaskinportenSc [ProducesResponseType(200)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task>> GetOfferedMaskinportenSchemaDelegations([FromRoute] string party) + public async Task>> GetOfferedMaskinportenSchemaDelegations([FromRoute] string party, CancellationToken cancellationToken) { try { AttributeMatch partyMatch = IdentifierUtil.GetIdentifierAsAttributeMatch(party, HttpContext); - List delegations = await _delegation.GetOfferedMaskinportenSchemaDelegations(partyMatch); + List delegations = await _delegation.GetOfferedMaskinportenSchemaDelegations(partyMatch, cancellationToken); return _mapper.Map>(delegations); } catch (ArgumentException argEx) @@ -252,7 +253,7 @@ public async Task>> GetO [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task RevokeOfferedMaskinportenScopeDelegation([FromRoute] string party, [FromBody] RevokeOfferedDelegationExternal delegation) + public async Task RevokeOfferedMaskinportenScopeDelegation([FromRoute] string party, [FromBody] RevokeOfferedDelegationExternal delegation, CancellationToken cancellationToken) { int authenticatedUserId = AuthenticationHelper.GetUserId(HttpContext); @@ -261,7 +262,7 @@ public async Task RevokeOfferedMaskinportenScopeDelegation([FromRo AttributeMatch reportee = IdentifierUtil.GetIdentifierAsAttributeMatch(party, HttpContext); DelegationLookup internalDelegation = _mapper.Map(delegation); internalDelegation.From = reportee.SingleToList(); - DelegationActionResult response = await _delegation.RevokeMaskinportenSchemaDelegation(authenticatedUserId, internalDelegation); + DelegationActionResult response = await _delegation.RevokeMaskinportenSchemaDelegation(authenticatedUserId, internalDelegation, cancellationToken); if (!response.IsValid) { @@ -301,12 +302,12 @@ public async Task RevokeOfferedMaskinportenScopeDelegation([FromRo [ProducesResponseType(200)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task>> GetReceivedMaskinportenSchemaDelegations([FromRoute] string party) + public async Task>> GetReceivedMaskinportenSchemaDelegations([FromRoute] string party, CancellationToken cancellationToken) { try { AttributeMatch partyMatch = IdentifierUtil.GetIdentifierAsAttributeMatch(party, HttpContext); - List delegations = await _delegation.GetReceivedMaskinportenSchemaDelegations(partyMatch); + List delegations = await _delegation.GetReceivedMaskinportenSchemaDelegations(partyMatch, cancellationToken); return _mapper.Map>(delegations); } catch (ArgumentException argEx) @@ -336,7 +337,7 @@ public async Task>> GetR [ProducesResponseType(204)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task RevokeReceivedMaskinportenScopeDelegation([FromRoute] string party, [FromBody] RevokeReceivedDelegationExternal delegation) + public async Task RevokeReceivedMaskinportenScopeDelegation([FromRoute] string party, [FromBody] RevokeReceivedDelegationExternal delegation, CancellationToken cancellationToken) { int authenticatedUserId = AuthenticationHelper.GetUserId(HttpContext); @@ -345,7 +346,7 @@ public async Task RevokeReceivedMaskinportenScopeDelegation([FromR AttributeMatch reportee = IdentifierUtil.GetIdentifierAsAttributeMatch(party, HttpContext); DelegationLookup internalDelegation = _mapper.Map(delegation); internalDelegation.To = reportee.SingleToList(); - DelegationActionResult response = await _delegation.RevokeMaskinportenSchemaDelegation(authenticatedUserId, internalDelegation); + DelegationActionResult response = await _delegation.RevokeMaskinportenSchemaDelegation(authenticatedUserId, internalDelegation, cancellationToken); if (!response.IsValid) { diff --git a/src/Altinn.AccessManagement/Controllers/PolicyInformationPointController.cs b/src/Altinn.AccessManagement/Controllers/PolicyInformationPointController.cs index ea5dd58a2..0a794522d 100644 --- a/src/Altinn.AccessManagement/Controllers/PolicyInformationPointController.cs +++ b/src/Altinn.AccessManagement/Controllers/PolicyInformationPointController.cs @@ -31,13 +31,14 @@ public PolicyInformationPointController(IPolicyInformationPoint pip, IMapper map /// Endpoint to find all delegation changes for a given user, reportee and app/resource context /// /// The input model that contains id info about user, reportee, resource and resourceMatchType + /// CancellationToken /// A list of delegation changes that's stored in the database [ApiExplorerSettings(IgnoreApi = true)] [HttpPost] [Route("getdelegationchanges")] - public async Task>> GetAllDelegationChanges([FromBody] DelegationChangeInput request) + public async Task>> GetAllDelegationChanges([FromBody] DelegationChangeInput request, CancellationToken cancellationToken) { - DelegationChangeList response = await _pip.GetAllDelegations(request); + DelegationChangeList response = await _pip.GetAllDelegations(request, cancellationToken); if (!response.IsValid) { diff --git a/src/Altinn.AccessManagement/Controllers/RightsInternalController.cs b/src/Altinn.AccessManagement/Controllers/RightsInternalController.cs index 7fedee4d7..673e9dfb3 100644 --- a/src/Altinn.AccessManagement/Controllers/RightsInternalController.cs +++ b/src/Altinn.AccessManagement/Controllers/RightsInternalController.cs @@ -51,6 +51,7 @@ public RightsInternalController(ILogger logger, IMappe /// Endpoint for performing a query of rights between two parties for a specific resource /// /// Query model for rights lookup + /// CancellationToken /// Whether the response should return all possible rights for the resource, not just the rights the user have access to /// Ok /// Bad Request @@ -59,12 +60,12 @@ public RightsInternalController(ILogger logger, IMappe [Authorize(Policy = AuthzConstants.ALTINNII_AUTHORIZATION)] [Route("internal/query/rights/")] [ApiExplorerSettings(IgnoreApi = true)] - public async Task>> RightsQuery([FromBody] RightsQueryExternal rightsQuery, [FromQuery] bool returnAllPolicyRights = false) + public async Task>> RightsQuery([FromBody] RightsQueryExternal rightsQuery, CancellationToken cancellationToken, [FromQuery] bool returnAllPolicyRights = false) { try { RightsQuery rightsQueryInternal = _mapper.Map(rightsQuery); - List rightsInternal = await _pip.GetRights(rightsQueryInternal, returnAllPolicyRights); + List rightsInternal = await _pip.GetRights(rightsQueryInternal, returnAllPolicyRights, cancellationToken: cancellationToken); return _mapper.Map>(rightsInternal); } catch (ValidationException valEx) @@ -84,6 +85,7 @@ public async Task>> RightsQuery([FromBody] Righ /// IMPORTANT: The delegable rights lookup does itself not check that the user has access to the necessary RolesAdministration/MainAdmin or MaskinportenSchema delegation system resources needed to be allowed to perform delegation. /// /// Query model for rights lookup + /// CancellationToken /// Whether the response should return all possible rights for the resource, not just the rights the user is allowed to delegate /// Ok /// Bad Request @@ -92,12 +94,12 @@ public async Task>> RightsQuery([FromBody] Righ [Authorize(Policy = AuthzConstants.ALTINNII_AUTHORIZATION)] [Route("internal/query/delegablerights")] [ApiExplorerSettings(IgnoreApi = true)] - public async Task>> DelegableRightsQuery([FromBody] RightsQueryExternal rightsQuery, [FromQuery] bool returnAllPolicyRights = false) + public async Task>> DelegableRightsQuery([FromBody] RightsQueryExternal rightsQuery, CancellationToken cancellationToken, [FromQuery] bool returnAllPolicyRights = false) { try { RightsQuery rightsQueryInternal = _mapper.Map(rightsQuery); - List rightsInternal = await _pip.GetRights(rightsQueryInternal, returnAllPolicyRights, getDelegableRights: true); + List rightsInternal = await _pip.GetRights(rightsQueryInternal, returnAllPolicyRights, getDelegableRights: true, cancellationToken); return _mapper.Map>(rightsInternal); } catch (ValidationException valEx) diff --git a/src/Altinn.AccessManagement/Program.cs b/src/Altinn.AccessManagement/Program.cs index b3bec8d21..617a10429 100644 --- a/src/Altinn.AccessManagement/Program.cs +++ b/src/Altinn.AccessManagement/Program.cs @@ -80,8 +80,8 @@ void ConfigureSetupLogging() builder .AddFilter("Microsoft", LogLevel.Warning) .AddFilter("System", LogLevel.Warning) - .AddFilter("Altinn.AccessManagement.Program", LogLevel.Debug) - .AddConsole(); + .AddFilter("Altinn.AccessManagement.Program", LogLevel.Debug); + // .AddConsole(); }); logger = logFactory.CreateLogger(); @@ -234,7 +234,6 @@ void ConfigureServices(IServiceCollection services, IConfiguration config) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -384,7 +383,7 @@ void ConfigurePostgreSql() { if (builder.Configuration.GetValue("PostgreSQLSettings:EnableDBConnection")) { - ConsoleTraceService traceService = new ConsoleTraceService { IsDebugEnabled = false }; + ConsoleTraceService traceService = new ConsoleTraceService(logger); string connectionString = string.Format( builder.Configuration.GetValue("PostgreSQLSettings:AdminConnectionString"), diff --git a/test/Altinn.AccessManagement.Tests/Altinn.AccessManagement.Tests.csproj b/test/Altinn.AccessManagement.Tests/Altinn.AccessManagement.Tests.csproj index 2f93a2d4a..354de2f72 100644 --- a/test/Altinn.AccessManagement.Tests/Altinn.AccessManagement.Tests.csproj +++ b/test/Altinn.AccessManagement.Tests/Altinn.AccessManagement.Tests.csproj @@ -27,6 +27,10 @@ + + + + all diff --git a/test/Altinn.AccessManagement.Tests/Controllers/Altinn2RightsControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/Altinn2RightsControllerTest.cs index d046feba5..a3f4184d9 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/Altinn2RightsControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/Altinn2RightsControllerTest.cs @@ -144,20 +144,20 @@ public async Task ClearAccessCache_ReturnOk(string authnUserToken, int party, Ba public static TheoryData> ClearAccessCache_ReturnOk_input() => new() { { - PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper Børstad + PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper B�rstad 50002598, // From Kasper - new BaseAttributeExternal { Type = Urn.Altinn.Person.Uuid, Value = "00000000-0000-0000-0005-000000003899" }, // To Ørjan Ravnås + new BaseAttributeExternal { Type = Urn.Altinn.Person.Uuid, Value = "00000000-0000-0000-0005-000000003899" }, // To �rjan Ravn�s AssertStatusCode(HttpStatusCode.OK) }, { - PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper Børstad + PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper B�rstad 50002598, // From Kasper new BaseAttributeExternal { Type = Urn.Altinn.Organization.Uuid, Value = "00000000-0000-0000-0005-000000004222" }, // To KARLSTAD OG ULOYBUKT AssertStatusCode(HttpStatusCode.OK) }, { - PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper Børstad - 50005545, // From Ørsta + PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper B�rstad + 50005545, // From �rsta new BaseAttributeExternal { Type = Urn.Altinn.EnterpriseUser.Uuid, Value = "00000000-0000-0000-0002-000000010727" }, // To OrstaECUser AssertStatusCode(HttpStatusCode.OK) } @@ -187,14 +187,14 @@ public async Task ClearAccessCache_ReturnBadRequest(string authnUserToken, int p public static TheoryData> ClearAccessCache_ReturnBadRequest_input() => new() { { - PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper Børstad + PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper B�rstad 50002598, // From Kasper new BaseAttributeExternal { Type = Urn.Altinn.Person.Uuid, Value = "asdf" }, // To not a well-formated uuid AssertStatusCode(HttpStatusCode.BadRequest) }, { - PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper Børstad - 50005545, // From Ørsta + PrincipalUtil.GetToken(20000490, 50002598, 3), // Kasper B�rstad + 50005545, // From �rsta new BaseAttributeExternal { Type = Urn.Altinn.Organization.Uuid, Value = "123" }, // To not a well-formated uuid AssertStatusCode(HttpStatusCode.BadRequest) } @@ -284,7 +284,7 @@ private static void WithServiceMoq(IServiceCollection services) { services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton(); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Controllers/AuthorizedPartiesControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/AuthorizedPartiesControllerTest.cs index 9e8db1579..a39f2fd19 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/AuthorizedPartiesControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/AuthorizedPartiesControllerTest.cs @@ -215,7 +215,7 @@ private HttpClient GetTestClient(string token, params Action { services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton(); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Controllers/DelegationsControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/DelegationsControllerTest.cs index fcb320458..3e353baec 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/DelegationsControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/DelegationsControllerTest.cs @@ -1615,7 +1615,7 @@ private HttpClient GetTestClient(IPDP pdpMock = null, IHttpContextAccessor httpC { services.AddSingleton(); services.AddSingleton(delegationMetadataRepositoryMock); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Controllers/MaskinportenSchemaControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/MaskinportenSchemaControllerTest.cs index af62f11e6..b2685a79c 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/MaskinportenSchemaControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/MaskinportenSchemaControllerTest.cs @@ -111,10 +111,10 @@ public async Task GetOfferedMaskinportenSchemaDelegations_Valid_OfferedByOrg() /// [Fact] public async Task GetOfferedMaskinportenSchemaDelegations_Notfound_MissingOfferedBy() - { + { // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1//maskinportenschema/offered"); - + // Assert Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } @@ -130,7 +130,7 @@ public async Task GetOfferedMaskinportenSchemaDelegations_Forbidden_InvalidOffer _client = GetTestClient(new PepWithPDPAuthorizationMock()); var token = PrincipalUtil.GetToken(1234, 12345678, 2); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - + // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/123/maskinportenschema/offered"); @@ -225,10 +225,10 @@ public async Task GetReceivedMaskinportenSchemaDelegations_Valid_CoveredBy() { // Arrange List expectedDelegations = TestDataUtil.GetReceivedMaskinportenSchemaDelegations(50004219); - + var token = PrincipalUtil.GetToken(1234, 12345678, 2); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - + // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/50004219/maskinportenschema/received"); string responseContent = await response.Content.ReadAsStringAsync(); @@ -249,7 +249,7 @@ public async Task GetReceivedMaskinportenSchemaDelegations_Valid_CoveredByOrg() { // Arrange List expectedDelegations = TestDataUtil.GetReceivedMaskinportenSchemaDelegations(50004219); - + var httpContextAccessorMock = GetHttpContextAccessorMock("party", "50004219"); _client = GetTestClient(new PepWithPDPAuthorizationMock(), httpContextAccessorMock); var token = PrincipalUtil.GetToken(1234, 12345678, 2); @@ -292,7 +292,7 @@ public async Task GetReceivedMaskinportenSchemaDelegations_Invalid_CoveredBy() _client = GetTestClient(new PepWithPDPAuthorizationMock()); var token = PrincipalUtil.GetToken(1234, 12345678, 2); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - + // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/1234/maskinportenschema/received"); @@ -330,10 +330,10 @@ public async Task GetReceivedMaskinportenSchemaDelegations_ResourceMetadataNotFo { // Arrange List expectedDelegations = TestDataUtil.GetReceivedMaskinportenSchemaDelegations(50004216); - + var token = PrincipalUtil.GetToken(1234, 12345678, 2); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - + // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/50004216/maskinportenschema/received"); string responseContent = await response.Content.ReadAsStringAsync(); @@ -668,7 +668,7 @@ public async Task GetOfferedMaskinportenSchemaDelegations_UserComplyingToPolicy( // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/organization/maskinportenschema/offered"); - + // Assert Assert.Equal(expectedStatusCode, response.StatusCode); } @@ -691,7 +691,7 @@ public async Task GetOfferedMaskinportenSchemaDelegations_UserNotComplyingToPoli // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/organization/maskinportenschema/offered"); - + // Assert Assert.Equal(expectedStatusCode, response.StatusCode); } @@ -713,7 +713,7 @@ public async Task GetReceivedMaskinportenSchemaDelegations_UserComplyingToPolicy // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/organization/maskinportenschema/received"); - + // Assert Assert.Equal(expectedStatusCode, response.StatusCode); } @@ -736,7 +736,7 @@ public async Task GetReceivedMaskinportenSchemaDelegations_UserNotComplyingToPol // Act HttpResponseMessage response = await _client.GetAsync($"accessmanagement/api/v1/organization/maskinportenschema/received"); - + // Assert Assert.Equal(expectedStatusCode, response.StatusCode); } @@ -1766,11 +1766,11 @@ private HttpClient GetTestClient(IPDP pdpMock = null, IHttpContextAccessor httpC { services.AddSingleton(); services.AddSingleton(delegationMetadataRepositoryMock); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(pdpMock); services.AddSingleton(httpContextAccessor); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Controllers/PolicyInformationPointControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/PolicyInformationPointControllerTest.cs index 498c14ee2..725515317 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/PolicyInformationPointControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/PolicyInformationPointControllerTest.cs @@ -21,7 +21,7 @@ namespace Altinn.AccessManagement.Tests.Controllers; /// /// Test class for /// -public class PolicyInformationPointControllerTest: IClassFixture> +public class PolicyInformationPointControllerTest : IClassFixture> { private HttpClient _client; private readonly CustomWebApplicationFactory _factory; @@ -29,7 +29,7 @@ public class PolicyInformationPointControllerTest: IClassFixture /// Initializes a new instance of the class. /// @@ -39,7 +39,7 @@ public PolicyInformationPointControllerTest(CustomWebApplicationFactory - /// Sets up test scenarios for + /// Sets up test scenarios for /// public static TheoryData Scenarios() => new() { diff --git a/test/Altinn.AccessManagement.Tests/Controllers/ResourceOwnerAPI/ResourceOwnerAuthorizedPartiesControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/ResourceOwnerAPI/ResourceOwnerAuthorizedPartiesControllerTest.cs index 8d990c90c..40202185d 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/ResourceOwnerAPI/ResourceOwnerAuthorizedPartiesControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/ResourceOwnerAPI/ResourceOwnerAuthorizedPartiesControllerTest.cs @@ -130,7 +130,7 @@ private HttpClient GetTestClient(string token, params Action { services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton(); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs index 52a2170d7..997fdb683 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs @@ -1546,7 +1546,7 @@ private HttpClient GetTestClient(string token, params Action { services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton(); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Controllers/V2MaskinportenSchemaControllerTest.cs b/test/Altinn.AccessManagement.Tests/Controllers/V2MaskinportenSchemaControllerTest.cs index 390d950d5..f2ac3f0b0 100644 --- a/test/Altinn.AccessManagement.Tests/Controllers/V2MaskinportenSchemaControllerTest.cs +++ b/test/Altinn.AccessManagement.Tests/Controllers/V2MaskinportenSchemaControllerTest.cs @@ -87,7 +87,7 @@ GIVEN that organization Voss consulting has delegated a MaskinportenSchema resou } /// - /// + /// /// /// acceptance criteria [Theory] diff --git a/test/Altinn.AccessManagement.Tests/Fixtures/PostgresFixture.cs b/test/Altinn.AccessManagement.Tests/Fixtures/PostgresFixture.cs index b1ff83905..e319ca9f6 100644 --- a/test/Altinn.AccessManagement.Tests/Fixtures/PostgresFixture.cs +++ b/test/Altinn.AccessManagement.Tests/Fixtures/PostgresFixture.cs @@ -11,6 +11,7 @@ using Altinn.AccessManagement.Persistence; using Altinn.AccessManagement.Persistence.Configuration; using Altinn.AccessManagement.Tests.Seeds; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Npgsql; using Testcontainers.PostgreSql; @@ -26,7 +27,10 @@ namespace Altinn.AccessManagement.Tests.Fixtures; /// public class PostgresFixture : IAsyncLifetime { - private ConsoleTraceService Tracer { get; } = new ConsoleTraceService { IsDebugEnabled = true }; + private ConsoleTraceService Tracer { get; } = new ConsoleTraceService(LoggerFactory.Create(options => + { + options.AddDebug(); + }).CreateLogger()); /// /// Creates a new database and runs the migrations diff --git a/test/Altinn.AccessManagement.Tests/Fixtures/WebApplicationFixture.cs b/test/Altinn.AccessManagement.Tests/Fixtures/WebApplicationFixture.cs index ad78b4796..1880435a2 100644 --- a/test/Altinn.AccessManagement.Tests/Fixtures/WebApplicationFixture.cs +++ b/test/Altinn.AccessManagement.Tests/Fixtures/WebApplicationFixture.cs @@ -105,7 +105,7 @@ private static void AddMockClients(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Mocks/PolicyFactoryMock.cs b/test/Altinn.AccessManagement.Tests/Mocks/PolicyFactoryMock.cs new file mode 100644 index 000000000..af20c0d2a --- /dev/null +++ b/test/Altinn.AccessManagement.Tests/Mocks/PolicyFactoryMock.cs @@ -0,0 +1,21 @@ +using Altinn.AccessManagement.Core.Enums; +using Altinn.AccessManagement.Core.Repositories.Interfaces; +using Microsoft.Extensions.Logging; + +namespace Altinn.AccessManagement.Tests.Mocks; + +/// +public class PolicyFactoryMock(ILogger logger) : IPolicyFactory +{ + /// + public IPolicyRepository Create(PolicyAccountType account, string filepath) + { + return new PolicyRepositoryMock(filepath, logger); + } + + /// + public IPolicyRepository Create(string filepath) + { + return new PolicyRepositoryMock(filepath, logger); + } +} \ No newline at end of file diff --git a/test/Altinn.AccessManagement.Tests/Mocks/PolicyRepositoryMock.cs b/test/Altinn.AccessManagement.Tests/Mocks/PolicyRepositoryMock.cs index a0f2b62e3..322d75049 100644 --- a/test/Altinn.AccessManagement.Tests/Mocks/PolicyRepositoryMock.cs +++ b/test/Altinn.AccessManagement.Tests/Mocks/PolicyRepositoryMock.cs @@ -1,6 +1,8 @@ using System; using System.IO; using System.Net; +using System.Reflection; +using System.Threading; using System.Threading.Tasks; using Altinn.AccessManagement.Core.Repositories.Interfaces; using Azure; @@ -13,95 +15,87 @@ namespace Altinn.AccessManagement.Tests.Mocks /// /// Mock class for interface /// - public class PolicyRepositoryMock : IPolicyRepository + public class PolicyRepositoryMock(string filepath, ILogger logger) : IPolicyRepository { - private readonly ILogger _logger; + private string Filepath { get; } = filepath; - /// - /// Constructor - /// - /// logger - public PolicyRepositoryMock(ILogger logger) - { - _logger = logger; - } + private ILogger Logger { get; } = logger; /// - public Task GetPolicyAsync(string filepath) + public Task GetPolicyAsync(CancellationToken cancellationToken = default) { - return Task.FromResult(GetTestDataStream(filepath)); + return Task.FromResult(GetTestDataStream(Filepath)); } /// - public Task GetPolicyVersionAsync(string filepath, string version) + public Task GetPolicyVersionAsync(string version, CancellationToken cancellationToken = default) { - return Task.FromResult(GetTestDataStream(filepath)); + return Task.FromResult(GetTestDataStream(Filepath)); } /// - public Task> WritePolicyAsync(string filepath, Stream fileStream) + public Task> WritePolicyAsync(Stream fileStream, CancellationToken cancellationToken = default) { - return WriteStreamToTestDataFolder(filepath, fileStream); + return WriteStreamToTestDataFolder(Filepath, fileStream); } /// - public Task DeletePolicyVersionAsync(string filepath, string version) + public Task DeletePolicyVersionAsync(string version, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } /// - public async Task> WritePolicyConditionallyAsync(string filepath, Stream fileStream, string blobLeaseId) + public async Task> WritePolicyConditionallyAsync(Stream fileStream, string blobLeaseId, CancellationToken cancellationToken = default) { - if (blobLeaseId == "CorrectLeaseId" && !filepath.Contains("error/blobstorageleaselockwritefail")) + if (blobLeaseId == "CorrectLeaseId" && !Filepath.Contains("error/blobstorageleaselockwritefail")) { - return await WriteStreamToTestDataFolder(filepath, fileStream); + return await WriteStreamToTestDataFolder(Filepath, fileStream); } throw new RequestFailedException((int)HttpStatusCode.PreconditionFailed, "The condition specified using HTTP conditional header(s) is not met."); } /// - public Task TryAcquireBlobLease(string filepath) + public Task TryAcquireBlobLease(CancellationToken cancellationToken = default) { - if (filepath.Contains("error/blobstoragegetleaselockfail")) + if (Filepath.Contains("error/blobstoragegetleaselockfail")) { return Task.FromResult((string)null); - } + } return Task.FromResult("CorrectLeaseId"); } /// - public void ReleaseBlobLease(string filepath, string leaseId) + public void ReleaseBlobLease(string leaseId, CancellationToken cancellationToken = default) { } /// - public Task PolicyExistsAsync(string filepath) + public Task PolicyExistsAsync(CancellationToken cancellationToken = default) { - string fullpath = Path.Combine(GetDataInputBlobPath(), filepath); + string fullpath = Path.Combine(GetDataInputBlobPath(), Filepath); if (File.Exists(fullpath)) { return Task.FromResult(true); } - _logger.LogWarning("Policy not found for full path" + fullpath); + Logger.LogWarning("Policy not found for full path" + fullpath); return Task.FromResult(false); } private static string GetDataOutputBlobPath() { - string unitTestFolder = Path.GetDirectoryName(new Uri(typeof(PolicyRepositoryMock).Assembly.Location).LocalPath); - return Path.Combine(unitTestFolder, "..", "..", "..", "Data", "blobs", "output"); + return Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Data", "blobs", "output"); + } private static string GetDataInputBlobPath() { - string unitTestFolder = Path.GetDirectoryName(new Uri(typeof(PolicyRepositoryMock).Assembly.Location).LocalPath); - return Path.Combine(unitTestFolder, "..", "..", "..", "Data", "blobs", "input"); + return Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Data", "blobs", "input"); } private static Stream GetTestDataStream(string filepath) diff --git a/test/Altinn.AccessManagement.Tests/PolicyAdministrationPointTest.cs b/test/Altinn.AccessManagement.Tests/PolicyAdministrationPointTest.cs index 7688129d5..0678d5121 100644 --- a/test/Altinn.AccessManagement.Tests/PolicyAdministrationPointTest.cs +++ b/test/Altinn.AccessManagement.Tests/PolicyAdministrationPointTest.cs @@ -27,7 +27,7 @@ namespace Altinn.AccessManagement.Tests public class PolicyAdministrationPointTest { private readonly IPolicyAdministrationPoint _pap; - private readonly IPolicyRepository _prp; + private readonly IPolicyFactory _prp; private readonly IDelegationChangeEventQueue _eventQueue; private readonly Mock> _logger; private DelegationMetadataRepositoryMock _delegationMetadataRepositoryMock; @@ -45,7 +45,7 @@ public PolicyAdministrationPointTest() _logger = new Mock>(); _delegationMetadataRepositoryMock = new DelegationMetadataRepositoryMock(); - _prp = new PolicyRepositoryMock(new Mock>().Object); + _prp = new PolicyFactoryMock(new Mock>().Object); _eventQueue = new DelegationChangeEventQueueMock(); _pap = new PolicyAdministrationPoint( new PolicyRetrievalPoint(_prp, memoryCache, Options.Create(new CacheConfig { PolicyCacheTimeout = 1 })), @@ -141,7 +141,7 @@ public async Task TryDeleteDelegationPolicyRules_Valid() { TestDataUtil.GetRequestToDeleteModel(performedByUserId, offeredByPartyId, "org1", "app3", new List { "0d0c8570-64fb-49f9-9f7d-45c057fddf94", "6f11dd0b-5e5d-4bd1-85f0-9796300dfded" }, coveredByUserId: coveredBy), TestDataUtil.GetRequestToDeleteModel(performedByUserId, offeredByPartyId, "org2", "app3", new List { "244278c1-7c6b-4f6b-b6e9-2bd41f84812f" }, coveredByUserId: coveredBy), - TestDataUtil.GetRequestToDeleteModel(performedByUserId, offeredByPartyId, "org1", "app4", new List { "adfa64fa-5859-46e5-8d0d-62762082f3b9" }, coveredByUserId: coveredBy) + TestDataUtil.GetRequestToDeleteModel(performedByUserId, offeredByPartyId, "org1", "app4", new List { "adfa64fa-5859-46e5-8d0d-62762082f3b9" }, coveredByUserId: coveredBy) }; List expected = new List @@ -524,7 +524,7 @@ public async Task TryDeleteDelegationPolicyRules_PolicyPathInvalid() TestDataUtil.GetRequestToDeleteModel(performedByUserId, offeredByPartyId, "org2", "app3", new List { "244278c1-7c6b-4f6b-b6e9-2bd41f84812f" }, coveredByUserId: coveredBy), TestDataUtil.GetRequestToDeleteModel(performedByUserId, offeredByPartyId, "org1", "app4", new List { "ade3b138-7fa4-4c83-9306-8ec4a72c2daa" }, coveredByUserId: 0) }; - + List expected = new List { TestDataUtil.GetRuleModel(performedByUserId, offeredByPartyId, coveredBy.ToString(), coveredByType, "read", "org1", "app3", createdSuccessfully: true), @@ -1244,7 +1244,7 @@ public async Task TryWriteDelegationPolicyRules_UnknownResource_PartialSuccess() List unsortedRules = new List { - TestDataUtil.GetRuleModel(delegatedByUserId, offeredByPartyId, coveredBy, coveredByType, "read", "org1", "app1"), + TestDataUtil.GetRuleModel(delegatedByUserId, offeredByPartyId, coveredBy, coveredByType, "read", "org1", "app1"), TestDataUtil.GetRuleModel(delegatedByUserId, offeredByPartyId, coveredBy, coveredByType, "read", "org2", "app1"), TestDataUtil.GetRuleModel(delegatedByUserId, offeredByPartyId, coveredBy, coveredByType, "sign", "org1", "app1", "task1"), TestDataUtil.GetRuleModel(delegatedByUserId, offeredByPartyId, coveredBy, coveredByType, "read", "org1", "app1", task: null, "event1") // This should fail all rules for org1, app1 as there is no event1 resource in the App Policy for this app diff --git a/test/Altinn.AccessManagement.Tests/Resolvers/ResolverServiceCollection.cs b/test/Altinn.AccessManagement.Tests/Resolvers/ResolverServiceCollection.cs index 6600965a1..15f57a8a7 100644 --- a/test/Altinn.AccessManagement.Tests/Resolvers/ResolverServiceCollection.cs +++ b/test/Altinn.AccessManagement.Tests/Resolvers/ResolverServiceCollection.cs @@ -46,7 +46,7 @@ public static void DefaultServiceCollection(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/test/Altinn.AccessManagement.Tests/Utils/SetupUtils.cs b/test/Altinn.AccessManagement.Tests/Utils/SetupUtils.cs index aad4f2c32..1107cedc0 100644 --- a/test/Altinn.AccessManagement.Tests/Utils/SetupUtils.cs +++ b/test/Altinn.AccessManagement.Tests/Utils/SetupUtils.cs @@ -33,7 +33,7 @@ public static HttpClient GetTestClient(CustomWebApplicationFactory(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton, JwtCookiePostConfigureOptionsStub>(); services.AddSingleton();