summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj4
-rw-r--r--projecttemplates/MvcRelyingParty/OAuthTokenEndpoint.ashx.cs23
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs24
-rw-r--r--projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj4
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj1
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/HttpAsyncHandlerBase.cs60
-rw-r--r--samples/OAuthClient/OAuthClient.csproj8
-rw-r--r--samples/OAuthClient/Twitter.aspx35
-rw-r--r--samples/OAuthClient/Twitter.aspx.cs101
-rw-r--r--samples/OAuthClient/Twitter.aspx.designer.cs78
-rw-r--r--samples/OAuthServiceProvider/Code/DatabaseTokenManager.cs21
-rw-r--r--samples/OAuthServiceProvider/Code/Global.cs37
-rw-r--r--samples/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs1
-rw-r--r--samples/OAuthServiceProvider/Login.aspx2
-rw-r--r--samples/OAuthServiceProvider/OAuth.ashx22
-rw-r--r--samples/OAuthServiceProvider/OAuthServiceProvider.csproj11
-rw-r--r--samples/OAuthServiceProvider/Web.config3
-rw-r--r--samples/OpenIdProviderWebForms/Provider.ashx.cs20
-rw-r--r--samples/OpenIdProviderWebForms/access_token.ashx.cs23
19 files changed, 158 insertions, 320 deletions
diff --git a/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
index c9c8848..703f1c7 100644
--- a/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
+++ b/projecttemplates/MvcRelyingParty/MvcRelyingParty.csproj
@@ -176,6 +176,10 @@
<Content Include="Views\Web.config" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\..\samples\DotNetOpenAuth.ApplicationBlock\DotNetOpenAuth.ApplicationBlock.csproj">
+ <Project>{aa78d112-d889-414b-a7d4-467b34c7b663}</Project>
+ <Name>DotNetOpenAuth.ApplicationBlock</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\DotNetOpenAuth.InfoCard.UI\DotNetOpenAuth.InfoCard.UI.csproj">
<Project>{E040EB58-B4D2-457B-A023-AE6EF3BD34DE}</Project>
<Name>DotNetOpenAuth.InfoCard.UI</Name>
diff --git a/projecttemplates/MvcRelyingParty/OAuthTokenEndpoint.ashx.cs b/projecttemplates/MvcRelyingParty/OAuthTokenEndpoint.ashx.cs
index 6f52ba4..f9a98f7 100644
--- a/projecttemplates/MvcRelyingParty/OAuthTokenEndpoint.ashx.cs
+++ b/projecttemplates/MvcRelyingParty/OAuthTokenEndpoint.ashx.cs
@@ -12,6 +12,7 @@ namespace MvcRelyingParty {
using System.Threading.Tasks;
using System.Web;
using System.Web.SessionState;
+ using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2;
using RelyingPartyLogic;
@@ -19,7 +20,7 @@ namespace MvcRelyingParty {
/// <summary>
/// An OAuth 2.0 token endpoint.
/// </summary>
- public class OAuthTokenEndpoint : IHttpAsyncHandler, IRequiresSessionState {
+ public class OAuthTokenEndpoint : HttpAsyncHandlerBase, IRequiresSessionState {
/// <summary>
/// Initializes a new instance of the <see cref="OAuthTokenEndpoint"/> class.
/// </summary>
@@ -32,27 +33,11 @@ namespace MvcRelyingParty {
/// <returns>
/// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
/// </returns>
- public bool IsReusable {
+ public override 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) {
- this.ProcessRequestAsync(context).GetAwaiter().GetResult();
- }
-
- public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
- return this.ProcessRequestAsync(context).ToApm(cb, extraData);
- }
-
- public void EndProcessRequest(IAsyncResult result) {
- ((Task)result).Wait(); // rethrows exceptions
- }
-
- private async Task ProcessRequestAsync(HttpContext context) {
+ protected override async Task ProcessRequestAsync(HttpContext context) {
var serviceProvider = OAuthServiceProvider.AuthorizationServer;
var response = await serviceProvider.HandleTokenRequestAsync(new HttpRequestWrapper(context.Request), context.Response.ClientDisconnectedToken);
await response.SendAsync(new HttpResponseWrapper(context.Response), context.Response.ClientDisconnectedToken);
diff --git a/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs b/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs
index 7f53a7b..bada3e4 100644
--- a/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs
+++ b/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs
@@ -11,16 +11,16 @@ namespace WebFormsRelyingParty {
using System.Threading.Tasks;
using System.Web;
using System.Web.SessionState;
+ using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2;
using RelyingPartyLogic;
-
using WebFormsRelyingParty.Code;
/// <summary>
/// An OAuth 2.0 token endpoint.
/// </summary>
- public class OAuthTokenEndpoint : IHttpAsyncHandler, IRequiresSessionState {
+ public class OAuthTokenEndpoint : HttpAsyncHandlerBase, IRequiresSessionState {
/// <summary>
/// Initializes a new instance of the <see cref="OAuthTokenEndpoint"/> class.
/// </summary>
@@ -33,27 +33,11 @@ namespace WebFormsRelyingParty {
/// <returns>
/// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
/// </returns>
- public bool IsReusable {
+ public override 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) {
- this.ProcessRequestAsync(context).GetAwaiter().GetResult();
- }
-
- public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
- return this.ProcessRequestAsync(context).ToApm(cb, extraData);
- }
-
- public void EndProcessRequest(IAsyncResult result) {
- ((Task)result).Wait(); // rethrows exceptions
- }
-
- private async Task ProcessRequestAsync(HttpContext context) {
+ protected override async Task ProcessRequestAsync(HttpContext context) {
var serviceProvider = OAuthServiceProvider.AuthorizationServer;
var response = await serviceProvider.HandleTokenRequestAsync(new HttpRequestWrapper(context.Request), context.Response.ClientDisconnectedToken);
await response.SendAsync(new HttpResponseWrapper(context.Response), context.Response.ClientDisconnectedToken);
diff --git a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
index 7de91cc..11384e2 100644
--- a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
+++ b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
@@ -252,6 +252,10 @@
<Content Include="PrivacyPolicy.aspx" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\..\samples\DotNetOpenAuth.ApplicationBlock\DotNetOpenAuth.ApplicationBlock.csproj">
+ <Project>{aa78d112-d889-414b-a7d4-467b34c7b663}</Project>
+ <Name>DotNetOpenAuth.ApplicationBlock</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\DotNetOpenAuth.InfoCard.UI\DotNetOpenAuth.InfoCard.UI.csproj">
<Project>{E040EB58-B4D2-457B-A023-AE6EF3BD34DE}</Project>
<Name>DotNetOpenAuth.InfoCard.UI</Name>
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
index 3169116..9f74693 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
+++ b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
@@ -99,6 +99,7 @@
<Compile Include="Facebook\FacebookGraph.cs" />
<Compile Include="CustomExtensions\UIRequestAtRelyingPartyFactory.cs" />
<Compile Include="GoogleConsumer.cs" />
+ <Compile Include="HttpAsyncHandlerBase.cs" />
<Compile Include="InMemoryClientAuthorizationTracker.cs" />
<Compile Include="InMemoryTokenManager.cs">
<SubType>Code</SubType>
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/HttpAsyncHandlerBase.cs b/samples/DotNetOpenAuth.ApplicationBlock/HttpAsyncHandlerBase.cs
new file mode 100644
index 0000000..a72a9b1
--- /dev/null
+++ b/samples/DotNetOpenAuth.ApplicationBlock/HttpAsyncHandlerBase.cs
@@ -0,0 +1,60 @@
+//-----------------------------------------------------------------------
+// <copyright file="HttpAsyncHandlerBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.ApplicationBlock {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using System.Web;
+
+ public abstract class HttpAsyncHandlerBase : IHttpAsyncHandler {
+ public abstract bool IsReusable { get; }
+
+ public IAsyncResult BeginProcessRequest(HttpContext context, System.AsyncCallback cb, object extraData) {
+ return ToApm(this.ProcessRequestAsync(context), cb, extraData);
+ }
+
+ public void EndProcessRequest(IAsyncResult result) {
+ ((Task)result).Wait(); // rethrows exceptions
+ }
+
+ public void ProcessRequest(HttpContext context) {
+ this.ProcessRequestAsync(context).GetAwaiter().GetResult();
+ }
+
+ protected abstract Task ProcessRequestAsync(HttpContext context);
+
+ private static Task ToApm(Task task, AsyncCallback callback, object state) {
+ if (task == null) {
+ throw new ArgumentNullException("task");
+ }
+
+ var tcs = new TaskCompletionSource<object>(state);
+ task.ContinueWith(
+ t => {
+ if (t.IsFaulted) {
+ tcs.TrySetException(t.Exception.InnerExceptions);
+ } else if (t.IsCanceled) {
+ tcs.TrySetCanceled();
+ } else {
+ tcs.TrySetResult(null);
+ }
+
+ if (callback != null) {
+ callback(tcs.Task);
+ }
+ },
+ CancellationToken.None,
+ TaskContinuationOptions.None,
+ TaskScheduler.Default);
+
+ return tcs.Task;
+ }
+ }
+}
diff --git a/samples/OAuthClient/OAuthClient.csproj b/samples/OAuthClient/OAuthClient.csproj
index 4ff85d3..61b3a79 100644
--- a/samples/OAuthClient/OAuthClient.csproj
+++ b/samples/OAuthClient/OAuthClient.csproj
@@ -97,7 +97,6 @@
<Content Include="SampleWcf2.aspx" />
<Content Include="SignInWithTwitter.aspx" />
<Content Include="TracePage.aspx" />
- <Content Include="Twitter.aspx" />
<Content Include="Web.config" />
<None Include="Service References\SampleResourceServer\DataApi1.xsd">
<SubType>Designer</SubType>
@@ -156,10 +155,6 @@
<Compile Include="TracePage.aspx.designer.cs">
<DependentUpon>TracePage.aspx</DependentUpon>
</Compile>
- <Compile Include="Twitter.aspx.cs">
- <DependentUpon>Twitter.aspx</DependentUpon>
- <SubType>ASPXCodeBehind</SubType>
- </Compile>
<Compile Include="Code\Logging.cs" />
<Compile Include="Code\TracePageAppender.cs" />
<Compile Include="GoogleAddressBook.aspx.cs">
@@ -167,9 +162,6 @@
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Twitter.aspx.designer.cs">
- <DependentUpon>Twitter.aspx</DependentUpon>
- </Compile>
<Compile Include="WindowsLive.aspx.cs">
<DependentUpon>WindowsLive.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
diff --git a/samples/OAuthClient/Twitter.aspx b/samples/OAuthClient/Twitter.aspx
deleted file mode 100644
index cb60851..0000000
--- a/samples/OAuthClient/Twitter.aspx
+++ /dev/null
@@ -1,35 +0,0 @@
-<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" Inherits="OAuthClient.Twitter" Codebehind="Twitter.aspx.cs" %>
-
-<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server">
-</asp:Content>
-<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="Server">
- <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
- <asp:View ID="View1" runat="server">
- <h2>Twitter setup</h2>
- <p>A Twitter client app must be endorsed by a Twitter user. </p>
- <ol>
- <li><a target="_blank" href="https://twitter.com/oauth_clients">Visit Twitter and create
- a client app</a>. </li>
- <li>Modify your web.config file to include your consumer key and consumer secret.</li>
- </ol>
- </asp:View>
- <asp:View runat="server">
- <h2>Updates</h2>
- <p>Ok, Twitter has authorized us to download your feeds. Notice how we never asked
- you for your Twitter username or password. </p>
- <p>
- Upload a new profile photo:
- <asp:FileUpload ID="profilePhoto" runat="server" />
- &nbsp;<asp:Button ID="uploadProfilePhotoButton" runat="server"
- onclick="uploadProfilePhotoButton_Click" Text="Upload photo" />
- &nbsp;<asp:Label ID="photoUploadedLabel" runat="server" EnableViewState="False"
- Text="Done!" Visible="False"></asp:Label>
- </p>
- <p>
- Click &#39;Get updates&#39; to download updates to this sample.
- </p>
- <asp:Button ID="downloadUpdates" runat="server" Text="Get updates" OnClick="downloadUpdates_Click" />
- <asp:PlaceHolder runat="server" ID="resultsPlaceholder" />
- </asp:View>
- </asp:MultiView>
-</asp:Content>
diff --git a/samples/OAuthClient/Twitter.aspx.cs b/samples/OAuthClient/Twitter.aspx.cs
deleted file mode 100644
index 2ef5ab8..0000000
--- a/samples/OAuthClient/Twitter.aspx.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-namespace OAuthClient {
- using System;
- using System.Collections.Generic;
- using System.Configuration;
- using System.Linq;
- using System.Text;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Xml.Linq;
- using System.Xml.XPath;
- using DotNetOpenAuth.ApplicationBlock;
- using DotNetOpenAuth.OAuth;
-
- using DotNetOpenAuth.Messaging;
-
- public partial class Twitter : System.Web.UI.Page {
- private string AccessToken {
- get { return (string)Session["TwitterAccessToken"]; }
- set { Session["TwitterAccessToken"] = value; }
- }
-
- private InMemoryTokenManager TokenManager {
- get {
- var tokenManager = (InMemoryTokenManager)Application["TwitterTokenManager"];
- if (tokenManager == null) {
- string consumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"];
- string consumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"];
- if (!string.IsNullOrEmpty(consumerKey)) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- Application["TwitterTokenManager"] = tokenManager;
- }
- }
-
- return tokenManager;
- }
- }
-
- protected async void Page_Load(object sender, EventArgs e) {
- if (this.TokenManager != null) {
- this.MultiView1.ActiveViewIndex = 1;
-
- if (!IsPostBack) {
- var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager);
-
- // Is Twitter calling back with authorization?
- var accessTokenResponse = await twitter.ProcessUserAuthorizationAsync(new HttpRequestWrapper(Request), Response.ClientDisconnectedToken);
- if (accessTokenResponse != null) {
- this.AccessToken = accessTokenResponse.AccessToken;
- } else if (this.AccessToken == null) {
- // If we don't yet have access, immediately request it.
- var request = await twitter.PrepareRequestUserAuthorizationAsync(Response.ClientDisconnectedToken);
- var response = await twitter.Channel.PrepareResponseAsync(request, Response.ClientDisconnectedToken);
- await response.SendAsync(new HttpResponseWrapper(Response), Response.ClientDisconnectedToken);
- }
- }
- }
- }
-
- protected async void downloadUpdates_Click(object sender, EventArgs e) {
- var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager);
- XPathDocument updates = new XPathDocument((await TwitterConsumer.GetUpdatesAsync(twitter, this.AccessToken, Response.ClientDisconnectedToken)).CreateReader());
- XPathNavigator nav = updates.CreateNavigator();
- var parsedUpdates = from status in nav.Select("/statuses/status").OfType<XPathNavigator>()
- where !status.SelectSingleNode("user/protected").ValueAsBoolean
- select new {
- User = status.SelectSingleNode("user/name").InnerXml,
- Status = status.SelectSingleNode("text").InnerXml,
- };
-
- StringBuilder tableBuilder = new StringBuilder();
- tableBuilder.Append("<table><tr><td>Name</td><td>Update</td></tr>");
-
- foreach (var update in parsedUpdates) {
- tableBuilder.AppendFormat(
- "<tr><td>{0}</td><td>{1}</td></tr>",
- HttpUtility.HtmlEncode(update.User),
- HttpUtility.HtmlEncode(update.Status));
- }
- tableBuilder.Append("</table>");
- this.resultsPlaceholder.Controls.Add(new Literal { Text = tableBuilder.ToString() });
- }
-
- protected async void uploadProfilePhotoButton_Click(object sender, EventArgs e) {
- if (this.profilePhoto.PostedFile.ContentType == null) {
- this.photoUploadedLabel.Visible = true;
- this.photoUploadedLabel.Text = "Select a file first.";
- return;
- }
-
- var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager);
- XDocument imageResult = await TwitterConsumer.UpdateProfileImageAsync(
- twitter,
- this.AccessToken,
- this.profilePhoto.PostedFile.InputStream,
- this.profilePhoto.PostedFile.ContentType,
- Response.ClientDisconnectedToken);
- this.photoUploadedLabel.Visible = true;
- }
- }
-} \ No newline at end of file
diff --git a/samples/OAuthClient/Twitter.aspx.designer.cs b/samples/OAuthClient/Twitter.aspx.designer.cs
deleted file mode 100644
index e82f477..0000000
--- a/samples/OAuthClient/Twitter.aspx.designer.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-// This code was generated by a tool.
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace OAuthClient {
-
-
- public partial class Twitter {
-
- /// <summary>
- /// MultiView1 control.
- /// </summary>
- /// <remarks>
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- /// </remarks>
- protected global::System.Web.UI.WebControls.MultiView MultiView1;
-
- /// <summary>
- /// View1 control.
- /// </summary>
- /// <remarks>
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- /// </remarks>
- protected global::System.Web.UI.WebControls.View View1;
-
- /// <summary>
- /// profilePhoto control.
- /// </summary>
- /// <remarks>
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- /// </remarks>
- protected global::System.Web.UI.WebControls.FileUpload profilePhoto;
-
- /// <summary>
- /// uploadProfilePhotoButton control.
- /// </summary>
- /// <remarks>
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- /// </remarks>
- protected global::System.Web.UI.WebControls.Button uploadProfilePhotoButton;
-
- /// <summary>
- /// photoUploadedLabel control.
- /// </summary>
- /// <remarks>
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- /// </remarks>
- protected global::System.Web.UI.WebControls.Label photoUploadedLabel;
-
- /// <summary>
- /// downloadUpdates control.
- /// </summary>
- /// <remarks>
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- /// </remarks>
- protected global::System.Web.UI.WebControls.Button downloadUpdates;
-
- /// <summary>
- /// resultsPlaceholder control.
- /// </summary>
- /// <remarks>
- /// Auto-generated field.
- /// To modify move field declaration from designer file to code-behind file.
- /// </remarks>
- protected global::System.Web.UI.WebControls.PlaceHolder resultsPlaceholder;
- }
-}
diff --git a/samples/OAuthServiceProvider/Code/DatabaseTokenManager.cs b/samples/OAuthServiceProvider/Code/DatabaseTokenManager.cs
index 49da45d..7c80275 100644
--- a/samples/OAuthServiceProvider/Code/DatabaseTokenManager.cs
+++ b/samples/OAuthServiceProvider/Code/DatabaseTokenManager.cs
@@ -9,13 +9,18 @@ namespace OAuthServiceProvider.Code {
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+ using System.ServiceModel;
+
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
public class DatabaseTokenManager : IServiceProviderTokenManager {
+ internal OperationContext OperationContext { get; set; }
+
#region IServiceProviderTokenManager
public IConsumerDescription GetConsumer(string consumerKey) {
+ this.ApplyOperationContext();
var consumerRow = Global.DataContext.OAuthConsumers.SingleOrDefault(
consumerCandidate => consumerCandidate.ConsumerKey == consumerKey);
if (consumerRow == null) {
@@ -27,6 +32,7 @@ namespace OAuthServiceProvider.Code {
public IServiceProviderRequestToken GetRequestToken(string token) {
try {
+ this.ApplyOperationContext();
return Global.DataContext.OAuthTokens.First(t => t.Token == token && t.State != TokenAuthorizationState.AccessToken);
} catch (InvalidOperationException ex) {
throw new KeyNotFoundException("Unrecognized token", ex);
@@ -34,6 +40,7 @@ namespace OAuthServiceProvider.Code {
}
public IServiceProviderAccessToken GetAccessToken(string token) {
+ this.ApplyOperationContext();
try {
return Global.DataContext.OAuthTokens.First(t => t.Token == token && t.State == TokenAuthorizationState.AccessToken);
} catch (InvalidOperationException ex) {
@@ -54,6 +61,7 @@ namespace OAuthServiceProvider.Code {
#region ITokenManager Members
public string GetTokenSecret(string token) {
+ this.ApplyOperationContext();
var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(
tokenCandidate => tokenCandidate.Token == token);
if (tokenRow == null) {
@@ -64,6 +72,7 @@ namespace OAuthServiceProvider.Code {
}
public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) {
+ this.ApplyOperationContext();
RequestScopedTokenMessage scopedRequest = (RequestScopedTokenMessage)request;
var consumer = Global.DataContext.OAuthConsumers.Single(consumerRow => consumerRow.ConsumerKey == request.ConsumerKey);
string scope = scopedRequest.Scope;
@@ -90,6 +99,7 @@ namespace OAuthServiceProvider.Code {
/// been authorized, has expired or does not exist.
/// </returns>
public bool IsRequestTokenAuthorized(string requestToken) {
+ this.ApplyOperationContext();
var tokenFound = Global.DataContext.OAuthTokens.SingleOrDefault(
token => token.Token == requestToken &&
token.State == TokenAuthorizationState.AuthorizedRequestToken);
@@ -97,6 +107,8 @@ namespace OAuthServiceProvider.Code {
}
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
+ this.ApplyOperationContext();
+
var data = Global.DataContext;
var consumerRow = data.OAuthConsumers.Single(consumer => consumer.ConsumerKey == consumerKey);
var tokenRow = data.OAuthTokens.Single(token => token.Token == requestToken && token.OAuthConsumer == consumerRow);
@@ -115,6 +127,7 @@ namespace OAuthServiceProvider.Code {
/// <param name="token">The token to classify.</param>
/// <returns>Request or Access token, or invalid if the token is not recognized.</returns>
public TokenType GetTokenType(string token) {
+ this.ApplyOperationContext();
var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(tokenCandidate => tokenCandidate.Token == token);
if (tokenRow == null) {
return TokenType.InvalidToken;
@@ -135,6 +148,7 @@ namespace OAuthServiceProvider.Code {
throw new ArgumentNullException("user");
}
+ this.ApplyOperationContext();
var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(
tokenCandidate => tokenCandidate.Token == requestToken &&
tokenCandidate.State == TokenAuthorizationState.UnauthorizedRequestToken);
@@ -151,6 +165,7 @@ namespace OAuthServiceProvider.Code {
throw new ArgumentNullException("requestToken");
}
+ this.ApplyOperationContext();
var tokenRow = Global.DataContext.OAuthTokens.SingleOrDefault(
tokenCandidate => tokenCandidate.Token == token);
if (tokenRow == null) {
@@ -159,5 +174,11 @@ namespace OAuthServiceProvider.Code {
return tokenRow.OAuthConsumer;
}
+
+ private void ApplyOperationContext() {
+ if (this.OperationContext != null && OperationContext.Current == null) {
+ OperationContext.Current = this.OperationContext;
+ }
+ }
}
} \ No newline at end of file
diff --git a/samples/OAuthServiceProvider/Code/Global.cs b/samples/OAuthServiceProvider/Code/Global.cs
index 60fed9f..37206ab 100644
--- a/samples/OAuthServiceProvider/Code/Global.cs
+++ b/samples/OAuthServiceProvider/Code/Global.cs
@@ -10,6 +10,10 @@
/// The web application global events and properties.
/// </summary>
public class Global : HttpApplication {
+ private readonly object syncObject = new object();
+
+ private volatile bool initialized;
+
/// <summary>
/// An application memory cache of recent log messages.
/// </summary>
@@ -95,17 +99,6 @@
private void Application_Start(object sender, EventArgs e) {
log4net.Config.XmlConfigurator.Configure();
Logger.Info("Sample starting...");
- string appPath = HttpContext.Current.Request.ApplicationPath;
- if (!appPath.EndsWith("/")) {
- appPath += "/";
- }
-
- // This will break in IIS Integrated Pipeline mode, since applications
- // start before the first incoming request context is available.
- // TODO: fix this.
- Constants.WebRootUrl = new Uri(HttpContext.Current.Request.Url, appPath);
- Global.TokenManager = new DatabaseTokenManager();
- Global.NonceStore = new DatabaseNonceStore();
}
private void Application_End(object sender, EventArgs e) {
@@ -128,8 +121,30 @@
}
}
+ private void Application_BeginRequest(object sender, EventArgs e) {
+ this.EnsureInitialized();
+ }
+
private void Application_EndRequest(object sender, EventArgs e) {
CommitAndCloseDatabaseIfNecessary();
}
+
+ private void EnsureInitialized() {
+ if (!this.initialized) {
+ lock (this.syncObject) {
+ if (!this.initialized) {
+ string appPath = HttpContext.Current.Request.ApplicationPath;
+ if (!appPath.EndsWith("/")) {
+ appPath += "/";
+ }
+
+ Constants.WebRootUrl = new Uri(HttpContext.Current.Request.Url, appPath);
+ Global.TokenManager = new DatabaseTokenManager();
+ Global.NonceStore = new DatabaseNonceStore();
+ this.initialized = true;
+ }
+ }
+ }
+ }
}
} \ No newline at end of file
diff --git a/samples/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs b/samples/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs
index cf28c15..2d942b5 100644
--- a/samples/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs
+++ b/samples/OAuthServiceProvider/Code/OAuthAuthorizationManager.cs
@@ -26,6 +26,7 @@
HttpRequestMessageProperty httpDetails = operationContext.RequestContext.RequestMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
Uri requestUri = operationContext.RequestContext.RequestMessage.Properties.Via;
ServiceProvider sp = Constants.CreateServiceProvider();
+ ((DatabaseTokenManager)sp.TokenManager).OperationContext = operationContext; // artificially preserve this across thread changes.
return Task.Run(
async delegate {
try {
diff --git a/samples/OAuthServiceProvider/Login.aspx b/samples/OAuthServiceProvider/Login.aspx
index 4498ee0..0b84ab9 100644
--- a/samples/OAuthServiceProvider/Login.aspx
+++ b/samples/OAuthServiceProvider/Login.aspx
@@ -1,4 +1,4 @@
-<%@ Page Title="Login" Language="C#" MasterPageFile="~/MasterPage.master" %>
+<%@ Page Title="Login" Language="C#" MasterPageFile="~/MasterPage.master" Async="true" %>
<%@ Register Assembly="DotNetOpenAuth.OpenId.RelyingParty.UI" Namespace="DotNetOpenAuth.OpenId.RelyingParty" TagPrefix="rp" %>
diff --git a/samples/OAuthServiceProvider/OAuth.ashx b/samples/OAuthServiceProvider/OAuth.ashx
index 8a74926..7b3dc75 100644
--- a/samples/OAuthServiceProvider/OAuth.ashx
+++ b/samples/OAuthServiceProvider/OAuth.ashx
@@ -2,41 +2,45 @@
using System;
using System.Linq;
+using System.Threading.Tasks;
using System.Web;
using System.Web.SessionState;
+using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
using DotNetOpenAuth.Messaging;
using OAuthServiceProvider.Code;
-public class OAuth : IHttpHandler, IRequiresSessionState {
+public class OAuth : HttpAsyncHandlerBase, IRequiresSessionState {
ServiceProvider sp;
public OAuth() {
sp = new ServiceProvider(Constants.SelfDescription, Global.TokenManager, new CustomOAuthMessageFactory(Global.TokenManager));
}
- public void ProcessRequest(HttpContext context) {
- IProtocolMessage request = sp.ReadRequest();
+ public override bool IsReusable {
+ get { return true; }
+ }
+
+ protected override async Task ProcessRequestAsync(HttpContext context) {
+ IProtocolMessage request = await sp.ReadRequestAsync();
RequestScopedTokenMessage requestToken;
UserAuthorizationRequest requestAuth;
AuthorizedTokenRequest requestAccessToken;
if ((requestToken = request as RequestScopedTokenMessage) != null) {
var response = sp.PrepareUnauthorizedTokenMessage(requestToken);
- sp.Channel.Send(response);
+ var responseMessage = await sp.Channel.PrepareResponseAsync(response);
+ await responseMessage.SendAsync(new HttpResponseWrapper(context.Response));
} else if ((requestAuth = request as UserAuthorizationRequest) != null) {
Global.PendingOAuthAuthorization = requestAuth;
HttpContext.Current.Response.Redirect("~/Members/Authorize.aspx");
} else if ((requestAccessToken = request as AuthorizedTokenRequest) != null) {
var response = sp.PrepareAccessTokenMessage(requestAccessToken);
- sp.Channel.Send(response);
+ var responseMessage = await sp.Channel.PrepareResponseAsync(response);
+ await responseMessage.SendAsync(new HttpResponseWrapper(context.Response));
} else {
throw new InvalidOperationException();
}
}
-
- public bool IsReusable {
- get { return true; }
- }
}
diff --git a/samples/OAuthServiceProvider/OAuthServiceProvider.csproj b/samples/OAuthServiceProvider/OAuthServiceProvider.csproj
index 2be5873..65d5a1f 100644
--- a/samples/OAuthServiceProvider/OAuthServiceProvider.csproj
+++ b/samples/OAuthServiceProvider/OAuthServiceProvider.csproj
@@ -26,7 +26,7 @@
<RootNamespace>OAuthServiceProvider</RootNamespace>
<AssemblyName>OAuthServiceProvider</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <UseIISExpress>false</UseIISExpress>
+ <UseIISExpress>true</UseIISExpress>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -190,6 +190,10 @@
<Project>{3896A32A-E876-4C23-B9B8-78E17D134CD3}</Project>
<Name>DotNetOpenAuth.OpenId</Name>
</ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.ApplicationBlock\DotNetOpenAuth.ApplicationBlock.csproj">
+ <Project>{aa78d112-d889-414b-a7d4-467b34c7b663}</Project>
+ <Name>DotNetOpenAuth.ApplicationBlock</Name>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
@@ -198,12 +202,11 @@
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
- <UseIIS>False</UseIIS>
+ <UseIIS>True</UseIIS>
<AutoAssignPort>False</AutoAssignPort>
<DevelopmentServerPort>65169</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
- <IISUrl>
- </IISUrl>
+ <IISUrl>http://localhost:65169/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
diff --git a/samples/OAuthServiceProvider/Web.config b/samples/OAuthServiceProvider/Web.config
index 51e9ca9..84aea1e 100644
--- a/samples/OAuthServiceProvider/Web.config
+++ b/samples/OAuthServiceProvider/Web.config
@@ -58,7 +58,8 @@
-->
<compilation debug="true" targetFramework="4.0">
<assemblies>
- <add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
+ <add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
+ <add assembly="System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</assemblies>
</compilation>
<authentication mode="Forms">
diff --git a/samples/OpenIdProviderWebForms/Provider.ashx.cs b/samples/OpenIdProviderWebForms/Provider.ashx.cs
index 8022aae..d5d747b 100644
--- a/samples/OpenIdProviderWebForms/Provider.ashx.cs
+++ b/samples/OpenIdProviderWebForms/Provider.ashx.cs
@@ -4,9 +4,9 @@
using System.Threading.Tasks;
using System.Web;
using System.Web.SessionState;
+ using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Provider;
-
using OpenIdProviderWebForms.Code;
/// <summary>
@@ -18,12 +18,12 @@
/// control to reduce the amount of source code in the web site. A typical Provider
/// site will have EITHER this .ashx handler OR the .aspx page -- NOT both.
/// </remarks>
- public class Provider : IHttpAsyncHandler, IRequiresSessionState {
- public bool IsReusable {
+ public class Provider : HttpAsyncHandlerBase, IRequiresSessionState {
+ public override bool IsReusable {
get { return true; }
}
- private async Task ProcessRequestAsync(HttpContext context) {
+ protected override async Task ProcessRequestAsync(HttpContext context) {
IRequest request = await ProviderEndpoint.Provider.GetRequestAsync(new HttpRequestWrapper(context.Request), context.Response.ClientDisconnectedToken);
if (request != null) {
// Some OpenID requests are automatable and can be responded to immediately.
@@ -66,17 +66,5 @@
}
}
}
-
- public IAsyncResult BeginProcessRequest(HttpContext context, System.AsyncCallback cb, object extraData) {
- return this.ProcessRequestAsync(context).ToApm(cb, extraData);
- }
-
- public void EndProcessRequest(IAsyncResult result) {
- ((Task)result).Wait(); // rethrows exceptions
- }
-
- public void ProcessRequest(HttpContext context) {
- this.ProcessRequestAsync(context).GetAwaiter().GetResult();
- }
}
}
diff --git a/samples/OpenIdProviderWebForms/access_token.ashx.cs b/samples/OpenIdProviderWebForms/access_token.ashx.cs
index afee82c..8dccc3f 100644
--- a/samples/OpenIdProviderWebForms/access_token.ashx.cs
+++ b/samples/OpenIdProviderWebForms/access_token.ashx.cs
@@ -2,22 +2,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Services;
- using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
using OpenIdProviderWebForms.Code;
- using System.Threading;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
- public class access_token : IHttpAsyncHandler {
- public bool IsReusable {
+ public class access_token : HttpAsyncHandlerBase {
+ public override bool IsReusable {
get { return true; }
}
- public async Task ProcessRequestAsync(HttpContext context) {
+ protected override async Task ProcessRequestAsync(HttpContext context) {
var request = await OAuthHybrid.ServiceProvider.ReadAccessTokenRequestAsync(
new HttpRequestWrapper(context.Request),
context.Response.ClientDisconnectedToken);
@@ -27,17 +28,5 @@
context.Response.ClientDisconnectedToken);
await httpResponseMessage.SendAsync();
}
-
- public void ProcessRequest(HttpContext context) {
- this.ProcessRequestAsync(context).GetAwaiter().GetResult();
- }
-
- public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
- return this.ProcessRequestAsync(context).ToApm(cb, extraData);
- }
-
- public void EndProcessRequest(IAsyncResult result) {
- ((Task)result).Wait(); // rethrows exceptions
- }
}
}