summaryrefslogtreecommitdiffstats
path: root/src/OpenID/OpenIdRelyingPartyMvc/Controllers/AccountController.cs
blob: 5422a61bb04cfcefbd1ba7f4a61c71170f3ade0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
namespace RelyingPartyMvc.Controllers {
	using System;
	using System.Collections.Generic;
	using System.Diagnostics.CodeAnalysis;
	using System.Globalization;
	using System.Linq;
	using System.Security.Cryptography;
	using System.Security.Principal;
	using System.Web;
	using System.Web.Mvc;
	using System.Web.Security;
	using System.Web.UI;

	public class AccountController : Controller {
		// This constructor is used by the MVC framework to instantiate the controller using
		// the default forms authentication and membership providers.

		public AccountController()
			: this(null, null) {
		}

		// This constructor is not used by the MVC framework but is instead provided for ease
		// of unit testing this type. See the comments at the end of this file for more
		// information.
		public AccountController(IFormsAuthentication formsAuth, IMembershipService service) {
			this.FormsAuth = formsAuth ?? new FormsAuthenticationService();
			this.MembershipService = service ?? new AccountMembershipService();
		}

		public IFormsAuthentication FormsAuth { get; private set; }

		public IMembershipService MembershipService { get; private set; }

		public ActionResult LogOn() {
			return View();
		}

		[AcceptVerbs(HttpVerbs.Post)]
		[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
			Justification = "Needs to take same parameter type as Controller.Redirect()")]
		public ActionResult LogOn(string userName, bool rememberMe, string returnUrl) {
			this.FormsAuth.SignIn(userName, rememberMe);
			if (!String.IsNullOrEmpty(returnUrl)) {
				return Redirect(returnUrl);
			} else {
				return RedirectToAction("Index", "Home");
			}
		}

		public ActionResult LogOff() {
			this.FormsAuth.SignOut();

			return RedirectToAction("Index", "Home");
		}

		protected override void OnActionExecuting(ActionExecutingContext filterContext) {
			if (filterContext.HttpContext.User.Identity is WindowsIdentity) {
				throw new InvalidOperationException("Windows authentication is not supported.");
			}
		}
	}

	// The FormsAuthentication type is sealed and contains static members, so it is difficult to
	// unit test code that calls its members. The interface and helper class below demonstrate
	// how to create an abstract wrapper around such a type in order to make the AccountController
	// code unit testable.

	public interface IFormsAuthentication {
		void SignIn(string userName, bool createPersistentCookie);

		void SignOut();
	}

	public class FormsAuthenticationService : IFormsAuthentication {
		public void SignIn(string userName, bool createPersistentCookie) {
			FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
		}
		public void SignOut() {
			FormsAuthentication.SignOut();
		}
	}

	public interface IMembershipService {
		MembershipCreateStatus CreateUser(string claimedIdentifier, string email);
	}

	public class AccountMembershipService : IMembershipService {
		private MembershipProvider provider;
		private RandomNumberGenerator passwordGenerator;

		public AccountMembershipService()
			: this(null) {
		}

		public AccountMembershipService(MembershipProvider provider) {
			this.provider = provider ?? Membership.Provider;
			this.passwordGenerator = RNGCryptoServiceProvider.Create();
		}

		public MembershipCreateStatus CreateUser(string userName, string email) {
			MembershipCreateStatus status;
			string password = this.GenerateInsaneSecurePassword();
			this.provider.CreateUser(userName, password, email, null, null, true, null, out status);
			return status;
		}

		private string GenerateInsaneSecurePassword() {
			byte[] secureBits = new byte[20];
			this.passwordGenerator.GetBytes(secureBits);
			return Convert.ToBase64String(secureBits);
		}
	}
}