public ValidationResult Validate(UserAccountService service, T account, string value)
        {
            if (String.IsNullOrWhiteSpace(value))
            {
                return(new ValidationResult(service.GetValidationMessage(MembershipRebootConstants.ValidationMessages.PasswordRequired)));
            }

            if (value.Length < this.MinimumLength)
            {
                return(new ValidationResult(String.Format(service.GetValidationMessage(MembershipRebootConstants.ValidationMessages.PasswordLength), this.MinimumLength)));
            }

            var upper = value.Any(x => Char.IsUpper(x));
            var lower = value.Any(x => Char.IsLower(x));
            var digit = value.Any(x => Char.IsDigit(x));
            var other = value.Any(x => !Char.IsUpper(x) && !Char.IsLower(x) && !Char.IsDigit(x));

            var vals    = new bool[] { upper, lower, digit, other };
            var matches = vals.Where(x => x).Count();

            if (matches < this.MinimumNumberOfComplexityRules)
            {
                return(new ValidationResult(String.Format(service.GetValidationMessage(MembershipRebootConstants.ValidationMessages.PasswordComplexityRules), this.MinimumNumberOfComplexityRules)));
            }

            return(null);
        }
        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");
            }

            Tracing.Information("[AuthenticationService.SignIn] sign in called: {0}", account.ID);

            if (!account.IsLoginAllowed || account.IsAccountClosed)
            {
                throw new ValidationException(UserAccountService.GetValidationMessage(MembershipRebootConstants.ValidationMessages.LoginNotAllowed));
            }

            if (!account.IsAccountVerified && UserAccountService.Configuration.RequireAccountVerification)
            {
                throw new ValidationException(UserAccountService.GetValidationMessage(MembershipRebootConstants.ValidationMessages.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 = GetAllClaims(account, method);

            // 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
            Tracing.Verbose("[AuthenticationService.SignIn] token issued: {0}", account.ID);
            IssueToken(cp, persistentCookie: persistent);
        }
Ejemplo n.º 3
0
        public void Handle(CertificateAddedEvent <TAccount> evt)
        {
            if (evt == null)
            {
                throw new ArgumentNullException("event");
            }
            if (evt.Account == null)
            {
                throw new ArgumentNullException("account");
            }
            if (evt.Certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }

            if (userAccountService.Configuration.CertificateIsUnique)
            {
                var account      = evt.Account;
                var otherAccount = userAccountService.GetByCertificate(account.Tenant, evt.Certificate.Thumbprint);
                if (otherAccount != null && otherAccount.ID != account.ID)
                {
                    Tracing.Verbose("[UserAccountValidation.CertificateThumbprintMustBeUnique] validation failed: {0}, {1}", account.Tenant, account.Username);
                    throw new ValidationException(userAccountService.GetValidationMessage("CertificateAlreadyInUse"));
                }
            }
        }
Ejemplo n.º 4
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");
            }

            var user = GetCurentPrincipal();

            if (user != null && user.Identity.IsAuthenticated)
            {
                // already logged in, so use the current user's account
                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)
                {
                    // 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));
                    }

                    // guess at a name to use
                    var name = claims.GetValue(ClaimTypes.Name);
                    if (name == null ||
                        this.UserAccountService.UsernameExists(tenant, name))
                    {
                        name = email;
                    }
                    else
                    {
                        name = name.Replace(" ", "");
                    }

                    // check to see if email already exists
                    if (this.UserAccountService.EmailExists(tenant, email))
                    {
                        throw new ValidationException(UserAccountService.GetValidationMessage(MembershipRebootConstants.ValidationMessages.LoginFailEmailAlreadyAssociated));
                    }

                    // auto-gen a password, they can always reset it later if they want to use the password feature
                    // this is slightly dangerous if we don't do email account verification, so if email account
                    // verification is disabled then we need to be very confident that the external provider has
                    // provided us with a verified email
                    account = this.UserAccountService.CreateAccount(tenant, name, null, email);
                }
            }

            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)
            {
                // 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);
            }
        }
Ejemplo n.º 5
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 = 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 = 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.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);
            }
        }
        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);
        }