Beispiel #1
0
        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);
        }
Beispiel #2
0
        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 = GetCurrentPrincipal();

            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 = ParseValidUsername(name);
                    }

                    // 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 = ParseValidUsername(name);

                        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.CreateUserAccount();

                    // update account with external claims
                    var cmd = new MapClaimsToAccount <TAccount> {
                        Account = account, Claims = claims
                    };
                    this.UserAccountService.ExecuteCommand(cmd);

                    this.UserAccountService.CreateAccount(tenant, name, null, email, account: 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);
            }
        }
Beispiel #3
0
        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);
        }