public void TestUpdateValidSecurityUser()
        {
            IPasswordHashingService hashingService = ApplicationServiceContext.Current.GetService <IPasswordHashingService>();

            SecurityUser userUnderTest = new SecurityUser()
            {
                Email          = "*****@*****.**",
                EmailConfirmed = false,
                Password       = hashingService.ComputeHash("password"),
                SecurityHash   = "cert",
                UserName       = "******",
                UserClass      = UserClassKeys.HumanUser
            };

            // Store user
            IIdentityProviderService identityService = ApplicationServiceContext.Current.GetService <IIdentityProviderService>();
            var authContext = AuthenticationContext.SystemPrincipal;

            Assert.IsNotNull(authContext);
            var userAfterUpdate = base.DoTestUpdate(userUnderTest, "PhoneNumber", authContext);

            // Update
            Assert.IsNotNull(userAfterUpdate.UpdatedTime);
            Assert.IsNotNull(userAfterUpdate.PhoneNumber);
            Assert.AreEqual(authContext.Identity.Name, userAfterUpdate.LoadProperty <SecurityProvenance>("UpdatedBy").LoadProperty <SecurityUser>("User").UserName);
        }
        /// <summary>
        /// Creates the identity.
        /// </summary>
        /// <param name="securityUser">The security user.</param>
        /// <param name="password">The password.</param>
        /// <param name="principal">The principal.</param>
        /// <returns>Returns the created user identity.</returns>
        /// <exception cref="PolicyViolationException"></exception>
        public IIdentity CreateIdentity(SecurityUser securityUser, string password, IPrincipal principal)
        {
            var pdp = ApplicationContext.Current.GetService <IPolicyDecisionService>();

            ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(PermissionPolicyIdentifiers.AccessClientAdministrativeFunction, principal);

            try
            {
                var conn = this.CreateConnection();
                IPasswordHashingService hash = ApplicationContext.Current.GetService <IPasswordHashingService>();

                using (conn.Lock())
                {
                    DbSecurityUser dbu = new DbSecurityUser()
                    {
                        Password      = hash.ComputeHash(password),
                        SecurityHash  = Guid.NewGuid().ToString(),
                        PhoneNumber   = securityUser.PhoneNumber,
                        Email         = securityUser.Email,
                        CreationTime  = DateTime.Now,
                        CreatedByUuid = conn.Table <DbSecurityUser>().FirstOrDefault(o => o.UserName == AuthenticationContext.Current?.Principal?.Identity?.Name)?.Uuid ?? Guid.Parse("fadca076-3690-4a6e-af9e-f1cd68e8c7e8").ToByteArray(),
                        UserName      = securityUser.UserName,
                        Key           = securityUser.Key.Value
                    };
                    conn.Insert(dbu);
                }
                return(new SQLiteIdentity(securityUser.UserName, false));
            }
            catch (Exception e)
            {
                throw new DataPersistenceException($"Error creating {securityUser}", e);
            }
        }
        public void TestDelayLoadUserProperties()
        {
            IPasswordHashingService hashingService = ApplicationServiceContext.Current.GetService <IPasswordHashingService>();
            String       securityHash  = Guid.NewGuid().ToString();
            SecurityUser userUnderTest = new SecurityUser()
            {
                Email          = "*****@*****.**",
                EmailConfirmed = false,
                Password       = hashingService.ComputeHash("password"),
                SecurityHash   = securityHash,
                UserName       = "******",
                UserClass      = UserClassKeys.HumanUser
            };


            var userAfterInsert  = base.DoTestInsert(userUnderTest, null);
            var roleProvider     = ApplicationServiceContext.Current.GetService <IRoleProviderService>();
            var identityProvider = ApplicationServiceContext.Current.GetService <IIdentityProviderService>();

            // Allow login
            roleProvider.AddUsersToRoles(new string[] { "delayLoadTest" }, new string[] { "USERS" }, AuthenticationContext.Current.Principal);

            var auth = identityProvider.Authenticate("delayLoadTest", "password");

            roleProvider.CreateRole("TestDelayLoadUserPropertiesGroup", auth);
            roleProvider.AddUsersToRoles(new String[] { "delayLoadTest" }, new String[] { "TestDelayLoadUserPropertiesGroup" }, AuthenticationContext.Current.Principal);

            // Now trigger a delay load
            var userForTest = base.DoTestQuery(u => u.UserName == "delayLoadTest", userAfterInsert.Key, auth).First();

            Assert.AreEqual(2, userForTest.Roles.Count);
            Assert.IsTrue(userForTest.Roles.Exists(o => o.Name == "TestDelayLoadUserPropertiesGroup"));
        }
