Skip to content

Commit

Permalink
Fixed errorhandling and caching of token
Browse files Browse the repository at this point in the history
  • Loading branch information
lailafritsvoldrognhaug committed Jul 3, 2024
1 parent 7c0c12a commit 5da9a97
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 204 deletions.
123 changes: 44 additions & 79 deletions src/Helsenorge.Registries/AddressRegistryRest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,12 @@
using Helsenorge.Registries.Utilities;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography.X509Certificates;
using Helsenorge.Registries.AddressService;
using CertificateDetails = Helsenorge.Registries.Abstractions.CertificateDetails;
using System.Collections.Generic;
using System.Linq;
using Code = Helsenorge.Registries.Abstractions.Code;
using Helsenorge.Registries.Configuration;
using System.Net.Http;
using Helsenorge.Registries.HelseId;
using System.Text.Json;
using System.Collections;

namespace Helsenorge.Registries
{
Expand All @@ -46,27 +41,29 @@ public class AddressRegistryRest : IAddressRegistry
/// <param name="settings">Options for this instance</param>
/// <param name="cache">Cache implementation to use</param>
/// <param name="logger">The ILogger object used to log diagnostics.</param>
/// <param name="helseIdClient">The HelseIdClient object used to retrive authentication token.</param>


public AddressRegistryRest(
AddressRegistryRestSettings settings,
IDistributedCache cache,
ILogger logger,
IHelseIdClient helseIdClient)
{
if (settings == null) throw new ArgumentNullException(nameof(settings));
if (cache == null) throw new ArgumentNullException(nameof(cache));
if (logger == null) throw new ArgumentNullException(nameof(logger));
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_helseIdClient = helseIdClient ?? throw new ArgumentNullException(nameof(helseIdClient));

_settings = settings;
_cache = cache;
_logger = logger;

var httpClientFactory = new ProxyHttpClientFactory(settings.RestConfiguration);
_restServiceInvoker = new RestServiceInvoker(_logger, httpClientFactory);
}


/// <summary>
/// Returns communication details for a specific counterparty
/// </summary>
/// <param name="herId">HER-Id of counter party</param>
/// <returns>Communication details if found, otherwise null</returns>
public async Task<CommunicationPartyDetails> FindCommunicationPartyDetailsAsync(int herId)
{
return await FindCommunicationPartyDetailsAsync(herId, false).ConfigureAwait(false);
Expand All @@ -76,6 +73,7 @@ public async Task<CommunicationPartyDetails> FindCommunicationPartyDetailsAsync(
/// Returns communication details for a specific counterparty
/// </summary>
/// <param name="herId">HER-Id of counter party</param>
/// /// <param name="forceUpdate">Set to true to force cache update.</param>
/// <returns>Communication details if found, otherwise null</returns>
public async Task<CommunicationPartyDetails> FindCommunicationPartyDetailsAsync(int herId, bool forceUpdate)
{
Expand All @@ -86,11 +84,16 @@ public async Task<CommunicationPartyDetails> FindCommunicationPartyDetailsAsync(
_cache,
key).ConfigureAwait(false);

if (communicationPartyDetails == null) { }
if (communicationPartyDetails == null)
{
try
{
communicationPartyDetails = await FindCommunicationPartyDetails(herId).ConfigureAwait(false);
var details = await FindCommunicationPartyDetails(herId).ConfigureAwait(false);

if (!string.IsNullOrEmpty(details))
{
communicationPartyDetails = MapCommunicationPartyDetails(details);
}
}
catch (FaultException<GenericFault> ex)
{
Expand All @@ -105,6 +108,7 @@ public async Task<CommunicationPartyDetails> FindCommunicationPartyDetailsAsync(
Data = { { "HerId", herId } }
};
}
await CacheExtensions.WriteValueToCacheAsync(_logger, _cache, key, communicationPartyDetails, _settings.CachingInterval).ConfigureAwait(false);
}
return communicationPartyDetails;
}
Expand All @@ -113,16 +117,15 @@ public async Task<CommunicationPartyDetails> FindCommunicationPartyDetailsAsync(
/// Makes the actual call to the registry. This is virtual so that it can be mocked by unit tests
/// </summary>
/// <param name="herId">Her id of communication party</param>
/// <returns></returns>
/// <returns>Communication party details as json</returns>
[ExcludeFromCodeCoverage] // requires wire communication
protected virtual async Task<CommunicationPartyDetails> FindCommunicationPartyDetails(int herId)
internal virtual async Task<string> FindCommunicationPartyDetails(int herId)
{
var request = await CreateRequestMessageAsync(HttpMethod.Get, $"/CommunicationParties/{herId}");
var communicationPartyDetails = await _restServiceInvoker.ExecuteAsync(request, nameof(FindCommunicationPartyDetails));
return MapCommunicationPartyDetails(communicationPartyDetails);
return await _restServiceInvoker.ExecuteAsync(request, nameof(FindCommunicationPartyDetails));
}

public static CommunicationPartyDetails MapCommunicationPartyDetails(string details)
private static CommunicationPartyDetails MapCommunicationPartyDetails(string details)
{
var communicationPartyDetails = new CommunicationPartyDetails();

Expand Down Expand Up @@ -165,109 +168,71 @@ private static string GetQueueName(JsonElement element, string value)
{
if (item.GetProperty("TypeCodeValue").GetString() == value)
{
return item.GetProperty("Address").GetString().Split('/').Last();
return item.GetProperty("Address").GetString();
}
}
return string.Empty;
}

/// <summary>
/// Returns encryption certificate for a specific communication party.
/// </summary>
/// <param name="herId">Her-ID of the communication party</param>
/// <returns></returns>
private async Task<RequestParameters> CreateRequestMessageAsync(HttpMethod method, string path)
{
var request = new RequestParameters()
{
Method = method,
Path = path,
BearerToken = await _helseIdClient.CreateJwtAccessTokenAsync(),
AcceptHeader = "application/json"
};
return request;
}

/// <inheritdoc cref="IAddressRegistry.GetCertificateDetailsForEncryptionAsync(int)"/>
[Obsolete("This method is no longer supported.")]
public async Task<CertificateDetails> GetCertificateDetailsForEncryptionAsync(int herId)
{
throw new NotImplementedException();
return await GetCertificateDetailsForEncryptionAsync(herId, false);
}

/// <summary>
/// Returns encryption certificate for a specific communication party.
/// </summary>
/// <param name="herId">Her-ID of the communication party</param>
/// <param name="forceUpdate">Set to true to force cache update.</param>
/// <returns></returns>
/// <inheritdoc cref="IAddressRegistry.GetCertificateDetailsForEncryptionAsync(int, bool)"/>
[Obsolete("This method is no longer supported.")]
public async Task<CertificateDetails> GetCertificateDetailsForEncryptionAsync(int herId, bool forceUpdate)

Check warning on line 198 in src/Helsenorge.Registries/AddressRegistryRest.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 198 in src/Helsenorge.Registries/AddressRegistryRest.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}

/// <summary>
/// Returns the signature certificate for a specific communication party.
/// </summary>
/// <param name="herId">Her-ID of the communication party</param>
/// <returns></returns>
/// <inheritdoc cref="IAddressRegistry.GetCertificateDetailsForValidatingSignatureAsync(int)"/>
[Obsolete("This method is no longer supported.")]
public async Task<CertificateDetails> GetCertificateDetailsForValidatingSignatureAsync(int herId)

Check warning on line 205 in src/Helsenorge.Registries/AddressRegistryRest.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}

/// <summary>
/// Returns the signature certificate for a specific communication party.
/// </summary>
/// <param name="herId">Her-ID of the communication party</param>
/// <param name="forceUpdate">Set to true to force cache update.</param>
/// <returns></returns>
/// <inheritdoc cref="IAddressRegistry.GetCertificateDetailsForValidatingSignatureAsync(int, bool)"/>
[Obsolete("This method is no longer supported.")]
public async Task<CertificateDetails> GetCertificateDetailsForValidatingSignatureAsync(int herId, bool forceUpdate)

Check warning on line 212 in src/Helsenorge.Registries/AddressRegistryRest.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
await Task.Delay(1000);
throw new NotImplementedException();
}

/// <inheritdoc/>
/// <inheritdoc cref="IAddressRegistry.SearchByIdAsync"/>/>
[Obsolete("This method is no longer supported.")]
public async Task<IEnumerable<CommunicationPartyDetails>> SearchByIdAsync(string id, bool forceUpdate = false)

Check warning on line 219 in src/Helsenorge.Registries/AddressRegistryRest.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
await Task.Delay(1000);
throw new NotImplementedException();
}

