using System; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Configuration.Provider; using System.Linq; using System.Threading.Tasks; using System.Web.Security; using MongoAuth.Properties; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver; namespace MongoAuth { public class MongoRoleProvider : RoleProvider { private const string MEMBER_COLLECTION_NAME = "members"; private const string ROLE_COLLECTION_NAME = "roles"; private IMongoCollection _memberCollection; private IMongoCollection _roleCollection; public override string ApplicationName { get { return ""; } set { } } public override void Initialize(string name, NameValueCollection config) { base.Initialize(name, config); MongoClientSettings settings = new MongoClientSettings { Server = new MongoServerAddress(DatabaseConfig.Host, DatabaseConfig.Port) }; if (!string.IsNullOrEmpty(DatabaseConfig.Username) && !string.IsNullOrEmpty(DatabaseConfig.Password)) { settings.Credentials = new List { MongoCredential.CreateCredential(DatabaseConfig.Database, DatabaseConfig.Username, DatabaseConfig.Password) }; } MongoClient dbClient = new MongoClient(settings); _roleCollection = dbClient.GetDatabase(DatabaseConfig.Database).GetCollection(ROLE_COLLECTION_NAME); _memberCollection = dbClient.GetDatabase(DatabaseConfig.Database).GetCollection(MEMBER_COLLECTION_NAME); } public override void AddUsersToRoles(string[] usernames, string[] roleNames) { Task> roleTask = _roleCollection.Find(r => roleNames.Contains(r.RoleName)).ToListAsync(); roleTask.Wait(); List roles = roleTask.Result; Task> userTask = _memberCollection.Find(u => usernames.Contains(u.UserName)).ToListAsync(); userTask.Wait(); List users = userTask.Result; for (int i = 0; i < roles.Count; i++) { var newUsers = new List(); if (roles[i].Users != null) { newUsers.AddRange(roles[i].Users); } IEnumerable usersToAdd = from u in users where newUsers.All(v => v != u.Id) select u.Id; newUsers.AddRange(usersToAdd); roles[i].Users = newUsers.ToArray(); Task update = _roleCollection.ReplaceOneAsync(Builders.Filter.Eq(r => r.Id, roles[i].Id), roles[i]); update.Wait(); } } public override void CreateRole(string roleName) { Task role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync(); role.Wait(); if (role.Result != null) { return; } MongoRole mr = new MongoRole { Id = Guid.NewGuid(), RoleName = roleName }; Task task = _roleCollection.InsertOneAsync(mr); task.Wait(); } public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { Task role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync(); role.Wait(); if (role.Result != null && role.Result.Users.Length > 0 && throwOnPopulatedRole) { throw new ProviderException(Resources.RoleNotEmpty); } Task task = _roleCollection.DeleteOneAsync(r => r.RoleName == roleName); task.Wait(); return true; } public override string[] FindUsersInRole(string roleName, string usernameToMatch) { Task role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync(); role.Wait(); if (role.Result == null) { return Array.Empty(); } Task> users = _memberCollection.Find(u => role.Result.Users.Contains(u.Id) && u.UserName.ToLower().Contains(usernameToMatch.ToLower())).ToListAsync(); users.Wait(); return users.Result.Select(r => r.UserName).ToArray(); } public override string[] GetAllRoles() { Task> roles = _roleCollection.Find(new BsonDocument()).ToListAsync(); roles.Wait(); return roles.Result.Select(r => r.RoleName).ToArray(); } public override string[] GetRolesForUser(string username) { Task user = _memberCollection.Find(u => u.UserName.ToLower() == username.ToLower()).SingleOrDefaultAsync(); user.Wait(); if (user.Result == null) { return Array.Empty(); } Task> role = _roleCollection.Find(r => r.Users != null && r.Users.Contains(user.Result.Id)).ToListAsync(); role.Wait(); return role.Result.Select(r => r.RoleName).ToArray(); } public override string[] GetUsersInRole(string roleName) { Task role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync(); role.Wait(); if (role.Result == null) { return Array.Empty(); } Task> users = _memberCollection.Find(u => role.Result.Users.Contains(u.Id)).ToListAsync(); users.Wait(); return users.Result.Select(u => u.UserName).ToArray(); } public override bool IsUserInRole(string username, string roleName) { Task user = _memberCollection.Find(u => u.UserName.ToLower() == username.ToLower()).SingleOrDefaultAsync(); Task role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync(); user.Wait(); role.Wait(); if (user.Result == null || role.Result?.Users == null) { return false; } return role.Result.Users.Contains(user.Result.Id); } public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) { Task> roleTask = _roleCollection.Find(r => roleNames.Contains(r.RoleName)).ToListAsync(); roleTask.Wait(); List roles = roleTask.Result; Task> userTask = _memberCollection.Find(u => usernames.Contains(u.UserName)).ToListAsync(); userTask.Wait(); List users = userTask.Result; foreach (MongoRole t in roles) { t.Users = (from u in t.Users where users.All(v => v.Id != u) select u).ToArray(); Task update = _roleCollection.ReplaceOneAsync(Builders.Filter.Eq(r => r.Id, t.Id), t); update.Wait(); } } public override bool RoleExists(string roleName) { Task role = _roleCollection.Find(r => r.RoleName == roleName).SingleOrDefaultAsync(); role.Wait(); return role.Result != null; } } [DataObject] public class MongoRole { [BsonId] public Guid Id { get; set; } public string RoleName { get; set; } public Guid[] Users { get; set; } } }