public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { // (1) Make sure the API caller have provided a tenantId, and extract it int tenantId; try { tenantId = _tenantIdAccessor.GetTenantId(); } catch (MultitenancyException ex) { // If the tenant Id is not provided cut the pipeline short and return a Bad Request 400 context.Result = new BadRequestObjectResult(ex.Message); return; } // (2) Make sure the user is a member of this tenant UserInfo userInfo = await _appRepo.GetUserInfoAsync(); if (userInfo.UserId == null) { // If there is no user cut the pipeline short and return a Forbidden 403 context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden); // This indicates to the client to discard all cached information about this // company since the user is no longer a member of it context.HttpContext.Response.Headers.Add("x-settings-version", Constants.Unauthorized); context.HttpContext.Response.Headers.Add("x-definitions-version", Constants.Unauthorized); context.HttpContext.Response.Headers.Add("x-permissions-version", Constants.Unauthorized); context.HttpContext.Response.Headers.Add("x-user-settings-version", Constants.Unauthorized); return; } var userId = userInfo.UserId.Value; var externalId = _externalUserAccessor.GetUserId(); var externalEmail = _externalUserAccessor.GetUserEmail(); // (3) If the user exists but new, set the External Id if (userInfo.ExternalId == null) { // Update external Id in this tenant database await _appRepo.Users__SetExternalIdByUserId(userId, externalId); // Update external Id in the central Admin database too (To avoid an awkward situation // where a user exists on the tenant but not on the Admin db, if they change their email in between) var adminRepo = _serviceProvider.GetRequiredService <AdminRepository>(); await adminRepo.GlobalUsers__SetExternalIdByEmail(externalEmail, externalId); } else if (userInfo.ExternalId != externalId) { // Note: there is the edge case of identity providers who allow email recycling. I.e. we can get the same email twice with // two different external Ids. This issue is so unlikely to naturally occur and cause problems here that we are not going // to handle it for now. It can however happen artificually if the application is re-configured to a new identity provider, // or if someone messed with the database directly, but again out of scope for now. context.Result = new BadRequestObjectResult("The sign-in email already exists but with a different external Id"); return; } // (4) If the user's email address has changed at the identity server, update it locally else if (userInfo.Email != externalEmail) { await _appRepo.Users__SetEmailByUserId(userId, externalEmail); } // (5) Set the tenant info in the context, to make accessible for model metadata providers var tenantInfo = await _appRepo.GetTenantInfoAsync(); _tenantInfoAccessor.SetInfo(tenantId, tenantInfo); // (6) Ensure the freshness of the definitions and settings caches { var databaseVersion = tenantInfo.DefinitionsVersion; var serverVersion = _definitionsCache.GetDefinitionsIfCached(tenantId)?.Version; if (serverVersion == null || serverVersion != databaseVersion) { // Update the cache var definitions = await DefinitionsController.LoadDefinitionsForClient(_appRepo); _definitionsCache.SetDefinitions(tenantId, definitions); } } { var databaseVersion = tenantInfo.SettingsVersion; var serverVersion = _settingsCache.GetSettingsIfCached(tenantId)?.Version; if (serverVersion == null || serverVersion != databaseVersion) { // Update the cache var settings = await SettingsController.LoadSettingsForClient(_appRepo); _settingsCache.SetSettings(tenantId, settings); } } // (7) If any version headers are supplied: examine their freshness { // Permissions var clientVersion = context.HttpContext.Request.Headers["X-Permissions-Version"].FirstOrDefault(); if (!string.IsNullOrWhiteSpace(clientVersion)) { var databaseVersion = userInfo.PermissionsVersion; context.HttpContext.Response.Headers.Add("x-permissions-version", clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale); } } { // User Settings var clientVersion = context.HttpContext.Request.Headers["X-User-Settings-Version"].FirstOrDefault(); if (!string.IsNullOrWhiteSpace(clientVersion)) { var databaseVersion = userInfo.UserSettingsVersion; context.HttpContext.Response.Headers.Add("x-user-settings-version", clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale); } } { // Definitions var clientVersion = context.HttpContext.Request.Headers["X-Definitions-Version"].FirstOrDefault(); if (!string.IsNullOrWhiteSpace(clientVersion)) { var databaseVersion = tenantInfo.DefinitionsVersion; context.HttpContext.Response.Headers.Add("x-definitions-version", clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale); } } { // Settings var clientVersion = context.HttpContext.Request.Headers["X-Settings-Version"].FirstOrDefault(); if (!string.IsNullOrWhiteSpace(clientVersion)) { var databaseVersion = tenantInfo.SettingsVersion; context.HttpContext.Response.Headers.Add("x-settings-version", clientVersion == databaseVersion ? Constants.Fresh : Constants.Stale); } } // Call the Action itself await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (!await _authService.AuthorizeAsync(context.HttpContext.User, context.ActionDescriptor.ToString(), _requiredPermission)) { context.Result = new ChallengeResult(); context.HttpContext.Response.StatusCode = Convert.ToInt16(HttpStatusCode.Unauthorized); return; } await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { await next(); }
} /* End of Function - ReaderWriterLockFilterAsyncAttribute */ /************************ Methods ****************************************/ /*----------------------- OnResourceExecutionAsync ----------------------*/ /// <summary> /// Wraps the execution with a lock, if out of date will get a writer lock /// otherwise will continue through as a reader /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <remarks> /// This method does not use the async keyword, due to `await` to possibly /// change the thread we are executing on, causing problems with the locks. /// </remarks> public Task OnResourceExecutionAsync( ResourceExecutingContext context, ResourceExecutionDelegate next) { if (null == context) { throw new ArgumentNullException( nameof(context), "A valid context must be provided"); } if (null == next) { throw new ArgumentNullException( nameof(next), "A valid execution delegate must be provided"); } return(Task.Factory.StartNew(() => { Logger.LogTrace("Enter main execution task"); // Grab the timeout value from configuration var timeout = GetWaitTimeSpan(); Logger.LogInformation($"Got a timeout from configuration: {timeout}"); Logger.LogInformation($" In milliseconds: {timeout.TotalMilliseconds}"); // Get a lock object associated with the resource key var lockObj = Manager.GetFor(GetResourceKey(context)); string auth = null; // Will look in the headers for an "Authentication" record var headers = context.HttpContext.Request.Headers; // If so, then we will get the value to use (assuming the first is // good enough, since there should just be one) if (headers.ContainsKey("Authorization")) { auth = headers["Authorization"].First(); } var repo = GitContext.RemoteFactory.Build(context.RouteData.Values["destinationServer"].ToString(), context.RouteData.Values["repositoryOwner"].ToString(), context.RouteData.Values["repository"].ToString(), auth); var local = GitContext.LocalFactory.Build(repo, Configuration); Logger.LogInformation("Grabbing reader lock"); lockObj.AcquireReaderLock(timeout); if (!IsRepositoryUpToDate(local)) { Logger.LogInformation("Repository out of date, asking for writer lock"); //lockObj.AcquireWriterLock(timeout); lockObj.UpgradeToWriterLock(timeout); } // end of if - out-of-date try { // Check to see if we are out of date, if we are then // upgrade to writer, to update our local values if (lockObj.IsWriterLockHeld) { // If still out of date, then we will update the local one, // because we are the instance stuck with the work if (!IsRepositoryUpToDate(local)) { Logger.LogInformation("We are responsible for updating the local repository"); GitContext.UpdateLocalAsync(local).Wait(); Logger.LogInformation("Local repository updated!"); } lockObj.DowngradeFromWriterLock(); } // end of if - repository is up-to-date Logger.LogInformation("Calling through to the next step in the pipeline"); // Allow the rest of the pipeline to continue next().Wait(); Logger.LogInformation("Next action has finished, continue to release locks"); } // end of try - to execute the job finally { // If we were holding the writer lock, release it // first if (lockObj.IsWriterLockHeld) { Logger.LogInformation("Releasing the writer lock"); lockObj.ReleaseWriterLock(); Logger.LogInformation("Writer lock released"); } // end of if - writer lock is held else { Logger.LogInformation("Releasing the reader lock"); lockObj.ReleaseReaderLock(); } // end of else - reader lock } // end of finally lockObj = null; Logger.LogTrace("Exit main execution task"); })); // end of task } /* End of Function - OnResourceExecutionAsync */
public Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { throw new NotImplementedException(); }
/// <summary> /// OnResourceExecutionAsync /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { var action = context.ActionDescriptor; var haveAdminAuth = action.FilterDescriptors.Any(o => o.Filter.ToString() == typeof(GeneralAdminAuthorizeAttribute).ToString()); if (haveAdminAuth) { var authSuccess = context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues authValue); if (!authSuccess) { var result = new ApiResult() { Code = 401, Message = "Authorization不能为空" }; context.Result = new JsonResult(result); return; } var token = authValue.ToString().Trim(); var jwtArr = token.Split("||"); if (jwtArr.Length < 2) { var result = new ApiResult() { Code = 401, Message = "Authorization不符合规范" }; context.Result = new JsonResult(result); return; } var account = jwtArr[0]; var password = jwtArr[1]; if (!await _tokenService.VerifyAdminAsync(account, password)) { var result = new ApiResult() { Code = 401, Message = "Admin授权验证未通过" }; context.Result = new JsonResult(result); return; } } else { var haveAuthor = action.FilterDescriptors.Any(o => o.Filter.ToString() == typeof(GeneralAuthorizeAttribute).ToString()); var haveAllowAny = action.FilterDescriptors.Any(o => o.Filter.ToString() == typeof(AllowAnonymousFilter).ToString()); bool needAuth = false; if (_configuration["needAuth"] != null && (bool.TryParse(_configuration["needAuth"], out needAuth)) && !haveAllowAny && haveAuthor) { if (needAuth) { var authSuccess = context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues authValue); if (!authSuccess) { var result = new ApiResult() { Code = 401, Message = "Authorization不能为空" }; context.Result = new JsonResult(result); return; } if (!authValue.ToString()?.Contains("Bearer") ?? false) { var result = new ApiResult() { Code = 401, Message = "Authorization不符合规范" }; context.Result = new JsonResult(result); return; } var token = authValue.ToString().Substring("Bearer ".Length).Trim(); var jwtArr = token.Split('.'); //var header = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(jwtArr[0])); Dictionary <string, object> payLoad; try { payLoad = JsonConvert.DeserializeObject <Dictionary <string, object> >(Base64UrlEncoder.Decode(jwtArr[1])); } catch (Exception) { var result = new ApiResult() { Code = 401, Message = "Authorization不符合规范" }; context.Result = new JsonResult(result); return; } var account = payLoad["sid"]?.ToString(); if (account == null) { var result = new ApiResult() { Code = 401, Message = "未找到sid" }; context.Result = new JsonResult(result); return; } if (!await _tokenService.VerifyTokenAsync(account, token)) { var result = new ApiResult() { Code = 401, Message = "授权验证未通过" }; context.Result = new JsonResult(result); return; } } } } await next(); }
/// <inheritdoc /> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } var routeData = context.RouteData; var request = context.HttpContext.Request; if (routeData.TryGetWebHookReceiverName(out var receiverName) && IsApplicable(receiverName) && HttpMethods.IsPost(request.Method)) { // 1. Confirm a secure connection. var errorResult = EnsureSecureConnection(ReceiverName, context.HttpContext.Request); if (errorResult != null) { context.Result = errorResult; return; } // 2. Get the expected hash from the signature headers. var header = GetRequestHeader(request, PusherConstants.SignatureHeaderName, out errorResult); if (errorResult != null) { context.Result = errorResult; return; } var expectedHash = GetDecodedHash(header, PusherConstants.SignatureHeaderName, out errorResult); if (errorResult != null) { context.Result = errorResult; return; } // 3. Get the configured secret key. var secretKeys = GetSecretKeys(ReceiverName, routeData); if (!secretKeys.Exists()) { context.Result = new NotFoundResult(); return; } var applicationKey = GetRequestHeader(request, PusherConstants.SignatureKeyHeaderName, out errorResult); if (errorResult != null) { context.Result = errorResult; return; } var secretKey = secretKeys[applicationKey]; if (secretKey == null || secretKey.Length < PusherConstants.SecretKeyMinLength || secretKey.Length > PusherConstants.SecretKeyMaxLength) { Logger.LogError( 0, "The '{HeaderName}' header value of '{HeaderValue}' is not recognized as a valid " + "application key. Please ensure the correct application key / secret key pairs have " + "been configured.", PusherConstants.SignatureKeyHeaderName, applicationKey); var message = string.Format( CultureInfo.CurrentCulture, Resources.SignatureFilter_SecretNotFound, PusherConstants.SignatureKeyHeaderName, applicationKey); context.Result = new BadRequestObjectResult(message); return; } var secret = Encoding.UTF8.GetBytes(secretKey); // 4. Get the actual hash of the request body. var actualHash = await GetRequestBodyHash_SHA256(request, secret); // 5. Verify that the actual hash matches the expected hash. if (!SecretEqual(expectedHash, actualHash)) { // Log about the issue and short-circuit remainder of the pipeline. errorResult = CreateBadSignatureResult(receiverName, PusherConstants.SignatureHeaderName); context.Result = errorResult; return; } } await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { string menuUrl = this.requiredPermissions.UrlAndButtonType.Url; // 判断用户权限 if (string.IsNullOrEmpty(menuUrl)) { // 区域判断 var area = context.RouteData.Values["area"]; var controller = context.RouteData.Values["controller"]; var action = context.RouteData.Values["action"]; if (area == null) { menuUrl = "_" + controller + "_" + action; } else { menuUrl = "_" + area + "_" + controller + "_" + action; } } menuUrl = menuUrl.Trim(); if (context.HttpContext.User.HasPermission(menuUrl)) { await next().ConfigureAwait(false); } else { string innermsg = PermissionStatusCodes.Status2Unauthorized + V; context.Result = new ContentResult() { Content = innermsg, }; await context.Result.ExecuteResultAsync(context).ConfigureAwait(false); } }
public Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { context.Result = new NotFoundResult(); return(Task.CompletedTask); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (!context.HttpContext.User.Identity.IsAuthenticated || !context.Filters.ExistsAuthorizeAttribute()) { await next(); return; } var method = context.GetMethod(); var authorization = context.GetAuthorization(); var onClientValidate = _options.OnClientValidate; var clientValidate = ClientValidate.None; if (context.Filters.OfType <BasicAuthorizeAttribute>().Any()) { clientValidate = context.Filters.OfType <BasicAuthorizeAttribute>().First().ClientValidate; } if (clientValidate != ClientValidate.None) { onClientValidate = (clientValidate == ClientValidate.On); } if (onClientValidate) { var clientId = context.HttpContext.User.GetClientId(); if (_options.ClientId != clientId) { if (string.IsNullOrWhiteSpace(_options.Authority)) { throw new ArgumentNullException(nameof(_options.Authority)); } var grantInfoResponse = await _serviceAuthorizeHttpClient.GetGrantInfo( method, authorization); if (grantInfoResponse.Code != 0) { context.Result = new BadRequestObjectResult(ActionObject.Ok(grantInfoResponse.Code, grantInfoResponse.Message)); return; } var grantInfo = grantInfoResponse.Data; if (grantInfo == null) { context.Result = new BadRequestObjectResult(ActionObject.Ok(-1, "获取授权信息失败")); return; } if (!grantInfo.Granted) { context.Result = new ObjectResult(ActionObject.Ok(-1, "该资源需要appid拥有授权")) { StatusCode = 403 }; return; } } } await next(); }
private async Task TaskParmIfPost(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (!context.HttpContext.Request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase)) { await next(); return; } bool requestModelValid = true; bool bodyRewrited = false; var initialBody = context.HttpContext.Request.Body; try { //context.HttpContext.Request.EnableRewind(); using (StreamReader sr = new StreamReader(context.HttpContext.Request.Body)) { string content = await sr.ReadToEndAsync(); if (!string.IsNullOrWhiteSpace(content)) { var m = JsonConvert.DeserializeObject <JObject>(content); if (!m.TryGetValue("param", out JToken param)) { requestModelValid = false; } else { //取ApiRequestModel的Param重新写入request body MemoryStream ms = new MemoryStream(JsonConvert.SerializeObject(param).ToBytes()); context.HttpContext.Request.Body = ms; context.HttpContext.Request.ContentLength = ms.Length; bodyRewrited = true; } } } } catch (Exception ex) { _logger.LogError(ex, "解析Post参数出错"); requestModelValid = false; } finally { if (!bodyRewrited) { context.HttpContext.Request.Body = initialBody; } } if (!requestModelValid) { context.Result = new JsonResult(new ApiResponseModel() { Ret = -1, ErrCode = "", ErrStr = "Illegal request" }); } else { await next(); } }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (_action == TestResourceFilterAction.ThrowException) { throw new NotImplementedException("This filter should not have been run!"); } else if (_action == TestResourceFilterAction.Passthrough) { ResourceExecutedContext = await next(); } else { context.Result = new TestActionResult(); } }
/// <inheritdoc /> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } var request = context.HttpContext.Request; if (HttpMethods.IsPost(request.Method)) { // 1. Confirm a secure connection. var errorResult = EnsureSecureConnection(ReceiverName, context.HttpContext.Request); if (errorResult != null) { context.Result = errorResult; return; } // 2. Get the expected hash from the signature header. var header = GetRequestHeader(request, GitHubConstants.SignatureHeaderName, out errorResult); if (errorResult != null) { context.Result = errorResult; return; } var values = new TrimmingTokenizer(header, PairSeparators); var enumerator = values.GetEnumerator(); enumerator.MoveNext(); var headerKey = enumerator.Current; if (values.Count != 2 || !StringSegment.Equals( headerKey, GitHubConstants.SignatureHeaderKey, StringComparison.OrdinalIgnoreCase)) { Logger.LogWarning( 0, $"Invalid '{GitHubConstants.SignatureHeaderName}' header value. Expecting a value of " + $"'{GitHubConstants.SignatureHeaderKey}=<value>'."); var message = string.Format( CultureInfo.CurrentCulture, Resources.SignatureFilter_BadHeaderValue, GitHubConstants.SignatureHeaderName, GitHubConstants.SignatureHeaderKey, "<value>"); errorResult = new BadRequestObjectResult(message); context.Result = errorResult; return; } enumerator.MoveNext(); var headerValue = enumerator.Current.Value; var expectedHash = FromHex(headerValue, GitHubConstants.SignatureHeaderName); if (expectedHash == null) { context.Result = CreateBadHexEncodingResult(GitHubConstants.SignatureHeaderKey); return; } // 3. Get the configured secret key. var secretKey = GetSecretKey( ReceiverName, context.RouteData, GitHubConstants.SecretKeyMinLength, GitHubConstants.SecretKeyMaxLength); if (secretKey == null) { context.Result = new NotFoundResult(); return; } var secret = Encoding.UTF8.GetBytes(secretKey); // 4. Get the actual hash of the request body. var actualHash = await ComputeRequestBodySha1HashAsync(request, secret); // 5. Verify that the actual hash matches the expected hash. if (!SecretEqual(expectedHash, actualHash)) { // Log about the issue and short-circuit remainder of the pipeline. errorResult = CreateBadSignatureResult(GitHubConstants.SignatureHeaderName); context.Result = errorResult; return; } } await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { string menuUrl = _requiredPermissions.UrlAndButtonType.Url; //判断用户权限 if (string.IsNullOrEmpty(menuUrl)) { //区域判断 string area = context.RouteData.Values["area"].ToString(); if (string.IsNullOrEmpty(area)) { menuUrl = "/" + context.RouteData.Values["controller"] + "/" + context.RouteData.Values["action"]; } else { menuUrl = "/" + area + "/" + context.RouteData.Values["controller"] + "/" + context.RouteData.Values["action"]; } } menuUrl = menuUrl.Trim().ToLower(); var dbpermission = await _permissionStorage.GetPermissionAsync(); var menu = dbpermission.Menus.FirstOrDefault(m => m.MenuUrl != null && m.MenuUrl.Trim().ToLower() == menuUrl); if (menu != null)//地址存在 { if (_requiredPermissions.UrlAndButtonType.ButtonType == default(byte)) { await next(); } else { byte buttonType = (byte)_requiredPermissions.UrlAndButtonType.ButtonType; if (menu.MenuButton.Select(m => m.ButtonType).Contains(buttonType))//拥有操作权限 { await next(); } else { //没有操作权限 if (_requiredPermissions.UrlAndButtonType.IsPage) { context.Result = new RedirectResult("/error/noauth"); } else { context.Result = new ContentResult() { Content = PermissionStatusCodes.Status2Unauthorized.ToString() }; } await context.Result.ExecuteResultAsync(context); } } } else { //没有操作权限 if (_requiredPermissions.UrlAndButtonType.IsPage) { context.Result = new RedirectResult("/error/noauth"); } else { context.Result = new ContentResult() { Content = PermissionStatusCodes.Status2Unauthorized.ToString() }; } await context.Result.ExecuteResultAsync(context); } }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { var httpContext = context.HttpContext; try { var userId = _userContextProvider.GetId(httpContext.User, ClaimType.UserId); var activeId = httpContext.Session.GetInt32(SessionKey.ActiveUserId); if (userId != activeId) { httpContext.Session.SetInt32(SessionKey.ActiveUserId, userId); var user = await _userService.GetDetails(userId); var questionnaireId = await _questionnaireService .GetRequiredQuestionnaire(user.Id, user.Age); if (questionnaireId.HasValue) { httpContext.Session.SetInt32(SessionKey.PendingQuestionnaire, questionnaireId.Value); } else { httpContext.Session.Remove(SessionKey.PendingQuestionnaire); } } } catch (Exception ex) { _logger.LogTrace($"Attempted Mission Control access while not logged in: {ex.Message}"); } if (httpContext.User.HasClaim(ClaimType.Permission, nameof(Permission.ReadAllMail))) { try { httpContext.Items[ItemKey.UnreadCount] = await _mailService.GetAdminUnreadCountAsync(); } catch (Exception ex) { _logger.LogError("Error getting admin mail unread count: {Message}", ex.Message); } } if (httpContext.User.HasClaim(ClaimType.Permission, nameof(Permission.ViewPerformerDetails))) { var settings = await _performerSchedulingService.GetSettingsAsync(); var schedulingStage = _performerSchedulingService .GetSchedulingStage(settings); if (schedulingStage != PsSchedulingStage.Unavailable) { httpContext.Items.Add(ItemKey.ShowPerformerScheduling, true); } } var siteId = httpContext.Session.GetInt32(SessionKey.SiteId); if (siteId != null && await _siteLookupService.GetSiteSettingBoolAsync((int)siteId, SiteSettingKey.VendorCodes.ShowPackingSlip)) { httpContext.Items.Add(ItemKey.ShowPackingSlips, true); } await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { var user = await _userManager.GetUserAsync(context.HttpContext.User); if (user?.HaveReadRules == true) { await next(); } else { context.Result = new RedirectToActionResult("Index", "Rules", null); } }
/// <inheritdoc /> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } // 1. Confirm we were reached using HTTPS. var request = context.HttpContext.Request; var errorResult = EnsureSecureConnection(ReceiverName, request); if (errorResult != null) { context.Result = errorResult; return; } // 2. Get XElement from the request body. var data = await _requestReader.ReadBodyAsync <XElement>(context); if (data == null) { var modelState = context.ModelState; if (modelState.IsValid) { // ReadAsXmlAsync returns null when model state is valid only when other filters will log and // return errors about the same conditions. Let those filters run. await next(); } else { context.Result = new BadRequestObjectResult(modelState); } return; } // 3. Ensure the organization ID exists and matches the expected value. var organizationIds = ObjectPathUtilities.GetStringValues(data, SalesforceConstants.OrganizationIdPath); if (StringValues.IsNullOrEmpty(organizationIds)) { Logger.LogWarning( 0, $"The HTTP request body did not contain a required '{SalesforceConstants.OrganizationIdPath}' " + "element."); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyOrganization_MissingValue, SalesforceConstants.OrganizationIdPath); context.Result = await _resultCreator.GetFailedResultAsync(message); return; } var routeData = context.RouteData; var secret = GetSecretKey( ReceiverName, routeData, SalesforceConstants.SecretKeyMinLength, SalesforceConstants.SecretKeyMaxLength); var organizationId = GetShortOrganizationId(organizationIds[0]); var secretKey = GetShortOrganizationId(secret); if (!SecretEqual(organizationId, secretKey)) { Logger.LogWarning( 1, $"The '{SalesforceConstants.OrganizationIdPath}' value provided in the HTTP request body did " + "not match the expected value."); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyOrganization_BadValue, SalesforceConstants.OrganizationIdPath); context.Result = await _resultCreator.GetFailedResultAsync(message); return; } // 4. Get the event name. var eventNames = ObjectPathUtilities.GetStringValues(data, SalesforceConstants.EventNamePath); if (StringValues.IsNullOrEmpty(eventNames)) { Logger.LogWarning( 2, $"The HTTP request body did not contain a required '{SalesforceConstants.EventNamePath}' " + "element."); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyOrganization_MissingValue, SalesforceConstants.EventNamePath); context.Result = await _resultCreator.GetFailedResultAsync(message); return; } // 5. Success. Provide event name for model binding. routeData.SetWebHookEventNames(eventNames); await next(); }
/// <inheritdoc /> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } // 1. Confirm we were reached using HTTPS. var request = context.HttpContext.Request; var errorResult = EnsureSecureConnection(ReceiverName, request); if (errorResult != null) { context.Result = errorResult; return; } // 2. Get IFormCollection from the request body. var data = await _requestReader.ReadAsFormDataAsync(context); if (data == null) { // ReadAsFormDataAsync returns null only when other filters will log and return errors about the same // conditions. Let those filters run. await next(); return; } // 3. Ensure the token exists and matches the expected value. string token = data[SlackConstants.TokenRequestFieldName]; if (string.IsNullOrEmpty(token)) { Logger.LogWarning( 0, $"The HTTP request body did not contain a required '{SlackConstants.TokenRequestFieldName}' " + "property."); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyToken_MissingValue, SlackConstants.TokenRequestFieldName); context.Result = new BadRequestObjectResult(message); return; } var routeData = context.RouteData; var secretKey = GetSecretKey( ReceiverName, routeData, SlackConstants.SecretKeyMinLength, SlackConstants.SecretKeyMaxLength); if (!SecretEqual(token, secretKey)) { Logger.LogWarning( 1, $"The '{SlackConstants.TokenRequestFieldName}' value provided in the HTTP request body did not " + "match the expected value."); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyToken_BadValue, SlackConstants.TokenRequestFieldName); context.Result = new BadRequestObjectResult(message); return; } // 4. Get the event name and subtext. string eventName = data[SlackConstants.TriggerRequestFieldName]; if (eventName != null) { // Trigger was supplied. Remove the trigger word to get subtext. string text = data[SlackConstants.TextRequestFieldName]; routeData.Values[SlackConstants.SubtextRequestKeyName] = GetSubtext(eventName, text); } else if ((eventName = data[SlackConstants.CommandRequestFieldName]) != null) { // Command was supplied. No need to set subtext. } else { // Trigger and command were omitted. Set subtext to the full text (if any). eventName = data[SlackConstants.TextRequestFieldName]; routeData.Values[SlackConstants.SubtextRequestKeyName] = eventName; } if (string.IsNullOrEmpty(eventName)) { Logger.LogWarning( 2, $"The HTTP request body did not contain a required '{SlackConstants.TriggerRequestFieldName}', " + $"'{SlackConstants.CommandRequestFieldName}', or '{SlackConstants.TextRequestFieldName}' " + "property."); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyToken_MissingValues, SlackConstants.TriggerRequestFieldName, SlackConstants.CommandRequestFieldName, SlackConstants.TextRequestFieldName); context.Result = new BadRequestObjectResult(message); return; } // 5. Success. Provide event name for model binding. routeData.Values[WebHookConstants.EventKeyName] = eventName; await next(); }
/// <summary> /// Validate authorization /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { AuthorizationResult result = await _authService.AuthorizeAsync(context.HttpContext.User, context.ActionDescriptor.DisplayName, _requiredPermissions); if (!result.Succeeded) { context.Result = new UnauthorizedResult(); HttpResponse response = context.HttpContext.Response; string responseText = "<HTML><HEAD><META http-equiv=\"Content - Type\" content=\"text / html; charset = windows - 1252\"></HEAD><BODY></BODY></HTML>"; byte[] data = Encoding.UTF8.GetBytes(responseText); response.StatusCode = 403; // forbidden response.Body.Write(data, 0, data.Length); await response.Body.FlushAsync(); } await next(); }
/// <inheritdoc /> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } var routeData = context.RouteData; var request = context.HttpContext.Request; if (routeData.TryGetWebHookReceiverName(out var receiverName) && IsApplicable(receiverName) && HttpMethods.IsPost(request.Method)) { // 1. Confirm a secure connection. var errorResult = EnsureSecureConnection(ReceiverName, context.HttpContext.Request); if (errorResult != null) { context.Result = errorResult; return; } // 2. Get the expected hash from the signature header. var header = GetRequestHeader(request, DropboxConstants.SignatureHeaderName, out errorResult); if (errorResult != null) { context.Result = errorResult; return; } var expectedHash = GetDecodedHash(header, DropboxConstants.SignatureHeaderName, out errorResult); if (errorResult != null) { context.Result = errorResult; return; } // 3. Get the configured secret key. var secretKey = GetSecretKey( ReceiverName, routeData, DropboxConstants.SecretKeyMinLength, DropboxConstants.SecretKeyMaxLength); if (secretKey == null) { context.Result = new NotFoundResult(); return; } var secret = Encoding.UTF8.GetBytes(secretKey); // 4. Get the actual hash of the request body. var actualHash = await GetRequestBodyHash_SHA256(request, secret); // 5. Verify that the actual hash matches the expected hash. if (!SecretEqual(expectedHash, actualHash)) { // Log about the issue and short-circuit remainder of the pipeline. errorResult = CreateBadSignatureResult(receiverName, DropboxConstants.SignatureHeaderName); context.Result = errorResult; return; } } await next(); }
public Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { //To do : before the action executes return(next()); //To do : after the action executes }
public async Task OnResourceExecutionAsync(ResourceExecutingContext precontext, ResourceExecutionDelegate next) { //Eagerly reading the whole body just in case to avoid "Cannot access a disposed object" //TODO: Make it more eficiently when https://github.com/aspnet/AspNetCore/issues/14396 var body = ReadAllBody(precontext.HttpContext); var context = await next(); if (context.Exception != null) { if (!AvoidLogException.Contains(context.Exception.GetType())) { var req = context.HttpContext.Request; var connFeature = context.HttpContext.Features.Get <IHttpConnectionFeature>(); var exLog = context.Exception.LogException(e => { e.ActionName = Try(100, () => (context.ActionDescriptor as ControllerActionDescriptor)?.ActionName); e.ControllerName = Try(100, () => (context.ActionDescriptor as ControllerActionDescriptor)?.ControllerName); e.UserAgent = Try(300, () => req.Headers["User-Agent"].FirstOrDefault()); e.RequestUrl = Try(int.MaxValue, () => req.GetDisplayUrl()); e.UrlReferer = Try(int.MaxValue, () => req.Headers["Referer"].ToString()); e.UserHostAddress = Try(100, () => connFeature.RemoteIpAddress?.ToString()); e.UserHostName = Try(100, () => connFeature.RemoteIpAddress == null ? null : Dns.GetHostEntry(connFeature.RemoteIpAddress).HostName); e.User = (UserHolder.Current ?? (IUserEntity?)context.HttpContext.Items[SignumAuthenticationFilter.Signum_User_Key])?.ToLite() ?? e.User; e.QueryString = new BigStringEmbedded(Try(int.MaxValue, () => req.QueryString.ToString())); e.Form = new BigStringEmbedded(Try(int.MaxValue, () => Encoding.UTF8.GetString(body))); e.Session = new BigStringEmbedded(); }); if (ExpectsJsonResult(context)) { var statusCode = GetStatus(context.Exception.GetType()); var error = CustomHttpErrorFactory(context.Exception); var ci = TranslateExceptionMessage(context.Exception) ? SignumCultureSelectorFilter.GetCurrentCulture?.Invoke(precontext) : null; using (ci == null ? null : CultureInfoUtils.ChangeBothCultures(ci)) { var response = context.HttpContext.Response; response.StatusCode = (int)statusCode; response.ContentType = "application/json"; await response.WriteAsync(JsonSerializer.Serialize(error, SignumServer.JsonSerializerOptions)); context.ExceptionHandled = true; } } } } }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { string menuUrl = _requiredPermissions.UrlAndButtonType.Url; //判断用户权限 if (string.IsNullOrEmpty(menuUrl)) { //区域判断 var area = context.RouteData.Values["area"]; var controller = context.RouteData.Values["controller"]; var action = context.RouteData.Values["action"]; if (area == null) { menuUrl = "_" + controller + "_" + action; } else { menuUrl = "_" + area + "_" + controller + "_" + action;; } } menuUrl = menuUrl.Trim(); //var authorities = context.HttpContext.User.Claims.Where(p => p.Type.Equals( "authorities")).Select(o => o.Value).ToList(); if (context.HttpContext.User.HasPermission(menuUrl)) { await next(); } else { context.Result = new ContentResult() { Content = PermissionStatusCodes.Status2Unauthorized.ToString() }; await context.Result.ExecuteResultAsync(context); } }
/// <inheritdoc /> public virtual async Task OnResourceExecutionAsync( ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } var routeData = context.RouteData; var bodyTypeMetadata = _bodyTypeMetadata; var eventFromBodyMetadata = _eventFromBodyMetadata; if (bodyTypeMetadata == null) { if (!routeData.TryGetWebHookReceiverName(out var receiverName)) { await next(); return; } bodyTypeMetadata = _metadataProvider.GetBodyTypeMetadata(receiverName); eventFromBodyMetadata = _metadataProvider.GetEventFromBodyMetadata(receiverName); if (eventFromBodyMetadata == null) { await next(); return; } } // No need to double-check the request's Content-Type. WebHookVerifyBodyTypeFilter would have // short-circuited the request if unsupported. StringValues eventNames; switch (bodyTypeMetadata.BodyType) { case WebHookBodyType.Form: var form = await _requestReader.ReadAsFormDataAsync(context); if (form == null) { // ReadAsFormDataAsync returns null only when other filters will log and return errors // about the same conditions. Let those filters run. await next(); return; } eventNames = form[eventFromBodyMetadata.BodyPropertyPath]; break; case WebHookBodyType.Json: var json = await _requestReader.ReadBodyAsync <JContainer>(context); if (json == null) { var modelState = context.ModelState; if (modelState.IsValid) { // ReadAsJContainerAsync returns null when model state is valid only when other filters // will log and return errors about the same conditions. Let those filters run. await next(); } else { context.Result = new BadRequestObjectResult(modelState); } return; } eventNames = ObjectPathUtilities.GetStringValues(json, eventFromBodyMetadata.BodyPropertyPath); break; case WebHookBodyType.Xml: var xml = await _requestReader.ReadBodyAsync <XElement>(context); if (xml == null) { var modelState = context.ModelState; if (modelState.IsValid) { // ReadAsXmlAsync returns null when model state is valid only when other filters will log // and return errors about the same conditions. Let those filters run. await next(); } else { context.Result = new BadRequestObjectResult(modelState); } return; } eventNames = ObjectPathUtilities.GetStringValues(xml, eventFromBodyMetadata.BodyPropertyPath); break; default: var message = string.Format( CultureInfo.CurrentCulture, Resources.General_InvalidEnumValue, typeof(WebHookBodyType), bodyTypeMetadata.BodyType); throw new InvalidOperationException(message); } if (StringValues.IsNullOrEmpty(eventNames) && !eventFromBodyMetadata.AllowMissing) { var receiverName = bodyTypeMetadata.ReceiverName; _logger.LogWarning( 0, "A '{ReceiverName}' WebHook request must contain a match for '{BodyPropertyPath}' in the HTTP " + "request entity body indicating the type or types of event.", receiverName, eventFromBodyMetadata.BodyPropertyPath); var message = string.Format( CultureInfo.CurrentCulture, Resources.EventMapper_NoBodyProperty, receiverName, eventFromBodyMetadata.BodyPropertyPath); context.Result = new BadRequestObjectResult(message); return; } routeData.SetWebHookEventNames(eventNames); await next(); }
/// <inheritdoc /> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } var request = context.HttpContext.Request; if (HttpMethods.IsPost(request.Method)) { // 1. Confirm a secure connection. var errorResult = EnsureSecureConnection(ReceiverName, context.HttpContext.Request); if (errorResult != null) { context.Result = errorResult; return; } // 2. Get the expected hash from the signature header. var header = GetRequestHeader(request, TrelloConstants.SignatureHeaderName, out errorResult); if (errorResult != null) { context.Result = errorResult; return; } var expectedHash = FromBase64(header, TrelloConstants.SignatureHeaderName); if (expectedHash == null) { context.Result = CreateBadBase64EncodingResult(TrelloConstants.SignatureHeaderName); return; } // 3. Get the configured secret key. var secretKey = GetSecretKey( ReceiverName, context.RouteData, TrelloConstants.SecretKeyMinLength, TrelloConstants.SecretKeyMaxLength); if (secretKey == null) { context.Result = new NotFoundResult(); return; } var secret = Encoding.UTF8.GetBytes(secretKey); var suffix = Encoding.UTF8.GetBytes(request.GetEncodedUrl()); // 4. Get the actual hash of the request body. var actualHash = await ComputeRequestBodySha1HashAsync(request, secret, prefix : null, suffix : suffix); // 5. Verify that the actual hash matches the expected hash. if (!SecretEqual(expectedHash, actualHash)) { // Log about the issue and short-circuit remainder of the pipeline. errorResult = CreateBadSignatureResult(TrelloConstants.SignatureHeaderName); context.Result = errorResult; return; } } await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { // do something before // Read response from cache var callerID = $"[{context.HttpContext.Request.Method}]{context.HttpContext.Request.Path}{context.HttpContext.Request.QueryString}"; Logger.LogInformation("Cache request query: {context.HttpContext.Request.Path}", context.HttpContext.Request.Path); var c = await FsManager.GetFSCacheEntryAsync( callerID, "application/json", // TODO: move this to attribute? CacheLifeSpan ); if (c != null) // I have a response from cache, let's perform a shortcut { context.Result = c; Logger.LogInformation("Cache entry was loaded from cache for Request: {context.HttpContext.Request.Path}, Lifespan = {CacheLifeSpan}", context.HttpContext.Request.Path, CacheLifeSpan); //GetThreadInfo(); return; } else { Logger.LogInformation("No cache entry found in cache for Request: {context.HttpContext.Request.Path}, Lifespan = {CacheLifeSpan}", context.HttpContext.Request.Path, CacheLifeSpan); var resultContext = await next(); // let's execute full controller - some API action to be executed if (c == null) // nothing was in cache and so storing results to cache { if (!resultContext.Canceled && StatusCodes.Contains(resultContext.HttpContext.Response.StatusCode)) { //only if JSON result and sucessfull call // Write response to cache await FsManager.AddFSCacheEntryAsync( callerID, // request resultContext.Result, //result resultContext.HttpContext.Response.ContentType //content type ); Logger.LogInformation("New entry to CACHE for Request: {context.HttpContext.Request.Path}", context.HttpContext.Request.Path); } } } }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { // (1) Make sure the user has an active user AdminUserInfo userInfo = await _adminRepo.GetAdminUserInfoAsync(); if (userInfo.UserId == null) { // If there is no user cut the pipeline short and return a Forbidden 403 context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden); // This indicates to the client to discard all cached information about this // company since the user is no longer a member of it context.HttpContext.Response.Headers.Add("x-settings-version", Constants.Unauthorized); context.HttpContext.Response.Headers.Add("x-permissions-version", Constants.Unauthorized); context.HttpContext.Response.Headers.Add("x-user-settings-version", Constants.Unauthorized); return; } var userId = userInfo.UserId.Value; var externalId = _externalUserAccessor.GetUserId(); var externalEmail = _externalUserAccessor.GetUserEmail(); // (3) If the user exists but new, set the External Id if (userInfo.ExternalId == null) { using var trx = ControllerUtilities.CreateTransaction(); await _adminRepo.AdminUsers__SetExternalIdByUserId(userId, externalId); await _adminRepo.GlobalUsers__SetExternalIdByUserId(userId, externalId); trx.Complete(); } else if (userInfo.ExternalId != externalId) { // Note: we will assume that no identity provider can provider the same email twice with // two different external Ids, i.e. that no provider allows email recycling, so we won't handle this case now // It can only happen if the application is re-configured to a new identity provider, or if someone messed with // database directly context.Result = new BadRequestObjectResult("The sign-in email already exists but with a different external Id"); return; } // (4) If the user's email address has changed at the identity server, update it locally else if (userInfo.Email != externalEmail) { using var trx = ControllerUtilities.CreateTransaction(); await _adminRepo.AdminUsers__SetEmailByUserId(userId, externalEmail); await _adminRepo.GlobalUsers__SetEmailByUserId(userId, externalEmail); trx.Complete(); } // (5) If any version headers are supplied: examine their freshness // TODO: same pattern as TenantApiAttribute // Finally call the Action itself await next(); }
/// <inheritdoc /> public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } var routeData = context.RouteData; if (!routeData.TryGetWebHookReceiverName(out var receiverName) || !IsApplicable(receiverName)) { await next(); return; } // 1. Confirm we were reached using HTTPS. var request = context.HttpContext.Request; var errorResult = EnsureSecureConnection(receiverName, request); if (errorResult != null) { context.Result = errorResult; return; } // 2. Get XElement and SalesforceNotifications from the request body. var data = await ReadAsXmlAsync(context); if (data == null) { var modelState = context.ModelState; if (modelState.IsValid) { // ReadAsXmlAsync returns null when model state is valid only when other filters will log and // return errors about the same conditions. Let those filters run. await next(); } else { context.Result = WebHookResultUtilities.CreateErrorResult(modelState); } return; } // Got a valid XML body. From this point on, all responses should contain XML. var notifications = new SalesforceNotifications(data); // 3. Ensure that the organization ID exists and matches the expected value. var organizationId = GetShortOrganizationId(notifications.OrganizationId); if (string.IsNullOrEmpty(organizationId)) { Logger.LogError( 0, "The HTTP request body did not contain a required '{PropertyName}' property.", nameof(notifications.OrganizationId)); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyOrganization_MissingValue, nameof(notifications.OrganizationId)); context.Result = await _resultCreator.GetFailedResultAsync(message); return; } var secret = GetSecretKey( SalesforceConstants.ConfigurationName, routeData, SalesforceConstants.SecretKeyMinLength, SalesforceConstants.SecretKeyMaxLength); var secretKey = GetShortOrganizationId(secret); if (!SecretEqual(organizationId, secretKey)) { Logger.LogError( 1, "The '{PropertyName}' value provided in the HTTP request body did not match the expected value.", nameof(notifications.OrganizationId)); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyOrganization_BadValue, nameof(notifications.OrganizationId)); context.Result = await _resultCreator.GetFailedResultAsync(message); return; } // 4. Get the event name. var eventName = notifications.ActionId; if (string.IsNullOrEmpty(eventName)) { Logger.LogError( 2, "The HTTP request body did not contain a required '{PropertyName}' property.", nameof(notifications.ActionId)); var message = string.Format( CultureInfo.CurrentCulture, Resources.VerifyOrganization_MissingValue, nameof(notifications.ActionId)); context.Result = await _resultCreator.GetFailedResultAsync(message); return; } // 5. Success. Provide event name for model binding. routeData.Values[WebHookConstants.EventKeyName] = eventName; await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { var userId = context.HttpContext.User.GetUserId(); var portfolioId = context.HttpContext.User.GetPortfolioId(); var accountId = TryParse(context.HttpContext.Request.Path.Value.Split('/').LastOrDefault()) ?? TryParse(context.HttpContext.Request.Query["entityId"]); if (!await userId.OwnsAccountAsync(portfolioId, accountId.GetValueOrDefault(), _context)) { context.Result = new ChallengeResult(); } else { await next(); } }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { if (!_securitySettings.EnableHoneypotProtection) { await next(); } var isBot = _honeypotProtector.IsBot(); if (!isBot) { await next(); } _logger.Warn("Honeypot detected a bot and rejected the request."); var redirectUrl = _webHelper.GetCurrentPageUrl(true); context.Result = new RedirectResult(redirectUrl); }