Skip to content

Commit

Permalink
Added DelegationCheck support for AppInstanceDelegation
Browse files Browse the repository at this point in the history
#840
- New DelegationCheck API endpoint added to AppInstanceDelegationController
- New service implementation for DelegationCheck in AppInstanceDelegationService
- Rewrite of existing internal delegation check logic in delegation service
- Added simple integration test
- Added Bruno automated test requests
  • Loading branch information
Jon Kjetil Øye committed Oct 11, 2024
1 parent fcfe4bb commit 95b4c89
Show file tree
Hide file tree
Showing 60 changed files with 848 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ public static class MatchAttributeIdentifiers
/// </summary>
public const string ResourceRegistryAttribute = "urn:altinn:resource";

/// <summary>
/// Resource delegation urn prefix used in Xacml policy rule subjects to identify rights the resourceId value of the attribute, is allowed to perform delegation of.
/// </summary>
public const string ResourceDelegationAttribute = "urn:altinn:resource:delegation";

/// <summary>
/// Organization name
/// </summary>
Expand Down
22 changes: 22 additions & 0 deletions src/Altinn.AccessManagement.Core/Enums/RightsQueryType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Altinn.AccessManagement.Core.Enums;

/// <summary>
/// Enum for different types of rights queries in Altinn Authorization
/// </summary>
public enum RightsQueryType
{
/// <summary>
/// Default
/// </summary>
NotSet = 0,

/// <summary>
/// Rights query where the recipient is a user
/// </summary>
User = 1,

/// <summary>
/// Rights query where the recipient is an Altinn app
/// </summary>
AltinnApp = 2
}
24 changes: 7 additions & 17 deletions src/Altinn.AccessManagement.Core/Helpers/RightsHelper.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System.Collections.Generic;
using Altinn.AccessManagement.Core.Constants;
using Altinn.AccessManagement.Core.Constants;
using Altinn.AccessManagement.Core.Enums;
using Altinn.AccessManagement.Core.Helpers.Extensions;
using Altinn.AccessManagement.Core.Models;
using Altinn.AccessManagement.Core.Models.ResourceRegistry;
using Authorization.Platform.Authorization.Models;

