diff options
12 files changed, 217 insertions, 191 deletions
diff --git a/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs b/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs index 2fd3ea1..a322f7d 100644 --- a/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs +++ b/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs @@ -20,150 +20,6 @@ [HandleError] public class AccountController : Controller { - /// <summary> - /// Initializes a new instance of the <see cref="AccountController"/> class. - /// </summary> - /// <remarks> - /// This constructor is used by the MVC framework to instantiate the controller using - /// the default forms authentication and OpenID services. - /// </remarks> - public AccountController() - : this(null, null) { - } - - /// <summary> - /// Initializes a new instance of the <see cref="AccountController"/> class. - /// </summary> - /// <param name="formsAuth">The forms auth.</param> - /// <param name="relyingParty">The relying party.</param> - /// <remarks> - /// This constructor is not used by the MVC framework but is instead provided for ease - /// of unit testing this type. - /// </remarks> - public AccountController(IFormsAuthentication formsAuth, IOpenIdRelyingParty relyingParty) { - this.FormsAuth = formsAuth ?? new FormsAuthenticationService(); - this.RelyingParty = relyingParty ?? new OpenIdRelyingPartyService(); - } - - /// <summary> - /// Gets the forms authentication module to use. - /// </summary> - public IFormsAuthentication FormsAuth { get; private set; } - - /// <summary> - /// Gets the OpenID relying party to use for logging users in. - /// </summary> - public IOpenIdRelyingParty RelyingParty { get; private set; } - - private Uri PrivacyPolicyUrl { - get { - return Url.ActionFull("PrivacyPolicy", "Home"); - } - } - - /// <summary> - /// Prepares a web page to help the user supply his login information. - /// </summary> - /// <returns>The action result.</returns> - public ActionResult LogOn() { - return View(); - } - - /// <summary> - /// Prepares a web page to help the user supply his login information. - /// </summary> - /// <returns>The action result.</returns> - public ActionResult LogOnPopUp() { - return View(); - } - - /// <summary> - /// Handles the positive assertion that comes from Providers to Javascript running in the browser. - /// </summary> - /// <returns>The action result.</returns> - /// <remarks> - /// This method instructs ASP.NET MVC to <i>not</i> validate input - /// because some OpenID positive assertions messages otherwise look like - /// hack attempts and result in errors when validation is turned on. - /// </remarks> - [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post), ValidateInput(false)] - public ActionResult PopUpReturnTo() { - return this.RelyingParty.ProcessAjaxOpenIdResponse(); - } - - /// <summary> - /// Handles the positive assertion that comes from Providers. - /// </summary> - /// <param name="openid_openidAuthData">The positive assertion obtained via AJAX.</param> - /// <returns>The action result.</returns> - /// <remarks> - /// This method instructs ASP.NET MVC to <i>not</i> validate input - /// because some OpenID positive assertions messages otherwise look like - /// hack attempts and result in errors when validation is turned on. - /// </remarks> - [AcceptVerbs(HttpVerbs.Post), ValidateInput(false)] - public ActionResult LogOnPostAssertion(string openid_openidAuthData) { - IAuthenticationResponse response; - if (!string.IsNullOrEmpty(openid_openidAuthData)) { - var auth = new Uri(openid_openidAuthData); - var headers = new WebHeaderCollection(); - foreach (string header in Request.Headers) { - headers[header] = Request.Headers[header]; - } - - // Always say it's a GET since the payload is all in the URL, even the large ones. - HttpRequestInfo clientResponseInfo = new HttpRequestInfo("GET", auth, auth.PathAndQuery, headers, null); - response = this.RelyingParty.GetResponse(clientResponseInfo); - } else { - response = this.RelyingParty.GetResponse(); - } - if (response != null) { - switch (response.Status) { - case AuthenticationStatus.Authenticated: - var token = RelyingPartyLogic.User.ProcessUserLogin(response); - this.FormsAuth.SignIn(token.ClaimedIdentifier, false); - string returnUrl = Request.Form["returnUrl"]; - if (!String.IsNullOrEmpty(returnUrl)) { - return Redirect(returnUrl); - } else { - return RedirectToAction("Index", "Home"); - } - case AuthenticationStatus.Canceled: - ModelState.AddModelError("OpenID", "It looks like you canceled login at your OpenID Provider."); - break; - case AuthenticationStatus.Failed: - ModelState.AddModelError("OpenID", response.Exception.Message); - break; - } - } - - // If we're to this point, login didn't complete successfully. - // Show the LogOn view again to show the user any errors and - // give another chance to complete login. - return View("LogOn"); - } - - /// <summary> - /// Logs the user out of the site and redirects the browser to our home page. - /// </summary> - /// <returns>The action result.</returns> - public ActionResult LogOff() { - this.FormsAuth.SignOut(); - return RedirectToAction("Index", "Home"); - } - - public ActionResult Discover(string identifier) { - if (!this.Request.IsAjaxRequest()) { - throw new InvalidOperationException(); - } - - return this.RelyingParty.AjaxDiscovery( - identifier, - Realm.AutoDetect, - Url.ActionFull("PopUpReturnTo"), - this.PrivacyPolicyUrl); - } - [Authorize] public ActionResult Edit() { return View(GetAccountInfoModel()); @@ -255,43 +111,6 @@ return PartialView("AuthorizedApps", GetAccountInfoModel()); } - [Authorize, AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)] - public ActionResult AddAuthenticationTokenReturnTo(string openid_identifier) { - var response = this.RelyingParty.GetResponse(); - if (response != null) { - switch (response.Status) { - case AuthenticationStatus.Authenticated: - Database.LoggedInUser.AuthenticationTokens.Add(new AuthenticationToken { - ClaimedIdentifier = response.ClaimedIdentifier, - FriendlyIdentifier = response.FriendlyIdentifierForDisplay, - }); - Database.DataContext.SaveChanges(); - break; - default: - break; - } - } - - return RedirectToAction("Edit"); - } - - [Authorize, AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken] - public ActionResult AddAuthenticationToken(string openid_identifier) { - Identifier userSuppliedIdentifier; - if (Identifier.TryParse(openid_identifier, out userSuppliedIdentifier)) { - try { - var request = this.RelyingParty.CreateRequest(userSuppliedIdentifier, Realm.AutoDetect, Url.ActionFull("AddAuthenticationTokenReturnTo"), this.PrivacyPolicyUrl); - return request.RedirectingResponse.AsActionResult(); - } catch (ProtocolException ex) { - ModelState.AddModelError("openid_identifier", ex); - } - } else { - ModelState.AddModelError("openid_identifier", "This doesn't look like a valid OpenID."); - } - - return View("Edit", GetAccountInfoModel()); - } - private static AccountInfoModel GetAccountInfoModel() { var authorizedApps = from token in Database.DataContext.IssuedTokens.OfType<IssuedAccessToken>() where token.User.UserId == Database.LoggedInUser.UserId diff --git a/projecttemplates/MvcRelyingParty/Controllers/AuthController.cs b/projecttemplates/MvcRelyingParty/Controllers/AuthController.cs new file mode 100644 index 0000000..84eedc3 --- /dev/null +++ b/projecttemplates/MvcRelyingParty/Controllers/AuthController.cs @@ -0,0 +1,206 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthController.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace MvcRelyingParty.Controllers { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using System.Web.Mvc; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.RelyingParty; + using System.Net; + using DotNetOpenAuth.Messaging; + using RelyingPartyLogic; + + public class AuthController : Controller { + /// <summary> + /// Initializes a new instance of the <see cref="AuthController"/> class. + /// </summary> + /// <remarks> + /// This constructor is used by the MVC framework to instantiate the controller using + /// the default forms authentication and OpenID services. + /// </remarks> + public AuthController() + : this(null, null) { + } + + /// <summary> + /// Initializes a new instance of the <see cref="AuthController"/> class. + /// </summary> + /// <param name="formsAuth">The forms auth.</param> + /// <param name="relyingParty">The relying party.</param> + /// <remarks> + /// This constructor is not used by the MVC framework but is instead provided for ease + /// of unit testing this type. + /// </remarks> + public AuthController(IFormsAuthentication formsAuth, IOpenIdRelyingParty relyingParty) { + this.FormsAuth = formsAuth ?? new FormsAuthenticationService(); + this.RelyingParty = relyingParty ?? new OpenIdRelyingPartyService(); + } + + /// <summary> + /// Gets the forms authentication module to use. + /// </summary> + public IFormsAuthentication FormsAuth { get; private set; } + + /// <summary> + /// Gets the OpenID relying party to use for logging users in. + /// </summary> + public IOpenIdRelyingParty RelyingParty { get; private set; } + + private Uri PrivacyPolicyUrl { + get { + return Url.ActionFull("PrivacyPolicy", "Home"); + } + } + + /// <summary> + /// Performs discovery on a given identifier. + /// </summary> + /// <param name="identifier">The identifier on which to perform discovery.</param> + /// <returns>The JSON result of discovery.</returns> + public ActionResult Discover(string identifier) { + if (!this.Request.IsAjaxRequest()) { + throw new InvalidOperationException(); + } + + return this.RelyingParty.AjaxDiscovery( + identifier, + Realm.AutoDetect, + Url.ActionFull("PopUpReturnTo"), + this.PrivacyPolicyUrl); + } + + /// <summary> + /// Prepares a web page to help the user supply his login information. + /// </summary> + /// <returns>The action result.</returns> + public ActionResult LogOn() { + return View(); + } + + /// <summary> + /// Prepares a web page to help the user supply his login information. + /// </summary> + /// <returns>The action result.</returns> + public ActionResult LogOnPopUp() { + return View(); + } + + /// <summary> + /// Handles the positive assertion that comes from Providers to Javascript running in the browser. + /// </summary> + /// <returns>The action result.</returns> + /// <remarks> + /// This method instructs ASP.NET MVC to <i>not</i> validate input + /// because some OpenID positive assertions messages otherwise look like + /// hack attempts and result in errors when validation is turned on. + /// </remarks> + [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post), ValidateInput(false)] + public ActionResult PopUpReturnTo() { + return this.RelyingParty.ProcessAjaxOpenIdResponse(); + } + + /// <summary> + /// Handles the positive assertion that comes from Providers. + /// </summary> + /// <param name="openid_openidAuthData">The positive assertion obtained via AJAX.</param> + /// <returns>The action result.</returns> + /// <remarks> + /// This method instructs ASP.NET MVC to <i>not</i> validate input + /// because some OpenID positive assertions messages otherwise look like + /// hack attempts and result in errors when validation is turned on. + /// </remarks> + [AcceptVerbs(HttpVerbs.Post), ValidateInput(false)] + public ActionResult LogOnPostAssertion(string openid_openidAuthData) { + IAuthenticationResponse response; + if (!string.IsNullOrEmpty(openid_openidAuthData)) { + var auth = new Uri(openid_openidAuthData); + var headers = new WebHeaderCollection(); + foreach (string header in Request.Headers) { + headers[header] = Request.Headers[header]; + } + + // Always say it's a GET since the payload is all in the URL, even the large ones. + HttpRequestInfo clientResponseInfo = new HttpRequestInfo("GET", auth, auth.PathAndQuery, headers, null); + response = this.RelyingParty.GetResponse(clientResponseInfo); + } else { + response = this.RelyingParty.GetResponse(); + } + if (response != null) { + switch (response.Status) { + case AuthenticationStatus.Authenticated: + var token = RelyingPartyLogic.User.ProcessUserLogin(response); + this.FormsAuth.SignIn(token.ClaimedIdentifier, false); + string returnUrl = Request.Form["returnUrl"]; + if (!String.IsNullOrEmpty(returnUrl)) { + return Redirect(returnUrl); + } else { + return RedirectToAction("Index", "Home"); + } + case AuthenticationStatus.Canceled: + ModelState.AddModelError("OpenID", "It looks like you canceled login at your OpenID Provider."); + break; + case AuthenticationStatus.Failed: + ModelState.AddModelError("OpenID", response.Exception.Message); + break; + } + } + + // If we're to this point, login didn't complete successfully. + // Show the LogOn view again to show the user any errors and + // give another chance to complete login. + return View("LogOn"); + } + + [Authorize, AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken] + public ActionResult AddAuthenticationToken(string openid_identifier) { + Identifier userSuppliedIdentifier; + if (Identifier.TryParse(openid_identifier, out userSuppliedIdentifier)) { + try { + var request = this.RelyingParty.CreateRequest(userSuppliedIdentifier, Realm.AutoDetect, Url.ActionFull("AddAuthenticationTokenReturnTo"), this.PrivacyPolicyUrl); + return request.RedirectingResponse.AsActionResult(); + } catch (ProtocolException ex) { + ModelState.AddModelError("openid_identifier", ex); + } + } else { + ModelState.AddModelError("openid_identifier", "This doesn't look like a valid OpenID."); + } + + return RedirectToAction("Edit", "Account"); + } + + [Authorize, AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)] + public ActionResult AddAuthenticationTokenReturnTo(string openid_identifier) { + var response = this.RelyingParty.GetResponse(); + if (response != null) { + switch (response.Status) { + case AuthenticationStatus.Authenticated: + Database.LoggedInUser.AuthenticationTokens.Add(new AuthenticationToken { + ClaimedIdentifier = response.ClaimedIdentifier, + FriendlyIdentifier = response.FriendlyIdentifierForDisplay, + }); + Database.DataContext.SaveChanges(); + break; + default: + break; + } + } + + return RedirectToAction("Edit", "Account"); + } + + /// <summary> + /// Logs the user out of the site and redirects the browser to our home page. + /// </summary> + /// <returns>The action result.</returns> + public ActionResult LogOff() { + this.FormsAuth.SignOut(); + return RedirectToAction("Index", "Home"); + } + } +} diff --git a/projecttemplates/MvcRelyingParty/Global.asax.cs b/projecttemplates/MvcRelyingParty/Global.asax.cs index 34f7a81..44c66b5 100644 --- a/projecttemplates/MvcRelyingParty/Global.asax.cs +++ b/projecttemplates/MvcRelyingParty/Global.asax.cs @@ -28,7 +28,7 @@ new { controller = "Home", action = "Index", id = string.Empty }); routes.MapRoute( "OpenIdDiscover", - "Account/Discover"); + "Auth/Discover"); } protected void Application_Start() { diff --git a/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj index 02fd93a..54e62bf 100644 --- a/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj +++ b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj @@ -72,6 +72,7 @@ <Compile Include="Code\FormsAuthenticationService.cs" /> <Compile Include="Code\OpenIdRelyingPartyService.cs" /> <Compile Include="Controllers\AccountController.cs" /> + <Compile Include="Controllers\AuthController.cs" /> <Compile Include="Controllers\HomeController.cs" /> <Compile Include="Default.aspx.cs"> <DependentUpon>Default.aspx</DependentUpon> @@ -137,9 +138,9 @@ <Content Include="Scripts\jquery.cookie.js" /> <Content Include="Scripts\LoginLink.js" /> <Content Include="Setup.aspx" /> - <Content Include="Views\Account\LogOnScripts.ascx" /> - <Content Include="Views\Account\LogOn.aspx" /> - <Content Include="Views\Account\LogOnContent.ascx" /> + <Content Include="Views\Auth\LogOnScripts.ascx" /> + <Content Include="Views\Auth\LogOn.aspx" /> + <Content Include="Views\Auth\LogOnContent.ascx" /> <Content Include="Views\Account\EditFields.ascx" /> <Content Include="Views\Account\Edit.aspx" /> <Content Include="Views\Home\PrivacyPolicy.aspx" /> @@ -153,7 +154,7 @@ <Content Include="Scripts\MicrosoftAjax.debug.js" /> <Content Include="Scripts\MicrosoftMvcAjax.js" /> <Content Include="Scripts\MicrosoftMvcAjax.debug.js" /> - <Content Include="Views\Account\LogOnPopup.aspx" /> + <Content Include="Views\Auth\LogOnPopup.aspx" /> <Content Include="Views\Home\About.aspx" /> <Content Include="Views\Home\Index.aspx" /> <Content Include="Views\Shared\Error.aspx" /> diff --git a/projecttemplates/MvcRelyingParty/Scripts/LoginLink.js b/projecttemplates/MvcRelyingParty/Scripts/LoginLink.js index 68124b0..1f22a50 100644 --- a/projecttemplates/MvcRelyingParty/Scripts/LoginLink.js +++ b/projecttemplates/MvcRelyingParty/Scripts/LoginLink.js @@ -1,5 +1,5 @@ $(function() { - var loginContent = '/Account/LogOnPopup'; + var loginContent = '/Auth/LogOnPopup'; var popupWindowName = 'openidlogin'; var popupWidth = 355; var popupHeight = 205; // use 205 for 1 row of OP buttons, or 273 for 2 rows diff --git a/projecttemplates/MvcRelyingParty/Views/Account/AuthenticationTokens.ascx b/projecttemplates/MvcRelyingParty/Views/Account/AuthenticationTokens.ascx index 9632988..3e4b920 100644 --- a/projecttemplates/MvcRelyingParty/Views/Account/AuthenticationTokens.ascx +++ b/projecttemplates/MvcRelyingParty/Views/Account/AuthenticationTokens.ascx @@ -11,7 +11,7 @@ </ul> <h4>Add a new login method </h4> -<% using(Html.BeginForm("AddAuthenticationToken", "Account", FormMethod.Post)) { %> +<% using(Html.BeginForm("AddAuthenticationToken", "Auth", FormMethod.Post)) { %> <%= Html.AntiForgeryToken() %> <label for="openid_identifier">OpenID:</label> <%= Html.TextBox("openid_identifier")%> diff --git a/projecttemplates/MvcRelyingParty/Views/Account/LogOn.aspx b/projecttemplates/MvcRelyingParty/Views/Auth/LogOn.aspx index 4709507..4709507 100644 --- a/projecttemplates/MvcRelyingParty/Views/Account/LogOn.aspx +++ b/projecttemplates/MvcRelyingParty/Views/Auth/LogOn.aspx diff --git a/projecttemplates/MvcRelyingParty/Views/Account/LogOnContent.ascx b/projecttemplates/MvcRelyingParty/Views/Auth/LogOnContent.ascx index 145a4f0..eb8dc16 100644 --- a/projecttemplates/MvcRelyingParty/Views/Account/LogOnContent.ascx +++ b/projecttemplates/MvcRelyingParty/Views/Auth/LogOnContent.ascx @@ -4,7 +4,7 @@ <p>Login using an account you already use. </p> <%= Html.ValidationSummary("Login was unsuccessful. Please correct the errors and try again.") %> -<% using (Html.BeginForm("LogOnPostAssertion", "Account", FormMethod.Post, new { target = "_top" })) { %> +<% using (Html.BeginForm("LogOnPostAssertion", "Auth", FormMethod.Post, new { target = "_top" })) { %> <%= Html.AntiForgeryToken() %> <%= Html.Hidden("ReturnUrl", Request.QueryString["ReturnUrl"], new { id = "ReturnUrl" }) %> <%= Html.Hidden("openid_openidAuthData") %> diff --git a/projecttemplates/MvcRelyingParty/Views/Account/LogOnPopup.aspx b/projecttemplates/MvcRelyingParty/Views/Auth/LogOnPopup.aspx index 465e7a0..465e7a0 100644 --- a/projecttemplates/MvcRelyingParty/Views/Account/LogOnPopup.aspx +++ b/projecttemplates/MvcRelyingParty/Views/Auth/LogOnPopup.aspx diff --git a/projecttemplates/MvcRelyingParty/Views/Account/LogOnScripts.ascx b/projecttemplates/MvcRelyingParty/Views/Auth/LogOnScripts.ascx index e983872..e983872 100644 --- a/projecttemplates/MvcRelyingParty/Views/Account/LogOnScripts.ascx +++ b/projecttemplates/MvcRelyingParty/Views/Auth/LogOnScripts.ascx diff --git a/projecttemplates/MvcRelyingParty/Views/Shared/LogOnUserControl.ascx b/projecttemplates/MvcRelyingParty/Views/Shared/LogOnUserControl.ascx index 1d59a10..214696a 100644 --- a/projecttemplates/MvcRelyingParty/Views/Shared/LogOnUserControl.ascx +++ b/projecttemplates/MvcRelyingParty/Views/Shared/LogOnUserControl.ascx @@ -16,7 +16,7 @@ Welcome <b> } %> </b>! [ -<%= Html.ActionLink("Log Off", "LogOff", "Account") %> +<%= Html.ActionLink("Log Off", "LogOff", "Auth") %> ] <% } else { diff --git a/projecttemplates/MvcRelyingParty/Web.config b/projecttemplates/MvcRelyingParty/Web.config index 6af9772..0f64273 100644 --- a/projecttemplates/MvcRelyingParty/Web.config +++ b/projecttemplates/MvcRelyingParty/Web.config @@ -166,7 +166,7 @@ ASP.NET to identify an incoming user. --> <authentication mode="Forms"> - <forms loginUrl="~/Account/LogOn" timeout="2880" name="MvcRelyingParty"/> + <forms loginUrl="~/Auth/LogOn" timeout="2880" name="MvcRelyingParty"/> </authentication> <roleManager enabled="true" defaultProvider="Database"> <providers> |