diff --git a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/ClientInterfaces/ISingleRightClient.cs b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/ClientInterfaces/ISingleRightClient.cs index 8b445a5d7..0b7da3e1a 100644 --- a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/ClientInterfaces/ISingleRightClient.cs +++ b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/ClientInterfaces/ISingleRightClient.cs @@ -18,8 +18,8 @@ public interface ISingleRightClient /// /// The delegation access check request object that's going to be consumed by the backend /// - /// List - Task> CheckDelegationAccess(string partyId, Right request); + /// HttpResponseMessage: The response from backend /> + Task CheckDelegationAccess(string partyId, Right request); /// /// Creates a single rights delegation diff --git a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/Interfaces/ISingleRightService.cs b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/Interfaces/ISingleRightService.cs index 91c517da6..786570cc4 100644 --- a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/Interfaces/ISingleRightService.cs +++ b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/Interfaces/ISingleRightService.cs @@ -17,7 +17,7 @@ public interface ISingleRightService /// /// The delegation access check request object that's going to be consumed by the backend /// List - Task> CheckDelegationAccess(string partyId, Right request); + Task CheckDelegationAccess(string partyId, Right request); /// /// Creates a single right delegation from a given party diff --git a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/SingleRightService.cs b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/SingleRightService.cs index 1fcaec7b2..ba66a85d0 100644 --- a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/SingleRightService.cs +++ b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Core/Services/SingleRightService.cs @@ -20,7 +20,7 @@ public SingleRightService(ISingleRightClient singleRightClient) } /// - public async Task> CheckDelegationAccess(string partyId, Right request) + public async Task CheckDelegationAccess(string partyId, Right request) { return await _singleRightClient.CheckDelegationAccess(partyId, request); } diff --git a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Integration/Clients/SingleRightClient.cs b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Integration/Clients/SingleRightClient.cs index e16e1ccf9..ebe33ab39 100644 --- a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Integration/Clients/SingleRightClient.cs +++ b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Integration/Clients/SingleRightClient.cs @@ -45,7 +45,7 @@ public SingleRightClient( } /// - public async Task> CheckDelegationAccess(string partyId, Right request) + public async Task CheckDelegationAccess(string partyId, Right request) { try { @@ -54,18 +54,7 @@ public async Task> CheckDelegationAccess(string par StringContent requestBody = new StringContent(JsonSerializer.Serialize(request, _serializerOptions), Encoding.UTF8, "application/json"); HttpResponseMessage response = await _client.PostAsync(token, endpointUrl, requestBody); - if (response.StatusCode == HttpStatusCode.OK) - { - string responseContent = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize>(responseContent, _serializerOptions); - } - else - { - string responseContent = await response.Content.ReadAsStringAsync(); - HttpStatusException error = JsonSerializer.Deserialize(responseContent, _serializerOptions); - - throw error; - } + return response; } catch (Exception ex) { diff --git a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/SingleRightClientMock.cs b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/SingleRightClientMock.cs index f41baca2b..6c61acc48 100644 --- a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/SingleRightClientMock.cs +++ b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Mocks/Mocks/SingleRightClientMock.cs @@ -19,14 +19,12 @@ public SingleRightClientMock() } /// - public Task> CheckDelegationAccess(string partyId, Right request) + public async Task CheckDelegationAccess(string partyId, Right request) { string resourceFileName = GetMockDataFilename(request.Resource); - string path = Path.Combine(localPath, "Data", "SingleRight", "DelegationAccessCheckResponse", resourceFileName+".json"); + string path = Path.Combine(localPath, "Data", "SingleRight", "DelegationAccessCheckResponse"); - List expectedResponse = Util.GetMockData>(path); - - return Task.FromResult(expectedResponse); + return await GetMockedHttpResponse(path, resourceFileName); } /// @@ -34,17 +32,8 @@ public async Task CreateDelegation(string party, Delegation { string resourceFileName = GetMockDataFilename(delegation.Rights.First().Resource); string dataPath = Path.Combine(localPath, "Data", "SingleRight", "CreateDelegation"); - - try - { - string data = Util.GetMockDataSerialized(dataPath, resourceFileName + ".json"); - return new HttpResponseMessage - { StatusCode = HttpStatusCode.OK, Content = new StringContent(data) }; - } - catch - { - return new HttpResponseMessage(HttpStatusCode.BadRequest); - } + + return await GetMockedHttpResponse(dataPath, resourceFileName); } private static string GetMockDataFilename(List resourceReference) @@ -64,5 +53,19 @@ private static string GetMockDataFilename(List resourceReference) return "Unknown"; } } + + private static async Task GetMockedHttpResponse(string path, string resourceFileName) + { + try + { + string data = Util.GetMockDataSerialized(path, resourceFileName + ".json"); + return new HttpResponseMessage + { StatusCode = HttpStatusCode.OK, Content = new StringContent(data) }; + } + catch + { + return new HttpResponseMessage(HttpStatusCode.BadRequest); + } + } } } diff --git a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI/Controllers/SingleRightController.cs b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI/Controllers/SingleRightController.cs index 33c5d3c6e..118ae6a53 100644 --- a/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI/Controllers/SingleRightController.cs +++ b/backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI/Controllers/SingleRightController.cs @@ -43,10 +43,28 @@ public async Task>> CheckDelegationAcc { try { - return await _singleRightService.CheckDelegationAccess(partyId, request); + HttpResponseMessage response = await _singleRightService.CheckDelegationAccess(partyId, request); + + if (response.StatusCode == HttpStatusCode.OK) + { + string responseContent = await response.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize>(responseContent, _serializerOptions); + } + + if (response.StatusCode == HttpStatusCode.BadRequest || response.StatusCode == HttpStatusCode.Unauthorized) + { + string responseContent = await response.Content.ReadAsStringAsync(); + return new ObjectResult(ProblemDetailsFactory.CreateProblemDetails(HttpContext, (int?)response.StatusCode, response.StatusCode == HttpStatusCode.BadRequest ? "Bad request" : "Unauthorized from backend", detail: responseContent)); + } + else + { + string responseContent = await response.Content.ReadAsStringAsync(); + return new ObjectResult(ProblemDetailsFactory.CreateProblemDetails(HttpContext, (int?)response.StatusCode, "Unexpected HttpStatus response", detail: responseContent)); + } } - catch (Exception) + catch (Exception ex) { + _logger.LogError(ex, "Unexpected exception occurred during delegation of resource:" + ex.Message); return new ObjectResult(ProblemDetailsFactory.CreateProblemDetails(HttpContext)); } } diff --git a/src/features/singleRight/components/ResourceActionBar/ResourceActionBar.tsx b/src/features/singleRight/components/ResourceActionBar/ResourceActionBar.tsx index e5b0ad000..2e6433236 100644 --- a/src/features/singleRight/components/ResourceActionBar/ResourceActionBar.tsx +++ b/src/features/singleRight/components/ResourceActionBar/ResourceActionBar.tsx @@ -51,7 +51,9 @@ export const ResourceActionBar = ({ useUpdate(() => { if ( - (status === ServiceStatus.NotDelegable || status === ServiceStatus.HTTPError) && + (status === ServiceStatus.NotDelegable || + status === ServiceStatus.HTTPError || + status === ServiceStatus.Unauthorized) && previousStatus !== undefined ) { setOpen(true); @@ -65,6 +67,7 @@ export const ResourceActionBar = ({ return 'success'; case ServiceStatus.NotDelegable: case ServiceStatus.HTTPError: + case ServiceStatus.Unauthorized: return 'danger'; default: return 'neutral'; @@ -135,6 +138,7 @@ export const ResourceActionBar = ({ case ServiceStatus.PartiallyDelegable: return undoButton; case ServiceStatus.NotDelegable: + case ServiceStatus.Unauthorized: return notDelegableLabel; default: return addButton; diff --git a/src/features/singleRight/components/SearchSection/SearchSection.tsx b/src/features/singleRight/components/SearchSection/SearchSection.tsx index 72c2aa2e0..9cedd5a00 100644 --- a/src/features/singleRight/components/SearchSection/SearchSection.tsx +++ b/src/features/singleRight/components/SearchSection/SearchSection.tsx @@ -173,6 +173,7 @@ export const SearchSection = ({ onAdd, onUndo }: SearchSectionParams) => { const errorCodeTextKeyList = currentServiceWithStatus?.status === ServiceStatus.NotDelegable || + currentServiceWithStatus?.status === ServiceStatus.Unauthorized || currentServiceWithStatus?.status === ServiceStatus.HTTPError ? currentServiceWithStatus.rightList?.flatMap( (result) => result.details?.map((detail) => detail.code) || [], @@ -220,9 +221,10 @@ export const SearchSection = ({ onAdd, onUndo }: SearchSectionParams) => { you: t('common.you_uppercase'), })} - {prioritizedErrorCodes[0] !== ServiceStatus.HTTPError && ( - {t('single_rights.ceo_or_main_admin_can_help')} - )} + {prioritizedErrorCodes[0] !== ServiceStatus.HTTPError && + prioritizedErrorCodes[0] !== ServiceStatus.Unauthorized && ( + {t('single_rights.ceo_or_main_admin_can_help')} + )} )} {resource.description} diff --git a/src/localizations/en.json b/src/localizations/en.json index fd313a16c..e3db56fcd 100644 --- a/src/localizations/en.json +++ b/src/localizations/en.json @@ -146,6 +146,8 @@ "new_error_title": "New error", "generic_error_try_again_title": "Whoops, we stumbled on a technical error", "generic_error_try_again": "Try adding the service again by clicking on the plus sign again. Contact Altinn Servicedesk if the problem persists.", + "unauthorized_for_party_title": "Manglar delegasjonstilgang", + "unauthorized_for_party": "Du kan ikkje delegere tenester for valde aktør. Om du meinte å delegere på vegner av nokon andre, vennlegst gå til profilen og vel denne aktøren frå avgjevarlista.", "give_more_rights": "Give more rights", "has_received_these_rights": "{{name}} has received these rights:", "rights_are_valid_until_deletion": "The rights are valid until they're deleted or withdrawn", diff --git a/src/localizations/no_nb.json b/src/localizations/no_nb.json index a83a731db..345a5399c 100644 --- a/src/localizations/no_nb.json +++ b/src/localizations/no_nb.json @@ -149,6 +149,8 @@ "new_error_title": "Ny feil", "generic_error_try_again_title": "Oj, det oppstod en teknisk feil", "generic_error_try_again": "Prøv å legge til tjenesten på nytt ved å klikke på pluss-tegnet igjen. Ta kontakt med Altinn Servicedesk hvis problemet fortsetter.", + "unauthorized_for_party_title": "Mangler delegeringstilgang", + "unauthorized_for_party": "Du kan ikke delegere tjenester for valgte aktør. Dersom du mente å delegere på vegne av noen andre, vennligst gå til profilen og velg denne aktøren fra avgiverlisten.", "missing_delegable_right": "Mangler rettighet", "missing_srr_right_access_title": "Mangler SRR-rettighet", "confirm_delegation_text": "Bekreft at du vil gi disse rettighetene til {{name}}.", diff --git a/src/localizations/no_nn.json b/src/localizations/no_nn.json index 803f0c655..9a4caa7e2 100644 --- a/src/localizations/no_nn.json +++ b/src/localizations/no_nn.json @@ -147,6 +147,8 @@ "new_error_title": "Ny feil", "generic_error_try_again_title": "Oj, det oppstod ein teknisk feil", "generic_error_try_again": "Prøv å legge til tenesta på nytt ved å klikke på pluss-teiknet igjen. Ta kontakt med Altinn Servicedesk om problemet held fram.", + "unauthorized_for_party_title": "Manglar delegasjonstilgang", + "unauthorized_for_party": "Du kan ikkje delegere tenester for valde aktør. Om du meinte å delegere på vegner av nokon andre, vennlegst gå til profilen og vel denne aktøren frå avgjevarlista.", "missing_delegable_right": "Manglar rett", "missing_srr_right_access_title": "Manglar SRR-rettegheit", "complete_delegation": "Fullfør delegering", diff --git a/src/resources/utils/errorCodeUtils.ts b/src/resources/utils/errorCodeUtils.ts index d5cb84cd8..9357c1af5 100644 --- a/src/resources/utils/errorCodeUtils.ts +++ b/src/resources/utils/errorCodeUtils.ts @@ -3,6 +3,7 @@ export enum ErrorCode { MissingDelegationAccess = 'MissingDelegationAccess', MissingSrrRightAccess = 'MissingSrrRightAccess', HTTPError = 'HTTPError', + Unauthorized = 'Unauthorized', InsufficientAuthenticationLevel = 'InsufficientAuthenticationLevel', Unknown = 'Unknown', } @@ -19,6 +20,8 @@ export const getErrorCodeTextKey = (errorCode: string | undefined): string | und return 'single_rights.unknown'; case ErrorCode.HTTPError: return 'single_rights.generic_error_try_again'; + case ErrorCode.Unauthorized: + return 'single_rights.unauthorized_for_party'; case ErrorCode.InsufficientAuthenticationLevel: return 'api_delegation.insufficient_authentication_level'; case undefined: @@ -30,6 +33,7 @@ export const getErrorCodeTextKey = (errorCode: string | undefined): string | und export const prioritizeErrors = (errors: string[]): string[] => { const priorityOrder: string[] = [ + ErrorCode.Unauthorized, ErrorCode.HTTPError, ErrorCode.MissingRoleAccess, ErrorCode.MissingDelegationAccess, diff --git a/src/rtk/features/singleRights/singleRightsSlice.ts b/src/rtk/features/singleRights/singleRightsSlice.ts index 8f96ddd22..7c6ec9bf8 100644 --- a/src/rtk/features/singleRights/singleRightsSlice.ts +++ b/src/rtk/features/singleRights/singleRightsSlice.ts @@ -26,6 +26,7 @@ export enum ServiceStatus { PartiallyDelegable = 'PartiallyDelegable', Unchecked = 'Unchecked', HTTPError = 'HTTPError', + Unauthorized = `Unauthorized`, } export interface DelegationAccessCheckDto { @@ -265,17 +266,21 @@ const singleRightSlice = createSlice({ .addCase(delegationAccessCheck.rejected, (state, action) => { const serviceID = action.meta.arg.serviceResource.identifier; + const errorCode = + action.payload.response.status === 401 + ? ServiceStatus.Unauthorized + : ServiceStatus.HTTPError; const nextStateArray = state.servicesWithStatus.map((sws: ServiceWithStatus) => { if (sws.service?.identifier === serviceID) { const delegationResponseList: Right[] = [ { - resource: [{ id: serviceID }], + resource: action.meta.arg.resourceReference, action: '', - status: ServiceStatus.HTTPError, + status: errorCode, details: [ { - code: ServiceStatus.HTTPError, + code: errorCode, }, ], }, @@ -284,7 +289,7 @@ const singleRightSlice = createSlice({ sws.service.identifier = serviceID; sws.rightList = delegationResponseList; sws.isLoading = false; - sws.status = ServiceStatus.HTTPError; + sws.status = errorCode; } return sws; });