Skip to content

Instantly share code, notes, and snippets.

@dereklawless
Created June 19, 2014 13:22
Show Gist options
  • Save dereklawless/5fc2ffdb9bac22c2c2aa to your computer and use it in GitHub Desktop.
Save dereklawless/5fc2ffdb9bac22c2c2aa to your computer and use it in GitHub Desktop.
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