Active Directory in MVC
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="ExtTransfersAdmin.Views.BaseViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization"/>
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.web>
<httpHandlers>
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<!--
Enabling request validation in view pages would cause validation to occur
after the input has already been processed by the controller. By default
MVC performs request validation before a controller processes the input.
To change this behavior apply the ValidateInputAttribute to a
controller or action.
-->
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
</configuration>
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace ExtTransfersAdmin
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AutoMapperConfig.RegisterMappings();
}
}
}
using System.Web.Mvc;
using ExtTransfersAdmin.Filters;
namespace ExtTransfersAdmin
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AuthorizationFilter());
}
}
}
using System.DirectoryServices.AccountManagement;
using System.Security.Principal;
namespace ExtTransfersAdmin.Secuirty
{
public class CustomPrincipal : IPrincipal
{
public CustomPrincipal(IPrincipal principal, UserPrincipal userPriciple)
{
_userPrincipal = userPriciple;
_principal = principal;
}
private readonly IPrincipal _principal;
private readonly UserPrincipal _userPrincipal;
public bool IsInRole(string role)
{
return _principal.IsInRole(role);
}
public IIdentity Identity
{
get { return _principal.Identity; }
}
/// <summary>
/// Gets the Full Name for this account.
/// </summary>
public string FullName
{
get { return _userPrincipal.Name; }
}
/// <summary>
/// Gets the omain for this account.
/// </summary>
public string Domain
{
get
{
var s = Identity.Name;
var stop = s.IndexOf("\\", System.StringComparison.Ordinal);
return (stop > -1) ? s.Substring(0, stop) : string.Empty;
}
}
/// <summary>
/// Gets the Login for this account.
/// </summary>
public string Login
{
get
{
var s = Identity.Name;
var stop = s.IndexOf("\\", System.StringComparison.Ordinal);
return (stop > -1) ? s.Substring(stop + 1, s.Length - stop - 1) : string.Empty;
}
}
/// <summary>
/// Gets the Display Name for this account.
/// </summary>
public string DisplayName
{
get { return _userPrincipal.DisplayName; }
}
/// <summary>
/// Gets the e-mail address for this account.
/// </summary>
public string EmailAddress
{
get { return _userPrincipal.EmailAddress; }
}
/// <summary>
/// Gets the employee ID for this user principal.
/// </summary>
public string EmployeeId
{
get { return _userPrincipal.EmployeeId; }
}
/// <summary>
/// Gets the given name for the user principal.
/// </summary>
public string GivenName { get { return _userPrincipal.GivenName; } }
/// <summary>
/// Gets the middle name for the user principal.
/// </summary>
public string MiddleName { get { return _userPrincipal.MiddleName; } }
/// <summary>
/// Gets the surname for the user principal.
/// </summary>
public string Surname { get { return _userPrincipal.Surname; } }
/// <summary>
/// Gets the voice telephone number for the user principal.
/// </summary>
public string VoiceTelephoneNumber { get { return _userPrincipal.VoiceTelephoneNumber; } }
}
}
using System;
using System.Web.Mvc;
namespace ExtTransfersAdmin.Controllers
{
public static class ControllerExtension
{
public static string MakeActive(this UrlHelper urlHelper, string controller)
{
var result = "active";
var controllerName = urlHelper.RequestContext.RouteData.Values["controller"].ToString();
if (!controllerName.Equals(controller, StringComparison.OrdinalIgnoreCase))
{
result = null;
}
return result;
}
}
}
using System.Web.Mvc;
using ExtTransfersAdmin.Secuirty;
namespace ExtTransfersAdmin.Views
{
public abstract class BaseViewPage : WebViewPage
{
public virtual new CustomPrincipal User
{
get { return base.User as CustomPrincipal; }
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new CustomPrincipal User
{
get { return base.User as CustomPrincipal; }
}
}
}
using System.Web.Mvc;
using ExtTransfersAdmin.Secuirty;
namespace ExtTransfersAdmin.Controllers
{
public class BaseController : Controller
{
protected virtual new CustomPrincipal User
{
get { return HttpContext.User as CustomPrincipal; }
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.DirectoryServices.AccountManagement;
using System.Web.Routing;
using System.Web.Security;
using ExtTransfersAdmin.Secuirty;
using Framework.Common.Utils;
using Framework.Logging;
namespace ExtTransfersAdmin.Filters
{
public class AuthorizationFilter : AuthorizeAttribute
{
private const string IsAuthorized = "isAuthorized";
public string RedirectUrl = "~/Message/DenyAccess";
/// <summary>
/// Authentication
/// </summary>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isAuthorized;
try
{
isAuthorized = base.AuthorizeCore(httpContext);
if (isAuthorized)
{
var routeData = ((MvcHandler)httpContext.Handler).RequestContext.RouteData;
var roles = GetAuthorizedRoles(routeData);
if (roles != null)
{
var provider = new WindowsTokenRoleProvider();
isAuthorized = (roles.Any(role => provider.IsUserInRole(httpContext.User.Identity.Name, role)));
}
}
// for testing only remove or comment out
//if (ConfigHelper.AppSettings("Environment").StartsWith("Dev"))
// isAuthorized = true;
// handle if already in context
var items = httpContext.Items;
if (items.Contains(IsAuthorized))
httpContext.Items.Remove(IsAuthorized);
httpContext.Items.Add(IsAuthorized, isAuthorized);
}
catch (Exception ex)
{
Logger.Instance.Error(ex, "Authorize Core", new Dictionary<string, object>
{
{ "user", httpContext.User.Identity.Name }
});
throw;
}
return isAuthorized;
}
/// <summary>
/// Authorization
/// </summary>
public override void OnAuthorization(AuthorizationContext filterContext)
{
// authenticated
base.OnAuthorization(filterContext);
try
{
// check if authorized
var isAuthorized = filterContext.HttpContext.Items[IsAuthorized] != null &&
Convert.ToBoolean(filterContext.HttpContext.Items[IsAuthorized]);
Logger.Instance.Info("User Authentication", "On Authorization", new Dictionary<string, object>
{
{ "user", filterContext.RequestContext.HttpContext.User.Identity.Name },
{"isAuthorized",isAuthorized}
});
// redirect to deny access page if not authorized
if (!isAuthorized && filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl);
// build custom user for extended user information throughout the app
var principalContext = new PrincipalContext(ContextType.Domain);
var principal = filterContext.RequestContext.HttpContext.User;
var identity = principal.Identity;
var userPrincipal = UserPrincipal.FindByIdentity(principalContext, identity.Name);
var newCustomePrincipal = new CustomPrincipal(principal, userPrincipal);
HttpContext.Current.User = newCustomePrincipal;
Thread.CurrentPrincipal = newCustomePrincipal;
}
catch (Exception ex)
{
Logger.Instance.Error(ex, "On Authorization", new Dictionary<string, object>
{
{ "user", filterContext.RequestContext.HttpContext.User.Identity.Name }
});
throw;
}
}
private static IEnumerable<string> GetAuthorizedRoles(RouteData routeData)
{
var controller = routeData.Values["controller"].ToString();
// var action = routeData.Values["action"].ToString();
string appSettings = null;
switch (controller.ToLower())
{
case "home":
appSettings = ConfigHelper.AppSettings("ViewAccountsRoleName");
break;
case "manageaccounts":
appSettings = ConfigHelper.AppSettings("ManageAccountsRoleName");
break;
case "holidaycalendar":
appSettings = ConfigHelper.AppSettings("HolidayRoleName");
break;
case "routing":
appSettings = ConfigHelper.AppSettings("RoutingRoleName");
break;
}
if (string.IsNullOrWhiteSpace(appSettings))
{
Logger.Instance.Warn("Missing AD groups in Web.config for Roles");
return null;
}
return appSettings.Split(',');
}
}
}