/// <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 GetUriDoesNotIncludeApplicationPathWithSuppliedBaseUri() { const string BaseRequestUri = "http://www.testsite.com"; const string ApplicationPathRequestUri = "/MySuperDuperApplication"; const string PathRequestUri = ApplicationPathRequestUri + "/Manage/Default.aspx"; const string QueryRequestUri = "?Param=SomeValue"; var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.ApplicationPath).Returns(ApplicationPathRequestUri); mockRequest.SetupGet(req => req.Url).Returns(new Uri(BaseRequestUri + PathRequestUri + QueryRequestUri)); mockRequest.SetupGet(req => req.RawUrl).Returns(PathRequestUri + QueryRequestUri); var mockResponse = new Mock<HttpResponseBase>(); mockResponse.Setup(resp => resp.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(s => s); var settings = new Settings { Mode = Mode.On, BaseSecureUri = "https://secure.someotherwebsite.com/testsite/" }; var evaluator = new HeadersSecurityEvaluator(); var enforcer = new SecurityEnforcer(evaluator); // Act. var targetUrl = enforcer.GetUriForMatchedSecurityRequest(mockRequest.Object, mockResponse.Object, RequestSecurity.Secure, settings); // Assert. Assert.Equal(settings.BaseSecureUri + PathRequestUri.Remove(0, ApplicationPathRequestUri.Length + 1) + QueryRequestUri, targetUrl); }
/// <summary> /// Initializes a module and prepares it to handle requests. /// </summary> /// <param name="context"> /// An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to /// all application objects within an ASP.NET application. /// </param> public void Init(HttpApplication context) { if (context == null) { Logger.Log("No HttpApplication supplied.", Logger.LogLevel.Warn); return; } Logger.Log("Begin module initialization."); // Get the settings for the securitySwitch section. Logger.Log("Getting securitySwitch configuration section.", Logger.LogLevel.Info); _settings = WebConfigurationManager.GetSection("securitySwitch") as Settings; if (_settings == null || _settings.Mode == Mode.Off) { Logger.LogFormat("{0}; module not activated.", Logger.LogLevel.Info, _settings == null ? "No settings provided" : "Mode is Off"); return; } Logger.Log("Creating RequestProcessor."); _requestProcessor = new RequestProcessor(_settings); // Hook the application's AcquireRequestState event. // * This ensures that the session ID is available for cookie-less session processing. // * I would rather hook sooner into the pipeline, but... // * It just is not possible (that I know of) to get the original URL requested when cookie-less sessions are used. // The Framework uses RewritePath when the HttpContext is created to strip the Session ID from the request's // Path/Url. The rewritten URL is actually stored in an internal field of HttpRequest; short of reflection, // it's not obtainable. // WARNING: Do not access the Form collection of the HttpRequest object to avoid weird issues with post-backs from the application root. Logger.Log("Adding handler for the application's 'AcquireRequestState' event."); context.AcquireRequestState += ProcessRequest; Logger.Log("End module initialization."); }
/// <summary> /// Parses the XML configuration section and returns the settings. /// </summary> /// <param name="parent"> /// The configuration settings in a corresponding parent /// configuration section. /// </param> /// <param name="configContext"> /// An HttpConfigurationContext when Create is called from the ASP.NET /// configuration system. Otherwise, this parameter is reserved and is /// a null reference (Nothing in Visual Basic). /// </param> /// <param name="section"> /// The XmlNode that contains the configuration information from the /// configuration file. Provides direct access to the XML contents of /// the configuration section. /// </param> /// <returns> /// Returns a Settings instance initialized with the /// read configuration settings. /// </returns> public object Create(object parent, object configContext, XmlNode section) { // Create a Settings object for the settings in this section. Settings Settings = new Settings(); // Read the general settings. ReadGeneralSettings(section, Settings); // Traverse the child nodes foreach (XmlNode Node in section.ChildNodes) { if (Node.NodeType == System.Xml.XmlNodeType.Comment) // Skip comment nodes (thanks to dcbrower on CodeProject for pointing this out). continue; else if (Node.Name.ToLower() == "directory") // This is a directory path node. Settings.Directories.Add(ReadDirectoryItem(Node)); else if (Node.Name.ToLower() == "file") // This is a file path node. Settings.Files.Add(ReadFileItem(Node)); else // Throw an exception for this unrecognized node. throw new SecuritySwitchSectionException(string.Format("'{0}' is not an acceptable setting.", Node.Name), Node); } // Return the settings. return Settings; }
/// <summary> /// Determines the unsecure page that should be requested if a redirect occurs. /// </summary> /// <param name="settings">The Settings to use in determining.</param> /// <param name="ignoreCurrentProtocol"> /// A flag indicating whether or not to ingore the current protocol when determining. /// </param> /// <returns>A string containing the absolute URL of the unsecure page to redirect to.</returns> /// <exception cref="ArgumentNullException"></exception> public static string DetermineUnsecurePage(Settings settings, bool ignoreCurrentProtocol) { if (settings == null) throw new ArgumentNullException("settings"); string Result = null; HttpRequest Request = HttpContext.Current.Request; // Is this request secure? string RequestPath = Request.Url.AbsoluteUri; if (ignoreCurrentProtocol || RequestPath.StartsWith(SecureProtocolPrefix)) { // Is there a different URI to redirect to? if (string.IsNullOrEmpty(settings.UnencryptedUri)) // Replace the protocol of the requested URL with "http". // * Account for cookieless sessions by applying the application modifier. Result = string.Concat( UnsecureProtocolPrefix, Request.Url.Authority, HttpContext.Current.Response.ApplyAppPathModifier(Request.Path), Request.Url.Query ); else // Build the URL with the "http" protocol. Result = BuildUrl(false, settings.MaintainPath, settings.EncryptedUri, settings.UnencryptedUri); } return Result; }
public void GetUriRequestReturnsNullIfOffloadedHeaderSecurityAlreadyMatchesSpecifiedSecurity() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.IsSecureConnection).Returns(false); var mockResponse = new Mock<HttpResponseBase>(); var settings = new Settings(); var evaluator = new HeadersSecurityEvaluator(); var enforcer = new SecurityEnforcer(evaluator); // Act. mockRequest.SetupGet(req => req.Headers).Returns(new NameValueCollection { { "SSL_REQUEST", "on" }, { "OTHER_HEADER", "some-value" } }); settings.OffloadedSecurityHeaders = "SSL_REQUEST="; var targetUrlForAlreadySecuredRequest = enforcer.GetUriForMatchedSecurityRequest(mockRequest.Object, mockResponse.Object, RequestSecurity.Secure, settings); mockRequest.SetupGet(req => req.Headers).Returns(new NameValueCollection { { "OTHER_HEADER", "some-value" } }); var targetUrlForAlreadyInsecureRequest = enforcer.GetUriForMatchedSecurityRequest(mockRequest.Object, mockResponse.Object, RequestSecurity.Insecure, settings); // Assert. Assert.Null(targetUrlForAlreadySecuredRequest); Assert.Null(targetUrlForAlreadyInsecureRequest); }
public void ProcessRequest(HttpContextBase context) { var settings = new Settings(); var requestProcessor = new RequestProcessor(settings); requestProcessor.Process(context, EvaluatorCallback); }
/// <summary> /// Evaluates a given request against specified settings for the type of security action required /// to fulfill the request properly. /// </summary> /// <param name="request">The request to evaluate.</param> /// <param name="settings">The settings to evaluate against.</param> /// <param name="forceEvaluation"> /// A flag indicating whether or not to force evaluation, despite the mode set. /// </param> /// <returns>A SecurityType value for the appropriate action.</returns> public static SecurityType Evaluate(HttpRequest request, Settings settings, bool forceEvaluation) { // Initialize the result to Ignore. SecurityType Result = SecurityType.Ignore; // Determine if this request should be ignored based on the settings' Mode. bool MustEvaluateRequest = (forceEvaluation || RequestMatchesMode(request, settings.Mode)); DebugHelper.Output(MustEvaluateRequest ? "Evaluating request..." : "Evaluation of request skipped."); if (MustEvaluateRequest) { // Make sure the request shouldn't be ignored as a HTTP handler. if (settings.IgnoreHandlers == IgnoreHandlers.BuiltIn && !IsBuiltInHandlerRequest(request) || settings.IgnoreHandlers == IgnoreHandlers.WithStandardExtensions && !IsStandardHandlerRequest(request) || settings.IgnoreHandlers == IgnoreHandlers.None) { // Get the relative file path of the current request from the application root. string RelativeFilePath = HttpUtility.UrlDecode(request.Url.AbsolutePath).Remove(0, request.ApplicationPath.Length).ToLower(CultureInfo.CurrentCulture); if (RelativeFilePath.StartsWith("/")) // Remove any leading "/". RelativeFilePath = RelativeFilePath.Substring(1); // Get the relative directory of the current request by removing the last segment of the RelativeFilePath. string RelativeDirectory = string.Empty; int i = RelativeFilePath.LastIndexOf('/'); if (i >= 0) RelativeDirectory = RelativeFilePath.Substring(0, i); // Determine if there is a matching file path for the current request. i = settings.Files.IndexOf(RelativeFilePath); if (i >= 0) { Result = settings.Files[i].Secure; DebugHelper.Output("Request matches file: {0} - {1}.", settings.Files[i].Secure, settings.Files[i].Path); } else { // Try to find a matching directory path. int j = -1; i = 0; while (i < settings.Directories.Count) { // Try to match the beginning of the directory if recursion is allowed (partial match). if ((settings.Directories[i].Recurse && RelativeDirectory.StartsWith(settings.Directories[i].Path, StringComparison.CurrentCultureIgnoreCase) || RelativeDirectory.Equals(settings.Directories[i].Path, StringComparison.CurrentCultureIgnoreCase)) && (j == -1 || settings.Directories[i].Path.Length > settings.Directories[j].Path.Length)) // First or longer partial match found (deepest recursion is the best match). j = i; i++; } if (j > -1) { // Indicate a match for a partially matched directory allowing recursion. Result = settings.Directories[j].Secure; DebugHelper.Output("Request matches directory: {0} - {1}.", settings.Directories[j].Secure, settings.Directories[j].Path); } else { // No match indicates an insecure result. Result = SecurityType.Insecure; DebugHelper.Output("Request does not match anything."); } } } } return Result; }
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 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 override bool IsSecureConnection(HttpRequestBase request, Settings settings) { Logger.Log("Checking for any header that matches one from OffloadedSecurityServerVariables..."); // Parse the expected security variables and check for each against the server variables. NameValueCollection expectedSecurityVariables = HttpUtility.ParseQueryString(settings.OffloadedSecurityServerVariables); bool isSecure = FindAnyNameValueMatch(expectedSecurityVariables, request.ServerVariables); Logger.Log(isSecure ? "Server variable match found; connection is secure." : "No match found; connection is presumed not secure."); return isSecure; }
public void IsSecureConnectionReturnsTrueIfRequestIndicatesSecurity() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.IsSecureConnection).Returns(true); var settings = new Settings(); var evaluator = new StandardSecurityEvaluator(); // Act. var result = evaluator.IsSecureConnection(mockRequest.Object, settings); // Assert. Assert.True(result); }
/// <summary> /// Evaluates a given request against specified settings for the type of security action required /// to fulfill the request properly. /// </summary> /// <param name="request">The request to evaluate.</param> /// <param name="settings">The settings to evaluate against.</param> /// <param name="forceEvaluation"> /// A flag indicating whether or not to force evaluation, despite the mode set. /// </param> /// <returns>A SecurityType value for the appropriate action.</returns> public static SecurityType Evaluate(HttpRequest request, Settings settings, bool forceEvaluation) { // Initialize the result to Ignore. SecurityType Result = SecurityType.Ignore; // Determine if this request should be ignored based on the settings' Mode. if (forceEvaluation || RequestMatchesMode(request, settings.Mode)) { // Get the relative file path of the current request from the application root. string RelativeFilePath = HttpUtility.UrlDecode(request.Url.AbsolutePath).Remove(0, request.ApplicationPath.Length).ToLower(); if (RelativeFilePath.StartsWith("/")) // Remove any leading "/". RelativeFilePath = RelativeFilePath.Substring(1); // Get the relative directory of the current request by removing the last segment of the RelativeFilePath. string RelativeDirectory = string.Empty; int i = RelativeFilePath.LastIndexOf('/'); if (i >= 0) RelativeDirectory = RelativeFilePath.Substring(0, i).ToLower(); // Determine if there is a matching file path for the current request. i = settings.Files.IndexOf(RelativeFilePath); if (i >= 0) Result = settings.Files[i].Secure; else { // Try to find a matching directory path. int j = -1; i = 0; while (i < settings.Directories.Count) { // Try to match the beginning of the directory if recursion is allowed (partial match). if ((settings.Directories[i].Recurse && RelativeDirectory.StartsWith(settings.Directories[i].Path.ToLower()) || RelativeDirectory.Equals(settings.Directories[i].Path.ToLower())) && (j == -1 || settings.Directories[i].Path.Length > settings.Directories[j].Path.Length)) // First or longer partial match found (deepest recursion is the best match). j = i; i++; } if (j > -1) // Indicate a match for a partially matched directory allowing recursion. Result = settings.Directories[j].Secure; else // No match indicates an insecure result. Result = SecurityType.Insecure; } } return Result; }
/// <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; }
public void EnrichDoesntAddHeaderIfRequestNotSecure() { var mockResponse = new Mock<HttpResponseBase>(); var mockRequest = new Mock<HttpRequestBase>(); var mockSecurityEvaluator = new Mock<ISecurityEvaluator>(); var enricher = new HstsResponseEnricher(); var settings = new Settings { EnableHsts = true, HstsMaxAge = 42 }; mockSecurityEvaluator.Setup(e => e.IsSecureConnection(mockRequest.Object, settings)).Returns(false); enricher.Enrich(mockResponse.Object, mockRequest.Object, mockSecurityEvaluator.Object, settings); mockResponse.Verify(resp => resp.AddHeader(It.IsAny<string>(), It.IsAny<string>()), Times.Never()); }
public void CreateReturnsPortSecurityEvaluatorIfSecurityPortHasValue() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); var mockContext = new Mock<HttpContextBase>(); IDictionary items = new Dictionary<object, object>(); mockContext.Setup(c => c.Items).Returns(items); mockContext.SetupGet(c => c.Request).Returns(mockRequest.Object); var settings = new Settings { SecurityPort = 81 }; // Act. var evaluator = SecurityEvaluatorFactory.Instance.Create(mockContext.Object, settings); // Assert. Assert.IsType<PortSecurityEvaluator>(evaluator); }
public void EnrichAddsHstsHeaderWithMaxAge() { const int HstsMaxAge = 42; var mockResponse = new Mock<HttpResponseBase>(); var mockRequest = new Mock<HttpRequestBase>(); var mockSecurityEvaluator = new Mock<ISecurityEvaluator>(); var enricher = new HstsResponseEnricher(); var settings = new Settings { EnableHsts = true, HstsMaxAge = HstsMaxAge }; mockSecurityEvaluator.Setup(e => e.IsSecureConnection(mockRequest.Object, settings)).Returns(true); enricher.Enrich(mockResponse.Object, mockRequest.Object, mockSecurityEvaluator.Object, settings); mockResponse.Verify(resp => resp.AddHeader("Strict-Transport-Security", string.Format("max-age={0:f0}", HstsMaxAge))); }
public void IsSecureConnectionReturnsFalseIfNoHeaderMatchesAnOffloadHeader() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.ServerVariables).Returns(new NameValueCollection { { "SOME_VARIABLE", "some-value" } }); var settings = new Settings { OffloadedSecurityServerVariables = "HTTP_X_FORWARD_PROTOCOL=HTTPS" }; var evaluator = new ServerVariablesSecurityEvaluator(); // Act. var result = evaluator.IsSecureConnection(mockRequest.Object, settings); // Assert. Assert.False(result); }
public void IsSecureConnectionReturnsFalseIfNoHeaderMatchesAnOffloadHeader() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.Headers).Returns(new NameValueCollection { { "SOME_HEADER", "some-value" } }); var settings = new Settings { OffloadedSecurityHeaders = "SSL_REQUEST=on" }; var evaluator = new HeadersSecurityEvaluator(); // Act. var result = evaluator.IsSecureConnection(mockRequest.Object, settings); // Assert. Assert.False(result); }
public void CreateReturnsHeadersSecurityEvaluatorIfSecurityPortNotSpecifiedAndServerVariablesNotExpectedAndHeadersExpectedAndPresent() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.Headers).Returns(new NameValueCollection()); var mockContext = new Mock<HttpContextBase>(); IDictionary items = new Dictionary<object, object>(); mockContext.Setup(c => c.Items).Returns(items); mockContext.SetupGet(c => c.Request).Returns(mockRequest.Object); var settings = new Settings { OffloadedSecurityHeaders = "SSL=" }; // Act. var evaluator = SecurityEvaluatorFactory.Instance.Create(mockContext.Object, settings); // Assert. Assert.IsType<HeadersSecurityEvaluator>(evaluator); }
public void IsSecureConnectionReturnsTrueOnlyIfPortMatchesSecurityPort() { // Arrange. var uri = new Uri("http://www.mysite.com:81/admin/"); var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.Url).Returns(uri); var settings = new Settings(); var evaluator = new PortSecurityEvaluator(); // Act. settings.SecurityPort = 80; var resultWithPortMisMatch = evaluator.IsSecureConnection(mockRequest.Object, settings); settings.SecurityPort = 81; var resultWithPortMatch = evaluator.IsSecureConnection(mockRequest.Object, settings); // Assert. Assert.False(resultWithPortMisMatch); Assert.True(resultWithPortMatch); }
public void IsSecureConnectionReturnsTrueIfHeaderMatchesAnOffloadHeader() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.ServerVariables).Returns(new NameValueCollection { { "SOME_VARIABLE", "some-value" }, { "HTTP_X_FORWARD_PROTOCOL", "HTTPS" } }); var settings = new Settings(); var evaluator = new ServerVariablesSecurityEvaluator(); // Act. settings.OffloadedSecurityServerVariables = "HTTP_X_FORWARD_PROTOCOL=HTTPS"; var resultWithHeaderValueMatch = evaluator.IsSecureConnection(mockRequest.Object, settings); settings.OffloadedSecurityServerVariables = "HTTP_X_FORWARD_PROTOCOL="; var resultWithJustHeaderPresent = evaluator.IsSecureConnection(mockRequest.Object, settings); // Assert. Assert.True(resultWithHeaderValueMatch); Assert.True(resultWithJustHeaderPresent); }
public void IsSecureConnectionReturnsTrueIfHeaderMatchesAnOffloadHeader() { // Arrange. var mockRequest = new Mock<HttpRequestBase>(); mockRequest.SetupGet(req => req.Headers).Returns(new NameValueCollection { { "SOME_HEADER", "some-value" }, { "SSL_REQUEST", "on" } }); var settings = new Settings(); var evaluator = new HeadersSecurityEvaluator(); // Act. settings.OffloadedSecurityHeaders = "SSL_REQUEST=on"; var resultWithHeaderValueMatch = evaluator.IsSecureConnection(mockRequest.Object, settings); settings.OffloadedSecurityHeaders = "SSL_REQUEST="; var resultWithJustHeaderPresent = evaluator.IsSecureConnection(mockRequest.Object, settings); // Assert. Assert.True(resultWithHeaderValueMatch); Assert.True(resultWithJustHeaderPresent); }
/// <summary> /// Reads general settings from the SecuritySwitch section into the given Settings instance. /// </summary> /// <param name="section">The XmlNode to read from.</param> /// <param name="settings">The Settings instance to set.</param> protected void ReadGeneralSettings(XmlNode section, Settings settings) { // Get the mode attribute. if (section.Attributes["mode"] != null) { string ModeValue = section.Attributes["mode"].Value.Trim(); if (Enum.IsDefined(typeof(Mode), ModeValue)) settings.Mode = (Mode)Enum.Parse(typeof(Mode), ModeValue); else throw new SecuritySwitchSectionException("Invalid value for the 'mode' attribute.", section); } // Get the encryptedUri attribute. if (section.Attributes["encryptedUri"] != null) settings.EncryptedUri = section.Attributes["encryptedUri"].Value; // Get the unencryptedUri attribute. if (section.Attributes["unencryptedUri"] != null) settings.UnencryptedUri = section.Attributes["unencryptedUri"].Value; // Validate that if either encryptedUri or unencryptedUri are set, both must be set. if ( (settings.EncryptedUri.Length > 0 && settings.UnencryptedUri.Length == 0) || (settings.UnencryptedUri.Length > 0 && settings.EncryptedUri.Length == 0)) throw new SecuritySwitchSectionException("You must specify both 'encryptedUri' and 'unencryptedUri', or neither.", section); // Get the maintainPath attribute. if (section.Attributes["maintainPath"] != null) { string Value = section.Attributes["maintainPath"].Value.ToLower(); settings.MaintainPath = (Value == "true" || Value == "yes" || Value == "on"); } // Get the warningBypassMode attribute. if (section.Attributes["warningBypassMode"] != null) { string WarningBypassModeValue = section.Attributes["warningBypassMode"].Value.Trim(); if (Enum.IsDefined(typeof(SecurityWarningBypassMode), WarningBypassModeValue)) settings.WarningBypassMode = (SecurityWarningBypassMode)Enum.Parse(typeof(SecurityWarningBypassMode), WarningBypassModeValue); else throw new SecuritySwitchSectionException("Invalid value for the 'warningBypassMode' attribute.", section); } // Get the bypassQueryParamName attribute. if (section.Attributes["bypassQueryParamName"] != null) settings.BypassQueryParamName = section.Attributes["bypassQueryParamName"].Value; }
/// <summary> /// Creates an instance of EvaluateRequestEventArgs with an instance of Settings. /// </summary> /// <param name="application">The HttpApplication for the current context.</param> /// <param name="settings">An instance of Settings used for the evaluation of the request.</param> public EvaluateRequestEventArgs(HttpApplication application, Settings settings) : base() { _application = application; _settings = settings; }
/// <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> /// Creates an instance of EvaluateRequestEventArgs with the specified application and settings. /// </summary> /// <param name="context">The current context.</param> /// <param name="settings">An instance of Settings used for the evaluation of the request.</param> public EvaluateRequestEventArgs(HttpContextBase context, Settings settings) { ExpectedSecurity = null; Context = context; Settings = settings; }
/// <summary> /// Requests the current page over a secure connection, if it is not already. /// </summary> /// <param name="settings">The Settings to use for this request.</param> public static void RequestSecurePage(Settings settings) { // Determine the response path, if any. string ResponsePath = DetermineSecurePage(settings, false); if (ResponsePath != null && ResponsePath != string.Empty) // Redirect to the secure page. HttpContext.Current.Response.Redirect(ResponsePath, true); }
/// <summary> /// Requests the current page over an unsecure connection, if it is not already. /// </summary> /// <param name="settings">The Settings to use for this request.</param> public static void RequestUnsecurePage(Settings settings) { // Determine the response path, if any. string ResponsePath = DetermineUnsecurePage(settings, false); if (ResponsePath != null && ResponsePath != string.Empty) { HttpRequest Request = HttpContext.Current.Request; // Test for the need to bypass a security warning. bool Bypass; if (settings.WarningBypassMode == SecurityWarningBypassMode.AlwaysBypass) Bypass = true; else if (settings.WarningBypassMode == SecurityWarningBypassMode.BypassWithQueryParam && Request.QueryString[settings.BypassQueryParamName] != null) { Bypass = true; // Remove the bypass query parameter from the URL. System.Text.StringBuilder NewPath = new System.Text.StringBuilder(ResponsePath); int i = ResponsePath.LastIndexOf(string.Format("?{0}=", settings.BypassQueryParamName)); if (i < 0) i = ResponsePath.LastIndexOf(string.Format("&{0}=", settings.BypassQueryParamName)); NewPath.Remove(i, settings.BypassQueryParamName.Length + Request.QueryString[settings.BypassQueryParamName].Length + 1); // Remove any abandoned "&" character. if (i >= NewPath.Length) i = NewPath.Length - 1; if (NewPath[i] == '&') NewPath.Remove(i, 1); // Remove any abandoned "?" character. i = NewPath.Length - 1; if (NewPath[i] == '?') NewPath.Remove(i, 1); ResponsePath = NewPath.ToString(); } else Bypass = false; // Output a redirector for the needed page to avoid a security warning. HttpResponse Response = HttpContext.Current.Response; if (Bypass) { // Clear the current response. Response.Clear(); // Add a refresh header to the response for the new path. Response.AddHeader("Refresh", string.Concat("0;URL=", ResponsePath)); // Also, add JavaScript to replace the current location as backup. Response.Write("<html><head><title></title>"); Response.Write("<!-- <script language=\"javascript\">window.location.replace(\""); Response.Write(ResponsePath); Response.Write("\");</script> -->"); Response.Write("</head><body></body></html>"); Response.End(); } else // Redirect to the insecure page. Response.Redirect(ResponsePath, true); } }
/// <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);