Updates Login and ForgotPassword to be MVC and have a Captcha

This commit is contained in:
Sebastiaan Janssen
2016-12-07 18:50:56 +01:00
parent d5761dbcd1
commit 6e1797537f
7 changed files with 353 additions and 6 deletions
+4
View File
@@ -1761,6 +1761,8 @@
<Content Include="umbraco\lib\bootstrap-tabdrop\README.md" />
<Content Include="Views\MacroPartials\Releases\ReleasesDropdown.cshtml" />
<Content Include="Views\Partials\Community\TermsAndConditions.cshtml" />
<Content Include="Views\MacroPartials\Members\ForgotPassword.cshtml" />
<Content Include="Views\MacroPartials\Members\Login.cshtml" />
<None Include="Views\Partials\Forum\MemberBadge.cshtml" />
<Content Include="Views\Search\Search.aspx" />
<Content Include="Views\Web.config" />
@@ -4414,6 +4416,8 @@
<Content Include="Views\Partials\Grid\Bootstrap3-Fluid.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2-Fluid.cshtml" />
<Content Include="Views\Partials\Members\Login.cshtml" />
<Content Include="Views\Partials\Members\ForgotPassword.cshtml" />
<None Include="web.Debug.config">
<DependentUpon>web.config</DependentUpon>
</None>
@@ -0,0 +1,10 @@
@inherits Umbraco.Web.Macros.PartialViewMacroPage
@{
if (Members.IsLoggedIn())
{
Response.Redirect("/member/profile");
}
}
@Html.Action("RenderForgotPassword", "Login")
@@ -0,0 +1,17 @@
@inherits Umbraco.Web.Macros.PartialViewMacroPage
@{
if (Members.IsLoggedIn())
{
if (Model.MacroParameters["NextPage"] != null && string.IsNullOrWhiteSpace(Model.MacroParameters["NextPage"].ToString()) == false)
{
// It's being called from the old package repository, don't redirect
}
else
{
Response.Redirect("/member/profile");
}
}
}
@Html.Action("RenderLogin", "Login")
@@ -0,0 +1,49 @@
@using OurUmbraco.Our.Controllers
@using reCAPTCHA.MVC
@inherits UmbracoViewPage<Umbraco.Web.Models.LoginModel>
@{
Html.EnableClientValidation(true);
Html.EnableUnobtrusiveJavaScript(true);
}
@if (Request.QueryString["success"] == null)
{
<div class="form simpleForm" id="registrationForm">
@using (Html.BeginUmbracoForm<LoginController>("ForgotPassword"))
{
@Html.ValidationSummary(true)
@Html.AntiForgeryToken()
<fieldset>
<p>
@Html.LabelFor(m => m.Username, new { @cless = "inputLabel" })<br />
@Html.ValidationMessageFor(m => m.Username)
@Html.TextBoxFor(m => m.Username, new { @class = "email title" })
</p>
</fieldset>
<fieldset>
<p>
@Html.Recaptcha()
@Html.ValidationMessage("ReCaptcha")
</p>
</fieldset>
<input class="button green" type="submit" value="Retrieve password">
}
</div>
}
else
{
<p>If an account with that email exists you have just been sent instructions to reset your password.</p>
}
<style type="text/css">
.field-validation-error, .validation-summary-errors {
color: red;
}
.input-validation-error {
border-color: red !important;
}
</style>
@@ -0,0 +1,50 @@
@using OurUmbraco.Our.Controllers
@using reCAPTCHA.MVC
@inherits UmbracoViewPage<Umbraco.Web.Models.LoginModel>
@{
Html.EnableClientValidation(true);
Html.EnableUnobtrusiveJavaScript(true);
}
<div class="form simpleForm" id="registrationForm">
@using (Html.BeginUmbracoForm<LoginController>("Login"))
{
@Html.ValidationSummary(true)
@Html.AntiForgeryToken()
<fieldset>
<p>
@Html.LabelFor(m => m.Username, new { @class = "inputLabel" })<br />
@Html.ValidationMessageFor(m => m.Username)
@Html.TextBoxFor(m => m.Username, new { @class = "email title" })
</p>
</fieldset>
<fieldset>
<p>
@Html.LabelFor(m => m.Password, new { @class = "inputLabel" })<br />
@Html.ValidationMessageFor(m => m.Password)
@Html.PasswordFor(m => m.Password, new { @class = "password title" })
</p>
</fieldset>
<fieldset>
<p>
@Html.Recaptcha()
@Html.ValidationMessage("ReCaptcha")
</p>
</fieldset>
<input class="button green" type="submit" value="Log in">
}
</div>
<style type="text/css">
.field-validation-error, .validation-summary-errors {
color: red;
}
.input-validation-error {
border-color: red !important;
}
</style>
+167 -2
View File
@@ -1,11 +1,176 @@
using System.Web.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Web.Mvc;
using System.Web.Security;
using OurUmbraco.Our.usercontrols;
using reCAPTCHA.MVC;
using Umbraco.Core;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
namespace OurUmbraco.Our.Controllers
{
public class LoginController: SurfaceController
public class LoginController : SurfaceController
{
[ChildActionOnly]
public ActionResult RenderLogin()
{
var loginModel = new LoginModel();
return PartialView("~/Views/Partials/Members/Login.cshtml", loginModel);
}
[ChildActionOnly]
public ActionResult RenderForgotPassword()
{
var loginModel = new LoginModel();
return PartialView("~/Views/Partials/Members/ForgotPassword.cshtml", loginModel);
}
[CaptchaValidator]
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid == false)
return CurrentUmbracoPage();
var memberService = Services.MemberService;
int totalMembers;
var members = memberService.FindByEmail(model.Username, 0, 100, out totalMembers).ToList();
if (totalMembers > 1)
{
var duplicateMembers = new List<DuplicateMember>();
foreach (var member in members)
{
var totalKarma = member.GetValue<int>("reputationTotal");
var duplicateMember = new DuplicateMember { MemberId = member.Id, TotalKarma = totalKarma };
duplicateMembers.Add(duplicateMember);
}
// rename username/email for each duplicate member
// EXCEPT for the one with the highest karma (Skip(1))
foreach (var duplicateMember in duplicateMembers.OrderByDescending(x => x.TotalKarma).ThenByDescending(x => x.MemberId).Skip(1))
{
var member = memberService.GetById(duplicateMember.MemberId);
var newUserName = member.Username.Replace("@", "@__" + member.Id);
member.Username = newUserName;
member.Email = newUserName;
memberService.Save(member, false);
}
}
var memberToLogin = memberService.FindByEmail(model.Username, 0, 1, out totalMembers).SingleOrDefault();
if (memberToLogin != null)
{
// Note: After July 23rd 2015 we need people to activate their accounts! Don't approve automatically
// otherwise:
// Automatically approve all members, as we don't have an approval process now
// This is needed as we added new membership after upgrading so IsApproved is
// currently empty. First time a member gets saved now (login also saves the member)
// IsApproved would turn false (default value of bool) so we want to prevent that
if (memberToLogin.CreateDate < DateTime.Parse("2015-07-23") && memberToLogin.Properties.Contains(Constants.Conventions.Member.IsApproved) && memberToLogin.IsApproved == false)
{
memberToLogin.IsApproved = true;
memberService.Save(memberToLogin, false);
}
}
if (Members.Login(model.Username, model.Password))
{
return Redirect("/");
}
ModelState.AddModelError("", "That username and password combination isn't valid here");
return CurrentUmbracoPage();
}
[CaptchaValidator]
public ActionResult ForgotPassword(LoginModel model)
{
if (string.IsNullOrWhiteSpace(model.Username))
return CurrentUmbracoPage();
var memberService = Services.MemberService;
int totalMembers;
var members = memberService.FindByEmail(model.Username, 0, 100, out totalMembers);
if (totalMembers > 1)
{
var duplicateMembers = new List<DuplicateMember>();
foreach (var member in members)
{
var totalKarma = member.GetValue<int>("reputationTotal");
var duplicateMember = new DuplicateMember { MemberId = member.Id, TotalKarma = totalKarma };
duplicateMembers.Add(duplicateMember);
}
// rename username/email for each duplicate member
// EXCEPT for the one with the highest karma (Skip(1))
foreach (
var duplicateMember in
duplicateMembers.OrderByDescending(x => x.TotalKarma).ThenByDescending(x => x.MemberId).Skip(1))
{
var member = memberService.GetById(duplicateMember.MemberId);
var newUserName = member.Username.Replace("@", "@__" + member.Id);
member.Username = newUserName;
member.Email = newUserName;
memberService.Save(member);
}
}
var m = memberService.GetByEmail(model.Username);
if (m == null)
{
// Don't add an error and reveal that someone with this email address exists on this site
return Redirect(CurrentPage.Url + "?success=true");
}
// Automatically approve all members, as we don't have an approval process now
// This is needed as we added new membership after upgrading so IsApproved is
// currently empty. First time a member gets saved now (login also saves the member)
// IsApproved would turn false (default value of bool) so we want to prevent that
if (m.Properties.Contains(Constants.Conventions.Member.IsApproved) && m.IsApproved == false)
{
m.IsApproved = true;
memberService.Save(m, false);
}
var pass = RandomString(16, true);
memberService.SavePassword(m, pass);
var mail = "<p>Hi " + m.Name + "</p>";
mail = mail + "<p>This is your new password for your account on https://our.umbraco.org:</p>";
mail = mail + "<p><strong>" + pass + "</strong></p>";
mail = mail + "<br/><br/><p>All the best<br/> <em>The email robot</em></p>";
using (var mailMessage = new MailMessage())
{
mailMessage.Subject = "Your password to our.umbraco.org";
mailMessage.Body = mail;
mailMessage.IsBodyHtml = true;
mailMessage.To.Add(new MailAddress(m.Email));
mailMessage.From = new MailAddress("robot@umbraco.org");
using (var smtpClient = new SmtpClient())
smtpClient.Send(mailMessage);
}
return Redirect(CurrentPage.Url + "?success=true");
}
private string RandomString(int size, bool lowerCase)
{
var builder = new StringBuilder();
var random = new Random();
for (var i = 0; i < size; i++)
{
var ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return lowerCase ? builder.ToString().ToLower() : builder.ToString();
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
+56 -4
View File
@@ -35,6 +35,8 @@ namespace OurUmbraco.Our
AddStrictMinimumVersionForPackages();
RenameUaaStoUCloud();
AddMarkAsSolutionReminderSent();
UseNewLoginForm();
UseNewForgotPasswordForm();
}
private void EnsureMigrationsMarkerPathExists()
@@ -379,7 +381,7 @@ namespace OurUmbraco.Our
compareContentType = contentTypeService.GetContentType(releaseCompareAlias);
var releaseLandingContentType = contentTypeService.GetContentType("ReleaseLanding");
var allowedContentTypes = new List<ContentTypeSort> { new ContentTypeSort(compareContentType.Id, 0) };
releaseLandingContentType.AllowedContentTypes = allowedContentTypes;
contentTypeService.Save(releaseLandingContentType);
@@ -489,13 +491,13 @@ namespace OurUmbraco.Our
var path = HostingEnvironment.MapPath(MigrationMarkersPath + migrationName + ".txt");
if (File.Exists(path))
return;
var macroService = ApplicationContext.Current.Services.MacroService;
var macro = macroService.GetByAlias("MemberSignup");
macro.ControlType = "";
macro.ScriptPath = "~/Views/MacroPartials/Members/Register.cshtml";
macroService.Save(macro);
string[] lines = { "" };
File.WriteAllLines(path, lines);
}
@@ -526,7 +528,7 @@ namespace OurUmbraco.Our
LogHelper.Error<MigrationsHandler>(string.Format("Migration: '{0}' failed", migrationName), ex);
}
}
private void RenameUaaStoUCloud()
{
var migrationName = MethodBase.GetCurrentMethod().Name;
@@ -585,5 +587,55 @@ namespace OurUmbraco.Our
LogHelper.Error<MigrationsHandler>(string.Format("Migration: '{0}' failed", migrationName), ex);
}
}
private void UseNewLoginForm()
{
var migrationName = MethodBase.GetCurrentMethod().Name;
try
{
var path = HostingEnvironment.MapPath(MigrationMarkersPath + migrationName + ".txt");
if (File.Exists(path))
return;
var macroService = ApplicationContext.Current.Services.MacroService;
var macro = macroService.GetByAlias("MemberLogin");
macro.ControlType = "";
macro.ScriptPath = "~/Views/MacroPartials/Members/Login.cshtml";
macroService.Save(macro);
string[] lines = { "" };
File.WriteAllLines(path, lines);
}
catch (Exception ex)
{
LogHelper.Error<MigrationsHandler>(string.Format("Migration: '{0}' failed", migrationName), ex);
}
}
private void UseNewForgotPasswordForm()
{
var migrationName = MethodBase.GetCurrentMethod().Name;
try
{
var path = HostingEnvironment.MapPath(MigrationMarkersPath + migrationName + ".txt");
if (File.Exists(path))
return;
var macroService = ApplicationContext.Current.Services.MacroService;
var macro = macroService.GetByAlias("MemberPasswordReminder");
macro.ControlType = "";
macro.ScriptPath = "~/Views/MacroPartials/Members/ForgotPassword.cshtml";
macroService.Save(macro);
string[] lines = { "" };
File.WriteAllLines(path, lines);
}
catch (Exception ex)
{
LogHelper.Error<MigrationsHandler>(string.Format("Migration: '{0}' failed", migrationName), ex);
}
}
}
}