public ValidationResult Validate(UserAccountService service, UserAccount account, string value) { if (String.IsNullOrWhiteSpace(value)) { return new ValidationResult(Resources.ValidationMessages.PasswordRequired); } if (value.Length < this.MinimumLength) { return new ValidationResult(String.Format(Resources.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(Resources.ValidationMessages.PasswordComplexityRules, this.MinimumNumberOfComplexityRules)); } return null; }
public virtual void SignIn(UserAccount account, string method) { if (account == null) throw new ArgumentNullException("account"); if (String.IsNullOrWhiteSpace(method)) throw new ArgumentNullException("method"); if (!account.IsAccountVerified) { throw new ValidationException("Account not yet verified"); } if (!account.IsLoginAllowed) { throw new ValidationException("Login not allowed for this account"); } // gather claims var claims = (from uc in account.Claims select new Claim(uc.Type, uc.Value)).ToList(); if (!String.IsNullOrWhiteSpace(account.Email)) { claims.Insert(0, new Claim(ClaimTypes.Email, account.Email)); } claims.Insert(0, new Claim(ClaimTypes.AuthenticationMethod, method)); claims.Insert(0, new Claim(ClaimTypes.AuthenticationInstant, DateTime.UtcNow.ToString("s"))); claims.Insert(0, new Claim(ClaimTypes.Name, account.Username)); claims.Insert(0, new Claim(MembershipRebootConstants.ClaimTypes.Tenant, account.Tenant)); claims.Insert(0, new Claim(ClaimTypes.NameIdentifier, account.ID.ToString("D"))); // create principal/identity var id = new ClaimsIdentity(claims, method); var cp = new ClaimsPrincipal(id); // claims transform cp = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager.Authenticate(String.Empty, cp); // issue cookie var sam = FederatedAuthentication.SessionAuthenticationModule; if (sam == null) { Tracing.Verbose("[ClaimsBasedAuthenticationService.Signin] SessionAuthenticationModule is not configured"); throw new Exception("SessionAuthenticationModule is not configured and it needs to be."); } var handler = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers[typeof(SessionSecurityToken)] as SessionSecurityTokenHandler; if (handler == null) { Tracing.Verbose("[ClaimsBasedAuthenticationService.Signin] SessionSecurityTokenHandler is not configured"); throw new Exception("SessionSecurityTokenHandler is not configured and it needs to be."); } var token = new SessionSecurityToken(cp, handler.TokenLifetime); token.IsPersistent = FederatedAuthentication.FederationConfiguration.WsFederationConfiguration.PersistentCookiesOnPassiveRedirects; token.IsReferenceMode = sam.IsReferenceMode; sam.WriteSessionTokenToCookie(token); Tracing.Verbose(String.Format("[ClaimsBasedAuthenticationService.Signin] cookie issued: {0}", claims.GetValue(ClaimTypes.NameIdentifier))); }
public string GetTwoFactorAuthToken(UserAccount account) { if (account == null) throw new ArgumentNullException("account"); var result = GetCookie(MembershipRebootConstants.AuthenticationService.CookieBasedTwoFactorAuthPolicyCookieName + account.Tenant); Tracing.Information("[CookieBasedTwoFactorAuthPolicy.ClearTwoFactorAuthToken] getting cookie for {0}, {1}, found:{2}", account.Tenant, account.Username, result); return result; }
public static UserAccount Create(string username, string password, string email) { if (SecuritySettings.Instance.EmailIsUsername && username != email) { throw new ValidationException("Username must be the same as the Email"); } UserAccount account = new UserAccount { Username = username, Email = email, Created = DateTime.UtcNow, IsAccountVerified = !SecuritySettings.Instance.RequireAccountVerification, IsLoginAllowed = SecuritySettings.Instance.AllowLoginAfterAccountCreation, Claims = new List<UserClaim>() }; account.SetPassword(password); if (SecuritySettings.Instance.RequireAccountVerification) { account.VerificationKey = StripUglyBase64(Crypto.GenerateSalt()); account.VerificationKeySent = DateTime.UtcNow; } return account; }
public void SendAccountVerified(UserAccount user) { Tracing.Information(String.Format("[NotificationService.SendAccountVerified] {0}, {1}, {2}", user.Tenant, user.Username, user.Email)); var msg = GetAccountVerifiedFormat(); var body = DoTokenReplacement(msg, user); DeliverMessage(user, "Account Verified", body); }
public void Remove(UserAccount item) { foreach (var claim in item.Claims.ToArray()) { item.Claims.Remove(claim); } db.Users.Remove(item); }
public virtual void SignIn(UserAccount account, string method) { if (account == null) throw new ArgumentNullException("account"); if (String.IsNullOrWhiteSpace(method)) throw new ArgumentNullException("method"); if (!account.IsAccountVerified) { throw new ValidationException(Resources.ValidationMessages.AccountNotVerified); } if (!account.IsLoginAllowed) { throw new ValidationException(Resources.ValidationMessages.LoginNotAllowed); } 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); // 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); }
internal protected void ValidateUsername(UserAccount account, string value) { var result = this.usernameValidator.Value.Validate(this, account, value); if (result != null && result != ValidationResult.Success) { Tracing.Error("ValidateUsername failed: " + result.ErrorMessage); throw new ValidationException(result.ErrorMessage); } }
public virtual void SignIn(UserAccount account, string method) { if (account == null) throw new ArgumentNullException("account"); if (String.IsNullOrWhiteSpace(method)) throw new ArgumentNullException("method"); if (!account.IsAccountVerified) { throw new ValidationException("Account not yet verified."); } if (!account.IsLoginAllowed) { throw new ValidationException("Login not allowed for this account."); } if (account.RequiresTwoFactorAuthToSignIn) { Tracing.Verbose("[AuthenticationService.SignIn] detected account requires two factor to sign in: {0}", account.Id); IssuePartialSignInTokenForTwoFactorAuth(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); // create principal/identity var id = new ClaimsIdentity(claims, method); var cp = new ClaimsPrincipal(id); // claims transform cp = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager.Authenticate(String.Empty, cp); // issue cookie IssueToken(cp); }
protected virtual string DoTokenReplacement(string msg, UserAccount user) { msg = msg.Replace("{username}", user.Username); msg = msg.Replace("{email}", user.Email); msg = msg.Replace("{applicationName}", appInfo.ApplicationName); msg = msg.Replace("{emailSignature}", appInfo.EmailSignature); msg = msg.Replace("{loginUrl}", appInfo.LoginUrl); msg = msg.Replace("{confirmAccountCreateUrl}", appInfo.VerifyAccountUrl + user.VerificationKey); msg = msg.Replace("{cancelNewAccountUrl}", appInfo.CancelNewAccountUrl + user.VerificationKey); msg = msg.Replace("{confirmPasswordResetUrl}", appInfo.ConfirmPasswordResetUrl + user.VerificationKey); msg = msg.Replace("{confirmChangeEmailUrl}", appInfo.ConfirmChangeEmailUrl + user.VerificationKey); return msg; }
internal static UserAccount Create(string tenant, string username, string password, string email) { UserAccount account = new UserAccount { Tenant = tenant, Username = username, Email = email, Created = DateTime.UtcNow, IsAccountVerified = !SecuritySettings.Instance.RequireAccountVerification, IsLoginAllowed = SecuritySettings.Instance.AllowLoginAfterAccountCreation, Claims = new List<UserClaim>() }; account.SetPassword(password); if (SecuritySettings.Instance.RequireAccountVerification) { account.VerificationKey = StripUglyBase64(Crypto.GenerateSalt()); account.VerificationKeySent = DateTime.UtcNow; } return account; }
public virtual void Update(UserAccount account) { if (account == null) { Tracing.Error("[UserAccountService.Update] called -- failed null account"); throw new ArgumentNullException("account"); } Tracing.Information("[UserAccountService.Update] called for account: {0}", account.ID); account.LastUpdated = account.UtcNow; this.userRepository.Update(account); }
public virtual bool AuthenticateWithCertificate(Guid accountID, X509Certificate2 certificate, out UserAccount account) { Tracing.Information("[UserAccountService.AuthenticateWithCertificate] called for userID: {0}", accountID); certificate.Validate(); account = this.GetByID(accountID); if (account == null) throw new ArgumentException("Invalid AccountID"); var result = account.Authenticate(certificate); Update(account); Tracing.Verbose("[UserAccountService.AuthenticateWithCertificate] result: {0}", result); return result; }
public virtual bool AuthenticateWithCertificate(X509Certificate2 certificate, out UserAccount account) { Tracing.Information("[UserAccountService.AuthenticateWithCertificate] called"); certificate.Validate(); account = this.GetByCertificate(certificate.Thumbprint); if (account == null) return false; var result = account.Authenticate(certificate); Update(account); Tracing.Verbose("[UserAccountService.AuthenticateWithCertificate] result {0}", result); return result; }
public virtual bool AuthenticateWithCode(Guid accountID, string code, out UserAccount account) { Tracing.Information("[UserAccountService.AuthenticateWithCode] called {0}", accountID); account = this.GetByID(accountID); if (account == null) throw new ArgumentException("Invalid AccountID"); var result = account.VerifyTwoFactorAuthCode(code); Update(account); Tracing.Verbose("[UserAccountService.AuthenticateWithCode] result {0}", result); return result; }
protected internal virtual bool Authenticate(UserAccount account, string password, AuthenticationPurpose purpose) { Tracing.Verbose("[UserAccountService.Authenticate] for account: {0}", account.ID); int failedLoginCount = SecuritySettings.AccountLockoutFailedLoginAttempts; TimeSpan lockoutDuration = SecuritySettings.AccountLockoutDuration; var result = account.Authenticate(password, failedLoginCount, lockoutDuration); if (result && purpose == AuthenticationPurpose.SignIn && account.AccountTwoFactorAuthMode != TwoFactorAuthMode.None) { Tracing.Verbose("[UserAccountService.Authenticate] password authN successful, doing two factor auth checks: {0}, {1}", account.Tenant, account.Username); bool shouldRequestTwoFactorAuthCode = true; if (this.Configuration.TwoFactorAuthenticationPolicy != null) { shouldRequestTwoFactorAuthCode = this.Configuration.TwoFactorAuthenticationPolicy.RequestRequiresTwoFactorAuth(account); Tracing.Verbose("[UserAccountService.Authenticate] TwoFactorAuthenticationPolicy.RequestRequiresTwoFactorAuth called, result: {0}", shouldRequestTwoFactorAuthCode); } if (shouldRequestTwoFactorAuthCode) { if (account.AccountTwoFactorAuthMode == TwoFactorAuthMode.Certificate) { Tracing.Verbose("[UserAccountService.Authenticate] requesting 2fa certificate: {0}, {1}", account.Tenant, account.Username); result = account.RequestTwoFactorAuthCertificate(); } if (account.AccountTwoFactorAuthMode == TwoFactorAuthMode.Mobile) { Tracing.Verbose("[UserAccountService.Authenticate] requesting 2fa mobile code: {0}, {1}", account.Tenant, account.Username); result = account.RequestTwoFactorAuthCode(); } } } Update(account); Tracing.Verbose("[UserAccountService.Authenticate] authentication outcome: {0}", result ? "Successful Login" : "Failed Login"); return result; }
public virtual bool AuthenticateWithUsernameOrEmail(string tenant, string userNameOrEmail, string password, out UserAccount account) { account = null; if (!SecuritySettings.MultiTenant) { Tracing.Verbose("[UserAccountService.AuthenticateWithUsernameOrEmail] applying default tenant"); tenant = SecuritySettings.DefaultTenant; } Tracing.Information("[UserAccountService.AuthenticateWithUsernameOrEmail] called {0}, {1}", tenant, userNameOrEmail); if (String.IsNullOrWhiteSpace(tenant)) return false; if (String.IsNullOrWhiteSpace(userNameOrEmail)) return false; if (String.IsNullOrWhiteSpace(password)) return false; if (!SecuritySettings.EmailIsUsername && userNameOrEmail.Contains("@")) { Tracing.Verbose("[UserAccountService.AuthenticateWithUsernameOrEmail] email detected"); return AuthenticateWithEmail(tenant, userNameOrEmail, password, out account); } else { Tracing.Verbose("[UserAccountService.AuthenticateWithUsernameOrEmail] username detected"); return Authenticate(tenant, userNameOrEmail, password, out account); } }
private void IssuePartialSignInTokenForTwoFactorAuth(UserAccount account, string method) { if (account == null) throw new ArgumentNullException("account"); Tracing.Verbose("[AuthenticationService.IssuePartialSignInCookieForTwoFactorAuth] Account ID: {0}", account.ID); var claims = GetBasicClaims(account, method); var ci = new ClaimsIdentity(claims); // no auth type param so user will not be actually authenticated var cp = new ClaimsPrincipal(ci); IssueToken(cp, MembershipRebootConstants.AuthenticationService.TwoFactorAuthTokenLifetime, false); }
protected virtual void DeliverMessage(UserAccount user, string subject, string body) { DeliverMessage(user.Email, subject, body); }
public void SendChangeUsernameRequestNotice(UserAccount user) { Tracing.Information(String.Format("[NotificationService.SendChangeUsernameRequestNotice] {0}, {1}, {2}", user.Tenant, user.Username, user.Email)); var msg = GetUsernameChangedNoticeFormat(); var body = DoTokenReplacement(msg, user); DeliverMessage(user, "Username Changed", body); }
public virtual bool IsPasswordExpired(UserAccount account) { if (account == null) throw new ArgumentNullException("account"); return account.GetIsPasswordExpired(SecuritySettings.PasswordResetFrequency); }
public void SignInWithLinkedAccount( string tenant, string providerName, string providerAccountID, IEnumerable <Claim> claims) { if (!UserAccountService.Configuration.SecuritySettings.MultiTenant) { tenant = UserAccountService.Configuration.SecuritySettings.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"); } UserAccount account = null; var user = ClaimsPrincipal.Current; if (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("Can't create an account because there was no email from the identity provider."); } // guess at a name to use var name = claims.GetValue(ClaimTypes.Name); if (name == null || this.UserAccountService.UsernameExists(tenant, name)) { name = email; } // check to see if email already exists if (this.UserAccountService.EmailExists(tenant, email)) { throw new ValidationException("Can't login with this provider because the email is already associated with another account. Please login with your local account and then associate the provider."); } // 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 var pwd = CryptoHelper.GenerateSalt(); account = this.UserAccountService.CreateAccount(tenant, name, pwd, email); } } if (account == null) { throw new Exception("Failed to locate account"); } // add/update the provider with this account account.AddOrUpdateLinkedAccount(providerName, providerAccountID, claims); this.UserAccountService.Update(account); // 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 virtual void SignIn(UserAccount account) { SignIn(account, AuthenticationMethods.Password); }
public void SendResetPassword(UserAccount user) { Tracing.Information(String.Format("[NotificationService.SendResetPassword] {0}, {1}, {2}", user.Tenant, user.Username, user.Email)); var msg = GetResetPasswordFormat(); var body = DoTokenReplacement(msg, user); DeliverMessage(user, "Password Reset Request", body); }
protected internal virtual void DeleteAccount(UserAccount account) { if (account == null) throw new ArgumentNullException("account"); Tracing.Verbose("[UserAccountService.DeleteAccount] marking account as closed: {0}", account.ID); account.CloseAccount(); Update(account); if (SecuritySettings.AllowAccountDeletion || !account.IsAccountVerified) { Tracing.Verbose("[UserAccountService.DeleteAccount] removing account record: {0}", account.ID); this.userRepository.Remove(account); } }
public void SendEmailChangedNotice(UserAccount user, string oldEmail) { Tracing.Information(String.Format("[NotificationService.SendEmailChangedNotice] {0}, {1}, {2}, {3}", user.Tenant, user.Username, user.Email, oldEmail)); var msg = GetEmailChangedNoticeFormat(); var body = DoTokenReplacement(msg, user); body = body.Replace("{newEmail}", user.Email); body = body.Replace("{oldEmail}", oldEmail); DeliverMessage(user, "Email Changed", body); }
public virtual bool Authenticate(string username, string password, out UserAccount account) { return Authenticate(null, username, password, out account); }
public virtual bool AuthenticateWithEmail(string email, string password, out UserAccount account) { return AuthenticateWithEmail(null, email, password, out account); }
private static List<Claim> GetBasicClaims(UserAccount account, string method) { if (account == null) throw new ArgumentNullException("account"); var claims = new List<Claim>(); claims.Add(new Claim(ClaimTypes.AuthenticationMethod, method)); claims.Add(new Claim(ClaimTypes.AuthenticationInstant, DateTime.UtcNow.ToString("s"))); claims.Add(new Claim(ClaimTypes.NameIdentifier, account.ID.ToString("D"))); claims.Add(new Claim(ClaimTypes.Name, account.Username)); claims.Add(new Claim(MembershipRebootConstants.ClaimTypes.Tenant, account.Tenant)); return claims; }
public virtual bool AuthenticateWithEmail(string tenant, string email, string password, out UserAccount account) { account = null; if (!SecuritySettings.MultiTenant) { Tracing.Verbose("[UserAccountService.AuthenticateWithEmail] applying default tenant"); tenant = SecuritySettings.DefaultTenant; } Tracing.Information("[UserAccountService.AuthenticateWithEmail] called: {0}, {1}", tenant, email); if (String.IsNullOrWhiteSpace(tenant)) return false; if (String.IsNullOrWhiteSpace(email)) return false; if (String.IsNullOrWhiteSpace(password)) return false; account = this.GetByEmail(tenant, email); if (account == null) return false; return Authenticate(account, password, AuthenticationPurpose.SignIn); }
public virtual bool AuthenticateWithUsernameOrEmail(string userNameOrEmail, string password, out UserAccount account) { return AuthenticateWithUsernameOrEmail(null, userNameOrEmail, password, out account); }