Example #1
0
        private async Task <AuthenticationResult> Authenticate(HttpContext httpContext, Common.IanvsContext ianvsContext,
                                                               IIanvsConfigurationStore ianvsConfiguration, AuthenticatorFactory authenticatorFactory)
        {
            // If multiple schemes are defined on the operation, only one can apply to the request; check which one
            foreach (Ianvs::SecurityRequirement securityRequirement in ianvsContext.Security)
            {
                Ianvs::SecurityScheme schemeDefinition = ianvsConfiguration.SecuritySchemes?
                                                         .Find(s => s.Name == securityRequirement.SchemeName);
                if (schemeDefinition != null)
                {
                    ianvsContext.SecurityScheme = schemeDefinition;
                    IAuthenticationHandler authenticator = authenticatorFactory.GetAuthenticator(ianvsContext.SecurityScheme);
                    if (authenticator.CanAuthenticate(httpContext, ianvsContext))
                    {
                        ianvsContext.SecurityRequirement = securityRequirement;
                        return(await authenticator.Authenticate(httpContext, ianvsContext));
                    }
                    ianvsContext.SecurityScheme = null;
                }
            }

            // Couldn't apply security requirements
            return(new AuthenticationResult()
            {
                Authenticated = false,
                Error = "No Matching Security Scheme"
            });
        }
Example #2
0
        public async Task InvokeAsync(HttpContext context, IanvsContext ianvsContext,
                                      IIanvsConfigurationStore ianvsConfiguration, LoadBalancerFactory loadBalancerFactory)
        {
            // TODO: Implement Load Balancing
            // WIP - https://github.com/onyx-ws/ianvs/issues/5

            // Support for different load balancing modes - Random/Round Robin/etc.
            _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} finding load balancer");
            string loadBalancerMode = ianvsContext.MatchedOperation.LoadBalancerMethod;

            if (string.IsNullOrWhiteSpace(loadBalancerMode))
            {
                loadBalancerMode = ianvsContext.MatchedEndpoint.LoadBalancerMethod;
            }
            if (string.IsNullOrWhiteSpace(loadBalancerMode))
            {
                loadBalancerMode = ianvsConfiguration.LoadBalancerMethod;
            }

            ILoadBalancer loadBalancer = loadBalancerFactory.GetLoadBalancer(loadBalancerMode);

            _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} {loadBalancerMode} load balancer found");

            // Operation level servers take priority
            if (!(ianvsContext.MatchedOperation.Servers?.Count == 0))
            {
                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Selecting server out of {ianvsContext.MatchedOperation.Servers.Count} server(s)");
                ianvsContext.TargetServer = await loadBalancer.Next(ianvsContext.MatchedOperation.Servers);

                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Server {ianvsContext.TargetServer.Url} selected");
            }
            // If not operation level servers then use Endpoint level servers
            else if (!(ianvsContext.MatchedEndpoint.Servers?.Count == 0))
            {
                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Selecting server out of {ianvsContext.MatchedEndpoint.Servers.Count} server(s)");
                ianvsContext.TargetServer = await loadBalancer.Next(ianvsContext.MatchedEndpoint.Servers);

                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Server {ianvsContext.TargetServer.Url} selected");
            }
            // Else use global servers defined
            else
            {
                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Selecting server out of {ianvsConfiguration.Servers.Count} server(s)");
                ianvsContext.TargetServer = await loadBalancer.Next(ianvsConfiguration.Servers);

                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Server {ianvsContext.TargetServer.Url} selected");
            }

            ianvsContext.TargetUrl = ianvsContext.TargetServer.Url + (ianvsContext.MatchedEndpoint.Url == "/" ? "" : ianvsContext.MatchedEndpoint.Url);

            await _next(context);
        }
