PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/SystemWebMembershipProxyProvider.cs

#
C# | 420 lines | 264 code | 68 blank | 88 comment | 65 complexity | 438807322937247dd7f17335489a9438 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Configuration;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Resources;
  8. using System.Text;
  9. using System.Web;
  10. using System.Web.Profile;
  11. using System.Web.Security;
  12. using System.Web.UI;
  13. using ScrewTurn.Wiki.PluginFramework;
  14. namespace Db4objects.ScrewTurnWiki.SystemMembership {
  15. public class SystemWebMembershipProxyProvider : IUsersStorageProviderV30 {
  16. static readonly ComponentInformation info;
  17. static readonly string helpHtml;
  18. static SystemWebMembershipProxyProvider() {
  19. var thisType = typeof(SystemWebMembershipProxyProvider);
  20. info = new ComponentInformation("System.Web.Membership Proxying User Provider",
  21. "Versant",
  22. thisType.Assembly.GetName().Version.ToString(),
  23. "http://www.versant.com",
  24. null);
  25. //var resources = new ResourceManager(thisType);
  26. //helpHtml = resources.GetString("HtmlHelp.htm");
  27. //thisType, "HtmlHelp.htm"
  28. using (var reader = new StreamReader(thisType.Assembly.GetManifestResourceStream("Db4objects.ScrewTurnWiki.SystemMembership.HelpHtml.htm"))) {
  29. helpHtml = reader.ReadToEnd();
  30. }
  31. }
  32. #region IProviderV30 Members
  33. /// <summary>
  34. /// Initializes the Storage Provider
  35. /// </summary>
  36. /// <param name="host"></param>
  37. /// <param name="config">configuration data, if any</param>
  38. public void Init(IHostV30 host, string config) {
  39. if (host == null) throw new ArgumentNullException("host");
  40. if (config == null) throw new ArgumentNullException("config");
  41. var membershipProvider = Membership.Provider;
  42. if (membershipProvider.RequiresQuestionAndAnswer)
  43. throw new InvalidConfigurationException(this.Information.Name + " does not support the RequiresQuestionAndAnswer option on the current Membership Provider.");
  44. // For UserInfo
  45. VerifyProfileField("DisplayName");
  46. // For User Profile
  47. VerifyProfileField("Culture");
  48. VerifyProfileField("Timezone");
  49. // For Email Notifications
  50. VerifyProfileField("PageChanges");
  51. VerifyProfileField("DiscussionMessages");
  52. VerifyProfileField("NamespacePageChanges");
  53. VerifyProfileField("NamespaceDiscussionMessages");
  54. }
  55. private void VerifyProfileField(string profileFieldName) {
  56. var profileProperties = ProfileBase.Properties;
  57. var profileProperty = profileProperties[profileFieldName];
  58. if (profileProperty == null)
  59. throw new InvalidConfigurationException(this.Information.Name + " requires a '" + profileFieldName + "' profile field defined in the current Profile Provider.");
  60. if (profileProperty.PropertyType != typeof(string))
  61. throw new InvalidConfigurationException(this.Information.Name + " requires that the '" + profileFieldName + "' profile field is configured with type=\"String\".");
  62. if (profileProperty.IsReadOnly)
  63. throw new InvalidConfigurationException(this.Information.Name + " requires that the '" + profileFieldName + "' profile field is configured with readOnly=\"true\".");
  64. //if (!(bool)profileProperty.Attributes["AllowAnonymous"])
  65. // throw new InvalidConfigurationException(this.Information.Name + " requires that the '" + profileFieldName + "' profile field is configured with allowAnonymous=\"true\".");
  66. }
  67. /// <summary>
  68. /// Gets the Information about the Provider.
  69. /// </summary>
  70. public ComponentInformation Information {
  71. get { return info; }
  72. }
  73. //cleanup/disconnect
  74. //not guaranteed to ever be called.
  75. public void Shutdown() {}
  76. /// <summary>
  77. /// Gets a brief summary of the configuration string format.
  78. /// null if no configuration is needed
  79. /// </summary>
  80. public string ConfigHelpHtml {
  81. get {
  82. return helpHtml;
  83. }
  84. }
  85. #endregion
  86. public bool UserAccountsReadOnly {
  87. get { return false; }
  88. }
  89. public bool UserGroupsReadOnly {
  90. get { return false; }
  91. }
  92. public bool UsersDataReadOnly {
  93. get { return false; }
  94. }
  95. /// <summary>
  96. /// Gets a value indicating whether group membership is read-only.
  97. /// </summary>
  98. /// <remarks>
  99. /// If UserAccountsReadOnly is false, then this property must also be false.
  100. /// If this property is true, the provider should return membership data compatible with default user groups.
  101. /// </remarks>
  102. public bool GroupMembershipReadOnly {
  103. get { return false; }
  104. }
  105. #region Users
  106. /// <summary>
  107. /// Adds a new user to the system.
  108. /// </summary>
  109. /// <param name="displayName">name to display for the user, can be null</param>
  110. /// <param name="active">is the account active</param>
  111. /// <param name="created">account creation datetime</param>
  112. /// <returns></returns>
  113. public UserInfo AddUser(string username, string displayName, string password, string email, bool active, DateTime created) {
  114. if(String.IsNullOrEmpty(username))
  115. throw new ArgumentNullException("username");
  116. if (String.IsNullOrEmpty(password))
  117. throw new ArgumentNullException("password");
  118. if(String.IsNullOrEmpty(email))
  119. throw new ArgumentNullException("email");
  120. MembershipCreateStatus createStatus;
  121. var membershipUser = Membership.CreateUser(username, password, email, null, null, active, out createStatus);
  122. switch(createStatus){
  123. case MembershipCreateStatus.DuplicateEmail:
  124. case MembershipCreateStatus.DuplicateProviderUserKey:
  125. case MembershipCreateStatus.DuplicateUserName:
  126. case MembershipCreateStatus.UserRejected:
  127. return null;
  128. }
  129. var profile = ProfileBase.Create(membershipUser.UserName);
  130. profile["DisplayName"] = displayName;
  131. profile.Save();
  132. return ToUserInfo(membershipUser);
  133. }
  134. /// <summary>
  135. /// get a user account
  136. /// </summary>
  137. /// <param name="username"></param>
  138. /// <returns>null if no matching user was found</returns>
  139. public UserInfo GetUser(string username) {
  140. if (String.IsNullOrEmpty(username)) throw new ArgumentNullException("username");
  141. var membershipUser = Membership.GetUser(username);
  142. return ToUserInfo(membershipUser);
  143. }
  144. /// <summary>
  145. /// get a user account
  146. /// </summary>
  147. /// <param name="email"></param>
  148. /// <returns>null if no matching user was found</returns>
  149. public UserInfo GetUserByEmail(string email) {
  150. if (String.IsNullOrEmpty(email)) throw new ArgumentNullException("email");
  151. var users = Membership.FindUsersByEmail(email).OfType<MembershipUser>();
  152. return ToUserInfo(users.SingleOrDefault());
  153. }
  154. /// <summary>
  155. ///
  156. /// </summary>
  157. /// <returns>All users, sorted by username</returns>
  158. public UserInfo[] GetUsers() {
  159. return new UserInfo[] { };
  160. //HACK: Don't return all users
  161. //var users = Membership.GetAllUsers().OfType<MembershipUser>().OrderBy(u=>u.UserName);
  162. //return (from u in users select ToUserInfo(u)).ToArray();
  163. }
  164. /// <summary>
  165. /// Gets all the users that have the specified element in their data.
  166. /// </summary>
  167. /// <param name="key">key of the data</param>
  168. /// <returns>the users and the data</returns>
  169. public IDictionary<UserInfo, string> GetUsersWithData(string key) {
  170. if (String.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
  171. //HACK: don't return any users.
  172. return new Dictionary<UserInfo, string>();
  173. }
  174. /// <summary>
  175. ///
  176. /// </summary>
  177. /// <param name="user">user to modify</param>
  178. /// <param name="newDisplayName">new display name (can be null)</param>
  179. /// <param name="newPassword">new password (null or empty to keep current password)</param>
  180. /// <param name="newEmail"></param>
  181. /// <param name="newActive"></param>
  182. /// <returns>The Modified UserInfo instance</returns>
  183. public UserInfo ModifyUser(UserInfo user, string newDisplayName, string newPassword, string newEmail, bool newActive) {
  184. if (user == null) throw new ArgumentNullException("user");
  185. var membershipUser = Membership.GetUser(user.Username, false);
  186. if (membershipUser == null)
  187. throw new ArgumentException("Could not locate user '" + user.Username + "' in Membership Provider.", "user");
  188. membershipUser.ChangePassword(membershipUser.GetPassword(), newPassword);
  189. membershipUser.Email = newEmail;
  190. membershipUser.IsApproved = newActive;
  191. Membership.UpdateUser(membershipUser);
  192. var profile = GetProfile(membershipUser);
  193. profile["DisplayName"] = newDisplayName;
  194. profile.Save();
  195. return ToUserInfo(membershipUser);
  196. }
  197. /// <returns>true if the user was removed successfuly</returns>
  198. public bool RemoveUser(UserInfo user) {
  199. if (user == null) throw new ArgumentNullException("user");
  200. return Membership.DeleteUser(user.Username);
  201. }
  202. #endregion
  203. #region Login/out
  204. /// <summary>
  205. /// Notifies the provider that a user has logged in through the authentication cookie.
  206. /// </summary>
  207. /// <param name="user"></param>
  208. public void NotifyCookieLogin(UserInfo user) {
  209. if (user == null) throw new ArgumentNullException("user");
  210. Membership.GetUser(true);
  211. }
  212. public void NotifyLogout(UserInfo user) {
  213. if (user == null) throw new ArgumentNullException("user");
  214. if(HttpContext.Current == null) return;
  215. switch (HttpContext.Current.User.Identity.AuthenticationType) {
  216. case "Forms":
  217. FormsAuthentication.SignOut();
  218. break;
  219. }
  220. }
  221. public bool TestAccount(UserInfo user, string password) {
  222. if (user == null) throw new ArgumentNullException("user");
  223. return Membership.ValidateUser(user.Username, password);
  224. }
  225. public UserInfo TryAutoLogin(System.Web.HttpContext context) {
  226. if (context == null) throw new ArgumentNullException("context");
  227. if (HttpContext.Current != null &&
  228. HttpContext.Current.User.Identity.IsAuthenticated)
  229. return ToUserInfo(Membership.GetUser(true));
  230. return null;
  231. }
  232. public UserInfo TryManualLogin(string username, string password) {
  233. if (String.IsNullOrEmpty(username)) throw new ArgumentNullException("username");
  234. //if (String.IsNullOrEmpty(password)) throw new ArgumentNullException("password");
  235. if (Membership.ValidateUser(username, password))
  236. return GetUser(username);
  237. return null;
  238. }
  239. #endregion
  240. #region UserGroups/Roles
  241. /// <summary>
  242. /// Adds a user group (role)
  243. /// </summary>
  244. /// <param name="description">ignored by the System Role Providers</param>
  245. public UserGroup AddUserGroup(string name, string description) {
  246. if (String.IsNullOrEmpty(name))
  247. throw new ArgumentNullException("name");
  248. //if (description == null)
  249. // throw new ArgumentNullException("description");
  250. Roles.CreateRole(name);
  251. return new MembershipUserGroup(name, String.Empty, this, name);
  252. }
  253. /// <summary>
  254. ///
  255. /// </summary>
  256. /// <returns>All user groups (Roles), sorted by name</returns>
  257. public UserGroup[] GetUserGroups() {
  258. var roles = Roles.GetAllRoles();
  259. Array.Sort<string>(roles);
  260. return (from roleName in roles
  261. orderby roleName
  262. select new MembershipUserGroup(roleName, String.Empty, this, roleName)
  263. {Users=GetUsersForGroup(roleName) }
  264. ).ToArray();
  265. }
  266. private string[] GetUsersForGroup(string roleName) {
  267. if (String.IsNullOrEmpty(roleName)) throw new ArgumentNullException("roleName");
  268. return new string[] { };
  269. //HACK: Don't return all users
  270. //return Roles.GetUsersInRole(roleName);
  271. }
  272. public UserGroup ModifyUserGroup(UserGroup group, string description) {
  273. if (group == null) throw new ArgumentNullException("group");
  274. //if (description == null) throw new ArgumentNullException("description");
  275. // System Role Provider does not support role descriptions
  276. return group;
  277. }
  278. public bool RemoveUserGroup(UserGroup group) {
  279. if (group == null) throw new ArgumentNullException("group");
  280. return Roles.DeleteRole(group.Name);
  281. }
  282. public UserInfo SetUserMembership(UserInfo user, string[] groups) {
  283. if (user == null) throw new ArgumentNullException("user");
  284. var currentRoles = Roles.GetRolesForUser(user.Username);
  285. Roles.RemoveUserFromRoles(user.Username,
  286. (from r in currentRoles
  287. where !groups.Contains(r)
  288. select r).ToArray());
  289. Roles.AddUserToRoles(user.Username, groups);
  290. var ret = GetUser(user.Username);
  291. ret.Groups = Roles.GetRolesForUser(user.Username);
  292. return ret;
  293. }
  294. #endregion
  295. #region User Data
  296. public IDictionary<string, string> RetrieveAllUserData(UserInfo user) {
  297. if (user == null) throw new ArgumentNullException("user");
  298. var ret = new Dictionary<string, string>();
  299. var profile = GetProfile(user.Username);
  300. foreach(var p in ProfileBase.Properties.OfType<SettingsProperty>()) {
  301. if (p.PropertyType == typeof(string))
  302. ret.Add(p.Name, (string)profile[p.Name]);
  303. else if (profile[p.Name] != null)
  304. ret.Add(p.Name, profile[p.Name].ToString());
  305. else
  306. ret.Add(p.Name, null);
  307. return ret;
  308. }
  309. return ret;
  310. }
  311. public string RetrieveUserData(UserInfo user, string key) {
  312. if (user == null) throw new ArgumentNullException("user");
  313. if (String.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
  314. key = key.ToLowerInvariant();
  315. var profile = GetProfile(user.Username);
  316. return profile[key] as string;
  317. }
  318. public bool StoreUserData(UserInfo user, string key, string value) {
  319. if (user == null) throw new ArgumentNullException("user");
  320. if (String.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
  321. try {
  322. var profile = GetProfile(user.Username);
  323. profile[key] = value;
  324. profile.Save();
  325. }
  326. catch {
  327. return false;
  328. }
  329. return true;
  330. }
  331. #endregion
  332. #region Internal Utilities
  333. private MembershipUserInfo ToUserInfo(MembershipUser membershipUser){
  334. if (membershipUser == null) return null;
  335. var profile = GetProfile(membershipUser);
  336. if (profile["DisplayName"] == null)
  337. profile["DisplayName"] = membershipUser.UserName;
  338. profile.Save();
  339. return new MembershipUserInfo(membershipUser.UserName, (string)profile["DisplayName"], membershipUser.Email, membershipUser.IsApproved, membershipUser.CreationDate, this, membershipUser.ProviderUserKey) {
  340. Groups = Roles.GetRolesForUser(membershipUser.UserName)};
  341. }
  342. private static ProfileBase GetProfile(string username) {
  343. if (String.IsNullOrEmpty(username)) throw new ArgumentNullException("username");
  344. return ProfileBase.Create(username);
  345. }
  346. private static ProfileBase GetProfile(MembershipUser user) {
  347. if (user == null) throw new ArgumentNullException("user");
  348. return GetProfile(user.UserName);
  349. }
  350. #endregion
  351. }
  352. }