public async Task <IHttpActionResult> CreateUser()
        {
            var owinContext = TryGetOwinContext().Result;
            var userManager = owinContext.GetBackOfficeUserManager();

            var email = "*****@*****.**";
            var user  = BackOfficeIdentityUser.CreateNew(email, email, "en-US");

            user.Name = "Paulo Samson";

            await userManager.CreateAsync(user);

            var password = userManager.GeneratePassword();
            await userManager.AddPasswordAsync(user.Id, password);

            //Save group
            var u = Services.UserService.GetByUsername(email);

            u.IsApproved = true;
            var group = Services.UserService.GetUserGroupByAlias("admin") as IReadOnlyUserGroup;

            u.AddGroup(group);
            Services.UserService.Save(u);

            return(Ok(password));
        }
Esempio n. 2
0
        private async Task <DeliverableResponse> CreateUser(string[] args)
        {
            if (args.Length != 5)
            {
                await Out.WriteLineAsync("Please provide 5 arguments, name, username, email, password and groups. For more information see `help`");

                return(DeliverableResponse.Continue);
            }

            var name       = args[0];
            var username   = args[1];
            var email      = args[2];
            var password   = args[3];
            var groupNames = args[4];

            var identity = BackOfficeIdentityUser.CreateNew(username, email, GlobalSettings.DefaultUILanguage);

            identity.Name = name;

            var result = await userManager.CreateAsync(identity);

            if (!result.Succeeded)
            {
                await Out.WriteLineAsync("Error saving the user:"******"\t{error}");
                }

                return(DeliverableResponse.FinishedWithError);
            }

            result = await userManager.AddPasswordAsync(identity.Id, password);

            if (!result.Succeeded)
            {
                await Out.WriteLineAsync("Error saving the user password:"******"\t{error}");
                }

                return(DeliverableResponse.FinishedWithError);
            }

            var user   = userService.GetByEmail(email);
            var groups = userService.GetUserGroupsByAlias(groupNames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));

            foreach (var group in groups)
            {
                var rg = new ReadOnlyUserGroup(group.Id, group.Name, group.Icon, group.StartContentId, group.StartMediaId, group.Alias, group.AllowedSections, group.Permissions);
                user.AddGroup(rg);
            }
            user.IsApproved = true;
            userService.Save(user);

            return(DeliverableResponse.Continue);
        }
        public void Customize(IFixture fixture)
        {
            fixture.Customize <BackOfficeIdentityUser>(
                u => u.FromFactory <string, string, string>(
                    (a, b, c) => BackOfficeIdentityUser.CreateNew(new GlobalSettings(), a, b, c)));

            fixture
            .Customize(new ConstructorCustomization(typeof(UsersController), new GreedyConstructorQuery()))
            .Customize(new ConstructorCustomization(typeof(InstallController), new GreedyConstructorQuery()))
            .Customize(new ConstructorCustomization(typeof(PreviewController), new GreedyConstructorQuery()))
            .Customize(new ConstructorCustomization(typeof(MemberController), new GreedyConstructorQuery()))
            .Customize(new ConstructorCustomization(typeof(BackOfficeController), new GreedyConstructorQuery()))
            .Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery()))
            .Customize(new ConstructorCustomization(typeof(MemberManager), new GreedyConstructorQuery()))
            .Customize(new ConstructorCustomization(typeof(DatabaseSchemaCreatorFactory), new GreedyConstructorQuery()));

            // When requesting an IUserStore ensure we actually uses a IUserLockoutStore
            fixture.Customize <IUserStore <BackOfficeIdentityUser> >(cc => cc.FromFactory(Mock.Of <IUserLockoutStore <BackOfficeIdentityUser> >));

            fixture.Customize <ConfigConnectionString>(
                u => u.FromFactory <string, string, string>(
                    (a, b, c) => new ConfigConnectionString(a, b, c)));

            fixture.Customize <IUmbracoVersion>(
                u => u.FromFactory(
                    () => new UmbracoVersion()));

            fixture.Customize <HostingSettings>(x =>
                                                x.With(settings => settings.ApplicationVirtualPath, string.Empty));

            fixture.Customize <BackOfficeAreaRoutes>(u => u.FromFactory(
                                                         () => new BackOfficeAreaRoutes(
                                                             Options.Create(new GlobalSettings()),
                                                             Mock.Of <IHostingEnvironment>(x => x.ToAbsolute(It.IsAny <string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
                                                             Mock.Of <IRuntimeState>(x => x.Level == RuntimeLevel.Run),
                                                             new UmbracoApiControllerTypeCollection(Enumerable.Empty <Type>))));

            fixture.Customize <PreviewRoutes>(u => u.FromFactory(
                                                  () => new PreviewRoutes(
                                                      Options.Create(new GlobalSettings()),
                                                      Mock.Of <IHostingEnvironment>(x => x.ToAbsolute(It.IsAny <string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
                                                      Mock.Of <IRuntimeState>(x => x.Level == RuntimeLevel.Run))));

            var configConnectionString = new ConfigConnectionString(
                "ss",
                "Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\Umbraco.mdf;Integrated Security=True");

            fixture.Customize <ConfigConnectionString>(x => x.FromFactory(() => configConnectionString));

            var httpContextAccessor = new HttpContextAccessor {
                HttpContext = new DefaultHttpContext()
            };

            fixture.Customize <HttpContext>(x => x.FromFactory(() => httpContextAccessor.HttpContext));
            fixture.Customize <IHttpContextAccessor>(x => x.FromFactory(() => httpContextAccessor));

            fixture.Customize <WebRoutingSettings>(x => x.With(settings => settings.UmbracoApplicationUrl, "http://localhost:5000"));
        }
                public void Customize(IFixture fixture)
                {
                    fixture.Customize <BackOfficeIdentityUser>(
                        u => u.FromFactory <string, string, string>(
                            (a, b, c) => BackOfficeIdentityUser.CreateNew(new GlobalSettings(), a, b, c)));
                    fixture
                    .Customize(new ConstructorCustomization(typeof(UsersController), new GreedyConstructorQuery()))
                    .Customize(new ConstructorCustomization(typeof(InstallController), new GreedyConstructorQuery()))
                    .Customize(new ConstructorCustomization(typeof(PreviewController), new GreedyConstructorQuery()))
                    .Customize(new ConstructorCustomization(typeof(MemberController), new GreedyConstructorQuery()))
                    .Customize(new ConstructorCustomization(typeof(BackOfficeController), new GreedyConstructorQuery()))
                    .Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery()))
                    .Customize(new ConstructorCustomization(typeof(MemberManager), new GreedyConstructorQuery()));

                    fixture.Customize(new AutoMoqCustomization());

                    // When requesting an IUserStore ensure we actually uses a IUserLockoutStore
                    fixture.Customize <IUserStore <BackOfficeIdentityUser> >(cc => cc.FromFactory(() => Mock.Of <IUserLockoutStore <BackOfficeIdentityUser> >()));

                    fixture.Customize <ConfigConnectionString>(
                        u => u.FromFactory <string, string, string>(
                            (a, b, c) => new ConfigConnectionString(a, b, c)));

                    fixture.Customize <IUmbracoVersion>(
                        u => u.FromFactory(
                            () => new UmbracoVersion()));

                    fixture.Customize <BackOfficeAreaRoutes>(u => u.FromFactory(
                                                                 () => new BackOfficeAreaRoutes(
                                                                     Options.Create(new GlobalSettings()),
                                                                     Mock.Of <IHostingEnvironment>(x => x.ToAbsolute(It.IsAny <string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
                                                                     Mock.Of <IRuntimeState>(x => x.Level == RuntimeLevel.Run),
                                                                     new UmbracoApiControllerTypeCollection(() => Enumerable.Empty <Type>()))));

                    fixture.Customize <PreviewRoutes>(u => u.FromFactory(
                                                          () => new PreviewRoutes(
                                                              Options.Create(new GlobalSettings()),
                                                              Mock.Of <IHostingEnvironment>(x => x.ToAbsolute(It.IsAny <string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
                                                              Mock.Of <IRuntimeState>(x => x.Level == RuntimeLevel.Run))));

                    var connectionStrings = new ConnectionStrings();

                    fixture.Customize <ConnectionStrings>(x => x.FromFactory(() => connectionStrings));

                    var httpContextAccessor = new HttpContextAccessor {
                        HttpContext = new DefaultHttpContext()
                    };

                    fixture.Customize <HttpContext>(x => x.FromFactory(() => httpContextAccessor.HttpContext));
                    fixture.Customize <IHttpContextAccessor>(x => x.FromFactory(() => httpContextAccessor));
                }
Esempio n. 5
0
        private async Task <bool> AutoLinkAndSignInExternalAccount(ExternalLoginInfo loginInfo, ExternalSignInAutoLinkOptions autoLinkOptions)
        {
            if (autoLinkOptions == null)
            {
                return(false);
            }

            if (autoLinkOptions.ShouldAutoLinkExternalAccount(UmbracoContext, loginInfo) == false)
            {
                return(true);
            }

            //we are allowing auto-linking/creating of local accounts
            if (loginInfo.Email.IsNullOrWhiteSpace())
            {
                ViewData.SetExternalSignInProviderErrors(
                    new BackOfficeExternalLoginProviderErrors(
                        loginInfo.Login.LoginProvider,
                        new[] { "The requested provider (" + loginInfo.Login.LoginProvider + ") has not provided an email address, the account cannot be linked." }));
            }
            else
            {
                //Now we need to perform the auto-link, so first we need to lookup/create a user with the email address
                var autoLinkUser = UserManager.FindByEmail(loginInfo.Email);
                if (autoLinkUser != null)
                {
                    try
                    {
                        //call the callback if one is assigned
                        autoLinkOptions.OnAutoLinking?.Invoke(autoLinkUser, loginInfo);
                    }
                    catch (Exception ex)
                    {
                        var msg = "Could not link login provider " + loginInfo.Login.LoginProvider + ".";
                        Logger.Error <BackOfficeController>(ex, msg);
                        ViewData.SetExternalSignInProviderErrors(
                            new BackOfficeExternalLoginProviderErrors(
                                loginInfo.Login.LoginProvider,
                                new[] { msg + " " + ex.Message }));
                        return(true);
                    }

                    await LinkUser(autoLinkUser, loginInfo);
                }
                else
                {
                    if (loginInfo.Email.IsNullOrWhiteSpace())
                    {
                        throw new InvalidOperationException("The Email value cannot be null");
                    }
                    if (loginInfo.ExternalIdentity.Name.IsNullOrWhiteSpace())
                    {
                        throw new InvalidOperationException("The Name value cannot be null");
                    }

                    var groups = Services.UserService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(UmbracoContext, loginInfo));

                    autoLinkUser = BackOfficeIdentityUser.CreateNew(
                        loginInfo.Email,
                        loginInfo.Email,
                        autoLinkOptions.GetDefaultCulture(UmbracoContext, loginInfo));
                    autoLinkUser.Name = loginInfo.ExternalIdentity.Name;
                    foreach (var userGroup in groups)
                    {
                        autoLinkUser.AddRole(userGroup.Alias);
                    }

                    //call the callback if one is assigned
                    try
                    {
                        autoLinkOptions.OnAutoLinking?.Invoke(autoLinkUser, loginInfo);
                    }
                    catch (Exception ex)
                    {
                        var msg = "Could not link login provider " + loginInfo.Login.LoginProvider + ".";
                        Logger.Error <BackOfficeController>(ex, msg);
                        ViewData.SetExternalSignInProviderErrors(
                            new BackOfficeExternalLoginProviderErrors(
                                loginInfo.Login.LoginProvider,
                                new[] { msg + " " + ex.Message }));
                        return(true);
                    }

                    var userCreationResult = await UserManager.CreateAsync(autoLinkUser);

                    if (userCreationResult.Succeeded == false)
                    {
                        ViewData.SetExternalSignInProviderErrors(
                            new BackOfficeExternalLoginProviderErrors(
                                loginInfo.Login.LoginProvider,
                                userCreationResult.Errors));
                    }
                    else
                    {
                        await LinkUser(autoLinkUser, loginInfo);
                    }
                }
            }
            return(true);
        }
Esempio n. 6
0
        /// <summary>
        /// Invites a user
        /// </summary>
        /// <param name="userSave"></param>
        /// <returns></returns>
        /// <remarks>
        /// This will email the user an invite and generate a token that will be validated in the email
        /// </remarks>
        public async Task <UserDisplay> PostInviteUser(UserInvite userSave)
        {
            if (userSave == null)
            {
                throw new ArgumentNullException("userSave");
            }

            if (userSave.Message.IsNullOrWhiteSpace())
            {
                ModelState.AddModelError("Message", "Message cannot be empty");
            }

            if (ModelState.IsValid == false)
            {
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
            }

            IUser user;

            if (Current.Configs.Settings().Security.UsernameIsEmail)
            {
                //ensure it's the same
                userSave.Username = userSave.Email;
            }
            else
            {
                //first validate the username if we're showing it
                user = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
            }
            user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);

            var userMgr = TryGetOwinContext().Result.GetBackOfficeUserManager();

            if (!EmailSender.CanSendRequiredEmail && !userMgr.HasSendingUserInviteEventHandler)
            {
                throw new HttpResponseException(
                          Request.CreateNotificationValidationErrorResponse("No Email server is configured"));
            }

            //Perform authorization here to see if the current user can actually save this user with the info being requested
            var authHelper  = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService, AppCaches);
            var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, user, null, null, userSave.UserGroups);

            if (canSaveUser == false)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, canSaveUser.Result));
            }

            if (user == null)
            {
                //we want to create the user with the UserManager, this ensures the 'empty' (special) password
                //format is applied without us having to duplicate that logic
                var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Username, userSave.Email, GlobalSettings.DefaultUILanguage);
                identityUser.Name = userSave.Name;

                var created = await UserManager.CreateAsync(identityUser);

                if (created.Succeeded == false)
                {
                    throw new HttpResponseException(
                              Request.CreateNotificationValidationErrorResponse(string.Join(", ", created.Errors)));
                }

                //now re-look the user back up
                user = Services.UserService.GetByEmail(userSave.Email);
            }

            //map the save info over onto the user
            user = Mapper.Map(userSave, user);

            //ensure the invited date is set
            user.InvitedDate = DateTime.Now;

            //Save the updated user (which will process the user groups too)
            Services.UserService.Save(user);
            var display = Mapper.Map <UserDisplay>(user);

            var inviteArgs = new UserInviteEventArgs(
                Request.TryGetHttpContext().Result.GetCurrentRequestIpAddress(),
                performingUser: Security.GetUserId().Result,
                userSave,
                user);

            try
            {
                userMgr.RaiseSendingUserInvite(inviteArgs);
            }
            catch (Exception ex)
            {
                Logger.Error <UsersController>(ex, "An error occurred in a custom event handler while inviting the user");
                throw new HttpResponseException(
                          Request.CreateNotificationValidationErrorResponse($"An error occurred inviting the user (check logs for more info): {ex.Message}"));
            }

            // If the event is handled then no need to send the email
            if (inviteArgs.InviteHandled)
            {
                // if no user result was created then map the minimum args manually for the UI
                if (!inviteArgs.ShowUserResult)
                {
                    display = new UserDisplay
                    {
                        Name     = userSave.Name,
                        Email    = userSave.Email,
                        Username = userSave.Username
                    };
                }
            }
            else
            {
                //send the email
                await SendUserInviteEmailAsync(display, Security.CurrentUser.Name, Security.CurrentUser.Email, user, userSave.Message);
            }

            display.AddSuccessNotification(Services.TextService.Localize("speechBubbles", "resendInviteHeader"), Services.TextService.Localize("speechBubbles", "resendInviteSuccess", new[] { user.Name }));
            return(display);
        }
