10
|
1 using System;
|
|
2 using System.Collections.Generic;
|
|
3 using System.ComponentModel;
|
|
4 using System.ComponentModel.DataAnnotations;
|
|
5 using System.Globalization;
|
|
6 using System.Linq;
|
|
7 using System.Web;
|
|
8 using System.Web.Mvc;
|
|
9 using System.Web.Security;
|
|
10
|
|
11 namespace Agendas.Web.Models
|
|
12 {
|
|
13
|
|
14 #region Models
|
|
15
|
|
16 public class ChangePasswordModel
|
|
17 {
|
|
18 [Required]
|
|
19 [DataType(DataType.Password)]
|
|
20 [Display(Name = "Current password")]
|
|
21 public string OldPassword { get; set; }
|
|
22
|
|
23 [Required]
|
|
24 [ValidatePasswordLength]
|
|
25 [DataType(DataType.Password)]
|
|
26 [Display(Name = "New password")]
|
|
27 public string NewPassword { get; set; }
|
|
28
|
|
29 [DataType(DataType.Password)]
|
|
30 [Display(Name = "Confirm new password")]
|
|
31 [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
|
32 public string ConfirmPassword { get; set; }
|
|
33 }
|
|
34
|
|
35 public class LogOnModel
|
|
36 {
|
|
37 [Required]
|
|
38 [Display(Name = "User name")]
|
|
39 public string UserName { get; set; }
|
|
40
|
|
41 [Required]
|
|
42 [DataType(DataType.Password)]
|
|
43 [Display(Name = "Password")]
|
|
44 public string Password { get; set; }
|
|
45
|
|
46 [Display(Name = "Remember me?")]
|
|
47 public bool RememberMe { get; set; }
|
|
48 }
|
|
49
|
|
50
|
|
51 public class RegisterModel
|
|
52 {
|
|
53 [Required]
|
|
54 [Display(Name = "User name")]
|
|
55 public string UserName { get; set; }
|
|
56
|
|
57 [Required]
|
|
58 [DataType(DataType.EmailAddress)]
|
|
59 [Display(Name = "Email address")]
|
|
60 public string Email { get; set; }
|
|
61
|
|
62 [Required]
|
|
63 [ValidatePasswordLength]
|
|
64 [DataType(DataType.Password)]
|
|
65 [Display(Name = "Password")]
|
|
66 public string Password { get; set; }
|
|
67
|
|
68 [DataType(DataType.Password)]
|
|
69 [Display(Name = "Confirm password")]
|
|
70 [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
|
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
|
|
99 public AccountMembershipService(MembershipProvider provider)
|
|
100 {
|
|
101 _provider = provider ?? Membership.Provider;
|
|
102 }
|
|
103
|
|
104 public int MinPasswordLength
|
|
105 {
|
|
106 get
|
|
107 {
|
|
108 return _provider.MinRequiredPasswordLength;
|
|
109 }
|
|
110 }
|
|
111
|
|
112 public bool ValidateUser(string userName, string password)
|
|
113 {
|
|
114 if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
|
|
115 if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
|
|
116
|
|
117 return _provider.ValidateUser(userName, password);
|
|
118 }
|
|
119
|
|
120 public MembershipCreateStatus CreateUser(string userName, string password, string email)
|
|
121 {
|
|
122 if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
|
|
123 if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
|
|
124 if (String.IsNullOrEmpty(email)) throw new ArgumentException("Value cannot be null or empty.", "email");
|
|
125
|
|
126 MembershipCreateStatus status;
|
|
127 _provider.CreateUser(userName, password, email, null, null, true, null, out status);
|
|
128 return status;
|
|
129 }
|
|
130
|
|
131 public bool ChangePassword(string userName, string oldPassword, string newPassword)
|
|
132 {
|
|
133 if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
|
|
134 if (String.IsNullOrEmpty(oldPassword)) throw new ArgumentException("Value cannot be null or empty.", "oldPassword");
|
|
135 if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("Value cannot be null or empty.", "newPassword");
|
|
136
|
|
137 // The underlying ChangePassword() will throw an exception rather
|
|
138 // than return false in certain failure scenarios.
|
|
139 try
|
|
140 {
|
|
141 MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
|
|
142 return currentUser.ChangePassword(oldPassword, newPassword);
|
|
143 }
|
|
144 catch (ArgumentException)
|
|
145 {
|
|
146 return false;
|
|
147 }
|
|
148 catch (MembershipPasswordException)
|
|
149 {
|
|
150 return false;
|
|
151 }
|
|
152 }
|
|
153 }
|
|
154
|
|
155 public interface IFormsAuthenticationService
|
|
156 {
|
|
157 void SignIn(string userName, bool createPersistentCookie);
|
|
158 void SignOut();
|
|
159 }
|
|
160
|
|
161 public class FormsAuthenticationService : IFormsAuthenticationService
|
|
162 {
|
|
163 public void SignIn(string userName, bool createPersistentCookie)
|
|
164 {
|
|
165 if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
|
|
166
|
|
167 FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
|
|
168 }
|
|
169
|
|
170 public void SignOut()
|
|
171 {
|
|
172 FormsAuthentication.SignOut();
|
|
173 }
|
|
174 }
|
|
175 #endregion
|
|
176
|
|
177 #region Validation
|
|
178 public static class AccountValidation
|
|
179 {
|
|
180 public static string ErrorCodeToString(MembershipCreateStatus createStatus)
|
|
181 {
|
|
182 // See http://go.microsoft.com/fwlink/?LinkID=177550 for
|
|
183 // a full list of status codes.
|
|
184 switch (createStatus)
|
|
185 {
|
|
186 case MembershipCreateStatus.DuplicateUserName:
|
|
187 return "Username already exists. Please enter a different user name.";
|
|
188
|
|
189 case MembershipCreateStatus.DuplicateEmail:
|
|
190 return "A username for that e-mail address already exists. Please enter a different e-mail address.";
|
|
191
|
|
192 case MembershipCreateStatus.InvalidPassword:
|
|
193 return "The password provided is invalid. Please enter a valid password value.";
|
|
194
|
|
195 case MembershipCreateStatus.InvalidEmail:
|
|
196 return "The e-mail address provided is invalid. Please check the value and try again.";
|
|
197
|
|
198 case MembershipCreateStatus.InvalidAnswer:
|
|
199 return "The password retrieval answer provided is invalid. Please check the value and try again.";
|
|
200
|
|
201 case MembershipCreateStatus.InvalidQuestion:
|
|
202 return "The password retrieval question provided is invalid. Please check the value and try again.";
|
|
203
|
|
204 case MembershipCreateStatus.InvalidUserName:
|
|
205 return "The user name provided is invalid. Please check the value and try again.";
|
|
206
|
|
207 case MembershipCreateStatus.ProviderError:
|
|
208 return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
|
|
209
|
|
210 case MembershipCreateStatus.UserRejected:
|
|
211 return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
|
|
212
|
|
213 default:
|
|
214 return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
|
|
215 }
|
|
216 }
|
|
217 }
|
|
218
|
|
219 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
|
220 public sealed class ValidatePasswordLengthAttribute : ValidationAttribute, IClientValidatable
|
|
221 {
|
|
222 private const string _defaultErrorMessage = "'{0}' must be at least {1} characters long.";
|
|
223 private readonly int _minCharacters = Membership.Provider.MinRequiredPasswordLength;
|
|
224
|
|
225 public ValidatePasswordLengthAttribute()
|
|
226 : base(_defaultErrorMessage)
|
|
227 {
|
|
228 }
|
|
229
|
|
230 public override string FormatErrorMessage(string name)
|
|
231 {
|
|
232 return String.Format(CultureInfo.CurrentCulture, ErrorMessageString,
|
|
233 name, _minCharacters);
|
|
234 }
|
|
235
|
|
236 public override bool IsValid(object value)
|
|
237 {
|
|
238 string valueAsString = value as string;
|
|
239 return (valueAsString != null && valueAsString.Length >= _minCharacters);
|
|
240 }
|
|
241
|
|
242 public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
|
|
243 {
|
|
244 return new[]{
|
|
245 new ModelClientValidationStringLengthRule(FormatErrorMessage(metadata.GetDisplayName()), _minCharacters, int.MaxValue)
|
|
246 };
|
|
247 }
|
|
248 }
|
|
249 #endregion
|
|
250 }
|