public void ResetPasswordRequest_HappyPath()
        {
            using (var disposer = new Disposer())
            {
                AuthenticationController controller;
                var utcNow = new DateTime(2012, 10, 22, 23, 30, 0, DateTimeKind.Utc);
                var hasBeenSaved = false;
                var wasEmailSent = false;

                User user;
                string emailToken = null;
                string emailBody = null;
                string emailToAddress = null;
                string emailSubject = null;
                try
                {
                    user = this.db.Users.Single(x => x.UserName == "andrerpena");

                    var mr = new MockRepository();

                    var mve = mr.SetupViewEngine(disposer);
                    mve.SetViewContent(
                        "ResetPasswordEmail",
                        vc =>
                        {
                            emailToken = ((UserEmailViewModel)vc.ViewData.Model).Token;
                            return vc.ViewData.Model.ConvertObjectToString("<div>{0}={1}</div>");
                        });

                    controller = mr.CreateController<AuthenticationController>(
                        setupNewDb: db1 => { db1.SavingChanges += (s, e) => hasBeenSaved = true; });
                    controller.UtcNowGetter = () => utcNow;

                    controller.EmailSender += mm =>
                    {
                        wasEmailSent = true;
                        emailBody = mm.Body;
                        emailSubject = mm.Subject;
                        emailToAddress = mm.To.Single().Address;
                    };
                }
                catch (Exception ex)
                {
                    InconclusiveInit(ex);
                    return;
                }

                ActionResult actionResult;
                {
                    actionResult = controller.ResetPasswordRequest(
                        new IdentityViewModel
                            {
                                PracticeIdentifier = user.Practice.UrlIdentifier,
                                UserNameOrEmail = user.UserName,
                            });
                }

                using (var dbs = CreateNewCerebelloEntities())
                {
                    // Asserting.
                    Assert.IsTrue(controller.ModelState.IsValid, "ModelState is not valid.");

                    Assert.IsNotNull(actionResult);
                    Assert.IsInstanceOfType(actionResult, typeof(RedirectToRouteResult));
                    var redirectToRouteResult = (RedirectToRouteResult)actionResult;
                    Assert.AreEqual("ResetPasswordEmailSent", redirectToRouteResult.RouteValues["action"]);
                    Assert.AreEqual(null, redirectToRouteResult.RouteValues["controller"]);
                    Assert.AreEqual(null, redirectToRouteResult.RouteValues["area"]);

                    // Assert DB values.
                    Assert.IsTrue(hasBeenSaved, "The database has not been changed. This was supposed to happen.");
                    var tokenId = new TokenId(emailToken);
                    var savedToken = dbs.GLB_Token.Single(tk => tk.Id == tokenId.Id);
                    Assert.AreEqual(32, savedToken.Value.Length);
                    Assert.AreEqual(tokenId.Value, savedToken.Value);
                    Assert.AreEqual(utcNow.AddDays(30), savedToken.ExpirationDate);

                    // Assertion for email.
                    Assert.IsTrue(wasEmailSent, "E-mail was not sent, but it should.");
                    var emailViewModel = new UserEmailViewModel(user) { Token = emailToken, };
                    var emailExpected = emailViewModel.ConvertObjectToString("<div>{0}={1}</div>");
                    Assert.AreEqual(emailExpected, emailBody);
                    Assert.AreEqual("Redefinir senha da conta no Cerebello", emailSubject);
                    Assert.AreEqual("*****@*****.**", emailToAddress);
                }
            }
        }
        public ActionResult ResetPasswordRequest(IdentityViewModel viewModel)
        {
            if (string.IsNullOrWhiteSpace(viewModel.PracticeIdentifier))
                return this.View(viewModel);

            if (string.IsNullOrWhiteSpace(viewModel.UserNameOrEmail))
                return this.View(viewModel);

            // Can only reset password if practice has already been verified.
            var practice = this.db.Practices.SingleOrDefault(p => p.UrlIdentifier == viewModel.PracticeIdentifier);

            var user = SecurityManager.GetUser(this.db.Users, viewModel.PracticeIdentifier, viewModel.UserNameOrEmail);

            if (practice == null || user == null)
            {
                this.ModelState.ClearPropertyErrors(() => viewModel.PracticeIdentifier);
                this.ModelState.ClearPropertyErrors(() => viewModel.UserNameOrEmail);
                this.ModelState.AddModelError(
                    () => viewModel.PracticeIdentifier,
                    "O consultório ou usuário não existem. Por favor verifique se não cometeu nenhum erro de digitação.");
            }

            if (practice != null && practice.VerificationDate == null && user != null)
            {
                this.ModelState.AddModelError(
                    () => viewModel.PracticeIdentifier,
                    "Não é possível resetar a senha pois o consultório ainda não foi verificado. "
                    + "Confirme o seu e-mail antes de tentar mudar a senha.");
            }

            if (this.ModelState.IsValid)
            {
                var utcNow = this.GetUtcNow();

                // Creating confirmation email, with the token.
                MailMessage message;

                if (user.Person.Email != null)
                {
                    #region Creating token and e-mail message

                    // Setting verification token.
                    // Note: tokens are safe to save even if validation fails.
                    TokenId tokenId;
                    using (var db2 = this.CreateNewCerebelloEntities())
                    {
                        var token = db2.GLB_Token.CreateObject();
                        token.Value = Guid.NewGuid().ToString("N");
                        token.Type = "ResetPassword";
                        token.Name = string.Format(
                            "Practice={0}&UserName={1}",
                            user.Practice.UrlIdentifier,
                            user.UserName);
                        token.ExpirationDate = utcNow.AddDays(Constants.MAX_DAYS_TO_RESET_PASSWORD);
                        db2.GLB_Token.AddObject(token);
                        db2.SaveChanges();

                        tokenId = new TokenId(token.Id, token.Value);
                    }

                    // Rendering message bodies from partial view.
                    var emailViewModel = new UserEmailViewModel(user) { Token = tokenId.ToString(), };
                    var toAddress = new MailAddress(user.Person.Email, user.Person.FullName);
                    message = this.CreateEmailMessagePartial("ResetPasswordEmail", toAddress, emailViewModel);

                    #endregion
                }
                else
                {
                    return this.RedirectToAction("ResetPasswordManually");
                }

                // If the ModelState is still valid, then save objects to the database,
                // and send confirmation email message to the user.
                using (message)
                {
                    if (this.ModelState.IsValid)
                    {
                        try
                        {
                            // Sending the password reset e-mail to the user.
                            this.TrySendEmail(message);
                        }
                        catch (SmtpException)
                        {
                            // if e-mail was not sent, try to send it again, after 10 seconds
                            Thread.Sleep(10000);
                            this.TrySendEmail(message);
                        }

                        return this.RedirectToAction("ResetPasswordEmailSent");
                    }
                }
            }

            return this.View(viewModel);
        }
        private MailMessage EmailMessageToUser(User user, DateTime utcNow, bool isTrial)
        {
            TokenId tokenId;

            // Setting verification token.
            using (var db2 = this.CreateNewCerebelloEntities())
            {
                var token = new GLB_Token();
                token.Value = Guid.NewGuid().ToString("N");
                token.Type = "VerifyPracticeAndEmail";
                token.Name = string.Format("Practice={0}&UserName={1}", user.Practice.UrlIdentifier, user.UserName);
                token.ExpirationDate = utcNow.AddHours(Constants.MAX_HOURS_TO_VERIFY_TRIAL_ACCOUNT);
                db2.GLB_Token.AddObject(token);
                db2.SaveChanges();

                tokenId = new TokenId(token.Id, token.Value);
            }

            // Rendering message bodies from partial view.
            var emailViewModel = new UserEmailViewModel(user) { Token = tokenId.ToString(), IsTrial = isTrial };
            var toAddress = new MailAddress(user.Person.Email, user.Person.FullName);
            var emailMessageToUser = this.CreateEmailMessage("ConfirmationEmail", toAddress, emailViewModel);

            return emailMessageToUser;
        }
        public ActionResult ResetPasswordCancel(ResetPasswordViewModel viewModel)
        {
            var utcNow = this.GetUtcNow();

            var user = SecurityManager.GetUser(this.db.Users, viewModel.PracticeIdentifier, viewModel.UserNameOrEmail);

            if (user != null)
            {
                // Getting token information, so that we can locate the token in the database.
                var tokenInfo = new TokenId(viewModel.Token);

                var tokenName = string.Format("Practice={0}&UserName={1}", viewModel.PracticeIdentifier, user.UserName);

                // Destroying the token.
                var token = this.db.GLB_Token.SingleOrDefault(tk =>
                                                              tk.Id == tokenInfo.Id
                                                              && tk.Value == tokenInfo.Value
                                                              && tk.ExpirationDate >= utcNow
                                                              && tk.Type == "ResetPassword"
                                                              && tk.Name == tokenName);

                if (token != null)
                {
                    this.db.GLB_Token.DeleteObject(token);

                    this.db.SaveChanges();
                }
                else
                    this.ViewBag.CannotRedefinePassword = true;
            }

            return this.View();
        }
        public ActionResult VerifyPracticeAndEmail(VerifyPracticeAndEmailViewModel viewModel)
        {
            var utcNow = this.GetUtcNow();

            User user = null;

            // If user is not logged yet, we will use the userName and password to login.
            if (this.Request.IsAuthenticated)
            {
                var authenticatedPrincipal = this.User as AuthenticatedPrincipal;

                if (authenticatedPrincipal == null)
                    throw new Exception(
                        "HttpContext.User should be a AuthenticatedPrincipal when the user is authenticated");

                if (authenticatedPrincipal.Profile.PracticeIdentifier == viewModel.PracticeIdentifier)
                    user = this.db.Users.FirstOrDefault(u => u.Id == authenticatedPrincipal.Profile.Id);
            }

            if (user != null || this.Request.HttpMethod == "GET")
            {
                this.ModelState.Remove(() => viewModel.PracticeIdentifier);
                this.ModelState.Remove(() => viewModel.UserNameOrEmail);
                this.ModelState.Remove(() => viewModel.Password);
                this.ModelState.Remove(() => viewModel.Token);
            }

            if (user == null)
            {
                var loginModel = new LoginViewModel
                {
                    PracticeIdentifier = viewModel.PracticeIdentifier ?? "",
                    UserNameOrEmail = viewModel.UserNameOrEmail ?? "",
                    Password = viewModel.Password ?? "",
                    RememberMe = viewModel.RememberMe,
                };

                var cookieCollection = this.HttpContext.Response.Cookies;
                if (!this.ModelState.IsValid ||
                    !SecurityManager.Login(cookieCollection, loginModel, this.db.Users, out user, this.GetUtcNow()))
                {
                    this.ViewBag.LoginFailed = true;
                }
                else
                {
                    user.LastActiveOn = this.GetUtcNow();
                    user.SYS_PasswordAlt = null;

                    this.db.SaveChanges();

                    if (loginModel.Password == Constants.DEFAULT_PASSWORD)
                        throw new Exception("Cannot create initial user with a default password.");
                }
            }

            var isTokenValid = TokenId.IsValid(viewModel.Token);
            GLB_Token token = null;
            if (isTokenValid && user != null)
            {
                var tokenId = new TokenId(viewModel.Token);

                // Getting verification token, using the informations.
                var tokenName = string.Format("Practice={0}&UserName={1}", viewModel.PracticeIdentifier, user.UserName);
                token = this.db.GLB_Token.SingleOrDefault(tk =>
                                                              tk.Id == tokenId.Id
                                                              && tk.Value == tokenId.Value
                                                              && tk.Type == "VerifyPracticeAndEmail"
                                                              && tk.Name == tokenName);
            }

            var practice = this.db.Practices
                .SingleOrDefault(p => p.UrlIdentifier == viewModel.PracticeIdentifier);

            if (token == null)
                isTokenValid = false;

            if (practice == null && this.Request.HttpMethod != "GET" && !this.ModelState.HasPropertyErrors(() => viewModel.PracticeIdentifier))
                this.ModelState.AddModelError(() => viewModel.PracticeIdentifier, "Consultório não foi achado.");

            if (token != null && practice != null)
            {
                // setting practice verification data
                if (utcNow <= token.ExpirationDate)
                {
                    practice.VerificationDate = utcNow;
                    practice.VerificationMethod = "EMAIL";
                }
                else
                    isTokenValid = false;

                // Destroying token... it has been used with success, and is no longer needed.
                this.db.GLB_Token.DeleteObject(token);

                // Saving changes.
                // Note: even if ModelState.IsValid is false,
                // we need to save the changes to invalidate token when it expires.
                this.db.SaveChanges();
            }

            if (!isTokenValid && user != null)
            {
                this.ModelState.AddModelError(() => viewModel.Token, "Problema com o token.");
            }

            if (this.ModelState.IsValid && user != null && practice != null)
            {
                return this.RedirectToAction(
                    "Welcome",
                    "Home",
                    new { area = "", practice = practice.UrlIdentifier });
            }

            viewModel.Password = null; // cannot allow password going to the view.
            return this.View(viewModel);
        }