Esempio n. 7
0
        /// <summary>
        /// Creates a new user
        /// </summary>
        /// <param name="userSave"></param>
        /// <returns></returns>
        public async Task <UserDisplay> PostCreateUser(UserInvite userSave)
        {
            if (userSave == null)
            {
                throw new ArgumentNullException("userSave");
            }

            if (ModelState.IsValid == false)
            {
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
            }

            if (Current.Configs.Settings().Security.UsernameIsEmail)
            {
                //ensure they are the same if we're using it
                userSave.Username = userSave.Email;
            }
            else
            {
                //first validate the username if were showing it
                CheckUniqueUsername(userSave.Username, null);
            }
            CheckUniqueEmail(userSave.Email, null);

            //Perform authorization here to see if the current user can actually save this user with the info being requested
            var authHelper  = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService, AppCaches);
            var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, null, null, null, userSave.UserGroups);

            if (canSaveUser == false)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, canSaveUser.Result));
            }

            //we want to create the user with the UserManager, this ensures the 'empty' (special) password
            //format is applied without us having to duplicate that logic
            var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Username, userSave.Email, GlobalSettings.DefaultUILanguage);

            identityUser.Name = userSave.Name;

            var created = await UserManager.CreateAsync(identityUser);

            if (created.Succeeded == false)
            {
                throw new HttpResponseException(
                          Request.CreateNotificationValidationErrorResponse(string.Join(", ", created.Errors)));
            }

            //we need to generate a password, however we can only do that if the user manager has a password validator that
            //we can read values from
            var passwordValidator = UserManager.PasswordValidator as PasswordValidator;
            var resetPassword     = string.Empty;

            if (passwordValidator != null)
            {
                var password = UserManager.GeneratePassword();

                var result = await UserManager.AddPasswordAsync(identityUser.Id, password);

                if (result.Succeeded == false)
                {
                    throw new HttpResponseException(
                              Request.CreateNotificationValidationErrorResponse(string.Join(", ", created.Errors)));
                }
                resetPassword = password;
            }

            //now re-look the user back up which will now exist
            var user = Services.UserService.GetByEmail(userSave.Email);

            //map the save info over onto the user
            user = Mapper.Map(userSave, user);

            //since the back office user is creating this user, they will be set to approved
            user.IsApproved = true;

            Services.UserService.Save(user);

            var display = Mapper.Map <UserDisplay>(user);

            display.ResetPasswordValue = resetPassword;
            return(display);
        }
