Ejemplo n.º 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);
        }
        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);
            }
        }
Ejemplo n.º 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);
        }
        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);
        }