0
votes

I am working on an MVC4 application that has authentication completed by ADFS before the application is launched and will only be launched by successfully authenticated users. Within the application itself I have a list of users held within the following class:

public class MyAppUser : IPrincipal
{
    [Key]
    public int UserID { get; set; }

    [StringLength(128)]
    public string Username { get; set; }              

    public int ParticipationPoints { get; set; }

    public DateTime JoinDate { get; set; }

    public DateTime LastLogin { get; set; }

    //1-to-1 Mappings
    public int? CompanyID { get; set; }
    public virtual Company Company { get; set; }

    public int? ProfileID { get; set; }
    public virtual Profile Profile { get; set; }

    public int? SocialID { get; set; }
    public virtual SocialMedia Social { get; set; }

    public int? RoleID { get; set; }
    public virtual Role Role { get; set; }

    //1-to-many Mappings
    public virtual ICollection<Block> Blocks { get; set; }

    public virtual ICollection<Enrollment> Enrollments { get; set; }

    public virtual ICollection<CategoryMap> CategoryMaps { get; set; }

    public virtual ICollection<Feedback> Feedbacks { get; set; }

    public virtual ICollection<Survey> Surveys { get; set; }

    public virtual ICollection<Friend> Friends { get; set; }

    public virtual ICollection<Participation> Participations { get; set; }

    public virtual ICollection<Post> Posts { get; set; }

    public virtual ICollection<Target> Targets { get; set; }

    public virtual ICollection<CourseStatus> CourseStatuses { get; set; }

    public virtual ICollection<Objective> Objectives { get; set; }

    public virtual ICollection<UserCourseInfo> UserCourseInfos { get; set; }

    public IIdentity Identity { get; set; }

    public bool IsInRole(string role)
    {
        if (this.Role.Name == role)
        {
            return true;
        }
        return false;
    }
}

I have created a custom role provider that is tied to my dbcontext as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration.Provider;
using MyApp.Data;
using MyApp.ViewModels;

namespace MyApp.Providers
{
  public class MyAppProvider : System.Web.Security.SqlRoleProvider
  {
    private MyAppContext dbcontext = new MyAppContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyAppContext"].ConnectionString);
    private Repository<MyAppUser> userRepository;
    private Repository<Role> roleRepository;

    public MyAppProvider()
    {
        this.userRepository = new Repository<MyAppUser>(dbcontext);
        this.roleRepository = new Repository<Role>(dbcontext);
    }

    public override string[] GetAllRoles()
    {
        IEnumerable<Role> dbRoles = roleRepository.GetAll();
        int dbRolesCount = roleRepository.GetAll().Count();
        string[] roles = new string[dbRolesCount];
        int i = 0;
        foreach(var role in dbRoles)
        {
            roles[i] = role.Name;
            i++;
        }
        return roles;
    }

    public string[] GetAllUsers()
    {
        IEnumerable<MyAppUser> dbUsers = userRepository.GetAll();
        int dbUsersCount = userRepository.GetAll().Count();
        string[] users = new string[dbUsersCount];
        int i = 0;
        foreach (var user in dbUsers)
        {
            users[i] = user.Username;
            i++;
        }
        return users;
    }

    public override bool RoleExists(string roleName)
    {
        string[] roles = { "Admin", "User", "BobsBusiness" };
        if(roles.Contains(roleName))
            return true;
        else
            return false;
    }

    public override void CreateRole(string roleName)
    {
        Role newRole = new Role();
        newRole.Name = roleName;
        roleRepository.Add(newRole);
        roleRepository.SaveChanges();
    }

    public override void AddUsersToRoles(string[] usernames, string[] roleNames)
    {
        foreach (var username in usernames)
        {
            MyAppUser user = userRepository.Get(u => u.Username == username).FirstOrDefault();

            foreach (var rolename in roleNames)
            {
                Role role = roleRepository.Get(r => r.Name == rolename).FirstOrDefault();
                user.RoleID = role.RoleID;
                userRepository.Add(user);
                userRepository.SaveChanges();
            }

        }
    }

    public override string[] GetRolesForUser(string username)
    {
        MyAppUser user = userRepository.Get(u => u.Username == username).FirstOrDefault();
        if (user == null)
        {
            string[] roles = new string[1];
            roles[0] = "Fail";
            return roles;
        }
        else
        {
            Role role = roleRepository.Get(r => r.RoleID == user.RoleID).FirstOrDefault();
            if (role == null)
            {
                string[] roles = new string[1];
                roles[0] = "Fail";
                return roles;
            }
            else
            {
                string[] roles = new string[1];
                roles[0] = role.Name;
                return roles;
            }
        }

    }

    public override bool IsUserInRole(string userName, string roleName)
    {
        MyAppUser user = userRepository.Get(u => u.Username == userName).FirstOrDefault();
        if (user == null)
          throw new ProviderException("Username cannot be empty or null.");
        Role role = roleRepository.Get(r => r.Name == roleName).FirstOrDefault();
        if (role == null)
          throw new ProviderException("Role name cannot be empty or null.");
        if (user.RoleID == role.RoleID)
            return true;
        else
            return false;
    }
  }
}

Now I have tried to create a CustomMembershipProvider but I am unsure how to tie this to the dbcontext and the MyAppUser that I have created. Due to the authentication type we do not have an AccountController and so simpleMembership is not an option. I have created the abstract class for the custom membership provider as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MyApp.Data;

namespace MyApp.Providers
{
  public class MyAppMembershipProvider : System.Web.Security.MembershipProvider
  {
    private MyAppContext dbcontext = new MyAppContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyAppContext"].ConnectionString);
    private Repository<MyAppUser> userRepository;
    public MyAppUser User { get; private set; }

    public MyAppMembershipProvider()
    {
        this.userRepository = new Repository<MyAppUser>(dbcontext);
        User = userRepository.Get(u => u.Username == "jpmcfeely").FirstOrDefault();
    }

    public override string ApplicationName
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            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 System.Web.Security.MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out System.Web.Security.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 System.Web.Security.MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

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

    public override System.Web.Security.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 System.Web.Security.MembershipUser GetUser(string username, bool userIsOnline)
    {
        //throw new NotImplementedException();
        MyAppUser user = userRepository.Get(u => u.Username == username).FirstOrDefault();
        return GetUser(username, true);
    }

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

    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 System.Web.Security.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(System.Web.Security.MembershipUser user)
    {
        throw new NotImplementedException();
    }

    public override bool ValidateUser(string username, string password)
    {
        throw new NotImplementedException();
    }
  }
}

I would be very grateful for any tips anyone has in connecting the MyAppUser to the custom membership provider.

2

2 Answers

1
votes

Assuming that the application authenticates users via ADFS, your role provider and membersh provider have nothing to do. Completely. The identity together with roles is passed to the application by the ADFS.

What you possibly could do is to have a custom ClaimsAuthenticationmanager. I've blogged on that some time ago:

http://netpl.blogspot.com/2012/09/sessionauthenticationmodule-and-dynamic.html

0
votes

As I was already authenticated by ADFS I had gotten the username in the claims and held it in session variable. I then used this session variable to call my database user with the GetRolesForUser method that I had overriden. Works great not too much effort.