Esempio n. 8
0
        /// <summary>
        /// Invites a user
        /// </summary>
        /// <param name="userSave"></param>
        /// <returns></returns>
        /// <remarks>
        /// This will email the user an invite and generate a token that will be validated in the email
        /// </remarks>
        public async Task <ActionResult <UserDisplay?> > PostInviteUser(UserInvite userSave)
        {
            if (userSave == null)
            {
                throw new ArgumentNullException(nameof(userSave));
            }

            if (userSave.Message.IsNullOrWhiteSpace())
            {
                ModelState.AddModelError("Message", "Message cannot be empty");
            }

            if (_securitySettings.UsernameIsEmail)
            {
                // ensure it's the same
                userSave.Username = userSave.Email;
            }
            else
            {
                // first validate the username if we're showing it
                ActionResult <IUser?> userResult = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
                if (userResult.Result is not null)
                {
                    return(userResult.Result);
                }
            }

            IUser?user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);

            if (ModelState.IsValid == false)
            {
                return(ValidationProblem(ModelState));
            }

            if (!_emailSender.CanSendRequiredEmail())
            {
                return(ValidationProblem("No Email server is configured"));
            }

            // Perform authorization here to see if the current user can actually save this user with the info being requested
            var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, user, null, null, userSave.UserGroups);

            if (canSaveUser == false)
            {
                return(ValidationProblem(canSaveUser.Result, StatusCodes.Status401Unauthorized));
            }

            if (user == null)
            {
                // we want to create the user with the UserManager, this ensures the 'empty' (special) password
                // format is applied without us having to duplicate that logic
                var identityUser = BackOfficeIdentityUser.CreateNew(_globalSettings, userSave.Username, userSave.Email, _globalSettings.DefaultUILanguage);
                identityUser.Name = userSave.Name;

                var created = await _userManager.CreateAsync(identityUser);

                if (created.Succeeded == false)
                {
                    return(ValidationProblem(created.Errors.ToErrorMessage()));
                }

                // now re-look the user back up
                user = _userService.GetByEmail(userSave.Email);
            }

            // map the save info over onto the user
            user = _umbracoMapper.Map(userSave, user);

            if (user is not null)
            {
                // ensure the invited date is set
                user.InvitedDate = DateTime.Now;

                // Save the updated user (which will process the user groups too)
                _userService.Save(user);
            }

            var display = _umbracoMapper.Map <UserDisplay>(user);

            // send the email
            await SendUserInviteEmailAsync(display, _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.Name, _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.Email, user, userSave.Message);

            display?.AddSuccessNotification(_localizedTextService.Localize("speechBubbles", "resendInviteHeader"), _localizedTextService.Localize("speechBubbles", "resendInviteSuccess", new[] { user?.Name }));
            return(display);
        }
