Files
git.stella-ops.org/src/StellaOps.Feedser.Source.Vndr.Cisco/Internal/CiscoOAuthMessageHandler.cs
Vladimir Moushkov ea1106ce7c up
2025-10-15 10:03:56 +03:00

102 lines
3.6 KiB
C#

using System.IO;
using System.Net;
using System.Net.Http.Headers;
using Microsoft.Extensions.Logging;
namespace StellaOps.Feedser.Source.Vndr.Cisco.Internal;
internal sealed class CiscoOAuthMessageHandler : DelegatingHandler
{
private readonly CiscoAccessTokenProvider _tokenProvider;
private readonly ILogger<CiscoOAuthMessageHandler> _logger;
public CiscoOAuthMessageHandler(
CiscoAccessTokenProvider tokenProvider,
ILogger<CiscoOAuthMessageHandler> logger)
{
_tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
HttpRequestMessage? retryTemplate = null;
try
{
retryTemplate = await CloneRequestAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (IOException)
{
// Unable to buffer content; retry will fail if needed.
retryTemplate = null;
}
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await _tokenProvider.GetTokenAsync(cancellationToken).ConfigureAwait(false));
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
if (response.StatusCode != HttpStatusCode.Unauthorized)
{
return response;
}
response.Dispose();
_logger.LogWarning("Cisco openVuln request returned 401 Unauthorized; refreshing access token.");
await _tokenProvider.RefreshAsync(cancellationToken).ConfigureAwait(false);
if (retryTemplate is null)
{
_tokenProvider.Invalidate();
throw new HttpRequestException("Cisco openVuln request returned 401 Unauthorized and could not be retried.");
}
retryTemplate.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await _tokenProvider.GetTokenAsync(cancellationToken).ConfigureAwait(false));
try
{
var retryResponse = await base.SendAsync(retryTemplate, cancellationToken).ConfigureAwait(false);
if (retryResponse.StatusCode == HttpStatusCode.Unauthorized)
{
_tokenProvider.Invalidate();
}
return retryResponse;
}
finally
{
retryTemplate.Dispose();
}
}
private static async Task<HttpRequestMessage?> CloneRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var clone = new HttpRequestMessage(request.Method, request.RequestUri)
{
Version = request.Version,
VersionPolicy = request.VersionPolicy,
};
foreach (var header in request.Headers)
{
clone.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
if (request.Content is not null)
{
using var memory = new MemoryStream();
await request.Content.CopyToAsync(memory, cancellationToken).ConfigureAwait(false);
memory.Position = 0;
var buffer = memory.ToArray();
var contentClone = new ByteArrayContent(buffer);
foreach (var header in request.Content.Headers)
{
contentClone.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
clone.Content = contentClone;
}
return clone;
}
}