From f9bd4d8b545fa5bad6aeda3e0c511787a0c9279c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remi=20L=C3=B8voll?= Date: Wed, 11 Dec 2024 17:15:57 +0100 Subject: [PATCH 1/5] Alowed to revoke rights given to system user --- .../Asserters/AttributeMatchAsserter.cs | 8 ++--- .../Resolvers/BaseUrn.cs | 2 +- .../Services/PolicyAdministrationPoint.cs | 2 ++ .../Services/SingleRightsService.cs | 31 +++++++++++++++---- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs index 2415de26..8cb6783d 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs @@ -168,13 +168,13 @@ public static void DefaultFrom(this IAssert assert, IDictionary< /// list of assertions /// dictionary for writing assertion errors /// list of attributes - public static void Altinn2InternalIds(this IAssert assert, IDictionary errors, IEnumerable values) => + public static void RevokeInternalIds(this IAssert assert, IDictionary errors, IEnumerable values) => assert.All( assert.Single( assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), - assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute)), - assert.AllAttributesHasValues, - assert.AttributesAreIntegers(BaseUrn.Altinn2InternalIds))(errors, values); + assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute), + assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid)), + assert.AllAttributesHasValues)(errors, values); /// /// A default list of assertions that contains the baseline for validating input for a resource. diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs index 4db9287b..afd2dbc1 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs @@ -21,7 +21,7 @@ public static class BaseUrn /// /// InternalIds from Altinn 2 /// - public static string[] Altinn2InternalIds => [AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute]; + public static string[] RevokeInternalIds => [AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid]; /// /// Resources that belongs to Altinn diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs index affbe1bf..2d66a808 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs @@ -908,6 +908,8 @@ private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDe OfferedByPartyId = policyToDelete.PolicyMatch.OfferedByPartyId, CoveredByPartyId = coveredByPartyId, CoveredByUserId = coveredByUserId, + ToUuid = coveredByUuid, + ToUuidType = coveredByUuidType, PerformedByUserId = policyToDelete.DeletedByUserId, BlobStoragePolicyPath = policyPath, BlobStorageVersionId = response.Value.VersionId diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs index e456f09a..a6195152 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs @@ -235,11 +235,9 @@ public async Task RevokeRightsDelegation(int authentic } var fromAttribute = await _resolver.Resolve(delegation.From, [AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute], cancellationToken); - var toAttribute = await _resolver.Resolve(delegation.To, BaseUrn.Altinn2InternalIds, cancellationToken); + var toAttribute = await _resolver.Resolve(delegation.To, BaseUrn.RevokeInternalIds, cancellationToken); - var to = toAttribute.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute) - ? new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, toAttribute.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute).Value) - : new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, toAttribute.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute).Value); + var to = GetAttributeMatchFromAttributeMatchList(toAttribute); var policiesToDelete = DelegationHelper.GetRequestToDeleteResource(authenticatedUserId, delegation.Rights[0].Resource, fromAttribute.GetRequiredInt(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), to); @@ -247,6 +245,27 @@ public async Task RevokeRightsDelegation(int authentic return assertion; } + /// + /// Fetch the actual internal id from the attribute match list + /// + /// the list to fetch from + /// The identified internal id + private AttributeMatch GetAttributeMatchFromAttributeMatchList(IEnumerable attributeMatches) + { + if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute)) + { + return new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute).Value); + } + else if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid)) + { + return new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid).Value); + } + else + { + return new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute).Value); + } + } + /// /// Ensures that given input for revoking a delegations contains a combination of attributes that /// the service layer can process. If the method return null then input should be processable. @@ -256,10 +275,10 @@ private ValidationProblemDetails AssertRevokeDelegationInput(DelegationLookup de _asserter.Join( _asserter.Evaluate( delegation.From, - _asserter.Altinn2InternalIds), + _asserter.RevokeInternalIds), _asserter.Evaluate( delegation.To, - _asserter.Altinn2InternalIds), + _asserter.RevokeInternalIds), _asserter.Evaluate( delegation.Rights?.FirstOrDefault()?.Resource ?? [], _asserter.DefaultResource)); From 6ff0427e4ebed94d790fd48d358853a30e2f1bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remi=20L=C3=B8voll?= Date: Thu, 2 Jan 2025 16:28:08 +0100 Subject: [PATCH 2/5] Fix missing Guids in Revoke calls to all user types Fix error in path calculation for userids as partyid exist also for person and party id prefered over userid in path calculation. --- .../Asserters/AttributeMatchAsserter.cs | 14 +++- .../Helpers/DelegationHelper.cs | 6 +- .../Models/PolicyMatch.cs | 11 +++ .../Altinn/PartyAttributeResolver.cs | 29 +++++-- .../Resolvers/BaseUrn.cs | 9 +- .../Services/PolicyAdministrationPoint.cs | 2 + .../Services/SingleRightsService.cs | 49 +++++++---- .../o2s delegate org2systemuser.bru | 84 +++++++++++++++++++ ...s org2systemuser delegation successful.bru | 53 ++++++++++++ ...g org revokes delegation to systemuser.bru | 70 ++++++++++++++++ .../rights-delegations/at22testdata.json | 3 + .../rights-delegations/devtestdata.json | 34 ++++++++ .../rights-delegations/localtestdata.json | 3 + 13 files changed, 342 insertions(+), 25 deletions(-) create mode 100644 src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s delegate org2systemuser.bru create mode 100644 src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s org2systemuser delegation successful.bru create mode 100644 src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s sending org revokes delegation to systemuser.bru create mode 100644 src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/devtestdata.json diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs index 8cb6783d..f97e3075 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs @@ -168,7 +168,19 @@ public static void DefaultFrom(this IAssert assert, IDictionary< /// list of assertions /// dictionary for writing assertion errors /// list of attributes - public static void RevokeInternalIds(this IAssert assert, IDictionary errors, IEnumerable values) => + public static void RevokeInternalFromIds(this IAssert assert, IDictionary errors, IEnumerable values) => + assert.All( + assert.Single(assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute)), + assert.AllAttributesHasValues, + assert.AttributesAreIntegers(BaseUrn.RevokeInternalFromIds))(errors, values); + + /// + /// A list of assertions for validating input is a single value of either of the internal Altinn 2 identifiers: UserId or PartyId. + /// + /// list of assertions + /// dictionary for writing assertion errors + /// list of attributes + public static void RevokeInternalToIds(this IAssert assert, IDictionary errors, IEnumerable values) => assert.All( assert.Single( assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Helpers/DelegationHelper.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Helpers/DelegationHelper.cs index 2e2927ca..365e0b80 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Helpers/DelegationHelper.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Helpers/DelegationHelper.cs @@ -820,7 +820,7 @@ public static List GetRequestToDeleteResourceRegistryService(in /// /// Builds a RequestToDelete request model for revoking all delegated rules for the resource if delegated between the from and to parties /// - public static List GetRequestToDeleteResource(int authenticatedUserId, IEnumerable resource, int fromPartyId, AttributeMatch to) + public static List GetRequestToDeleteResource(int authenticatedUserId, IEnumerable resource, int fromPartyId, IEnumerable to, UuidType fromType, Guid from) { return new List { @@ -830,7 +830,9 @@ public static List GetRequestToDeleteResource(int authenticated PolicyMatch = new PolicyMatch { OfferedByPartyId = fromPartyId, - CoveredBy = to.SingleToList(), + FromUuid = from, + FromUuidType = fromType, + CoveredBy = to.ToList(), Resource = resource.ToList() } } diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Models/PolicyMatch.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Models/PolicyMatch.cs index c14b1ef9..319c7009 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Models/PolicyMatch.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Models/PolicyMatch.cs @@ -1,3 +1,4 @@ +using Altinn.AccessManagement.Enums; using System.ComponentModel.DataAnnotations; namespace Altinn.AccessManagement.Core.Models @@ -12,6 +13,16 @@ public class PolicyMatch /// public int OfferedByPartyId { get; set; } + /// + /// The type of FromUuid + /// + public UuidType FromUuidType { get; set; } + + /// + /// The values of the FromUuid + /// + public Guid FromUuid { get; set; } + /// /// Gets or sets resource match which uniquely identifies the resource this policy applies to. /// diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/Altinn/PartyAttributeResolver.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/Altinn/PartyAttributeResolver.cs index 20ae7567..e7cea913 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/Altinn/PartyAttributeResolver.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/Altinn/PartyAttributeResolver.cs @@ -22,8 +22,8 @@ public class PartyAttributeResolver : AttributeResolver /// profile client public PartyAttributeResolver(IContextRetrievalService contextRetrievalService, IProfileClient profile) : base(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute) { - AddLeaf([AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute], [AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute], ResolvePartyIdFromParty()); - AddLeaf([AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute], [AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute], ResolvePartyIdFromUser()); + AddLeaf([AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute], [AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationUuid, AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid], ResolvePartyIdOrganizationPersonUuidFromParty()); + AddLeaf([AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute], [AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid], ResolvePartyIdPersonUuidFromUser()); _contextRetrievalService = contextRetrievalService; _profile = profile; @@ -32,7 +32,7 @@ public PartyAttributeResolver(IContextRetrievalService contextRetrievalService, /// /// Resolves a PartyId if given exists /// - public LeafResolver ResolvePartyIdFromUser() => async (attributes, cancellationToken) => + public LeafResolver ResolvePartyIdPersonUuidFromUser() => async (attributes, cancellationToken) => { UserProfile user = await _profile.GetUser( new() { UserId = attributes.GetRequiredInt(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute) }, @@ -40,7 +40,11 @@ public LeafResolver ResolvePartyIdFromUser() => async (attributes, cancellationT if (user != null) { - return [new(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, user.Party.PartyId)]; + return + [ + new(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, user.Party.PartyId), + new(AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid, user.UserUuid), + ]; } return []; @@ -49,11 +53,24 @@ public LeafResolver ResolvePartyIdFromUser() => async (attributes, cancellationT /// /// Resolves a PartyId if given exists /// - public LeafResolver ResolvePartyIdFromParty() => async (attributes, cancellationToken) => + public LeafResolver ResolvePartyIdOrganizationPersonUuidFromParty() => async (attributes, cancellationToken) => { if (await _contextRetrievalService.GetPartyAsync(attributes.GetRequiredInt(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), cancellationToken) is var party && party != null) { - return [new(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, party.PartyId)]; + if (party.Organization != null) + { + return + [ + new(AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationUuid, party.PartyUuid), + ]; + } + else if (party.Person != null) + { + return + [ + new(AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid, party.PartyUuid), + ]; + } } return []; diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs index afd2dbc1..bd45ab23 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Resolvers/BaseUrn.cs @@ -19,9 +19,14 @@ public static class BaseUrn public static string[] InternalIds => [Altinn.Organization.PartyId, Altinn.Person.PartyId, Altinn.Person.UserId, Altinn.EnterpriseUser.UserId, AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute]; /// - /// InternalIds from Altinn 2 + /// InternalIds from Altinn II /// - public static string[] RevokeInternalIds => [AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid]; + public static string[] RevokeInternalFromIds => [AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute]; + + /// + /// InternalIds for revoke + /// + public static string[] RevokeInternalToIds => [AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid, AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationUuid, AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid]; /// /// Resources that belongs to Altinn diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs index 2d66a808..2872abad 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/PolicyAdministrationPoint.cs @@ -910,6 +910,8 @@ private async Task> DeleteAllRulesInPolicy(RequestToDelete policyToDe CoveredByUserId = coveredByUserId, ToUuid = coveredByUuid, ToUuidType = coveredByUuidType, + FromUuid = policyToDelete.PolicyMatch.FromUuid, + FromUuidType = policyToDelete.PolicyMatch.FromUuidType, PerformedByUserId = policyToDelete.DeletedByUserId, BlobStoragePolicyPath = policyPath, BlobStorageVersionId = response.Value.VersionId diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs index a6195152..6273abfe 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs @@ -234,12 +234,12 @@ public async Task RevokeRightsDelegation(int authentic return assertion; } - var fromAttribute = await _resolver.Resolve(delegation.From, [AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute], cancellationToken); - var toAttribute = await _resolver.Resolve(delegation.To, BaseUrn.RevokeInternalIds, cancellationToken); - - var to = GetAttributeMatchFromAttributeMatchList(toAttribute); - - var policiesToDelete = DelegationHelper.GetRequestToDeleteResource(authenticatedUserId, delegation.Rights[0].Resource, fromAttribute.GetRequiredInt(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), to); + var fromAttribute = await _resolver.Resolve(delegation.From, [AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationUuid, AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid], cancellationToken); + var toAttribute = await _resolver.Resolve(delegation.To, BaseUrn.RevokeInternalToIds, cancellationToken); + + var to = FilterRequiredAttributeMatchesFromAttributeMatchList(toAttribute); + bool validUuidFrom = DelegationHelper.TryGetUuidFromAttributeMatch(fromAttribute.ToList(), out Guid fromUuid, out UuidType fromUuidType); + var policiesToDelete = DelegationHelper.GetRequestToDeleteResource(authenticatedUserId, delegation.Rights[0].Resource, fromAttribute.GetRequiredInt(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), to, fromUuidType, fromUuid); await _pap.TryDeleteDelegationPolicies(policiesToDelete, cancellationToken); return assertion; @@ -250,20 +250,41 @@ public async Task RevokeRightsDelegation(int authentic /// /// the list to fetch from /// The identified internal id - private AttributeMatch GetAttributeMatchFromAttributeMatchList(IEnumerable attributeMatches) + private IEnumerable FilterRequiredAttributeMatchesFromAttributeMatchList(IEnumerable attributeMatches) { + List attributeMatchList = []; + bool userSet = false; + if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute)) { - return new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute).Value); + attributeMatchList.Add(new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute).Value)); + userSet = true; + } + + if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute)) + { + if (userSet != true) + { + attributeMatchList.Add(new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute).Value)); + } + } + + if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid)) + { + attributeMatchList.Add(new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid).Value)); } - else if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid)) + + if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid)) { - return new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid).Value); + attributeMatchList.Add(new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PersonUuid).Value)); } - else + + if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationUuid)) { - return new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute).Value); + attributeMatchList.Add(new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationUuid, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.OrganizationUuid).Value)); } + + return attributeMatchList; } /// @@ -275,10 +296,10 @@ private ValidationProblemDetails AssertRevokeDelegationInput(DelegationLookup de _asserter.Join( _asserter.Evaluate( delegation.From, - _asserter.RevokeInternalIds), + _asserter.RevokeInternalFromIds), _asserter.Evaluate( delegation.To, - _asserter.RevokeInternalIds), + _asserter.RevokeInternalToIds), _asserter.Evaluate( delegation.Rights?.FirstOrDefault()?.Resource ?? [], _asserter.DefaultResource)); diff --git a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s delegate org2systemuser.bru b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s delegate org2systemuser.bru new file mode 100644 index 00000000..123e2ed1 --- /dev/null +++ b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s delegate org2systemuser.bru @@ -0,0 +1,84 @@ +meta { + name: o2s delegate org2systemuser + type: http + seq: 2 +} + +post { + url: {{baseUrl}}/accessmanagement/api/v1/internal/{{party}}/rights/delegation/offered + body: json + auth: inherit +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "to": [ + { + "id": "urn:altinn:systemuser:uuid", + "value": "{{to_systemuser}}" + } + ], + "rights": [ + { + "resource": [ + { + "id": "urn:altinn:org", + "value": "{{org}}" + }, + { + "id": "urn:altinn:app", + "value": "{{app}}" + } + ], + "action": "read" + } + ] + } +} + +vars:pre-request { + toSsn: + toLastName: + org: + app: + auth_tokenType: Personal + auth_userId: + auth_partyId: + auth_ssn: + party: +} + +script:pre-request { + const testdata = require(`./Testdata/rights-delegations/${bru.getEnvVar("tokenEnv")}testdata.json`); + const sharedtestdata = require(`./Testdata/sharedtestdata.json`); + bru.setVar("party", testdata.org1.partyid); + bru.setVar("to_systemuser", testdata.system1.uuid); + bru.setVar("org", testdata.org); + bru.setVar("app", testdata.app); + + var getTokenParameters = { + auth_userId: testdata.org1.dagl.userid, + auth_partyId: testdata.org1.dagl.partyid, + auth_ssn: testdata.org1.dagl.pid, + scope: sharedtestdata.scopes.read, + auth_tokenType: sharedtestdata.authTokenType.personal, + auth_scopes: sharedtestdata.auth_scopes.read + } + const token = await testTokenGenerator.getToken(getTokenParameters); + + bru.setVar("bearerToken", token); +} + +tests { + test("organization to organization delegation", function() { + const data = res.getBody(); + expect(res.status).to.equal(200); + expect(data.rightDelegationResults[0]).to.have.property('status', 'Delegated'); + }); + +} diff --git a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s org2systemuser delegation successful.bru b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s org2systemuser delegation successful.bru new file mode 100644 index 00000000..72217627 --- /dev/null +++ b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s org2systemuser delegation successful.bru @@ -0,0 +1,53 @@ +meta { + name: o2s org2systemuser delegation successful + type: http + seq: 3 +} + +get { + url: {{baseUrl}}/accessmanagement/api/v1/internal/{{party}}/rights/delegation/received + body: json + auth: inherit +} + +vars:pre-request { + auth_tokenType: Personal + auth_userId: + auth_partyId: + auth_ssn: + party: +} + +script:pre-request { + const testdata = require(`./Testdata/rights-delegations/${bru.getEnvVar("tokenEnv")}testdata.json`); + const sharedtestdata = require(`./Testdata/sharedtestdata.json`); + bru.setVar("party", testdata.org2.dagl.partyid); + + var getTokenParameters = { + auth_userId: testdata.org2.dagl.userid, + auth_partyId: testdata.org2.dagl.partyid, + auth_ssn: testdata.org2.dagl.pid, + scope: sharedtestdata.scopes.read, + auth_tokenType: sharedtestdata.authTokenType.personal, + auth_scopes: sharedtestdata.auth_scopes.read + } + const token = await testTokenGenerator.getToken(getTokenParameters); + + bru.setVar("bearerToken", token); +} + +tests { + test("organization successfully delegated to an organization", function() { + const testdata = require(`./Testdata/rights-delegations/${bru.getEnvVar("tokenEnv")}testdata.json`); + const data = res.getBody(); + expect(res.status).to.equal(200); + expect(data[0].from[0]).to.have.property('id', 'urn:altinn:partyid'); + expect(data[0].from[0]).to.have.property('value', testdata.org1.partyid.toString()); + expect(data[0].to[0]).to.have.property('id', 'urn:altinn:partyid'); + expect(data[0].to[0]).to.have.property('value', testdata.org2.partyid.toString()); + expect(data[0].resource[0]).to.have.property('id', 'urn:altinn:org'); + expect(data[0].resource[0]).to.have.property('value', bru.getVar('org')); + expect(data[0].resource[1]).to.have.property('id', 'urn:altinn:app'); + expect(data[0].resource[1]).to.have.property('value', bru.getVar('app')); + }); +} diff --git a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s sending org revokes delegation to systemuser.bru b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s sending org revokes delegation to systemuser.bru new file mode 100644 index 00000000..4af9b6d7 --- /dev/null +++ b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Automatic Test Collection/RightsInternal/SystemUser/o2s sending org revokes delegation to systemuser.bru @@ -0,0 +1,70 @@ +meta { + name: o2s sending org revokes delegation to systemuser + type: http + seq: 43 +} + +post { + url: {{baseUrl}}/accessmanagement/api/v1/internal/{{party}}/rights/delegation/offered/revoke + body: json + auth: inherit +} + +body:json { + + { + "to": [ + { + "id": "urn:altinn:partyid", + "value": "{{to_partyid}}" + } + ], + "rights": [ + { + "resource": [ + { + "id": "urn:altinn:org", + "value": "{{org}}" + }, + { + "id": "urn:altinn:app", + "value": "{{app}}" + } + ] + } + ] + } + +} + +vars:pre-request { + auth_tokenType: Personal + auth_userId: + auth_partyId: + auth_ssn: + party: + org: + app: + toUserId: +} + +script:pre-request { + const testdata = require(`./Testdata/rights-delegations/${bru.getEnvVar("tokenEnv")}testdata.json`); + const sharedtestdata = require(`./Testdata/sharedtestdata.json`); + bru.setVar("party", testdata.org1.partyid); + bru.setVar("to_partyid", testdata.org2.partyid); + bru.setVar("org", testdata.org); + bru.setVar("app", testdata.app); + + var getTokenParameters = { + auth_userId: testdata.org1.dagl.userid, + auth_partyId: testdata.org1.dagl.partyid, + auth_ssn: testdata.org1.dagl.pid, + scope: sharedtestdata.scopes.read, + auth_tokenType: sharedtestdata.authTokenType.personal, + auth_scopes: sharedtestdata.auth_scopes.read + } + const token = await testTokenGenerator.getToken(getTokenParameters); + + bru.setVar("bearerToken", token); +} diff --git a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/at22testdata.json b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/at22testdata.json index 0af2c192..c0750f9e 100644 --- a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/at22testdata.json +++ b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/at22testdata.json @@ -52,5 +52,8 @@ "lastname": "KLOSETT", "userid": 20012655, "partyid": 50146491 + }, + "system1": { + "uuid": "e6c868ef-d9d6-4847-ba25-409bbd040540" } } diff --git a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/devtestdata.json b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/devtestdata.json new file mode 100644 index 00000000..b94ed7d2 --- /dev/null +++ b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/devtestdata.json @@ -0,0 +1,34 @@ +{ + "env": "at22", + "org": "ttd", + "app": "apps-test", + "servicecode": "2802", + "serviceeditioncode": "3", + "resource": "", + "org1": { + "orgno": "810414782", + "partyid": 50067258, + "dagl": { + "pid":"21025400167", + "userid": 20004896, + "partyid": 50020295 + }, + "hadm": { + "pid": "17048001742", + "userid": 20003595, + "partyid": 50020440 + } + }, + "org2": { + "orgno": "910049356", + "partyid": 50066506, + "dagl": { + "pid": "26013000394", + "userid": 20004270, + "partyid": 50019590 + } + }, + "system1": { + "uuid": "16C1F2F6-9E00-4922-B16D-74C46D948E61" + } +} diff --git a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/localtestdata.json b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/localtestdata.json index 52c1ca2b..b94ed7d2 100644 --- a/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/localtestdata.json +++ b/src/apps/Altinn.AccessManagement/test/Bruno/Altinn.AccessManagement/Testdata/rights-delegations/localtestdata.json @@ -27,5 +27,8 @@ "userid": 20004270, "partyid": 50019590 } + }, + "system1": { + "uuid": "16C1F2F6-9E00-4922-B16D-74C46D948E61" } } From f2abf64ee6488a04ffdb43573fbf259f87ceb77a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remi=20L=C3=B8voll?= Date: Fri, 3 Jan 2025 10:01:59 +0100 Subject: [PATCH 3/5] Fix for delegation from user should this be allowed? All delegations should be from Party but there exist two test that expect from to be a user --- .../Asserters/AttributeMatchAsserter.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs index f97e3075..af03ee2c 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Asserters/AttributeMatchAsserter.cs @@ -170,7 +170,9 @@ public static void DefaultFrom(this IAssert assert, IDictionary< /// list of attributes public static void RevokeInternalFromIds(this IAssert assert, IDictionary errors, IEnumerable values) => assert.All( - assert.Single(assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute)), + assert.Single( + assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), + assert.HasAttributeTypes(AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute)), assert.AllAttributesHasValues, assert.AttributesAreIntegers(BaseUrn.RevokeInternalFromIds))(errors, values); From 1f08b0b2212dbc7dff63ded43b460724ecd4c598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remi=20L=C3=B8voll?= Date: Fri, 3 Jan 2025 10:27:41 +0100 Subject: [PATCH 4/5] Fixed some code smells --- .../Services/SingleRightsService.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs index 6273abfe..bc5c9043 100644 --- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs +++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessManagement.Core/Services/SingleRightsService.cs @@ -238,7 +238,8 @@ public async Task RevokeRightsDelegation(int authentic var toAttribute = await _resolver.Resolve(delegation.To, BaseUrn.RevokeInternalToIds, cancellationToken); var to = FilterRequiredAttributeMatchesFromAttributeMatchList(toAttribute); - bool validUuidFrom = DelegationHelper.TryGetUuidFromAttributeMatch(fromAttribute.ToList(), out Guid fromUuid, out UuidType fromUuidType); + DelegationHelper.TryGetUuidFromAttributeMatch(fromAttribute.ToList(), out Guid fromUuid, out UuidType fromUuidType); + var policiesToDelete = DelegationHelper.GetRequestToDeleteResource(authenticatedUserId, delegation.Rights[0].Resource, fromAttribute.GetRequiredInt(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute), to, fromUuidType, fromUuid); await _pap.TryDeleteDelegationPolicies(policiesToDelete, cancellationToken); @@ -250,7 +251,7 @@ public async Task RevokeRightsDelegation(int authentic /// /// the list to fetch from /// The identified internal id - private IEnumerable FilterRequiredAttributeMatchesFromAttributeMatchList(IEnumerable attributeMatches) + private static List FilterRequiredAttributeMatchesFromAttributeMatchList(IEnumerable attributeMatches) { List attributeMatchList = []; bool userSet = false; @@ -261,12 +262,9 @@ private IEnumerable FilterRequiredAttributeMatchesFromAttributeM userSet = true; } - if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute)) + if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute) && !userSet) { - if (userSet != true) - { - attributeMatchList.Add(new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute).Value)); - } + attributeMatchList.Add(new AttributeMatch(AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, attributeMatches.First(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute).Value)); } if (attributeMatches.Any(p => p.Id == AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid)) From 7562f75c4ca6d890ea8b4c50a3e532f451359132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remi=20L=C3=B8voll?= Date: Fri, 3 Jan 2025 10:48:42 +0100 Subject: [PATCH 5/5] Add test SystemUser --- .../Controllers/RightsInternalControllerTest.cs | 1 + .../TestDataRevokeOfferedDelegationExternal.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs b/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs index 1250e00d..e1ba5728 100644 --- a/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs +++ b/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Controllers/RightsInternalControllerTest.cs @@ -1557,6 +1557,7 @@ public async Task Delegation_MaskinportenSchema_BadRequest() [MemberData(nameof(TestDataRevokeOfferedDelegationExternal.FromPersonToOrganization), MemberType = typeof(TestDataRevokeOfferedDelegationExternal))] [MemberData(nameof(TestDataRevokeOfferedDelegationExternal.FromOrganizationToOrganization), MemberType = typeof(TestDataRevokeOfferedDelegationExternal))] [MemberData(nameof(TestDataRevokeOfferedDelegationExternal.FromOrganizationToPerson), MemberType = typeof(TestDataRevokeOfferedDelegationExternal))] + [MemberData(nameof(TestDataRevokeOfferedDelegationExternal.FromOrganizationToSystemUser), MemberType = typeof(TestDataRevokeOfferedDelegationExternal))] public async Task RevokeRightsOfferedDelegations_ReturnNoContent(string userToken, RevokeOfferedDelegationExternal input, string partyRouteValue, string headerKey = null, string headerValue = null) { var client = GetTestClient(userToken, WithPDPMock); diff --git a/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Data/TestDataRevokeOfferedDelegationExternal.cs b/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Data/TestDataRevokeOfferedDelegationExternal.cs index 5eadffc5..5afc1f3e 100644 --- a/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Data/TestDataRevokeOfferedDelegationExternal.cs +++ b/src/apps/Altinn.AccessManagement/test/Altinn.AccessManagement.Tests/Data/TestDataRevokeOfferedDelegationExternal.cs @@ -15,6 +15,8 @@ public static class TestDataRevokeOfferedDelegationExternal private static int PersonPaulaUserId => 20000095; + private static Guid System1SystemUserId => new Guid("9B2EB39D-701C-4813-B847-315721DBFBAB"); + private static int PersonPaulaPartyId => 50002203; private static string PersonOrjanSSN => "27099450067"; @@ -100,6 +102,20 @@ public static IEnumerable FromOrganizationToPerson() => [[ OrganizationOrstaPartyId ]]; + /// + /// summary + /// + /// + public static IEnumerable FromOrganizationToSystemUser() => [[ + PrincipalUtil.GetToken(PersonKasperUserId, PersonKasperPartyId, 3), + NewRevokeOfferedModel( + WithRevokeOfferedTo(AltinnXacmlConstants.MatchAttributeIdentifiers.SystemUserUuid, System1SystemUserId), + WithRevokeOfferedAction("read"), + WithRevokeOfferedResource(BaseUrn.Altinn.Resource.AppOwner, ResourceOrg), + WithRevokeOfferedResource(BaseUrn.Altinn.Resource.AppId, ResourceAppId)), + OrganizationOrstaPartyId + ]]; + /// /// summary ///