/// <summary>
        /// Evaluates the specified request for the need to switch its security.
        /// </summary>
        /// <param name="request">The request to evaluate.</param>
        /// <param name="settings">The settings to use for evaluation.</param>
        /// <return>
        /// A RequestSecurity value indicating the security the evaluated request should be under.
        /// </return>
        public RequestSecurity Evaluate(HttpRequestBase request, Settings settings)
        {
            // Test if the request matches the configured mode.
            if (!RequestMatchesMode(request, settings.Mode)) {
                Logger.Log("Request does not match mode and should be ignored.");
                return RequestSecurity.Ignore;
            }

            if (settings.IgnoreAjaxRequests && IsAjaxRequest(request)) {
                Logger.Log("Request is an AJAX request that should be ignored.");
                return RequestSecurity.Ignore;
            }

            // Find any matching path setting for the request.
            Logger.Log("Checking for a matching path for this request...");
            string requestPath = request.RawUrl;
            if (!string.IsNullOrEmpty(requestPath)) {
                foreach (PathSetting pathSetting in settings.Paths) {
                    // Get an appropriate path matcher and test the request's path for a match.
                    IPathMatcher matcher = PathMatcherFactory.Create(pathSetting.MatchType);
                    if (matcher.IsMatch(requestPath, pathSetting.Path, pathSetting.IgnoreCase)) {
                        Logger.LogFormat("Matching path found; security is {0}.", pathSetting.Security);
                        return pathSetting.Security;
                    }
                }
            }

            // Any non-matching request should default to Insecure.
            Logger.Log("No matching path found; security defaults to Insecure.");
            return RequestSecurity.Insecure;
        }
        public void Enrich(HttpResponseBase response, HttpRequestBase request, ISecurityEvaluator securityEvaluator, Settings settings)
        {
            if (!securityEvaluator.IsSecureConnection(request, settings) || !settings.EnableHsts) {
                return;
            }

            // Add the needed STS header.
            response.AddHeader("Strict-Transport-Security", string.Format("max-age={0:f0}", settings.HstsMaxAge));
        }
        /// <summary>
        /// Determines whether or not a request is an AJAX request.
        /// </summary>
        /// <param name="request">The request to test.</param>
        /// <returns>
        ///   <c>true</c> if the specified request is an AJAX request; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsAjaxRequest(HttpRequestBase request)
        {
            if (request == null) {
                throw new ArgumentNullException("request");
            }

            // * Avoid accessing HttpRequestBase.Form at this point. There is a weird issue that forces the Framework to ignore the target of a
            //   post-back if you access the Form collection during a request to the root of the application (i.e. http://mydomain.com/).
            //   This issue does not appear if an actual page name is used in the URL (i.e. http://mydomain.com/Default.aspx).
            return (request.QueryString != null && request.QueryString[XRequestedWithHeaderKey] == AjaxRequestHeaderValue ||
                    request.Headers != null && request.Headers[XRequestedWithHeaderKey] == AjaxRequestHeaderValue);
        }
        /// <summary>
        /// Gets any URI for the specified request that ensures it is being accessed by the proper protocol, if a match is found in the settings.
        /// </summary>
        /// <param name="request">The request to ensure proper access for.</param>
        /// <param name="response">The response to use if a redirection or other output is necessary.</param>
        /// <param name="security">The security setting to match.</param>
        /// <param name="settings">The settings used for any redirection.</param>
        /// <returns>A URL that ensures the requested resources matches the specified security; or null if the current request already does.</returns>
        public string GetUriForMatchedSecurityRequest(HttpRequestBase request, HttpResponseBase response, RequestSecurity security, Settings settings)
        {
            string targetUrl = null;

            // Evaluate the request's security.
            Logger.Log("Determining if the connection is secure.");
            bool isSecureConnection = _securityEvaluator.IsSecureConnection(request, settings);

            if (security == RequestSecurity.Secure && !isSecureConnection ||
                security == RequestSecurity.Insecure && isSecureConnection) {
                Logger.Log("Calculating the target URI to switch to.");

                // Determine the target protocol and get any base target URL from the settings.
                string targetProtocolScheme;
                string baseTargetUrl;
                if (security == RequestSecurity.Secure) {
                    targetProtocolScheme = Uri.UriSchemeHttps;
                    baseTargetUrl = settings.BaseSecureUri;
                } else {
                    targetProtocolScheme = Uri.UriSchemeHttp;
                    baseTargetUrl = settings.BaseInsecureUri;
                }

                if (string.IsNullOrEmpty(baseTargetUrl)) {
                    // If there is no base target URI, just switch the protocol scheme of the current request's URI.
                    // * Account for cookie-less sessions by applying the application modifier.
                    targetUrl = targetProtocolScheme + Uri.SchemeDelimiter + request.Url.Authority + response.ApplyAppPathModifier(request.RawUrl);
                } else {
                    // Build the appropriate URI based on the specified target URL.
                    var uri = new StringBuilder(baseTargetUrl);

                    // - Use the full request path, but remove any sub-application path.
                    uri.Append(request.RawUrl);
                    if (request.ApplicationPath.Length > 1) {
                        uri.Remove(baseTargetUrl.Length, request.ApplicationPath.Length);
                    }

                    // Normalize the URI.
                    uri.Replace("//", "/", baseTargetUrl.Length - 1, uri.Length - baseTargetUrl.Length);

                    targetUrl = uri.ToString();
                }
            }

            return targetUrl;
        }
 /// <summary>
 /// Determines whether the specified request is over a secure connection.
 /// </summary>
 /// <param name="request">The request to test.</param>
 /// <param name="settings">The settings used for determining a secure connection.</param>
 /// <returns>
 ///   <c>true</c> if the specified request is over a secure connection; otherwise, <c>false</c>.
 /// </returns>
 public bool IsSecureConnection(HttpRequestBase request, Settings settings)
 {
     bool isPortMatch = (request.Url.Port == settings.SecurityPort);
     Logger.LogFormat("Checking if the request port matches the SecurityPort; {0}.", isPortMatch ? "it does" : "no match");
     return isPortMatch;
 }
 /// <summary>
 /// Determines whether the specified request is over a secure connection.
 /// </summary>
 /// <param name="request">The request to test.</param>
 /// <param name="settings">The settings used for determining a secure connection.</param>
 /// <returns>
 ///   <c>true</c> if the specified request is over a secure connection; otherwise, <c>false</c>.
 /// </returns>
 public bool IsSecureConnection(HttpRequestBase request, Settings settings)
 {
     Logger.LogFormat("Connection {0} secure.", request.IsSecureConnection ? "is" : "is not");
     return request.IsSecureConnection;
 }
 /// <summary>
 /// Determines whether the specified request is over a secure connection.
 /// </summary>
 /// <param name="request">The request to test.</param>
 /// <param name="settings">The settings used for determining a secure connection.</param>
 /// <returns>
 ///   <c>true</c> if the specified request is over a secure connection; otherwise, <c>false</c>.
 /// </returns>
 public abstract bool IsSecureConnection(HttpRequestBase request, Settings settings);
        /// <summary>
        /// Tests the given request to see if it matches the specified mode.
        /// </summary>
        /// <param name="request">An HttpRequestBase to test.</param>
        /// <param name="mode">The Mode used for the test.</param>
        /// <returns>
        ///		Returns true if the request matches the mode as follows:
        ///		<list type="disc">
        ///			<item>If mode is On.</item>
        ///			<item>If mode is set to RemoteOnly and the request is from a computer other than the server.</item>
        ///			<item>If mode is set to LocalOnly and the request is from the server.</item>
        ///		</list>
        ///	</returns>
        private static bool RequestMatchesMode(HttpRequestBase request, Mode mode)
        {
            switch (mode) {
                case Mode.On:
                    return true;

                case Mode.RemoteOnly:
                    return !request.IsLocal;

                case Mode.LocalOnly:
                    return request.IsLocal;

                default:
                    return false;
            }
        }