예제 #1
0
        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;
            }
        }
예제 #2
0
 private bool handleErrorIfOnUnhandledExceptionPage(string errorEvent, Exception exception)
 {
     if (getErrorPage(MetaLogicFactory.CreateUnhandledExceptionErrorPageInfo()).GetUrl() != RequestState.Url)
     {
         return(false);
     }
     RequestState.SetError(errorEvent + " during a request for the unhandled exception page" + (exception != null ? ":" : "."), exception);
     set500StatusCode("Unhandled Exception Page Error");
     return(true);
 }
예제 #3
0
        private bool handleErrorIfOnHandledErrorPage(string errorEvent, Exception exception)
        {
            var handledErrorPages = new List <PageInfo>
            {
                MetaLogicFactory.CreateAccessDeniedErrorPageInfo(false),
                MetaLogicFactory.CreatePageDisabledErrorPageInfo(""),
                MetaLogicFactory.CreatePageNotAvailableErrorPageInfo(false)
            };

            if (handledErrorPages.All(p => getErrorPage(p).GetUrl().Separate("?", false).First() != RequestState.Url.Separate("?", false).First()))
            {
                return(false);
            }
            RequestState.SetError(errorEvent + " during a request for a handled error page" + (exception != null ? ":" : "."), exception);
            transferRequest(getErrorPage(MetaLogicFactory.CreateUnhandledExceptionErrorPageInfo()), true);
            return(true);
        }
예제 #4
0
        private bool handleErrorIfOnHandledErrorPage(string errorEvent, Exception exception)
        {
            var handledErrorPages = new[]
            {
                MetaLogicFactory.CreateAccessDeniedErrorPageInfo(false), MetaLogicFactory.CreatePageDisabledErrorPageInfo(""),
                MetaLogicFactory.CreatePageNotAvailableErrorPageInfo(false)
            }.Select(getErrorPage);
            var requestParameters = new HashSet <string>(getQueryParameters(RequestState.Url));

            if (handledErrorPages.All(
                    page => page.GetUrl().Separate("?", false).First() != RequestState.Url.Separate("?", false).First() ||
                    getQueryParameters(page.GetUrl()).Any(i => !requestParameters.Contains(i))))
            {
                return(false);
            }
            RequestState.SetError(errorEvent + " during a request for a handled error page" + (exception != null ? ":" : "."), exception);
            transferRequest(getErrorPage(MetaLogicFactory.CreateUnhandledExceptionErrorPageInfo()), true);
            return(true);
        }
예제 #5
0
        private void handleEndRequest(object sender, EventArgs e)
        {
            if (!FrameworkInitialized || RequestState == null)
            {
                return;
            }

            ExecuteWithBasicExceptionHandling(
                delegate {
                try {
                    // This 404 condition covers two types of requests:
                    // 1. Requests where we set the status code in handleError
                    // 2. Requests to handlers that set the status code directly instead of throwing exceptions, e.g. the IIS static file handler
                    if (Response.StatusCode == 404 && !handleErrorIfOnErrorPage("A status code of 404 was produced", null))
                    {
                        transferRequest(getErrorPage(MetaLogicFactory.CreatePageNotAvailableErrorPageInfo(!RequestState.HomeUrlRequest)), false);
                    }

                    if (RequestState.TransferRequestPath.Length > 0)
                    {
                        // NOTE: If we transfer to a path with no query string, TransferRequest adds the current query string. Because of this bug we need to make sure all
                        // pages we transfer to have at least one parameter.
                        Server.TransferRequest(RequestState.TransferRequestPath, false, "GET", null);
                    }
                }
                catch {
                    RequestState.RollbackDatabaseTransactions();
                    DataAccessState.Current.ResetCache();
                    throw;
                }
            },
                true,
                true);

            // Do not set a status code since we may have already set one or set a redirect page.
            ExecuteWithBasicExceptionHandling(delegate { RequestState.CleanUp(); }, false, false);
            RequestState = null;
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        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())));
                }
            }
        }