protected internal virtual bool VerifyTwoFactorAuthCode(string code) { Tracing.Information("[UserAccount.VerifyTwoFactorAuthCode] called for accountID: {0}", this.ID); if (code == null) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed - null code"); return(false); } if (!this.IsAccountVerified) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed -- account not verified"); return(false); } if (this.IsAccountClosed) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed -- account closed"); return(false); } if (!this.IsLoginAllowed) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed -- login not allowed"); return(false); } if (this.AccountTwoFactorAuthMode != TwoFactorAuthMode.Mobile) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed -- two factor auth mode not mobile"); return(false); } if (this.CurrentTwoFactorAuthStatus != TwoFactorAuthMode.Mobile) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed -- current auth status not mobile"); return(false); } if (IsMobileCodeStale) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed -- mobile code stale"); return(false); } if (code != this.MobileCode) { Tracing.Error("[UserAccount.VerifyTwoFactorAuthCode] failed -- codes don't match"); return(false); } Tracing.Verbose("[UserAccount.VerifyTwoFactorAuthCode] success"); this.LastLogin = UtcNow; this.CurrentTwoFactorAuthStatus = TwoFactorAuthMode.None; this.ClearMobileAuthCode(); this.AddEvent(new SuccessfulTwoFactorAuthCodeLoginEvent { Account = this }); return(true); }
public void SignInWithLinkedAccount( string tenant, string providerName, string providerAccountID, IEnumerable <Claim> claims, out TAccount account) { account = null; if (!UserAccountService.Configuration.MultiTenant) { tenant = UserAccountService.Configuration.DefaultTenant; } if (String.IsNullOrWhiteSpace(tenant)) { throw new ArgumentException("tenant"); } if (String.IsNullOrWhiteSpace(providerName)) { throw new ArgumentException("providerName"); } if (String.IsNullOrWhiteSpace(providerAccountID)) { throw new ArgumentException("providerAccountID"); } if (claims == null) { throw new ArgumentNullException("claims"); } Tracing.Information("[AuthenticationService.SignInWithLinkedAccount] tenant: {0}, provider: {1}, id: {2}", tenant, providerName, providerAccountID); var user = GetCurentPrincipal(); if (user != null && user.Identity.IsAuthenticated) { // already logged in, so use the current user's account Tracing.Verbose("[AuthenticationService.SignInWithLinkedAccount] user already logged in as: {0}", user.Identity.Name); account = this.UserAccountService.GetByID(user.GetUserID()); } else { // see if there's already an account mapped to this provider account = this.UserAccountService.GetByLinkedAccount(tenant, providerName, providerAccountID); if (account == null) { Tracing.Verbose("[AuthenticationService.SignInWithLinkedAccount] linked account not found"); // no account associated, so create one // we need email var email = claims.GetValue(ClaimTypes.Email); if (String.IsNullOrWhiteSpace(email)) { throw new ValidationException(UserAccountService.GetValidationMessage(MembershipRebootConstants.ValidationMessages.AccountCreateFailNoEmailFromIdp)); } // check to see if email already exists if (this.UserAccountService.EmailExists(tenant, email)) { throw new ValidationException(UserAccountService.GetValidationMessage(MembershipRebootConstants.ValidationMessages.LoginFailEmailAlreadyAssociated)); } // guess at a username to use var name = claims.GetValue(ClaimTypes.Name); // remove whitespace if (name != null) { name = new String(name.Where(x => Char.IsLetterOrDigit(x)).ToArray()); } // check to see if username already exists if (String.IsNullOrWhiteSpace(name) || this.UserAccountService.UsernameExists(tenant, name)) { // try use email for name then name = email.Substring(0, email.IndexOf('@')); name = new String(name.Where(x => Char.IsLetterOrDigit(x)).ToArray()); if (this.UserAccountService.UsernameExists(tenant, name)) { // gen random username -- this isn't ideal but // they should always be able to change it later name = Guid.NewGuid().ToString("N"); } } // create account without password -- user can verify their email and then // do a password reset to assign password Tracing.Verbose("[AuthenticationService.SignInWithLinkedAccount] creating account: {0}, {1}", name, email); account = this.UserAccountService.CreateAccount(tenant, name, null, email); // update account with external claims var cmd = new MapClaimsToAccount <TAccount> { Account = account, Claims = claims }; this.UserAccountService.ExecuteCommand(cmd); this.UserAccountService.Update(account); } else { Tracing.Verbose("[AuthenticationService.SignInWithLinkedAccount] linked account found: {0}", account.ID); } } if (account == null) { throw new Exception("Failed to locate account"); } // add/update the provider with this account this.UserAccountService.AddOrUpdateLinkedAccount(account, providerName, providerAccountID, claims); // log them in if the account if they're verified if (account.IsAccountVerified || !UserAccountService.Configuration.RequireAccountVerification) { Tracing.Verbose("[AuthenticationService.SignInWithLinkedAccount] signing user in: {0}", account.ID); // signin from the account // if we want to include the provider's claims, then perhaps this // should be done in the claims transformer this.SignIn(account, providerName); } else { Tracing.Error("[AuthenticationService.SignInWithLinkedAccount] user account not verified, not allowed to login: {0}", account.ID); } }
protected internal virtual bool Authenticate(string password, int failedLoginCount, TimeSpan lockoutDuration) { Tracing.Information("[UserAccount.Authenticate] called for accountID: {0}", this.ID); if (failedLoginCount <= 0) { throw new ArgumentException("failedLoginCount"); } if (String.IsNullOrWhiteSpace(password)) { Tracing.Error("[UserAccount.Authenticate] failed -- no password"); return(false); } if (!IsAccountVerified) { Tracing.Error("[UserAccount.Authenticate] failed -- account not verified"); this.AddEvent(new AccountNotVerifiedEvent { Account = this }); return(false); } if (IsAccountClosed) { Tracing.Error("[UserAccount.Authenticate] failed -- account closed"); return(false); } if (!IsLoginAllowed) { Tracing.Error("[UserAccount.Authenticate] failed -- account not allowed to login"); this.AddEvent(new AccountLockedEvent { Account = this }); return(false); } if (HasTooManyRecentPasswordFailures(failedLoginCount, lockoutDuration)) { Tracing.Error("[UserAccount.Authenticate] failed -- account in lockout due to failed login attempts"); FailedLoginCount++; this.AddEvent(new TooManyRecentPasswordFailuresEvent { Account = this }); return(false); } var valid = VerifyHashedPassword(password); if (valid) { Tracing.Verbose("[UserAccount.Authenticate] authentication success"); LastLogin = UtcNow; FailedLoginCount = 0; this.AddEvent(new SuccessfulPasswordLoginEvent { Account = this }); } else { Tracing.Error("[UserAccount.Authenticate] failed -- invalid password"); LastFailedLogin = UtcNow; if (FailedLoginCount > 0) { FailedLoginCount++; } else { FailedLoginCount = 1; } this.AddEvent(new InvalidPasswordEvent { Account = this }); } return(valid); }
public virtual void SignIn(TAccount account, string method, bool persistent = false) { if (account == null) { throw new ArgumentNullException("account"); } if (String.IsNullOrWhiteSpace(method)) { throw new ArgumentNullException("method"); } if (!account.IsLoginAllowed || account.IsAccountClosed) { throw new ValidationException(UserAccountService.GetValidationMessage("LoginNotAllowed")); } if (!account.IsAccountVerified && UserAccountService.Configuration.RequireAccountVerification) { throw new ValidationException(UserAccountService.GetValidationMessage("AccountNotVerified")); } if (account.RequiresTwoFactorAuthToSignIn() || account.RequiresPasswordReset || this.UserAccountService.IsPasswordExpired(account)) { Tracing.Verbose("[AuthenticationService.SignIn] detected account requires two factor or password reset to sign in: {0}", account.ID); IssuePartialSignInToken(account, method); return; } // gather claims var claims = GetBasicClaims(account, method); // get the rest if (!String.IsNullOrWhiteSpace(account.Email)) { claims.Add(new Claim(ClaimTypes.Email, account.Email)); } if (!String.IsNullOrWhiteSpace(account.MobilePhoneNumber)) { claims.Add(new Claim(ClaimTypes.MobilePhone, account.MobilePhoneNumber)); } var x509 = from c in account.Certificates select new Claim(ClaimTypes.X500DistinguishedName, c.Subject); claims.AddRange(x509); var otherClaims = (from uc in account.Claims select new Claim(uc.Type, uc.Value)).ToList(); claims.AddRange(otherClaims); // get custom claims from properties var cmd = new MapClaimsFromAccount <TAccount> { Account = account }; this.UserAccountService.ExecuteCommand(cmd); if (cmd.MappedClaims != null) { claims.AddRange(cmd.MappedClaims); } // create principal/identity var id = new ClaimsIdentity(claims, method); var cp = new ClaimsPrincipal(id); // claims transform if (this.ClaimsAuthenticationManager != null) { cp = ClaimsAuthenticationManager.Authenticate(String.Empty, cp); } // issue cookie IssueToken(cp, persistentCookie: persistent); }