/// <inheritdoc cref="IAddressRegistry.GetOrganizationDetailsAsync"/>
[Obsolete("This method is no longer supported.")]
public async Task<OrganizationDetails> GetOrganizationDetailsAsync(int herId, bool forceUpdate = false)

Check warning on line 226 in src/Helsenorge.Registries/AddressRegistryRest.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
await Task.Delay(1000);
throw new NotImplementedException();
}

/// <inheritdoc cref="PingAsync"/>
[Obsolete("This method will be replaced in the future.")]
/// <inheritdoc cref="IAddressRegistry.PingAsync"/>
[Obsolete("This method is no longer supported.")]
public async Task PingAsync()

Check warning on line 233 in src/Helsenorge.Registries/AddressRegistryRest.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
await Task.Delay(1000);
throw new NotImplementedException();
}

/// <inheritdoc cref="PingAsync"/>
[Obsolete("This method will be replaced in the future.")]
public async Task PingAsync(int herId)
{
await PingAsyncInternal(herId).ConfigureAwait(false);
}

/// <inheritdoc cref="PingAsync"/>
[ExcludeFromCodeCoverage]
protected virtual async Task PingAsyncInternal(int herId)
{
var request = await CreateRequestMessageAsync(HttpMethod.Get, $"/CommunicationParties/{herId}");
await _restServiceInvoker.ExecuteAsync(request, nameof(PingAsync));
}