예제 #4
0
        /// <summary>
        /// Create the identity
        /// </summary>
        public IIdentity CreateIdentity(Guid sid, string name, string deviceSecret, IPrincipal principal)
        {
            try
            {
                ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(PermissionPolicyIdentifiers.AccessClientAdministrativeFunction, principal);
                ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(PermissionPolicyIdentifiers.CreateLocalIdentity, principal);

                var conn = this.CreateConnection();
                IPasswordHashingService hash = ApplicationContext.Current.GetService <IPasswordHashingService>();

                using (conn.Lock())
                {
                    DbSecurityDevice dbu = new DbSecurityDevice()
                    {
                        DeviceSecret  = hash.ComputeHash(deviceSecret),
                        PublicId      = name,
                        Key           = sid,
                        CreationTime  = DateTime.Now,
                        CreatedByUuid = conn.Table <DbSecurityUser>().FirstOrDefault(o => o.UserName == AuthenticationContext.Current?.Principal?.Identity?.Name)?.Uuid ?? Guid.Parse("fadca076-3690-4a6e-af9e-f1cd68e8c7e8").ToByteArray()
                    };
                    conn.Insert(dbu);
                }
                return(new SQLiteDeviceIdentity(name, false));
            }
            catch
            {
                throw;
            }
        }
 public void EachTestSetUp()
 {
     _passwordHashingService = Substitute.For<IPasswordHashingService>();
     _passwordHashingService.ComputeHash("somestring", new byte[4]).ReturnsForAnyArgs("hashedPassword");
     _userRepository = Substitute.For<ILinqRepository<User>>();
     _authService = new AuthenticationService(_userRepository, _passwordHashingService);
 }
예제 #6
0
        /// <summary>
        /// Change the user's password
        /// </summary>
        /// <param name="userName">User name.</param>
        /// <param name="newPassword">New password.</param>
        /// <param name="principal">Principal.</param>
        public void ChangePassword(string userName, string password, System.Security.Principal.IPrincipal principal)
        {
            // We must demand the change password permission
            try
            {
                IPolicyDecisionService pdp = ApplicationContext.Current.GetService <IPolicyDecisionService>();

                if (userName != principal.Identity.Name &&
                    pdp.GetPolicyOutcome(principal, PolicyIdentifiers.ChangePassword) == OpenIZ.Core.Model.Security.PolicyGrantType.Deny)
                {
                    throw new SecurityException("User cannot change specified users password");
                }
                var conn = this.CreateConnection();
                using (conn.Lock())
                {
                    var dbu = conn.Table <DbSecurityUser>().Where(o => o.UserName == userName).FirstOrDefault();
                    if (dbu == null)
                    {
                        throw new KeyNotFoundException();
                    }
                    else
                    {
                        IPasswordHashingService hash = ApplicationContext.Current.GetService <IPasswordHashingService>();
                        dbu.PasswordHash  = hash.ComputeHash(password);
                        dbu.SecurityHash  = Guid.NewGuid().ToString();
                        dbu.UpdatedByUuid = conn.Table <DbSecurityUser>().First(u => u.UserName == principal.Identity.Name).Uuid;
                        dbu.UpdatedTime   = DateTime.Now;
                        conn.Update(dbu);
                        this.SecurityAttributesChanged?.Invoke(this, new SecurityAuditDataEventArgs(dbu, "password"));
                    }
                }
            }
            catch (Exception e)
            {
                this.SecurityAttributesChanged?.Invoke(this, new SecurityAuditDataEventArgs(new SecurityUser()
                {
                    Key = Guid.Empty, UserName = userName
                }, "password")
                {
                    Success = false
                });

                this.m_tracer.TraceError("Error changing password for user {0} : {1}", userName, e);
                throw;
            }
        }
