Alright so I made a custom role provider for my website and no matter what I do I can't get the code in the overridden functions to get hit.
This is the Custom Role Provider
namespace XXX.Security
{
using System;
using System.Linq;
using XXX.Areas.AccountManagement;
using System.Web.Security;
public class AppRoleProvider : RoleProvider
{
public override string ApplicationName
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
AccountManagementDbContext accountManagement = new AccountManagementDbContext("App Role Provider - GetAllRoles()");
string[] roles = accountManagement.getRoles();
return roles;
}
public override string[] GetRolesForUser(string username)
{
AccountManagementDbContext accountManagement = new AccountManagementDbContext("App Role Provider - GetRolesForUser()");
string[] userRoles = accountManagement.getRolesForUser(username);
return userRoles;
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override bool IsUserInRole(string username, string roleName)
{
AccountManagementDbContext accountManagement = new AccountManagementDbContext("App Role Provider - GetAllRoles()");
string[] userRoles = accountManagement.getRolesForUser(username);
return userRoles.Contains(roleName);
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
}
Here is my web.config file
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<connectionStrings>
<add name="xxx"
providerName="System.Data.SqlClient"
connectionString="Data Source=xxx;
Initial Catalog=xxx;
Integrated Security=false;
User ID=xxx;
Password=xxx;"/>
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="EnableSimpleMembership" value="false" />
</appSettings>
<system.web>
<authentication mode="Windows" />
<roleManager defaultProvider="AppRoleProvider" enabled="true">
<providers>
<clear/>
<add name="AppRoleProvider" type="xxx.Security.AppRoleProvider"/>
</providers>
</roleManager>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
<remove name="TelemetryCorrelationHttpModule" />
<add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" preCondition="integratedMode,managedHandler" />
<remove name="ApplicationInsightsWebTracking" />
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" />
</providers>
</entityFramework>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
</compilers>
</system.codedom>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
</DbProviderFactories>
</system.data>
</configuration>
This is a custom Authorization Attribute I am using
namespace XXX.Models
{
using System.Web;
using System.Web.Mvc;
public class AccessDeniedAuthorizationAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
var user = HttpContext.Current.User.Identity.Name;
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectResult("/AccessDenied");
}
}
}
}
Finally this is my controller
namespace XXX.Areas.Admin.Controllers
{
using Models;
using System.Web.Mvc;
public class AdminController : Controller
{
[AccessDeniedAuthorization(Roles = "Administrator")]
public ActionResult AdminHome()
{
var user = HttpContext.User.Identity.Name;
return View();
}
}
}
So here are some things I've tried to get this to work...
Tried using the default Authorize attribute on my controller action.
Tried specifying the other attributes in my web.config for the provider like so...
<system.web>
<authentication mode="Windows" />
<roleManager defaultProvider="AppRoleProvider" enabled="true">
<providers>
<clear/>
<add name="AppRoleProvider" type="XXX.Security.AppRoleProvider, XXX" connectionStringName="XXX"/>
</providers>
</roleManager>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1" />
</system.web>
I've hit all my overridden functions in the Role provider from a controller to make sure they worked and they all worked normally and hit the breakpoints I had in it. When I put a break point in my custom Authorization attribute though it hits when the controller action in the Admin controller gets called. I even looked at the HttpContext.Current.User.ProviderName and it is the name of my custom Role Provider.
Another thing that is weird is that my User.Identity is never filled out when it should be populating with my windows login information, so I would imagine this has to be some sort of problem with the windows authentication not working.
I have the windows authentication turned on in my project properties too. I also left anonymous authentication enabled as I need to use both types of authentication.
Also going to throw this out there. My custom Role provider is in my web project, but the acccountmanagementdbcontext it references is in a separate project, though I can't see that causing any issues.
** Update ** I found something while googling about changing the applicatonhost.config file for IIS express.
<windowsAuthentication enabled="true">
<providers>
<add value="Negotiate" />
<add value="NTLM" />
</providers>
</windowsAuthentication>
I did this, but still doesn't work.
** Update 2 ** It seems that for some reason the user has to enter their windows credentials at least one time for the windows authentication to be able to authenticate them. I tried it with my windows credentials, while running locally, and after I entered my credentials the code in my custom role provider was then hit.
I was under the impression that if windows authentication was turned on and a request was sent to a controller/action that required authentication that it would just pull the windows user's credentials automatically and then pass them to the role provider.
My boss says that if you're on the same network as the IIS server that it will automatically get the windows user's credentials, but I have my doubts, as I tried hosting this on my pc in IIS with a dns address in my host file and it still didn't auto populate my windows credentials into the HttpContext.User.Identity.