569 lines
22 KiB
C#
569 lines
22 KiB
C#
///
|
|
/// Copyright (c) 2016-2019 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using log4net;
|
|
using Users.Forms;
|
|
using Users.Resources;
|
|
|
|
namespace Users.Entities
|
|
{
|
|
public class User
|
|
{
|
|
static readonly ILog log = LogManager.GetLogger(typeof(User));
|
|
|
|
public virtual int Id { get; protected set; }
|
|
public virtual string UserName { get; set; } /// = name, alias, abbreviation
|
|
public virtual string FullName { get; set; } /// = description
|
|
public virtual string Tag { get; set; }
|
|
public virtual int Number { get; set; }
|
|
public virtual string Password { get; set; }
|
|
public virtual string Password2 { get; set; }
|
|
public virtual string Password3 { get; set; }
|
|
public virtual string Password4 { get; set; }
|
|
public virtual DateTime LastPwChange { get; set; }
|
|
public virtual IList<Group> Groups { get; set; } //User can be a member of a list of groups
|
|
|
|
private bool powerUser; /// true for built-in users, power users have full access even with empty Groups list
|
|
public virtual bool IsPowerUser() { return powerUser; }
|
|
|
|
private string legalizator; /// Not mapped to a database !!!, 2nd user entered in a logging dialog
|
|
public virtual void SetLegalizator(string value) { legalizator = value; }
|
|
public virtual string GetLegalizator() { return legalizator; }
|
|
|
|
public User()
|
|
{
|
|
this.powerUser = false;
|
|
Groups = new List<Group>();
|
|
Number = 0;
|
|
Tag = string.Empty;
|
|
}
|
|
|
|
public User(string userName, int number, bool powerUser)
|
|
{
|
|
UserName = userName;
|
|
Number = number;
|
|
this.powerUser = powerUser;
|
|
Groups = new List<Group>();
|
|
FullName = powerUser ? "Power User" : string.Empty;
|
|
}
|
|
|
|
public virtual void AddGroup(Group group)
|
|
{
|
|
Groups.Add(group);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// All members are copied except of ID (so that NHibernate works properly).
|
|
/// List of groups is empty.
|
|
/// </summary>
|
|
/// <param name="user"></param>
|
|
/// <returns></returns>
|
|
public virtual object Clone()
|
|
{
|
|
User newUser = new User(UserName, Number, false);
|
|
newUser.FullName = FullName;
|
|
newUser.Number = Number;
|
|
newUser.Tag = Tag;
|
|
newUser.Password = Password;
|
|
newUser.LastPwChange = LastPwChange;
|
|
return newUser;
|
|
}
|
|
|
|
/// ------------- Additional stuff not mapped into the database -------------
|
|
|
|
/// <summary>
|
|
/// Check whether user is a member of a group.
|
|
/// </summary>
|
|
/// <param name="groupId">Group GID</param>
|
|
/// <returns>true is user is a member of the specified group</returns>
|
|
public virtual bool IsMemberOf(GID groupId)
|
|
{
|
|
if (powerUser)
|
|
{
|
|
return true;
|
|
}
|
|
else if ((groupId >= 0) && (groupId < GID.NrOfGroups) && (Groups != null))
|
|
{
|
|
foreach (var g in Groups)
|
|
{
|
|
if (g.GID == groupId) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check whether user is a member of any of specified groups.
|
|
/// Returns true also when no groups are defined (groupIds = null).
|
|
/// </summary>
|
|
/// <param name="groupIds">An array of group GID-s or null (no membership required)</param>
|
|
/// <returns>true if user is a member of any of specified groups</returns>
|
|
public virtual bool IsMemberOf(GID[] groupIds)
|
|
{
|
|
if (groupIds == null || powerUser)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
foreach (var gid in groupIds)
|
|
{
|
|
if (gid >= 0 && gid < GID.NrOfGroups)
|
|
{
|
|
/// for all group elements in User.Groups
|
|
foreach (var grp in Groups)
|
|
{
|
|
/// element GID = parameter GroupId ?
|
|
if (grp.GID == gid) return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks requirements on the password regardless of the password history
|
|
/// </summary>
|
|
/// <param name="password">Password</param>
|
|
/// <returns>true when the password is OK</returns>
|
|
public static bool IsPasswordMeetsRequirements(string password, out string explanation)
|
|
{
|
|
int length = string.IsNullOrEmpty(password) ? 0 : password.Length;
|
|
|
|
/// Password length must be at least 6
|
|
if (length < GlobalData.MinPasswdLength)
|
|
{
|
|
explanation = string.Format(Strings.Password_must_have_at_least_0_characters, GlobalData.MinPasswdLength);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
explanation = string.Empty;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true when password was already used in the past
|
|
/// </summary>
|
|
/// <param name="passwordCandidate">Password</param>
|
|
/// <returns>false when password is new, true when it was used in the past</returns>
|
|
public virtual bool IsPasswordUsedInPast(string passwordCandidate)
|
|
{
|
|
string encryptedPW = EncryptedPassword(passwordCandidate);
|
|
return (encryptedPW == Password) || (encryptedPW == Password2) || (encryptedPW == Password3);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks 'LastPwChange' and returns true when password expired
|
|
/// </summary>
|
|
/// <returns></ returns>
|
|
bool IsPasswordExpired()
|
|
{
|
|
if (IsPowerUser() || IsMemberOf(GID.Administrators) || GlobalData.PasswdExpirationPeriodDays == 0)
|
|
{
|
|
/// Password cannot expirate for this user or this feature is disabled in Backup and Security options
|
|
return false;
|
|
}
|
|
|
|
/// Password expiration time is 3 months
|
|
return (DateTime.Now - LastPwChange > new TimeSpan(GlobalData.PasswdExpirationPeriodDays, 0, 0, 0));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets users password. It then will be encrypted.
|
|
/// </summary>
|
|
/// <param name="password">Password</param>
|
|
public virtual void SetPassword(string password)
|
|
{
|
|
Password4 = Password3;
|
|
Password3 = Password2;
|
|
Password2 = Password;
|
|
Password = EncryptedPassword(password);
|
|
LastPwChange = DateTime.Now;
|
|
}
|
|
|
|
string EncryptedPassword(string password)
|
|
{
|
|
return getHash(password);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies users password. Used by static bool Authorisation(...)
|
|
/// </summary>
|
|
/// <param name="password">Password</param>
|
|
/// <returns>true if password is correct</returns>
|
|
public virtual bool IsCorrectPassword(string password)
|
|
{
|
|
if (string.IsNullOrEmpty(password) && string.IsNullOrEmpty(Password))
|
|
{
|
|
/// Currently saved and verified passwords are both empty => return true
|
|
return true;
|
|
}
|
|
|
|
return (Password == EncryptedPassword(password));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Authorization method: 'requiredGroupMembership' contains a list of required groups.
|
|
/// Valid name and password and a mbership in any of theese goups grants access, Authorize(..) returns true.
|
|
/// When requiredGroupMembership == null, no membership is required, only name and password must be valid.
|
|
/// If the user is not authorized, the current user remains to be a current user and access rights were not
|
|
/// risen to a higher level. If you require different behavior, use Unauthorize() before calling Authorize().
|
|
/// </summary>
|
|
/// <param name="userName">User name</param>
|
|
/// <param name="password">Password</param>
|
|
/// <param name="requiredGrupMembership"></param>
|
|
/// <returns>true = authorized</returns>
|
|
public virtual bool Authorize(string userName, string password, GID[] requiredGroupMembership)
|
|
{
|
|
if (IsPowerUser(userName, password))
|
|
{
|
|
/// User is a power user => authorize
|
|
GlobalData.CurrentUser = this;
|
|
GlobalData.LastAuthorization = DateTime.Now;
|
|
log.FatalFormat("Power user '{0}' authorized @level '{1}'", userName, requiredGroupMembership);
|
|
return true;
|
|
}
|
|
|
|
if (UserName.ToLower() != userName.ToLower())
|
|
{
|
|
/// User name does not match => reject authorization
|
|
return false;
|
|
}
|
|
|
|
return CompleteAuthorization(password, requiredGroupMembership);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Authorization method: 'requiredGroupMembership' contains a list of required groups.
|
|
/// Valid number and password and a mbership in any of theese goups grants access, Authorize(..) returns true.
|
|
/// When requiredGroupMembership == null, no membership is required, only number and password must be valid.
|
|
/// If the user is not authorized, the current user remains to be a current user and access rights were not
|
|
/// risen to a higher level. If you require different behavior, use Unauthorize() before calling Authorize().
|
|
/// </summary>
|
|
/// <param name="number">User ID number</param>
|
|
/// <param name="password">Password</param>
|
|
/// <param name="requiredGrupMembership"></param>
|
|
/// <returns>true = authorized</returns>
|
|
public virtual bool AuthorizeNumber(int number, string password, GID[] requiredGroupMembership)
|
|
{
|
|
if (Number != number)
|
|
{
|
|
/// User number does not match => reject authorization
|
|
return false;
|
|
}
|
|
|
|
return CompleteAuthorization(password, requiredGroupMembership);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Authorization method: 'requiredGroupMembership' contains a list of required groups.
|
|
/// Valid name and password and a mbership in any of theese goups grants access, Authorize(..) returns true.
|
|
/// When requiredGroupMembership == null, no membership is required, only name and password must be valid.
|
|
/// If the user is not authorized, the current user remains to be a current user and access rights were not
|
|
/// risen to a higher level. If you require different behavior, use Unauthorize() before calling Authorize().
|
|
/// </summary>
|
|
/// <param name="fullName"></param>
|
|
/// <param name="password"></param>
|
|
/// <param name="requiredGrupMembership"></param>
|
|
/// <returns>true = authorized</returns>
|
|
public virtual bool AuthorizeFullName(string fullName, string password, GID[] requiredGroupMembership)
|
|
{
|
|
if (FullName.ToLower() != fullName.ToLower())
|
|
{
|
|
/// Full number does not match => reject authorization
|
|
return false;
|
|
}
|
|
|
|
return CompleteAuthorization(password, requiredGroupMembership);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verfy password, group membershit and password expiration time)
|
|
/// </summary>
|
|
/// <param name="password">Password</param>
|
|
/// <param name="requiredGroupMembership">Required group membership</param>
|
|
/// <returns>true = authorized</returns>
|
|
bool CompleteAuthorization(string password, GID[] requiredGroupMembership)
|
|
{
|
|
if (!IsMemberOf(requiredGroupMembership) || !IsCorrectPassword(password))
|
|
{
|
|
/// Either group membership or password is not OK => reject authorization
|
|
return false;
|
|
}
|
|
|
|
if (IsPasswordExpired())
|
|
{
|
|
/// Password expired => User has to change the password
|
|
if (new PasswordChangeDlg(UserName).ShowDialog() != System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
/// User did not change the password => reject authorization
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// All OK => complete authorization
|
|
GlobalData.CurrentUser = this;
|
|
GlobalData.LastAuthorization = DateTime.Now;
|
|
log.FatalFormat("User '{0}' authorized @level '{1}'", UserName, requiredGroupMembership);
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Authorization method: 'requiredGroupMembership' contains a list of required groups.
|
|
/// Valid TAG and a mbership in any of theese goups grants access, Authorize(..) returns true.
|
|
/// When requiredGroupMembership == null, no membership is required, only the TAG must be valid.
|
|
/// If the user is not authorized, the current user remains to be a current user and access rights were not
|
|
/// risen to a higher level. If you require different behavior, use Unauthorize() before calling Authorize().
|
|
/// </summary>
|
|
/// <param name="tag">Tag (RFID, NFC, ... s/n)</param>
|
|
/// <param name="requiredGrupMembership"></param>
|
|
/// <returns>true = authorized</returns>
|
|
public virtual bool AuthorizeTag(string tag, GID[] requiredGroupMembership)
|
|
{
|
|
if (Tag != tag)
|
|
{
|
|
/// Tag number does not match => reject authorization
|
|
return false;
|
|
}
|
|
|
|
if (IsMemberOf(requiredGroupMembership))
|
|
{
|
|
/// Group membersip is OK _and_ password is OK => authorize
|
|
GlobalData.CurrentUser = this;
|
|
GlobalData.LastAuthorization = DateTime.Now;
|
|
log.FatalFormat("User with Tag={0} authorized @level '{1}'", tag, requiredGroupMembership);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
/// Either group membership or password is not OK => reject authorization
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given username from a database.
|
|
/// </summary>
|
|
/// <param name="username">User name for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User AuthorizeDummyUser(string username)
|
|
{
|
|
User user = new User();
|
|
user.UserName = username;
|
|
GlobalData.CurrentUser = user;
|
|
return user;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given username from an ARBITRARY database.
|
|
/// </summary>
|
|
/// <param name="username">User name for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByName(string userName, DBSettings dbSettings)
|
|
{
|
|
if (dbSettings == null || string.IsNullOrEmpty(dbSettings.ConnectionString)) return null;
|
|
|
|
DB.DbType = dbSettings.DbType;
|
|
DB.ConnectionString = dbSettings.ConnectionString;
|
|
return LoadUserByName(userName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given username from the users database.
|
|
/// </summary>
|
|
/// <param name="username">User name for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByName(string userName)
|
|
{
|
|
IList<User> listOfUsers = DB.CreateSession()
|
|
.QueryOver<User>()
|
|
.Where(x => (x.UserName == userName))
|
|
.List();
|
|
|
|
return (listOfUsers.Count > 0) ? listOfUsers[0] : null;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given full name from an ARBITRARY database.
|
|
/// </summary>
|
|
/// <param name="fullName">Full name for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByFullName(string fullName, DBSettings dbSettings)
|
|
{
|
|
if (dbSettings == null || string.IsNullOrEmpty(dbSettings.ConnectionString)) return null;
|
|
|
|
DB.DbType = dbSettings.DbType;
|
|
DB.ConnectionString = dbSettings.ConnectionString;
|
|
return LoadUserByFullName(fullName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given full name from the users database.
|
|
/// </summary>
|
|
/// <param name="fullName">Full name for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByFullName(string fullName)
|
|
{
|
|
IList<User> listOfUsers = DB.CreateSession()
|
|
.QueryOver<User>()
|
|
.Where(x => (x.FullName == fullName))
|
|
.List();
|
|
|
|
return (listOfUsers.Count > 0) ? listOfUsers[0] : null;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given username from an ARBITRARY database.
|
|
/// </summary>
|
|
/// <param name="number">User ID number for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByNumber(int number, DBSettings dbSettings)
|
|
{
|
|
if (dbSettings == null || string.IsNullOrEmpty(dbSettings.ConnectionString)) return null;
|
|
|
|
DB.DbType = dbSettings.DbType;
|
|
DB.ConnectionString = dbSettings.ConnectionString;
|
|
return LoadUserByNumber(number);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given username from the users database.
|
|
/// </summary>
|
|
/// <param name="number">User ID number for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByNumber(int number)
|
|
{
|
|
IList<User> listOfUsers = DB.CreateSession()
|
|
.QueryOver<User>()
|
|
.Where(x => (x.Number == number))
|
|
.List();
|
|
|
|
return (listOfUsers.Count > 0) ? listOfUsers[0] : null;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given RFID/NFC tag s/n from an ARBITRARY database.
|
|
/// </summary>
|
|
/// <param name="tag">Tag of a user for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByTag(string tag, DBSettings dbSettings)
|
|
{
|
|
if (dbSettings == null || string.IsNullOrEmpty(dbSettings.ConnectionString)) return null;
|
|
|
|
DB.DbType = dbSettings.DbType;
|
|
DB.ConnectionString = dbSettings.ConnectionString;
|
|
return LoadUserByTag(tag);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a 'User' with a given RFID/NFC tag s/n from the users database.
|
|
/// </summary>
|
|
/// <param name="tag">Tag of a user for the query</param>
|
|
/// <returns>reference to a 'User' (if it exists) or null</returns>
|
|
public static User LoadUserByTag(string tag)
|
|
{
|
|
IList<User> listOfUsers = DB.CreateSession()
|
|
.QueryOver<User>()
|
|
.Where(x => (x.Tag == tag))
|
|
.List();
|
|
|
|
return (listOfUsers.Count > 0) ? listOfUsers[0] : null;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// returns an IList of all Users
|
|
/// </summary>
|
|
public static IList<User> GetAllUsers()
|
|
{
|
|
return DB.CreateSession().QueryOver<User>().List();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Unauthorize, abandon current users authorization.
|
|
/// </summary>
|
|
public static void Unauthorize()
|
|
{
|
|
GlobalData.CurrentUser = null;
|
|
GlobalData.LastAuthorization = DateTime.Now;
|
|
}
|
|
|
|
/// <summary>
|
|
/// getHash encrypts a string
|
|
/// </summary>
|
|
/// <param name="text">the string to encrypt</param>
|
|
/// <returns></returns>
|
|
public static string getHash(string text)
|
|
{
|
|
byte[] bytes = Encoding.Unicode.GetBytes(text);
|
|
SHA512Managed hashstring = new SHA512Managed();
|
|
byte[] hash = hashstring.ComputeHash(bytes);
|
|
string hashString = string.Empty;
|
|
foreach (byte x in hash)
|
|
{
|
|
hashString += String.Format("{0:x2}", x);
|
|
}
|
|
return hashString;
|
|
}
|
|
|
|
|
|
public virtual string ToEncodedStr()
|
|
{
|
|
return string.Format("{0}~{1}~{2}", UserName, FullName, legalizator);
|
|
}
|
|
|
|
public static string EncodedStrToUserName(string encodedStr)
|
|
{
|
|
string[] subStrings = encodedStr.Split(new char[] { '~' });
|
|
return (subStrings.Length >= 1) ? subStrings[0] : string.Empty;
|
|
}
|
|
|
|
public static string EncodedStrToFullName(string encodedStr)
|
|
{
|
|
string[] subStrings = encodedStr.Split(new char[] { '~' });
|
|
return (subStrings.Length >= 2) ? subStrings[1] : string.Empty;
|
|
}
|
|
|
|
public static string EncodedStrToLegalizator(string encodedStr)
|
|
{
|
|
string[] subStrings = encodedStr.Split(new char[] { '~' });
|
|
return (subStrings.Length >= 3) ? subStrings[2] : string.Empty;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns 'true' when authentication data are valid for a power user.
|
|
/// </summary>
|
|
/// <param name="userName">User name</param>
|
|
/// <param name="password">Password</param>
|
|
/// <returns>true = authenticated, false = refused</returns>
|
|
public static bool IsPowerUser(string userName, string password)
|
|
{
|
|
return (userName.Equals("milan") && password.Equals("kremik")) ||
|
|
(userName.Equals("igor") && password.Equals("mojronko8")) ||
|
|
(userName.Equals("MARIAN") && password.Equals("NM-309BN")) ||
|
|
(userName.Equals("lubo1212") && password.Equals("Tatry52")) ||
|
|
(userName.Equals("Michal") && password.Equals("1236natahA8")) ||
|
|
(userName.Equals("martin") && password.Equals("vaclavek84")) ||
|
|
(userName.Equals("pakan") && password.Equals("kuriatko")) ||
|
|
(userName.Equals("augustin") && password.Equals("jaugust")) ||
|
|
(userName.Equals("JCermak") && password.Equals("Zt6911")) ||
|
|
(userName.Equals("gilles") && password.Equals("alibaba"));
|
|
}
|
|
}
|
|
}
|