ASP.NET MVC2 Implementing Custom RoleManager problem

Posted by ile on Stack Overflow See other posts from Stack Overflow or by ile
Published on 2010-05-11T14:42:22Z Indexed on 2010/05/11 14:44 UTC
Read the original article Hit count: 1082

To create a custom membership provider I followed these instructions:
http://stackoverflow.com/questions/2771094/asp-net-mvc2-custom-membership
and these:
http://mattwrock.com/post/2009/10/14/Implementing-custom-Membership-Provider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx

So far, I've managed to implement custom membership provider and that part works fine. RoleManager still needs some modifications...

Project structure:

alt text

SAMembershipProvider.cs:

public class SAMembershipProvider : MembershipProvider
    {

        #region - Properties -

        private int NewPasswordLength { get; set; }
        private string ConnectionString { get; set; }

        public bool enablePasswordReset { get; set; }
        public bool enablePasswordRetrieval { get; set; }
        public bool requiresQuestionAndAnswer { get; set; }
        public bool requiresUniqueEmail { get; set; }
        public int maxInvalidPasswordAttempts { get; set; }
        public int passwordAttemptWindow { get; set; }
        public MembershipPasswordFormat passwordFormat { get; set; }
        public int minRequiredNonAlphanumericCharacters { get; set; }
        public int minRequiredPasswordLength { get; set; }
        public string passwordStrengthRegularExpression { get; set; }

        public override string ApplicationName { get; set; }

        public override bool EnablePasswordRetrieval
        {
            get { return enablePasswordRetrieval; }
        }

        public override bool EnablePasswordReset
        {
            get { return enablePasswordReset; }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return requiresQuestionAndAnswer; }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return maxInvalidPasswordAttempts; }
        }

        public override int PasswordAttemptWindow
        {
            get { return passwordAttemptWindow; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return requiresUniqueEmail; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return passwordFormat; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return minRequiredPasswordLength; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return minRequiredNonAlphanumericCharacters; }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { return passwordStrengthRegularExpression; }
        }

        #endregion

        #region - Methods -

        public override void Initialize(string name, NameValueCollection config)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        protected override void OnValidatingPassword(ValidatePasswordEventArgs e)
        {
            base.OnValidatingPassword(e);
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        public override bool ValidateUser(string username, string password)
        {
            AccountRepository accountRepository = new AccountRepository();
            var user = accountRepository.GetUser(username);

            if (string.IsNullOrEmpty(password.Trim())) return false;
            if (user == null) return false;

            //string hash = EncryptPassword(password);
            var email = user.Email;
            var pass = user.Password;            

            if (user == null) return false;

            if (pass == password)
            {
                //User = user;
                return true;
            }

            return false;
        }
        #endregion

        protected string EncryptPassword(string password)
        {
            //we use codepage 1252 because that is what sql server uses
            byte[] pwdBytes = Encoding.GetEncoding(1252).GetBytes(password);
            byte[] hashBytes = System.Security.Cryptography.MD5.Create().ComputeHash(pwdBytes);
            return Encoding.GetEncoding(1252).GetString(hashBytes);
        }

    }

SARoleProvider.cs

public class SARoleProvider : RoleProvider
    {
        AccountRepository accountRepository = new AccountRepository();

        public override bool IsUserInRole(string username, string roleName)
        {
            return true;
        }
        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 RemoveUsersFromRoles(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 bool RoleExists(string roleName)
        {
            throw new NotImplementedException();
        }
        public override string[] GetRolesForUser(string username)
        {
            int rolesCount = 0;
            IQueryable<RoleViewModel> rolesNames;

            try
            {
                // get roles for this user from DB...
                rolesNames = accountRepository.GetRolesForUser(username);
                rolesCount = rolesNames.Count();

            }
            catch (Exception ex)
            {
                throw ex;
            }

            string[] roles = new string[rolesCount];
            int counter = 0;
            foreach (var item in rolesNames)
            {
                roles[counter] = item.RoleName.ToString();
                counter++;
            }

            return roles;

        }
        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();

        }
        public override string[] GetAllRoles()
        {
            throw new NotImplementedException();

        }

    }

AccountRepository.cs

public class RoleViewModel
    {
        public string RoleName { get; set; }
    }

    public class AccountRepository
    {
        private DB db = new DB();

        public User GetUser(string email)
        {
            return db.Users.SingleOrDefault(d => d.Email == email);
        }
        public IQueryable<RoleViewModel> GetRolesForUser(string email)
        {

            var result = (
                         from role in db.Roles
                         join user in db.Users on role.RoleID equals user.RoleID
                         where user.Email == email
                         select new RoleViewModel
                         {
                             RoleName = role.Name
                         });

            return result;
        }
    }

webconfig

<membership defaultProvider="SAMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear/>
        <add
          name="SAMembershipProvider"
          type="SA_Contacts.Membership.SAMembershipProvider, SA_Contacts"
          connectionStringName ="ShinyAntConnectionString"
          />
      </providers>
    </membership>

    <roleManager defaultProvider="SARoleProvider" enabled="true" cacheRolesInCookie="true">
      <providers>
        <clear/>
        <add
          name="SARoleProvider"
          type="SA_Contacts.Membership.SARoleProvider"
          connectionStringName ="ShinyAntConnectionString"
          />
      </providers>
    </roleManager>

AccountController.cs:

public class AccountController : Controller
    {
        SAMembershipProvider provider = new SAMembershipProvider();
        AccountRepository accountRepository = new AccountRepository();

        public AccountController()
        {
        }

        public ActionResult LogOn()
        {
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult LogOn(string userName, string password, string returnUrl)
        {

            if (!ValidateLogOn(userName, password))
            {
                return View();
            }

            var user = accountRepository.GetUser(userName);
            var userFullName = user.FirstName + " " + user.LastName;

            FormsAuthentication.SetAuthCookie(userFullName, false);
            if (!String.IsNullOrEmpty(returnUrl) && returnUrl != "/")
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        public ActionResult LogOff()
        {

            FormsAuthentication.SignOut();
            return RedirectToAction("Index", "Home");
        }

        private bool ValidateLogOn(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", "You must specify a username.");
            }
            if (String.IsNullOrEmpty(password))
            {
                ModelState.AddModelError("password", "You must specify a password.");
            }
            if (!provider.ValidateUser(userName, password))
            {
                ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
            }

            return ModelState.IsValid;
        }
    }

In some testing controller I have following:

[Authorize]
    public class ContactsController : Controller
    {

        SAMembershipProvider saMembershipProvider = new SAMembershipProvider();
        SARoleProvider saRoleProvider = new SARoleProvider();

        //
        // GET: /Contact/

        public ActionResult Index()
        {
            string[] roleNames = Roles.GetRolesForUser("[email protected]");

            // Outputs admin
            ViewData["r1"] = roleNames[0].ToString();

            // Outputs True
            // I'm not even sure if this method is the same as the one below
            ViewData["r2"] = Roles.IsUserInRole("[email protected]", roleNames[0].ToString());

            // Outputs True
            ViewData["r3"] = saRoleProvider.IsUserInRole("[email protected]", "admin"); 


            return View();
        }

If I use attribute [Authorize] then everything works ok, but if I use [Authorize(Roles="admin")] then user is always rejected, like he is not in role.

Any idea of what could be wrong here?

Thanks in advance,
Ile

© Stack Overflow or respective owner

Related posts about asp.net-mvc2

Related posts about membership-provider