diff --git a/Web/Controllers/AccountController.cs b/Web/Controllers/AccountController.cs
index 60b5ca4..f602e8a 100644
--- a/Web/Controllers/AccountController.cs
+++ b/Web/Controllers/AccountController.cs
@@ -43,11 +43,17 @@ namespace MileageTraker.Web.Controllers
catch (UserLockedOutException)
{
ModelState.AddModelError("",
- "Too many failed password attempts for " +
- model.Username + ". Account is locked. " +
- @"Use 'Forgot Password' or contact " +
- "administrator to unlock."
- );
+ "Too many failed password attempts for " +
+ model.Username + ". Account is locked. " +
+ @"Use 'Forgot Password' or contact " +
+ "administrator to unlock.");
+ }
+ catch (UninitializedAccountException)
+ {
+ ModelState.AddModelError("",
+ "Account for " +
+ model.Username + " has not been initialized. " +
+ @"Please check your email for initialization instructions.");
}
}
diff --git a/Web/Controllers/UserController.cs b/Web/Controllers/UserController.cs
index fcf76e9..320e359 100644
--- a/Web/Controllers/UserController.cs
+++ b/Web/Controllers/UserController.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using MileageTraker.Web.Attributes;
+using MileageTraker.Web.DAL;
using MileageTraker.Web.Email;
using MileageTraker.Web.Utility;
using MileageTraker.Web.ViewModels;
@@ -109,7 +110,7 @@ namespace MileageTraker.Web.Controllers
var membershipUser =
Membership.CreateUser(
viewModel.Username,
- "uninitialized_state",
+ CodeFirstMembershipProvider.UninitializedPassword,
viewModel.Email,
null,
null,
diff --git a/Web/DAL/CodeFirstMembershipProvider.cs b/Web/DAL/CodeFirstMembershipProvider.cs
index 2d28b26..97bdb58 100644
--- a/Web/DAL/CodeFirstMembershipProvider.cs
+++ b/Web/DAL/CodeFirstMembershipProvider.cs
@@ -8,6 +8,8 @@ namespace MileageTraker.Web.DAL
{
public class CodeFirstMembershipProvider : MembershipProvider
{
+ public const string UninitializedPassword = "uninitialized_state";
+
#region Properties
public override string ApplicationName
@@ -68,19 +70,17 @@ namespace MileageTraker.Web.DAL
status = MembershipCreateStatus.InvalidUserName;
return null;
}
- if (string.IsNullOrEmpty(password))
- {
- status = MembershipCreateStatus.InvalidPassword;
- return null;
- }
+
if (string.IsNullOrEmpty(email))
{
status = MembershipCreateStatus.InvalidEmail;
return null;
}
- var hashedPassword = Crypto.HashPassword(password);
- if (hashedPassword.Length > 128)
+ string hashedPassword = null;
+ if (password != UninitializedPassword)
+ hashedPassword = Crypto.HashPassword(password);
+ if (hashedPassword != null && hashedPassword.Length > 128)
{
status = MembershipCreateStatus.InvalidPassword;
return null;
@@ -143,7 +143,11 @@ namespace MileageTraker.Web.DAL
throw new UserLockedOutException();
}
var hashedPassword = user.Password;
- var verificationSucceeded = (hashedPassword != null && Crypto.VerifyHashedPassword(hashedPassword, password));
+
+ if (hashedPassword == null)
+ throw new UninitializedAccountException();
+
+ var verificationSucceeded =Crypto.VerifyHashedPassword(hashedPassword, password);
if (verificationSucceeded)
{
user.PasswordFailuresSinceLastSuccess = 0;
diff --git a/Web/DAL/UninitializedAccountException.cs b/Web/DAL/UninitializedAccountException.cs
new file mode 100644
index 0000000..139884c
--- /dev/null
+++ b/Web/DAL/UninitializedAccountException.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace MileageTraker.Web.DAL
+{
+ public class UninitializedAccountException : Exception
+ {
+ }
+}
\ No newline at end of file
diff --git a/Web/Migrations/201302130049004_PasswordNullForUninitialized.Designer.cs b/Web/Migrations/201302130049004_PasswordNullForUninitialized.Designer.cs
new file mode 100644
index 0000000..606f5a2
--- /dev/null
+++ b/Web/Migrations/201302130049004_PasswordNullForUninitialized.Designer.cs
@@ -0,0 +1,24 @@
+//
+namespace MileageTraker.Web.Migrations
+{
+ using System.Data.Entity.Migrations;
+ using System.Data.Entity.Migrations.Infrastructure;
+
+ public sealed partial class PasswordNullForUninitialized : IMigrationMetadata
+ {
+ string IMigrationMetadata.Id
+ {
+ get { return "201302130049004_PasswordNullForUninitialized"; }
+ }
+
+ string IMigrationMetadata.Source
+ {
+ get { return null; }
+ }
+
+ string IMigrationMetadata.Target
+ {
+ get { return "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"; }
+ }
+ }
+}
diff --git a/Web/Migrations/201302130049004_PasswordNullForUninitialized.cs b/Web/Migrations/201302130049004_PasswordNullForUninitialized.cs
new file mode 100644
index 0000000..775dbca
--- /dev/null
+++ b/Web/Migrations/201302130049004_PasswordNullForUninitialized.cs
@@ -0,0 +1,20 @@
+namespace MileageTraker.Web.Migrations
+{
+ using System.Data.Entity.Migrations;
+
+ public partial class PasswordNullForUninitialized : DbMigration
+ {
+ public override void Up()
+ {
+ AlterColumn("User", "Password", c => c.String(maxLength: 128));
+ Sql(@"update [User]
+ set Password = null
+ where Password = 'uninitialized_state'");
+ }
+
+ public override void Down()
+ {
+ AlterColumn("User", "Password", c => c.String(nullable: false, maxLength: 128));
+ }
+ }
+}
diff --git a/Web/Models/User.cs b/Web/Models/User.cs
index 64b38cc..e43dceb 100644
--- a/Web/Models/User.cs
+++ b/Web/Models/User.cs
@@ -28,7 +28,7 @@ namespace MileageTraker.Web.Models
[RegularExpression(@"[A-Za-z().]+(\s+[A-Za-z().]+)+", ErrorMessage = "Need complete name")]
public string FullName { get; set; }
- [Required, DataType(DataType.Password)]
+ [DataType(DataType.Password)]
[StringLength(128)]
public string Password { get; set; }
diff --git a/Web/Web.csproj b/Web/Web.csproj
index d0ace1d..95f9948 100644
--- a/Web/Web.csproj
+++ b/Web/Web.csproj
@@ -123,6 +123,7 @@
+
@@ -151,6 +152,10 @@
201301061929006_DropLogEmployeeName.cs
+
+
+ 201302130049004_PasswordNullForUninitialized.cs
+