Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Umbraco 7 custom membership and role providers

I went through 10's of documentation and I am doing the right thing but I am sure it is a small detail I am missing.

I want to use my own login mechanism to log in my website. the login mechanism is in an Identity server for single sign on.

But I want to use the Public access feature in umbraco, so I am adding the roles from my local database. by changing the config file

<roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
      <providers>
        <clear />
        <add name="UmbracoRoleProvider" type="rcsedWebServiceBLL.RCSEdRoleProvider" />
      </providers>
    </roleManager>

and implement the RoleProvider

 class RCSEdRoleProvider : RoleProvider
    {
        private string _ApplicationName = "UmbracoRoleProvider";
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
        throw new NotImplementedException();
    }

    public override string ApplicationName
    {
        get { return _ApplicationName; }
        set
        {
            if(string.IsNullOrEmpty(value))
                throw new ProviderException("ApplicationName Cacnnot be Empty");

            if(value.Length > 0x100)
                throw new ProviderException("provider application name too long");

            _ApplicationName = value;
        }
    }

    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()
    {
        return UBISRoles.GetRoleList();
    }

    public override string[] GetRolesForUser(string username)
    {
        // code to return user role access
        try
        {
           //ool isAuthenticateSession = RCSEd.UolsSecurity.CommonFunctions.CheckAuthenticateSessionOrNot();

            if (HttpContext.Current.Session["UOSStudent"] != null)
            {
                return (String[])HttpContext.Current.Session["userRoles"];
            }
            else
            {
                List<String> retval = new List<string>();
                retval.Add("Public");
                return retval.ToArray();
            }
        }
        catch (Exception ex)
        {
           // AppLogWriter _objApplog = new AppLogWriter();
           // _objApplog.WriteLogMessages(ex.Message.ToString());
            //TODO catch Error 
            List<String> retval = new List<string>();
            retval.Add("Public");
            return retval.ToArray();
        }

    }

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

    public override bool IsUserInRole(string username, string roleName)
    {
        try
        {
            foreach (String role in (String[])HttpContext.Current.Session["userRoles"])
            {
                if (String.Compare(role, roleName, true) == 0)
                    return true;
            }


            return false;

        }
        catch { }

        return false;

    }

    public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }

    public override bool RoleExists(string roleName)
    {

        foreach (string val in UBISRoles.GetRoleList())
        {
            if (val == roleName)
                return true;
        }

        return false;
    }
}

class UBISRoles
{
    private static string[] allroles = new string[] { //"Public", 
     "MembershipCandidate",
        "MembershipMember"
      };


    public static string[] GetRoleList()
    {
        return allroles;
    }



    public static void SetRoles(DataTable UBIsRolesResultsTBL)
    {
        List<String> userRoles = new List<string>();

        DataRow rec = UBIsRolesResultsTBL.Rows[0];


        switch (rec["Membership"].ToString())
        {

            case "member":
                userRoles.Add("MembershipMember");
                break;
            case "pending member":
                userRoles.Add("MembershipPending");//add
                break;
            case "public":
                userRoles.Add("MembershipPublic");//add
                break;

        }






        HttpContext.Current.Session["userRoles"] = userRoles.ToArray();

    }

    private static void CheckSimpleFieldVal(List<String> userRoles, DataRow rec, string roleName)
    {
        try
        {
            if (string.Compare(rec[roleName].ToString(), "YES", true) == 0)
                userRoles.Add(roleName);

        }
        catch (Exception ex)
        {
            string msg = ex.Message;

        }

    }

    private static void CheckSimpleFieldValV2(List<String> userRoles, DataRow rec, string roleName)
    {
        try
        {
            if (string.Compare(rec[roleName].ToString(), "1", true) == 0)
                userRoles.Add(roleName);

        }
        catch (Exception ex)
        {
            string msg = ex.Message;

        }

    }

}

And this works fine and everything is being loaded in the member groups in umbraco back office.

But when I try to implement the MembershipProvider where i feel things is not working. the web config look something like this

  <membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear />
        <add name="UmbracoMembershipProvider" type="rcsedWebServiceBLL.RCSEdMembershipProvide"  />
        <add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed" />
      </providers>
    </membership>

And the Membershiprovider class look like this

