示例#1
0
        public virtual async Task <UserLoginResult> TryLoginWithRecoveryCode(LoginWithRecoveryCodeViewModel model)
        {
            var          template    = new LoginResultTemplate();
            IUserContext userContext = null;

            template.User = await SignInManager.GetTwoFactorAuthenticationUserAsync();

            if (template.User != null)
            {
                await LoginRulesProcessor.ProcessAccountLoginRules(template);
            }

            if (template.User != null)
            {
                //this will get persisted if login succeeds
                template.User.BrowserKey = Guid.NewGuid().ToString();
                userContext = new UserContext(template.User);
            }

            if (userContext != null &&
                template.SignInResult == SignInResult.Failed && //initial state
                template.RejectReasons.Count == 0
                )
            {
                var recoveryCode = model.RecoveryCode.Replace(" ", string.Empty);
                template.SignInResult = await SignInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);
            }

            if (template.SignInResult.Succeeded)
            {
                //update last login time and browser key
                template.User.LastLoginUtc = DateTime.UtcNow;
                await UserManager.UpdateAsync(template.User);

                if (UserManager.Site.SingleBrowserSessions)
                {
                    //the sign in we just did won't have the new browserkey claim so sign out and sign in again to ensure it gets the claim
                    await SignInManager.SignOutAsync();

                    await SignInManager.SignInAsync(template.User, isPersistent : false);
                }
            }

            return(new UserLoginResult(
                       template.SignInResult,
                       template.RejectReasons,
                       userContext,
                       template.IsNewUserRegistration,
                       template.MustAcceptTerms,
                       template.NeedsAccountApproval,
                       template.NeedsEmailConfirmation,
                       template.EmailConfirmationToken,
                       template.NeedsPhoneConfirmation
                       ));
        }
示例#2
0
        public virtual async Task <UserLoginResult> TryLoginWithRecoveryCode(LoginWithRecoveryCodeViewModel model)
        {
            var          template    = new LoginResultTemplate();
            IUserContext userContext = null;

            template.User = await SignInManager.GetTwoFactorAuthenticationUserAsync();

            if (template.User != null)
            {
                await LoginRulesProcessor.ProcessAccountLoginRules(template);
            }

            if (template.User != null)
            {
                userContext = new UserContext(template.User);
            }

            if (userContext != null &&
                template.SignInResult == SignInResult.Failed && //initial state
                template.RejectReasons.Count == 0
                )
            {
                var recoveryCode = model.RecoveryCode.Replace(" ", string.Empty);
                template.SignInResult = await SignInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);
            }

            if (template.SignInResult.Succeeded)
            {
                //update last login time
                template.User.LastLoginUtc = DateTime.UtcNow;
                await UserManager.UpdateAsync(template.User);
            }

            return(new UserLoginResult(
                       template.SignInResult,
                       template.RejectReasons,
                       userContext,
                       template.IsNewUserRegistration,
                       template.MustAcceptTerms,
                       template.NeedsAccountApproval,
                       template.NeedsEmailConfirmation,
                       template.EmailConfirmationToken,
                       template.NeedsPhoneConfirmation
                       ));
        }
