Created
June 19, 2014 13:22
-
-
Save dereklawless/5fc2ffdb9bac22c2c2aa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Collections.ObjectModel; | |
using System.Configuration; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Http; | |
using System.Net.Http.Headers; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using App.API.Resources; | |
namespace App.API.Handlers | |
{ | |
/// <summary> | |
/// A custom handler to determine whether a request must be made using the HTTPS protocol. | |
/// Where HTTPS is required, also allows requests made with a specific HTTP header (indicating the request | |
/// originated from HTTPS e.g. through a gateway). | |
/// </summary> | |
public class RequireHttpsHandler : DelegatingHandler | |
{ | |
private ICollection<string> _allowHttpRequestsWithHeaders; | |
private bool? _redirectHttpRequests; | |
private bool? _requireHttps; | |
/// <summary> | |
/// Gets or sets a collection of HTTP header keys which, if present, indicate an HTTP request should be allowed. | |
/// If set, overrides the behaviour of the <see cref="RedirectHttpRequests"/> property. | |
/// </summary> | |
/// <value>The HTTP header collection.</value> | |
public ICollection<string> AllowHttpRequestsWithHttpsOriginHeaders | |
{ | |
get | |
{ | |
if (_allowHttpRequestsWithHeaders == null) | |
{ | |
var headers = ConfigurationManager.AppSettings[ConfigurationKeys.HttpsOriginHttpHeaders]; | |
if (!string.IsNullOrWhiteSpace(headers)) | |
{ | |
_allowHttpRequestsWithHeaders = headers.Split(','); | |
} | |
else | |
{ | |
_allowHttpRequestsWithHeaders = new Collection<string>(); | |
} | |
} | |
return _allowHttpRequestsWithHeaders; | |
} | |
set { _allowHttpRequestsWithHeaders = value; } | |
} | |
/// <summary> | |
/// Gets or sets a value indicating whether requests made using the HTTP protocol should be | |
/// redirected to their HTTPS equivalent. | |
/// By default, set to <c>false</c>. | |
/// </summary> | |
/// <value><c>true</c> if redirection should occur; otherwise, <c>false</c>.</value> | |
public bool RedirectHttpRequests | |
{ | |
get | |
{ | |
if (_redirectHttpRequests == null) | |
{ | |
var redirectToHttps = ConfigurationManager.AppSettings[ConfigurationKeys.RedirectToHttps]; | |
bool result; | |
if (Boolean.TryParse(redirectToHttps, out result)) | |
{ | |
_redirectHttpRequests = result; | |
} | |
} | |
return _redirectHttpRequests.GetValueOrDefault(false); | |
} | |
set { _redirectHttpRequests = value; } | |
} | |
/// <summary> | |
/// Gets or sets a value indicating whether requests must be made securely using the HTTPS protocol. | |
/// By default, set to <c>true</c>. | |
/// </summary> | |
/// <value><c>true</c> if a requested must be secured; otherwise, <c>false</c>.</value> | |
public bool RequireHttps | |
{ | |
get | |
{ | |
if (_requireHttps == null) | |
{ | |
var httpsRequired = ConfigurationManager.AppSettings[ConfigurationKeys.RequireHttps]; | |
bool result; | |
if (Boolean.TryParse(httpsRequired, out result)) | |
{ | |
_requireHttps = result; | |
} | |
} | |
return _requireHttps.GetValueOrDefault(true); | |
} | |
set { _requireHttps = value; } | |
} | |
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | |
{ | |
if ((request.RequestUri.Scheme.ToUpperInvariant() == "HTTPS") | |
|| !RequireHttps | |
|| _ContainsHttpHeaders(request.Headers)) | |
{ | |
// Allow the request. | |
return base.SendAsync(request, cancellationToken); | |
} | |
if (RedirectHttpRequests) | |
{ | |
// Redirect the request to the secure protocol equivalent. | |
var response = new HttpResponseMessage(HttpStatusCode.Redirect); | |
response.Headers.Location = new Uri(request.RequestUri.ToString().Replace("http:", "https:")); | |
var task = new TaskCompletionSource<HttpResponseMessage>(); | |
task.SetResult(response); | |
return task.Task; | |
} | |
else | |
{ | |
// Return an HTTP 403 status code as the response. | |
var task = new TaskCompletionSource<HttpResponseMessage>(); | |
task.SetResult(new HttpResponseMessage(HttpStatusCode.Forbidden)); | |
return task.Task; | |
} | |
} | |
private bool _ContainsHttpHeaders(HttpHeaders headers) | |
{ | |
return AllowHttpRequestsWithHttpsOriginHeaders.Any(headers.Contains); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment