up
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user