示例#3
0
        public virtual async Task <UserLoginResult> TryRegister(
            RegisterViewModel model,
            ModelStateDictionary modelState,
            HttpContext httpContext,
            IHandleCustomRegistration customRegistration
            )
        {
            var          template    = new LoginResultTemplate();
            IUserContext userContext = null;

            var userName = !string.IsNullOrWhiteSpace(model.Username) ? model.Username : await UserManager.SuggestLoginNameFromEmail(UserManager.Site.Id, model.Email);

            var userNameAvailable = await UserManager.LoginIsAvailable(Guid.Empty, userName);

            if (!userNameAvailable)
            {
                userName = await UserManager.SuggestLoginNameFromEmail(UserManager.Site.Id, model.Email);
            }

            var user = new SiteUser
            {
                SiteId          = UserManager.Site.Id,
                UserName        = userName,
                Email           = model.Email,
                FirstName       = model.FirstName,
                LastName        = model.LastName,
                DisplayName     = model.DisplayName,
                LastLoginUtc    = DateTime.UtcNow,
                BrowserKey      = Guid.NewGuid().ToString(),
                AccountApproved = UserManager.Site.RequireApprovalBeforeLogin ? false : true
            };

            await customRegistration.ProcessUserBeforeCreate(user, httpContext);


            if (model.DateOfBirth.HasValue)
            {
                user.DateOfBirth = model.DateOfBirth.Value;
            }

            if (!string.IsNullOrWhiteSpace(UserManager.Site.RegistrationAgreement))
            {
                if (model.AgreeToTerms)
                {
                    user.AgreementAcceptedUtc = DateTime.UtcNow;
                }
            }

            var result = await UserManager.CreateAsync(user, model.Password);

            if (result.Succeeded)
            {
                template.User = user;
                template.IsNewUserRegistration = true;
                await LoginRulesProcessor.ProcessAccountLoginRules(template);
            }
            else
            {
                foreach (var error in result.Errors)
                {
                    if (!string.IsNullOrWhiteSpace(error.Description) && error.Description.IndexOf("Email") > -1 && error.Description.IndexOf("is already taken") > -1)
                    {
                        //asp identity is returning an error message like "Email someaddress@somedomain is alreaady taken"
                        // this is account disclosure and we don't want that so return a more generic error message
                        //modelState.AddModelError(string.Empty, "Provided email address not accepted, please try again with a different email address.");
                        // even the above message would give a clue so don't add anything, the user still sees message "Invalid registration attempt."
                    }
                    else
                    {
                        modelState.AddModelError(string.Empty, error.Description);
                    }
                }
            }


            if (template.RejectReasons.Count == 0 &&
                user != null &&
                template.SignInResult == SignInResult.Failed && // failed is initial state, could have been changed to lockedout
                result.Errors.Count <IdentityError>() == 0
                )
            {
                await SignInManager.SignInAsync(user, isPersistent : false);

                template.SignInResult = SignInResult.Success;
            }

            if (template.User != null)
            {
                userContext = new UserContext(template.User);
            }

            return(new UserLoginResult(
                       template.SignInResult,
                       template.RejectReasons,
                       userContext,
                       template.IsNewUserRegistration,
                       template.MustAcceptTerms,
                       template.NeedsAccountApproval,
                       template.NeedsEmailConfirmation,
                       template.EmailConfirmationToken,
                       template.NeedsPhoneConfirmation
                       ));
        }