예제 #7
0
        /// <summary>
        /// Change the device secret
        /// </summary>
        public void ChangeSecret(string deviceName, string deviceSecret, IPrincipal principal)
        {
            // We must demand the change password permission
            try
            {
                var pep = ApplicationContext.Current.GetService <IPolicyEnforcementService>();
                if (pep == null)
                {
                    throw new InvalidOperationException("Cannot find the PolicyEnforcementService");
                }
                if (deviceName != principal.Identity.Name)
                {
                    pep.Demand(PermissionPolicyIdentifiers.AccessClientAdministrativeFunction, principal);
                }
                var conn = this.CreateConnection();
                using (conn.Lock())
                {
                    var dbu = conn.Table <DbSecurityDevice>().Where(o => o.PublicId == deviceName).FirstOrDefault();
                    if (dbu == null)
                    {
                        throw new KeyNotFoundException();
                    }
                    else
                    {
                        IPasswordHashingService hash = ApplicationContext.Current.GetService <IPasswordHashingService>();

                        if (hash == null)
                        {
                            throw new InvalidOperationException("Cannot find Password Hashing Service");
                        }

                        dbu.DeviceSecret  = hash.ComputeHash(deviceSecret);
                        dbu.UpdatedByUuid = conn.Table <DbSecurityUser>().First(u => u.UserName == principal.Identity.Name).Uuid;
                        dbu.UpdatedTime   = DateTime.Now;
                        conn.Update(dbu);
                    }
                }
            }
            catch (Exception e)
            {
                this.m_tracer.TraceError("Error changing secret for device {0} : {1}", deviceName, e);
                throw;
            }
        }
        /// <summary>
        /// Change the user's password
        /// </summary>
        /// <param name="userName">User name.</param>
        /// <param name="newPassword">New password.</param>
        /// <param name="principal">Principal.</param>
        public void ChangePassword(string userName, string password, System.Security.Principal.IPrincipal principal)
        {
            // We must demand the change password permission
            IPolicyDecisionService pdp = ApplicationContext.Current.GetService <IPolicyDecisionService>();

            if (!userName.Equals(principal.Identity.Name, StringComparison.OrdinalIgnoreCase))
            {
                ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(PermissionPolicyIdentifiers.ChangePassword, principal);
            }

            // Password failed validation
            if (ApplicationServiceContext.Current.GetService <IPasswordValidatorService>()?.Validate(password) == false)
            {
                throw new DetectedIssueException(new DetectedIssue(DetectedIssuePriorityType.Error, "err.password.complexity", "Password does not meet complexity requirements", DetectedIssueKeys.SecurityIssue));
            }


            try
            {
                var conn = this.CreateConnection();
                using (conn.Lock())
                {
                    var dbu = conn.Table <DbSecurityUser>().Where(o => o.UserName.ToLower() == userName.ToLower()).FirstOrDefault();
                    if (dbu == null)
                    {
                        throw new KeyNotFoundException();
                    }
                    else
                    {
                        IPasswordHashingService hash = ApplicationContext.Current.GetService <IPasswordHashingService>();
                        dbu.Password      = hash.ComputeHash(password);
                        dbu.SecurityHash  = Guid.NewGuid().ToString();
                        dbu.UpdatedByUuid = conn.Table <DbSecurityUser>().First(u => u.UserName == principal.Identity.Name).Uuid;
                        dbu.UpdatedTime   = DateTime.Now;
                        conn.Update(dbu);
                    }
                }
            }
            catch (Exception e)
            {
                this.m_tracer.TraceError("Error changing password for user {0} : {1}", userName, e);
                throw new DataPersistenceException($"Error changing password for {userName}", e);
            }
        }
        public void TestQueryValidResult()
        {
            IPasswordHashingService hashingService = ApplicationContext.Current.GetService <IPasswordHashingService>();
            String       securityHash  = Guid.NewGuid().ToString();
            SecurityUser userUnderTest = new SecurityUser()
            {
                Email          = "*****@*****.**",
                EmailConfirmed = false,
                PasswordHash   = hashingService.ComputeHash("password"),
                SecurityHash   = securityHash,
                UserName       = "******"
            };

            var testUser = base.DoTestInsert(userUnderTest);
            IIdentityProviderService identityService = ApplicationContext.Current.GetService <IIdentityProviderService>();
            var results = base.DoTestQuery(o => o.Email == "*****@*****.**", testUser.Key);

            Assert.AreEqual(1, results.Count());
            Assert.AreEqual(userUnderTest.Email, results.First().Email);
        }
        /// <summary>
        /// Change the PIN for the user
        /// </summary>
        /// <param name="userName">The name of the user to change the PIN for</param>
        /// <param name="pin">The PIN to change to</param>
        /// <remarks>Only the currently logged in credential can change a PIN number for themselves</remarks>
        public void ChangePin(string userName, byte[] pin, IPrincipal principal)
        {
            // We must demand the change password permission
            IPolicyDecisionService pdp = ApplicationContext.Current.GetService <IPolicyDecisionService>();

            if (userName != principal.Identity.Name)
            {
                throw new SecurityException("Can only change PIN number of your own account");
            }
            else if (pin.Length < 4 || pin.Length > 8 || pin.Any(o => o < 0 || o > 9))
            {
                throw new ArgumentOutOfRangeException("PIN numbers must be between 4 and 8 digits");
            }

            try
            {
                var conn = this.CreateConnection();
                using (conn.Lock())
                {
                    var dbu = conn.Table <DbSecurityUser>().Where(o => o.UserName == userName).FirstOrDefault();
                    if (dbu == null)
                    {
                        throw new KeyNotFoundException();
                    }
                    else
                    {
                        IPasswordHashingService hash = ApplicationContext.Current.GetService <IPasswordHashingService>();
                        dbu.PinHash       = hash.ComputeHash(Encoding.UTF8.GetString(pin.Select(o => (byte)(o + 48)).ToArray(), 0, pin.Length));
                        dbu.SecurityHash  = Guid.NewGuid().ToString();
                        dbu.UpdatedByUuid = conn.Table <DbSecurityUser>().First(u => u.UserName == AuthenticationContext.Current.Principal.Identity.Name).Uuid;
                        dbu.UpdatedTime   = DateTime.Now;
                        conn.Update(dbu);
                    }
                }
            }
            catch (Exception e)
            {
                this.m_tracer.TraceError("Error changing password for user {0} : {1}", userName, e);
                throw new DataPersistenceException($"Error changing password for {userName}", e);
            }
        }
        public void TestUpdateValidSecurityUser()
        {
            IPasswordHashingService hashingService = ApplicationContext.Current.GetService <IPasswordHashingService>();

            SecurityUser userUnderTest = new SecurityUser()
            {
                Email          = "*****@*****.**",
                EmailConfirmed = false,
                PasswordHash   = hashingService.ComputeHash("password"),
                SecurityHash   = "cert",
                UserName       = "******"
            };

            // Store user
            IIdentityProviderService identityService = ApplicationContext.Current.GetService <IIdentityProviderService>();
            var userAfterUpdate = base.DoTestInsertUpdate(userUnderTest, "PhoneNumber");

            // Update
            //Assert.IsNotNull(userAfterUpdate.UpdatedTime);
            Assert.IsNotNull(userAfterUpdate.PhoneNumber);
        }
