PageRenderTime 21ms CodeModel.GetById 11ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/src/MM.Web/Models/AccountModels.cs

#
C# | 261 lines | 204 code | 49 blank | 8 comment | 12 complexity | 70ed468bd6694622f4429098afe64991 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.ComponentModel;
  4using System.ComponentModel.DataAnnotations;
  5using System.Globalization;
  6using System.Linq;
  7using System.Web;
  8using System.Web.Mvc;
  9using System.Web.Security;
 10
 11namespace MM.Web.Models
 12{
 13
 14    #region Models
 15    [PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "The new password and confirmation password do not match.")]
 16    public class ChangePasswordModel
 17    {
 18        [Required]
 19        [DataType(DataType.Password)]
 20        [DisplayName("Current password")]
 21        public string OldPassword { get; set; }
 22
 23        [Required]
 24        [ValidatePasswordLength]
 25        [DataType(DataType.Password)]
 26        [DisplayName("New password")]
 27        public string NewPassword { get; set; }
 28
 29        [Required]
 30        [DataType(DataType.Password)]
 31        [DisplayName("Confirm new password")]
 32        public string ConfirmPassword { get; set; }
 33    }
 34
 35    public class LogOnModel
 36    {
 37        [Required]
 38        [DisplayName("User name")]
 39        public string UserName { get; set; }
 40
 41        [Required]
 42        [DataType(DataType.Password)]
 43        [DisplayName("Password")]
 44        public string Password { get; set; }
 45
 46        [DisplayName("Remember me?")]
 47        public bool RememberMe { get; set; }
 48    }
 49
 50    [PropertiesMustMatch("Password", "ConfirmPassword", ErrorMessage = "The password and confirmation password do not match.")]
 51    public class RegisterModel
 52    {
 53        [Required]
 54        [DisplayName("User name")]
 55        public string UserName { get; set; }
 56
 57        [Required]
 58        [DataType(DataType.EmailAddress)]
 59        [DisplayName("Email address")]
 60        public string Email { get; set; }
 61
 62        [Required]
 63        [ValidatePasswordLength]
 64        [DataType(DataType.Password)]
 65        [DisplayName("Password")]
 66        public string Password { get; set; }
 67
 68        [Required]
 69        [DataType(DataType.Password)]
 70        [DisplayName("Confirm password")]
 71        public string ConfirmPassword { get; set; }
 72    }
 73    #endregion
 74
 75    #region Services
 76    // The FormsAuthentication type is sealed and contains static members, so it is difficult to
 77    // unit test code that calls its members. The interface and helper class below demonstrate
 78    // how to create an abstract wrapper around such a type in order to make the AccountController
 79    // code unit testable.
 80
 81    public interface IMembershipService
 82    {
 83        int MinPasswordLength { get; }
 84
 85        bool ValidateUser(string userName, string password);
 86        MembershipCreateStatus CreateUser(string userName, string password, string email);
 87        bool ChangePassword(string userName, string oldPassword, string newPassword);
 88    }
 89
 90    public class AccountMembershipService : IMembershipService
 91    {
 92        private readonly MembershipProvider _provider;
 93
 94        public AccountMembershipService()
 95            : this(null) {
 96        }
 97
 98        public AccountMembershipService(MembershipProvider provider) {
 99            _provider = provider ?? Membership.Provider;
100        }
101
102        public int MinPasswordLength {
103            get {
104                return _provider.MinRequiredPasswordLength;
105            }
106        }
107
108        public bool ValidateUser(string userName, string password) {
109            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
110            if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
111
112            return _provider.ValidateUser(userName, password);
113        }
114
115        public MembershipCreateStatus CreateUser(string userName, string password, string email) {
116            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
117            if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
118            if (String.IsNullOrEmpty(email)) throw new ArgumentException("Value cannot be null or empty.", "email");
119
120            MembershipCreateStatus status;
121            _provider.CreateUser(userName, password, email, null, null, true, null, out status);
122            return status;
123        }
124
125        public bool ChangePassword(string userName, string oldPassword, string newPassword) {
126            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
127            if (String.IsNullOrEmpty(oldPassword)) throw new ArgumentException("Value cannot be null or empty.", "oldPassword");
128            if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("Value cannot be null or empty.", "newPassword");
129
130            // The underlying ChangePassword() will throw an exception rather
131            // than return false in certain failure scenarios.
132            try {
133                MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
134                return currentUser.ChangePassword(oldPassword, newPassword);
135            }
136            catch (ArgumentException) {
137                return false;
138            }
139            catch (MembershipPasswordException) {
140                return false;
141            }
142        }
143    }
144
145    public interface IFormsAuthenticationService
146    {
147        void SignIn(string userName, bool createPersistentCookie);
148        void SignOut();
149    }
150
151    public class FormsAuthenticationService : IFormsAuthenticationService
152    {
153        public void SignIn(string userName, bool createPersistentCookie) {
154            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
155
156            FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
157        }
158
159        public void SignOut() {
160            FormsAuthentication.SignOut();
161        }
162    }
163    #endregion
164
165    #region Validation
166    public static class AccountValidation
167    {
168        public static string ErrorCodeToString(MembershipCreateStatus createStatus) {
169            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
170            // a full list of status codes.
171            switch (createStatus) {
172                case MembershipCreateStatus.DuplicateUserName:
173                    return "Username already exists. Please enter a different user name.";
174
175                case MembershipCreateStatus.DuplicateEmail:
176                    return "A username for that e-mail address already exists. Please enter a different e-mail address.";
177
178                case MembershipCreateStatus.InvalidPassword:
179                    return "The password provided is invalid. Please enter a valid password value.";
180
181                case MembershipCreateStatus.InvalidEmail:
182                    return "The e-mail address provided is invalid. Please check the value and try again.";
183
184                case MembershipCreateStatus.InvalidAnswer:
185                    return "The password retrieval answer provided is invalid. Please check the value and try again.";
186
187                case MembershipCreateStatus.InvalidQuestion:
188                    return "The password retrieval question provided is invalid. Please check the value and try again.";
189
190                case MembershipCreateStatus.InvalidUserName:
191                    return "The user name provided is invalid. Please check the value and try again.";
192
193                case MembershipCreateStatus.ProviderError:
194                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
195
196                case MembershipCreateStatus.UserRejected:
197                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
198
199                default:
200                    return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
201            }
202        }
203    }
204
205    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
206    public sealed class PropertiesMustMatchAttribute : ValidationAttribute
207    {
208        private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
209        private readonly object _typeId = new object();
210
211        public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
212            : base(_defaultErrorMessage) {
213            OriginalProperty = originalProperty;
214            ConfirmProperty = confirmProperty;
215        }
216
217        public string ConfirmProperty { get; private set; }
218        public string OriginalProperty { get; private set; }
219
220        public override object TypeId {
221            get {
222                return _typeId;
223            }
224        }
225
226        public override string FormatErrorMessage(string name) {
227            return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
228                OriginalProperty, ConfirmProperty);
229        }
230
231        public override bool IsValid(object value) {
232            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
233            object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
234            object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
235            return Object.Equals(originalValue, confirmValue);
236        }
237    }
238
239    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
240    public sealed class ValidatePasswordLengthAttribute : ValidationAttribute
241    {
242        private const string _defaultErrorMessage = "'{0}' must be at least {1} characters long.";
243        private readonly int _minCharacters = Membership.Provider.MinRequiredPasswordLength;
244
245        public ValidatePasswordLengthAttribute()
246            : base(_defaultErrorMessage) {
247        }
248
249        public override string FormatErrorMessage(string name) {
250            return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
251                name, _minCharacters);
252        }
253
254        public override bool IsValid(object value) {
255            string valueAsString = value as string;
256            return (valueAsString != null && valueAsString.Length >= _minCharacters);
257        }
258    }
259    #endregion
260
261}