/// <summary>
        /// Sign out the specified authentication scheme.
        /// </summary>
        /// <param name="context">The <see cref="ProtoContext"/>.</param>
        /// <param name="scheme">The name of the authentication scheme.</param>
        /// <param name="properties">The <see cref="AuthenticationProperties"/>.</param>
        /// <returns>A task.</returns>
        public virtual async Task SignOutAsync(ProtoContext context, string scheme, AuthenticationProperties properties)
        {
            if (scheme == null)
            {
                var defaultScheme = await Schemes.GetDefaultSignOutSchemeAsync();

                scheme = defaultScheme?.Name;
                if (scheme == null)
                {
                    throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultSignOutScheme found.");
                }
            }

            var handler = await Handlers.GetHandlerAsync(context, scheme);

            if (handler == null)
            {
                throw await CreateMissingSignOutHandlerException(scheme);
            }

            if (!(handler is IAuthenticationSignOutHandler signOutHandler))
            {
                throw await CreateMismatchedSignOutHandlerException(scheme, handler);
            }

            await signOutHandler.SignOutAsync(properties);
        }
        /// <inheritdoc />
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (values.TryGetValue(routeKey, out var obj) && obj != null)
            {
                var value = Convert.ToString(obj, CultureInfo.InvariantCulture);
                return(!FileNameRouteConstraint.IsFileName(value));
            }

            // No value or null value.
            //
            // We want to return true here because the core use-case of the constraint is to *exclude*
            // things that look like file names. There's nothing here that looks like a file name, so
            // let it through.
            return(true);
        }
        /// <inheritdoc />
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            foreach (var constraint in Constraints)
            {
                if (!constraint.Match(httpContext, route, routeKey, values, routeDirection))
                {
                    return(false);
                }
            }

            return(true);
        }
Example #4
0
        public async Task Invoke(ProtoContext httpContext)
        {
            var feature = new EndpointSelectorContext();

            // There's an inherent race condition between waiting for init and accessing the matcher
            // this is OK because once `_matcher` is initialized, it will not be set to null again.
            var matcher = await InitializeAsync();

            await matcher.MatchAsync(httpContext, feature);

            if (feature.Endpoint != null)
            {
                // Set the endpoint feature only on success. This means we won't overwrite any
                // existing state for related features unless we did something.
                SetFeatures(httpContext, feature);

                Log.MatchSuccess(_logger, feature);
            }
            else
            {
                Log.MatchFailure(_logger);
            }

            await _next(httpContext);
        }
Example #5
0
        /// <summary>
        /// Extension method for setting the <see cref="Endpoint"/> for the current request.
        /// </summary>
        /// <param name="context">The <see cref="ProtoContext"/> context.</param>
        /// <param name="endpoint">The <see cref="Endpoint"/>.</param>
        public static void SetEndpoint(this ProtoContext context, Endpoint endpoint)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var feature = context.Features.Get <IEndpointFeature>();

            if (endpoint != null)
            {
                if (feature == null)
                {
                    feature = new EndpointFeature();
                    context.Features.Set(feature);
                }

                feature.Endpoint = endpoint;
            }
            else
            {
                if (feature == null)
                {
                    // No endpoint to set and no feature on context. Do nothing
                    return;
                }

                feature.Endpoint = null;
            }
        }
