示例#1
0
        private static void OnBeginRequest(object sender, EventArgs e)
        {
            _lastRequestDateTime = DateTime.UtcNow;

            var httpContext = ((HttpApplication)sender).Context;
            var httpRequest = new HttpRequestWrapper(httpContext.Request);

            // HACK: This is abusing the trace module
            // Disallow GET requests from CSM extensions bridge
            // Except if owner or coadmin (aka legacy or non-rbac) authorization
            if (!String.IsNullOrEmpty(httpRequest.Headers["X-MS-VIA-EXTENSIONS-ROUTE"]) &&
                httpRequest.HttpMethod.Equals(HttpMethod.Get.Method, StringComparison.OrdinalIgnoreCase) &&
                !String.Equals(httpRequest.Headers["X-MS-CLIENT-AUTHORIZATION-SOURCE"], "legacy", StringComparison.OrdinalIgnoreCase))
            {
                httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                httpContext.Response.End();
            }

            // HACK: If it's a Razor extension, add a dummy extension to prevent WebPages for blocking it,
            // as we need to serve those files via /vfs
            // Yes, this is an abuse of the trace module
            if (httpRequest.FilePath.IndexOf("vfs/", StringComparison.OrdinalIgnoreCase) >= 0 &&
                (httpRequest.FilePath.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase) ||
                 httpRequest.FilePath.EndsWith(".vbhtml", StringComparison.OrdinalIgnoreCase)))
            {
                httpContext.Server.TransferRequest(httpRequest.FilePath + Constants.DummyRazorExtension, preserveForm: true);
                return;
            }

            // Always trace the startup request.
            ITracer tracer = TraceStartup(httpContext);

            // Skip certain paths
            if (TraceExtensions.ShouldSkipRequest(httpRequest))
            {
                TraceServices.RemoveRequestTracer(httpContext);
                return;
            }

            tracer = tracer ?? TraceServices.CreateRequestTracer(httpContext);

            if (tracer == null || tracer.TraceLevel <= TraceLevel.Off)
            {
                return;
            }

            var attribs = GetTraceAttributes(httpContext);

            AddTraceLevel(httpContext, attribs);

            foreach (string key in httpContext.Request.Headers)
            {
                if (!key.Equals("Authorization", StringComparison.OrdinalIgnoreCase) &&
                    !key.Equals("X-MS-CLIENT-PRINCIPAL-NAME", StringComparison.OrdinalIgnoreCase))
                {
                    attribs[key] = httpContext.Request.Headers[key];
                }
            }

            httpContext.Items[_stepKey] = tracer.Step(XmlTracer.IncomingRequestTrace, attribs);
        }
