Skip to content

Commit

Permalink
Fix for AzureOnBehalfOfAuthStrategy
Browse files Browse the repository at this point in the history
The on-behalf token was not cached per request in the strategy method, but was always set once with the token of the first requesting user when the strategy method was called for the very first time. This token was then the token for ANY user that was routed to the APIs (“on behalf of”) via the gateway until the next restart of the gateway. Each on-behalf token is now cached with the unique, incoming session ID of the requesting user and can therefore be retrieved correctly when needed again.
  • Loading branch information
miseeger committed Nov 15, 2024
1 parent 213bdf9 commit 41e2827
Showing 1 changed file with 19 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Fancy.ResourceLinker.Gateway.Authentication;
using System.Collections.Concurrent;
using Fancy.ResourceLinker.Gateway.Authentication;
using Fancy.ResourceLinker.Gateway.Common;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -93,9 +94,10 @@ internal class AzureOnBehalfOfAuthStrategy : IRouteAuthenticationStrategy
private DiscoveryDocument? _discoveryDocument;

/// <summary>
/// The current token response.
/// The currently in-use token responses per SessionId.
/// </summary>
private OnBehalfOfTokenResponse? _currentTokenResponse;
// private ConcurrentDictionary<string, OnBehalfOfTokenResponse?> _cachedTokenResponses;
private ConcurrentDictionary<string, OnBehalfOfTokenResponse?> _cachedTokenResponses = new ();

/// <summary>
/// Initializes a new instance of the <see cref="AzureOnBehalfOfAuthStrategy"/> class.
Expand Down Expand Up @@ -165,26 +167,31 @@ public async Task SetAuthenticationAsync(IServiceProvider serviceProvider, HttpR
string accessToken = await GetAccessTokenAsync(serviceProvider);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
}

/// <summary>
/// Gets the access token asynchronous.
/// </summary>
/// <returns>The access token.</returns>
private async Task<string> GetAccessTokenAsync(IServiceProvider serviceProvider)
{
if (_currentTokenResponse == null || IsExpired(_currentTokenResponse))
var tokenService = TryGetTokenService(serviceProvider);

if (tokenService == null)
{
TokenService? tokenService = TryGetTokenService(serviceProvider);
throw new InvalidOperationException("A token service in a scope is needed to use the azure on behalf of flow");
}

if (tokenService == null)
{
throw new InvalidOperationException("A token service in a scope is needed to use the azure on behalf of flow");
}
var tokenResponse = _cachedTokenResponses.ContainsKey(tokenService.CurrentSessionId!)
? _cachedTokenResponses[tokenService.CurrentSessionId!]
: null;

_currentTokenResponse = await GetOnBehalfOfTokenAsync(tokenService);
if (tokenResponse == null || IsExpired(tokenResponse))
{
tokenResponse = await GetOnBehalfOfTokenAsync(tokenService);
_cachedTokenResponses.TryAdd(tokenService.CurrentSessionId!, tokenResponse);
}

return _currentTokenResponse.AccessToken;
return tokenResponse.AccessToken;
}

/// <summary>
Expand Down

0 comments on commit 41e2827

Please sign in to comment.