Example #6
0
        /// <summary>
        /// This examines the request to see if it matches a configured directory, and if there are any files with the
        /// configured default names in that directory.  If so this will append the corresponding file name to the request
        /// path for a later middleware to handle.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public Task Invoke(ProtoContext context)
        {
            if (context.GetEndpoint() == null &&
                Helpers.IsGetOrHeadMethod(context.Request.Method) &&
                Helpers.TryMatchPath(context, _matchUrl, forDirectory: true, subpath: out var subpath))
            {
                var dirContents = _fileProvider.GetDirectoryContents(subpath.Value);
                if (dirContents.Exists)
                {
                    // Check if any of our default files exist.
                    for (var matchIndex = 0; matchIndex < _options.DefaultFileNames.Count; matchIndex++)
                    {
                        var defaultFile = _options.DefaultFileNames[matchIndex];
                        var file        = _fileProvider.GetFileInfo(subpath.Value + defaultFile);
                        // TryMatchPath will make sure subpath always ends with a "/" by adding it if needed.
                        if (file.Exists)
                        {
                            // If the path matches a directory but does not end in a slash, redirect to add the slash.
                            // This prevents relative links from breaking.
                            if (!Helpers.PathEndsInSlash(context.Request.Path))
                            {
                                context.Response.StatusCode = 301;
                                context.Response.Headers[HeaderNames.Location] = context.Request.PathBase + context.Request.Path + "/" + context.Request.QueryString;
                                return(Task.CompletedTask);
                            }

                            // Match found, re-write the url. A later middleware will actually serve the file.
                            context.Request.Path = new PathString(context.Request.Path.Value + defaultFile);
                            break;
                        }
                    }
                }
            }
            return(_next(context));
        }
Example #7
0
 private static Task Success(ProtoContext context)
 {
     context.Response.StatusCode    = 200;
     context.Items["test.PathBase"] = context.Request.PathBase.Value;
     context.Items["test.Path"]     = context.Request.Path.Value;
     return(Task.FromResult <object>(null));
 }
        /// <summary>
        /// Generates a URI with an absolute path based on the provided values.
        /// </summary>
        /// <param name="generator">The <see cref="LinkGenerator"/>.</param>
        /// <param name="httpContext">The <see cref="ProtoContext"/> associated with the current request.</param>
        /// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
        /// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
        /// <param name="pathBase">
        /// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="ProtoRequest.PathBase"/> will be used.
        /// </param>
        /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
        /// <param name="options">
        /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
        /// names from <c>RouteOptions</c>.
        /// </param>
        /// <returns>A URI with an absolute path, or <c>null</c>.</returns>
        public static string GetPathByRouteValues(
            this LinkGenerator generator,
            ProtoContext httpContext,
            string routeName,
            object values,
            PathString?pathBase     = default,
            FragmentString fragment = default,
            LinkOptions options     = default)
        {
            if (generator == null)
            {
                throw new ArgumentNullException(nameof(generator));
            }

            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            var address = CreateAddress(httpContext, routeName, values);

            return(generator.GetPathByAddress <RouteValuesAddress>(
                       httpContext,
                       address,
                       address.ExplicitValues,
                       address.AmbientValues,
                       pathBase,
                       fragment,
                       options));
        }
        /// <summary>
        /// Authenticate for the specified authentication scheme.
        /// </summary>
        /// <param name="context">The <see cref="ProtoContext"/>.</param>
        /// <param name="scheme">The name of the authentication scheme.</param>
        /// <returns>The result.</returns>
        public virtual async Task <AuthenticateResult> AuthenticateAsync(ProtoContext context, string scheme)
        {
            if (scheme == null)
            {
                var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync();

                scheme = defaultScheme?.Name;
                if (scheme == null)
                {
                    throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found.");
                }
            }

            var handler = await Handlers.GetHandlerAsync(context, scheme);

            if (handler == null)
            {
                throw await CreateMissingHandlerException(scheme);
            }

            var result = await handler.AuthenticateAsync();

            if (result != null && result.Succeeded)
            {
                var transformed = await Transform.TransformAsync(result.Principal);

                return(AuthenticateResult.Success(new AuthenticationTicket(transformed, result.Properties, result.Ticket.AuthenticationScheme)));
            }
            return(result);
        }
Example #10
0
        /// <inheritdoc />
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (values.TryGetValue(routeKey, out var obj) && obj != null)
            {
                var value = Convert.ToString(obj, CultureInfo.InvariantCulture);
                return(IsFileName(value));
            }

            // No value or null value.
            return(false);
        }
Example #11
0
        /// <inheritdoc />
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (values.TryGetValue(routeKey, out var value) && value != null)
            {
                var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
                return(valueString.Length <= MaxLength);
            }

            return(false);
        }