示例#4
0
        public virtual async Task <UserLoginResult> TryLogin(LoginViewModel model)
        {
            var          template        = new LoginResultTemplate();
            IUserContext userContext     = null;
            LdapUser     ldapUser        = null;
            var          isFakeLdapEmail = false;

            if (UserManager.Site.UseEmailForLogin && !string.IsNullOrWhiteSpace(model.UserName) && model.UserName.IndexOf("@") > -1)
            {
                template.User = await UserManager.FindByEmailAsync(model.UserName);
            }

            if (template.User == null)
            {
                template.User = await UserManager.FindByNameAsync(model.UserName);
            }

            if (template.User == null || string.IsNullOrWhiteSpace(template.User.PasswordHash)) //no password on cloudscribe user so could be ldap
            {
                if (LdapHelper.IsImplemented && !string.IsNullOrWhiteSpace(UserManager.Site.LdapServer) && !string.IsNullOrWhiteSpace(UserManager.Site.LdapDomain))
                {
                    ldapUser = await LdapHelper.TryLdapLogin(UserManager.Site as ILdapSettings, model.UserName, model.Password);
                }
            }

            if (ldapUser != null) //ldap auth success
            {
                if (template.User == null)
                {
                    //ldap auth success but no siteuser exists so create one and sign in
                    var cloudscribeUser = new SiteUser()
                    {
                        SiteId          = UserManager.Site.Id,
                        UserName        = model.UserName,
                        Email           = ldapUser.Email,
                        DisplayName     = ldapUser.CommonName,
                        FirstName       = ldapUser.FirstName,
                        LastName        = ldapUser.LastName,
                        LastLoginUtc    = DateTime.UtcNow,
                        AccountApproved = true
                    };

                    if (string.IsNullOrWhiteSpace(cloudscribeUser.DisplayName))
                    {
                        cloudscribeUser.DisplayName = model.UserName;
                    }

                    if (string.IsNullOrWhiteSpace(cloudscribeUser.Email))
                    {
                        // identity doesn't allow create user with no email so fake it here then null it out below after sign in.
                        // the cloudscribe site rules middleware will then force the user to provide an email
                        cloudscribeUser.Email = model.UserName + "@fake-email.com";
                        isFakeLdapEmail       = true;
                    }

                    var createdResult = await UserManager.CreateAsync(cloudscribeUser);

                    if (createdResult.Succeeded)
                    {
                        template.User = cloudscribeUser;
                        await SignInManager.SignInAsync(cloudscribeUser, model.RememberMe);

                        template.SignInResult = SignInResult.Success;
                        if (isFakeLdapEmail)
                        {
                            // clear the fake email, the user should then be forced to provide an email by site rules middleware
                            cloudscribeUser.Email           = null;
                            cloudscribeUser.NormalizedEmail = null;
                            await UserCommands.Update(cloudscribeUser);
                        }
                    }
                }
                else
                {
                    //siteuser already created for ldap user so just sign in
                    await SignInManager.SignInAsync(template.User, model.RememberMe);

                    template.SignInResult = SignInResult.Success;
                }
            }

            if (template.User != null && ldapUser == null) //these rules don't apply for ldap users
            {
                await LoginRulesProcessor.ProcessAccountLoginRules(template);
            }

            if (template.User != null)
            {
                //this will get persisted if login succeeds
                template.User.BrowserKey = Guid.NewGuid().ToString();

                userContext = new UserContext(template.User);
            }

            if (userContext != null &&
                template.SignInResult == SignInResult.Failed &&
                template.RejectReasons.Count == 0)
            {
                var persistent = false;
                if (UserManager.Site.AllowPersistentLogin)
                {
                    persistent = model.RememberMe;
                }

                //template.SignInResult = await SignInManager.PasswordSignInAsync(
                //    model.UserName,
                //    model.Password,
                //    persistent,
                //    lockoutOnFailure: false);

                template.SignInResult = await SignInManager.PasswordSignInAsync(
                    template.User,
                    model.Password,
                    persistent,
                    lockoutOnFailure : false);


                if (template.SignInResult.Succeeded)
                {
                    //update last login time
                    template.User.LastLoginUtc = DateTime.UtcNow;

                    if (string.IsNullOrEmpty(template.User.SecurityStamp))
                    {
                        // if security stamp is empty then the securitystamp validation
                        // fails when it checks after 30 minutes
                        // users created via usermanager this gets populated but not
                        // populated for the admin user created by seeding data
                        // changes to the user such as password change also will populate it
                        // but we can go ahead and check here and populate it if it is empty
                        await UserManager.UpdateSecurityStampAsync(template.User);

                        if (template.User.PasswordHash == "admin||0")
                        {
                            // initial admin user has not updated the password, need to hash it
                            await UserManager.ChangeUserPassword(template.User, "admin", validatePassword : false);

                            await SignInManager.SignOutAsync();

                            // security stamp needs to be there before authentication to avoid the problem

                            template.SignInResult = await SignInManager.PasswordSignInAsync(
                                model.UserName,
                                model.Password,
                                persistent,
                                lockoutOnFailure : false);
                        }
                    }
                    else
                    {
                        await UserManager.UpdateAsync(template.User);
                    }
                }
            }

            return(new UserLoginResult(
                       template.SignInResult,
                       template.RejectReasons,
                       userContext,
                       template.IsNewUserRegistration,
                       template.MustAcceptTerms,
                       template.NeedsAccountApproval,
                       template.NeedsEmailConfirmation,
                       template.EmailConfirmationToken,
                       template.NeedsPhoneConfirmation
                       ));
        }
示例#5
0
        public virtual async Task <UserLoginResult> TryExternalLogin(string providedEmail = "", bool?didAcceptTerms = null)
        {
            var          template    = new LoginResultTemplate();
            IUserContext userContext = null;
            var          email       = providedEmail;

            template.ExternalLoginInfo = await SignInManager.GetExternalLoginInfoAsync();

            if (template.ExternalLoginInfo == null)
            {
                template.RejectReasons.Add("signInManager.GetExternalLoginInfoAsync returned null");
            }
            else
            {
                template.User = await UserManager.FindByLoginAsync(template.ExternalLoginInfo.LoginProvider, template.ExternalLoginInfo.ProviderKey);

                if (template.User == null)
                {
                    if (string.IsNullOrWhiteSpace(email))
                    {
                        var emailClaim = template.ExternalLoginInfo.Principal.Claims.Where(x => x.Type == ClaimTypes.Email || x.Type == "email").FirstOrDefault();
                        if (emailClaim != null)
                        {
                            email = emailClaim.Value;
                        }
                    }

                    if (!string.IsNullOrWhiteSpace(email) && email.Contains("@"))
                    {
                        template.User = await UserManager.FindByNameAsync(email);
                    }

                    if (template.User == null)
                    {
                        template.IsNewUserRegistration = true;
                        template.User = await CreateUserFromExternalLogin(template.ExternalLoginInfo, email, didAcceptTerms);
                    }

                    if (template.User != null)
                    {
                        var identityResult = await UserManager.AddLoginAsync(template.User, template.ExternalLoginInfo);
                    }
                }
            }

            if (template.User != null)
            {
                //this will get persisted if login succeeds
                template.User.BrowserKey = Guid.NewGuid().ToString();
                if (UserManager.Site.SingleBrowserSessions)
                {
                    // need to save here because the signin code below looks up the user again using provider info
                    // and creates the claims principal
                    // and we need it to see the updated browserkey to set the claim
                    await UserManager.UpdateAsync(template.User);
                }

                await LoginRulesProcessor.ProcessAccountLoginRules(template);
            }

            if (template.SignInResult == SignInResult.Failed && template.User != null && template.RejectReasons.Count == 0)
            {
                var updatTokenResult = await SignInManager.UpdateExternalAuthenticationTokensAsync(template.ExternalLoginInfo);

                //var accessToken = template.ExternalLoginInfo.AuthenticationTokens.Where(x => x.Name == "access_token").FirstOrDefault();


                template.SignInResult = await SignInManager.ExternalLoginSignInAsync(template.ExternalLoginInfo.LoginProvider, template.ExternalLoginInfo.ProviderKey, isPersistent : false);



                if (template.SignInResult.Succeeded)
                {
                    //update last login time and browser key set above
                    template.User.LastLoginUtc = DateTime.UtcNow;
                    await UserManager.UpdateAsync(template.User);
                }
            }

            if (template.User != null &&
                template.SignInResult != SignInResult.Success &&
                template.SignInResult != SignInResult.TwoFactorRequired)
            {
                //clear the external login
                await SignInManager.SignOutAsync();
            }

            if (template.User != null)
            {
                userContext = new UserContext(template.User);
            }

            return(new UserLoginResult(
                       template.SignInResult,
                       template.RejectReasons,
                       userContext,
                       template.IsNewUserRegistration,
                       template.MustAcceptTerms,
                       template.NeedsAccountApproval,
                       template.NeedsEmailConfirmation,
                       template.EmailConfirmationToken,
                       template.NeedsPhoneConfirmation,
                       template.ExternalLoginInfo
                       ));
        }