Esempio n. 9
0
        /// <summary>
        /// Creates a new user
        /// </summary>
        /// <param name="userSave"></param>
        /// <returns></returns>
        public async Task <ActionResult <UserDisplay?> > PostCreateUser(UserInvite userSave)
        {
            if (userSave == null)
            {
                throw new ArgumentNullException("userSave");
            }

            if (ModelState.IsValid == false)
            {
                return(ValidationProblem(ModelState));
            }

            if (_securitySettings.UsernameIsEmail)
            {
                //ensure they are the same if we're using it
                userSave.Username = userSave.Email;
            }
            else
            {
                //first validate the username if were showing it
                CheckUniqueUsername(userSave.Username, null);
            }
            CheckUniqueEmail(userSave.Email, null);

            if (ModelState.IsValid == false)
            {
                return(ValidationProblem(ModelState));
            }

            //Perform authorization here to see if the current user can actually save this user with the info being requested
            var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, null, null, null, userSave.UserGroups);

            if (canSaveUser == false)
            {
                return(Unauthorized(canSaveUser.Result));
            }

            //we want to create the user with the UserManager, this ensures the 'empty' (special) password
            //format is applied without us having to duplicate that logic
            var identityUser = BackOfficeIdentityUser.CreateNew(_globalSettings, userSave.Username, userSave.Email, _globalSettings.DefaultUILanguage);

            identityUser.Name = userSave.Name;

            var created = await _userManager.CreateAsync(identityUser);

            if (created.Succeeded == false)
            {
                return(ValidationProblem(created.Errors.ToErrorMessage()));
            }

            string resetPassword;
            var    password = _userManager.GeneratePassword();

            var result = await _userManager.AddPasswordAsync(identityUser, password);

            if (result.Succeeded == false)
            {
                return(ValidationProblem(created.Errors.ToErrorMessage()));
            }

            resetPassword = password;

            //now re-look the user back up which will now exist
            var user = _userService.GetByEmail(userSave.Email);

            //map the save info over onto the user
            user = _umbracoMapper.Map(userSave, user);

            if (user is not null)
            {
                // Since the back office user is creating this user, they will be set to approved
                user.IsApproved = true;

                _userService.Save(user);
            }

            var display = _umbracoMapper.Map <UserDisplay>(user);

            if (display is not null)
            {
                display.ResetPasswordValue = resetPassword;
            }

            return(display);
        }
        /// <summary>
        /// Invites a user
        /// </summary>
        /// <param name="userSave"></param>
        /// <returns></returns>
        /// <remarks>
        /// This will email the user an invite and generate a token that will be validated in the email
        /// </remarks>
        public async Task <UserDisplay> PostInviteUser(UserInvite userSave)
        {
            if (userSave == null)
            {
                throw new ArgumentNullException("userSave");
            }

            if (userSave.Message.IsNullOrWhiteSpace())
            {
                ModelState.AddModelError("Message", "Message cannot be empty");
            }

            if (ModelState.IsValid == false)
            {
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
            }

            if (EmailSender.CanSendRequiredEmail == false)
            {
                throw new HttpResponseException(
                          Request.CreateNotificationValidationErrorResponse("No Email server is configured"));
            }

            IUser user;

            if (Current.Configs.Settings().Security.UsernameIsEmail)
            {
                //ensure it's the same
                userSave.Username = userSave.Email;
            }
            else
            {
                //first validate the username if we're showing it
                user = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default(DateTime) || u.EmailConfirmedDate.HasValue);
            }
            user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default(DateTime) || u.EmailConfirmedDate.HasValue);

            //Perform authorization here to see if the current user can actually save this user with the info being requested
            var authHelper  = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService);
            var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, user, null, null, userSave.UserGroups);

            if (canSaveUser == false)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, canSaveUser.Result));
            }

            if (user == null)
            {
                //we want to create the user with the UserManager, this ensures the 'empty' (special) password
                //format is applied without us having to duplicate that logic
                var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Username, userSave.Email, GlobalSettings.DefaultUILanguage);
                identityUser.Name = userSave.Name;

                var created = await UserManager.CreateAsync(identityUser);

                if (created.Succeeded == false)
                {
                    throw new HttpResponseException(
                              Request.CreateNotificationValidationErrorResponse(string.Join(", ", created.Errors)));
                }

                //now re-look the user back up
                user = Services.UserService.GetByEmail(userSave.Email);
            }

            //map the save info over onto the user
            user = Mapper.Map(userSave, user);

            //ensure the invited date is set
            user.InvitedDate = DateTime.Now;

            //Save the updated user
            Services.UserService.Save(user);
            var display = Mapper.Map <UserDisplay>(user);

            //send the email

            await SendUserInviteEmailAsync(display, Security.CurrentUser.Name, Security.CurrentUser.Email, user, userSave.Message);

            display.AddSuccessNotification(Services.TextService.Localize("speechBubbles/resendInviteHeader"), Services.TextService.Localize("speechBubbles/resendInviteSuccess", new[] { user.Name }));

            return(display);
        }
        private async Task<bool> AutoLinkAndSignInExternalAccount(ExternalLoginInfo loginInfo, ExternalSignInAutoLinkOptions autoLinkOptions)
        {
            if (autoLinkOptions == null)
                return false;

            if (autoLinkOptions.ShouldAutoLinkExternalAccount(UmbracoContext, loginInfo) == false)
                return true;

            //we are allowing auto-linking/creating of local accounts
            if (loginInfo.Email.IsNullOrWhiteSpace())
            {
                ViewData.SetExternalSignInError(new[] { "The requested provider (" + loginInfo.Login.LoginProvider + ") has not provided an email address, the account cannot be linked." });
            }
            else
            {
                //Now we need to perform the auto-link, so first we need to lookup/create a user with the email address
                var foundByEmail = Services.UserService.GetByEmail(loginInfo.Email);
                if (foundByEmail != null)
                {
                    ViewData.SetExternalSignInError(new[] { "A user with this email address already exists locally. You will need to login locally to Umbraco and link this external provider: " + loginInfo.Login.LoginProvider });
                }
                else
                {
                    if (loginInfo.Email.IsNullOrWhiteSpace()) throw new InvalidOperationException("The Email value cannot be null");
                    if (loginInfo.ExternalIdentity.Name.IsNullOrWhiteSpace()) throw new InvalidOperationException("The Name value cannot be null");

                    var groups = Services.UserService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(UmbracoContext, loginInfo));

                    var autoLinkUser = BackOfficeIdentityUser.CreateNew(
                        loginInfo.Email,
                        loginInfo.Email,
                        autoLinkOptions.GetDefaultCulture(UmbracoContext, loginInfo));
                    autoLinkUser.Name = loginInfo.ExternalIdentity.Name;
                    foreach (var userGroup in groups)
                    {
                        autoLinkUser.AddRole(userGroup.Alias);
                    }

                    //call the callback if one is assigned
                    if (autoLinkOptions.OnAutoLinking != null)
                    {
                        autoLinkOptions.OnAutoLinking(autoLinkUser, loginInfo);
                    }

                    var userCreationResult = await UserManager.CreateAsync(autoLinkUser);

                    if (userCreationResult.Succeeded == false)
                    {
                        ViewData.SetExternalSignInError(userCreationResult.Errors);
                    }
                    else
                    {
                        var linkResult = await UserManager.AddLoginAsync(autoLinkUser.Id, loginInfo.Login);
                        if (linkResult.Succeeded == false)
                        {
                            ViewData.SetExternalSignInError(linkResult.Errors);

                            //If this fails, we should really delete the user since it will be in an inconsistent state!
                            var deleteResult = await UserManager.DeleteAsync(autoLinkUser);
                            if (deleteResult.Succeeded == false)
                            {
                                //DOH! ... this isn't good, combine all errors to be shown
                                ViewData.SetExternalSignInError(linkResult.Errors.Concat(deleteResult.Errors));
                            }
                        }
                        else
                        {
                            //sign in
                            await SignInManager.SignInAsync(autoLinkUser, isPersistent: false, rememberBrowser: false);
                        }
                    }
                }

            }
            return true;
        }
        private async Task <bool> AutoLinkAndSignInExternalAccount(ExternalLoginInfo loginInfo)
        {
            //Here we can check if the provider associated with the request has been configured to allow
            // new users (auto-linked external accounts). This would never be used with public providers such as
            // Google, unless you for some reason wanted anybody to be able to access the backend if they have a Google account
            // .... not likely!

            var authType = OwinContext.Authentication.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == loginInfo.Login.LoginProvider);

            if (authType == null)
            {
                Logger.Warn <BackOfficeController>("Could not find external authentication provider registered: " + loginInfo.Login.LoginProvider);
                return(false);
            }

            var autoLinkOptions = authType.GetExternalAuthenticationOptions();

            if (autoLinkOptions != null)
            {
                if (autoLinkOptions.ShouldAutoLinkExternalAccount(UmbracoContext, loginInfo))
                {
                    //we are allowing auto-linking/creating of local accounts
                    if (loginInfo.Email.IsNullOrWhiteSpace())
                    {
                        ViewData[TokenExternalSignInError] = new[] { "The requested provider (" + loginInfo.Login.LoginProvider + ") has not provided an email address, the account cannot be linked." };
                    }
                    else
                    {
                        //Now we need to perform the auto-link, so first we need to lookup/create a user with the email address
                        var foundByEmail = Services.UserService.GetByEmail(loginInfo.Email);
                        if (foundByEmail != null)
                        {
                            ViewData[TokenExternalSignInError] = new[] { "A user with this email address already exists locally. You will need to login locally to Umbraco and link this external provider: " + loginInfo.Login.LoginProvider };
                        }
                        else
                        {
                            if (loginInfo.Email.IsNullOrWhiteSpace())
                            {
                                throw new InvalidOperationException("The Email value cannot be null");
                            }
                            if (loginInfo.ExternalIdentity.Name.IsNullOrWhiteSpace())
                            {
                                throw new InvalidOperationException("The Name value cannot be null");
                            }

                            var groups = Services.UserService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(UmbracoContext, loginInfo));

                            var autoLinkUser = BackOfficeIdentityUser.CreateNew(
                                loginInfo.Email,
                                loginInfo.Email,
                                autoLinkOptions.GetDefaultCulture(UmbracoContext, loginInfo));
                            autoLinkUser.Name = loginInfo.ExternalIdentity.Name;
                            foreach (var userGroup in groups)
                            {
                                autoLinkUser.AddRole(userGroup.Alias);
                            }

                            //call the callback if one is assigned
                            if (autoLinkOptions.OnAutoLinking != null)
                            {
                                autoLinkOptions.OnAutoLinking(autoLinkUser, loginInfo);
                            }

                            var userCreationResult = await UserManager.CreateAsync(autoLinkUser);

                            if (userCreationResult.Succeeded == false)
                            {
                                ViewData[TokenExternalSignInError] = userCreationResult.Errors;
                            }
                            else
                            {
                                var linkResult = await UserManager.AddLoginAsync(autoLinkUser.Id, loginInfo.Login);

                                if (linkResult.Succeeded == false)
                                {
                                    ViewData[TokenExternalSignInError] = linkResult.Errors;

                                    //If this fails, we should really delete the user since it will be in an inconsistent state!
                                    var deleteResult = await UserManager.DeleteAsync(autoLinkUser);

                                    if (deleteResult.Succeeded == false)
                                    {
                                        //DOH! ... this isn't good, combine all errors to be shown
                                        ViewData[TokenExternalSignInError] = linkResult.Errors.Concat(deleteResult.Errors);
                                    }
                                }
                                else
                                {
                                    //sign in
                                    await SignInManager.SignInAsync(autoLinkUser, isPersistent : false, rememberBrowser : false);
                                }
                            }
                        }
                    }
                }
                return(true);
            }

            return(false);
        }