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