context: // ---------------------------------------------------------------------- //
  //                                                                        //
  //                       Copyright (c) 2007-2014                          //
  //                         Digital Beacon, LLC                            //
  //                                                                        //
  // ---------------------------------------------------------------------- //
  
  using System;
  using System.Collections.Generic;
  using System.Globalization;
  using System.Linq;
  using System.Reflection;
  using System.Web;
  using System.Web.Security;
  using Common.Logging;
  using DigitalBeacon.Business;
  using DigitalBeacon.Business.Support;
  using DigitalBeacon.Model;
  using DigitalBeacon.SiteBase.Data;
  using DigitalBeacon.SiteBase.Model;
  using DigitalBeacon.Util;
  
  namespace DigitalBeacon.SiteBase.Business.Support
  {
  	public class IdentityService : BaseService, IIdentityService
  	{
  		#region Private Members
  
  		private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  
  		private const string ChangedPassword = "Changed Password";
  		private const string ChangedSecurityChallege = "Changed Security Question/Answer";
  		private const string ChangedIsApproved = "IsApproved = {0}";
  
  		private static readonly VersionedEntityHelper VersionHelper = new VersionedEntityHelper();
  		private static readonly IPersonDao PersonDao = ServiceFactory.Instance.GetService<IPersonDao>();
  		private static readonly IUserDao UserDao = ServiceFactory.Instance.GetService<IUserDao>();
  		private static readonly IRoleDao RoleDao = ServiceFactory.Instance.GetService<IRoleDao>();
  		private static readonly IRoleGroupDao RoleGroupDao = ServiceFactory.Instance.GetService<IRoleGroupDao>();
  		private static readonly IRoleHomeDao RoleHomeDao = ServiceFactory.Instance.GetService<IRoleHomeDao>();
  		private static readonly IMailService MailService = ServiceFactory.Instance.GetService<IMailService>();
  		private static readonly IModuleService ModuleService = ServiceFactory.Instance.GetService<IModuleService>();
  
  		#endregion
  
  		#region IIdentityService Members
  
  		public AuthenticationStatus AuthenticateUser(string username, string password)
  		{
  			var retVal = AuthenticationStatus.Failed;
  
  			if (MembershipValidateUser(username, password) || ValidateDemoUser(username, password))
  			{
  				var user = UserDao.FetchByUsername(username);
  				if (user != null)
  				{
  					var associationId = GetCurrentAssociationId();
  					var isAssociated = user.SuperUser;
  					if (!isAssociated)
  					{
  						foreach (var ae in user.Associations)
  						{
  							if (ae.Id == associationId)
  							{
  								isAssociated = true;
  								break;
  							}
  						}
  					}
  					if (isAssociated)
  					{
  						GetMembershipUserInfo(user);
  						if (Membership.Provider.Name == BusinessConstants.SqlMembershipProvider && String.IsNullOrEmpty(user.SecurityQuestion))
  						{
  							retVal = AuthenticationStatus.PasswordUpdateRequired;
  						}
  						else
  						{
  							AuditingService.CreateAuditLogEntry(AuditAction.LogIn, associationId, user.Id, String.Empty);
  							retVal = AuthenticationStatus.Success;
  						}
  					}
  					else
  					{
  						Log.Error(String.Format("User with username [{0}] authenticated but was not associated with association Id [{1}].", username, associationId));
  					}
  				}
  				else
  				{
  					Log.Error(String.Format("Authenticated ASP.NET user with username [{0}] but could not locate UserEntity with that username.", username));
  				}
  			}
  			if (retVal == AuthenticationStatus.Failed)
  			{
  				var aspNetUser = MembershipGetUser(username);
  				if (aspNetUser != null && aspNetUser.IsLockedOut)
  				{
  					retVal = AuthenticationStatus.AccountLocked;
  				}
  				AuditingService.CreateAuditLogEntry(AuditAction.LogInFailed, GetCurrentAssociationId(), username);
  			}
  			return retVal;
  		}
  
  		public void SignOutUser()
  		{
  			var user = GetCurrentUser();
  			if (user != null)
  			{
  				AuditingService.CreateAuditLogEntry(AuditAction.LogOut, GetCurrentAssociationId(), user.Id, String.Empty);
  			}
  		}
  
  		public bool IsUsernameAvailable(string username)
  		{
  			return GetUser(username) == null && Membership.Providers[BusinessConstants.SqlMembershipProvider].GetUser(username, false) == null;
  		}
  
  		public RegistrationResponse RegisterUser(UserEntity user, bool selfRegistration, bool sendEmail)
  		{
  			var retVal = new RegistrationResponse { Status = RegistrationStatus.NonSpecifiedError };
  			try
  			{
  				MembershipCreateStatus createStatus;
  				MembershipProvider provider;
  				if (selfRegistration)
  				{
  					provider = Membership.Providers[BusinessConstants.SqlMembershipProvider];
  				}
  				else
  				{
  					provider = Membership.Providers[BusinessConstants.AdminMembershipProvider];
  					if (provider == null)
  					{
  						throw new ServiceException("Could not find admin membership provider [{0}].", BusinessConstants.AdminMembershipProvider);
  					}
  					if (user.SecurityQuestion.IsNullOrBlank())
  					{
  						user.SecurityQuestion = null;
  					}
  					if (user.SecurityAnswer.IsNullOrBlank())
  					{
  						user.SecurityAnswer = null;
  					}
  					if (String.IsNullOrEmpty(user.Password))
  					{
  						user.Password = Membership.GeneratePassword(10, 1);
  					}
  				}
  				provider.CreateUser(user.Username, user.Password, user.Email, user.SecurityQuestion, user.SecurityAnswer, user.Approved, null, out createStatus);
  				if (createStatus == MembershipCreateStatus.Success)
  				{
  					var password = user.Password;
  					user.Person = SaveWithAudit(user.Person);
  					user.DisplayName = GetDisplayName(user);
  					user = DataAdapter.Save(user);
  					var msDef = selfRegistration ? ModuleSettingDefinition.RegistrationEmailSubmitted : ModuleSettingDefinition.RegistrationEmailUserCreatedByAdmin;
  					var ms = ModuleService.GetGlobalModuleSetting(msDef, user.Language);
  					var msg = new MessageInfo { UserId = user.Id, Subject = ms.Subject };
  					var substitutions = new Dictionary<SubstitutionDefinition, string>();
  					substitutions[SubstitutionDefinition.UserDisplayName] = user.DisplayName;
  					if (selfRegistration)
  					{
  						var ms2 = ModuleService.GetGlobalModuleSetting(ModuleSettingDefinition.GlobalSiteUrl);
  						var ms3 = ModuleService.GetGlobalModuleSetting(ModuleSettingDefinition.RegistrationUrlConfirmBaseUrl);
  						var confirmUrl = "{0}{1}?token={2}".FormatWith(ms2.Value, ms3.Value, MembershipGetUser(user.Username).ProviderUserKey);
  						if (user.Language != null)
  						{
  							confirmUrl = "{0}&{1}={2}".FormatWith(confirmUrl, BusinessConstants.PersistentLanguageKey, (long)user.Language.Value);
  						}
  						substitutions[SubstitutionDefinition.ConfirmRegistrationUrl] = confirmUrl;
  					}
  					else
  					{
  						substitutions[SubstitutionDefinition.Username] = user.Username;
  						substitutions[SubstitutionDefinition.Password] = password;
  					}
  					msg.Body = ModuleService.GetModuleSettingValueWithSubstitutions(ms, substitutions);
  					var queuedEmailId = MailService.QueueEmail(user.Associations[0].Id, msg);
  					if (!sendEmail)
  					{
  						var qe = MailService.GetQueuedEmail(queuedEmailId);
  						qe.DateProcessed = DateTime.Now;
  						qe.ErrorMessage = "Email notification was suppressed.";
  					}
  					retVal.UserId = user.Id;
  					retVal.Status = RegistrationStatus.Success;
  					user.Password = String.Empty;
  					user.SecurityAnswer = String.Empty;
  					AuditingService.CreateAuditLogEntry(AuditAction.CreateEntity, user.Associations[0].Id, selfRegistration ? user.Id : GetCurrentUser().Id, user, user.ToString());
  				}
  				else if (createStatus == MembershipCreateStatus.DuplicateUserName)
  				{
  					retVal.Status = RegistrationStatus.DuplicateUsername;
  				}
  				else if (createStatus == MembershipCreateStatus.DuplicateEmail)
  				{
  					retVal.Status = RegistrationStatus.DuplicateEmail;
  				}
  			}
  			catch (Exception ex)
  			{
  				Log.Error(ex);
  				throw;
  			}
  			return retVal;
  		}
  
  		public string GetUsernameByRegistrationToken(string token)
  		{
  			string retVal = null;
  			var userId = token.ToGuid();
  			if (userId == null)
  			{
  				throw new ServiceException("The token [{0}] is not a valid Guid.", token);
  			}
  			var aspNetUser = Membership.GetUser(userId.Value);
  			if (aspNetUser != null && !aspNetUser.IsApproved)
  			{
  				retVal = aspNetUser.UserName;
  			}
  			return retVal;
  		}
  
  		public void SetUserEnabled(string username, bool enabled)
  		{
  			if (Membership.Provider.Name != BusinessConstants.SqlMembershipProvider)
  			{
  				return;
  			}
  			var aspNetUser = MembershipGetUser(username);
  			if (aspNetUser == null)
  			{
  				throw new ServiceException("Could not find ASP.NET user with username [{0}].", username);
  			}
  			var user = GetUser(username);
  			if (user == null)
  			{
  				throw new ServiceException("Could not find user entity with username [{0}].", username);
  			}
  			aspNetUser.IsApproved = enabled;
  			Membership.UpdateUser(aspNetUser);
  			var currentUser = GetCurrentUser();
  			AuditingService.CreateAuditLogEntry(AuditAction.UpdateEntity, GetCurrentAssociationId(), currentUser != null ? currentUser.Id : user.Id, user, String.Format(ChangedIsApproved, enabled));
  		}
  
  		public void ConfirmRegistration(string token)
  		{
  			var username = GetUsernameByRegistrationToken(token);
  			if (String.IsNullOrEmpty(username))
  			{
  				throw new ServiceException("Could not find username for the registration token [{0}].", token);
  			}
  			var user = UserDao.FetchByUsername(GetCurrentAssociationId(), username);
  			if (user == null)
  			{
  				throw new ServiceException("Could not find user with username [{0}].", username);
  			}
  			user.AddRole(GetCurrentAssociationId(), Role.User);
  			UserDao.Save(user);
  			SetUserEnabled(username, true);
  			var ms = ModuleService.GetGlobalModuleSetting(ModuleSettingDefinition.RegistrationEmailComplete, user.Language);
  			var msg = new MessageInfo { UserId = user.Id, Subject = ms.Subject };
  			var substitutions = new Dictionary<SubstitutionDefinition, string>();
  			substitutions[SubstitutionDefinition.UserDisplayName] = user.DisplayName;
  			msg.Body = ModuleService.GetModuleSettingValueWithSubstitutions(ms, substitutions);
  			MailService.QueueEmail(GetCurrentAssociationId(), msg);
  		}
  
  		public UserEntity GetUser(long userId)
  		{
  			var user = UserDao.Fetch(userId);
  			if (user != null)
  			{
  				GetMembershipUserInfo(user);
  			}
  			return user;
  		}
  
  		public UserEntity GetUser(string username)
  		{
  			var user = UserDao.FetchByUsername(username);
  			if (user != null)
  			{
  				GetMembershipUserInfo(user);
  			}
  			return user;
  		}
  
  		public UserEntity GetUserByEmail(string email)
  		{
  			UserEntity retVal = null;
  			var username = Membership.GetUserNameByEmail(email);
  			if (username.HasText())
  			{
  				retVal = GetUser(username);
  			}
  			return retVal;
  		}
  
  		public IList<UserEntity> GetUsersByRole(long associationId, Role role)
  		{
  			var users = UserDao.FetchByRole(associationId, role);
  			foreach (var user in users)
  			{
  				GetMembershipUserInfo(user);
  			}
  			return users;
  		}
  
  		public UserEntity GetCurrentUser()
  		{
  			return GetUser(HttpContext.Current.User.Identity.Name);
  		}
  
  		public IList<UserEntity> GetAllUsers()
  		{
  			var users = UserDao.FetchActive(GetCurrentAssociationId());
  			foreach (var user in users)
  			{
  				GetMembershipUserInfo(user);
  			}
  			return users;
  		}
  
  		public IList<UserEntity> GetUsers(UserSearchInfo searchInfo)
  		{
  			var users = UserDao.FetchUsers(searchInfo);
  			foreach (var user in users)
  			{
  				GetMembershipUserInfo(user);
  			}
  			return users;
  		}
  
  		public int GetUserCount(UserSearchInfo searchInfo)
  		{
  			return UserDao.FetchUserCount(searchInfo);
  		}
  
  		public IList<SecurityQuestionEntity> GetSecurityQuestions()
  		{
  			return LocalizeRegistered(DataAdapter.FetchAll<SecurityQuestionEntity>(BaseEntity.DisplayOrderProperty));
  		}
  
  		public void UpdateUser(UserEntity user)
  		{
  			var provider = Membership.Providers[BusinessConstants.AdminMembershipProvider];
  			if (provider == null)
  			{
  				throw new ServiceException("Could not find admin membership provider [{0}].", BusinessConstants.AdminMembershipProvider);
  			}
  			var aspNetUser = provider.GetUser(user.Username, false);
  			if (aspNetUser == null)
  			{
  				throw new ServiceException("Could not find ASP.NET user with username [{0}].", user.Username);
  			}
  			if (user.Password.HasText())
  			{
  				aspNetUser.ChangePassword(aspNetUser.ResetPassword(), user.Password);
  				if (user.SecurityQuestion.HasText() && user.SecurityAnswer.HasText())
  				{
  					aspNetUser.ChangePasswordQuestionAndAnswer(user.Password, user.SecurityQuestion, user.SecurityAnswer);
  				}
  			}
  
gt: 			if (aspNetUser.IsLockedOut && !user.LockedOut)