/// <inheritdoc/>
 public Task DeleteClientAccessTokenAsync(
     string clientName = AccessTokenManagementDefaults.DefaultTokenClientName,
     ClientAccessTokenParameters parameters = null,
     CancellationToken cancellationToken    = default)
 {
     return(_clientAccessTokenCache.DeleteAsync(clientName, parameters, cancellationToken));
 }
示例#2
0
        /// <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));
        }
示例#3
0
        /// <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);
        }
示例#4
0
        /// <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 _);
            }
        }
示例#7
0
        /// <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);
        }
示例#8
0
        /// <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);
        }
示例#9
0
 /// <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 ?? "");
 }