Example #12
0
        public Task Invoke(ProtoContext context)
        {
            // Detect if an opaque upgrade is available. If so, add a websocket upgrade.
            var upgradeFeature = context.Features.Get <IProtoUpgradeFeature>();

            if (upgradeFeature != null && context.Features.Get <IProtoGameSocketFeature>() == null)
            {
                var webSocketFeature = new UpgradeHandshake(context, upgradeFeature, _options);
                context.Features.Set <IProtoGameSocketFeature>(webSocketFeature);

                if (!_anyOriginAllowed)
                {
                    // Check for Origin header
                    var originHeader = context.Request.Headers[HeaderNames.Origin];

                    if (!StringValues.IsNullOrEmpty(originHeader) && webSocketFeature.IsGameSocketRequest)
                    {
                        // Check allowed origins to see if request is allowed
                        if (!_allowedOrigins.Contains(originHeader.ToString(), StringComparer.Ordinal))
                        {
                            _logger.LogDebug("Request origin {Origin} is not in the list of allowed origins.", originHeader);
                            context.Response.StatusCode = StatusCodes.Status403Forbidden;
                            return(Task.CompletedTask);
                        }
                    }
                }
            }

            return(_next(context));
        }
        /// <inheritdoc />
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (values.TryGetValue(routeKey, out var value) && value != null)
            {
                var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
                if (long.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
                {
                    return(longValue >= Min && longValue <= Max);
                }
            }

            return(false);
        }
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (values.TryGetValue(routeKey, out var value))
            {
                return(InnerConstraint.Match(httpContext,
                                             route,
                                             routeKey,
                                             values,
                                             routeDirection));
            }

            return(true);
        }
 // Internal for testing
 internal bool TryProcessTemplate(
     ProtoContext httpContext,
     RouteEndpoint endpoint,
     RouteValueDictionary values,
     RouteValueDictionary ambientValues,
     LinkOptions options,
     out (PathString path, QueryString query) result)
Example #16
0
        /// <summary>
        /// Executes the middleware.
        /// </summary>
        /// <param name="context">The <see cref="ProtoContext"/> for the current request.</param>
        /// <returns>A task that represents the execution of this middleware.</returns>
        public async Task Invoke(ProtoContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            PathString matchedPath;
            PathString remainingPath;

            if (context.Request.Path.StartsWithSegments(_options.PathMatch, out matchedPath, out remainingPath))
            {
                // Update the path
                var path     = context.Request.Path;
                var pathBase = context.Request.PathBase;
                context.Request.PathBase = pathBase.Add(matchedPath);
                context.Request.Path     = remainingPath;

                try
                {
                    await _options.Branch(context);
                }
                finally
                {
                    context.Request.PathBase = pathBase;
                    context.Request.Path     = path;
                }
            }
            else
            {
                await _next(context);
            }
        }
        /// <summary>
        /// Executes the middleware.
        /// </summary>
        /// <param name="context">The <see cref="ProtoContext"/> for the current request.</param>
        /// <returns>A task that represents the execution of this middleware.</returns>
        public async Task Invoke(ProtoContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            PathString matchedPath;
            PathString remainingPath;

            if (context.Request.Path.StartsWithSegments(_pathBase, out matchedPath, out remainingPath))
            {
                var originalPath     = context.Request.Path;
                var originalPathBase = context.Request.PathBase;
                context.Request.Path     = remainingPath;
                context.Request.PathBase = originalPathBase.Add(matchedPath);

                try
                {
                    await _next(context);
                }
                finally
                {
                    context.Request.Path     = originalPath;
                    context.Request.PathBase = originalPathBase;
                }
            }
            else
            {
                await _next(context);
            }
        }
Example #18
0
        /// <inheritdoc />
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (values.TryGetValue(routeKey, out var value) && value != null)
            {
                if (value is decimal)
                {
                    return(true);
                }

                var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
                return(decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out _));
            }

            return(false);
        }