示例#2
0
        private static void OnBeginRequest(object sender, EventArgs e)
        {
            _lastRequestDateTime = DateTime.UtcNow;

            var httpContext = ((HttpApplication)sender).Context;
            var httpRequest = new HttpRequestWrapper(httpContext.Request);

            LogBeginRequest(httpContext);

            // HACK: This is abusing the trace module
            // Disallow GET requests from CSM extensions bridge
            // Except if owner or coadmin (aka legacy or non-rbac) authorization
            if (!String.IsNullOrEmpty(httpRequest.Headers["X-MS-VIA-EXTENSIONS-ROUTE"]) &&
                httpRequest.HttpMethod.Equals(HttpMethod.Get.Method, StringComparison.OrdinalIgnoreCase) &&
                !String.Equals(httpRequest.Headers["X-MS-CLIENT-AUTHORIZATION-SOURCE"], "legacy", StringComparison.OrdinalIgnoreCase) &&
                !IsRbacWhiteListPaths(httpRequest.Url.AbsolutePath))
            {
                httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                httpContext.Response.End();
            }

            TryConvertSpecialHeadersToEnvironmentVariable(httpRequest);

            // HACK: If it's a Razor extension, add a dummy extension to prevent WebPages for blocking it,
            // as we need to serve those files via /vfs
            // Yes, this is an abuse of the trace module
            if (httpRequest.FilePath.IndexOf("vfs/", StringComparison.OrdinalIgnoreCase) >= 0 &&
                (httpRequest.FilePath.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase) ||
                 httpRequest.FilePath.EndsWith(".vbhtml", StringComparison.OrdinalIgnoreCase)))
            {
                httpContext.Server.TransferRequest(httpRequest.FilePath + Constants.DummyRazorExtension, preserveForm: true);
                return;
            }

            // Always trace the startup request.
            ITracer tracer = TraceStartup(httpContext);

            // Trace heartbeat periodically
            TraceHeartbeat();

            // Skip certain paths
            if (TraceExtensions.ShouldSkipRequest(httpRequest))
            {
                // this is to prevent Kudu being IFrame (typically where host != referer)
                // to optimize where we return X-FRAME-OPTIONS DENY header, only return when
                // in Azure env, browser non-ajax requests and referer mismatch with host
                // since browser uses referer for other scenarios (such as href, redirect), we may return
                // this header (benign) in such cases.
                if (Kudu.Core.Environment.IsAzureEnvironment() && !TraceExtensions.IsAjaxRequest(httpRequest) && TraceExtensions.MismatchedHostReferer(httpRequest))
                {
                    httpContext.Response.Headers.Add("X-FRAME-OPTIONS", "DENY");
                }

                if (TraceServices.TraceLevel != TraceLevel.Verbose)
                {
                    TraceServices.RemoveRequestTracer(httpContext);

                    // enable just ETW tracer
                    tracer = TraceServices.EnsureETWTracer(httpContext);
                }
            }

            tracer = tracer ?? TraceServices.CreateRequestTracer(httpContext);

            if (tracer == null || tracer.TraceLevel <= TraceLevel.Off)
            {
                return;
            }

            var attribs = GetTraceAttributes(httpContext);

            AddTraceLevel(httpContext, attribs);

            foreach (string key in httpContext.Request.Headers)
            {
                if (!key.Equals("Authorization", StringComparison.OrdinalIgnoreCase) &&
                    !key.Equals("X-MS-CLIENT-PRINCIPAL-NAME", StringComparison.OrdinalIgnoreCase))
                {
                    attribs[key] = httpContext.Request.Headers[key];
                }
                else
                {
                    // for sensitive header, we only trace first 3 characters following by "..."
                    var value = httpContext.Request.Headers[key];
                    attribs[key] = string.IsNullOrEmpty(value) ? value : (value.Substring(0, Math.Min(3, value.Length)) + "...");
                }
            }

            httpContext.Items[_stepKey] = tracer.Step(XmlTracer.IncomingRequestTrace, attribs);
        }