namespace Altinn.AccessManagement.Core.Helpers
Expand Down Expand Up @@ -57,23 +56,14 @@ public static List<AttributeMatch> GetDelegationSubjectAttributeMatches(Delegati
/// <summary>
/// Builds a RightsQuery request model for lookup of a users rights for a given service resource on behalf of the given reportee party
/// </summary>
public static RightsQuery GetRightsQuery(int userId, int fromPartyId, string resourceRegistryId = null, string org = null, string app = null)
public static RightsQuery GetRightsQuery(int userId, int fromPartyId, ServiceResource resource)
{
if (!string.IsNullOrEmpty(org) && !string.IsNullOrEmpty(app))
{
return new RightsQuery
{
To = new List<AttributeMatch> { new AttributeMatch { Id = AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, Value = userId.ToString() } },
From = new List<AttributeMatch> { new AttributeMatch { Id = AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, Value = fromPartyId.ToString() } },
Resource = new List<AttributeMatch> { new AttributeMatch { Id = AltinnXacmlConstants.MatchAttributeIdentifiers.OrgAttribute, Value = org }, new AttributeMatch { Id = AltinnXacmlConstants.MatchAttributeIdentifiers.AppAttribute, Value = app } }
};
}

return new RightsQuery
return new RightsQuery()
{
Type = RightsQueryType.User,
To = new List<AttributeMatch> { new AttributeMatch { Id = AltinnXacmlConstants.MatchAttributeIdentifiers.UserAttribute, Value = userId.ToString() } },
From = new List<AttributeMatch> { new AttributeMatch { Id = AltinnXacmlConstants.MatchAttributeIdentifiers.PartyAttribute, Value = fromPartyId.ToString() } },
Resource = new AttributeMatch { Id = AltinnXacmlConstants.MatchAttributeIdentifiers.ResourceRegistryAttribute, Value = resourceRegistryId }.SingleToList()
Resource = resource
};
}

Expand All @@ -84,7 +74,7 @@ public static RightsQuery GetRightsQuery(int userId, int fromPartyId, string res
/// <returns>the decision</returns>
public static bool CheckIfRuleIsAnEndUserRule(Right right)
{
List<RightSource> roleAccessSources = right.RightSources.Where(rs => rs.RightSourceType != Enums.RightSourceType.DelegationPolicy).ToList();
List<RightSource> roleAccessSources = right.RightSources.Where(rs => rs.RightSourceType != RightSourceType.DelegationPolicy).ToList();
if (roleAccessSources.Any())
{
List<AttributeMatch> roles = GetAttributeMatches(roleAccessSources.SelectMany(roleAccessSource => roleAccessSource.PolicySubjects)).FindAll(policySubject => policySubject.Id.Equals(AltinnXacmlConstants.MatchAttributeIdentifiers.RoleAttribute, StringComparison.OrdinalIgnoreCase));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Altinn.AccessManagement.Core.Enums;
using Altinn.AccessManagement.Core.Models.Register;
using Altinn.AccessManagement.Core.Models.ResourceRegistry;
using Altinn.Swashbuckle.Examples;

namespace Altinn.AccessManagement.Core.Models;

Expand Down Expand Up @@ -43,7 +41,7 @@ public class AppsInstanceDelegationRequest
/// <summary>
/// The app performing the delegation
/// </summary>
public IEnumerable<AttributeMatch> PerformedBy { get; set; }
public ResourceIdUrn PerformedBy { get; set; }

/// <summary>
/// Gets or sets the rights to delegate
Expand Down
8 changes: 8 additions & 0 deletions src/Altinn.AccessManagement.Core/Models/AttributeMatch.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using Altinn.Urn;

namespace Altinn.AccessManagement.Core.Models
{
Expand Down Expand Up @@ -58,5 +59,12 @@ public AttributeMatch(string id, object value)
/// <returns></returns>
public override string ToString() =>
$"{Id.ToLowerInvariant()}:{Value}";

/// <summary>
/// Creates a KeyValueUrn from the attribute match
/// </summary>
/// <returns>KeyValueUrn</returns>
public KeyValueUrn ToKeyValueUrn() =>
KeyValueUrn.CreateUnchecked($"{Id.ToLowerInvariant()}:{Value}", Id.Length + 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
using Altinn.AccessManagement.Core.Models.ResourceRegistry;

namespace Altinn.AccessManagement.Core.Models;

/// <summary>
/// Request model for a list of all delegable rights for a specific resource.
/// </summary>
public class ResourceDelegationCheckRequest
{
/// <summary>
/// Gets or sets the urn for identifying the resource of the rights to be checked
/// </summary>
[Required]
public ResourceIdUrn ResourceId { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Altinn.AccessManagement.Core.Models.Register;

namespace Altinn.AccessManagement.Core.Models;

/// <summary>
/// Response model for the result of a delegation status check, for which rights a user is able to delegate between two parties.
/// </summary>
public class ResourceDelegationCheckResponse
{
/// <summary>
/// Gets or sets the urn identifying the party the rights can be delegated from
/// </summary>
public required PartyUrn From { get; set; }

/// <summary>
/// Gets or sets a list of right delegation status models
/// </summary>
public List<ResourceRightDelegationCheckResult> ResourceRightDelegationCheckResults { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using Altinn.AccessManagement.Core.Enums;
using Altinn.AccessManagement.Core.Models.Rights;
using Altinn.Urn;

namespace Altinn.AccessManagement.Core.Models;

/// <summary>
/// Response model describing the delegation status for a given single right, whether the authenticated user is able to delegate the right or not on behalf of the from part.
/// </summary>
public class ResourceRightDelegationCheckResult
{
/// <summary>
/// Gets or sets the right key
/// </summary>
[Required]
public string RightKey { get; set; }

/// <summary>
/// Gets or sets the list of resource matches which uniquely identifies the resource this right applies to.
/// </summary>
[Required]
public List<KeyValueUrn> Resource { get; set; }

/// <summary>
/// Gets or sets the set of Attribute Id and Attribute Value for a specific action, to identify the action this right applies to
/// </summary>
[Required]
public ActionUrn Action { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the right is delegable or not
/// </summary>
[Required]
[JsonConverter(typeof(JsonStringEnumConverter))]
public DelegableStatus Status { get; set; }

/// <summary>
/// Gets or sets a list of details describing why or why not the right is valid in the current user and reportee party context
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public List<Detail> Details { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#nullable enable

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand All @@ -27,6 +24,14 @@ private ActionIdentifier(string value)
_value = value;
}

/// <summary>
/// Creates a new <see cref="ActionIdentifier"/> from the specified value without validation.
/// </summary>
/// <param name="value">The action identifier.</param>
/// <returns>A <see cref="ActionIdentifier"/>.</returns>
public static ActionIdentifier CreateUnchecked(string value)
=> new(value);

/// <inheritdoc/>
public static IEnumerable<ActionIdentifier>? GetExamples(ExampleDataOptions options)
{
Expand Down
14 changes: 11 additions & 3 deletions src/Altinn.AccessManagement.Core/Models/Rights/RightsQuery.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Altinn.AccessManagement.Core.Models
using Altinn.AccessManagement.Core.Enums;
using Altinn.AccessManagement.Core.Models.ResourceRegistry;

namespace Altinn.AccessManagement.Core.Models
{
/// <summary>
/// Queries for a list of all rights between two parties for a specific resource.
Expand All @@ -7,6 +10,11 @@
/// </summary>
public class RightsQuery
{
/// <summary>
/// Gets or sets the type of rights query to perform
/// </summary>
public RightsQueryType Type { get; set; }

/// <summary>
/// Gets or sets the set of Attribute Id and Attribute Value for the entity having offered rights
/// </summary>
Expand All @@ -18,8 +26,8 @@ public class RightsQuery
public List<AttributeMatch> To { get; set; }

/// <summary>
/// Gets or sets the set of Attribute Id and Attribute Value for identifying the resource the rights
/// Gets or sets the service resource model of the rights
/// </summary>
public List<AttributeMatch> Resource { get; set; }
public ServiceResource Resource { get; set; }
}
}
Loading

0 comments on commit 95b4c89

Please sign in to comment.