Skip to content

Commit

Permalink
User can edit actions on delegated service (#1130)
Browse files Browse the repository at this point in the history
* trigger delegation modal from service display

* display which resources user already has on delegation

* display what rights the user already has

* made hooks for delegation and revoke rights

* new revoke endpoint and hook based on backends new endpoints

* added use of new endpoints for edit functionality

* fixed and added tests

* added final tests

* moved back button up

* Fix code scanning alert no. 36: Log entries created from user input

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fixed warnings

* more conditional testing

* typo

* more warning fixes

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
  • Loading branch information
allinox and github-advanced-security[bot] authored Oct 25, 2024
1 parent d64ee2b commit 6385d56
Show file tree
Hide file tree
Showing 49 changed files with 1,315 additions and 1,909 deletions.
7 changes: 2 additions & 5 deletions .github/workflows/continuous-integration-frontend.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
name: 'Continuous Integration: Frontend'

on:
workflow_dispatch:
workflow_dispatch: # Manual trigger
push:
branches: [main]
paths-ignore:
- backend/**

pull_request:
types: [opened, synchronize, reopened]
paths-ignore:
- backend/**

jobs:
ci:
name: 'Continous Integration'
name: 'Continuous Integration'
uses: './.github/workflows/template-build-and-test-frontend.yml'
Original file line number Diff line number Diff line change
Expand Up @@ -122,27 +122,32 @@ public interface IAccessManagementClient
Task<HttpResponseMessage> GetSingleRightsForRightholder(string party, string userId);

/// <summary>
/// Revokes a single rights delegation
/// Revokes all rights on a resource that has been granted from one party to another.
/// </summary>
/// <param name="party">
/// The party from which the rights have been given (delegator)
/// </param>
/// <param name="delegationObject">
/// The delegation object to be revoked
/// </param>
/// <param name="from">The right owner on which behalf access to the resource has been granted. Provided on urn format</param>
/// <param name="to">The right holder that has been granted access to the resource. Provided on urn format</param>
/// <param name="resourceId">The identifier of the resource that has been granted access to</param>
/// <returns></returns>
Task<HttpResponseMessage> RevokeOfferedSingleRightsDelegation(string party, DelegationInput delegationObject);
Task<HttpResponseMessage> RevokeResourceDelegation(string from, string to, string resourceId);

/// <summary>
/// Revokes a single rights delegation
/// Revokes a single right on a resource that has been granted from one party to another.
/// </summary>
/// <param name="party">
/// The party from which the rights have been given (delegator)
/// </param>
/// <param name="delegationObject">
/// The delegation object to be revoked
/// </param>
/// <param name="from">The right owner on which behalf access to the resource has been granted. Provided on urn format</param>
/// <param name="to">The right holder that has been granted access to the resource. Provided on urn format</param>
/// <param name="resourceId">The identifier of the resource that has been granted access to</param>
/// <param name="rightKey">The identifier of the right that is to be revoked</param>
/// <returns></returns>
Task<HttpResponseMessage> RevokeRightDelegation(string from, string to, string resourceId, string rightKey);

/// <summary>
/// Revokes a single right on a resource that has been granted from one party to another.
/// </summary>
/// <param name="from">The right owner on which behalf access to the resource has been granted. Provided on urn format</param>
/// <param name="to">The right holder that has been granted access to the resource. Provided on urn format</param>
/// <param name="resourceId">The identifier of the resource that has been granted access to</param>
/// <param name="rightKeys">List of identifiers for the rights to be delegated</param>
/// <returns></returns>
Task<HttpResponseMessage> RevokeReceivedSingleRightsDelegation(string party, DelegationInput delegationObject);
Task<HttpResponseMessage> DelegateResourceRights(string from, string to, string resourceId, List<string> rightKeys);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,16 @@ public RevokeReceivedDelegation(RevokeDelegationDTO dto)
From = new List<IdValuePair> { new IdValuePair { Id = "urn:altinn:organizationnumber", Value = dto.OrgNumber } };
Rights = new List<Right> { new Right { Resource = new List<IdValuePair> { new IdValuePair { Id = "urn:altinn:resource", Value = dto.ApiId } } } };
}

/// <summary>
/// Initializes a new instance of the <see cref="RevokeReceivedDelegation"/> class.
/// </summary>
/// <param name="from">The party from which the delegation is received</param>
/// <param name="rights">The rights that are to be revoked</param>
public RevokeReceivedDelegation(List<IdValuePair> from, List<Right> rights)
{
From = from;
Rights = rights;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Altinn.AccessManagement.UI.Core.Models.ResourceRegistry.Frontend;

namespace Altinn.AccessManagement.UI.Core.Models.SingleRight
{
/// <summary>
/// Used to display a delegation in GUI, complete with the delegated rights and information about the resource
/// </summary>
public class ResourceDelegation
{
/// <summary>
/// The resource delegated.
/// </summary>
public ServiceResourceFE Resource { get; set; }

/// <summary>
/// Information about the delegation and rights
/// </summary>
public DelegationOutput Delegation { get; set; }

/// <summary>
/// Constructor
/// </summary>
public ResourceDelegation(ServiceResourceFE resource, DelegationOutput delegation)
{
Resource = resource;
Delegation = delegation;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Altinn.AccessManagement.UI.Core.Models.SingleRight
{
/// <summary>
/// The edits to be made to the delegated right on a resource
/// </summary>
public class RightChanges
{
/// <summary>
/// List of rightKeys for the rights that are to be delegated
/// </summary>
public List<string> RightsToDelegate { get; set; }

/// <summary>
/// List of rightKeys for the rights that are to be revoked
/// </summary>
public List<string> RightsToRevoke { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using Altinn.AccessManagement.UI.Core.Models;
using Altinn.AccessManagement.UI.Core.Models.ResourceRegistry.Frontend;
using Altinn.AccessManagement.UI.Core.Models.SingleRight;
using Altinn.AccessManagement.UI.Core.Models.SingleRight.CheckDelegationAccess;

namespace Altinn.AccessManagement.UI.Core.Services.Interfaces
{
Expand Down Expand Up @@ -57,15 +55,25 @@ public interface ISingleRightService
/// The user id of the rightholder
/// </param>
/// <returns></returns>
Task<List<ServiceResourceFE>> GetSingleRightsForRightholder(string languageCode, string party, string userId);
Task<List<ResourceDelegation>> GetSingleRightsForRightholder(string languageCode, string party, string userId);

/// <summary>
/// Revokes a single right for a rightholder.
/// Revokes all rights on a resource that has been granted from one party to another.
/// </summary>
/// <param name="party">The party from which the rights have been given (delegator).</param>
/// <param name="delegationDTO">The delegation data transfer object containing the details of the revocation.</param>
/// <param name="delegationType">The type of delegation to be revoked.</param>
/// <param name="from">The right owner on which behalf access to the resource has been granted. Provided on urn format</param>
/// <param name="to">The right holder that has been granted access to the resource. Provided on urn format</param>
/// <param name="resourceId">The identifier of the resource that has been granted access to</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the HTTP response message.</returns>
Task<HttpResponseMessage> RevokeSingleRightForRightholder(string party, RevokeSingleRightDelegationDTO delegationDTO, DelegationType delegationType);
Task<HttpResponseMessage> RevokeResourceAccess(string from, string to, string resourceId);

/// <summary>
/// Makes requested changes to the rights on a resource that has been granted from one party to another.
/// </summary>
/// <param name="from">The right owner on which behalf access to the resource has been granted. Provided on urn format</param>
/// <param name="to">The right holder that has been granted access to the resource. Provided on urn format</param>
/// <param name="resourceId">The identifier of the resource that has been granted access to</param>
/// <param name="rightsUpdate">The changes in right accesses that is to be made</param>
/// <returns>A list of right keys whose edits failed, if any</returns>
Task<List<string>> EditResourceAccess(string from, string to, string resourceId, RightChanges rightsUpdate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Altinn.AccessManagement.UI.Core.Models;
using Altinn.AccessManagement.UI.Core.Models.ResourceRegistry.Frontend;
using Altinn.AccessManagement.UI.Core.Models.ResourceRegistry.ResourceOwner;
using Altinn.AccessManagement.UI.Core.Models.SingleRight;
using Altinn.AccessManagement.UI.Core.Services.Interfaces;
using Azure;

Expand Down Expand Up @@ -52,20 +53,20 @@ public async Task<HttpResponseMessage> ClearAccessCacheOnRecipient(string party,
}

/// <inheritdoc />
public async Task<List<ServiceResourceFE>> GetSingleRightsForRightholder(string languageCode, string party, string userId)
public async Task<List<ResourceDelegation>> GetSingleRightsForRightholder(string languageCode, string party, string userId)
{
var res = await _accessManagementClient.GetSingleRightsForRightholder(party, userId);
var results = await res.Content.ReadAsStringAsync();

var delegationOutput = JsonSerializer.Deserialize<List<DelegationOutput>>(results, options);
List<ServiceResourceFE> serviceResourceFE = new List<ServiceResourceFE>();
var delegationOutputs = JsonSerializer.Deserialize<List<DelegationOutput>>(results, options);
List<ResourceDelegation> delegationsFE = new List<ResourceDelegation>();

// Create a Lookup to map orgnr to org details
OrgList orgList = await _resourceRegistryClient.GetAllResourceOwners();

foreach (var item in delegationOutput)
foreach (var delegation in delegationOutputs)
{
var firstRightDelegationResult = item.RightDelegationResults?.First();
var firstRightDelegationResult = delegation.RightDelegationResults?.First();
var firstResource = firstRightDelegationResult?.Resource?.First();
var resourceId = firstResource?.Value;

Expand All @@ -79,55 +80,66 @@ public async Task<List<ServiceResourceFE>> GetSingleRightsForRightholder(string
// Find the logo based on the orgnr in the orgnrToOrgLookup
orgList.Orgs.TryGetValue(resource.HasCompetentAuthority.Orgcode.ToLower(), out var org);

serviceResourceFE.Add(new ServiceResourceFE(
resource.Identifier,
resource.Title?.GetValueOrDefault(languageCode) ?? resource.Title?.GetValueOrDefault("nb"),
resourceType: resource.ResourceType,
status: resource.Status,
resourceReferences: resource.ResourceReferences,
resourceOwnerName: resource.HasCompetentAuthority?.Name?.GetValueOrDefault(languageCode) ?? resource.HasCompetentAuthority?.Name?.GetValueOrDefault("nb"),
resourceOwnerOrgNumber: resource.HasCompetentAuthority?.Organization,
rightDescription: resource.RightDescription?.GetValueOrDefault(languageCode) ?? resource.RightDescription?.GetValueOrDefault("nb"),
description: resource.Description?.GetValueOrDefault(languageCode) ?? resource.Description?.GetValueOrDefault("nb"),
visible: resource.Visible,
delegable: resource.Delegable,
contactPoints: resource.ContactPoints,
spatial: resource.Spatial,
authorizationReference: resource.AuthorizationReference,
resourceOwnerLogoUrl: org?.Logo));
ServiceResourceFE resourceFE = new ServiceResourceFE(
resource.Identifier,
resource.Title?.GetValueOrDefault(languageCode) ?? resource.Title?.GetValueOrDefault("nb"),
resourceType: resource.ResourceType,
status: resource.Status,
resourceReferences: resource.ResourceReferences,
resourceOwnerName: resource.HasCompetentAuthority?.Name?.GetValueOrDefault(languageCode) ?? resource.HasCompetentAuthority?.Name?.GetValueOrDefault("nb"),
resourceOwnerOrgNumber: resource.HasCompetentAuthority?.Organization,
rightDescription: resource.RightDescription?.GetValueOrDefault(languageCode) ?? resource.RightDescription?.GetValueOrDefault("nb"),
description: resource.Description?.GetValueOrDefault(languageCode) ?? resource.Description?.GetValueOrDefault("nb"),
visible: resource.Visible,
delegable: resource.Delegable,
contactPoints: resource.ContactPoints,
spatial: resource.Spatial,
authorizationReference: resource.AuthorizationReference,
resourceOwnerLogoUrl: org?.Logo);

delegationsFE.Add(new ResourceDelegation(resourceFE, delegation));
}

return serviceResourceFE;
return delegationsFE;
}

/// <summary>
/// Revokes a single right for a rightholder.
/// </summary>
/// <param name="party">The party ID.</param>
/// <param name="delegationDTO">The delegation DTO.</param>
/// <param name="delegationType">The type of delegation.</param>
/// <returns>The task representing the asynchronous operation.</returns>
public Task<HttpResponseMessage> RevokeSingleRightForRightholder(string party, RevokeSingleRightDelegationDTO delegationDTO, DelegationType delegationType)
/// <inheritdoc />
public Task<HttpResponseMessage> RevokeResourceAccess(string from, string to, string resourceId)
{
var delegationObject = new DelegationInput
{
To = new List<IdValuePair> { new IdValuePair { Id = "urn:altinn:userId", Value = delegationDTO.UserId } },
Rights = new List<Right>
{
new Right
{
Resource = new List<IdValuePair> { new IdValuePair { Id = "urn:altinn:resource", Value = delegationDTO.ResourceId } }
}
}
};
if (delegationType == DelegationType.Offered)
return _accessManagementClient.RevokeResourceDelegation(from, to, resourceId);
}

/// <inheritdoc />
public async Task<List<string>> EditResourceAccess(string from, string to, string resourceId, RightChanges update)
{
List<string> failedEdits = new List<string>();

var delResponse = await _accessManagementClient.DelegateResourceRights(from, to, resourceId, update.RightsToDelegate);
var delegationResult = await delResponse.Content.ReadAsStringAsync();

DelegationOutput delegationOutput = JsonSerializer.Deserialize<DelegationOutput>(delegationResult, options);

var failingDelegations = delegationOutput.RightDelegationResults.Where(right => right.Status != "Delegated").Select(right => right.RightKey).ToList();

if (failingDelegations != null && failingDelegations.Count > 0)
{
return _accessManagementClient.RevokeOfferedSingleRightsDelegation(party, delegationObject);
failedEdits.AddRange(failingDelegations);
}
else

foreach (string rightKey in update.RightsToRevoke)
{
return _accessManagementClient.RevokeReceivedSingleRightsDelegation(party, delegationObject);
var revokeResponse = await _accessManagementClient.RevokeRightDelegation(from, to, resourceId, rightKey);
var revokeResult = await revokeResponse.Content.ReadAsStringAsync();

bool deleted = JsonSerializer.Deserialize<bool>(revokeResult, options);

if (!deleted)
{
failedEdits.Add(rightKey);
}
}

return failedEdits;
}
}
}
Loading

0 comments on commit 6385d56

Please sign in to comment.