/// <summary>
        /// Adds the user access token handler to an HttpClient
        /// </summary>
        /// <param name="httpClientBuilder"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static IHttpClientBuilder AddUserAccessTokenHandler(this IHttpClientBuilder httpClientBuilder,
                                                                   UserAccessTokenParameters parameters = null)
        {
            return(httpClientBuilder.AddHttpMessageHandler(provider =>
            {
                var contextAccessor = provider.GetRequiredService <IHttpContextAccessor>();

                return new UserAccessTokenHandler(contextAccessor, parameters);
            }));
        }
Beispiel #2
0
        /// <summary>
        /// Revokes the current user refresh token
        /// </summary>
        /// <param name="httpContext">The HTTP context</param>
        /// <param name="parameters">Extra optional parameters</param>
        /// <param name="cancellationToken">A cancellation token to cancel operation.</param>
        /// <returns></returns>
        public static async Task RevokeUserRefreshTokenAsync(
            this HttpContext httpContext,
            UserAccessTokenParameters parameters = null,
            CancellationToken cancellationToken = default)
        {
            var service = httpContext.RequestServices.GetRequiredService<IUserAccessTokenManagementService>();
            var store = httpContext.RequestServices.GetRequiredService<IUserTokenStore>();

            await service.RevokeRefreshTokenAsync(httpContext.User, parameters, cancellationToken);
            await store.ClearTokenAsync(httpContext.User);
        }
        /// <summary>
        /// Adds a named HTTP client for the factory that automatically sends the current user access token
        /// </summary>
        /// <param name="services"></param>
        /// <param name="name">The name of the client.</param>
        /// <param name="parameters"></param>
        /// <param name="configureClient">Additional configuration.</param>
        /// <returns></returns>
        public static IHttpClientBuilder AddUserAccessTokenHttpClient(this IServiceCollection services,
                                                                      string name,
                                                                      UserAccessTokenParameters parameters = null,
                                                                      Action <HttpClient> configureClient  = null)
        {
            if (configureClient != null)
            {
                return(services.AddHttpClient(name, configureClient)
                       .AddUserAccessTokenHandler(parameters));
            }

            return(services.AddHttpClient(name)
                   .AddUserAccessTokenHandler(parameters));
        }
Beispiel #4
0
        /// <summary>
        /// Endpoint logic
        /// </summary>
        /// <param name="localPath">The local path (e.g. /api)</param>
        /// <param name="apiAddress">The remote address (e.g. https://api.myapp.com/foo)</param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public static RequestDelegate Map(string localPath, string apiAddress)
        {
            return(async context =>
            {
                var loggerFactory = context.RequestServices.GetRequiredService <ILoggerFactory>();
                var logger = loggerFactory.CreateLogger(LogCategories.RemoteApiEndpoints);

                var endpoint = context.GetEndpoint();
                if (endpoint == null)
                {
                    throw new InvalidOperationException("endpoint not found");
                }

                var metadata = endpoint.Metadata.GetMetadata <BffRemoteApiEndpointMetadata>();
                if (metadata == null)
                {
                    throw new InvalidOperationException("API endoint is missing BFF metadata");
                }

                UserAccessTokenParameters toUserAccessTokenParameters = null;

                if (metadata.BffUserAccessTokenParameters != null)
                {
                    toUserAccessTokenParameters = metadata.BffUserAccessTokenParameters.ToUserAccessTokenParameters();
                }

                string token = null;
                if (metadata.RequiredTokenType.HasValue)
                {
                    token = await context.GetManagedAccessToken(metadata.RequiredTokenType.Value, toUserAccessTokenParameters);

                    if (string.IsNullOrWhiteSpace(token))
                    {
                        logger.AccessTokenMissing(localPath, metadata.RequiredTokenType.Value);

                        context.Response.StatusCode = 401;
                        return;
                    }
                }

                if (token == null)
                {
                    if (metadata.OptionalUserToken)
                    {
                        token = await context.GetUserAccessTokenAsync(toUserAccessTokenParameters);
                    }
                }

                var forwarder = context.RequestServices.GetRequiredService <IHttpForwarder>();
                var clientFactory = context.RequestServices.GetRequiredService <IHttpMessageInvokerFactory>();
                var transformerFactory = context.RequestServices.GetRequiredService <IHttpTransformerFactory>();

                var httpClient = clientFactory.CreateClient(localPath);
                var transformer = transformerFactory.CreateTransformer(localPath, token);

                await forwarder.SendAsync(context, apiAddress, httpClient, ForwarderRequestConfig.Empty, transformer);

                var errorFeature = context.Features.Get <IForwarderErrorFeature>();
                if (errorFeature != null)
                {
                    var error = errorFeature.Error;
                    var exception = errorFeature.Exception;

                    logger.ProxyResponseError(localPath, exception?.ToString() ?? error.ToString());
                }
            });
        }
Beispiel #5
0
        public static async Task <string> GetManagedAccessToken(this HttpContext context, TokenType tokenType, UserAccessTokenParameters userAccessTokenParameters = null)
        {
            string token;

            if (tokenType == TokenType.User)
            {
                token = await context.GetUserAccessTokenAsync(userAccessTokenParameters);
            }
            else if (tokenType == TokenType.Client)
            {
                token = await context.GetClientAccessTokenAsync();
            }
            else
            {
                token = await context.GetUserAccessTokenAsync(userAccessTokenParameters);

                if (string.IsNullOrEmpty(token))
                {
                    token = await context.GetClientAccessTokenAsync();
                }
            }

            return(token);
        }
Beispiel #6
0
        /// <summary>
        /// Returns (and refreshes if needed) the current access token for the logged on user
        /// </summary>
        /// <param name="httpContext">The HTTP context</param>
        /// <param name="parameters">Extra optional parameters</param>
        /// <param name="cancellationToken">A cancellation token to cancel operation.</param>
        /// <returns></returns>
        public static async Task<string> GetUserAccessTokenAsync(this HttpContext httpContext, UserAccessTokenParameters parameters = null, CancellationToken cancellationToken = default)
        {
            // todo convert null exception to TaskCanceledException for blazor.
            if (httpContext == null)
            {
                throw new TaskCanceledException();
            }

            try
            {
                var service = httpContext.RequestServices.GetRequiredService<IUserAccessTokenManagementService>();
                return await service.GetUserAccessTokenAsync(httpContext.User, parameters, cancellationToken);
            }
            catch (NullReferenceException)
            {
                throw new TaskCanceledException();
            }
        }
        /// <summary>
        /// Returns (and refreshes if needed) the current access token for the logged on user
        /// </summary>
        /// <param name="httpContext">The HTTP context</param>
        /// <param name="parameters">Extra optional parameters</param>
        /// <param name="cancellationToken">A cancellation token to cancel operation.</param>
        /// <returns></returns>
        public static async Task <string> GetUserAccessTokenAsync(this HttpContext httpContext, UserAccessTokenParameters parameters = null, CancellationToken cancellationToken = default)
        {
            var service = httpContext.RequestServices.GetRequiredService <IUserAccessTokenManagementService>();

            return(await service.GetUserAccessTokenAsync(httpContext.User, parameters, cancellationToken));
        }