From 61b88f4b1fa508b745fca782396a7a4365ede570 Mon Sep 17 00:00:00 2001 From: Hammerbeck Date: Fri, 8 Nov 2024 12:28:33 +0100 Subject: [PATCH 1/3] add auth to all legacy enpoints --- .../Mappers/LegacyGetCorrespondencesMapper.cs | 1 - .../LegacyGetCorrespondencesRequestExt.cs | 6 ---- .../LegacyGetCorrespondencesHandler.cs | 35 +++++++------------ .../LegacyGetCorrespondencesRequest.cs | 2 -- .../LegacyGetCorrespondenceHistoryHandler.cs | 18 +++++----- .../LegacyGetCorrespondenceOverviewHandler.cs | 1 - ...LegacyUpdateCorrespondenceStatusHandler.cs | 10 +++++- 7 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/Altinn.Correspondence.API/Mappers/LegacyGetCorrespondencesMapper.cs b/src/Altinn.Correspondence.API/Mappers/LegacyGetCorrespondencesMapper.cs index b00aeeb8..382372b9 100644 --- a/src/Altinn.Correspondence.API/Mappers/LegacyGetCorrespondencesMapper.cs +++ b/src/Altinn.Correspondence.API/Mappers/LegacyGetCorrespondencesMapper.cs @@ -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, diff --git a/src/Altinn.Correspondence.API/Models/LegacyGetCorrespondencesRequestExt.cs b/src/Altinn.Correspondence.API/Models/LegacyGetCorrespondencesRequestExt.cs index 206f08d9..04ecb65d 100644 --- a/src/Altinn.Correspondence.API/Models/LegacyGetCorrespondencesRequestExt.cs +++ b/src/Altinn.Correspondence.API/Models/LegacyGetCorrespondencesRequestExt.cs @@ -20,12 +20,6 @@ public class LegacyGetCorrespondencesRequestExt [JsonPropertyName("limit")] public int Limit { get; set; } - /// - /// PartyId of the end user performing the search - /// - [JsonPropertyName("onbehalfOfPartyId")] - public required int OnbehalfOfPartyId { get; set; } - /// /// A list of the parties/recipients that own the Correspondence instances /// diff --git a/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs b/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs index 8802a10e..03d2a98a 100644 --- a/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs +++ b/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs @@ -38,16 +38,14 @@ public async Task> 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.NoAccessToResource; } - 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(); if (request.InstanceOwnerPartyIdList != null && request.InstanceOwnerPartyIdList.Length > 0) @@ -68,7 +66,8 @@ public async Task> 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 resourcesToSearch = new List(); @@ -76,8 +75,6 @@ public async Task> Process(Legacy // 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(); List correspondenceItems = new List(); @@ -112,6 +109,11 @@ public async Task> Process(Legacy } foreach (var correspondence in correspondences.Item1) { + var minAuthLevel = await _altinnAuthorizationService.CheckUserAccessAndGetMinimumAuthLevel(userParty.SSN, correspondence.ResourceId, new List { 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; @@ -124,7 +126,7 @@ public async Task> 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, @@ -135,7 +137,6 @@ public async Task> Process(Legacy } ); } - Console.WriteLine($"Finished correspondences: {correspondenceItems.Count}"); var response = new LegacyGetCorrespondencesResponse { Items = correspondenceItems, @@ -148,14 +149,4 @@ public async Task> Process(Legacy }; return response; } -} - -// TODO: Get All Resources these parties can access. I do think these resources is included in authorized parties response -// -// 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 \ No newline at end of file +} \ No newline at end of file diff --git a/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesRequest.cs b/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesRequest.cs index daba844b..bc9b241d 100644 --- a/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesRequest.cs +++ b/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesRequest.cs @@ -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; } diff --git a/src/Altinn.Correspondence.Application/GetCorrespondenceHistory/LegacyGetCorrespondenceHistoryHandler.cs b/src/Altinn.Correspondence.Application/GetCorrespondenceHistory/LegacyGetCorrespondenceHistoryHandler.cs index e86e2d7b..191f73fc 100644 --- a/src/Altinn.Correspondence.Application/GetCorrespondenceHistory/LegacyGetCorrespondenceHistoryHandler.cs +++ b/src/Altinn.Correspondence.Application/GetCorrespondenceHistory/LegacyGetCorrespondenceHistoryHandler.cs @@ -33,23 +33,21 @@ public async Task> 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.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.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()) @@ -61,7 +59,7 @@ public async Task> Process( User = new LegacyUser { PartyId = recipientParty.PartyId.ToString(), - AuthenticationLevel = authenticationLevel + AuthenticationLevel = (int)minimumAuthLevel }, }).ToList(); @@ -81,7 +79,7 @@ public async Task> Process( notificationDetails.NotificationsStatusDetails.Sms.Recipient, notification.IsReminder, senderParty.PartyId.ToString(), - authenticationLevel)); + (int)minimumAuthLevel)); } if (notificationDetails.NotificationsStatusDetails.Email is not null) { @@ -90,7 +88,7 @@ public async Task> Process( notificationDetails.NotificationsStatusDetails.Email.Recipient, notification.IsReminder, senderParty.PartyId.ToString(), - authenticationLevel)); + (int)minimumAuthLevel)); } } diff --git a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs index 22799602..78df81b2 100644 --- a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs +++ b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs @@ -51,7 +51,6 @@ public async Task> Process { return Errors.LegacyNoAccessToCorrespondence; } - var recipients = new List(); if (correspondence.Recipient != userParty.SSN && correspondence.Recipient != ("0192:" + userParty.OrgNumber)) { var authorizedParties = await _altinnAccessManagementService.GetAuthorizedParties(userParty, cancellationToken); diff --git a/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/LegacyUpdateCorrespondenceStatusHandler.cs b/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/LegacyUpdateCorrespondenceStatusHandler.cs index 6ff3314b..6baf80f0 100644 --- a/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/LegacyUpdateCorrespondenceStatusHandler.cs +++ b/src/Altinn.Correspondence.Application/UpdateCorrespondenceStatus/LegacyUpdateCorrespondenceStatusHandler.cs @@ -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; @@ -9,6 +10,7 @@ public class LegacyUpdateCorrespondenceStatusHandler : IHandler> 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.Read }, correspondence.Recipient, cancellationToken); + if (minimumAuthLevel == null) + { + return Errors.LegacyNoAccessToCorrespondence; + } var currentStatus = correspondence.GetLatestStatus(); if (currentStatus is null) { From 7022dbcaff7b9cbfd2b29286118e530b5fe25842 Mon Sep 17 00:00:00 2001 From: Hammerbeck Date: Fri, 8 Nov 2024 12:35:37 +0100 Subject: [PATCH 2/3] correct error message --- .../LegacyGetCorrespondenceOverviewHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs index 78df81b2..80ad980d 100644 --- a/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs +++ b/src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs @@ -34,7 +34,7 @@ public async Task> 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))) From 8a7aa4704e5e9fe907c29b86a2a30a75624a6e45 Mon Sep 17 00:00:00 2001 From: Hammerbeck Date: Fri, 8 Nov 2024 12:37:08 +0100 Subject: [PATCH 3/3] correct error message --- .../GetCorespondences/LegacyGetCorrespondencesHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs b/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs index 03d2a98a..4170abc6 100644 --- a/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs +++ b/src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs @@ -40,7 +40,7 @@ public async Task> Process(Legacy DateTimeOffset? from = request.From != null ? ((DateTimeOffset)request.From).ToUniversalTime() : null; 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)))