Exemplo n.º 1
0
        /// <summary>
        /// Authentication using: [Salted password hashing with PBKDF2-SHA1].
        /// Implementation available at: [HouseOfSynergy.PowerTools.Library.Security.Cryptography.PasswordHash].
        /// The password should never reach here in plain text. It should b encrypted using Sha512 in TypeScript or JavaScript.
        /// A C# implementation of Sha512 is available at: [HouseOfSynergy.PowerTools.Library.Security.Cryptography.Sha].
        /// </summary>
        /// <param name="sessionType">The origin of the request.</param>
        /// <param name="username">Username in plain text.</param>
        /// <param name="passwordHash">Password from client hashed using Sha512.</param>
        /// <param name="token">The user object fetched.</param>
        /// <param name="exception">Populates an exception where applicable.</param>
        /// <returns></returns>
        public static bool SignIn
        (
            SessionType sessionType,
            string username,
            string passwordHash,
            string clientIpAddress,
            string userAgent,
            long ticks,
            string sessionId,
            out MasterUserSession masterUserSession,
            out Exception exception
        )
        {
            var           result          = false;
            var           now             = DateTime.UtcNow;
            MasterUser    userDatabase    = null;
            MasterSession sessionDatabase = null;

            exception         = null;
            masterUserSession = null;

            try
            {
                using (var context = new ContextMaster())
                {
                    userDatabase = context.Users.SingleOrDefault(u => (u.UserName == username));
                    if (userDatabase == null)
                    {
                        throw (new UserNotFoundException());
                    }

                    if (!PasswordHash.ValidatePassword(passwordHash, userDatabase.PasswordHash))
                    {
                        throw (new AuthenticationException());
                    }

                    var token
                        = userDatabase.Id.ToString()
                          + EntityConstants.TokenDelimiter
                          + userDatabase.UserName
                          + EntityConstants.TokenDelimiter
                          + userDatabase.AuthenticationType.ToString()
                          + EntityConstants.TokenDelimiter
                          + (userDatabase.ActiveDirectoryId ?? "").Trim()
                          + EntityConstants.TokenDelimiter
                          + ""
                          + EntityConstants.TokenDelimiter
                          + sessionType.ToString()
                          + EntityConstants.TokenDelimiter
                          + EntityConstants.TokenDelimiter
                          + EntityConstants.TokenDelimiter;

                    // TODO: Remove for production.
                    if (AffinityConfiguration.DeploymentLocation == DeploymentLocation.BtsSaleem)
                    {
                        now = now.Add(TimeSpan.FromHours(1));
                    }

                    sessionDatabase = userDatabase.Sessions.SingleOrDefault
                                      (
                        s =>
                        (
                            (s.DateTimeCreated < now) &&
                            (s.DateTimeExpiration > now) &&
                            (s.SessionId == sessionId) &&
                            (s.Token == token) &&
                            (s.UserAgent == userAgent) &&
                            (s.IPAddressString == clientIpAddress) &&
                            (s.SessionType == sessionType)
                        )
                                      );

                    var lines = new List <string>();
                    lines.Add($"--------------------------------------------------------------------------------------------------------------------------------------------------------------");
                    lines.Add($"SIGNIN");
                    lines.Add($"Session Found: {sessionDatabase != null}");
                    lines.Add($"now: {now}");
                    lines.Add($"SessionId: {sessionId}");
                    lines.Add($"token: {token}");
                    lines.Add($"useragent: {userAgent}");
                    lines.Add($"ipAddressString: {clientIpAddress}");
                    lines.Add($"sessionType: {sessionType}");
                    lines.Add($"--------------------------------------------------------------------------------------------------------------------------------------------------------------");
                    AffinityConfiguration.Messages.Add(string.Join("<br />", lines));

                    if (sessionDatabase == null)
                    {
                        var guid        = Guid.NewGuid();
                        var rijndaelKey = new byte [GlobalConstants.AlgorithmSymmetricKeySize];
                        var rijndaelInitializationVector = new byte [GlobalConstants.AlgorithmSymmetricInitializationVectorSize];
                        var rsaKeyPair = Rsa.GenerateKeyPair(GlobalConstants.AlgorithmAsymmetricKeySize);

                        using (var randomNumberGenerator = RandomNumberGenerator.Create())
                        {
                            randomNumberGenerator.GetBytes(rijndaelKey);
                            randomNumberGenerator.GetBytes(rijndaelInitializationVector);
                        }

                        do
                        {
                            guid = Guid.NewGuid();
                        } while (context.Sessions.Any(s => s.Guid == guid));

                        sessionDatabase                              = new MasterSession();
                        sessionDatabase.Guid                         = guid;
                        sessionDatabase.CultureName                  = "en";
                        sessionDatabase.Token                        = token;
                        sessionDatabase.SessionId                    = sessionId;
                        sessionDatabase.SessionType                  = sessionType;
                        sessionDatabase.UserAgent                    = userAgent;
                        sessionDatabase.IPAddressString              = clientIpAddress;
                        sessionDatabase.DeviceType                   = DeviceType.Unknown;
                        sessionDatabase.DateTimeCreated              = now;
                        sessionDatabase.DateTimeExpiration           = sessionDatabase.DateTimeCreated.Add(TimeSpan.FromDays(1));
                        sessionDatabase.RijndaelKey                  = Convert.ToBase64String(rijndaelKey);
                        sessionDatabase.RijndaelInitializationVector = Convert.ToBase64String(rijndaelInitializationVector);
                        sessionDatabase.RsaKeyPublic                 = rsaKeyPair.KeyPublic.KeyToString();
                        sessionDatabase.RsaKeyPrivate                = rsaKeyPair.KeyPrivate.KeyToString();
                        sessionDatabase.User                         = userDatabase;
                        sessionDatabase.UserId                       = userDatabase.Id;
                        context.Sessions.Add(sessionDatabase);
                        context.SaveChanges();
                    }
                    else
                    {
                        sessionDatabase.DateTimeExpiration = DateTime.UtcNow.Add(TimeSpan.FromDays(1));
                        context.SaveChanges();
                    }

                    var sessions = userDatabase.Sessions.Where(s => s.DateTimeExpiration < DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)));
                    foreach (var s in sessions)
                    {
                        context.Sessions.Remove(s);
                    }
                    context.SaveChanges();

                    sessionDatabase = context.Sessions.AsNoTracking().Single(s => s.Id == sessionDatabase.Id);
                    userDatabase    = context.Users.AsNoTracking().Include(p => p.Roles).AsNoTracking().Single(u => u.Id == userDatabase.Id);

                    userDatabase.PasswordHash   = "";
                    userDatabase.PasswordSalt   = "";
                    sessionDatabase.RijndaelKey = "";
                    sessionDatabase.RijndaelInitializationVector = "";
                    sessionDatabase.RsaKeyPrivate = "";
                    sessionDatabase.RsaKeyPublic  = (sessionType == SessionType.Api) ? sessionDatabase.RsaKeyPublic : "";

                    masterUserSession = new MasterUserSession(userDatabase, sessionDatabase);

                    result = true;
                }
            }
            catch (Exception e)
            {
                exception = e;
            }

            return(result);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Authentication using: [Salted password hashing with PBKDF2-SHA1].
        /// Implementation available at: [HouseOfSynergy.PowerTools.Library.Security.Cryptography.PasswordHash].
        /// The password should never reach here in plain text. It should be hashed using Sha512 in TypeScript or JavaScript.
        /// A C# implementation of Sha512 is available at: [HouseOfSynergy.PowerTools.Library.Security.Cryptography.Sha].
        /// </summary>
        /// <param name="sessionType">The origin of the request.</param>
        /// <param name="domain">The domain of the requested tenant.</param>
        /// <param name="username">Username in plain text.</param>
        /// <param name="passwordHash">Password from client hashed using Sha512.</param>
        /// <param name="clientIpAddress">The IP Address the request originated from.</param>
        /// <param name="userAgent">The User Agent of the request.</param>
        /// <param name="ticks">The user's timestamp in ticks.</param>
        /// <param name="ticks">The requests server Session Id.</param>
        /// <param name="tenantUserSession">Populates the out tenantUserSession if the function succeeds.</param>
        /// <param name="exception">Populates the out exception where applicable.</param>
        /// <returns>Returns true if sign-in succeeds. Otherwise, populates the out exception parameter.</returns>
        public static bool SignIn
        (
            SessionType sessionType,
            string domain,
            string username,
            string passwordHash,
            string clientIpAddress,
            string userAgent,
            long ticks,
            string sessionId,
            out TenantUserSession tenantUserSession,
            out Exception exception
        )
        {
            var     result          = false;
            User    userDatabase    = null;
            var     now             = DateTime.UtcNow;
            Tenant  tenantDatabase  = null;
            Session sessionDatabase = null;

            exception         = null;
            tenantUserSession = null;

            try
            {
                if (!MasterTenantManagement.GetTenantByDomain(domain, out tenantDatabase, out exception))
                {
                    throw (exception);
                }
                if (tenantDatabase == null)
                {
                    throw (new DomainNotFoundException());
                }

                // ContextTenant.Initialize(tenantDatabase.DatabaseConnectionString);

                using (var context = new ContextTenant(tenantDatabase.DatabaseConnectionString))
                {
                    tenantDatabase = context.Tenants.SingleOrDefault();
                    if (tenantDatabase == null)
                    {
                        throw (new DomainNotFoundException());
                    }

                    // TODO: Use a single exception for unmatched username/password scenarios.
                    userDatabase = context.Users.SingleOrDefault(u => (u.UserName == username));
                    if (userDatabase == null)
                    {
                        throw (new AuthenticationException(isValidDomain: true, isValidUsername: false, isValidPassword: null));
                    }

                    if (!PasswordHash.ValidatePassword(passwordHash, userDatabase.PasswordHash))
                    {
                        throw (new AuthenticationException(isValidDomain: true, isValidUsername: true, isValidPassword: false));
                    }

                    var token
                        = tenantDatabase.Id.ToString()
                          + EntityConstants.TokenDelimiter
                          + tenantDatabase.Domain
                          + EntityConstants.TokenDelimiter
                          + userDatabase.Id.ToString()
                          + EntityConstants.TokenDelimiter
                          + userDatabase.UserName
                          + EntityConstants.TokenDelimiter
                          + userDatabase.AuthenticationType.ToString()
                          + EntityConstants.TokenDelimiter
                          + (userDatabase.ActiveDirectory_ObjectId.ToString(GuidUtilities.EnumGuidFormat.N.ToString())).Trim()
                          + EntityConstants.TokenDelimiter
                          + ""
                          + EntityConstants.TokenDelimiter
                          + sessionType.ToString()
                          + EntityConstants.TokenDelimiter
                          + EntityConstants.TokenDelimiter
                          + EntityConstants.TokenDelimiter;

                    // TODO: Remove for production.
                    if (AffinityConfiguration.DeploymentLocation == DeploymentLocation.BtsSaleem)
                    {
                        now = now.Add(TimeSpan.FromHours(1));
                    }

                    //clientIpAddress.r

                    sessionDatabase = userDatabase.Sessions.SingleOrDefault
                                      (
                        s =>
                        (
                            (s.DateTimeCreated < now) &&
                            (s.DateTimeExpiration > now) &&
                            (s.SessionId == sessionId) &&
                            (s.Token == token) &&
                            (s.UserAgent == userAgent) &&
                            (s.IPAddressString == clientIpAddress) &&
                            (s.SessionType == sessionType)
                        )
                                      );

                    var lines = new List <string>();
                    lines.Add($"--------------------------------------------------------------------------------------------------------------------------------------------------------------");
                    lines.Add($"SIGNIN TOKEN");
                    lines.Add($"Session Found: {sessionDatabase != null}");
                    lines.Add($"now: {now}");
                    lines.Add($"SessionId: {sessionId}");
                    lines.Add($"token: {token}");
                    lines.Add($"useragent: {userAgent}");
                    lines.Add($"ipAddressString: {clientIpAddress}");
                    lines.Add($"sessionType: {sessionType}");
                    lines.Add($"--------------------------------------------------------------------------------------------------------------------------------------------------------------");
                    AffinityConfiguration.Messages.Add(string.Join("<br />", lines));

                    // TODO: Remove for production.
                    if (AffinityConfiguration.DeploymentLocation == DeploymentLocation.BtsSaleem)
                    {
                        now = now.Subtract(TimeSpan.FromHours(2));
                    }

                    if (sessionDatabase == null)
                    {
                        var guid        = Guid.NewGuid();
                        var rijndaelKey = new byte[GlobalConstants.AlgorithmSymmetricKeySize];
                        var rijndaelInitializationVector = new byte[GlobalConstants.AlgorithmSymmetricInitializationVectorSize];
                        var rsaKeyPair = Rsa.GenerateKeyPair(GlobalConstants.AlgorithmAsymmetricKeySize);

                        using (var randomNumberGenerator = RandomNumberGenerator.Create())
                        {
                            randomNumberGenerator.GetBytes(rijndaelKey);
                            randomNumberGenerator.GetBytes(rijndaelInitializationVector);
                        }

                        do
                        {
                            guid = Guid.NewGuid();
                        } while (context.Sessions.Any(s => s.Guid == guid));

                        sessionDatabase                              = new Session();
                        sessionDatabase.Guid                         = guid;
                        sessionDatabase.CultureName                  = "en";
                        sessionDatabase.Token                        = token;
                        sessionDatabase.SessionId                    = sessionId;
                        sessionDatabase.SessionType                  = sessionType;
                        sessionDatabase.UserAgent                    = userAgent;
                        sessionDatabase.IPAddressString              = clientIpAddress;
                        sessionDatabase.DeviceType                   = DeviceType.Unknown;
                        sessionDatabase.DateTimeCreated              = now;
                        sessionDatabase.DateTimeExpiration           = sessionDatabase.DateTimeCreated.Add(TimeSpan.FromDays(1));
                        sessionDatabase.RijndaelKey                  = Convert.ToBase64String(rijndaelKey);
                        sessionDatabase.RijndaelInitializationVector = Convert.ToBase64String(rijndaelInitializationVector);
                        sessionDatabase.RsaKeyPublic                 = rsaKeyPair.KeyPublic.KeyToString();
                        sessionDatabase.RsaKeyPrivate                = rsaKeyPair.KeyPrivate.KeyToString();
                        sessionDatabase.User                         = userDatabase;
                        sessionDatabase.UserId                       = userDatabase.Id;
                        sessionDatabase.Tenant                       = tenantDatabase;
                        sessionDatabase.TenantId                     = tenantDatabase.Id;
                        context.Sessions.Add(sessionDatabase);
                        context.SaveChanges();
                    }
                    else
                    {
                        sessionDatabase.DateTimeExpiration = now.Add(TimeSpan.FromDays(1));
                        context.SaveChanges();
                    }

                    var sessions = userDatabase.Sessions.Where(s => s.DateTimeExpiration < now.Subtract(TimeSpan.FromDays(30)));
                    foreach (var s in sessions)
                    {
                        context.Sessions.Remove(s);
                    }
                    context.SaveChanges();

                    sessionDatabase = context.Sessions.AsNoTracking().Single(s => s.Id == sessionDatabase.Id);
                    userDatabase    = context.Users.AsNoTracking().Include(p => p.Roles).AsNoTracking().Single(u => u.Id == userDatabase.Id);
                    tenantDatabase  = context.Tenants.AsNoTracking().Include(t => t.TenantSubscriptions).Single(t => t.Id == tenantDatabase.Id);

                    userDatabase.PasswordHash   = "";
                    userDatabase.PasswordSalt   = "";
                    sessionDatabase.RijndaelKey = "";
                    sessionDatabase.RijndaelInitializationVector = "";
                    sessionDatabase.RsaKeyPrivate                   = "";
                    sessionDatabase.RsaKeyPublic                    = (sessionType == SessionType.Api) ? sessionDatabase.RsaKeyPublic : "";
                    tenantDatabase.RsaKeyPrivate                    = "";
                    tenantDatabase.RsaKeyPublic                     = (sessionType == SessionType.Api) ? tenantDatabase.RsaKeyPublic : "";
                    tenantDatabase.StorageAccessKeyPrimary          = "";
                    tenantDatabase.StorageAccessKeySecondary        = "";
                    tenantDatabase.StorageConnectionStringPrimary   = (sessionType == SessionType.Mvc) ? tenantDatabase.StorageConnectionStringPrimary : "";
                    tenantDatabase.StorageConnectionStringSecondary = (sessionType == SessionType.Mvc) ? tenantDatabase.StorageConnectionStringSecondary : "";

                    if (sessionType == SessionType.Api)
                    {
                        foreach (var ts in tenantDatabase.TenantSubscriptions)
                        {
                            ts.Tenant = null;
                        }
                        foreach (var r in userDatabase.Roles)
                        {
                            r.Users.Clear(); r.UserRoles.Clear();
                        }
                    }

                    // The out parameter [tenantUserSession] should not be assigned until
                    //	the objects passed to its constructor are fully populated and scrubbed.
                    tenantUserSession = new TenantUserSession(tenantDatabase, userDatabase, sessionDatabase);

                    result = true;
                }
            }
            catch (Exception e)
            {
                exception = e;
            }

            return(result);
        }