mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Adding password storage and verification. Clear and hashed supported. Hashed is default, uses SHA1 with unique salt per user.
--HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4040935
This commit is contained in:
@@ -13,14 +13,17 @@ using Orchard.Users.ViewModels;
|
||||
namespace Orchard.Users.Controllers {
|
||||
|
||||
public class AdminController : Controller, IModelUpdater {
|
||||
private readonly IMembershipService _membershipService;
|
||||
private readonly IModelManager _modelManager;
|
||||
private readonly IRepository<UserRecord> _userRepository;
|
||||
private readonly INotifier _notifier;
|
||||
|
||||
public AdminController(
|
||||
IMembershipService membershipService,
|
||||
IModelManager modelManager,
|
||||
IRepository<UserRecord> userRepository,
|
||||
INotifier notifier) {
|
||||
_membershipService = membershipService;
|
||||
_modelManager = modelManager;
|
||||
_userRepository = userRepository;
|
||||
_notifier = notifier;
|
||||
@@ -49,12 +52,17 @@ namespace Orchard.Users.Controllers {
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Create(UserCreateViewModel model) {
|
||||
if (model.Password != model.ConfirmPassword) {
|
||||
ModelState.AddModelError("ConfirmPassword", T("Password confirmation must match").ToString());
|
||||
}
|
||||
if (ModelState.IsValid == false) {
|
||||
return View(model);
|
||||
}
|
||||
var user = _modelManager.New("user");
|
||||
user.As<UserModel>().Record = new UserRecord { UserName = model.UserName, Email = model.Email };
|
||||
_modelManager.Create(user);
|
||||
var user = _membershipService.CreateUser(new CreateUserParams(
|
||||
model.UserName,
|
||||
model.Password,
|
||||
model.Email,
|
||||
null, null, true));
|
||||
return RedirectToAction("edit", new { user.Id });
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,13 @@
|
||||
using System.Web.Security;
|
||||
using Orchard.Models.Records;
|
||||
|
||||
namespace Orchard.Users.Models {
|
||||
public class UserRecord : ModelPartRecord {
|
||||
public virtual string UserName { get; set; }
|
||||
public virtual string Email { get; set; }
|
||||
|
||||
public virtual string Password { get; set; }
|
||||
public virtual MembershipPasswordFormat PasswordFormat { get; set; }
|
||||
public virtual string PasswordSalt { get; set; }
|
||||
}
|
||||
}
|
@@ -77,6 +77,7 @@
|
||||
<Content Include="Package.txt" />
|
||||
<Content Include="Views\Admin\Edit.aspx" />
|
||||
<Content Include="Views\Admin\Create.aspx" />
|
||||
<Content Include="Views\Admin\EditorTemplates\inputPasswordLarge.ascx" />
|
||||
<Content Include="Views\Admin\EditorTemplates\UserEditViewModel.ascx" />
|
||||
<Content Include="Views\Admin\EditorTemplates\inputTextLarge.ascx" />
|
||||
<Content Include="Views\Admin\EditorTemplates\UserCreateViewModel.ascx" />
|
||||
|
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Web.Security;
|
||||
using Orchard.Data;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Models;
|
||||
@@ -26,11 +30,14 @@ namespace Orchard.Users.Services {
|
||||
|
||||
public IUser CreateUser(CreateUserParams createUserParams) {
|
||||
Logger.Information("CreateUser {0} {1}", createUserParams.Username, createUserParams.Email);
|
||||
var user = _modelManager.New("user");
|
||||
user.As<UserModel>().Record = new UserRecord {
|
||||
var record = new UserRecord {
|
||||
UserName = createUserParams.Username,
|
||||
Email = createUserParams.Email
|
||||
};
|
||||
SetPassword(record, createUserParams.Password);
|
||||
|
||||
var user = _modelManager.New("user");
|
||||
user.As<UserModel>().Record = record;
|
||||
_modelManager.Create(user);
|
||||
return user.As<IUser>();
|
||||
}
|
||||
@@ -44,7 +51,104 @@ namespace Orchard.Users.Services {
|
||||
}
|
||||
|
||||
public IUser ValidateUser(string username, string password) {
|
||||
return GetUser(username);
|
||||
var userRecord = _userRepository.Get(x => x.UserName == username);
|
||||
if (userRecord == null || ValidatePassword(userRecord, password) == false)
|
||||
return null;
|
||||
|
||||
return _modelManager.Get(userRecord.Id).As<IUser>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void SetPassword(IUser user, string password) {
|
||||
if (!user.Is<UserModel>())
|
||||
throw new InvalidCastException();
|
||||
|
||||
var userRecord = user.As<UserModel>().Record;
|
||||
SetPassword(userRecord, password);
|
||||
}
|
||||
|
||||
|
||||
void SetPassword(UserRecord record, string password) {
|
||||
switch (GetSettings().PasswordFormat) {
|
||||
case MembershipPasswordFormat.Clear:
|
||||
SetPasswordClear(record, password);
|
||||
break;
|
||||
case MembershipPasswordFormat.Hashed:
|
||||
SetPasswordHashed(record, password);
|
||||
break;
|
||||
case MembershipPasswordFormat.Encrypted:
|
||||
SetPasswordEncrypted(record, password);
|
||||
break;
|
||||
default:
|
||||
throw new ApplicationException("Unexpected password format value");
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidatePassword(UserRecord record, string password) {
|
||||
// Note - the password format stored with the record is used
|
||||
// otherwise changing the password format on the site would invalidate
|
||||
// all logins
|
||||
switch (record.PasswordFormat) {
|
||||
case MembershipPasswordFormat.Clear:
|
||||
return ValidatePasswordClear(record, password);
|
||||
case MembershipPasswordFormat.Hashed:
|
||||
return ValidatePasswordHashed(record, password);
|
||||
case MembershipPasswordFormat.Encrypted:
|
||||
return ValidatePasswordEncrypted(record, password);
|
||||
default:
|
||||
throw new ApplicationException("Unexpected password format value");
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetPasswordClear(UserRecord record, string password) {
|
||||
record.PasswordFormat = MembershipPasswordFormat.Clear;
|
||||
record.Password = password;
|
||||
record.PasswordSalt = null;
|
||||
}
|
||||
|
||||
private static bool ValidatePasswordClear(UserRecord record, string password) {
|
||||
return record.Password == password;
|
||||
}
|
||||
|
||||
private static void SetPasswordHashed(UserRecord record, string password) {
|
||||
|
||||
var saltBytes = new byte[0x10];
|
||||
var random = new RNGCryptoServiceProvider();
|
||||
random.GetBytes(saltBytes);
|
||||
|
||||
var passwordBytes = Encoding.Unicode.GetBytes(password);
|
||||
|
||||
var combinedBytes = saltBytes.Concat(passwordBytes).ToArray();
|
||||
|
||||
var hashAlgorithm = HashAlgorithm.Create("SHA1");
|
||||
var hashBytes = hashAlgorithm.ComputeHash(combinedBytes);
|
||||
|
||||
record.PasswordFormat = MembershipPasswordFormat.Hashed;
|
||||
record.Password = Convert.ToBase64String(hashBytes);
|
||||
record.PasswordSalt = Convert.ToBase64String(saltBytes);
|
||||
}
|
||||
|
||||
private static bool ValidatePasswordHashed(UserRecord record, string password) {
|
||||
|
||||
var saltBytes = Convert.FromBase64String(record.PasswordSalt);
|
||||
|
||||
var passwordBytes = Encoding.Unicode.GetBytes(password);
|
||||
|
||||
var combinedBytes = saltBytes.Concat(passwordBytes).ToArray();
|
||||
|
||||
var hashAlgorithm = HashAlgorithm.Create("SHA1");
|
||||
var hashBytes = hashAlgorithm.ComputeHash(combinedBytes);
|
||||
|
||||
return record.Password == Convert.ToBase64String(hashBytes);
|
||||
}
|
||||
|
||||
private static void SetPasswordEncrypted(UserRecord record, string password) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static bool ValidatePasswordEncrypted(UserRecord record, string password) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,13 @@ namespace Orchard.Users.ViewModels {
|
||||
[Required]
|
||||
public string UserName { get; set; }
|
||||
|
||||
[Required]
|
||||
[Required, DataType(DataType.EmailAddress)]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required, DataType(DataType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Required, DataType(DataType.Password)]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
}
|
@@ -4,4 +4,6 @@
|
||||
<ol>
|
||||
<%=Html.EditorFor(m=>m.UserName, "inputTextLarge") %>
|
||||
<%=Html.EditorFor(m=>m.Email, "inputTextLarge") %>
|
||||
<%=Html.EditorFor(m=>m.Password, "inputPasswordLarge") %>
|
||||
<%=Html.EditorFor(m=>m.ConfirmPassword, "inputPasswordLarge") %>
|
||||
</ol>
|
||||
|
@@ -0,0 +1,6 @@
|
||||
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
|
||||
<li>
|
||||
<%=Html.LabelForModel() %>
|
||||
<%=Html.Password("",Model,new{@class="inputText inputTextLarge"}) %>
|
||||
<%=Html.ValidationMessage("","*")%>
|
||||
</li>
|
Reference in New Issue
Block a user