Search code examples
asp.net-mvc-4membership-provider

Custom Membership Provider with Windows authetication


I've created my own Membership Provider where I have below method:

public override bool ValidateUser(string username, string password)
{
    if (username == "John")
        return true;
    else
        return false;
}

I've also added below lines to web.config file:

<authentication mode="Windows" />
    <authorization>
      <deny users="?" />
    </authorization>
    <membership defaultProvider="MembershipProviter">
      <providers>
        <clear />
        <add name="cls_MembershipProvider" type="App.cls_MembershipProvider" 
             enablePasswordRetrieval="false" 
             enablePasswordReset="false" 
             requiresQuestionAndAnswer="false" 
             requiresUniqueEmail="false" 
             maxInvalidPasswordAttempts="5" 
             minRequiredPasswordLength="5" 
             minRequiredNonalphanumericCharacters="0" 
             passwordAttemptWindow="10" 
             applicationName="App"
             />
      </providers>
    </membership>

As you may notice I am using Windows authentication and I don't have Log In page. By default all users from Active Directory has access to the page. My goal is to check if user exist in my database. Everywhere I searched, there is Log In page, where ValidateUser is launched. My question is where should I implement ValidateUser method as I don't have Log In page. I just want to have control on each Controler method so I could add [Authorize] so only users from my database can actually access the page.


Solution

  • You can define your own CustomAuthorizeAttribute deriving from AuthorizeAttribute. Override OnAuthorization method to perform validation using details in context. Apply your custom filter on top of each controller or define a BaseController and derive your controllers from BaseController. For example you can define a class like:

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public sealed class RdbiAuthorizationAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// Verifies that the logged in user is a valid organization user.
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            Guard.ArgumentNotNull(filterContext, "filterContext");
            Guard.ArgumentNotNull(filterContext.Controller, "filterContext.Controller");
    
            bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(
                typeof(AllowAnonymousAttribute), inherit: true)
                                     || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
                                         typeof(AllowAnonymousAttribute), inherit: true);
    
            if (skipAuthorization)
            {
                return;
            }
    
            if (string.IsNullOrEmpty(filterContext.HttpContext.User.Identity.Name))
                throw new AuthenticationException("User must be logged in to access this page.");
    
            var controller = filterContext.Controller as BaseController;
            if (controller != null)
            {
                var user = controller.GetUser();
    
                if (user == null)
                {
                    throw new InvalidOperationException(string.Format("Logged in user {0} is not a valid user", filterContext.HttpContext.User.Identity.Name));
                }
            }
    
            base.OnAuthorization(filterContext);
        }
    }
    

    Then you can define controller like:

    [RdbiAuthorization]
    public class BaseController : Controller
    {
    }
    
    public class MyTestController : BaseController
    {
    }