// Copyright (c) 2012, Outercurve Foundation. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // - Neither the name of the Outercurve Foundation nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using System; using System.Data; using System.Collections; using System.Collections.Generic; using System.Xml; using System.Net.Mail; using System.Text.RegularExpressions; using System.Xml.Linq; namespace WebsitePanel.EnterpriseServer { /// /// Summary description for UserController. /// public class UserController { public static bool UserExists(string username) { // try to get user from database UserInfo user = GetUserInternally(username); return (user != null); } public static int AuthenticateUser(string username, string password, string ip) { // start task TaskManager.StartTask("USER", "AUTHENTICATE", username); TaskManager.WriteParameter("IP", ip); try { // try to get user from database UserInfo user = GetUserInternally(username); // check if the user exists if (user == null) { TaskManager.WriteWarning("Wrong username"); return BusinessErrorCodes.ERROR_USER_WRONG_USERNAME; } // check if the user is disabled if (user.LoginStatus == UserLoginStatus.Disabled) { TaskManager.WriteWarning("User disabled"); return BusinessErrorCodes.ERROR_USER_ACCOUNT_DISABLED; } // check if the user is locked out if (user.LoginStatus == UserLoginStatus.LockedOut) { TaskManager.WriteWarning("User locked out"); return BusinessErrorCodes.ERROR_USER_ACCOUNT_LOCKEDOUT; } //Get the password policy UserSettings userSettings = UserController.GetUserSettings(user.UserId, UserSettings.WEBSITEPANEL_POLICY); int lockOut = -1; if (!string.IsNullOrEmpty(userSettings["PasswordPolicy"])) { string passwordPolicy = userSettings["PasswordPolicy"]; try { // parse settings string[] parts = passwordPolicy.Split(';'); lockOut = Convert.ToInt32(parts[7]); } catch { /* skip */ } } // compare user passwords if (user.Password != password) { if (lockOut >= 0) DataProvider.UpdateUserFailedLoginAttempt(user.UserId, lockOut, false); TaskManager.WriteWarning("Wrong password"); return BusinessErrorCodes.ERROR_USER_WRONG_PASSWORD; } else DataProvider.UpdateUserFailedLoginAttempt(user.UserId, lockOut, true); // check status if (user.Status == UserStatus.Cancelled) { TaskManager.WriteWarning("Account cancelled"); return BusinessErrorCodes.ERROR_USER_ACCOUNT_CANCELLED; } if (user.Status == UserStatus.Pending) { TaskManager.WriteWarning("Account pending"); return BusinessErrorCodes.ERROR_USER_ACCOUNT_PENDING; } return 0; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } public static UserInfo GetUserByUsernamePassword(string username, string password, string ip) { // place log record TaskManager.StartTask("USER", "GET_BY_USERNAME_PASSWORD", username); TaskManager.WriteParameter("IP", ip); try { // try to get user from database UserInfo user = GetUserInternally(username); // check if the user exists if (user == null) { TaskManager.WriteWarning("Account not found"); return null; } // compare user passwords if (user.Password == password) return user; return null; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } public static int ChangeUserPassword(string username, string oldPassword, string newPassword, string ip) { // place log record TaskManager.StartTask("USER", "CHANGE_PASSWORD_BY_USERNAME_PASSWORD", username); TaskManager.WriteParameter("IP", ip); try { UserInfo user = GetUserByUsernamePassword(username, oldPassword, ip); if (user == null) { TaskManager.WriteWarning("Account not found"); return BusinessErrorCodes.ERROR_USER_NOT_FOUND; } // change password DataProvider.ChangeUserPassword(-1, user.UserId, CryptoUtils.Encrypt(newPassword)); return 0; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } public static int SendPasswordReminder(string username, string ip) { // place log record TaskManager.StartTask("USER", "SEND_REMINDER", username); TaskManager.WriteParameter("IP", ip); try { // try to get user from database UserInfo user = GetUserInternally(username); if (user == null) { TaskManager.WriteWarning("Account not found"); // Fix for item #273 (NGS-9) //return BusinessErrorCodes.ERROR_USER_NOT_FOUND; return 0; } UserSettings settings = UserController.GetUserSettings(user.UserId, UserSettings.PASSWORD_REMINDER_LETTER); string from = settings["From"]; string cc = settings["CC"]; string subject = settings["Subject"]; string body = user.HtmlMail ? settings["HtmlBody"] : settings["TextBody"]; bool isHtml = user.HtmlMail; MailPriority priority = MailPriority.Normal; if (!String.IsNullOrEmpty(settings["Priority"])) priority = (MailPriority)Enum.Parse(typeof(MailPriority), settings["Priority"], true); if (body == null || body == "") return BusinessErrorCodes.ERROR_SETTINGS_PASSWORD_LETTER_EMPTY_BODY; // set template context items Hashtable items = new Hashtable(); items["user"] = user; items["Email"] = true; // get reseller details UserInfo reseller = UserController.GetUser(user.OwnerId); if (reseller != null) { reseller.Password = ""; items["reseller"] = reseller; } subject = PackageController.EvaluateTemplate(subject, items); body = PackageController.EvaluateTemplate(body, items); // send message MailHelper.SendMessage(from, user.Email, cc, subject, body, priority, isHtml); return 0; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } internal static UserInfo GetUserInternally(int userId) { // try to get user from database UserInfo user = ObjectUtils.FillObjectFromDataReader( DataProvider.GetUserByIdInternally(userId)); if (user != null) user.Password = CryptoUtils.Decrypt(user.Password); return user; } internal static UserInfo GetUserInternally(string username) { // try to get user from database UserInfo user = ObjectUtils.FillObjectFromDataReader( DataProvider.GetUserByUsernameInternally(username)); if (user != null) { user.Password = CryptoUtils.Decrypt(user.Password); } return user; } public static UserInfo GetUser(int userId) { // try to get user from database UserInfo user = ObjectUtils.FillObjectFromDataReader( DataProvider.GetUserById(SecurityContext.User.UserId, userId)); if (user != null) user.Password = CryptoUtils.Decrypt(user.Password); return user; } public static UserInfo GetUser(string username) { // try to get user from database UserInfo user = ObjectUtils.FillObjectFromDataReader( DataProvider.GetUserByUsername(SecurityContext.User.UserId, username)); if (user != null) user.Password = CryptoUtils.Decrypt(user.Password); return user; } public static List GetUserParents(int userId) { // get users from database DataSet dsUsers = DataProvider.GetUserParents(SecurityContext.User.UserId, userId); // convert to arraylist List users = new List(); ObjectUtils.FillCollectionFromDataSet(users, dsUsers); return users; } public static List GetUsers(int userId, bool recursive) { // get users from database DataSet dsUsers = DataProvider.GetUsers(SecurityContext.User.UserId, userId, recursive); // convert to arraylist List users = new List(); ObjectUtils.FillCollectionFromDataSet(users, dsUsers); return users; } public static DataSet GetUsersPaged(int userId, string filterColumn, string filterValue, int statusId, int roleId, string sortColumn, int startRow, int maximumRows) { // get users from database return DataProvider.GetUsersPaged(SecurityContext.User.UserId, userId, filterColumn, filterValue, statusId, roleId, sortColumn, startRow, maximumRows, false); } public static DataSet GetUsersPagedRecursive(int userId, string filterColumn, string filterValue, int statusId, int roleId, string sortColumn, int startRow, int maximumRows) { // get users from database return DataProvider.GetUsersPaged(SecurityContext.User.UserId, userId, filterColumn, filterValue, statusId, roleId, sortColumn, startRow, maximumRows, true); } public static DataSet GetUsersSummary(int userId) { return DataProvider.GetUsersSummary(SecurityContext.User.UserId, userId); } public static DataSet GetUserDomainsPaged(int userId, string filterColumn, string filterValue, string sortColumn, int startRow, int maximumRows) { // get users from database return DataProvider.GetUserDomainsPaged(SecurityContext.User.UserId, userId, filterColumn, filterValue, sortColumn, startRow, maximumRows); } public static List GetUserPeers(int userId) { // get user peers from database return ObjectUtils.CreateListFromDataSet(GetRawUserPeers(userId)); } public static DataSet GetRawUserPeers(int userId) { // get user peers from database return DataProvider.GetUserPeers(SecurityContext.User.UserId, userId); } public static DataSet GetRawUsers(int ownerId, bool recursive) { // get users from database return DataProvider.GetUsers(SecurityContext.User.UserId, ownerId, recursive); } public static int AddUser(UserInfo user, bool sendLetter) { // check account int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo); if (accountCheck < 0) return accountCheck; string pattern = @"[\\/:*?<>|""]+"; if (String.IsNullOrEmpty(user.Username)) return BusinessErrorCodes.ERROR_INVALID_USER_NAME; if (Regex.IsMatch(user.Username, pattern)) return BusinessErrorCodes.ERROR_INVALID_USER_NAME; if (UserExists(user.Username)) return BusinessErrorCodes.ERROR_USER_ALREADY_EXISTS; // only administrators can set admin role if (!SecurityContext.User.IsInRole(SecurityContext.ROLE_ADMINISTRATOR) && user.Role == UserRole.Administrator) user.Role = UserRole.User; // check integrity when creating a user account if (user.Role == UserRole.User) user.EcommerceEnabled = false; // place log record TaskManager.StartTask("USER", "ADD", user.Username); try { // add user to database int userId = DataProvider.AddUser( SecurityContext.User.UserId, user.OwnerId, user.RoleId, user.StatusId, user.SubscriberNumber, user.LoginStatusId, user.IsDemo, user.IsPeer, user.Comments, user.Username.Trim(), CryptoUtils.Encrypt(user.Password), user.FirstName, user.LastName, user.Email, user.SecondaryEmail, user.Address, user.City, user.Country, user.State, user.Zip, user.PrimaryPhone, user.SecondaryPhone, user.Fax, user.InstantMessenger, user.HtmlMail, user.CompanyName, user.EcommerceEnabled); if (userId == -1) { TaskManager.WriteWarning("Account with such username already exists"); return BusinessErrorCodes.ERROR_USER_ALREADY_EXISTS; } BackgroundTask topTask = TaskController.GetTopTask(); topTask.ItemId = userId; topTask.UpdateParamValue("SendLetter", sendLetter); TaskController.UpdateTask(topTask); return userId; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } const string userAdditionalParamsTemplate = @""; public static void AddUserVLan(int userId, UserVlan vLan) { UserInfo user = GetUser(userId); // if (user == null) throw new ApplicationException(String.Format("User with UserID={0} not found", userId)); XDocument doc = XDocument.Parse(user.AdditionalParams ?? userAdditionalParamsTemplate); XElement vlans = doc.Root.Element("VLans"); vlans.Add(new XElement("VLan", new XAttribute("VLanID", vLan.VLanID), new XAttribute("Comment", vLan.Comment))); user.AdditionalParams = doc.ToString(); UpdateUser(user); } public static void DeleteUserVLan(int userId, ushort vLanId) { UserInfo user = GetUser(userId); // if (user == null) throw new ApplicationException(String.Format("User with UserID={0} not found", userId)); XDocument doc = XDocument.Parse(user.AdditionalParams ?? userAdditionalParamsTemplate); XElement vlans = doc.Root.Element("VLans"); if (vlans != null) foreach (XElement element in vlans.Elements("VLan")) if (ushort.Parse(element.Attribute("VLanID").Value) == vLanId) element.Remove(); user.AdditionalParams = doc.ToString(); UpdateUser(user); } public static int UpdateUser(UserInfo user) { return UpdateUser(null, user); } public static int UpdateUserAsync(string taskId, UserInfo user) { UserAsyncWorker usersWorker = new UserAsyncWorker(); usersWorker.ThreadUserId = SecurityContext.User.UserId; usersWorker.TaskId = taskId; usersWorker.User = user; usersWorker.UpdateUserAsync(); return 0; } public static int UpdateUser(string taskId, UserInfo user) { try { // start task TaskManager.StartTask(taskId, "USER", "UPDATE", user.Username, user.UserId); // check account int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo); if (accountCheck < 0) return accountCheck; UserInfo currentUser = GetUser(user.UserId); //prevent downgrade reseller with child accounts to user role if (currentUser.RoleId.Equals(2)) { if (user.RoleId.Equals(3)) { // check if user has child accounts (It happens when Reseller has child accounts and admin changes his role to User) if (GetUsers(currentUser.UserId, false).Count > 0) return BusinessErrorCodes.ERROR_USER_HAS_USERS; } } // only administrators can set admin role if (!SecurityContext.User.IsInRole(SecurityContext.ROLE_ADMINISTRATOR) && user.Role == UserRole.Administrator) user.Role = UserRole.User; // check integrity when creating a user account if (user.Role == UserRole.User) user.EcommerceEnabled = false; //// task progress //int maxSteps = 100; //TaskManager.IndicatorMaximum = maxSteps; //for (int i = 0; i < maxSteps; i++) //{ // TaskManager.Write(String.Format("Step {0} of {1}", i, maxSteps)); // TaskManager.IndicatorCurrent = i; // System.Threading.Thread.Sleep(1000); //} DataProvider.UpdateUser( SecurityContext.User.UserId, user.UserId, user.RoleId, user.StatusId, user.SubscriberNumber, user.LoginStatusId, user.IsDemo, user.IsPeer, user.Comments, user.FirstName, user.LastName, user.Email, user.SecondaryEmail, user.Address, user.City, user.Country, user.State, user.Zip, user.PrimaryPhone, user.SecondaryPhone, user.Fax, user.InstantMessenger, user.HtmlMail, user.CompanyName, user.EcommerceEnabled, user.AdditionalParams); return 0; } catch (System.Threading.ThreadAbortException ex) { TaskManager.WriteError(ex, "The process has been terminated by the user."); return 0; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } public static int DeleteUser(int userId) { return DeleteUser(null, userId); } public static int DeleteUser(string taskId, int userId) { // check account int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo); if (accountCheck < 0) return accountCheck; // check if user has child accounts if (GetUsers(userId, false).Count > 0) return BusinessErrorCodes.ERROR_USER_HAS_USERS; UserAsyncWorker userWorker = new UserAsyncWorker(); userWorker.ThreadUserId = SecurityContext.User.UserId; userWorker.UserId = userId; userWorker.TaskId = taskId; userWorker.DeleteUserAsync(); return 0; } public static int ChangeUserPassword(int userId, string password) { // check account int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo); if (accountCheck < 0) return accountCheck; // get user details UserInfo user = GetUserInternally(userId); // place log record TaskManager.StartTask("USER", "CHANGE_PASSWORD", user.Username, user.UserId); try { DataProvider.ChangeUserPassword(SecurityContext.User.UserId, userId, CryptoUtils.Encrypt(password)); return 0; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } public static int ChangeUserStatus(int userId, UserStatus status) { return ChangeUserStatus(null, userId, status); } public static int ChangeUserStatus(string taskId, int userId, UserStatus status) { // check account int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo); if (accountCheck < 0) return accountCheck; int result = 0; // get user details UserInfo user = GetUserInternally(userId); // place log record TaskManager.StartTask(taskId, "USER", "CHANGE_STATUS", user.Username, user.UserId); // update user packages List packages = new List(); // Add the users package(s) packages.AddRange(PackageController.GetPackages(userId)); try { // change this account result = ChangeUserStatusInternal(userId, status); if (result < 0) return result; // change peer accounts List peers = GetUserPeers(userId); foreach (UserInfo peer in peers) { result = ChangeUserStatusInternal(peer.UserId, status); if (result < 0) return result; } // change child accounts List children = GetUsers(userId, true); foreach (UserInfo child in children) { // Add the child users packages packages.AddRange(PackageController.GetPackages(child.UserId)); // change child user peers List childPeers = GetUserPeers(child.UserId); foreach (UserInfo peer in childPeers) { result = ChangeUserStatusInternal(peer.UserId, status); if (result < 0) return result; } // change child account result = ChangeUserStatusInternal(child.UserId, status); if (result < 0) return result; } PackageStatus packageStatus = PackageStatus.Active; switch (status) { case UserStatus.Active: packageStatus = PackageStatus.Active; break; case UserStatus.Cancelled: packageStatus = PackageStatus.Cancelled; break; case UserStatus.Pending: packageStatus = PackageStatus.New; break; case UserStatus.Suspended: packageStatus = PackageStatus.Suspended; break; } // change packages state result = PackageController.ChangePackagesStatus(packages, packageStatus, true); if (result < 0) return result; return 0; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } private static int ChangeUserStatusInternal(int userId, UserStatus status) { // get user details UserInfo user = GetUser(userId); if (user != null && user.Status != status) { // change status user.Status = status; // save user UpdateUser(user); } return 0; } #region User Settings public static UserSettings GetUserSettings(int userId, string settingsName) { IDataReader reader = DataProvider.GetUserSettings( SecurityContext.User.UserId, userId, settingsName); UserSettings settings = new UserSettings(); settings.UserId = userId; settings.SettingsName = settingsName; while (reader.Read()) { settings.UserId = (int)reader["UserID"]; settings[(string)reader["PropertyName"]] = (string)reader["PropertyValue"]; } reader.Close(); return settings; } public static int UpdateUserSettings(UserSettings settings) { // check account int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo); if (accountCheck < 0) return accountCheck; // get user details UserInfo user = GetUserInternally(settings.UserId); // place log record TaskManager.StartTask("USER", "UPDATE_SETTINGS", user.Username, user.UserId); try { // build xml XmlDocument doc = new XmlDocument(); XmlElement nodeProps = doc.CreateElement("properties"); if (settings.SettingsArray != null) { foreach (string[] pair in settings.SettingsArray) { XmlElement nodeProp = doc.CreateElement("property"); nodeProp.SetAttribute("name", pair[0]); nodeProp.SetAttribute("value", pair[1]); nodeProps.AppendChild(nodeProp); } } string xml = nodeProps.OuterXml; // update settings DataProvider.UpdateUserSettings(SecurityContext.User.UserId, settings.UserId, settings.SettingsName, xml); return 0; } catch (Exception ex) { throw TaskManager.WriteError(ex); } finally { TaskManager.CompleteTask(); } } #endregion } }