Last week my friend and colleague Greg Coffman had asked me if I knew of a way to restrict IP access to directories within the Sitecore web application, and I recalled reading a post by Alex Shyba quite some time ago.
Although Alex’s solution is probably good enough in most circumstances, I decided to explore other solutions, and came up with the following <httpRequestBegin> pipeline processor as another way to accomplish this:
using System; using System.Collections.Generic; using System.Linq; using System.Web.Hosting; using Sitecore.Configuration; using Sitecore.Diagnostics; using Sitecore.Pipelines.HttpRequest; using Sitecore.Web; namespace Sitecore.Sandbox.Pipelines.HttpRequest { public class FilePathRestrictor : HttpRequestProcessor { public override void Process(HttpRequestArgs args) { Assert.ArgumentNotNull(args, "args"); if (!ShouldRedirect(args)) { return; } RedirectToNoAccessUrl(); } private bool ShouldRedirect(HttpRequestArgs args) { return CanProcess(args, GetFilePath(args)) && !CanAccess(args.Context.Request.UserHostAddress); } protected virtual string GetFilePath(HttpRequestArgs args) { if (string.IsNullOrWhiteSpace(Context.Page.FilePath)) { return args.Url.FilePath; } return Context.Page.FilePath; } protected virtual bool CanProcess(HttpRequestArgs args, string filePath) { return !string.IsNullOrWhiteSpace(filePath) && !string.IsNullOrWhiteSpace(RootFilePath) && AllowedIPs != null && AllowedIPs.Any() && (HostingEnvironment.VirtualPathProvider.DirectoryExists(filePath) || HostingEnvironment.VirtualPathProvider.FileExists(filePath)) && args.Url.FilePath.StartsWith(RootFilePath, StringComparison.CurrentCultureIgnoreCase) && !string.IsNullOrWhiteSpace(args.Context.Request.UserHostAddress) && !string.Equals(filePath, Settings.NoAccessUrl, StringComparison.CurrentCultureIgnoreCase); } protected virtual bool CanAccess(string ip) { Assert.ArgumentNotNullOrEmpty(ip, "ip"); return AllowedIPs.Contains(ip); } protected virtual void RedirectToNoAccessUrl() { WebUtil.Redirect(Settings.NoAccessUrl); } protected virtual void AddAllowedIP(string ip) { if (string.IsNullOrWhiteSpace(ip) || AllowedIPs.Contains(ip)) { return; } AllowedIPs.Add(ip); } private string RootFilePath { get; set; } private IList<string> _AllowedIPs; private IList<string> AllowedIPs { get { if (_AllowedIPs == null) { _AllowedIPs = new List<string>(); } return _AllowedIPs; } } } }
The pipeline processor above determines whether the IP making the request has access to the directory or file on the file system — a list of IP addresses that should have access are passed to the pipeline processor via a configuration file, and the code does check to see if the requested URL is a directory or a file on the file system — by matching the beginning of the URL with a configuration defined root path.
If the user does not have access to the requested path, s/he is redirected to the “No Access Url” which is specified in the Sitecore instance’s configuration.
The list of IP addresses that should have access to the directory — including everything within it — and the root path are handed to the pipeline processor via the following patch configuration file:
<?xml version="1.0" encoding="utf-8" ?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <httpRequestBegin> <processor patch:before=" processor[@type='Sitecore.Pipelines.HttpRequest.FileResolver, Sitecore.Kernel']" type="Sitecore.Sandbox.Pipelines.HttpRequest.FilePathRestrictor, Sitecore.Sandbox"> <RootFilePath>/sitecore</RootFilePath> <AllowedIPs hint="list:AddAllowedIP"> <IP>127.0.0.2</IP> </AllowedIPs> </processor> </httpRequestBegin> </pipelines> </sitecore> </configuration>
Since my IP is 127.0.0.1, I decided to only allow 127.0.0.2 access to my Sitecore directory — this also includes everything within it — in the above configuration file for testing.
After navigating to /sitecore of my local sandbox instance, I was redirected to the “No Access Url” page defined in my Web.config:
If you have any thoughts on this, or know of other solutions, please share in a comment.