PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/SLSTOffCampusWeb/Controllers/AccountController.cs

https://bitbucket.org/jrobertshawe/off-campus-server
C# | 407 lines | 309 code | 58 blank | 40 comment | 28 complexity | d097b9915dd7823151d9e4d3e374504e MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Transactions;
  5. using System.Web;
  6. using System.Web.Mvc;
  7. using System.Web.Security;
  8. using DotNetOpenAuth.AspNet;
  9. using Microsoft.Web.WebPages.OAuth;
  10. using WebMatrix.WebData;
  11. using SLSTOffCampusWeb.Filters;
  12. using SLSTOffCampusWeb.Models;
  13. namespace SLSTOffCampusWeb.Controllers
  14. {
  15. [Authorize]
  16. [InitializeSimpleMembership]
  17. public class AccountController : Controller
  18. {
  19. //
  20. // GET: /Account/Login
  21. [AllowAnonymous]
  22. public ActionResult Login(string returnUrl)
  23. {
  24. ViewBag.ReturnUrl = returnUrl;
  25. return View();
  26. }
  27. //
  28. // POST: /Account/Login
  29. [HttpPost]
  30. [AllowAnonymous]
  31. [ValidateAntiForgeryToken]
  32. public ActionResult Login(LoginModel model, string returnUrl)
  33. {
  34. if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
  35. {
  36. return RedirectToLocal(returnUrl);
  37. }
  38. // If we got this far, something failed, redisplay form
  39. ModelState.AddModelError("", "The user name or password provided is incorrect.");
  40. return View(model);
  41. }
  42. //
  43. // POST: /Account/LogOff
  44. [HttpPost]
  45. [ValidateAntiForgeryToken]
  46. public ActionResult LogOff()
  47. {
  48. WebSecurity.Logout();
  49. return RedirectToAction("Index", "Home");
  50. }
  51. //
  52. // GET: /Account/Register
  53. [AllowAnonymous]
  54. public ActionResult Register()
  55. {
  56. return View();
  57. }
  58. //
  59. // POST: /Account/Register
  60. [HttpPost]
  61. [AllowAnonymous]
  62. [ValidateAntiForgeryToken]
  63. public ActionResult Register(RegisterModel model)
  64. {
  65. if (ModelState.IsValid)
  66. {
  67. // Attempt to register the user
  68. try
  69. {
  70. WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
  71. WebSecurity.Login(model.UserName, model.Password);
  72. return RedirectToAction("Index", "Home");
  73. }
  74. catch (MembershipCreateUserException e)
  75. {
  76. ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
  77. }
  78. }
  79. // If we got this far, something failed, redisplay form
  80. return View(model);
  81. }
  82. //
  83. // POST: /Account/Disassociate
  84. [HttpPost]
  85. [ValidateAntiForgeryToken]
  86. public ActionResult Disassociate(string provider, string providerUserId)
  87. {
  88. string ownerAccount = OAuthWebSecurity.GetUserName(provider, providerUserId);
  89. ManageMessageId? message = null;
  90. // Only disassociate the account if the currently logged in user is the owner
  91. if (ownerAccount == User.Identity.Name)
  92. {
  93. // Use a transaction to prevent the user from deleting their last login credential
  94. using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable }))
  95. {
  96. bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
  97. if (hasLocalAccount || OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name).Count > 1)
  98. {
  99. OAuthWebSecurity.DeleteAccount(provider, providerUserId);
  100. scope.Complete();
  101. message = ManageMessageId.RemoveLoginSuccess;
  102. }
  103. }
  104. }
  105. return RedirectToAction("Manage", new { Message = message });
  106. }
  107. //
  108. // GET: /Account/Manage
  109. public ActionResult Manage(ManageMessageId? message)
  110. {
  111. ViewBag.StatusMessage =
  112. message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
  113. : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
  114. : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
  115. : "";
  116. ViewBag.HasLocalPassword = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
  117. ViewBag.ReturnUrl = Url.Action("Manage");
  118. return View();
  119. }
  120. //
  121. // POST: /Account/Manage
  122. [HttpPost]
  123. [ValidateAntiForgeryToken]
  124. public ActionResult Manage(LocalPasswordModel model)
  125. {
  126. bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
  127. ViewBag.HasLocalPassword = hasLocalAccount;
  128. ViewBag.ReturnUrl = Url.Action("Manage");
  129. if (hasLocalAccount)
  130. {
  131. if (ModelState.IsValid)
  132. {
  133. // ChangePassword will throw an exception rather than return false in certain failure scenarios.
  134. bool changePasswordSucceeded;
  135. try
  136. {
  137. changePasswordSucceeded = WebSecurity.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword);
  138. }
  139. catch (Exception)
  140. {
  141. changePasswordSucceeded = false;
  142. }
  143. if (changePasswordSucceeded)
  144. {
  145. return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
  146. }
  147. else
  148. {
  149. ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
  150. }
  151. }
  152. }
  153. else
  154. {
  155. // User does not have a local password so remove any validation errors caused by a missing
  156. // OldPassword field
  157. ModelState state = ModelState["OldPassword"];
  158. if (state != null)
  159. {
  160. state.Errors.Clear();
  161. }
  162. if (ModelState.IsValid)
  163. {
  164. try
  165. {
  166. WebSecurity.CreateAccount(User.Identity.Name, model.NewPassword);
  167. return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
  168. }
  169. catch (Exception e)
  170. {
  171. ModelState.AddModelError("", e);
  172. }
  173. }
  174. }
  175. // If we got this far, something failed, redisplay form
  176. return View(model);
  177. }
  178. //
  179. // POST: /Account/ExternalLogin
  180. [HttpPost]
  181. [AllowAnonymous]
  182. [ValidateAntiForgeryToken]
  183. public ActionResult ExternalLogin(string provider, string returnUrl)
  184. {
  185. return new ExternalLoginResult(provider, Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
  186. }
  187. //
  188. // GET: /Account/ExternalLoginCallback
  189. [AllowAnonymous]
  190. public ActionResult ExternalLoginCallback(string returnUrl)
  191. {
  192. AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
  193. if (!result.IsSuccessful)
  194. {
  195. return RedirectToAction("ExternalLoginFailure");
  196. }
  197. if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
  198. {
  199. return RedirectToLocal(returnUrl);
  200. }
  201. if (User.Identity.IsAuthenticated)
  202. {
  203. // If the current user is logged in add the new account
  204. OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
  205. return RedirectToLocal(returnUrl);
  206. }
  207. else
  208. {
  209. // User is new, ask for their desired membership name
  210. string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);
  211. ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
  212. ViewBag.ReturnUrl = returnUrl;
  213. return View("ExternalLoginConfirmation", new RegisterExternalLoginModel { UserName = result.UserName, ExternalLoginData = loginData });
  214. }
  215. }
  216. //
  217. // POST: /Account/ExternalLoginConfirmation
  218. [HttpPost]
  219. [AllowAnonymous]
  220. [ValidateAntiForgeryToken]
  221. public ActionResult ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)
  222. {
  223. string provider = null;
  224. string providerUserId = null;
  225. if (User.Identity.IsAuthenticated || !OAuthWebSecurity.TryDeserializeProviderUserId(model.ExternalLoginData, out provider, out providerUserId))
  226. {
  227. return RedirectToAction("Manage");
  228. }
  229. if (ModelState.IsValid)
  230. {
  231. // Insert a new user into the database
  232. using (UsersContext db = new UsersContext())
  233. {
  234. UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == model.UserName.ToLower());
  235. // Check if user already exists
  236. if (user == null)
  237. {
  238. // Insert name into the profile table
  239. db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
  240. db.SaveChanges();
  241. OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
  242. OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
  243. return RedirectToLocal(returnUrl);
  244. }
  245. else
  246. {
  247. ModelState.AddModelError("UserName", "User name already exists. Please enter a different user name.");
  248. }
  249. }
  250. }
  251. ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(provider).DisplayName;
  252. ViewBag.ReturnUrl = returnUrl;
  253. return View(model);
  254. }
  255. //
  256. // GET: /Account/ExternalLoginFailure
  257. [AllowAnonymous]
  258. public ActionResult ExternalLoginFailure()
  259. {
  260. return View();
  261. }
  262. [AllowAnonymous]
  263. [ChildActionOnly]
  264. public ActionResult ExternalLoginsList(string returnUrl)
  265. {
  266. ViewBag.ReturnUrl = returnUrl;
  267. return PartialView("_ExternalLoginsListPartial", OAuthWebSecurity.RegisteredClientData);
  268. }
  269. [ChildActionOnly]
  270. public ActionResult RemoveExternalLogins()
  271. {
  272. ICollection<OAuthAccount> accounts = OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name);
  273. List<ExternalLogin> externalLogins = new List<ExternalLogin>();
  274. foreach (OAuthAccount account in accounts)
  275. {
  276. AuthenticationClientData clientData = OAuthWebSecurity.GetOAuthClientData(account.Provider);
  277. externalLogins.Add(new ExternalLogin
  278. {
  279. Provider = account.Provider,
  280. ProviderDisplayName = clientData.DisplayName,
  281. ProviderUserId = account.ProviderUserId,
  282. });
  283. }
  284. ViewBag.ShowRemoveButton = externalLogins.Count > 1 || OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
  285. return PartialView("_RemoveExternalLoginsPartial", externalLogins);
  286. }
  287. #region Helpers
  288. private ActionResult RedirectToLocal(string returnUrl)
  289. {
  290. if (Url.IsLocalUrl(returnUrl))
  291. {
  292. return Redirect(returnUrl);
  293. }
  294. else
  295. {
  296. return RedirectToAction("Index", "Home");
  297. }
  298. }
  299. public enum ManageMessageId
  300. {
  301. ChangePasswordSuccess,
  302. SetPasswordSuccess,
  303. RemoveLoginSuccess,
  304. }
  305. internal class ExternalLoginResult : ActionResult
  306. {
  307. public ExternalLoginResult(string provider, string returnUrl)
  308. {
  309. Provider = provider;
  310. ReturnUrl = returnUrl;
  311. }
  312. public string Provider { get; private set; }
  313. public string ReturnUrl { get; private set; }
  314. public override void ExecuteResult(ControllerContext context)
  315. {
  316. OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);
  317. }
  318. }
  319. private static string ErrorCodeToString(MembershipCreateStatus createStatus)
  320. {
  321. // See http://go.microsoft.com/fwlink/?LinkID=177550 for
  322. // a full list of status codes.
  323. switch (createStatus)
  324. {
  325. case MembershipCreateStatus.DuplicateUserName:
  326. return "User name already exists. Please enter a different user name.";
  327. case MembershipCreateStatus.DuplicateEmail:
  328. return "A user name for that e-mail address already exists. Please enter a different e-mail address.";
  329. case MembershipCreateStatus.InvalidPassword:
  330. return "The password provided is invalid. Please enter a valid password value.";
  331. case MembershipCreateStatus.InvalidEmail:
  332. return "The e-mail address provided is invalid. Please check the value and try again.";
  333. case MembershipCreateStatus.InvalidAnswer:
  334. return "The password retrieval answer provided is invalid. Please check the value and try again.";
  335. case MembershipCreateStatus.InvalidQuestion:
  336. return "The password retrieval question provided is invalid. Please check the value and try again.";
  337. case MembershipCreateStatus.InvalidUserName:
  338. return "The user name provided is invalid. Please check the value and try again.";
  339. case MembershipCreateStatus.ProviderError:
  340. return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
  341. case MembershipCreateStatus.UserRejected:
  342. return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
  343. default:
  344. return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
  345. }
  346. }
  347. #endregion
  348. }
  349. }