Example #19
0
        /// <summary>
        /// Generates a URI with an absolute path based on the provided values.
        /// </summary>
        /// <param name="generator">The <see cref="LinkGenerator"/>.</param>
        /// <param name="httpContext">The <see cref="ProtoContext"/> associated with the current request.</param>
        /// <param name="endpointName">The endpoint name. Used to resolve endpoints.</param>
        /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
        /// <param name="pathBase">
        /// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="ProtoRequest.PathBase"/> will be used.
        /// </param>
        /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
        /// <param name="options">
        /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
        /// names from <c>RouteOptions</c>.
        /// </param>
        /// <returns>A URI with an absolute path, or <c>null</c>.</returns>
        public static string GetPathByName(
            this LinkGenerator generator,
            ProtoContext httpContext,
            string endpointName,
            object values,
            PathString?pathBase     = default,
            FragmentString fragment = default,
            LinkOptions options     = default)
        {
            if (generator == null)
            {
                throw new ArgumentNullException(nameof(generator));
            }

            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (endpointName == null)
            {
                throw new ArgumentNullException(nameof(endpointName));
            }

            return(generator.GetPathByAddress <string>(
                       httpContext,
                       endpointName,
                       new RouteValueDictionary(values),
                       ambientValues: null,
                       pathBase,
                       fragment,
                       options));
        }
        /// <inheritdoc />
        public bool Match(
            ProtoContext httpContext,
            IRouter route,
            string routeKey,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (routeKey == null)
            {
                throw new ArgumentNullException(nameof(routeKey));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (values.TryGetValue(routeKey, out var value) && value != null)
            {
                // In routing the empty string is equivalent to null, which is equivalent to an unset value.
                var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
                return(!string.IsNullOrEmpty(valueString));
            }

            return(false);
        }
Example #21
0
 private void EnsureOptions(ProtoContext context)
 {
     if (_options == null)
     {
         _options = context.RequestServices.GetRequiredService <IOptions <RouteOptions> >().Value;
     }
 }
        public override string GetPathByAddress <TAddress>(
            ProtoContext httpContext,
            TAddress address,
            RouteValueDictionary values,
            RouteValueDictionary ambientValues = default,
            PathString?pathBase     = default,
            FragmentString fragment = default,
            LinkOptions options     = null)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            var endpoints = GetEndpoints(address);

            if (endpoints.Count == 0)
            {
                return(null);
            }

            return(GetPathByEndpoints(
                       httpContext,
                       endpoints,
                       values,
                       ambientValues,
                       pathBase ?? httpContext.Request.PathBase,
                       fragment,
                       options));
        }
        public async Task Invoke(ProtoContext context)
        {
            if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
            {
                if (_options.FormFieldName != null)
                {
                    if (context.Request.HasFormContentType)
                    {
                        var form = await context.Request.ReadFormAsync();

                        var methodType = form[_options.FormFieldName];
                        if (!string.IsNullOrEmpty(methodType))
                        {
                            context.Request.Method = methodType;
                        }
                    }
                }
                else
                {
                    var xProtoMethodOverrideValue = context.Request.Headers[xProtoMethodOverride];
                    if (!string.IsNullOrEmpty(xProtoMethodOverrideValue))
                    {
                        context.Request.Method = xProtoMethodOverrideValue;
                    }
                }
            }
            await _next(context);
        }