예제 #12
0
        /// <summary>
        /// Creates the identity.
        /// </summary>
        /// <param name="securityUser">The security user.</param>
        /// <param name="password">The password.</param>
        /// <param name="principal">The principal.</param>
        /// <returns>Returns the created user identity.</returns>
        /// <exception cref="PolicyViolationException"></exception>
        public IIdentity CreateIdentity(SecurityUser securityUser, string password, IPrincipal principal)
        {
            try
            {
                var pdp = ApplicationContext.Current.GetService <IPolicyDecisionService>();
                if (pdp.GetPolicyOutcome(principal ?? AuthenticationContext.Current.Principal, PolicyIdentifiers.AccessClientAdministrativeFunction) != PolicyGrantType.Grant)
                {
                    throw new PolicyViolationException(PolicyIdentifiers.AccessClientAdministrativeFunction, PolicyGrantType.Deny);
                }

                var conn = this.CreateConnection();
                IPasswordHashingService hash = ApplicationContext.Current.GetService <IPasswordHashingService>();

                using (conn.Lock())
                {
                    DbSecurityUser dbu = new DbSecurityUser()
                    {
                        PasswordHash  = hash.ComputeHash(password),
                        SecurityHash  = Guid.NewGuid().ToString(),
                        PhoneNumber   = securityUser.PhoneNumber,
                        Email         = securityUser.Email,
                        CreationTime  = DateTime.Now,
                        CreatedByUuid = conn.Table <DbSecurityUser>().FirstOrDefault(o => o.UserName == AuthenticationContext.Current?.Principal?.Identity?.Name)?.Uuid ?? Guid.Parse("fadca076-3690-4a6e-af9e-f1cd68e8c7e8").ToByteArray(),
                        UserName      = securityUser.UserName,
                        Key           = securityUser.Key.Value
                    };
                    conn.Insert(dbu);
                    this.DataCreated?.Invoke(this, new AuditDataEventArgs(dbu));
                }
                return(new SQLiteIdentity(securityUser.UserName, false));
            }
            catch
            {
                this.DataCreated?.Invoke(this, new AuditDataEventArgs(new SecurityUser())
                {
                    Success = false
                });
                throw;
            }
        }
