/// <inheritdoc/> public Task DeleteClientAccessTokenAsync( string clientName = AccessTokenManagementDefaults.DefaultTokenClientName, ClientAccessTokenParameters parameters = null, CancellationToken cancellationToken = default) { return(_clientAccessTokenCache.DeleteAsync(clientName, parameters, cancellationToken)); }
/// <inheritdoc/> public async Task <TokenResponse> RequestClientAccessToken( string clientName = AccessTokenManagementDefaults.DefaultTokenClientName, ClientAccessTokenParameters parameters = null, CancellationToken cancellationToken = default) { _logger.LogDebug("Requesting client access token for client: {client}", clientName); parameters ??= new ClientAccessTokenParameters(); var requestDetails = await _configService.GetClientCredentialsRequestAsync(clientName, parameters); #if NET5_0 requestDetails.Options.TryAdd(AccessTokenManagementDefaults.AccessTokenParametersOptionsName, parameters); #elif NETCOREAPP3_1 requestDetails.Properties[AccessTokenManagementDefaults.AccessTokenParametersOptionsName] = parameters; #endif if (!string.IsNullOrWhiteSpace(parameters.Resource)) { requestDetails.Resource.Add(parameters.Resource); } var httpClient = _httpClientFactory.CreateClient(AccessTokenManagementDefaults.BackChannelHttpClientName); return(await httpClient.RequestClientCredentialsTokenAsync(requestDetails, cancellationToken)); }
/// <inheritdoc/> public async Task <ClientAccessToken> GetAsync(string clientName, ClientAccessTokenParameters parameters, CancellationToken cancellationToken = default) { if (clientName is null) { throw new ArgumentNullException(nameof(clientName)); } var cacheKey = GenerateCacheKey(_options, clientName, parameters); var entry = await _cache.GetStringAsync(cacheKey, token : cancellationToken); if (entry != null) { try { _logger.LogDebug("Cache hit for access token for client: {clientName}", clientName); var values = entry.Split(new[] { "___" }, StringSplitOptions.RemoveEmptyEntries); return(new ClientAccessToken { AccessToken = values[0], Expiration = DateTimeOffset.FromUnixTimeSeconds(long.Parse(values[1])) }); } catch (Exception ex) { _logger.LogCritical(ex, "Error parsing cached access token for client {clientName}", clientName); return(null); } } _logger.LogDebug("Cache miss for access token for client: {clientName}", clientName); return(null); }
/// <inheritdoc/> public Task DeleteAsync(string clientName, ClientAccessTokenParameters parameters, CancellationToken cancellationToken = default) { if (clientName is null) { throw new ArgumentNullException(nameof(clientName)); } var cacheKey = GenerateCacheKey(_options, clientName, parameters); return(_cache.RemoveAsync(cacheKey, cancellationToken)); }
/// <summary> /// Set an access token on the HTTP request /// </summary> /// <param name="request"></param> /// <param name="forceRenewal"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected virtual async Task SetTokenAsync(HttpRequestMessage request, bool forceRenewal, CancellationToken cancellationToken) { var parameters = new ClientAccessTokenParameters { ForceRenewal = forceRenewal }; var token = await _accessTokenManagementService.GetClientAccessTokenAsync(_tokenClientName, parameters, cancellationToken); if (!string.IsNullOrWhiteSpace(token)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); } }
/// <inheritdoc/> public async Task <string> GetClientAccessTokenAsync( string clientName = AccessTokenManagementDefaults.DefaultTokenClientName, ClientAccessTokenParameters parameters = null, CancellationToken cancellationToken = default) { parameters ??= new ClientAccessTokenParameters(); if (parameters.ForceRenewal == false) { var item = await _clientAccessTokenCache.GetAsync(clientName, parameters, cancellationToken); if (item != null) { return(item.AccessToken); } } try { return(await _sync.Dictionary.GetOrAdd(clientName, _ => { return new Lazy <Task <string> >(async() => { var response = await _tokenEndpointService.RequestClientAccessToken(clientName, parameters, cancellationToken); if (response.IsError) { _logger.LogError("Error requesting access token for client {clientName}. Error = {error}", clientName, response.Error); return null; } await _clientAccessTokenCache.SetAsync(clientName, response.AccessToken, response.ExpiresIn, parameters, cancellationToken); return response.AccessToken; }); }).Value); } finally { _sync.Dictionary.TryRemove(clientName, out _); } }
/// <inheritdoc /> public virtual async Task <ClientCredentialsTokenRequest> GetClientCredentialsRequestAsync(string clientName, ClientAccessTokenParameters parameters) { ClientCredentialsTokenRequest requestDetails; // if a named client configuration was passed in, try to load it if (string.Equals(clientName, AccessTokenManagementDefaults.DefaultTokenClientName)) { // if only one client configuration exists, load that if (_clientAccessTokenManagementOptions.Clients.Count == 1) { _logger.LogDebug("Reading token client configuration from single configuration entry."); requestDetails = _clientAccessTokenManagementOptions.Clients.First().Value; } // otherwise fall back to the scheme configuration else { _logger.LogDebug("Constructing token client configuration from OpenID Connect handler."); var(options, configuration) = await GetOpenIdConnectSettingsAsync(_userAccessTokenManagementOptions.SchemeName); requestDetails = new ClientCredentialsTokenRequest { Address = configuration.TokenEndpoint, ClientId = options.ClientId, ClientSecret = options.ClientSecret }; if (!string.IsNullOrWhiteSpace(_clientAccessTokenManagementOptions.DefaultClient.Scope)) { requestDetails.Scope = _clientAccessTokenManagementOptions.DefaultClient.Scope; } if (!string.IsNullOrWhiteSpace(_clientAccessTokenManagementOptions.DefaultClient.Resource)) { requestDetails.Resource.Add(_clientAccessTokenManagementOptions.DefaultClient.Resource); } var assertion = await CreateAssertionAsync(clientName); if (assertion != null) { requestDetails.ClientAssertion = assertion; } } } else { if (!_clientAccessTokenManagementOptions.Clients.TryGetValue(clientName, out requestDetails)) { throw new InvalidOperationException($"No access token client configuration found for client: {clientName}"); } } _logger.LogDebug("Returning token client configuration for client: {client}", clientName); return(requestDetails); }
/// <inheritdoc/> public async Task SetAsync(string clientName, string accessToken, int expiresIn, ClientAccessTokenParameters parameters, CancellationToken cancellationToken = default) { if (clientName is null) { throw new ArgumentNullException(nameof(clientName)); } var expiration = DateTimeOffset.UtcNow.AddSeconds(expiresIn); var expirationEpoch = expiration.ToUnixTimeSeconds(); var cacheExpiration = expiration.AddSeconds(-_options.CacheLifetimeBuffer); var data = $"{accessToken}___{expirationEpoch.ToString()}"; var entryOptions = new DistributedCacheEntryOptions { AbsoluteExpiration = cacheExpiration }; _logger.LogDebug("Caching access token for client: {clientName}. Expiration: {expiration}", clientName, cacheExpiration); var cacheKey = GenerateCacheKey(_options, clientName, parameters); await _cache.SetStringAsync(cacheKey, data, entryOptions, token : cancellationToken); }
/// <summary> /// Generates the cache key based on various inputs /// </summary> /// <param name="options"></param> /// <param name="clientName"></param> /// <param name="parameters"></param> /// <returns></returns> protected virtual string GenerateCacheKey(ClientAccessTokenManagementOptions options, string clientName, ClientAccessTokenParameters parameters) { return(options.CacheKeyPrefix + "::" + clientName + "::" + parameters?.Resource ?? ""); }