/// <summary> /// Authenticate the user /// </summary> public IPrincipal Authenticate(string userName, string password) { var evt = new AuthenticatingEventArgs(userName); this.Authenticating?.Invoke(this, evt); if (evt.Cancel) { throw new SecurityException("Authentication cancelled"); } try { var principal = SqlClaimsIdentity.Create(userName, password).CreateClaimsPrincipal(); this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(userName, principal, true)); return(principal); } catch (SecurityException e) { this.m_traceSource.TraceEvent(TraceEventType.Verbose, e.HResult, "Invalid credentials : {0}/{1}", userName, password); this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(userName, null, false)); throw; } }
/// <summary> /// Create a basic user /// </summary> public IIdentity CreateIdentity(string userName, string password, IPrincipal authContext) { if (String.IsNullOrEmpty(userName)) { throw new ArgumentNullException(nameof(userName)); } else if (String.IsNullOrEmpty(password)) { throw new ArgumentNullException(nameof(password)); } else if (authContext == null) { throw new ArgumentNullException(nameof(authContext)); } this.m_traceSource.TraceInformation("Creating identity {0} ({1})", userName, authContext); try { using (var dataContext = new ModelDataContext(this.m_configuration.ReadWriteConnectionString)) { var hashingService = ApplicationContext.Current.GetService <IPasswordHashingService>(); var pdpService = ApplicationContext.Current.GetService <IPolicyDecisionService>(); // Demand create identity new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.CreateIdentity, authContext).Demand(); // Does this principal have the ability to Data.SecurityUser newIdentityUser = new Data.SecurityUser() { UserId = Guid.NewGuid(), UserName = userName, UserPassword = hashingService.EncodePassword(password), SecurityStamp = Guid.NewGuid().ToString(), UserClass = UserClassKeys.HumanUser }; if (authContext != null) { newIdentityUser.CreatedByEntity = dataContext.SecurityUsers.Single(u => u.UserName == authContext.Identity.Name); } dataContext.SecurityUsers.InsertOnSubmit(newIdentityUser); dataContext.SubmitChanges(); return(SqlClaimsIdentity.Create(newIdentityUser)); } } catch (Exception e) { this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); throw; } }
/// <summary> /// Authenticate using a refresh token /// </summary> public IPrincipal Authenticate(byte[] refreshToken) { if (refreshToken == null) { throw new ArgumentNullException(nameof(refreshToken)); } else if (refreshToken.Length != 32) { throw new ArgumentOutOfRangeException(nameof(refreshToken), "Invalid refresh token"); } string trokenName = BitConverter.ToString(refreshToken).Replace("-", ""); var evt = new AuthenticatingEventArgs(trokenName); this.Authenticating?.Invoke(this, evt); if (evt.Cancel) { throw new SecurityException("Authentication cancelled"); } try { var principal = SqlClaimsIdentity.Create(refreshToken).CreateClaimsPrincipal(); this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(trokenName, principal, true)); return(principal); } catch (SecurityException e) { this.m_traceSource.TraceEvent(TraceEventType.Verbose, e.HResult, "Invalid credentials : {0}", refreshToken); this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(trokenName, null, false)); throw; } }
/// <summary> /// Authenticate the user using a TwoFactorAuthentication secret /// </summary> public IPrincipal Authenticate(string userName, string password, string tfaSecret) { // First, let's verify the TFA if (String.IsNullOrEmpty(userName)) { throw new ArgumentNullException(nameof(userName)); } else if (String.IsNullOrEmpty(tfaSecret)) { throw new ArgumentNullException(nameof(tfaSecret)); } // Authentication event args var evt = new AuthenticatingEventArgs(userName); this.Authenticating?.Invoke(this, evt); if (evt.Cancel) { throw new SecurityException("Authentication cancelled"); } // Password hasher var hashingService = ApplicationContext.Current.GetService <IPasswordHashingService>(); tfaSecret = hashingService.EncodePassword(tfaSecret); // Try to authenticate try { using (var dataContext = new ModelDataContext(this.m_configuration.ReadWriteConnectionString)) { var user = dataContext.SecurityUsers.FirstOrDefault(o => o.UserName == userName); if (user == null) { throw new KeyNotFoundException(userName); } SecurityUserClaim tfaClaim = dataContext.SecurityUserClaims.FirstOrDefault(o => o.UserId == user.Id && o.ClaimType == OpenIzClaimTypes.OpenIZTfaSecretClaim), tfaExpiry = dataContext.SecurityUserClaims.FirstOrDefault(o => o.UserId == user.Id && o.ClaimType == OpenIzClaimTypes.OpenIZTfaSecretExpiry), noPassword = dataContext.SecurityUserClaims.FirstOrDefault(o => o.UserId == user.Id && o.ClaimType == OpenIzClaimTypes.OpenIZPasswordlessAuth); if (tfaClaim == null || tfaExpiry == null) { throw new InvalidOperationException("Cannot find appropriate claims for TFA"); } // Expiry check ClaimsPrincipal retVal = null; DateTime expiryDate = DateTime.Parse(tfaExpiry.ClaimValue); if (expiryDate < DateTime.Now) { throw new SecurityException("TFA secret expired"); } else if (String.IsNullOrEmpty(password) && Boolean.Parse(noPassword?.ClaimValue ?? "false") && tfaSecret == tfaClaim.ClaimValue) // Last known password hash sent as password, this is a password reset token - It will be set to expire ASAP { retVal = SqlClaimsIdentity.Create(user, true, "Tfa+LastPasswordHash").CreateClaimsPrincipal(); (retVal.Identity as ClaimsIdentity).AddClaim(new Claim(OpenIzClaimTypes.OpenIzGrantedPolicyClaim, PermissionPolicyIdentifiers.ChangePassword)); (retVal.Identity as ClaimsIdentity).RemoveClaim(retVal.FindFirst(ClaimTypes.Expiration)); // TODO: Add to configuration (retVal.Identity as ClaimsIdentity).AddClaim(new Claim(ClaimTypes.Expiration, DateTime.Now.AddMinutes(5).ToString("o"))); } else if (!String.IsNullOrEmpty(password)) { retVal = this.Authenticate(userName, password) as ClaimsPrincipal; } else { throw new PolicyViolationException(PermissionPolicyIdentifiers.Login, PolicyDecisionOutcomeType.Deny); } // Now we want to fire authenticated this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(userName, retVal, true)); return(retVal); } } catch (Exception e) { this.m_traceSource.TraceEvent(TraceEventType.Verbose, e.HResult, "Invalid credentials : {0}/{1}", userName, password); this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(userName, null, false)); throw; } }
/// <summary> /// Gets an un-authenticated identity /// </summary> public IIdentity GetIdentity(string userName) { return(SqlClaimsIdentity.Create(userName)); }