class RCSEdMembershipProvide : MembershipProvider
    {
        string connectionStringName;
        private string _ApplicationName =  "UmbracoMembershipProvider";
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
        base.Initialize(name, config);

      /*  if (config["ConnectionStringName"] != null)
            connectionStringName = config["connectionStringName"];*/




    }

    public override string ApplicationName
    {
        get { return _ApplicationName; }
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new ProviderException("ApplicationName Cacnnot be Empty");

            if (value.Length > 0x100)
                throw new ProviderException("provider application name too long");

            _ApplicationName = value;
        }
    }

    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 bool EnablePasswordReset
    {
        get { throw new NotImplementedException(); }
    }

    public override bool EnablePasswordRetrieval
    {
        get { 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(string username, bool userIsOnline)
    {
        try
        {
            User user = (User)HttpContext.Current.Session["user"];
            if (user != null)
                return new MembershipUser("RCSEdMembershipProvider", user.DisplayName, username, user.Email, "", "", true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
            else
                return null;

        }
        catch
        {
            return null;
        }
    }

    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        try
        {
            User user = (User)HttpContext.Current.Session["user"];

            if (user != null)
                return new MembershipUser("RCSEdMembershipProvider", user.DisplayName, providerUserKey, user.Email, "", "", true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
            else
                return null;
        }
        catch
        {

            return null;
        }
    }

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

    public override int MaxInvalidPasswordAttempts
    {
        get { throw new NotImplementedException(); }
    }

    public override int MinRequiredNonAlphanumericCharacters
    {
        get { throw new NotImplementedException(); }
    }

    public override int MinRequiredPasswordLength
    {
        get { throw new NotImplementedException(); }
    }

    public override int PasswordAttemptWindow
    {
        get { throw new NotImplementedException(); }
    }

    public override MembershipPasswordFormat PasswordFormat
    {
        get { throw new NotImplementedException(); }
    }

    public override string PasswordStrengthRegularExpression
    {
        get { throw new NotImplementedException(); }
    }

    public override bool RequiresQuestionAndAnswer
    {
        get { throw new NotImplementedException(); }
    }

    public override bool RequiresUniqueEmail
    {
        get { throw new NotImplementedException(); }
    }

    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)
    {


        return true;
    }
}

I even put the validateUser as true all the time.

so when the User log in to my identity server I load the User role in HttpContext.Current.Session["userRoles"] and I limit the public access of my page and redirect the user to the correct pages.

when the user is not logged the user is redirected to the login page which is fine but when the user is returned and his/her roles is loaded and try to visit the restricted pages the membership provider ValidateUser don't get hit and the User is redirected back to the log in page again and again.

PS. I am using umbraco 7.1.3

Excuse the long question but i wanted to cover all my steps. thank you in advance.

like image 783
dori naji Avatar asked Nov 10 '22 15:11

dori naji


1 Answers

Cant' comment so it will be answer :) Hope this will help. My example is based on the user using umbraco login and you want an external provider to handle membership login. If it's the other way around I apologize.

I have both a role provider and user provider in umbraco 7.2 I hope you can use my implementation to compare. It works for me.

Web.config looks like:

<membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear/>
        <!--<add name="UmbracoMembershipProvider" type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed" />-->
        <add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="4" useLegacyEncoding="true" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" passwordFormat="Hashed"/>
        <add name="UmbracoMembershipProvider" type="XXX.Model.Membership.SAPMembershipProvider" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="_umbracoSystemDefaultProtectType" passwordFormat="Hashed"/>
      </providers>
    </membership>
    <!-- Role Provider -->
    <roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
      <providers>
        <clear/>
        <add name="UmbracoRoleProvider" type="XXX.Model.Membership.SAPRoleProvider"/>
        <!--<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider"/>-->
      </providers>
    </roleManager>

My role provider looks like this

    public class SAPRoleProvider : Umbraco.Web.Security.Providers.MembersRoleProvider
        {

            public override bool IsUserInRole(string username, string roleName)
            {
                if (roleName.ToLower() == "standard")
                    return true;
                else
                    return base.IsUserInRole(username, roleName);
            }
            public override string[] GetRolesForUser(string username)
            {
                return new[] { "Standard" };
            }
        }

and membership provider like this:

public class SAPMembershipProvider : Umbraco.Web.Security.Providers.UsersMembershipProvider
    {
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            ILoginService Loginss = new LoginService();
            return Loginss.ChangePassword(oldPassword, newPassword, username);
        }
        public override string ResetPassword(string username, string answer)
        {
            ILoginService Loginss = new LoginService();
            return Loginss.ResetPassword(username).ToString();
        }
        public override MembershipUser GetUser(object providerUserKey, bool someonelinestuff)
        {
            return GetSapUser(providerUserKey);
        }


        /// <summary>
        /// It is not the username but providerUserKey i ask for herem just to test since I am not sure what SAP want right now, regarding request of userdata
        /// </summary>
        /// <param name="providerUserKey"></param>
        /// <param name="someonelinestuff"></param>
        /// <returns></returns>
        public override MembershipUser GetUser(string username, bool someonelinestuff)
        {
            return GetSapUser(username);
        }
        public SAPMembershipUser GetUser(string username)
        {
            return (SAPMembershipUser)GetUser(username, false);
        }

        public override bool ValidateUser(string username, string password)
        {
            try
            {
                ILoginService LoginS = new LoginService();
                SAPMembershipUser SU = LoginS.Login(username, password);
                if (SU != null)
                {
                    FrieLib.CacheHelper.StoreCache(username.ToLower(), SU,true,20);
                    return true;
                }
            }
            catch { return false; }
            return false;
        }


        protected override bool PerformChangePassword(string username, string oldPassword, string newPassword)
        {
            ILoginService Loginss = new LoginService();
            return Loginss.ChangePassword(oldPassword, newPassword, username);
        }
        private SAPMembershipUser GetSapUser(string username)
        {

            try
            {
                SAPMembershipUser SU = (SAPMembershipUser)FrieLib.CacheHelper.RetrieveCache(username.ToLower());
                if (SU != null)
                {
                    return SU;
                }
                else
                {
                    HttpContext.Current.Response.Redirect("/umbraco/Surface/MemberLoginSurface/MemberLogout");
                }

            }
            catch (Exception es)
            {
                HttpContext.Current.Response.Redirect("/umbraco/Surface/MemberLoginSurface/MemberLogout");
            }
            return null;
        }
        private SAPMembershipUser GetSapUser(object providerUserKey)
        {
            return GetSapUser(providerUserKey.ToString());
        }
    }

I have one additional step which I do not know if you are missing where I ensure the end user is logged in.

[HttpPost]
        [ActionName("MemberLogin")]
        public ActionResult MemberLoginPost(MemberLoginModel model)
        {
            if (Membership.ValidateUser(model.Username, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.Username.ToLower(), model.RememberMe);

                    return RedirectToCurrentUmbracoUrl();
            }
            else
            {
                TempData["Status"] = "danger";
                TempData["StatusMessage"] = "login_fail_message";
                return RedirectToCurrentUmbracoPage();
            }
        }

I hope it helps.

like image 73
Lau Frie Avatar answered Dec 23 '22 22:12

Lau Frie