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 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); // update account with external claims var cmd = new MapClaimsToAccount <TAccount> { Account = account, Claims = claims }; this.UserAccountService.ExecuteCommand(cmd); this.UserAccountService.Update(account); } } 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); } }