예제 #13
0
        /// <summary>
        /// Authenticate the device
        /// </summary>
        public IPrincipal Authenticate(string deviceId, string deviceSecret, AuthenticationMethod authMethod = AuthenticationMethod.Any)
        {
            var config = ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>();

            if (!authMethod.HasFlag(AuthenticationMethod.Local))
            {
                throw new InvalidOperationException("Identity provider only supports local auth");
            }

            // Pre-event
            AuthenticatingEventArgs e = new AuthenticatingEventArgs(deviceId)
            {
            };

            this.Authenticating?.Invoke(this, e);
            if (e.Cancel)
            {
                this.m_tracer.TraceWarning("Pre-Event hook indicates cancel {0}", deviceId);
                return(e.Principal);
            }

            IPrincipal retVal = null;

            try
            {
                // Connect to the db
                var connection = this.CreateConnection();
                using (connection.Lock())
                {
                    // Password service
                    IPasswordHashingService passwordHash = ApplicationContext.Current.GetService(typeof(IPasswordHashingService)) as IPasswordHashingService;

                    DbSecurityDevice dbd = connection.Table <DbSecurityDevice>().FirstOrDefault(o => o.PublicId.ToLower() == deviceId.ToLower());
                    if (dbd == null)
                    {
                        throw new SecurityException(Strings.locale_authenticationFailure);
                    }
                    else if (config?.MaxInvalidLogins.HasValue == true && dbd.Lockout.HasValue && dbd.Lockout > DateTime.Now)
                    {
                        throw new SecurityException(Strings.locale_accountLocked);
                    }
                    else if (dbd.ObsoletionTime != null)
                    {
                        throw new SecurityException(Strings.locale_accountObsolete);
                    }
                    else if (!String.IsNullOrEmpty(deviceSecret) && passwordHash.ComputeHash(deviceSecret) != dbd.DeviceSecret)
                    {
                        dbd.InvalidAuthAttempts++;
                        connection.Update(dbd);
                        throw new SecurityException(Strings.locale_authenticationFailure);
                    }
                    else if (config?.MaxInvalidLogins.HasValue == true && dbd.InvalidAuthAttempts > config?.MaxInvalidLogins)
                    { //s TODO: Make this configurable
                        dbd.Lockout = DateTime.Now.AddSeconds(30 * (dbd.InvalidAuthAttempts - config.MaxInvalidLogins.Value));
                        connection.Update(dbd);
                        throw new SecurityException(Strings.locale_accountLocked);
                    } // TODO: Lacks login permission
                    else
                    {
                        dbd.LastAuthTime        = DateTime.Now;
                        dbd.InvalidAuthAttempts = 0;
                        connection.Update(dbd);

                        IPolicyDecisionService    pdp = ApplicationContext.Current.GetService <IPolicyDecisionService>();
                        IPolicyInformationService pip = ApplicationContext.Current.GetService <IPolicyInformationService>();
                        List <IClaim>             additionalClaims = new List <IClaim>();
                        additionalClaims.AddRange(pip.GetPolicies(dbd).Where(o => o.Rule == PolicyGrantType.Grant).Select(o => new SanteDBClaim(SanteDBClaimTypes.SanteDBGrantedPolicyClaim, o.Policy.Oid)));
                        additionalClaims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBDeviceIdentifierClaim, dbd.Key.ToString()));
                        additionalClaims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBApplicationIdentifierClaim, ApplicationContext.Current.Application.Key.ToString())); // Local application only for SQLite
                        // Create the principal
                        retVal = new SQLitePrincipal(new SQLiteDeviceIdentity(dbd.PublicId, true, DateTime.Now, DateTime.Now.Add(config?.MaxLocalSession ?? new TimeSpan(0, 15, 0)), additionalClaims), new string[] { });

                        ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(PermissionPolicyIdentifiers.LoginAsService, retVal);
                    }
                }

                // Post-event
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(deviceId, retVal, true));
            }
            catch (Exception ex)
            {
                this.m_tracer.TraceError("Error establishing device session ({1}): {0}", ex, deviceSecret);
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(deviceId, retVal, false));

                throw;
            }

            return(retVal);
        }