示例#6
0
        public virtual async Task <UserLoginResult> TryExternalLogin(string providedEmail = "", bool?didAcceptTerms = null)
        {
            var          template    = new LoginResultTemplate();
            IUserContext userContext = null;
            var          email       = providedEmail;

            template.ExternalLoginInfo = await SignInManager.GetExternalLoginInfoAsync();

            if (template.ExternalLoginInfo == null)
            {
                template.RejectReasons.Add("signInManager.GetExternalLoginInfoAsync returned null");
            }
            else
            {
                template.User = await UserManager.FindByLoginAsync(template.ExternalLoginInfo.LoginProvider, template.ExternalLoginInfo.ProviderKey);

                if (template.User == null)
                {
                    if (string.IsNullOrWhiteSpace(email))
                    {
                        email = template.ExternalLoginInfo.Principal.FindFirstValue(ClaimTypes.Email);
                    }

                    if (!string.IsNullOrWhiteSpace(email) && email.Contains("@"))
                    {
                        template.User = await UserManager.FindByNameAsync(email);
                    }
                }

                if (template.User == null)
                {
                    template.User = await CreateUserFromExternalLogin(template.ExternalLoginInfo, email, didAcceptTerms);

                    if (template.User != null)
                    {
                        template.IsNewUserRegistration = true;
                    }
                }
            }

            if (template.User != null)
            {
                await LoginRulesProcessor.ProcessAccountLoginRules(template);
            }

            if (template.SignInResult == SignInResult.Failed && template.User != null && template.RejectReasons.Count == 0)
            {
                //var updatTokenResult = await SignInManager.UpdateExternalAuthenticationTokensAsync(template.ExternalLoginInfo);

                template.SignInResult = await SignInManager.ExternalLoginSignInAsync(template.ExternalLoginInfo.LoginProvider, template.ExternalLoginInfo.ProviderKey, isPersistent : false);

                if (template.SignInResult.Succeeded)
                {
                    //update last login time
                    if (!template.IsNewUserRegistration)
                    {
                        //already tracked if user was just created
                        template.User.LastLoginUtc = DateTime.UtcNow;
                        await UserManager.UpdateAsync(template.User);
                    }
                }
            }

            if (template.User != null &&
                template.SignInResult != SignInResult.Success &&
                template.SignInResult != SignInResult.TwoFactorRequired)
            {
                //clear the external login
                await SignInManager.SignOutAsync();
            }

            if (template.User != null)
            {
                userContext = new UserContext(template.User);
            }

            return(new UserLoginResult(
                       template.SignInResult,
                       template.RejectReasons,
                       userContext,
                       template.IsNewUserRegistration,
                       template.MustAcceptTerms,
                       template.NeedsAccountApproval,
                       template.NeedsEmailConfirmation,
                       template.EmailConfirmationToken,
                       template.NeedsPhoneConfirmation,
                       template.ExternalLoginInfo
                       ));
        }