Skip to content

Commit

Permalink
add auth to all legacy enpoints (#468)
Browse files Browse the repository at this point in the history
* add auth to all legacy enpoints

* correct error message

* correct error message

---------

Co-authored-by: Hammerbeck <[email protected]>
  • Loading branch information
Andreass2 and Hammerbeck authored Nov 8, 2024
1 parent 817b4b5 commit 8656258
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ internal static LegacyGetCorrespondencesRequest MapToRequest(LegacyGetCorrespond
IncludeArchived = requestExt.IncludeArchived,
IncludeDeleted = requestExt.IncludeDeleted,
InstanceOwnerPartyIdList = requestExt.InstanceOwnerPartyIdList,
OnbehalfOfPartyId = requestExt.OnbehalfOfPartyId,
Offset = requestExt.Offset,
Limit = requestExt.Limit,
Language = requestExt.Language,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ public class LegacyGetCorrespondencesRequestExt
[JsonPropertyName("limit")]
public int Limit { get; set; }

/// <summary>
/// PartyId of the end user performing the search
/// </summary>
[JsonPropertyName("onbehalfOfPartyId")]
public required int OnbehalfOfPartyId { get; set; }

/// <summary>
/// A list of the parties/recipients that own the Correspondence instances
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,14 @@ public async Task<OneOf<LegacyGetCorrespondencesResponse, Error>> Process(Legacy
var limit = request.Limit == 0 ? 50 : request.Limit;
DateTimeOffset? to = request.To != null ? ((DateTimeOffset)request.To).ToUniversalTime() : null;
DateTimeOffset? from = request.From != null ? ((DateTimeOffset)request.From).ToUniversalTime() : null;

// Verify and map partyId for user
if (request.OnbehalfOfPartyId == 0 || request.OnbehalfOfPartyId == int.MinValue)
if (_userClaimsHelper.GetPartyId() is not int partyId)
{
return Errors.CouldNotFindOrgNo; // TODO: Update to better error message
return Errors.InvalidPartyId;
}
var userParty = await _altinnRegisterService.LookUpPartyByPartyId(request.OnbehalfOfPartyId, cancellationToken);
var userParty = await _altinnRegisterService.LookUpPartyByPartyId(partyId, cancellationToken);
if (userParty == null || (string.IsNullOrEmpty(userParty.SSN) && string.IsNullOrEmpty(userParty.OrgNumber)))
{
return Errors.CouldNotFindOrgNo; // TODO: Update to better error message
return Errors.CouldNotFindOrgNo;
}
var recipients = new List<string>();
if (request.InstanceOwnerPartyIdList != null && request.InstanceOwnerPartyIdList.Length > 0)
Expand All @@ -68,16 +66,15 @@ public async Task<OneOf<LegacyGetCorrespondencesResponse, Error>> Process(Legacy
}
else
{
recipients.Add(string.IsNullOrEmpty(userParty.SSN) ? "0192:" + userParty.OrgNumber : userParty.SSN);
if (!string.IsNullOrEmpty(userParty.SSN)) recipients.Add(userParty.SSN);
if (!string.IsNullOrEmpty(userParty.OrgNumber)) recipients.Add("0192:" + userParty.OrgNumber);
}

List<string> resourcesToSearch = new List<string>();

// Get all correspondences owned by Recipients
var correspondences = await _correspondenceRepository.GetCorrespondencesForParties(request.Offset, limit, from, to, request.Status, recipients, resourcesToSearch, request.Language, request.IncludeActive, request.IncludeArchived, request.IncludeDeleted, request.SearchString, cancellationToken);

Console.WriteLine($"Found {correspondences.Item1.Count} correspondences");

var resourceIds = correspondences.Item1.Select(c => c.ResourceId).Distinct().ToList();
var authorizedCorrespondences = new List<CorrespondenceEntity>();
List<LegacyCorrespondenceItem> correspondenceItems = new List<LegacyCorrespondenceItem>();
Expand Down Expand Up @@ -112,6 +109,11 @@ public async Task<OneOf<LegacyGetCorrespondencesResponse, Error>> Process(Legacy
}
foreach (var correspondence in correspondences.Item1)
{
var minAuthLevel = await _altinnAuthorizationService.CheckUserAccessAndGetMinimumAuthLevel(userParty.SSN, correspondence.ResourceId, new List<ResourceAccessLevel> { ResourceAccessLevel.Read }, correspondence.Recipient, cancellationToken);
if (minAuthLevel == null)
{
continue;
}
var purgedStatus = correspondence.GetPurgedStatus();
var owner = resourceOwners.SingleOrDefault(r => r.OrgNumber == correspondence.Sender)?.Party;
var recipient = recipientDetails.SingleOrDefault(r => r.OrgNumber == correspondence.Recipient)?.Party;
Expand All @@ -124,7 +126,7 @@ public async Task<OneOf<LegacyGetCorrespondencesResponse, Error>> Process(Legacy
MessageTitle = correspondence.Content.MessageTitle,
Status = correspondence.GetLatestStatusWithoutPurged().Status,
CorrespondenceId = correspondence.Id,
MinimumAuthenticationLevel = 0, // Insert from response from PDP multirequest
MinimumAuthenticationLevel = (int)minAuthLevel,
Published = correspondence.Published,
PurgedStatus = purgedStatus?.Status,
Purged = purgedStatus?.StatusChanged,
Expand All @@ -135,7 +137,6 @@ public async Task<OneOf<LegacyGetCorrespondencesResponse, Error>> Process(Legacy
}
);
}
Console.WriteLine($"Finished correspondences: {correspondenceItems.Count}");
var response = new LegacyGetCorrespondencesResponse
{
Items = correspondenceItems,
Expand All @@ -148,14 +149,4 @@ public async Task<OneOf<LegacyGetCorrespondencesResponse, Error>> Process(Legacy
};
return response;
}
}

// TODO: Get All Resources these parties can access. I do think these resources is included in authorized parties response
// <https://docs.altinn.studio/api/resourceregistry/spec/#/Resource/post_resource_bysubjects>
// https://digdir.slack.com/archives/D07CXBW9AJH/p1727966248268839?thread_ts=1727960943.538609&cid=D07CXBW9AJH

// TODO: Authorize each correspondence using multirequests
// https://docs.altinn.studio/authorization/guides/xacml/#request-for-multiple-decisions
// https://docs.altinn.studio/api/authorization/spec/#/Decision/post_authorize
// Filter out where authorization failed
// Enrich with minimum authentication level where successfull
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ public class LegacyGetCorrespondencesRequest
{
public required int[] InstanceOwnerPartyIdList { get; set; }

public required int OnbehalfOfPartyId { get; set; }

public int Offset { get; set; }

public int Limit { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,21 @@ public async Task<OneOf<LegacyGetCorrespondenceHistoryResponse, Error>> Process(
{
return Errors.CouldNotFindOrgNo;
}
// TODO: Authorize party
var correspondence = await _correspondenceRepository.GetCorrespondenceById(correspondenceId, true, true, cancellationToken);
if (correspondence is null)
{
return Errors.CorrespondenceNotFound;
}
var minimumAuthLevel = await _altinnAuthorizationService.CheckUserAccessAndGetMinimumAuthLevel(recipientParty.SSN, correspondence.ResourceId, new List<ResourceAccessLevel> { ResourceAccessLevel.Read }, correspondence.Recipient, cancellationToken);
if (minimumAuthLevel is null)
{
return Errors.LegacyNoAccessToCorrespondence;
}
var senderParty = await _altinnRegisterService.LookUpPartyById(correspondence.Sender, cancellationToken);
if (senderParty == null || (string.IsNullOrEmpty(senderParty.SSN) && string.IsNullOrEmpty(senderParty.OrgNumber)))
{
return Errors.CouldNotFindOrgNo;
}
var minimumAuthLevel = await _altinnAuthorizationService.CheckUserAccessAndGetMinimumAuthLevel(recipientParty.SSN, correspondence.ResourceId, new List<ResourceAccessLevel> { ResourceAccessLevel.Read }, correspondence.Recipient, cancellationToken);
if (minimumAuthLevel is not int authenticationLevel)
{
authenticationLevel = 2; // TODO: Remove when authorization is implemented
// return Errors.LegacyNoAccessToCorrespondence;
}

var correspondenceHistory = correspondence.Statuses
.Where(s => s.Status.IsAvailableForRecipient())
Expand All @@ -61,7 +59,7 @@ public async Task<OneOf<LegacyGetCorrespondenceHistoryResponse, Error>> Process(
User = new LegacyUser
{
PartyId = recipientParty.PartyId.ToString(),
AuthenticationLevel = authenticationLevel
AuthenticationLevel = (int)minimumAuthLevel
},
}).ToList();

Expand All @@ -81,7 +79,7 @@ public async Task<OneOf<LegacyGetCorrespondenceHistoryResponse, Error>> Process(
notificationDetails.NotificationsStatusDetails.Sms.Recipient,
notification.IsReminder,
senderParty.PartyId.ToString(),
authenticationLevel));
(int)minimumAuthLevel));
}
if (notificationDetails.NotificationsStatusDetails.Email is not null)
{
Expand All @@ -90,7 +88,7 @@ public async Task<OneOf<LegacyGetCorrespondenceHistoryResponse, Error>> Process(
notificationDetails.NotificationsStatusDetails.Email.Recipient,
notification.IsReminder,
senderParty.PartyId.ToString(),
authenticationLevel));
(int)minimumAuthLevel));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public async Task<OneOf<LegacyGetCorrespondenceOverviewResponse, Error>> Process
{
if (_userClaimsHelper.GetPartyId() is not int partyId)
{
return Errors.NoAccessToResource;
return Errors.InvalidPartyId;
}
var userParty = await _altinnRegisterService.LookUpPartyByPartyId(partyId, cancellationToken);
if (userParty == null || (string.IsNullOrEmpty(userParty.SSN) && string.IsNullOrEmpty(userParty.OrgNumber)))
Expand All @@ -51,7 +51,6 @@ public async Task<OneOf<LegacyGetCorrespondenceOverviewResponse, Error>> Process
{
return Errors.LegacyNoAccessToCorrespondence;
}
var recipients = new List<string>();
if (correspondence.Recipient != userParty.SSN && correspondence.Recipient != ("0192:" + userParty.OrgNumber))
{
var authorizedParties = await _altinnAccessManagementService.GetAuthorizedParties(userParty, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Altinn.Correspondence.Application.Helpers;
using Altinn.Correspondence.Core.Models.Entities;
using Altinn.Correspondence.Core.Models.Enums;
using Altinn.Correspondence.Core.Repositories;
using Altinn.Correspondence.Core.Services;
using OneOf;
Expand All @@ -9,20 +10,23 @@ public class LegacyUpdateCorrespondenceStatusHandler : IHandler<UpdateCorrespond
{
private readonly ICorrespondenceRepository _correspondenceRepository;
private readonly ICorrespondenceStatusRepository _correspondenceStatusRepository;
private readonly IAltinnAuthorizationService _altinnAuthorizationService;
private readonly IAltinnRegisterService _altinnRegisterService;
private readonly IEventBus _eventBus;
private readonly UserClaimsHelper _userClaimsHelper;
private readonly UpdateCorrespondenceStatusHelper _updateCorrespondenceStatusHelper;
public LegacyUpdateCorrespondenceStatusHandler(
ICorrespondenceRepository correspondenceRepository,
ICorrespondenceStatusRepository correspondenceStatusRepository,
IAltinnAuthorizationService altinnAuthorizationService,
IAltinnRegisterService altinnRegisterService,
IEventBus eventBus,
UserClaimsHelper userClaimsHelper,
UpdateCorrespondenceStatusHelper updateCorrespondenceStatusHelper)
{
_correspondenceRepository = correspondenceRepository;
_correspondenceStatusRepository = correspondenceStatusRepository;
_altinnAuthorizationService = altinnAuthorizationService;
_altinnRegisterService = altinnRegisterService;
_eventBus = eventBus;
_userClaimsHelper = userClaimsHelper;
Expand All @@ -39,12 +43,16 @@ public async Task<OneOf<Guid, Error>> Process(UpdateCorrespondenceStatusRequest
{
return Errors.CouldNotFindOrgNo;
}
// TODO: Authorize party
var correspondence = await _correspondenceRepository.GetCorrespondenceById(request.CorrespondenceId, true, false, cancellationToken);
if (correspondence == null)
{
return Errors.CorrespondenceNotFound;
}
var minimumAuthLevel = await _altinnAuthorizationService.CheckUserAccessAndGetMinimumAuthLevel(party.SSN, correspondence.ResourceId, new List<ResourceAccessLevel> { ResourceAccessLevel.Read }, correspondence.Recipient, cancellationToken);
if (minimumAuthLevel == null)
{
return Errors.LegacyNoAccessToCorrespondence;
}
var currentStatus = correspondence.GetLatestStatus();
if (currentStatus is null)
{
Expand Down

0 comments on commit 8656258

Please sign in to comment.