예제 #14
0
        /// <summary>
        /// Authenticate the user
        /// </summary>
        /// <param name="principal">Principal.</param>
        /// <param name="password">Password.</param>
        public IPrincipal Authenticate(IPrincipal principal, String password)
        {
            var config = ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>();

            if (principal == null)
            {
                throw new ArgumentNullException(nameof(principal));
            }
            else if (String.IsNullOrEmpty(password))
            {
                if (principal.Identity.IsAuthenticated)
                {
                    // Refresh
                    if (principal is SQLitePrincipal) /// extend the existing session
                    {
                        (principal as SQLitePrincipal).Expires = DateTime.Now.Add(config?.MaxLocalSession ?? new TimeSpan(0, 15, 0));
                    }
                    else if (principal is ClaimsPrincipal) // switch them to a SQLitePrincipal
                    {
                        var sid   = (principal as ClaimsPrincipal).FindClaim(ClaimTypes.Sid)?.Value;
                        var uname = (principal as ClaimsPrincipal).FindClaim(ClaimsIdentity.DefaultNameClaimType)?.Value;
                        if (!String.IsNullOrEmpty(uname))
                        {
                            ApplicationContext.Current.GetService <ITickleService>()?.SendTickle(new Tickler.Tickle(Guid.Parse(sid), Tickler.TickleType.SecurityInformation | Tickler.TickleType.Toast, Strings.locale_securitySwitchedMode, DateTime.Now.AddSeconds(10)));
                            return(new SQLitePrincipal(new SQLiteIdentity(uname, true), (principal as ClaimsPrincipal).Claims.Where(o => o.Type == ClaimsIdentity.DefaultRoleClaimType).Select(o => o.Value).ToArray())
                            {
                                Expires = DateTime.Now.Add(config?.MaxLocalSession ?? new TimeSpan(0, 15, 0)),
                                IssueTime = DateTime.Now
                            });
                        }
                        else
                        {
                            throw new SecurityException(Strings.locale_sessionError);
                        }
                    }
                    return(principal);
                }
                else
                {
                    throw new ArgumentNullException(nameof(password));
                }
            }

            // Pre-event
            AuthenticatingEventArgs e = new AuthenticatingEventArgs(principal.Identity.Name, password)
            {
                Principal = principal
            };

            this.Authenticating?.Invoke(this, e);
            if (e.Cancel)
            {
                this.m_tracer.TraceWarning("Pre-Event hook indicates cancel {0}", principal.Identity.Name);
                return(e.Principal);
            }

            IPrincipal retVal = null;

            try
            {
                // Connect to the db
                var connection = this.CreateConnection();
                using (connection.Lock())
                {
                    // Password service
                    IPasswordHashingService passwordHash = ApplicationContext.Current.GetService(typeof(IPasswordHashingService)) as IPasswordHashingService;

                    DbSecurityUser dbs = connection.Table <DbSecurityUser>().FirstOrDefault(o => o.UserName == principal.Identity.Name);
                    if (dbs == null)
                    {
                        throw new SecurityException(Strings.locale_invalidUserNamePassword);
                    }
                    else if (config?.MaxInvalidLogins.HasValue == true && dbs.Lockout.HasValue && dbs.Lockout > DateTime.Now)
                    {
                        throw new SecurityException(Strings.locale_accountLocked);
                    }
                    else if (dbs.ObsoletionTime != null)
                    {
                        throw new SecurityException(Strings.locale_accountObsolete);
                    }
                    else if (passwordHash.ComputeHash(password) != dbs.PasswordHash)
                    {
                        dbs.InvalidLoginAttempts++;
                        connection.Update(dbs);
                        throw new SecurityException(Strings.locale_invalidUserNamePassword);
                    }
                    else if (config?.MaxInvalidLogins.HasValue == true && dbs.InvalidLoginAttempts > config?.MaxInvalidLogins)
                    { //s TODO: Make this configurable
                        dbs.Lockout = DateTime.Now.AddSeconds(30 * (dbs.InvalidLoginAttempts - config.MaxInvalidLogins.Value));
                        connection.Update(dbs);
                        throw new SecurityException(Strings.locale_accountLocked);
                    } // TODO: Lacks login permission
                    else
                    {
                        dbs.LastLoginTime        = DateTime.Now;
                        dbs.InvalidLoginAttempts = 0;
                        connection.Update(dbs);

                        // Create the principal
                        retVal = new SQLitePrincipal(new SQLiteIdentity(dbs.UserName, true),
                                                     connection.Query <DbSecurityRole>("SELECT security_role.* FROM security_user_role INNER JOIN security_role ON (security_role.uuid = security_user_role.role_id) WHERE security_user_role.user_id = ?",
                                                                                       dbs.Uuid).Select(o => o.Name).ToArray())
                        {
                            IssueTime = DateTime.Now,
                            Expires   = DateTime.Now.Add(config?.MaxLocalSession ?? new TimeSpan(0, 15, 0))
                        };
                    }
                }

                // Post-event
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(principal.Identity.Name, password, true)
                {
                    Principal = retVal
                });
            }
            catch (Exception ex)
            {
                this.m_tracer.TraceError("Error establishing session: {0}", ex);
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(principal.Identity.Name, password, false)
                {
                    Principal = retVal
                });

                throw;
            }

            return(retVal);
        }
        /// <summary>
        /// Authenticate this user with a local PIN number
        /// </summary>
        /// <param name="userName">The name of the user</param>
        /// <param name="password">The password of the user</param>
        /// <param name="pin">The PIN number for PIN based authentication</param>
        /// <returns>The authenticated principal</returns>
        private IPrincipal AuthenticateInternal(String userName, string password, byte[] pin)
        {
            var config = ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>();

            // Pre-event
            AuthenticatingEventArgs e = new AuthenticatingEventArgs(userName)
            {
            };

            this.Authenticating?.Invoke(this, e);
            if (e.Cancel)
            {
                this.m_tracer.TraceWarning("Pre-Event hook indicates cancel {0}", userName);
                return(e.Principal);
            }

            IPrincipal retVal = null;

            try
            {
                // Connect to the db
                var connection = this.CreateConnection();
                using (connection.Lock())
                {
                    // Password service
                    IPasswordHashingService passwordHash = ApplicationContext.Current.GetService(typeof(IPasswordHashingService)) as IPasswordHashingService;

                    DbSecurityUser dbs = connection.Table <DbSecurityUser>().FirstOrDefault(o => o.UserName.ToLower() == userName.ToLower() && !o.ObsoletionTime.HasValue);
                    if (dbs == null)
                    {
                        throw new SecurityException(Strings.locale_invalidUserNamePassword);
                    }
                    else if (dbs.Lockout.HasValue && dbs.Lockout > DateTime.Now)
                    {
                        throw new SecurityException(Strings.locale_accountLocked);
                    }
                    else if (dbs.ObsoletionTime != null)
                    {
                        throw new SecurityException(Strings.locale_accountObsolete);
                    }
                    else if (!String.IsNullOrEmpty(password) && passwordHash.ComputeHash(password) != dbs.Password ||
                             pin != null && passwordHash.ComputeHash(Encoding.UTF8.GetString(pin.Select(o => (byte)(o + 48)).ToArray(), 0, pin.Length)) != dbs.PinHash)
                    {
                        dbs.InvalidLoginAttempts++;
                        connection.Update(dbs);
                        throw new SecurityException(Strings.locale_invalidUserNamePassword);
                    }
                    else if (config?.MaxInvalidLogins.HasValue == true && dbs.InvalidLoginAttempts > config?.MaxInvalidLogins)
                    { //s TODO: Make this configurable
                        dbs.Lockout = DateTime.Now.AddSeconds(30 * (dbs.InvalidLoginAttempts - config.MaxInvalidLogins.Value));
                        connection.Update(dbs);
                        throw new SecurityException(Strings.locale_accountLocked);
                    } // TODO: Lacks login permission
                    else
                    {
                        dbs.LastLoginTime        = DateTime.Now;
                        dbs.InvalidLoginAttempts = 0;
                        connection.Update(dbs);

                        var roles = connection.Query <DbSecurityRole>("SELECT security_role.* FROM security_user_role INNER JOIN security_role ON (security_role.uuid = security_user_role.role_id) WHERE lower(security_user_role.user_id) = lower(?)",
                                                                      dbs.Uuid).Select(o => o.Name).ToArray();

                        var additionalClaims = new List <IClaim>()
                        {
                            new SanteDBClaim(SanteDBClaimTypes.NameIdentifier, dbs.Key.ToString()),
                            new SanteDBClaim(SanteDBClaimTypes.DefaultNameClaimType, dbs.UserName),
                            new SanteDBClaim(SanteDBClaimTypes.SanteDBApplicationIdentifierClaim, ApplicationContext.Current.Application.Key.ToString()), // Local application only allows
                            new SanteDBClaim(SanteDBClaimTypes.SanteDBDeviceIdentifierClaim, ApplicationContext.Current.Device.Key.ToString())
                        };

                        // Create the principal
                        retVal = new SQLitePrincipal(new SQLiteIdentity(dbs.UserName, true, DateTime.Now, DateTime.Now.Add(config?.MaxLocalSession ?? new TimeSpan(0, 15, 0)), additionalClaims), roles);
                        ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(PermissionPolicyIdentifiers.Login, retVal);
                    }
                }

                // Post-event
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(userName, retVal, true));
            }
            catch (Exception ex)
            {
                this.m_tracer.TraceError("Error establishing session: {0}", ex);
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(userName, retVal, false));
                throw new DataPersistenceException($"Error establishing session", ex);
            }

            return(retVal);
        }
