diff options
Diffstat (limited to 'src/OAuth/OAuthAuthorizationServer/Controllers')
3 files changed, 229 insertions, 0 deletions
diff --git a/src/OAuth/OAuthAuthorizationServer/Controllers/AccountController.cs b/src/OAuth/OAuthAuthorizationServer/Controllers/AccountController.cs new file mode 100644 index 0000000..d69a3b5 --- /dev/null +++ b/src/OAuth/OAuthAuthorizationServer/Controllers/AccountController.cs @@ -0,0 +1,78 @@ +namespace OAuthAuthorizationServer.Controllers { + using System; + using System.Linq; + using System.Web.Mvc; + using System.Web.Security; + + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.RelyingParty; + + using OAuthAuthorizationServer.Code; + using OAuthAuthorizationServer.Models; + + [HandleError] + public class AccountController : Controller { + // ************************************** + // URL: /Account/LogOn + // ************************************** + public ActionResult LogOn() { + return View(); + } + + [HttpPost] + public ActionResult LogOn(LogOnModel model, string returnUrl) { + if (ModelState.IsValid) { + var rp = new OpenIdRelyingParty(); + var request = rp.CreateRequest(model.UserSuppliedIdentifier, Realm.AutoDetect, new Uri(Request.Url, Url.Action("Authenticate"))); + if (request != null) { + if (returnUrl != null) { + request.AddCallbackArguments("returnUrl", returnUrl); + } + + return request.RedirectingResponse.AsActionResult(); + } else { + ModelState.AddModelError(string.Empty, "The identifier you supplied is not recognized as a valid OpenID Identifier."); + } + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + public ActionResult Authenticate(string returnUrl) { + var rp = new OpenIdRelyingParty(); + var response = rp.GetResponse(); + if (response != null) { + switch (response.Status) { + case AuthenticationStatus.Authenticated: + // Make sure we have a user account for this guy. + string identifier = response.ClaimedIdentifier; // convert to string so LinqToSQL expression parsing works. + if (MvcApplication.DataContext.Users.FirstOrDefault(u => u.OpenIDClaimedIdentifier == identifier) == null) { + MvcApplication.DataContext.Users.InsertOnSubmit(new User { + OpenIDFriendlyIdentifier = response.FriendlyIdentifierForDisplay, + OpenIDClaimedIdentifier = response.ClaimedIdentifier, + }); + } + + FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false); + return this.Redirect(returnUrl ?? Url.Action("Index", "Home")); + default: + ModelState.AddModelError(string.Empty, "An error occurred during login."); + break; + } + } + + return this.View("LogOn"); + } + + // ************************************** + // URL: /Account/LogOff + // ************************************** + public ActionResult LogOff() { + FormsAuthentication.SignOut(); + + return RedirectToAction("Index", "Home"); + } + } +} diff --git a/src/OAuth/OAuthAuthorizationServer/Controllers/HomeController.cs b/src/OAuth/OAuthAuthorizationServer/Controllers/HomeController.cs new file mode 100644 index 0000000..d6dd144 --- /dev/null +++ b/src/OAuth/OAuthAuthorizationServer/Controllers/HomeController.cs @@ -0,0 +1,59 @@ +namespace OAuthAuthorizationServer.Controllers { + using System.Configuration; + using System.Data.SqlClient; + using System.IO; + using System.Linq; + using System.Web.Mvc; + using System.Web.Security; + using OAuthAuthorizationServer.Code; + + [HandleError] + public class HomeController : Controller { + public ActionResult Index() { + return View(); + } + + public ActionResult About() { + return View(); + } + + [HttpPost] + public ActionResult CreateDatabase() { + string databasePath = Path.Combine(Server.MapPath(Request.ApplicationPath), "App_Data"); + if (!Directory.Exists(databasePath)) { + Directory.CreateDirectory(databasePath); + } + string connectionString = ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString.Replace("|DataDirectory|", databasePath); + var dc = new DataClassesDataContext(connectionString); + if (dc.DatabaseExists()) { + dc.DeleteDatabase(); + } + try { + dc.CreateDatabase(); + + // Add the necessary row for the sample client. + dc.Clients.InsertOnSubmit(new Client { + ClientIdentifier = "sampleconsumer", + ClientSecret = "samplesecret", + Name = "Some sample client", + }); + dc.Clients.InsertOnSubmit(new Client { + ClientIdentifier = "sampleImplicitConsumer", + Name = "Some sample client used for implicit grants (no secret)", + Callback = "http://localhost:59721/", + }); + + dc.SubmitChanges(); + + // Force the user to log out because a new database warrants a new row in the users table, which we create + // when the user logs in. + FormsAuthentication.SignOut(); + ViewData["Success"] = true; + } catch (SqlException ex) { + ViewData["Error"] = string.Join("<br>", ex.Errors.OfType<SqlError>().Select(er => er.Message).ToArray()); + } + + return this.View(); + } + } +} diff --git a/src/OAuth/OAuthAuthorizationServer/Controllers/OAuthController.cs b/src/OAuth/OAuthAuthorizationServer/Controllers/OAuthController.cs new file mode 100644 index 0000000..4260b48 --- /dev/null +++ b/src/OAuth/OAuthAuthorizationServer/Controllers/OAuthController.cs @@ -0,0 +1,92 @@ +namespace OAuthAuthorizationServer.Controllers { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Security.Cryptography; + using System.Web; + using System.Web.Mvc; + + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth2; + + using OAuthAuthorizationServer.Code; + using OAuthAuthorizationServer.Models; + + public class OAuthController : Controller { + private readonly AuthorizationServer authorizationServer = new AuthorizationServer(new OAuth2AuthorizationServer()); + + /// <summary> + /// The OAuth 2.0 token endpoint. + /// </summary> + /// <returns>The response to the Client.</returns> + public ActionResult Token() { + return this.authorizationServer.HandleTokenRequest(this.Request).AsActionResult(); + } + + /// <summary> + /// Prompts the user to authorize a client to access the user's private data. + /// </summary> + /// <returns>The browser HTML response that prompts the user to authorize the client.</returns> + [Authorize, AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)] + [HttpHeader("x-frame-options", "SAMEORIGIN")] // mitigates clickjacking + public ActionResult Authorize() { + var pendingRequest = this.authorizationServer.ReadAuthorizationRequest(); + if (pendingRequest == null) { + throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request."); + } + + var requestingClient = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier); + + // Consider auto-approving if safe to do so. + if (((OAuth2AuthorizationServer)this.authorizationServer.AuthorizationServerServices).CanBeAutoApproved(pendingRequest)) { + var approval = this.authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, HttpContext.User.Identity.Name); + return this.authorizationServer.Channel.PrepareResponse(approval).AsActionResult(); + } + + var model = new AccountAuthorizeModel { + ClientApp = requestingClient.Name, + Scope = pendingRequest.Scope, + AuthorizationRequest = pendingRequest, + }; + + return View(model); + } + + /// <summary> + /// Processes the user's response as to whether to authorize a Client to access his/her private data. + /// </summary> + /// <param name="isApproved">if set to <c>true</c>, the user has authorized the Client; <c>false</c> otherwise.</param> + /// <returns>HTML response that redirects the browser to the Client.</returns> + [Authorize, HttpPost, ValidateAntiForgeryToken] + public ActionResult AuthorizeResponse(bool isApproved) { + var pendingRequest = this.authorizationServer.ReadAuthorizationRequest(); + if (pendingRequest == null) { + throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request."); + } + + IDirectedProtocolMessage response; + if (isApproved) { + // The authorization we file in our database lasts until the user explicitly revokes it. + // You can cause the authorization to expire by setting the ExpirationDateUTC + // property in the below created ClientAuthorization. + var client = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier); + client.ClientAuthorizations.Add( + new ClientAuthorization { + Scope = OAuthUtilities.JoinScopes(pendingRequest.Scope), + User = MvcApplication.LoggedInUser, + CreatedOnUtc = DateTime.UtcNow, + }); + MvcApplication.DataContext.SubmitChanges(); // submit now so that this new row can be retrieved later in this same HTTP request + + // In this simple sample, the user either agrees to the entire scope requested by the client or none of it. + // But in a real app, you could grant a reduced scope of access to the client by passing a scope parameter to this method. + response = this.authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, User.Identity.Name); + } else { + response = this.authorizationServer.PrepareRejectAuthorizationRequest(pendingRequest); + } + + return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult(); + } + } +} |