private void rewritePathIfShortcutUrl() { var ewfResolvers = new[] { new ShortcutUrlResolver( "ewf", ConnectionSecurity.SecureIfPossible, () => { var page = MetaLogicFactory.CreateBasicTestsPageInfo(); return(page.UserCanAccessResource ? page : null); }), new ShortcutUrlResolver( "ewf/impersonate", ConnectionSecurity.SecureIfPossible, () => { if (!UserManagementStatics.UserManagementEnabled) { return(null); } var page = MetaLogicFactory.CreateSelectUserPageInfo(""); return(page.UserCanAccessResource ? page : null); }) }; var url = GetRequestAppRelativeUrl(Request); foreach (var resolver in ewfResolvers.Concat(GetShortcutUrlResolvers())) { if (resolver.ShortcutUrl.ToLower() != url.ToLower()) { continue; } // Redirect to the same shortcut URL to fix the connection security, normalize the base URL, normalize the shortcut URL casing, or any combination of // these. var canonicalAbsoluteUrl = GetDefaultBaseUrl(resolver.ConnectionSecurity.ShouldBeSecureGivenCurrentRequest(false)) + resolver.ShortcutUrl.PrependDelimiter("/"); if (canonicalAbsoluteUrl != RequestState.Url) { NetTools.Redirect(canonicalAbsoluteUrl); } if (ConfigurationStatics.IsIntermediateInstallation && !RequestState.IntermediateUserExists) { throw new AccessDeniedException(true, null); } var resource = resolver.Function(); if (resource == null) { throw new AccessDeniedException(false, resolver.LogInPageGetter?.Invoke()); } if (resource is ExternalResourceInfo) { NetTools.Redirect(resource.GetUrl()); } HttpContext.Current.RewritePath(getTransferPath(resource), false); break; } }
/// <summary> /// This method will not work properly unless the application is initialized, RequestState is not null, and the authenticated user is available. /// </summary> private void handleError(object sender, EventArgs e) { // The reason we don't write our error page HTML directly to the response, like ASP.NET does, is that this limits the functionality of the error pages // and requires them to be built differently than all other pages. We don't transfer to the error pages either, because application errors can occur at // any time in the ASP.NET life cycle and transferring to a page causes it to immediately execute even if it's not the normal time for this to happen. // Redirecting works, but has the drawback of not being able to send proper HTTP error codes in the response since the redirects themselves require a // particular code. TransferRequest seems to be the only method that gives us everything we want. ExecuteWithBasicExceptionHandling( delegate { // This code should happen first to prevent errors from going to the Windows event log. var exception = Server.GetLastError(); Server.ClearError(); RequestState.RollbackDatabaseTransactions(); DataAccessState.Current.ResetCache(); var errorIsWcf404 = exception.InnerException is System.ServiceModel.EndpointNotFoundException; // We can remove this as soon as requesting a URL with a vertical pipe doesn't blow up our web applications. var argException = exception as ArgumentException; var errorIsBogusPathException = argException != null && argException.Message == "Illegal characters in path."; // In the first part of this condition we check to make sure the base exception is also an HttpException, because we had a problem with WCF wrapping an // important non-HttpException inside an HttpException that somehow had a code of 404. In the second part of the condition (after the OR) we use // InnerException instead of GetBaseException because the ResourceNotAvailableException always has an inner exception that describes the specific // problem that occurred. The third part of the condition handles ResourceNotAvailableExceptions from HTTP handlers such as CssHandler; these are not // wrapped with another exception. if ((exception is HttpException && (exception as HttpException).GetHttpCode() == 404 && exception.GetBaseException() is HttpException) || exception.InnerException is ResourceNotAvailableException || exception is ResourceNotAvailableException || onErrorProneAspNetHandler || errorIsWcf404 || errorIsBogusPathException) { setStatusCode(404); return; } if (!handleErrorIfOnErrorPage("An exception occurred", exception)) { var accessDeniedException = exception.GetBaseException() as AccessDeniedException; var pageDisabledException = exception.GetBaseException() as PageDisabledException; if (accessDeniedException != null) { if (accessDeniedException.CausedByIntermediateUser) { transferRequest(MetaLogicFactory.CreateIntermediateLogInPageInfo(RequestState.Url), true); } else { var userNotYetAuthenticated = RequestState.UserAccessible && AppTools.User == null && UserManagementStatics.UserManagementEnabled; if (userNotYetAuthenticated && !ConfigurationStatics.IsLiveInstallation && !RequestState.ImpersonatorExists) { transferRequest(MetaLogicFactory.CreateSelectUserPageInfo(RequestState.Url), true); } else if (userNotYetAuthenticated && FormsAuthStatics.FormsAuthEnabled) { if (accessDeniedException.LogInPage != null) { // We pass false here to avoid complicating things with ThreadAbortExceptions. Response.Redirect(accessDeniedException.LogInPage.GetUrl(), false); CompleteRequest(); } else { transferRequest(MetaLogicFactory.CreateLogInPageInfo(RequestState.Url), true); } } else { transferRequest(getErrorPage(MetaLogicFactory.CreateAccessDeniedErrorPageInfo(!RequestState.HomeUrlRequest)), true); } } } else if (pageDisabledException != null) { transferRequest(MetaLogicFactory.CreatePageDisabledErrorPageInfo(pageDisabledException.Message), true); } else { RequestState.SetError("", exception); transferRequest(getErrorPage(MetaLogicFactory.CreateUnhandledExceptionErrorPageInfo()), true); } } }, true, true); }
private void rewritePathIfShortcutUrl() { var ewfResolvers = new[] { new ShortcutUrlResolver( "ewf", ConnectionSecurity.SecureIfPossible, () => { var page = MetaLogicFactory.CreateBasicTestsPageInfo(); return(page.UserCanAccessResource ? page : null); }), new ShortcutUrlResolver( "ewf/impersonate", ConnectionSecurity.SecureIfPossible, () => { if (!UserManagementStatics.UserManagementEnabled) { return(null); } var page = MetaLogicFactory.CreateSelectUserPageInfo(""); return(page.UserCanAccessResource ? page : null); }) }; var url = GetRequestAppRelativeUrl(Request); foreach (var resolver in ewfResolvers.Concat(GetShortcutUrlResolvers())) { if (resolver.ShortcutUrl.ToLower() != url.ToLower()) { continue; } // Redirect to the same shortcut URL to fix the connection security, normalize the base URL, normalize the shortcut URL casing, or any combination of // these. var canonicalAbsoluteUrl = GetDefaultBaseUrl(resolver.ConnectionSecurity.ShouldBeSecureGivenCurrentRequest(false)) + resolver.ShortcutUrl.PrependDelimiter("/"); if (canonicalAbsoluteUrl != RequestState.Url) { NetTools.Redirect(canonicalAbsoluteUrl); } if (ConfigurationStatics.IsIntermediateInstallation && !RequestState.IntermediateUserExists) { throw new AccessDeniedException(true, null); } var resource = resolver.Function(); if (resource == null) { throw new AccessDeniedException(false, resolver.LogInPageGetter?.Invoke()); } if (resource is ExternalResourceInfo) { NetTools.Redirect(resource.GetUrl()); } HttpContext.Current.RewritePath(getTransferPath(resource), false); return; } // ACME challenge response; see https://tools.ietf.org/html/rfc8555#section-8.3 var absoluteUrl = new Uri(RequestState.Url); if (absoluteUrl.Scheme == "http" && absoluteUrl.Port == 80 && absoluteUrl.AbsolutePath.StartsWith("/.well-known/acme-challenge/")) { var systemManager = ConfigurationStatics.MachineConfiguration?.SystemManager; if (systemManager != null) { NetTools.Redirect( systemManager.HttpBaseUrl.Replace("https://", "http://") + "/Pages/Public/AcmeChallengeResponse.aspx?Token={0}".FormatWith(HttpUtility.UrlEncode(absoluteUrl.Segments.Last()))); } } }