Example #24
0
        public StaticFileContext(ProtoContext context, StaticFileOptions options, PathString matchUrl, ILogger logger, IFileProvider fileProvider, IContentTypeProvider contentTypeProvider)
        {
            _context             = context;
            _options             = options;
            _matchUrl            = matchUrl;
            _request             = context.Request;
            _response            = context.Response;
            _logger              = logger;
            _requestHeaders      = _request.GetTypedHeaders();
            _responseHeaders     = _response.GetTypedHeaders();
            _fileProvider        = fileProvider;
            _contentTypeProvider = contentTypeProvider;

            _method                 = null;
            _isGet                  = false;
            _isHead                 = false;
            _subPath                = PathString.Empty;
            _contentType            = null;
            _fileInfo               = null;
            _length                 = 0;
            _lastModified           = new DateTimeOffset();
            _etag                   = null;
            _ifMatchState           = PreconditionState.Unspecified;
            _ifNoneMatchState       = PreconditionState.Unspecified;
            _ifModifiedSinceState   = PreconditionState.Unspecified;
            _ifUnmodifiedSinceState = PreconditionState.Unspecified;
            _range                  = null;
            _isRangeRequest         = false;
        }
        private string GetPathByEndpoints(
            ProtoContext httpContext,
            List <RouteEndpoint> endpoints,
            RouteValueDictionary values,
            RouteValueDictionary ambientValues,
            PathString pathBase,
            FragmentString fragment,
            LinkOptions options)
        {
            for (var i = 0; i < endpoints.Count; i++)
            {
                var endpoint = endpoints[i];
                if (TryProcessTemplate(
                        httpContext: httpContext,
                        endpoint: endpoint,
                        values: values,
                        ambientValues: ambientValues,
                        options: options,
                        result: out var result))
                {
                    var uri = UriHelper.BuildRelative(
                        pathBase,
                        result.path,
                        result.query,
                        fragment);
                    Log.LinkGenerationSucceeded(_logger, endpoints, uri);
                    return(uri);
                }
            }

            Log.LinkGenerationFailed(_logger, endpoints);
            return(null);
        }
Example #26
0
 /// <summary>
 /// Creates a new instance of <see cref="VirtualPathContext"/>.
 /// </summary>
 /// <param name="httpContext">The <see cref="Proto.ProtoContext"/> associated with the current request.</param>
 /// <param name="ambientValues">The set of route values associated with the current request.</param>
 /// <param name="values">The set of new values provided for virtual path generation.</param>
 public VirtualPathContext(
     ProtoContext httpContext,
     RouteValueDictionary ambientValues,
     RouteValueDictionary values)
     : this(httpContext, ambientValues, values, null)
 {
 }
Example #27
0
        public override Task MatchAsync(ProtoContext httpContext, EndpointSelectorContext context)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var path = httpContext.Request.Path.Value;

            for (var i = 0; i < Matchers.Length; i++)
            {
                if (Matchers[i].TryMatch(path))
                {
                    context.Endpoint    = Matchers[i].Endpoint;
                    context.RouteValues = new RouteValueDictionary();
                }
            }

            return(Task.CompletedTask);
        }
Example #28
0
 /// <summary>
 /// Generates a URI with an absolute path based on the provided values and <see cref="ProtoContext"/>.
 /// </summary>
 /// <typeparam name="TAddress">The address type.</typeparam>
 /// <param name="httpContext">The <see cref="ProtoContext"/> associated with the current request.</param>
 /// <param name="address">The address value. Used to resolve endpoints.</param>
 /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
 /// <param name="ambientValues">The values associated with the current request. Optional.</param>
 /// <param name="pathBase">
 /// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="ProtoRequest.PathBase"/> will be used.
 /// </param>
 /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
 /// <param name="options">
 /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
 /// names from <c>RouteOptions</c>.
 /// </param>
 /// <returns>A URI with an absolute path, or <c>null</c>.</returns>
 public abstract string GetPathByAddress <TAddress>(
     ProtoContext httpContext,
     TAddress address,
     RouteValueDictionary values,
     RouteValueDictionary ambientValues = default,
     PathString?pathBase     = default,
     FragmentString fragment = default,
     LinkOptions options     = default);
Example #29
0
 public void ModelInjectionTest()
 {
     p = new ProtobufContext();
     p.Add(m1);
     p.ExecutorInterface((List <member>)p.ModelsList.ElementAt(0));
     ProtoContext c = p.Context;
     var          s = c.members.ElementAt(0).FirstName;
 }
 public bool Match(ProtoContext httpContext,
                   IRouter route,
                   string routeKey,
                   RouteValueDictionary values,
                   RouteDirection routeDirection)
 {
     return(true);
 }