Files
Orchard/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs
2010-12-08 18:18:52 -08:00

389 lines
16 KiB
C#

using System;
using System.Diagnostics.CodeAnalysis;
using Orchard.Localization;
using System.Security.Principal;
using System.Web.Mvc;
using System.Web.Security;
using Orchard.Logging;
using Orchard.Mvc.Extensions;
using Orchard.Security;
using Orchard.Themes;
using Orchard.Users.Services;
using Orchard.Users.ViewModels;
using Orchard.ContentManagement;
using Orchard.Users.Models;
using Orchard.UI.Notify;
namespace Orchard.Users.Controllers {
[HandleError, Themed]
public class AccountController : Controller {
private readonly IAuthenticationService _authenticationService;
private readonly IMembershipService _membershipService;
private readonly IUserService _userService;
private readonly IOrchardServices _orchardServices;
public AccountController(
IAuthenticationService authenticationService,
IMembershipService membershipService,
IUserService userService,
IOrchardServices orchardServices) {
_authenticationService = authenticationService;
_membershipService = membershipService;
_userService = userService;
_orchardServices = orchardServices;
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
}
public ILogger Logger { get; set; }
public Localizer T { get; set; }
public ActionResult AccessDenied() {
var returnUrl = Request.QueryString["ReturnUrl"];
var currentUser = _authenticationService.GetAuthenticatedUser();
if (currentUser == null) {
Logger.Information("Access denied to anonymous request on {0}", returnUrl);
return View("LogOn", new LogOnViewModel {Title = "Access Denied"});
}
//TODO: (erikpo) Add a setting for whether or not to log access denieds since these can fill up a database pretty fast from bots on a high traffic site
Logger.Information("Access denied to user #{0} '{1}' on {2}", currentUser.Id, currentUser.UserName, returnUrl);
return View();
}
public ActionResult LogOn() {
if (_authenticationService.GetAuthenticatedUser() != null)
return Redirect("~/");
return View(new LogOnViewModel { Title = T("Log On").Text });
}
[HttpPost]
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameter type as Controller.Redirect()")]
public ActionResult LogOn(string userNameOrEmail, string password, string returnUrl) {
var user = ValidateLogOn(userNameOrEmail, password);
if (!ModelState.IsValid) {
return View(new LogOnViewModel { Title = T("Log On").Text });
}
_authenticationService.SignIn(user, false);
if (string.IsNullOrEmpty(returnUrl))
return new RedirectResult("~/");
return new RedirectResult(returnUrl);
}
public ActionResult LogOff(string returnUrl) {
_authenticationService.SignOut();
if (string.IsNullOrEmpty(returnUrl))
return new RedirectResult("~/");
return new RedirectResult(returnUrl);
}
int MinPasswordLength {
get {
return _membershipService.GetSettings().MinRequiredPasswordLength;
}
}
public ActionResult Register() {
// ensure users can register
var registrationSettings = _orchardServices.WorkContext.CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.UsersCanRegister ) {
return HttpNotFound();
}
ViewData["PasswordLength"] = MinPasswordLength;
return View();
}
[HttpPost]
public ActionResult Register(string userName, string email, string password, string confirmPassword) {
// ensure users can register
var registrationSettings = _orchardServices.WorkContext.CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.UsersCanRegister ) {
return HttpNotFound();
}
ViewData["PasswordLength"] = MinPasswordLength;
if (ValidateRegistration(userName, email, password, confirmPassword)) {
// Attempt to register the user
var user = _membershipService.CreateUser(new CreateUserParams(userName, password, email, null, null, false));
if (user != null) {
if ( user.As<UserPart>().EmailStatus == UserStatus.Pending ) {
_userService.SendChallengeEmail(user.As<UserPart>(), nonce => Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new { Area = "Orchard.Users", nonce = nonce })));
return RedirectToAction("ChallengeEmailSent");
}
if (user.As<UserPart>().RegistrationStatus == UserStatus.Pending) {
return RedirectToAction("RegistrationPending");
}
_authenticationService.SignIn(user, false /* createPersistentCookie */);
return Redirect("~/");
}
ModelState.AddModelError("_FORM", T(ErrorCodeToString(/*createStatus*/MembershipCreateStatus.ProviderError)));
}
// If we got this far, something failed, redisplay form
return Register();
}
public ActionResult RequestLostPassword() {
// ensure users can request lost password
var registrationSettings = _orchardServices.WorkContext.CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.EnableLostPassword ) {
return HttpNotFound();
}
return View();
}
[HttpPost]
public ActionResult RequestLostPassword(string username) {
// ensure users can request lost password
var registrationSettings = _orchardServices.WorkContext.CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.EnableLostPassword ) {
return HttpNotFound();
}
if(String.IsNullOrWhiteSpace(username)){
_orchardServices.Notifier.Error(T("Invalid username or E-mail"));
return View();
}
_userService.SendLostPasswordEmail(username, nonce => Url.AbsoluteAction(() => Url.Action("ValidateLostPassword", "Account", new { Area = "Orchard.Users", nonce = nonce })));
_orchardServices.Notifier.Information(T("Check your e-mail for the confirmation link."));
return RedirectToAction("LogOn");
}
[Authorize]
public ActionResult ChangePassword() {
ViewData["PasswordLength"] = MinPasswordLength;
return View();
}
[Authorize]
[HttpPost]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "Exceptions result in password not being changed.")]
public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword) {
ViewData["PasswordLength"] = MinPasswordLength;
if ( !ValidateChangePassword(currentPassword, newPassword, confirmPassword) ) {
return View();
}
try {
var validated = _membershipService.ValidateUser(User.Identity.Name, currentPassword);
if ( validated != null ) {
_membershipService.SetPassword(validated, newPassword);
return RedirectToAction("ChangePasswordSuccess");
}
ModelState.AddModelError("_FORM",
T("The current password is incorrect or the new password is invalid."));
return ChangePassword();
}
catch {
ModelState.AddModelError("_FORM", T("The current password is incorrect or the new password is invalid."));
return ChangePassword();
}
}
public ActionResult LostPassword(string nonce) {
if ( _userService.ValidateLostPassword(nonce) == null ) {
return RedirectToAction("LogOn");
}
ViewData["PasswordLength"] = MinPasswordLength;
return View();
}
[HttpPost]
public ActionResult LostPassword(string nonce, string newPassword, string confirmPassword) {
IUser user;
if ( (user = _userService.ValidateLostPassword(nonce)) == null ) {
return Redirect("~/");
}
ViewData["PasswordLength"] = MinPasswordLength;
if (newPassword == null || newPassword.Length < MinPasswordLength) {
ModelState.AddModelError("newPassword", T("You must specify a new password of {0} or more characters.", MinPasswordLength));
}
if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal)) {
ModelState.AddModelError("_FORM", T("The new password and confirmation password do not match."));
}
if (!ModelState.IsValid) {
return View();
}
_membershipService.SetPassword(user, newPassword);
return RedirectToAction("ChangePasswordSuccess");
}
public ActionResult ChangePasswordSuccess() {
return View();
}
public ActionResult RegistrationPending() {
return View();
}
public ActionResult ChallengeEmailSent() {
return View();
}
public ActionResult ChallengeEmailSuccess() {
return View();
}
public ActionResult ChallengeEmailFail() {
return View();
}
public ActionResult ChallengeEmail(string nonce) {
var user = _userService.ValidateChallenge(nonce);
if ( user != null ) {
_authenticationService.SignIn(user, false /* createPersistentCookie */);
return RedirectToAction("ChallengeEmailSuccess");
}
return RedirectToAction("ChallengeEmailFail");
}
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.HttpContext.User.Identity is WindowsIdentity) {
throw new InvalidOperationException(T("Windows authentication is not supported.").ToString());
}
}
#region Validation Methods
private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword) {
if ( String.IsNullOrEmpty(currentPassword) ) {
ModelState.AddModelError("currentPassword", T("You must specify a current password."));
}
if ( newPassword == null || newPassword.Length < MinPasswordLength ) {
ModelState.AddModelError("newPassword", T("You must specify a new password of {0} or more characters.", MinPasswordLength));
}
if ( !String.Equals(newPassword, confirmPassword, StringComparison.Ordinal) ) {
ModelState.AddModelError("_FORM", T("The new password and confirmation password do not match."));
}
return ModelState.IsValid;
}
private IUser ValidateLogOn(string userNameOrEmail, string password) {
bool validate = true;
if (String.IsNullOrEmpty(userNameOrEmail)) {
ModelState.AddModelError("userNameOrEmail", T("You must specify a username or e-mail."));
validate = false;
}
if (String.IsNullOrEmpty(password)) {
ModelState.AddModelError("password", T("You must specify a password."));
validate = false;
}
if (!validate)
return null;
var user = _membershipService.ValidateUser(userNameOrEmail, password);
if (user == null) {
ModelState.AddModelError("_FORM", T("The username or e-mail or password provided is incorrect."));
}
return user;
}
private bool ValidateRegistration(string userName, string email, string password, string confirmPassword) {
bool validate = true;
if (String.IsNullOrEmpty(userName)) {
ModelState.AddModelError("username", T("You must specify a username."));
validate = false;
}
if (String.IsNullOrEmpty(email)) {
ModelState.AddModelError("email", T("You must specify an email address."));
validate = false;
}
if (!validate)
return false;
if (!_userService.VerifyUserUnicity(userName, email)) {
ModelState.AddModelError("userExists", T("User with that username and/or email already exists."));
}
if (password == null || password.Length < MinPasswordLength) {
ModelState.AddModelError("password", T("You must specify a password of {0} or more characters.", MinPasswordLength));
}
if (!String.Equals(password, confirmPassword, StringComparison.Ordinal)) {
ModelState.AddModelError("_FORM", T("The new password and confirmation password do not match."));
}
return ModelState.IsValid;
}
private static string ErrorCodeToString(MembershipCreateStatus createStatus) {
// See http://msdn.microsoft.com/en-us/library/system.web.security.membershipcreatestatus.aspx for
// a full list of status codes.
switch (createStatus) {
case MembershipCreateStatus.DuplicateUserName:
return "Username already exists. Please enter a different user name.";
case MembershipCreateStatus.DuplicateEmail:
return "A username for that e-mail address already exists. Please enter a different e-mail address.";
case MembershipCreateStatus.InvalidPassword:
return "The password provided is invalid. Please enter a valid password value.";
case MembershipCreateStatus.InvalidEmail:
return "The e-mail address provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidAnswer:
return "The password retrieval answer provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidQuestion:
return "The password retrieval question provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidUserName:
return "The user name provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.ProviderError:
return
"The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
case MembershipCreateStatus.UserRejected:
return
"The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
default:
return
"An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
}
}
#endregion
}
}