예제 #16
0
        /// <summary>
        /// Authenticate the application identity to an application principal
        /// </summary>
        public IPrincipal Authenticate(string applicationId, string applicationSecret)
        {
            // Data context
            using (DataContext dataContext = this.m_configuration.Provider.GetWriteConnection())
            {
                try
                {
                    dataContext.Open();
                    IPasswordHashingService hashService = ApplicationServiceContext.Current.GetService <IPasswordHashingService>();

                    var client = dataContext.FirstOrDefault <DbSecurityApplication>("auth_app", applicationId, hashService.ComputeHash(applicationSecret), 5);
                    if (client == null)
                    {
                        throw new SecurityException("Invalid application credentials");
                    }
                    else if (client.Key == Guid.Empty)
                    {
                        throw new AuthenticationException(client.PublicId);
                    }

                    IPrincipal applicationPrincipal = new ApplicationPrincipal(new SanteDB.Core.Security.ApplicationIdentity(client.Key, client.PublicId, true));
                    new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.LoginAsService, applicationPrincipal).Demand();
                    return(applicationPrincipal);
                }
                catch (Exception e)
                {
                    this.m_traceSource.TraceEvent(EventLevel.Error, "Error authenticating {0} : {1}", applicationId, e);
                    throw new AuthenticationException("Error authenticating application", e);
                }
            }
        }