示例#3
0
        private void BeginRequest(HttpContext httpContext)
        {
            var httpRequest = httpContext.Request;

            // If an external deployment ID is injected, inject it back into the response
            string deploymentId = GetExternalDeploymentId(httpRequest);

            if (string.IsNullOrEmpty(deploymentId))
            {
                httpContext.Response.Headers.Add(Constants.ScmDeploymentIdHeader, deploymentId);
            }

            _lastRequestDateTime = DateTime.UtcNow;

            /* CORE TODO missing functionality:
             * Disallow GET requests from CSM extensions bridge
             * Razor dummy extension for vfs
             */

            // Always trace the startup request.
            ITracer tracer = TraceStartup(httpContext);

            LogBeginRequest(httpContext);

            // Trace heartbeat periodically
            TraceHeartbeat();

            TryConvertSpecialHeadersToEnvironmentVariable(httpRequest);

            // Skip certain paths
            if (TraceExtensions.ShouldSkipRequest(httpRequest))
            {
                // this is to prevent Kudu being IFrame (typically where host != referer)
                // to optimize where we return X-FRAME-OPTIONS DENY header, only return when
                // in Azure env, browser non-ajax requests and referer mismatch with host
                // since browser uses referer for other scenarios (such as href, redirect), we may return
                // this header (benign) in such cases.
                if (Environment.IsAzureEnvironment() && !TraceExtensions.IsAjaxRequest(httpRequest) &&
                    TraceExtensions.MismatchedHostReferer(httpRequest))
                {
                    httpContext.Response.Headers.Add("X-FRAME-OPTIONS", "DENY");
                }

                if (TraceServices.TraceLevel != TraceLevel.Verbose)
                {
                    TraceServices.RemoveRequestTracer(httpContext);

                    // enable just ETW tracer
                    tracer = TraceServices.EnsureEtwTracer(httpContext);
                }
            }

            tracer = tracer ?? TraceServices.CreateRequestTracer(httpContext);

            if (tracer == null || tracer.TraceLevel <= TraceLevel.Off)
            {
                return;
            }

            var attribs = GetTraceAttributes(httpContext);

            AddTraceLevel(httpContext, attribs);

            foreach (string key in httpContext.Request.Headers.Keys)
            {
                if (key != null)
                {
                    if (!key.Equals("Authorization", StringComparison.OrdinalIgnoreCase) &&
                        !key.Equals("X-MS-CLIENT-PRINCIPAL-NAME", StringComparison.OrdinalIgnoreCase))
                    {
                        attribs[key] = httpContext.Request.Headers[key];
                    }
                    else
                    {
                        // for sensitive header, we only trace first 3 characters following by "..."
                        var value = httpContext.Request.Headers[key].ToString();
                        attribs[key] = string.IsNullOrEmpty(value)
                            ? value
                            : (value.Substring(0, Math.Min(3, value.Length)) + "...");
                    }
                }
            }

            httpContext.Items[_stepKey] = tracer.Step(XmlTracer.IncomingRequestTrace, attribs);

            AddTrackingHeader(httpContext);
        }
示例#4
0
        public void Init(HttpApplication app)
        {
            app.BeginRequest += (sender, e) =>
            {
                var httpContext = ((HttpApplication)sender).Context;

                // Skip certain paths
                if (httpContext.Request.RawUrl.EndsWith("favicon.ico", StringComparison.OrdinalIgnoreCase) ||
                    httpContext.Request.Path.StartsWith("/dump", StringComparison.OrdinalIgnoreCase) ||
                    httpContext.Request.RawUrl == "/")
                {
                    return;
                }

                // Setup the request for the tracer
                var tracer = TraceServices.CreateRequesTracer(httpContext);

                var attribs = new Dictionary <string, string>
                {
                    { "url", httpContext.Request.RawUrl },
                    { "method", httpContext.Request.HttpMethod },
                    { "type", "request" }
                };

                foreach (string key in httpContext.Request.Headers)
                {
                    attribs["h_" + key] = httpContext.Request.Headers[key];
                }

                if (httpContext.Request.RawUrl.Contains(".git") ||
                    httpContext.Request.RawUrl.EndsWith("/deploy", StringComparison.OrdinalIgnoreCase))
                {
                    // Mark git requests specially
                    attribs.Add("git", "true");
                }

                httpContext.Items[_stepKey] = tracer.Step("Incoming Request", attribs);
            };

            app.Error += (sender, e) =>
            {
                try
                {
                    var httpContext = ((HttpApplication)sender).Context;
                    var tracer      = TraceServices.GetRequestTracer(httpContext);

                    if (tracer == null)
                    {
                        return;
                    }

                    tracer.TraceError(app.Server.GetLastError());
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            };

            app.EndRequest += (sender, e) =>
            {
                var httpContext = ((HttpApplication)sender).Context;
                var tracer      = TraceServices.GetRequestTracer(httpContext);

                if (tracer == null)
                {
                    return;
                }

                var attribs = new Dictionary <string, string>
                {
                    { "type", "response" },
                    { "statusCode", httpContext.Response.StatusCode.ToString() },
                    { "statusText", httpContext.Response.StatusDescription }
                };

                foreach (string key in httpContext.Response.Headers)
                {
                    attribs["h_" + key] = httpContext.Response.Headers[key];
                }

                tracer.Trace("Outgoing response", attribs);

                var requestStep = (IDisposable)httpContext.Items[_stepKey];

                if (requestStep != null)
                {
                    requestStep.Dispose();
                }
            };
        }