/samples/OpenIdProviderWebForms/Code/ReadOnlyXmlMembershipProvider.cs
C# | 270 lines | 186 code | 53 blank | 31 comment | 16 complexity | eb89afd90db55def85d5d13198573596 MD5 | raw file
1namespace OpenIdProviderWebForms.Code {
2 using System;
3 using System.Collections.Generic;
4 using System.Collections.Specialized;
5 using System.Configuration.Provider;
6 using System.Security.Permissions;
7 using System.Web;
8 using System.Web.Hosting;
9 using System.Web.Security;
10 using System.Xml;
11
12 public class ReadOnlyXmlMembershipProvider : MembershipProvider {
13 private Dictionary<string, MembershipUser> users;
14 private string xmlFileName;
15
16 // MembershipProvider Properties
17 public override string ApplicationName {
18 get { throw new NotSupportedException(); }
19 set { throw new NotSupportedException(); }
20 }
21
22 public override bool EnablePasswordRetrieval {
23 get { return false; }
24 }
25
26 public override bool EnablePasswordReset {
27 get { return false; }
28 }
29
30 public override int MaxInvalidPasswordAttempts {
31 get { throw new NotSupportedException(); }
32 }
33
34 public override int MinRequiredNonAlphanumericCharacters {
35 get { throw new NotSupportedException(); }
36 }
37
38 public override int MinRequiredPasswordLength {
39 get { throw new NotSupportedException(); }
40 }
41
42 public override int PasswordAttemptWindow {
43 get { throw new NotSupportedException(); }
44 }
45
46 public override MembershipPasswordFormat PasswordFormat {
47 get { throw new NotSupportedException(); }
48 }
49
50 public override string PasswordStrengthRegularExpression {
51 get { throw new NotSupportedException(); }
52 }
53
54 public override bool RequiresQuestionAndAnswer {
55 get { throw new NotSupportedException(); }
56 }
57
58 public override bool RequiresUniqueEmail {
59 get { throw new NotSupportedException(); }
60 }
61
62 // MembershipProvider Methods
63 public override void Initialize(string name, NameValueCollection config) {
64 // Verify that config isn't null
65 if (config == null) {
66 throw new ArgumentNullException("config");
67 }
68
69 // Assign the provider a default name if it doesn't have one
70 if (string.IsNullOrEmpty(name)) {
71 name = "ReadOnlyXmlMembershipProvider";
72 }
73
74 // Add a default "description" attribute to config if the
75 // attribute doesn't exist or is empty
76 if (string.IsNullOrEmpty(config["description"])) {
77 config.Remove("description");
78 config.Add("description", "Read-only XML membership provider");
79 }
80
81 // Call the base class's Initialize method
82 base.Initialize(name, config);
83
84 // Initialize _XmlFileName and make sure the path
85 // is app-relative
86 string path = config["xmlFileName"];
87
88 if (string.IsNullOrEmpty(path)) {
89 path = "~/App_Data/Users.xml";
90 }
91
92 if (!VirtualPathUtility.IsAppRelative(path)) {
93 throw new ArgumentException("xmlFileName must be app-relative");
94 }
95
96 string fullyQualifiedPath = VirtualPathUtility.Combine(
97 VirtualPathUtility.AppendTrailingSlash(HttpRuntime.AppDomainAppVirtualPath),
98 path);
99
100 this.xmlFileName = HostingEnvironment.MapPath(fullyQualifiedPath);
101 config.Remove("xmlFileName");
102
103 // Make sure we have permission to read the XML data source and
104 // throw an exception if we don't
105 FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Read, this.xmlFileName);
106 permission.Demand();
107
108 // Throw an exception if unrecognized attributes remain
109 if (config.Count > 0) {
110 string attr = config.GetKey(0);
111 if (!string.IsNullOrEmpty(attr)) {
112 throw new ProviderException("Unrecognized attribute: " + attr);
113 }
114 }
115 }
116
117 public override bool ValidateUser(string username, string password) {
118 // Validate input parameters
119 if (string.IsNullOrEmpty(username) ||
120 string.IsNullOrEmpty(password)) {
121 return false;
122 }
123
124 try {
125 // Make sure the data source has been loaded
126 this.ReadMembershipDataStore();
127
128 // Validate the user name and password
129 MembershipUser user;
130 if (this.users.TryGetValue(username, out user)) {
131 if (user.Comment == password) { // Case-sensitive
132 // NOTE: A read/write membership provider
133 // would update the user's LastLoginDate here.
134 // A fully featured provider would also fire
135 // an AuditMembershipAuthenticationSuccess
136 // Web event
137 return true;
138 }
139 }
140
141 // NOTE: A fully featured membership provider would
142 // fire an AuditMembershipAuthenticationFailure
143 // Web event here
144 return false;
145 } catch (Exception) {
146 return false;
147 }
148 }
149
150 public override MembershipUser GetUser(string username, bool userIsOnline) {
151 // Note: This implementation ignores userIsOnline
152
153 // Validate input parameters
154 if (string.IsNullOrEmpty(username)) {
155 return null;
156 }
157
158 // Make sure the data source has been loaded
159 this.ReadMembershipDataStore();
160
161 // Retrieve the user from the data source
162 MembershipUser user;
163 if (this.users.TryGetValue(username, out user)) {
164 return user;
165 }
166
167 return null;
168 }
169
170 public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) {
171 // Note: This implementation ignores pageIndex and pageSize,
172 // and it doesn't sort the MembershipUser objects returned
173
174 // Make sure the data source has been loaded
175 this.ReadMembershipDataStore();
176
177 MembershipUserCollection users = new MembershipUserCollection();
178
179 foreach (KeyValuePair<string, MembershipUser> pair in this.users) {
180 users.Add(pair.Value);
181 }
182
183 totalRecords = users.Count;
184 return users;
185 }
186
187 public override int GetNumberOfUsersOnline() {
188 throw new NotSupportedException();
189 }
190
191 public override bool ChangePassword(string username, string oldPassword, string newPassword) {
192 throw new NotSupportedException();
193 }
194
195 public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) {
196 throw new NotSupportedException();
197 }
198
199 public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) {
200 throw new NotSupportedException();
201 }
202
203 public override bool DeleteUser(string username, bool deleteAllRelatedData) {
204 throw new NotSupportedException();
205 }
206
207 public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) {
208 throw new NotSupportedException();
209 }
210
211 public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) {
212 throw new NotSupportedException();
213 }
214
215 public override string GetPassword(string username, string answer) {
216 throw new NotSupportedException();
217 }
218
219 public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) {
220 throw new NotSupportedException();
221 }
222
223 public override string GetUserNameByEmail(string email) {
224 throw new NotSupportedException();
225 }
226
227 public override string ResetPassword(string username, string answer) {
228 throw new NotSupportedException();
229 }
230
231 public override bool UnlockUser(string userName) {
232 throw new NotSupportedException();
233 }
234
235 public override void UpdateUser(MembershipUser user) {
236 throw new NotSupportedException();
237 }
238
239 // Helper method
240 private void ReadMembershipDataStore() {
241 lock (this) {
242 if (this.users == null) {
243 this.users = new Dictionary<string, MembershipUser>(16, StringComparer.InvariantCultureIgnoreCase);
244 XmlDocument doc = new XmlDocument();
245 doc.Load(this.xmlFileName);
246 XmlNodeList nodes = doc.GetElementsByTagName("User");
247
248 foreach (XmlNode node in nodes) {
249 MembershipUser user = new MembershipUser(
250 Name, // Provider name
251 node["UserName"].InnerText, // Username
252 null, // providerUserKey
253 null, // Email
254 string.Empty, // passwordQuestion
255 node["Password"].InnerText, // Comment
256 true, // isApproved
257 false, // isLockedOut
258 DateTime.Now, // creationDate
259 DateTime.Now, // lastLoginDate
260 DateTime.Now, // lastActivityDate
261 DateTime.Now, // lastPasswordChangedDate
262 new DateTime(1980, 1, 1)); // lastLockoutDate
263
264 this.users.Add(user.UserName, user);
265 }
266 }
267 }
268 }
269 }
270}