Example #3
0
        public async Task InvokeAsync(HttpContext httpContext, Ianvs::IanvsContext ianvsContext,
                                      IIanvsConfigurationStore ianvsConfiguration, AuthenticatorFactory authenticatorFactory)
        {
            // TODO: Implement Security
            // https://github.com/onyx-ws/ianvs/issues/8

            // Any security requirements?
            ianvsContext.Security = GetSecurityRequirements(ianvsContext);
            // Yes
            if (ianvsContext.Security?.Count > 0)
            {
                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Authenticating request");
                AuthenticationResult authResult = await Authenticate(httpContext, ianvsContext, ianvsConfiguration, authenticatorFactory);

                if (!authResult.Authenticated)
                {
                    _logger.LogWarning($"{Environment.MachineName} {ianvsContext.RequestId} Request authentication failed");
                    _logger.LogWarning($"{Environment.MachineName} {ianvsContext.RequestId} Authentication Error: {authResult.Error}");
                    SetUnAuthorizedResponse(ianvsContext);
                    return;
                }
                else
                {
                    _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Request authenticated successfully");
                    ianvsContext.Principal = authResult.Principal;

                    _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Authorizing request");
                    authResult = await Authorize(httpContext, ianvsContext);

                    if (!authResult.Authenticated)
                    {
                        _logger.LogWarning($"{Environment.MachineName} {ianvsContext.RequestId} Request authorization failed");
                        _logger.LogWarning($"{Environment.MachineName} {ianvsContext.RequestId} Authorization Error: {authResult.Error}");
                        SetForbiddenResponse(ianvsContext);
                        return;
                    }
                    else
                    {
                        _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Request authorized successfully");
                    }
                }
            }
            // request authenticated or no security requirement
            await _next(httpContext);
        }
Example #4
0
        public async Task InvokeAsync(HttpContext httpContext, Ianvs::IanvsContext ianvsContext,
                                      IIanvsConfigurationStore ianvsConfiguration, Tracer tracer)
        {
            // TODO: Implement Routing
            // WIP - https://github.com/onyx-ws/ianvs/issues/1
            // TODO: Handle endpoints with templates
            // https://github.com/onyx-ws/ianvs/issues/2

            var routingSpan = tracer.StartSpan("ianvs-routing");

            // Find a matching Path
            string requestPath = httpContext.Request.Path;

            _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Looking for a configured route");
            Ianvs::Endpoint matchedEndpoint = ianvsConfiguration.Endpoints.FirstOrDefault(
                endpoint =>
                requestPath == (!string.IsNullOrWhiteSpace(endpoint.IanvsUrl) ? endpoint.IanvsUrl : endpoint.Url)
                );

            if (matchedEndpoint is null)
            {
                // Path not found
                // Return 404 - Not Found (https://tools.ietf.org/html/rfc7231#section-6.5.4)
                routingSpan.AddEvent("Route not matched");
                _logger.LogWarning($"{Environment.MachineName} {ianvsContext.RequestId} No configured route found");
                ianvsContext.StatusCode = 404;
                ianvsContext.Response   = "";
            }
            else
            {
                ianvsContext.MatchedEndpoint = matchedEndpoint;
                _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Possible matching route found at {ianvsContext.MatchedEndpoint.Url}");

                // Path found - Match Operation
                string           requestMethod    = httpContext.Request.Method;
                Ianvs::Operation matchedOperation = matchedEndpoint.Operations.FirstOrDefault(
                    operation =>
                    operation.Method.Equals(requestMethod, StringComparison.InvariantCultureIgnoreCase)
                    );
                if (matchedOperation is null)
                {
                    // Operation not found
                    // Return 405 - Method Not Allowed (https://tools.ietf.org/html/rfc7231#section-6.5.5)
                    routingSpan.AddEvent("Method not matched");
                    _logger.LogWarning($"{Environment.MachineName} {ianvsContext.RequestId} No configured operation found");
                    ianvsContext.StatusCode = 405;
                    ianvsContext.Response   = "";
                }
                else
                {
                    // Operation found
                    // Simulate operation
                    routingSpan.AddEvent("Route found");

                    ianvsContext.MatchedOperation = matchedOperation;
                    _logger.LogInformation($"{Environment.MachineName} {ianvsContext.RequestId} Matched route at {ianvsContext.MatchedOperation.OperationId} {ianvsContext.MatchedOperation.Method} {ianvsContext.MatchedEndpoint.Url}");

                    await _next(httpContext);
                }
            }

            routingSpan.End();
        }