private static HttpRequestMessage CreateProxyHttpRequest(HttpContext context, Uri uri) { var request = context.Request; var requestMessage = new HttpRequestMessage(); var requestMethod = request.Method; if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod)) { var streamContent = new StreamContent(request.Body); requestMessage.Content = streamContent; } // Copy the request headers foreach (var header in request.Headers) { if (NotForwardedHttpHeaders.Contains(header.Key, StringComparer.OrdinalIgnoreCase)) { continue; } if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null) { requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); } } requestMessage.Headers.Host = uri.Authority; requestMessage.RequestUri = uri; requestMessage.Method = new HttpMethod(request.Method); return(requestMessage); }
protected override bool ShouldValidate(AuthorizationFilterContext context) { if (!base.ShouldValidate(context)) { return(false); } //if (!_securitySettings.EnableXsrfProtectionForPublicStore) // return false; ////ignore GET requests var request = context.HttpContext.Request; if (request == null) { return(false); } if (HttpMethods.IsGet(request.Method)) { return(false); } //check whether this filter has been overridden for the Action var actionFilter = context.ActionDescriptor.FilterDescriptors .Where(f => f.Scope == FilterScope.Action) .Select(f => f.Filter).OfType <PublicAntiForgeryAttribute>().FirstOrDefault(); //ignore this filter if (actionFilter?.IgnoreFilter ?? _ignoreFilter) { return(false); } return(true); }
public async Task ExecuteAsync(HttpContext context, HttpConnectionDispatcherOptions options, ConnectionDelegate connectionDelegate) { // Create the log scope and attempt to pass the Connection ID to it so as many logs as possible contain // the Connection ID metadata. If this is the negotiate request then the Connection ID for the scope will // be set a little later. var logScope = new ConnectionLogScope(GetConnectionId(context)); using (_logger.BeginScope(logScope)) { if (!await AuthorizeHelper.AuthorizeAsync(context, options.AuthorizationData)) { return; } if (HttpMethods.IsPost(context.Request.Method)) { // POST /{path} await ProcessSend(context, options); } else if (HttpMethods.IsGet(context.Request.Method)) { // GET /{path} await ExecuteAsync(context, connectionDelegate, options, logScope); } else if (HttpMethods.IsDelete(context.Request.Method)) { // DELETE /{path} await ProcessDeleteAsync(context); } else { context.Response.ContentType = "text/plain"; context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed; } } }
protected virtual HttpVerbs GetVerb(HttpRequest request) { if (HttpMethods.IsGet(request.Method)) { return(HttpVerbs.Get); } if (HttpMethods.IsPost(request.Method)) { return(HttpVerbs.Post); } if (HttpMethods.IsPut(request.Method)) { return(HttpVerbs.Put); } if (HttpMethods.IsDelete(request.Method)) { return(HttpVerbs.Delete); } return(HttpVerbs.None); }
public Task <IEndpointResult> ProcessAsync(HttpContext context) { _logger.LogTrace("Processing discovery request."); // validate HTTP if (!HttpMethods.IsGet(context.Request.Method)) { _logger.LogWarning("Discovery endpoint only supports GET requests"); return(Task.FromResult((IEndpointResult) new StatusCodeResult(HttpStatusCode.MethodNotAllowed))); } if (!_options.Discovery.ShowKeySet) { _logger.LogInformation("Key discovery disabled. 404."); return(Task.FromResult((IEndpointResult) new StatusCodeResult(HttpStatusCode.NotFound))); } // generate response _logger.LogTrace("Calling into discovery response generator: {type}", _responseGenerator.GetType().FullName); var response = _responseCache.GetOrAdd(1, _ => _responseGenerator.CreateJwkDocumentAsync().GetAwaiter().GetResult()); _logger.LogTrace("Discovery request completed. Return JsonWebKeysResult"); return(Task.FromResult((IEndpointResult) new JsonWebKeysResult(response, _options.Discovery.ResponseCacheInterval))); }
private static HttpMethod GetMethod(string method) { if (HttpMethods.IsDelete(method)) { return(HttpMethod.Delete); } if (HttpMethods.IsGet(method)) { return(HttpMethod.Get); } if (HttpMethods.IsOptions(method)) { return(HttpMethod.Options); } if (HttpMethods.IsPost(method)) { return(HttpMethod.Post); } if (HttpMethods.IsPut(method)) { return(HttpMethod.Put); } return(new HttpMethod(method)); }
public override async Task Invoke(HttpContext context) { if (HttpMethods.IsGet(context.Request.Method)) { var tempData = _tempDataFactory.GetTempData(context); var requestTempData = tempData.Get <Payment>(CloudPaymentsDefaults.TempDataKey); if (requestTempData == null) { _logger.EmptyTempData(CloudPaymentsDefaults.TempDataKey); context.Response.StatusCode = StatusCodes.Status404NotFound; return; } tempData.Keep(CloudPaymentsDefaults.TempDataKey); tempData.Save(); await new PaymentForm(new PaymentFormModel { Amount = requestTempData.Amount, PublicId = _clientOptions.PublicId, AntiforgeryToken = _antiforgery.GetHtml(context), Action = context.Request.GetEncodedUrl(), PaymentFormHeader = requestTempData.Description }).ExecuteAsync(context); return; } if (HttpMethods.IsPost(context.Request.Method)) { var valid = await _antiforgery.IsRequestValidAsync(context); if (!valid) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } if (!context.Request.HasFormContentType) { _logger.NotFormContentType(); context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var form = await context.Request.ReadFormAsync(); if (!(form.TryGetValue(CloudPaymentsDefaults.FormKeyName, out var name) && form.TryGetValue(CloudPaymentsDefaults.FormKeyCryptogram, out var cryptogram))) { _logger.MissingRequiredFormKeys(CloudPaymentsDefaults.FormKeyName, CloudPaymentsDefaults.FormKeyCryptogram); context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var requestTempData = _tempDataFactory.GetTempData(context).Get <Payment>(CloudPaymentsDefaults.TempDataKey); var response = await _client.PayCryptogram(new PaymentCryptogramRequest { Name = name.ToString().ToUpperInvariant(), CardCryptogramPacket = cryptogram.ToString(), Amount = requestTempData.Amount, Currency = requestTempData.Currency, AccountId = requestTempData.AccountId, Description = requestTempData.Description, Email = requestTempData.Email, InvoiceId = requestTempData.InvoiceId, JsonData = requestTempData.JsonData, IPAddress = context.Connection.RemoteIpAddress.ToString() }, requestTempData.TwoStage); if (response.IsSecure3D) { _tempDataFactory.GetTempData(context).Save(CloudPaymentsDefaults.TempDataKey, response); var secure3dLocation = context.Request.BuildAbsolute(CloudPaymentsDefaults.Secure3dPath); _logger.LocalRedirectExecuting(secure3dLocation); context.Response.Redirect(secure3dLocation); return; } if (response.Success) { _logger.PaymentSuccess(); } else { _logger.PaymentFailed(response.Message); } _tempDataFactory.GetTempData(context).Save(CloudPaymentsDefaults.TempDataKey, response); var location = context.Request.BuildAbsolute(_options.ReturnUrl); _logger.LocalRedirectExecuting(location); context.Response.Redirect(location); return; } await _next(context); }
public bool Matches(RouteData routeData, string httpMethod) => HttpMethods.IsGet(httpMethod) && string.Equals((string)routeData.Values["controller"], "orders", StringComparison.OrdinalIgnoreCase) && !routeData.Values.ContainsKey("id");
public async Task InvokeAsync(HttpContext context, ISchema schema, FillDataExtensions fillDataExtensions) { if (context.WebSockets.IsWebSocketRequest || !context.Request.Path.StartsWithSegments(_path)) { await _next(context); return; } _fillDataExtensions = fillDataExtensions; // Handle requests as per recommendation at http://graphql.org/learn/serving-over-http/ // Inspiration: https://github.com/graphql/express-graphql/blob/master/src/index.js var httpRequest = context.Request; var httpResponse = context.Response; //var writer = context.RequestServices.GetRequiredService<IDocumentWriter>(); var cancellationToken = GetCancellationToken(context); // GraphQL HTTP only supports GET and POST methods bool isGet = HttpMethods.IsGet(httpRequest.Method); bool isPost = HttpMethods.IsPost(httpRequest.Method); if (!isGet && !isPost) { httpResponse.Headers["Allow"] = "GET, POST"; await WriteErrorResponseAsync(context, $"Invalid HTTP method. Only GET and POST are supported. {DOCS_URL}", httpStatusCode : 405 // Method Not Allowed ); return; } // Parse POST body GraphQLRequest bodyGQLRequest = null; GraphQLRequest[] bodyGQLBatchRequest = null; if (isPost) { if (!MediaTypeHeaderValue.TryParse(httpRequest.ContentType, out var mediaTypeHeader)) { await WriteErrorResponseAsync(context, $"Invalid 'Content-Type' header: value '{httpRequest.ContentType}' could not be parsed."); return; } switch (mediaTypeHeader.MediaType) { case MediaType.JSON: var deserializationResult = await _deserializer.DeserializeFromJsonBodyAsync(httpRequest, cancellationToken); if (!deserializationResult.IsSuccessful) { await WriteErrorResponseAsync(context, "Body text could not be parsed. Body text should start with '{' for normal graphql query or with '[' for batched query."); return; } bodyGQLRequest = deserializationResult.Single; bodyGQLBatchRequest = deserializationResult.Batch; break; case MediaType.GRAPH_QL: bodyGQLRequest = await DeserializeFromGraphBodyAsync(httpRequest.Body); break; case MediaType.FORM: var formCollection = await httpRequest.ReadFormAsync(); bodyGQLRequest = DeserializeFromFormBody(formCollection); break; default: await WriteErrorResponseAsync(context, $"Invalid 'Content-Type' header: non-supported media type. " + $"Must be of '{MediaType.JSON}', '{MediaType.GRAPH_QL}' or '{MediaType.FORM}'. {DOCS_URL}"); return; } } // If we don't have a batch request, parse the URL too to determine the actual request to run // Querystring params take priority GraphQLRequest gqlRequest = null; if (bodyGQLBatchRequest == null) { // Parse URL var urlGQLRequest = DeserializeFromQueryString(httpRequest.Query); gqlRequest = new GraphQLRequest { Query = urlGQLRequest.Query ?? bodyGQLRequest?.Query, Inputs = urlGQLRequest.Inputs ?? bodyGQLRequest?.Inputs, OperationName = urlGQLRequest.OperationName ?? bodyGQLRequest?.OperationName }; } // Prepare context and execute var userContextBuilder = context.RequestServices.GetService <IUserContextBuilder>(); var userContext = userContextBuilder == null ? new Dictionary <string, object>() // in order to allow resolvers to exchange their state through this object : await userContextBuilder.BuildUserContext(context); var executer = context.RequestServices.GetRequiredService <IGraphQLExecuter <TSchema> >(); // var executer = context.RequestServices.GetRequiredService<IDocumentExecuter>(); // Normal execution with single graphql request if (bodyGQLBatchRequest == null) { var stopwatch = ValueStopwatch.StartNew(); // var result = await ExecuteRequestAsync(schema, gqlRequest, context, executer, cancellationToken); var result = await ExecuteRequestAsync(gqlRequest, userContext, executer, context.RequestServices, cancellationToken); await RequestExecutedAsync(new GraphQLRequestExecutionResult(gqlRequest, result, stopwatch.Elapsed)); if (result.Errors?.Count > 0) { await WriteErrorResponseAsync(context, result); } else { await WriteResponseAsync(context, result); } } // Execute multiple graphql requests in one batch else { var error = false; ExecutionResult executionResult = null; var executionResults = new ExecutionResult[bodyGQLBatchRequest.Length]; for (int i = 0; i < bodyGQLBatchRequest.Length; ++i) { var gqlRequestInBatch = bodyGQLBatchRequest[i]; var stopwatch = ValueStopwatch.StartNew(); // var result = await ExecuteRequestAsync(schema, gqlRequestInBatch, context, executer, cancellationToken); var result = await ExecuteRequestAsync(gqlRequestInBatch, userContext, executer, context.RequestServices, cancellationToken); await RequestExecutedAsync(new GraphQLRequestExecutionResult(gqlRequestInBatch, result, stopwatch.Elapsed, i)); if (result.Errors?.Count > 0) { error = true; executionResult = result; } executionResults[i] = result; } if (error) { await WriteErrorResponseAsync(context, executionResult); } else { // await WriteResponseAsync(context, executionResults); } } }
public bool Matches(RouteData routeData, string httpVerb, HttpRequest request) { return(HttpMethods.IsGet(httpVerb) && routeData.Values.ContainsKey("id")); }
/// <summary> /// Overridden to handle remote signout requests /// </summary> /// <returns><see langword="true" /> if request processing should stop.</returns> public override Task <bool> HandleRequestAsync() { // RemoteSignOutPath and CallbackPath may be the same, fall through if the message doesn't match. if (Options.RemoteSignOutPath.HasValue && Options.RemoteSignOutPath == Request.Path && HttpMethods.IsGet(Request.Method) && string.Equals(Request.Query[WsFederationConstants.WsFederationParameterNames.Wa], WsFederationConstants.WsFederationActions.SignOutCleanup, StringComparison.OrdinalIgnoreCase)) { // We've received a remote sign-out request return(HandleRemoteSignOutAsync()); } return(base.HandleRequestAsync()); }
internal static bool IsGetOrHeadMethod(string method) { return(HttpMethods.IsGet(method) || HttpMethods.IsHead(method)); }
private async Task <bool> InvokeIntrospectionEndpointAsync() { OpenIdConnectRequest request; // See https://tools.ietf.org/html/rfc7662#section-2.1 // and https://tools.ietf.org/html/rfc7662#section-4 if (HttpMethods.IsGet(Request.Method)) { request = new OpenIdConnectRequest(Request.Query); } else if (HttpMethods.IsPost(Request.Method)) { // See http://openid.net/specs/openid-connect-core-1_0.html#FormSerialization if (string.IsNullOrEmpty(Request.ContentType)) { Logger.LogError("The introspection request was rejected because " + "the mandatory 'Content-Type' header was missing."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'Content-Type' header must be specified." })); } // May have media/type; charset=utf-8, allow partial match. if (!Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)) { Logger.LogError("The introspection request was rejected because an invalid 'Content-Type' " + "header was specified: {ContentType}.", Request.ContentType); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified 'Content-Type' header is not valid." })); } request = new OpenIdConnectRequest(await Request.ReadFormAsync(Context.RequestAborted)); } else { Logger.LogError("The introspection request was rejected because an invalid " + "HTTP method was specified: {Method}.", Request.Method); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified HTTP method is not valid." })); } // Note: set the message type before invoking the ExtractIntrospectionRequest event. request.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.IntrospectionRequest); // Store the introspection request in the ASP.NET context. Context.SetOpenIdConnectRequest(request); var @event = new ExtractIntrospectionRequestContext(Context, Scheme, Options, request); await Provider.ExtractIntrospectionRequest(@event); if (@event.Result != null) { if (@event.Result.Handled) { Logger.LogDebug("The introspection request was handled in user code."); return(true); } else if (@event.Result.Skipped) { Logger.LogDebug("The default introspection request handling was skipped from user code."); return(false); } } else if (@event.IsRejected) { Logger.LogError("The introspection request was rejected with the following error: {Error} ; {Description}", /* Error: */ @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ @event.ErrorDescription); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = @event.ErrorDescription, ErrorUri = @event.ErrorUri })); } Logger.LogInformation("The introspection request was successfully extracted " + "from the HTTP request: {Request}.", request); if (string.IsNullOrEmpty(request.Token)) { return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'token' parameter is missing." })); } // Try to resolve the client credentials specified in the 'Authorization' header. // If they cannot be extracted, fallback to the client_id/client_secret parameters. var credentials = Request.Headers.GetClientCredentials(); if (credentials != null) { // Reject requests that use multiple client authentication methods. // See https://tools.ietf.org/html/rfc6749#section-2.3 for more information. if (!string.IsNullOrEmpty(request.ClientSecret)) { Logger.LogError("The introspection request was rejected because " + "multiple client credentials were specified."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "Multiple client credentials cannot be specified." })); } request.ClientId = credentials?.Key; request.ClientSecret = credentials?.Value; } var context = new ValidateIntrospectionRequestContext(Context, Scheme, Options, request); await Provider.ValidateIntrospectionRequest(context); // If the validation context was set as fully validated, // mark the OpenID Connect request as confidential. if (context.IsValidated) { request.SetProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel, OpenIdConnectConstants.ConfidentialityLevels.Private); } if (context.Result != null) { if (context.Result.Handled) { Logger.LogDebug("The introspection request was handled in user code."); return(true); } else if (context.Result.Skipped) { Logger.LogDebug("The default introspection request handling was skipped from user code."); return(false); } } else if (context.IsRejected) { Logger.LogError("The introspection request was rejected with the following error: {Error} ; {Description}", /* Error: */ context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ context.ErrorDescription); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = context.ErrorDescription, ErrorUri = context.ErrorUri })); } // Store the validated client_id as a request property. request.SetProperty(OpenIdConnectConstants.Properties.ValidatedClientId, context.ClientId); Logger.LogInformation("The introspection request was successfully validated."); AuthenticationTicket ticket = null; // Note: use the "token_type_hint" parameter to determine // the type of the token sent by the client application. // See https://tools.ietf.org/html/rfc7662#section-2.1 switch (request.TokenTypeHint) { case OpenIdConnectConstants.TokenTypeHints.AccessToken: ticket = await DeserializeAccessTokenAsync(request.Token, request); break; case OpenIdConnectConstants.TokenTypeHints.AuthorizationCode: ticket = await DeserializeAuthorizationCodeAsync(request.Token, request); break; case OpenIdConnectConstants.TokenTypeHints.IdToken: ticket = await DeserializeIdentityTokenAsync(request.Token, request); break; case OpenIdConnectConstants.TokenTypeHints.RefreshToken: ticket = await DeserializeRefreshTokenAsync(request.Token, request); break; } // Note: if the token can't be found using "token_type_hint", // the search must be extended to all supported token types. // See https://tools.ietf.org/html/rfc7662#section-2.1 if (ticket == null) { // To avoid calling the same deserialization methods twice, // an additional check is made to exclude the corresponding // method when an explicit token_type_hint was specified. switch (request.TokenTypeHint) { case OpenIdConnectConstants.TokenTypeHints.AccessToken: ticket = await DeserializeAuthorizationCodeAsync(request.Token, request) ?? await DeserializeIdentityTokenAsync(request.Token, request) ?? await DeserializeRefreshTokenAsync(request.Token, request); break; case OpenIdConnectConstants.TokenTypeHints.AuthorizationCode: ticket = await DeserializeAccessTokenAsync(request.Token, request) ?? await DeserializeIdentityTokenAsync(request.Token, request) ?? await DeserializeRefreshTokenAsync(request.Token, request); break; case OpenIdConnectConstants.TokenTypeHints.IdToken: ticket = await DeserializeAccessTokenAsync(request.Token, request) ?? await DeserializeAuthorizationCodeAsync(request.Token, request) ?? await DeserializeRefreshTokenAsync(request.Token, request); break; case OpenIdConnectConstants.TokenTypeHints.RefreshToken: ticket = await DeserializeAccessTokenAsync(request.Token, request) ?? await DeserializeAuthorizationCodeAsync(request.Token, request) ?? await DeserializeIdentityTokenAsync(request.Token, request); break; default: ticket = await DeserializeAccessTokenAsync(request.Token, request) ?? await DeserializeAuthorizationCodeAsync(request.Token, request) ?? await DeserializeIdentityTokenAsync(request.Token, request) ?? await DeserializeRefreshTokenAsync(request.Token, request); break; } } if (ticket == null) { Logger.LogInformation("The introspection request was rejected because the token was invalid."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { [OpenIdConnectConstants.Parameters.Active] = false })); } // Note: unlike refresh or identity tokens that can only be validated by client applications, // access tokens can be validated by either resource servers or client applications: // in both cases, the caller must be authenticated if the ticket is marked as confidential. if (context.IsSkipped && ticket.IsConfidential()) { Logger.LogError("The introspection request was rejected because the caller was not authenticated."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { [OpenIdConnectConstants.Parameters.Active] = false })); } // If the ticket is already expired, directly return active=false. if (ticket.Properties.ExpiresUtc.HasValue && ticket.Properties.ExpiresUtc < Options.SystemClock.UtcNow) { Logger.LogInformation("The introspection request was rejected because the token was expired."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { [OpenIdConnectConstants.Parameters.Active] = false })); } // When a client_id can be inferred from the introspection request, // ensure that the client application is a valid audience/presenter. if (!string.IsNullOrEmpty(context.ClientId)) { if (ticket.IsAuthorizationCode() && ticket.HasPresenter() && !ticket.HasPresenter(context.ClientId)) { Logger.LogError("The introspection request was rejected because the " + "authorization code was issued to a different client."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { [OpenIdConnectConstants.Parameters.Active] = false })); } // Ensure the caller is listed as a valid audience or authorized presenter. else if (ticket.IsAccessToken() && ticket.HasAudience() && !ticket.HasAudience(context.ClientId) && ticket.HasPresenter() && !ticket.HasPresenter(context.ClientId)) { Logger.LogError("The introspection request was rejected because the access token " + "was issued to a different client or for another resource server."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { [OpenIdConnectConstants.Parameters.Active] = false })); } // Reject the request if the caller is not listed as a valid audience. else if (ticket.IsIdentityToken() && ticket.HasAudience() && !ticket.HasAudience(context.ClientId)) { Logger.LogError("The introspection request was rejected because the " + "identity token was issued to a different client."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { [OpenIdConnectConstants.Parameters.Active] = false })); } // Reject the introspection request if the caller doesn't // correspond to the client application the token was issued to. else if (ticket.IsRefreshToken() && ticket.HasPresenter() && !ticket.HasPresenter(context.ClientId)) { Logger.LogError("The introspection request was rejected because the " + "refresh token was issued to a different client."); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { [OpenIdConnectConstants.Parameters.Active] = false })); } } var notification = new HandleIntrospectionRequestContext(Context, Scheme, Options, request, ticket) { Active = true, Issuer = Context.GetIssuer(Options), TokenId = ticket.GetTokenId(), TokenUsage = ticket.GetProperty(OpenIdConnectConstants.Properties.TokenUsage), Subject = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject) }; // Note: only set "token_type" when the received token is an access token. // See https://tools.ietf.org/html/rfc7662#section-2.2 // and https://tools.ietf.org/html/rfc6749#section-5.1 if (ticket.IsAccessToken()) { notification.TokenType = OpenIdConnectConstants.TokenTypes.Bearer; } notification.IssuedAt = ticket.Properties.IssuedUtc; notification.NotBefore = ticket.Properties.IssuedUtc; notification.ExpiresAt = ticket.Properties.ExpiresUtc; // Infer the audiences/client_id claims from the properties stored in the authentication ticket. // Note: the client_id claim must be a unique string so multiple presenters cannot be returned. // To work around this limitation, only the first one is returned if multiple values are listed. notification.Audiences.UnionWith(ticket.GetAudiences()); notification.ClientId = ticket.GetPresenters().FirstOrDefault(); // Note: non-metadata claims are only added if the caller's client_id is known // AND is in the specified audiences, unless there's no explicit audience. if (!ticket.HasAudience() || (!string.IsNullOrEmpty(context.ClientId) && ticket.HasAudience(context.ClientId))) { notification.Username = ticket.Principal.Identity?.Name; notification.Scopes.UnionWith(ticket.GetScopes()); // Potentially sensitive claims are only exposed if the client was authenticated // and if the authentication ticket corresponds to an identity or access token. if (context.IsValidated && (ticket.IsAccessToken() || ticket.IsIdentityToken())) { foreach (var grouping in ticket.Principal.Claims.GroupBy(claim => claim.Type)) { // Exclude standard claims, that are already handled via strongly-typed properties. // Make sure to always update this list when adding new built-in claim properties. var type = grouping.Key; switch (type) { case OpenIdConnectConstants.Claims.Audience: case OpenIdConnectConstants.Claims.ExpiresAt: case OpenIdConnectConstants.Claims.IssuedAt: case OpenIdConnectConstants.Claims.Issuer: case OpenIdConnectConstants.Claims.NotBefore: case OpenIdConnectConstants.Claims.Scope: case OpenIdConnectConstants.Claims.Subject: case OpenIdConnectConstants.Claims.TokenType: case OpenIdConnectConstants.Claims.TokenUsage: continue; } var claims = grouping.ToArray(); switch (claims.Length) { case 0: continue; // When there's only one claim with the same type, directly // convert the claim as an OpenIdConnectParameter instance, // whose token type is determined from the claim value type. case 1: { notification.Claims[type] = claims[0].AsParameter(); continue; } // When multiple claims share the same type, convert all the claims // to OpenIdConnectParameter instances, retrieve the underlying // JSON values and add everything to a new JSON array. default: { notification.Claims[type] = new JArray(claims.Select(claim => claim.AsParameter().Value)); continue; } } } } } await Provider.HandleIntrospectionRequest(notification); if (notification.Result != null) { if (notification.Result.Handled) { Logger.LogDebug("The introspection request was handled in user code."); return(true); } else if (notification.Result.Skipped) { Logger.LogDebug("The default introspection request handling was skipped from user code."); return(false); } } else if (notification.IsRejected) { Logger.LogError("The introspection request was rejected with the following error: {Error} ; {Description}", /* Error: */ notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ notification.ErrorDescription); return(await SendIntrospectionResponseAsync(new OpenIdConnectResponse { Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = notification.ErrorDescription, ErrorUri = notification.ErrorUri })); } var response = new OpenIdConnectResponse { [OpenIdConnectConstants.Claims.Active] = notification.Active }; // Only add the other properties if // the token is considered as active. if (notification.Active) { response[OpenIdConnectConstants.Claims.Issuer] = notification.Issuer; response[OpenIdConnectConstants.Claims.Username] = notification.Username; response[OpenIdConnectConstants.Claims.Subject] = notification.Subject; response[OpenIdConnectConstants.Claims.Scope] = string.Join(" ", notification.Scopes); response[OpenIdConnectConstants.Claims.JwtId] = notification.TokenId; response[OpenIdConnectConstants.Claims.TokenType] = notification.TokenType; response[OpenIdConnectConstants.Claims.TokenUsage] = notification.TokenUsage; response[OpenIdConnectConstants.Claims.ClientId] = notification.ClientId; if (notification.IssuedAt != null) { response[OpenIdConnectConstants.Claims.IssuedAt] = EpochTime.GetIntDate(notification.IssuedAt.Value.UtcDateTime); } if (notification.NotBefore != null) { response[OpenIdConnectConstants.Claims.NotBefore] = EpochTime.GetIntDate(notification.NotBefore.Value.UtcDateTime); } if (notification.ExpiresAt != null) { response[OpenIdConnectConstants.Claims.ExpiresAt] = EpochTime.GetIntDate(notification.ExpiresAt.Value.UtcDateTime); } switch (notification.Audiences.Count) { case 0: break; case 1: response[OpenIdConnectConstants.Claims.Audience] = notification.Audiences.ElementAt(0); break; default: response[OpenIdConnectConstants.Claims.Audience] = new JArray(notification.Audiences); break; } foreach (var claim in notification.Claims) { response.SetParameter(claim.Key, claim.Value); } } return(await SendIntrospectionResponseAsync(response)); }
private async Task HandleHttpRequest(HttpContext context) { PathString path = context.Request.Path; if (path.ToString().Contains("lfs")) { await this.next(context); return; } var matchCriteria = new Regex("/api/([0-9]+)/([a-zA-Z0-9-\\.]*/?.*)"); Match match = matchCriteria.Match(context.Request.Path.ToString()); if (match.Success == false) { await this.next(context); return; } var dbContext = context.RequestServices.GetService <ApplicationDbContext>(); if (int.TryParse(match.Groups[1].Value, out int hostIndex) == false) { await this.next(context); return; } GitHost gitHost = await dbContext.GitHost.SingleOrDefaultAsync(x => x.Id == hostIndex); if (gitHost == null) { await this.next(context); return; } var requestMessage = new HttpRequestMessage(); string requestMethod = context.Request.Method; if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod)) { var streamContent = new StreamContent(context.Request.Body); requestMessage.Content = streamContent; } // Copy the request headers foreach (KeyValuePair <string, StringValues> header in context.Request.Headers) { if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null) { requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); } } string newPath = match.Groups[2].Value; var uri = new Uri($"{gitHost.Href}/{context.Request.PathBase}{newPath}{context.Request.QueryString}"); requestMessage.Headers.Host = uri.Host; requestMessage.RequestUri = uri; requestMessage.Method = new HttpMethod(context.Request.Method); using (HttpResponseMessage responseMessage = await this.httpClient.SendAsync( requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted)) { context.Response.StatusCode = (int)responseMessage.StatusCode; foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Headers) { context.Response.Headers[header.Key] = header.Value.ToArray(); } foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Content.Headers) { context.Response.Headers[header.Key] = header.Value.ToArray(); } // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response. context.Response.Headers.Remove("transfer-encoding"); await responseMessage.Content.CopyToAsync(context.Response.Body); } }
public async Task <IActionResult> CashOut(CashOutModel model) { var member = await HttpContext.GetMemberAsync(); var issuers = await _paymentProcessor.GetIssuersAsync(); model.MobileIssuerOptions.AddRange(SelectListHelper.GetSelectList(elements: issuers.Where(x => x.Mode == PaymentMode.Mobile), x => new SelectListItem <PaymentIssuer>(x.Name, x.Code))); model.MobileIssuer = member.MobileIssuer; model.MobileNumber = member.MobileNumber; model.BankIssuerOptions.AddRange(SelectListHelper.GetSelectList(elements: issuers.Where(x => x.Mode == PaymentMode.Bank), x => new SelectListItem <PaymentIssuer>(x.Name, x.Code))); model.BankIssuer = member.BankIssuer; model.BankNumber = member.BankNumber; model.Fee = Math.Round(((_appSettings.PaymentRate * 100) * model.Amount) / 100, 2, MidpointRounding.AwayFromZero); if (HttpMethods.IsGet(Request.Method)) { ModelState.Clear(); } else if (HttpMethods.IsPost(Request.Method)) { if (ModelState.IsValid) { var canWithdraw = _userService.CanWithdraw(member, model.Amount + model.Fee); if (canWithdraw.Success) { if (!Request.IsCallBack()) { ViewData["Persistent"] = true; } else { var transaction = new Transaction { Title = $"Payment for Withdrawal.", Description = $"Payment for Withdrawal.", Logo = Url.ContentLink(Url.Content("~/img/logo.png")), MemberId = member.Id, Reference = model.Reference, AccountName = member.FullName, AccountEmail = member.Email, AccountNumber = model.AccountNumber, AccountBalance = member.Balance, TransactionCode = await _paymentProcessor.GenerateTransactionCodeAsync(), AuthorizationCode = await _paymentProcessor.GetAuthorizationCodeAsync(), Issuer = model.Issuer, Mode = model.Mode, Processor = TransactionProcessor.External, Amount = model.Amount, Fee = model.Fee, IpAddress = await HttpContext.GetIpAddressAsync(), UserAgent = Request.Headers["User-Agent"], Type = TransactionType.Withdrawal, }; await _paymentProcessor.ProcessAsync(transaction); if (transaction.Status == TransactionStatus.Pending) { await _paymentProcessor.VerifyAsync(transaction); } if (transaction.Status == TransactionStatus.Succeeded) { await _transactionService.CreateAsync(transaction); await _userService.WithdrawAsync(member, transaction.Amount + transaction.Fee); TempData.AddAlert(AlertMode.Notify, AlertType.Success, "Payment successful!"); } else { ModelState.AddModelError(string.Empty, "Unable to process payment."); } } } else { ModelState.AddModelError(string.Empty, canWithdraw.Message); } } } return(PartialView(model)); }
private StreamCopyHttpContent SetupRequestBodyCopy(HttpRequest request, bool isStreamingRequest, CancellationToken cancellation) { // If we generate an HttpContent without a Content-Length then for HTTP/1.1 HttpClient will add a Transfer-Encoding: chunked header // even if it's a GET request. Some servers reject requests containing a Transfer-Encoding header if they're not expecting a body. // Try to be as specific as possible about the client's intent to send a body. The one thing we don't want to do is to start // reading the body early because that has side-effects like 100-continue. var hasBody = true; var contentLength = request.Headers.ContentLength; var method = request.Method; #if NET var canHaveBodyFeature = request.HttpContext.Features.Get <IHttpRequestBodyDetectionFeature>(); if (canHaveBodyFeature != null) { // 5.0 servers provide a definitive answer for us. hasBody = canHaveBodyFeature.CanHaveBody; } else #endif // https://tools.ietf.org/html/rfc7230#section-3.3.3 // All HTTP/1.1 requests should have Transfer-Encoding or Content-Length. // Http.Sys/IIS will even add a Transfer-Encoding header to HTTP/2 requests with bodies for back-compat. // HTTP/1.0 Connection: close bodies are only allowed on responses, not requests. // https://tools.ietf.org/html/rfc1945#section-7.2.2 // // Transfer-Encoding overrides Content-Length per spec if (request.Headers.TryGetValue(HeaderNames.TransferEncoding, out var transferEncoding) && transferEncoding.Count == 1 && string.Equals("chunked", transferEncoding.ToString(), StringComparison.OrdinalIgnoreCase)) { hasBody = true; } else if (contentLength.HasValue) { hasBody = contentLength > 0; } // Kestrel HTTP/2: There are no required headers that indicate if there is a request body so we need to sniff other fields. else if (!ProtocolHelper.IsHttp2OrGreater(request.Protocol)) { hasBody = false; } // https://tools.ietf.org/html/rfc7231#section-4.3.1 // A payload within a GET/HEAD/DELETE/CONNECT request message has no defined semantics; sending a payload body on a // GET/HEAD/DELETE/CONNECT request might cause some existing implementations to reject the request. // https://tools.ietf.org/html/rfc7231#section-4.3.8 // A client MUST NOT send a message body in a TRACE request. else if (HttpMethods.IsGet(method) || HttpMethods.IsHead(method) || HttpMethods.IsDelete(method) || HttpMethods.IsConnect(method) || HttpMethods.IsTrace(method)) { hasBody = false; } // else hasBody defaults to true StreamCopyHttpContent requestContent = null; if (hasBody) { if (isStreamingRequest) { DisableMinRequestBodyDataRateAndMaxRequestBodySize(request.HttpContext); } // Note on `autoFlushHttpClientOutgoingStream: isStreamingRequest`: // The.NET Core HttpClient stack keeps its own buffers on top of the underlying outgoing connection socket. // We flush those buffers down to the socket on every write when this is set, // but it does NOT result in calls to flush on the underlying socket. // This is necessary because we proxy http2 transparently, // and we are deliberately unaware of packet structure used e.g. in gRPC duplex channels. // Because the sockets aren't flushed, the perf impact of this choice is expected to be small. // Future: It may be wise to set this to true for *all* http2 incoming requests, // but for now, out of an abundance of caution, we only do it for requests that look like gRPC. requestContent = new StreamCopyHttpContent( source: request.Body, autoFlushHttpClientOutgoingStream: isStreamingRequest, clock: _clock, cancellation: cancellation); } return(requestContent); }
private async Task <bool> InvokeAuthorizationEndpointAsync() { OpenIdConnectRequest request; if (HttpMethods.IsGet(Request.Method)) { request = new OpenIdConnectRequest(Request.Query); } else if (HttpMethods.IsPost(Request.Method)) { // See http://openid.net/specs/openid-connect-core-1_0.html#FormSerialization if (string.IsNullOrEmpty(Request.ContentType)) { Logger.LogError("The authorization request was rejected because " + "the mandatory 'Content-Type' header was missing."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'Content-Type' header must be specified." })); } // May have media/type; charset=utf-8, allow partial match. if (!Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)) { Logger.LogError("The authorization request was rejected because an invalid 'Content-Type' " + "header was specified: {ContentType}.", Request.ContentType); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified 'Content-Type' header is not valid." })); } request = new OpenIdConnectRequest(await Request.ReadFormAsync(Context.RequestAborted)); } else { Logger.LogError("The authorization request was rejected because an invalid " + "HTTP method was specified: {Method}.", Request.Method); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified HTTP method is not valid." })); } // Note: set the message type before invoking the ExtractAuthorizationRequest event. request.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.AuthorizationRequest); // Store the authorization request in the ASP.NET context. Context.SetOpenIdConnectRequest(request); var @event = new ExtractAuthorizationRequestContext(Context, Scheme, Options, request); await Provider.ExtractAuthorizationRequest(@event); if (@event.Result != null) { if (@event.Result.Handled) { Logger.LogDebug("The authorization request was handled in user code."); return(true); } else if (@event.Result.Skipped) { Logger.LogDebug("The default authorization request handling was skipped from user code."); return(false); } } else if (@event.IsRejected) { Logger.LogError("The authorization request was rejected with the following error: {Error} ; {Description}", /* Error: */ @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ @event.ErrorDescription); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = @event.ErrorDescription, ErrorUri = @event.ErrorUri })); } // Store the original redirect_uri sent by the client application for later comparison. request.SetProperty(OpenIdConnectConstants.Properties.OriginalRedirectUri, request.RedirectUri); Logger.LogInformation("The authorization request was successfully extracted " + "from the HTTP request: {Request}.", request); // client_id is mandatory parameter and MUST cause an error when missing. // See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest if (string.IsNullOrEmpty(request.ClientId)) { Logger.LogError("The authorization request was rejected because " + "the mandatory 'client_id' parameter was missing."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'client_id' parameter is missing." })); } // While redirect_uri was not mandatory in OAuth2, this parameter // is now declared as REQUIRED and MUST cause an error when missing. // See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest // To keep AspNet.Security.OpenIdConnect.Server compatible with pure OAuth2 clients, // an error is only returned if the request was made by an OpenID Connect client. if (string.IsNullOrEmpty(request.RedirectUri) && request.HasScope(OpenIdConnectConstants.Scopes.OpenId)) { Logger.LogError("The authorization request was rejected because " + "the mandatory 'redirect_uri' parameter was missing."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'redirect_uri' parameter is missing." })); } if (!string.IsNullOrEmpty(request.RedirectUri)) { // Note: when specified, redirect_uri MUST be an absolute URI. // See http://tools.ietf.org/html/rfc6749#section-3.1.2 // and http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest // // Note: on Linux/macOS, "/path" URLs are treated as valid absolute file URLs. // To ensure relative redirect_uris are correctly rejected on these platforms, // an additional check using IsWellFormedOriginalString() is made here. // See https://github.com/dotnet/corefx/issues/22098 for more information. if (!Uri.TryCreate(request.RedirectUri, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString()) { Logger.LogError("The authorization request was rejected because the 'redirect_uri' parameter " + "didn't correspond to a valid absolute URL: {RedirectUri}.", request.RedirectUri); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The 'redirect_uri' parameter must be a valid absolute URL." })); } // Note: when specified, redirect_uri MUST NOT include a fragment component. // See http://tools.ietf.org/html/rfc6749#section-3.1.2 // and http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest if (!string.IsNullOrEmpty(uri.Fragment)) { Logger.LogError("The authorization request was rejected because the 'redirect_uri' " + "contained a URL fragment: {RedirectUri}.", request.RedirectUri); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The 'redirect_uri' parameter must not include a fragment." })); } } // Reject requests missing the mandatory response_type parameter. if (string.IsNullOrEmpty(request.ResponseType)) { Logger.LogError("The authorization request was rejected because " + "the mandatory 'response_type' parameter was missing."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'response_type' parameter is missing." })); } // response_mode=query (explicit or not) and a response_type containing id_token // or token are not considered as a safe combination and MUST be rejected. // See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security if (request.IsQueryResponseMode() && (request.HasResponseType(OpenIdConnectConstants.ResponseTypes.IdToken) || request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token))) { Logger.LogError("The authorization request was rejected because the 'response_type'/'response_mode' combination " + "was invalid: {ResponseType} ; {ResponseMode}.", request.ResponseType, request.ResponseMode); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified 'response_type'/'response_mode' combination is invalid." })); } // Reject OpenID Connect implicit/hybrid requests missing the mandatory nonce parameter. // See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest, // http://openid.net/specs/openid-connect-implicit-1_0.html#RequestParameters // and http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken. if (string.IsNullOrEmpty(request.Nonce) && request.HasScope(OpenIdConnectConstants.Scopes.OpenId) && (request.IsImplicitFlow() || request.IsHybridFlow())) { Logger.LogError("The authorization request was rejected because the mandatory 'nonce' parameter was missing."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'nonce' parameter is missing." })); } // Reject requests containing the id_token response_type if no openid scope has been received. if (request.HasResponseType(OpenIdConnectConstants.ResponseTypes.IdToken) && !request.HasScope(OpenIdConnectConstants.Scopes.OpenId)) { Logger.LogError("The authorization request was rejected because the 'openid' scope was missing."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'openid' scope is missing." })); } // Reject requests containing the id_token response_type if no asymmetric signing key has been registered. if (request.HasResponseType(OpenIdConnectConstants.ResponseTypes.IdToken) && !Options.SigningCredentials.Any(credentials => credentials.Key is AsymmetricSecurityKey)) { Logger.LogError("The authorization request was rejected because the 'id_token' response type could not be honored. " + "To fix this error, consider registering a X.509 signing certificate or an ephemeral signing key."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.UnsupportedResponseType, ErrorDescription = "The specified 'response_type' is not supported by this server." })); } // Reject requests containing the code response_type if the token endpoint has been disabled. if (request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Code) && !Options.TokenEndpointPath.HasValue) { Logger.LogError("The authorization request was rejected because the authorization code flow was disabled."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.UnsupportedResponseType, ErrorDescription = "The specified 'response_type' is not supported by this server." })); } // Reject requests specifying prompt=none with consent/login or select_account. if (request.HasPrompt(OpenIdConnectConstants.Prompts.None) && (request.HasPrompt(OpenIdConnectConstants.Prompts.Consent) || request.HasPrompt(OpenIdConnectConstants.Prompts.Login) || request.HasPrompt(OpenIdConnectConstants.Prompts.SelectAccount))) { Logger.LogError("The authorization request was rejected because an invalid prompt parameter was specified."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified 'prompt' parameter is invalid." })); } if (!string.IsNullOrEmpty(request.CodeChallenge) || !string.IsNullOrEmpty(request.CodeChallengeMethod)) { // When code_challenge or code_challenge_method is specified, ensure the response_type includes "code". if (!request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Code)) { Logger.LogError("The authorization request was rejected because the response type " + "was not compatible with 'code_challenge'/'code_challenge_method'."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The 'code_challenge' and 'code_challenge_method' parameters " + "can only be used with a response type containing 'code'." })); } if (!string.IsNullOrEmpty(request.CodeChallengeMethod)) { // Ensure a code_challenge was specified if a code_challenge_method was used. if (string.IsNullOrEmpty(request.CodeChallenge)) { Logger.LogError("The authorization request was rejected because the code_challenge was missing."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The 'code_challenge_method' parameter " + "cannot be used without 'code_challenge'." })); } // If a code_challenge_method was specified, ensure the algorithm is supported. if (request.CodeChallengeMethod != OpenIdConnectConstants.CodeChallengeMethods.Plain && request.CodeChallengeMethod != OpenIdConnectConstants.CodeChallengeMethods.Sha256) { Logger.LogError("The authorization request was rejected because " + "the specified code challenge was not supported."); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified code_challenge_method is not supported." })); } } } var context = new ValidateAuthorizationRequestContext(Context, Scheme, Options, request); await Provider.ValidateAuthorizationRequest(context); if (context.Result != null) { if (context.Result.Handled) { Logger.LogDebug("The authorization request was handled in user code."); return(true); } else if (context.Result.Skipped) { Logger.LogDebug("The default authorization request handling was skipped from user code."); return(false); } } else if (context.IsRejected) { Logger.LogError("The authorization request was rejected with the following error: {Error} ; {Description}", /* Error: */ context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ context.ErrorDescription); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = context.ErrorDescription, ErrorUri = context.ErrorUri })); } // Store the validated client_id/redirect_uri as request properties. request.SetProperty(OpenIdConnectConstants.Properties.ValidatedClientId, context.ClientId) .SetProperty(OpenIdConnectConstants.Properties.ValidatedRedirectUri, context.RedirectUri); Logger.LogInformation("The authorization request was successfully validated."); var notification = new HandleAuthorizationRequestContext(Context, Scheme, Options, request); await Provider.HandleAuthorizationRequest(notification); if (notification.Result != null) { if (notification.Result.Handled) { Logger.LogDebug("The authorization request was handled in user code."); return(true); } else if (notification.Result.Skipped) { Logger.LogDebug("The default authorization request handling was skipped from user code."); return(false); } } else if (notification.IsRejected) { Logger.LogError("The authorization request was rejected with the following error: {Error} ; {Description}", /* Error: */ notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ notification.ErrorDescription); return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse { Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = notification.ErrorDescription, ErrorUri = notification.ErrorUri })); } // If an authentication ticket was provided, stop processing // the request and return an authorization response. var ticket = notification.Ticket; if (ticket == null) { return(false); } return(await SignInAsync(ticket)); }
protected virtual (RangeItemHeaderValue range, long rangeLength, bool serveBody) SetHeadersAndLog( ActionContext context, FileResult result, long?fileLength, DateTimeOffset?lastModified = null, EntityTagHeaderValue etag = null, bool enableRangeProcessing = true) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } SetContentType(context, result); SetContentDispositionHeader(context, result); Logger.FileResultExecuting(result.FileDownloadName); var request = context.HttpContext.Request; var httpRequestHeaders = request.GetTypedHeaders(); var response = context.HttpContext.Response; var httpResponseHeaders = response.GetTypedHeaders(); if (lastModified.HasValue) { httpResponseHeaders.LastModified = lastModified; } if (etag != null) { httpResponseHeaders.ETag = etag; } var serveBody = !HttpMethods.IsHead(request.Method); var preconditionState = GetPreconditionState(context, httpRequestHeaders, lastModified, etag); if (preconditionState == PreconditionState.NotModified) { serveBody = false; response.StatusCode = StatusCodes.Status304NotModified; } else if (preconditionState == PreconditionState.PreconditionFailed) { serveBody = false; response.StatusCode = StatusCodes.Status412PreconditionFailed; } if (fileLength.HasValue) { // Assuming the request is not a range request, the Content-Length header is set to the length of the entire file. // If the request is a valid range request, this header is overwritten with the length of the range as part of the // range processing (see method SetContentLength). if (serveBody) { response.ContentLength = fileLength.Value; } if (enableRangeProcessing) { SetAcceptRangeHeader(context); if (HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method)) { if ((preconditionState == PreconditionState.Unspecified || preconditionState == PreconditionState.ShouldProcess)) { if (IfRangeValid(context, httpRequestHeaders, lastModified, etag)) { return(SetRangeHeaders(context, httpRequestHeaders, fileLength.Value)); } } } } } return(range : null, rangeLength : 0, serveBody : serveBody); }
private static bool IsGetOrHeadMethod(string method) => HttpMethods.IsGet(method) || HttpMethods.IsHead(method);
/// <inheritdoc /> public void OnResourceExecuting(ResourceExecutingContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var routeData = context.RouteData; var request = context.HttpContext.Request; if (routeData.TryGetWebHookReceiverName(out var receiverName) && (HttpMethods.IsGet(request.Method) || HttpMethods.IsHead(request.Method))) { var getHeadRequestMetadata = _getHeadRequestMetadata .FirstOrDefault(metadata => metadata.IsApplicable(receiverName)); if (getHeadRequestMetadata != null) { // First verify that we have the secret key configuration value. This may be redundant if the // receiver also implements IWebHookVerifyCodeMetadata in its metadata. However this verification // is necessary for some receivers because signature verification (for example) is not possible // without a body. var secretKey = GetSecretKey( receiverName, routeData, getHeadRequestMetadata.SecretKeyMinLength, getHeadRequestMetadata.SecretKeyMaxLength); if (secretKey == null) { // Have already logged about this case. context.Result = new NotFoundResult(); return; } if (HttpMethods.IsHead(request.Method)) { if (getHeadRequestMetadata.AllowHeadRequests) { // Success #1 Logger.LogInformation( 400, "Received a HEAD request for the '{ReceiverName}' WebHook receiver -- ignoring.", receiverName); context.Result = new OkResult(); } // Never respond to a HEAD request with a challenge response. return; } if (getHeadRequestMetadata.ChallengeQueryParameterName == null) { // Success #2: Simple GET case. Have done all necessary verification. Logger.LogInformation( 401, "Received a GET request for the '{ReceiverName}' WebHook receiver -- ignoring.", receiverName); context.Result = new OkResult(); return; } // Success #3 unless required query parameter is missing. context.Result = GetChallengeResponse(getHeadRequestMetadata, receiverName, request, routeData); } } }
private async Task <bool> InvokeUserinfoEndpointAsync() { OpenIdConnectRequest request; if (HttpMethods.IsGet(Request.Method)) { request = new OpenIdConnectRequest(Request.Query); } else if (HttpMethods.IsPost(Request.Method)) { // Note: if no Content-Type header was specified, assume the userinfo request // doesn't contain any parameter and create an empty OpenIdConnectRequest. if (string.IsNullOrEmpty(Request.ContentType)) { request = new OpenIdConnectRequest(); } else { // May have media/type; charset=utf-8, allow partial match. if (!Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)) { Logger.LogError("The userinfo request was rejected because an invalid 'Content-Type' " + "header was specified: {ContentType}.", Request.ContentType); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified 'Content-Type' header is not valid." })); } request = new OpenIdConnectRequest(await Request.ReadFormAsync()); } } else { Logger.LogError("The userinfo request was rejected because an invalid " + "HTTP method was specified: {Method}.", Request.Method); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified HTTP method is not valid." })); } // Note: set the message type before invoking the ExtractUserinfoRequest event. request.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.UserinfoRequest); // Insert the userinfo request in the ASP.NET context. Context.SetOpenIdConnectRequest(request); var @event = new ExtractUserinfoRequestContext(Context, Scheme, Options, request); await Provider.ExtractUserinfoRequest(@event); if (@event.Result != null) { if (@event.Result.Handled) { Logger.LogDebug("The userinfo request was handled in user code."); return(true); } else if (@event.Result.Skipped) { Logger.LogDebug("The default userinfo request handling was skipped from user code."); return(false); } } else if (@event.IsRejected) { Logger.LogError("The userinfo request was rejected with the following error: {Error} ; {Description}", /* Error: */ @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ @event.ErrorDescription); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = @event.ErrorDescription, ErrorUri = @event.ErrorUri })); } Logger.LogInformation("The userinfo request was successfully extracted " + "from the HTTP request: {Request}.", request); string token = null; if (!string.IsNullOrEmpty(request.AccessToken)) { token = request.AccessToken; } else { string header = Request.Headers[HeaderNames.Authorization]; if (!string.IsNullOrEmpty(header)) { if (!header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { Logger.LogError("The userinfo request was rejected because the " + "'Authorization' header was invalid: {Header}.", header); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified 'Authorization' header is invalid." })); } token = header.Substring("Bearer ".Length); } } if (string.IsNullOrEmpty(token)) { Logger.LogError("The userinfo request was rejected because the access token was missing."); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'access_token' parameter is missing." })); } var context = new ValidateUserinfoRequestContext(Context, Scheme, Options, request); await Provider.ValidateUserinfoRequest(context); if (context.Result != null) { if (context.Result.Handled) { Logger.LogDebug("The userinfo request was handled in user code."); return(true); } else if (context.Result.Skipped) { Logger.LogDebug("The default userinfo request handling was skipped from user code."); return(false); } } else if (context.IsRejected) { Logger.LogError("The userinfo request was rejected with the following error: {Error} ; {Description}", /* Error: */ context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ context.ErrorDescription); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = context.ErrorDescription, ErrorUri = context.ErrorUri })); } Logger.LogInformation("The userinfo request was successfully validated."); var ticket = await DeserializeAccessTokenAsync(token, request); if (ticket == null) { Logger.LogError("The userinfo request was rejected because the access token was invalid."); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidToken, ErrorDescription = "The specified access token is not valid." })); } if (ticket.Properties.ExpiresUtc.HasValue && ticket.Properties.ExpiresUtc < Options.SystemClock.UtcNow) { Logger.LogError("The userinfo request was rejected because the access token was expired."); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidToken, ErrorDescription = "The specified access token is no longer valid." })); } var notification = new HandleUserinfoRequestContext(Context, Scheme, Options, request, ticket) { Issuer = Context.GetIssuer(Options), Subject = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject) }; // Note: when receiving an access token, its audiences list cannot be used for the "aud" claim // as the client application is not the intented audience but only an authorized presenter. // See http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse notification.Audiences.UnionWith(ticket.GetPresenters()); // The following claims are all optional and should be excluded when // no corresponding value has been found in the authentication ticket. if (ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) { notification.FamilyName = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.FamilyName); notification.GivenName = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.GivenName); notification.BirthDate = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Birthdate); } if (ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) { notification.Email = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Email); } if (ticket.HasScope(OpenIdConnectConstants.Scopes.Phone)) { notification.PhoneNumber = ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.PhoneNumber); } await Provider.HandleUserinfoRequest(notification); if (notification.Result != null) { if (notification.Result.Handled) { Logger.LogDebug("The userinfo request was handled in user code."); return(true); } else if (notification.Result.Skipped) { Logger.LogDebug("The default userinfo request handling was skipped from user code."); return(false); } } else if (notification.IsRejected) { Logger.LogError("The userinfo request was rejected with the following error: {Error} ; {Description}", /* Error: */ notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ notification.ErrorDescription); return(await SendUserinfoResponseAsync(new OpenIdConnectResponse { Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = notification.ErrorDescription, ErrorUri = notification.ErrorUri })); } // Ensure the "sub" claim has been correctly populated. if (string.IsNullOrEmpty(notification.Subject)) { throw new InvalidOperationException("The subject claim cannot be null or empty."); } var response = new OpenIdConnectResponse { [OpenIdConnectConstants.Claims.Subject] = notification.Subject, [OpenIdConnectConstants.Claims.Address] = notification.Address, [OpenIdConnectConstants.Claims.Birthdate] = notification.BirthDate, [OpenIdConnectConstants.Claims.Email] = notification.Email, [OpenIdConnectConstants.Claims.EmailVerified] = notification.EmailVerified, [OpenIdConnectConstants.Claims.FamilyName] = notification.FamilyName, [OpenIdConnectConstants.Claims.GivenName] = notification.GivenName, [OpenIdConnectConstants.Claims.Issuer] = notification.Issuer, [OpenIdConnectConstants.Claims.PhoneNumber] = notification.PhoneNumber, [OpenIdConnectConstants.Claims.PhoneNumberVerified] = notification.PhoneNumberVerified, [OpenIdConnectConstants.Claims.PreferredUsername] = notification.PreferredUsername, [OpenIdConnectConstants.Claims.Profile] = notification.Profile, [OpenIdConnectConstants.Claims.Website] = notification.Website }; switch (notification.Audiences.Count) { case 0: break; case 1: response[OpenIdConnectConstants.Claims.Audience] = notification.Audiences.ElementAt(0); break; default: response[OpenIdConnectConstants.Claims.Audience] = new JArray(notification.Audiences); break; } foreach (var claim in notification.Claims) { response.SetParameter(claim.Key, claim.Value); } return(await SendUserinfoResponseAsync(response)); }
/// <summary> /// Called before the action executes, after model binding is complete /// </summary> /// <param name="context">A context for action filters</param> public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { await next(); if (context == null || context.HttpContext == null || context.HttpContext.Request == null) { return; } if (!DataSettingsHelper.DatabaseIsInstalled()) { return; } //only in GET requests if (!HttpMethods.IsGet(context.HttpContext.Request.Method)) { return; } //update last activity date if (_workContext.CurrentCustomer.LastActivityDateUtc.AddMinutes(1.0) < DateTime.UtcNow) { await _customerService.UpdateCustomerField(_workContext.CurrentCustomer, x => x.LastActivityDateUtc, DateTime.UtcNow); } //get current IP address var currentIpAddress = context.HttpContext?.Connection?.RemoteIpAddress?.ToString(); //update customer's IP address if (!string.IsNullOrEmpty(currentIpAddress) && !currentIpAddress.Equals(_workContext.CurrentCustomer.LastIpAddress, StringComparison.OrdinalIgnoreCase)) { _workContext.CurrentCustomer.LastIpAddress = currentIpAddress; await _customerService.UpdateCustomerField(_workContext.CurrentCustomer, x => x.LastIpAddress, currentIpAddress); } //whether is need to store last visited page URL if (!_customerSettings.StoreLastVisitedPage) { return; } //get current page var pageUrl = context.HttpContext?.Request?.GetDisplayUrl(); if (string.IsNullOrEmpty(pageUrl)) { return; } //get previous last page var previousPageUrl = _workContext.CurrentCustomer.GetUserFieldFromEntity <string>(SystemCustomerFieldNames.LastVisitedPage); //save new one if don't match if (!pageUrl.Equals(previousPageUrl, StringComparison.OrdinalIgnoreCase)) { await _userFieldService.SaveField(_workContext.CurrentCustomer, SystemCustomerFieldNames.LastVisitedPage, pageUrl); } if (!string.IsNullOrEmpty(context.HttpContext.Request.Headers[HeaderNames.Referer])) { if (!context.HttpContext.Request.Headers[HeaderNames.Referer].ToString().Contains(context.HttpContext.Request.Host.ToString())) { var previousUrlReferrer = _workContext.CurrentCustomer.GetUserField <string>(_userFieldService, SystemCustomerFieldNames.LastUrlReferrer); var actualUrlReferrer = context.HttpContext.Request.Headers[HeaderNames.Referer]; if (previousUrlReferrer != actualUrlReferrer) { await _userFieldService.SaveField(_workContext.CurrentCustomer, SystemCustomerFieldNames.LastUrlReferrer, actualUrlReferrer); } } } if (_customerSettings.SaveVisitedPage) { if (!_workContext.CurrentCustomer.IsSearchEngineAccount()) { //activity await _customerActivityService.InsertActivity("PublicStore.Url", pageUrl, pageUrl, _workContext.CurrentCustomer); //action await _customerActionEventService.Url(_workContext.CurrentCustomer, context.HttpContext?.Request?.Path.ToString(), context.HttpContext?.Request?.Headers["Referer"]); } } }
private bool isGetRequest(HttpContext context) { return(HttpMethods.IsGet(context.Request.Method)); }
private async Task <bool> InvokeLogoutEndpointAsync() { OpenIdConnectRequest request; // Note: logout requests must be made via GET but POST requests // are also accepted to allow flowing large logout payloads. // See https://openid.net/specs/openid-connect-session-1_0.html#RPLogout if (HttpMethods.IsGet(Request.Method)) { request = new OpenIdConnectRequest(Request.Query); } else if (HttpMethods.IsPost(Request.Method)) { // See http://openid.net/specs/openid-connect-core-1_0.html#FormSerialization if (string.IsNullOrEmpty(Request.ContentType)) { Logger.LogError("The logout request was rejected because " + "the mandatory 'Content-Type' header was missing."); return(await SendLogoutResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The mandatory 'Content-Type' header must be specified." })); } // May have media/type; charset=utf-8, allow partial match. if (!Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)) { Logger.LogError("The logout request was rejected because an invalid 'Content-Type' " + "header was specified: {ContentType}.", Request.ContentType); return(await SendLogoutResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified 'Content-Type' header is not valid." })); } request = new OpenIdConnectRequest(await Request.ReadFormAsync(Context.RequestAborted)); } else { Logger.LogError("The logout request was rejected because an invalid " + "HTTP method was specified: {Method}.", Request.Method); return(await SendLogoutResponseAsync(new OpenIdConnectResponse { Error = OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = "The specified HTTP method is not valid." })); } // Note: set the message type before invoking the ExtractLogoutRequest event. request.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.LogoutRequest); // Store the logout request in the ASP.NET context. Context.SetOpenIdConnectRequest(request); var @event = new ExtractLogoutRequestContext(Context, Scheme, Options, request); await Provider.ExtractLogoutRequest(@event); if (@event.Result != null) { if (@event.Result.Handled) { Logger.LogDebug("The logout request was handled in user code."); return(true); } else if (@event.Result.Skipped) { Logger.LogDebug("The default logout request handling was skipped from user code."); return(false); } } else if (@event.IsRejected) { Logger.LogError("The logout request was rejected with the following error: {Error} ; {Description}", /* Error: */ @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ @event.ErrorDescription); return(await SendLogoutResponseAsync(new OpenIdConnectResponse { Error = @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = @event.ErrorDescription, ErrorUri = @event.ErrorUri })); } Logger.LogInformation("The logout request was successfully extracted " + "from the HTTP request: {Request}.", request); var context = new ValidateLogoutRequestContext(Context, Scheme, Options, request); await Provider.ValidateLogoutRequest(context); if (context.Result != null) { if (context.Result.Handled) { Logger.LogDebug("The logout request was handled in user code."); return(true); } else if (context.Result.Skipped) { Logger.LogDebug("The default logout request handling was skipped from user code."); return(false); } } else if (context.IsRejected) { Logger.LogError("The logout request was rejected with the following error: {Error} ; {Description}", /* Error: */ context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ context.ErrorDescription); return(await SendLogoutResponseAsync(new OpenIdConnectResponse { Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = context.ErrorDescription, ErrorUri = context.ErrorUri })); } // Store the validated post_logout_redirect_uri as a request property. request.SetProperty(OpenIdConnectConstants.Properties.PostLogoutRedirectUri, context.PostLogoutRedirectUri); Logger.LogInformation("The logout request was successfully validated."); var notification = new HandleLogoutRequestContext(Context, Scheme, Options, request); await Provider.HandleLogoutRequest(notification); if (notification.Result != null) { if (notification.Result.Handled) { Logger.LogDebug("The logout request was handled in user code."); return(true); } else if (notification.Result.Skipped) { Logger.LogDebug("The default logout request handling was skipped from user code."); return(false); } } else if (notification.IsRejected) { Logger.LogError("The logout request was rejected with the following error: {Error} ; {Description}", /* Error: */ notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ notification.ErrorDescription); return(await SendLogoutResponseAsync(new OpenIdConnectResponse { Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = notification.ErrorDescription, ErrorUri = notification.ErrorUri })); } return(false); }
public async Task Invoke(HttpContext context) { var requestFeatures = context.Features.Get <IHttpRequestFeature>(); if (!_settings.Enabled || !HttpMethods.IsGet(requestFeatures.Method) || (context.Request.GetTypedHeaders().CacheControl?.NoCache ?? false)) { await _next.Invoke(context); return; } var cacheKey = requestFeatures.RawTarget; try { CachedResponse cachedResponse = null; if (context.User.Identity.IsAuthenticated) { cachedResponse = _memoryCache.Get <CachedResponse>($"{cacheKey}_u:{context.User.FindFirst(ClaimTypes.NameIdentifier).Value}"); if (cachedResponse == null) { cachedResponse = _memoryCache.Get <CachedResponse>(cacheKey); if (cachedResponse?.ForAnonymusUsers ?? false) { cachedResponse = null; } } } else { cachedResponse = _memoryCache.Get <CachedResponse>(cacheKey); } if (cachedResponse != null) { await cachedResponse.Apply(context).ConfigureAwait(false); return; } } catch (Exception ex) { _logger.Exception(ex); } var cachedItem = await CaptureResponse(context).ConfigureAwait(false); if (cachedItem != null) { try { if (context.Items.TryGetValue(Consts.IsCachebleKey, out object isCacheble) && (isCacheble is bool) && (bool)isCacheble) { cacheKey = requestFeatures.RawTarget; if (context.Items.TryGetValue(Consts.IsUserSpecificKey, out object isUserSpecific) && (isUserSpecific is bool) && (bool)isUserSpecific) { if (context.User.Identity.IsAuthenticated) { cacheKey = $"{cacheKey}_u:{context.User.FindFirst(ClaimTypes.NameIdentifier).Value}"; } else { cachedItem.ForAnonymusUsers = true; } } var slidingDuration = (context.Items.TryGetValue(Consts.SlidingDurationKey, out object slidingDurationO) && (slidingDurationO is int)) ? TimeSpan.FromSeconds((int)slidingDurationO) : TimeSpan.Zero; var duration = (context.Items.TryGetValue(Consts.DurationKey, out object durationO) && (durationO is int)) ? TimeSpan.FromSeconds((int)durationO) : TimeSpan.FromSeconds(_settings.MaxCacheInSec); var options = new MemoryCacheEntryOptions(); if (slidingDuration > TimeSpan.Zero) { options.SlidingExpiration = slidingDuration; } else { options.AbsoluteExpirationRelativeToNow = duration; } Dictionary <string, string> tagsToApply = null; if (context.Items.TryGetValue(Consts.CachedObjectTags, out var tagsO) && tagsO is Dictionary <string, string> tags) { tagsToApply = tags; } _memoryCache.Add(cacheKey, cachedItem, options, tagsToApply); } } catch (Exception ex) { _logger.Exception(ex); } } }
protected virtual (RangeItemHeaderValue range, long rangeLength, bool serveBody) SetHeadersAndLog( ActionContext context, FileResult result, long?fileLength, bool enableRangeProcessing, DateTimeOffset?lastModified = null, EntityTagHeaderValue etag = null) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } SetContentType(context, result); SetContentDispositionHeader(context, result); var request = context.Context.Request; var httpRequestHeaders = request.GetTypedHeaders(); // Since the 'Last-Modified' and other similar http date headers are rounded down to whole seconds, // round down current file's last modified to whole seconds for correct comparison. if (lastModified.HasValue) { lastModified = RoundDownToWholeSeconds(lastModified.Value); } var preconditionState = GetPreconditionState(httpRequestHeaders, lastModified, etag); var response = context.Context.Response; SetLastModifiedAndEtagHeaders(response, lastModified, etag); // Short circuit if the preconditional headers process to 304 (NotModified) or 412 (PreconditionFailed) if (preconditionState == PreconditionState.NotModified) { response.StatusCode = StatusCodes.Status304NotModified; return(range : null, rangeLength : 0, serveBody : false); } else if (preconditionState == PreconditionState.PreconditionFailed) { response.StatusCode = StatusCodes.Status412PreconditionFailed; return(range : null, rangeLength : 0, serveBody : false); } if (fileLength.HasValue) { // Assuming the request is not a range request, and the response body is not empty, the Content-Length header is set to // the length of the entire file. // If the request is a valid range request, this header is overwritten with the length of the range as part of the // range processing (see method SetContentLength). response.ContentLength = fileLength.Value; // Handle range request if (enableRangeProcessing) { SetAcceptRangeHeader(response); // If the request method is HEAD or GET, PreconditionState is Unspecified or ShouldProcess, and IfRange header is valid, // range should be processed and Range headers should be set if ((HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method)) && (preconditionState == PreconditionState.Unspecified || preconditionState == PreconditionState.ShouldProcess) && (IfRangeValid(httpRequestHeaders, lastModified, etag))) { return(SetRangeHeaders(context, httpRequestHeaders, fileLength.Value)); } } else { Logger.NotEnabledForRangeProcessing(); } } return(range : null, rangeLength : 0, serveBody : !HttpMethods.IsHead(request.Method)); }
public async Task InvokeAsync(HttpContext context, ISchema schema) { if (!context.Request.Path.StartsWithSegments(_settings.Path)) { await _next(context); return; } // Handle requests as per recommendation at http://graphql.org/learn/serving-over-http/ var httpRequest = context.Request; var request = new Request(); if (HttpMethods.IsGet(httpRequest.Method) || (HttpMethods.IsPost(httpRequest.Method) && httpRequest.Query.ContainsKey(Request.QueryKey))) { ExtractGraphQLRequestFromQueryString(httpRequest.Query, request); } else if (HttpMethods.IsPost(httpRequest.Method)) { if (!MediaTypeHeaderValue.TryParse(httpRequest.ContentType, out var mediaTypeHeader)) { await WriteBadRequestResponseAsync(context, _writer, $"Invalid 'Content-Type' header: value '{httpRequest.ContentType}' could not be parsed."); return; } switch (mediaTypeHeader.MediaType) { case "application/json": request = Deserialize <Request>(httpRequest.Body); break; case "application/graphql": request.Query = await ReadAsStringAsync(httpRequest.Body); break; case "application/x-www-form-urlencoded": var formCollection = await httpRequest.ReadFormAsync(); ExtractGraphQLRequestFromPostBody(formCollection, request); break; default: await WriteBadRequestResponseAsync(context, _writer, "Invalid 'Content-Type' header: non-supported media type. See: http://graphql.org/learn/serving-over-http/."); return; } } else { await WriteBadRequestResponseAsync(context, _writer, $"Invalid request method: value '{httpRequest.Method}' could not be handled. See: http://graphql.org/learn/serving-over-http/."); } var start = DateTime.UtcNow; var result = await _executer.ExecuteAsync(_ => { _.Schema = schema; _.Query = request?.Query; _.OperationName = request?.OperationName; _.Inputs = request?.Variables.ToInputs(); _.UserContext = new UserContext { User = context.User }; _.FieldMiddleware.Use <InstrumentFieldsMiddleware>(); _.ValidationRules = DocumentValidator.CoreRules().Concat(_rules); _.EnableMetrics = _settings.EnableMetrics; _.ExposeExceptions = _settings.ExposeExceptions; }); if (_settings.EnableMetrics && result.Errors == null) { result.EnrichWithApolloTracing(start); } if (result.Errors != null) { _logger.LogError("GraphQL execution error(s): {Errors}", result.Errors); } await WriteResponseAsync(context, result); }
protected virtual async Task ProxyRequestAsync(HttpContext context, string serviceHost) { using (var requestMessage = new HttpRequestMessage()) { var requestMethod = context.Request.Method; if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod)) { var streamContent = new StreamContent(context.Request.Body); requestMessage.Content = streamContent; } var xForwardedForHeaderValues = new List <string>(); // copy the request headers foreach (var header in context.Request.Headers) { if (string.Equals(header.Key, XForwardedForHeaderKey, StringComparison.OrdinalIgnoreCase)) { xForwardedForHeaderValues = header.Value.ToList(); continue; } if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray())) { requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); } } // add remote ip address to x-forwarded-for header xForwardedForHeaderValues.Add(context.Connection.RemoteIpAddress.ToString()); requestMessage.Headers.TryAddWithoutValidation(XForwardedForHeaderKey, xForwardedForHeaderValues); var requestUri = new Uri($"{context.Request.Scheme}://{serviceHost}{context.Request.Path}{context.Request.QueryString}"); requestMessage.Headers.Host = requestUri.Authority; requestMessage.RequestUri = requestUri; requestMessage.Method = new HttpMethod(requestMethod); _logger.LogInformation($"ProxyRequestAsync RequestUri: {requestUri}"); var httpClient = _httpClientFactory.CreateClient(nameof(ReverseProxyMiddleware)); using (var responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted)) { context.Response.StatusCode = (int)responseMessage.StatusCode; foreach (var header in responseMessage.Headers) { context.Response.Headers[header.Key] = header.Value.ToArray(); } foreach (var header in responseMessage.Content.Headers) { context.Response.Headers[header.Key] = header.Value.ToArray(); } // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response. context.Response.Headers.Remove("transfer-encoding"); await responseMessage.Content.CopyToAsync(context.Response.Body); } } }
private bool IsRequestingAsyncApiIndex(HttpRequest request) { return(HttpMethods.IsGet(request.Method) && string.Equals(request.Path, "/asyncapi/index.html", StringComparison.OrdinalIgnoreCase)); }
private bool IsRequestingAsyncApiSchema(HttpRequest request) { return(HttpMethods.IsGet(request.Method) && string.Equals(request.Path, _asyncApiOptionsAccessor.Value.Route, StringComparison.OrdinalIgnoreCase)); }