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")); }
/// <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); }
/// <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; } }
/// <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); }
/// <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; } }
/// <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); }
/// <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); }
/// <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); } } }