private async Task<RequestParameters> CreateRequestMessageAsync(HttpMethod method, string path)
{
var request = new RequestParameters()
{
Method = method,
Path = path,
BearerToken = await _helseIdClient.CreateJwtAccessTokenAsync(),
AcceptHeader = "application/json"
};
return request;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using System.Net.Http;
using System.Threading.Tasks;
using Helsenorge.Registries.Configuration;
using Helsenorge.Registries.HelseId;
using IdentityModel;
using IdentityModel.Client;
using Microsoft.IdentityModel.Tokens;
Expand All @@ -35,7 +34,7 @@ public HelseIdClient(HelseIdConfiguration configuration, ISecurityKeyProvider se
/// <returns>Jwt access token</returns>
public async Task<string> CreateJwtAccessTokenAsync()
{
string tokenKey = "HelseIdJwtAccessToken"; // Could be more specific if needed
string tokenKey = $"HelseIdJwtAccessToken_{_configuration.ScopeName}";

if (TokenCache.TryGetToken(tokenKey, out var cachedToken))
{
Expand Down
5 changes: 5 additions & 0 deletions src/Helsenorge.Registries/Utilities/RestServiceInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ internal async Task<string> ExecuteAsync(RequestParameters request, string opera
stopwatch.Start();

var response = await httpClient.SendAsync(httpRequest);
if (response.IsSuccessStatusCode == false)
{
throw new HttpRequestException(
"Error calling {operationName} on {absoluteUri}. Status code: {response.StatusCode}");
}
var result = await response.Content.ReadAsStringAsync();

stopwatch.Stop();
Expand Down
Loading

0 comments on commit 5da9a97

Please sign in to comment.