summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2010-04-29 06:40:59 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2010-04-29 06:40:59 -0700
commit6d234b8df2a2eee625b1f52f458c2e28706343ca (patch)
tree4097f4233d6d2b93df036a185c6e7740c9c613ef
parentdc5c6421e4fbc243ed3c6e2485cc1b2974ca76ec (diff)
downloadDotNetOpenAuth-origin/dimebrain.zip
DotNetOpenAuth-origin/dimebrain.tar.gz
DotNetOpenAuth-origin/dimebrain.tar.bz2
An adaptation of @dimebrain's more MVC-ish way of doing OAuth SP.origin/dimebrain
We probably have a bit more work to do in this area before merging back.
-rw-r--r--projecttemplates/MvcRelyingParty/Code/OAuthAuthorizeAttribute.cs16
-rw-r--r--projecttemplates/MvcRelyingParty/Code/OAuthEndpointAttribute.cs37
-rw-r--r--projecttemplates/MvcRelyingParty/Controllers/AccountController.cs32
-rw-r--r--projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj6
-rw-r--r--projecttemplates/MvcRelyingParty/OAuth.ashx1
-rw-r--r--projecttemplates/MvcRelyingParty/OAuth.ashx.cs66
-rw-r--r--projecttemplates/MvcRelyingParty/Web.config2
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs52
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingUtilities.cs44
9 files changed, 152 insertions, 104 deletions
diff --git a/projecttemplates/MvcRelyingParty/Code/OAuthAuthorizeAttribute.cs b/projecttemplates/MvcRelyingParty/Code/OAuthAuthorizeAttribute.cs
new file mode 100644
index 0000000..28cc463
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/Code/OAuthAuthorizeAttribute.cs
@@ -0,0 +1,16 @@
+namespace MvcRelyingParty.Code {
+ using System.Web.Mvc;
+ using RelyingPartyLogic;
+
+ public class OAuthAuthorize : AuthorizeAttribute {
+ public override void OnAuthorization(AuthorizationContext filterContext) {
+ var authorization = OAuthServiceProvider.ServiceProvider.ReadProtectedResourceAuthorization();
+ if (authorization != null) {
+ filterContext.HttpContext.User = OAuthServiceProvider.ServiceProvider.CreatePrincipal(authorization);
+ } else {
+ // Doesn't authorize with OAuth; defer to other schemes
+ base.OnAuthorization(filterContext);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/projecttemplates/MvcRelyingParty/Code/OAuthEndpointAttribute.cs b/projecttemplates/MvcRelyingParty/Code/OAuthEndpointAttribute.cs
new file mode 100644
index 0000000..33ba960
--- /dev/null
+++ b/projecttemplates/MvcRelyingParty/Code/OAuthEndpointAttribute.cs
@@ -0,0 +1,37 @@
+namespace MvcRelyingParty.Code {
+ using System.Web.Mvc;
+ using DotNetOpenAuth.Messaging;
+ using RelyingPartyLogic;
+
+ public abstract class OAuthEndpointAttribute : ActionFilterAttribute {
+ internal MessageReceivingEndpoint GetRequestAsEndpoint(ActionExecutingContext filterContext) {
+ return new MessageReceivingEndpoint(
+ filterContext.HttpContext.Request.Url,
+ MessagingUtilities.GetHttpDeliveryMethod(filterContext.HttpContext.Request.HttpMethod));
+ }
+ }
+
+ public class OAuthRequestTokenEndpoint : OAuthEndpointAttribute {
+ public override void OnActionExecuting(ActionExecutingContext filterContext) {
+ var endpoint = GetRequestAsEndpoint(filterContext);
+ OAuthServiceProvider.RequestTokenEndpoint = endpoint;
+ base.OnActionExecuting(filterContext);
+ }
+ }
+
+ public class OAuthAccessTokenEndpoint : OAuthEndpointAttribute {
+ public override void OnActionExecuting(ActionExecutingContext filterContext) {
+ var endpoint = GetRequestAsEndpoint(filterContext);
+ OAuthServiceProvider.AccessTokenEndpoint = endpoint;
+ base.OnActionExecuting(filterContext);
+ }
+ }
+
+ public class OAuthUserAuthorizationEndpoint : OAuthEndpointAttribute {
+ public override void OnActionExecuting(ActionExecutingContext filterContext) {
+ var endpoint = GetRequestAsEndpoint(filterContext);
+ OAuthServiceProvider.UserAuthorizationEndpoint = endpoint;
+ base.OnActionExecuting(filterContext);
+ }
+ }
+}
diff --git a/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs b/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs
index a322f7d..3d3e1aa 100644
--- a/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs
+++ b/projecttemplates/MvcRelyingParty/Controllers/AccountController.cs
@@ -1,4 +1,6 @@
-namespace MvcRelyingParty.Controllers {
+using MvcRelyingParty.Code;
+
+namespace MvcRelyingParty.Controllers {
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -20,7 +22,7 @@
[HandleError]
public class AccountController : Controller {
- [Authorize]
+ [OAuthAuthorize]
public ActionResult Edit() {
return View(GetAccountInfoModel());
}
@@ -35,7 +37,7 @@
/// <remarks>
/// This action accepts PUT because this operation is idempotent in nature.
/// </remarks>
- [Authorize, AcceptVerbs(HttpVerbs.Put), ValidateAntiForgeryToken]
+ [OAuthAuthorize, AcceptVerbs(HttpVerbs.Put), ValidateAntiForgeryToken]
public ActionResult Update(string firstName, string lastName, string emailAddress) {
Database.LoggedInUser.FirstName = firstName;
Database.LoggedInUser.LastName = lastName;
@@ -49,6 +51,9 @@
}
[Authorize]
+ [OAuthUserAuthorizationEndpoint]
+ [ActionName("authorize")]
+ [AcceptVerbs(HttpVerbs.Get)]
public ActionResult Authorize() {
if (OAuthServiceProvider.PendingAuthorizationRequest == null) {
return RedirectToAction("Edit");
@@ -111,6 +116,27 @@
return PartialView("AuthorizedApps", GetAccountInfoModel());
}
+ [OAuthRequestTokenEndpoint]
+ [AcceptVerbs(HttpVerbs.Post)]
+ [ActionName("request_token")]
+ public ActionResult GetRequestToken()
+ {
+ var serviceProvider = OAuthServiceProvider.ServiceProvider;
+ var requestMessage = serviceProvider.ReadTokenRequest();
+ var response = serviceProvider.PrepareUnauthorizedTokenMessage(requestMessage);
+ return serviceProvider.Channel.PrepareResponse(response).AsActionResult();
+ }
+
+ [OAuthAccessTokenEndpoint]
+ [ActionName("access_token")]
+ [AcceptVerbs(HttpVerbs.Post)]
+ public ActionResult GetAccessToken() {
+ var serviceProvider = OAuthServiceProvider.ServiceProvider;
+ var requestMessage = serviceProvider.ReadAccessTokenRequest();
+ var response = serviceProvider.PrepareAccessTokenMessage(requestMessage);
+ return serviceProvider.Channel.PrepareResponse(response).AsActionResult();
+ }
+
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/MvcRelyingParty.csproj b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
index 540b702..21f7196 100644
--- a/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
+++ b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
@@ -70,6 +70,8 @@
<ItemGroup>
<Compile Include="Code\Extensions.cs" />
<Compile Include="Code\FormsAuthenticationService.cs" />
+ <Compile Include="Code\OAuthAuthorizeAttribute.cs" />
+ <Compile Include="Code\OAuthEndpointAttribute.cs" />
<Compile Include="Code\OpenIdRelyingPartyService.cs" />
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\AuthController.cs" />
@@ -83,9 +85,6 @@
</Compile>
<Compile Include="Models\AccountAuthorizeModel.cs" />
<Compile Include="Models\AccountInfoModel.cs" />
- <Compile Include="OAuth.ashx.cs">
- <DependentUpon>OAuth.ashx</DependentUpon>
- </Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Setup.aspx.cs">
<DependentUpon>Setup.aspx</DependentUpon>
@@ -175,7 +174,6 @@
</ItemGroup>
<ItemGroup>
<Content Include="Content\images\infocard_23x16.png" />
- <Content Include="OAuth.ashx" />
<Content Include="Views\Account\AuthenticationTokens.ascx" />
<Content Include="Views\Account\Authorize.aspx" />
<Content Include="Views\Account\AuthorizeApproved.aspx" />
diff --git a/projecttemplates/MvcRelyingParty/OAuth.ashx b/projecttemplates/MvcRelyingParty/OAuth.ashx
deleted file mode 100644
index 81b3d52..0000000
--- a/projecttemplates/MvcRelyingParty/OAuth.ashx
+++ /dev/null
@@ -1 +0,0 @@
-<%@ WebHandler Language="C#" CodeBehind="OAuth.ashx.cs" Class="MvcRelyingParty.OAuth" %>
diff --git a/projecttemplates/MvcRelyingParty/OAuth.ashx.cs b/projecttemplates/MvcRelyingParty/OAuth.ashx.cs
deleted file mode 100644
index b9051c1..0000000
--- a/projecttemplates/MvcRelyingParty/OAuth.ashx.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuth.ashx.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace MvcRelyingParty {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.SessionState;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth;
- using DotNetOpenAuth.OAuth.Messages;
- using RelyingPartyLogic;
-
- /// <summary>
- /// Responds to incoming OAuth Service Provider messages.
- /// </summary>
- public class OAuth : IHttpHandler, IRequiresSessionState {
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuth"/> class.
- /// </summary>
- public OAuth() {
- }
-
- /// <summary>
- /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
- /// </summary>
- /// <returns>
- /// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
- /// </returns>
- public bool IsReusable {
- get { return true; }
- }
-
- /// <summary>
- /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
- /// </summary>
- /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
- public void ProcessRequest(HttpContext context) {
- var serviceProvider = OAuthServiceProvider.ServiceProvider;
- var requestMessage = serviceProvider.ReadRequest(new HttpRequestInfo(context.Request));
-
- UnauthorizedTokenRequest unauthorizedTokenRequestMessage;
- AuthorizedTokenRequest authorizedTokenRequestMessage;
- UserAuthorizationRequest userAuthorizationRequest;
- if ((unauthorizedTokenRequestMessage = requestMessage as UnauthorizedTokenRequest) != null) {
- var response = serviceProvider.PrepareUnauthorizedTokenMessage(unauthorizedTokenRequestMessage);
- serviceProvider.Channel.Send(response);
- } else if ((authorizedTokenRequestMessage = requestMessage as AuthorizedTokenRequest) != null) {
- var response = serviceProvider.PrepareAccessTokenMessage(authorizedTokenRequestMessage);
- serviceProvider.Channel.Send(response);
- } else if ((userAuthorizationRequest = requestMessage as UserAuthorizationRequest) != null) {
- // This is a browser opening to allow the user to authorize a request token,
- // so redirect to the authorization page, which will automatically redirect
- // to have the user log in if necessary.
- OAuthServiceProvider.PendingAuthorizationRequest = userAuthorizationRequest;
- HttpContext.Current.Response.Redirect("~/Account/Authorize");
- } else {
- throw new InvalidOperationException();
- }
- }
- }
-}
diff --git a/projecttemplates/MvcRelyingParty/Web.config b/projecttemplates/MvcRelyingParty/Web.config
index 7a867bb..1310bd6 100644
--- a/projecttemplates/MvcRelyingParty/Web.config
+++ b/projecttemplates/MvcRelyingParty/Web.config
@@ -209,7 +209,6 @@
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
- <add name="OAuthAuthenticationModule" type="RelyingPartyLogic.OAuthAuthenticationModule, RelyingPartyLogic"/>
<add name="Database" type="RelyingPartyLogic.Database, RelyingPartyLogic"/>
</httpModules>
</system.web>
@@ -238,7 +237,6 @@
<remove name="UrlRoutingModule"/>
<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
- <add name="OAuthAuthenticationModule" type="RelyingPartyLogic.OAuthAuthenticationModule, RelyingPartyLogic"/>
<add name="Database" type="RelyingPartyLogic.Database, RelyingPartyLogic"/>
</modules>
<handlers>
diff --git a/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs b/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
index 807da2d..357464a 100644
--- a/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
+++ b/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
@@ -107,17 +107,23 @@ namespace RelyingPartyLogic {
/// Initializes the <see cref="serviceProvider"/> field if it has not yet been initialized.
/// </summary>
private static void EnsureInitialized() {
- if (serviceProvider == null) {
+ if (serviceProvider == null || serviceDescription == null) {
lock (initializerLock) {
if (serviceDescription == null) {
- var postEndpoint = new MessageReceivingEndpoint(new Uri(Utilities.ApplicationRoot, "OAuth.ashx"), HttpDeliveryMethods.PostRequest);
- var getEndpoint = new MessageReceivingEndpoint(postEndpoint.Location, HttpDeliveryMethods.GetRequest);
+ //var postEndpoint = new MessageReceivingEndpoint(new Uri(Utilities.ApplicationRoot, "OAuth.ashx"), HttpDeliveryMethods.PostRequest);
+ //var getEndpoint = new MessageReceivingEndpoint(postEndpoint.Location, HttpDeliveryMethods.GetRequest);
+
serviceDescription = new ServiceProviderDescription {
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- RequestTokenEndpoint = postEndpoint,
- AccessTokenEndpoint = postEndpoint,
- UserAuthorizationEndpoint = getEndpoint,
+ RequestTokenEndpoint = _requestTokenEndpoint,
+ AccessTokenEndpoint = _accessTokenEndpoint,
+ UserAuthorizationEndpoint = _userAuthorizationEndpoint,
};
+
+ if (tokenManager == null) {
+ tokenManager = new OAuthServiceProviderTokenManager();
+ }
+ serviceProvider = new ServiceProvider(serviceDescription, tokenManager);
}
if (tokenManager == null) {
@@ -130,5 +136,39 @@ namespace RelyingPartyLogic {
}
}
}
+
+ private static MessageReceivingEndpoint _requestTokenEndpoint;
+ private static MessageReceivingEndpoint _accessTokenEndpoint;
+ private static MessageReceivingEndpoint _userAuthorizationEndpoint;
+
+ public static MessageReceivingEndpoint RequestTokenEndpoint {
+ get {
+ return _requestTokenEndpoint;
+ }
+ set {
+ _requestTokenEndpoint = value;
+ serviceDescription = null;
+ }
+ }
+
+ public static MessageReceivingEndpoint AccessTokenEndpoint {
+ get {
+ return _accessTokenEndpoint;
+ }
+ set {
+ _accessTokenEndpoint = value;
+ serviceDescription = null;
+ }
+ }
+
+ public static MessageReceivingEndpoint UserAuthorizationEndpoint {
+ get {
+ return _userAuthorizationEndpoint;
+ }
+ set {
+ _userAuthorizationEndpoint = value;
+ serviceDescription = null;
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs
index 231637a..ab9ddc1 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs
+++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs
@@ -193,6 +193,28 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Gets the <see cref="HttpDeliveryMethods"/> enum value for a given HTTP verb.
+ /// </summary>
+ /// <param name="httpVerb">The HTTP verb.</param>
+ /// <returns>A <see cref="HttpDeliveryMethods"/> enum value that is within the <see cref="HttpDeliveryMethods.HttpVerbMask"/>.</returns>
+ /// <exception cref="ArgumentException">Thrown if the HTTP request is something we can't handle.</exception>
+ public static HttpDeliveryMethods GetHttpDeliveryMethod(string httpVerb) {
+ if (httpVerb == "GET") {
+ return HttpDeliveryMethods.GetRequest;
+ } else if (httpVerb == "POST") {
+ return HttpDeliveryMethods.PostRequest;
+ } else if (httpVerb == "PUT") {
+ return HttpDeliveryMethods.PutRequest;
+ } else if (httpVerb == "DELETE") {
+ return HttpDeliveryMethods.DeleteRequest;
+ } else if (httpVerb == "HEAD") {
+ return HttpDeliveryMethods.HeadRequest;
+ } else {
+ throw ErrorUtilities.ThrowArgumentNamed("httpVerb", MessagingStrings.UnsupportedHttpVerb, httpVerb);
+ }
+ }
+
+ /// <summary>
/// Sends a multipart HTTP POST request (useful for posting files) but doesn't call GetResponse on it.
/// </summary>
/// <param name="request">The HTTP request.</param>
@@ -683,28 +705,6 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
- /// Gets the <see cref="HttpDeliveryMethods"/> enum value for a given HTTP verb.
- /// </summary>
- /// <param name="httpVerb">The HTTP verb.</param>
- /// <returns>A <see cref="HttpDeliveryMethods"/> enum value that is within the <see cref="HttpDeliveryMethods.HttpVerbMask"/>.</returns>
- /// <exception cref="ArgumentException">Thrown if the HTTP request is something we can't handle.</exception>
- internal static HttpDeliveryMethods GetHttpDeliveryMethod(string httpVerb) {
- if (httpVerb == "GET") {
- return HttpDeliveryMethods.GetRequest;
- } else if (httpVerb == "POST") {
- return HttpDeliveryMethods.PostRequest;
- } else if (httpVerb == "PUT") {
- return HttpDeliveryMethods.PutRequest;
- } else if (httpVerb == "DELETE") {
- return HttpDeliveryMethods.DeleteRequest;
- } else if (httpVerb == "HEAD") {
- return HttpDeliveryMethods.HeadRequest;
- } else {
- throw ErrorUtilities.ThrowArgumentNamed("httpVerb", MessagingStrings.UnsupportedHttpVerb, httpVerb);
- }
- }
-
- /// <summary>
/// Gets the HTTP verb to use for a given <see cref="HttpDeliveryMethods"/> enum value.
/// </summary>
/// <param name="httpMethod">The HTTP method.</param>