summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2009-11-10 21:00:37 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2009-11-10 21:00:37 -0800
commit6df46c9875f82f5a5f94a082a0b699fde2978d6f (patch)
tree56df88c1a4fe02a363e5a0d7d087c1947322ab09
parent5d4d80b4a83bb9d6af62cc5f6d78f6f7e541e67d (diff)
downloadDotNetOpenAuth-6df46c9875f82f5a5f94a082a0b699fde2978d6f.zip
DotNetOpenAuth-6df46c9875f82f5a5f94a082a0b699fde2978d6f.tar.gz
DotNetOpenAuth-6df46c9875f82f5a5f94a082a0b699fde2978d6f.tar.bz2
Added a bunch more OAuth SP supporting code, but it's not done yet.
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs117
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs26
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/Utilities.cs66
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx20
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs41
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs52
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.Consumer.cs8
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.Designer.cs25
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs8
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs35
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.User.cs8
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.edmx5
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuth.ashx1
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs65
-rw-r--r--projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj15
15 files changed, 485 insertions, 7 deletions
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs
new file mode 100644
index 0000000..473b6d2
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthServiceProvider.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+
+ public class OAuthServiceProvider {
+ private const string PendingAuthorizationRequestSessionKey = "PendingAuthorizationRequest";
+
+ /// <summary>
+ /// The shared service description for this web site.
+ /// </summary>
+ private static ServiceProviderDescription serviceDescription;
+
+ private static OAuthServiceProviderTokenManager tokenManager;
+
+ /// <summary>
+ /// The shared service provider object.
+ /// </summary>
+ private static ServiceProvider serviceProvider;
+
+ /// <summary>
+ /// The lock to synchronize initialization of the <see cref="serviceProvider"/> field.
+ /// </summary>
+ private static object initializerLock = new object();
+
+ /// <summary>
+ /// Gets the service provider.
+ /// </summary>
+ /// <value>The service provider.</value>
+ public static ServiceProvider ServiceProvider {
+ get {
+ EnsureInitialized();
+ return serviceProvider;
+ }
+ }
+
+ /// <summary>
+ /// Gets the service description.
+ /// </summary>
+ /// <value>The service description.</value>
+ public static ServiceProviderDescription ServiceDescription {
+ get {
+ EnsureInitialized();
+ return serviceDescription;
+ }
+ }
+
+ public static UserAuthorizationRequest PendingAuthorizationRequest {
+ get { return HttpContext.Current.Session[PendingAuthorizationRequestSessionKey] as UserAuthorizationRequest; }
+ set { HttpContext.Current.Session[PendingAuthorizationRequestSessionKey] = value; }
+ }
+
+ public static WebFormsRelyingParty.Consumer PendingAuthorizationConsumer {
+ get {
+ ITokenContainingMessage message = PendingAuthorizationRequest;
+ if (message == null) {
+ throw new InvalidOperationException();
+ }
+
+ return Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().First(t => t.Token == message.Token).Consumer;
+ }
+ }
+
+ public static void AuthorizePendingRequestToken() {
+ var pendingRequest = PendingAuthorizationRequest;
+ if (pendingRequest == null) {
+ throw new InvalidOperationException("No pending authorization request to authorize.");
+ }
+
+ ITokenContainingMessage msg = pendingRequest;
+ var token = Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().First(t => t.Token == msg.Token);
+ token.Authorize();
+
+ var response = serviceProvider.PrepareAuthorizationResponse(pendingRequest);
+ serviceProvider.Channel.Send(response);
+ PendingAuthorizationRequest = null;
+ }
+
+ /// <summary>
+ /// Initializes the <see cref="serviceProvider"/> field if it has not yet been initialized.
+ /// </summary>
+ private static void EnsureInitialized() {
+ if (serviceProvider == null) {
+ lock (initializerLock) {
+ if (serviceDescription == null) {
+ var endpoint = new MessageReceivingEndpoint(Utilities.ApplicationRoot + "OAuth.ashx", HttpDeliveryMethods.PostRequest);
+ serviceDescription = new ServiceProviderDescription {
+ TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
+ RequestTokenEndpoint = endpoint,
+ AccessTokenEndpoint = endpoint,
+ UserAuthorizationEndpoint = endpoint,
+ };
+ }
+
+ if (tokenManager == null) {
+ tokenManager = new OAuthServiceProviderTokenManager();
+ }
+
+ if (serviceProvider == null) {
+ serviceProvider = new ServiceProvider(serviceDescription, tokenManager);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
index 653d791..d9c04bd 100644
--- a/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
@@ -75,18 +75,42 @@ namespace WebFormsRelyingParty.Code {
Global.DataContext.SaveChanges();
}
+ /// <summary>
+ /// Deletes a request token and its associated secret and stores a new access token and secret.
+ /// </summary>
+ /// <param name="consumerKey">The Consumer that is exchanging its request token for an access token.</param>
+ /// <param name="requestToken">The Consumer's request token that should be deleted/expired.</param>
+ /// <param name="accessToken">The new access token that is being issued to the Consumer.</param>
+ /// <param name="accessTokenSecret">The secret associated with the newly issued access token.</param>
+ /// <remarks>
+ /// <para>
+ /// Any scope of granted privileges associated with the request token from the
+ /// original call to <see cref="StoreNewRequestToken"/> should be carried over
+ /// to the new Access Token.
+ /// </para>
+ /// <para>
+ /// To associate a user account with the new access token,
+ /// <see cref="System.Web.HttpContext.User">HttpContext.Current.User</see> may be
+ /// useful in an ASP.NET web application within the implementation of this method.
+ /// Alternatively you may store the access token here without associating with a user account,
+ /// and wait until <see cref="WebConsumer.ProcessUserAuthorization()"/> or
+ /// <see cref="DesktopConsumer.ProcessUserAuthorization(string, string)"/> return the access
+ /// token to associate the access token with a user account at that point.
+ /// </para>
+ /// </remarks>
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
var requestTokenEntity = Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().First(
t => t.Consumer.ConsumerKey == consumerKey && t.Token == requestToken);
- Global.DataContext.DeleteObject(requestTokenEntity);
var accessTokenEntity = new IssuedAccessToken {
Token = accessToken,
TokenSecret = accessTokenSecret,
ExpirationDate = null, // currently, our access tokens don't expire
CreatedOn = DateTime.Now,
+ User = requestTokenEntity.User,
};
+ Global.DataContext.DeleteObject(requestTokenEntity);
Global.DataContext.AddToIssuedToken(accessTokenEntity);
Global.DataContext.SaveChanges();
}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs b/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs
new file mode 100644
index 0000000..b9c9f43
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+// <copyright file="Utilities.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Web;
+
+ public static class Utilities {
+ private static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider();
+
+ public static string ApplicationRoot {
+ get {
+ string appRoot = HttpContext.Current.Request.ApplicationPath;
+ if (!appRoot.EndsWith("/", StringComparison.Ordinal)) {
+ appRoot += "/";
+ }
+
+ return appRoot;
+ }
+ }
+
+ public static string SetCsrfCookie() {
+ // Generate an unpredictable secret that goes to the user agent and must come back
+ // with authorization to guarantee the user interacted with this page rather than
+ // being scripted by an evil Consumer.
+ byte[] randomData = new byte[8];
+ CryptoRandomDataGenerator.GetBytes(randomData);
+ string secret = Convert.ToBase64String(randomData);
+
+ // Send the secret down as a cookie...
+ var cookie = new HttpCookie("CsrfCookie", secret) {
+ Path = HttpContext.Current.Request.Path,
+ HttpOnly = true,
+ Expires = DateTime.Now.AddMinutes(30),
+ };
+ HttpContext.Current.Response.SetCookie(cookie);
+
+ // ...and also return the secret so the caller can save it as a hidden form field.
+ return secret;
+ }
+
+ public static void VerifyCsrfCookie(string secret) {
+ var cookie = HttpContext.Current.Request.Cookies["CsrfCookie"];
+ if (cookie != null) {
+ if (cookie.Value == secret) {
+ // Valid CSRF check. Clear the cookie and return.
+ cookie.Expires = DateTime.Now.Subtract(TimeSpan.FromDays(1));
+ cookie.Value = string.Empty;
+ if (HttpContext.Current.Request.Browser["supportsEmptyStringInCookieValue"] == "false") {
+ cookie.Value = "NoCookie";
+ }
+ HttpContext.Current.Response.SetCookie(cookie);
+ return;
+ }
+ }
+
+ throw new InvalidOperationException("Invalid CSRF check.");
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx
new file mode 100644
index 0000000..720c4b2
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx
@@ -0,0 +1,20 @@
+<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
+ CodeBehind="OAuthAuthorize.aspx.cs" Inherits="WebFormsRelyingParty.Members.OAuthAuthorize" %>
+
+<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
+</asp:Content>
+<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="server">
+ <h2>
+ Client authorization</h2>
+ <p>
+ The
+ <asp:Label ID="consumerNameLabel" runat="server" Text="(app name)" />
+ application is requesting to access the private data in your account here. Is that
+ alright with you?
+ </p>
+ <asp:Button ID="yesButton" runat="server" Text="Yes"
+ onclick="yesButton_Click" />
+ &nbsp;<asp:Button ID="noButton" runat="server" Text="No"
+ onclick="noButton_Click" />
+ <asp:HiddenField runat="server" ID="csrfCheck" EnableViewState="false" />
+</asp:Content>
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs
new file mode 100644
index 0000000..4ffb9b8
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthAuthorize.aspx.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Members {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using System.Web.UI;
+ using System.Web.UI.WebControls;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.Messages;
+ using WebFormsRelyingParty.Code;
+
+ public partial class OAuthAuthorize : System.Web.UI.Page {
+ protected void Page_Load(object sender, EventArgs e) {
+ if (!IsPostBack) {
+ if (OAuthServiceProvider.PendingAuthorizationRequest == null) {
+ Response.Redirect("~/");
+ }
+
+ this.csrfCheck.Value = Utilities.SetCsrfCookie();
+ this.consumerNameLabel.Text = HttpUtility.HtmlEncode(OAuthServiceProvider.PendingAuthorizationConsumer.Name);
+ } else {
+ Utilities.VerifyCsrfCookie(this.csrfCheck.Value);
+ }
+ }
+
+ protected void yesButton_Click(object sender, EventArgs e) {
+ OAuthServiceProvider.AuthorizePendingRequestToken();
+ }
+
+ protected void noButton_Click(object sender, EventArgs e) {
+ OAuthServiceProvider.PendingAuthorizationRequest = null;
+ Response.Redirect("~/");
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs
new file mode 100644
index 0000000..719a853
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs
@@ -0,0 +1,52 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4927
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Members {
+
+
+ public partial class OAuthAuthorize {
+
+ /// <summary>
+ /// consumerNameLabel 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 consumerNameLabel;
+
+ /// <summary>
+ /// yesButton 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 yesButton;
+
+ /// <summary>
+ /// noButton 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 noButton;
+
+ /// <summary>
+ /// csrfCheck 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.HiddenField csrfCheck;
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Model.Consumer.cs b/projecttemplates/WebFormsRelyingParty/Model.Consumer.cs
index 20a1ccc..5076d6d 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.Consumer.cs
+++ b/projecttemplates/WebFormsRelyingParty/Model.Consumer.cs
@@ -1,4 +1,10 @@
-namespace WebFormsRelyingParty {
+//-----------------------------------------------------------------------
+// <copyright file="Model.Consumer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty {
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/projecttemplates/WebFormsRelyingParty/Model.Designer.cs b/projecttemplates/WebFormsRelyingParty/Model.Designer.cs
index 95ba3d3..85bd476 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.Designer.cs
+++ b/projecttemplates/WebFormsRelyingParty/Model.Designer.cs
@@ -15,7 +15,7 @@
[assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("DatabaseModel", "FK_IssuedToken_User", "User", global::System.Data.Metadata.Edm.RelationshipMultiplicity.ZeroOrOne, typeof(WebFormsRelyingParty.User), "IssuedTokens", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(WebFormsRelyingParty.IssuedToken))]
// Original file name:
-// Generation date: 11/10/2009 8:47:09 AM
+// Generation date: 11/10/2009 8:48:49 PM
namespace WebFormsRelyingParty
{
@@ -772,6 +772,29 @@ namespace WebFormsRelyingParty
partial void OnConsumerIdChanging(int value);
partial void OnConsumerIdChanged();
/// <summary>
+ /// There are no comments for Property Name in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string Name
+ {
+ get
+ {
+ return this._Name;
+ }
+ set
+ {
+ this.OnNameChanging(value);
+ this.ReportPropertyChanging("Name");
+ this._Name = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true);
+ this.ReportPropertyChanged("Name");
+ this.OnNameChanged();
+ }
+ }
+ private string _Name;
+ partial void OnNameChanging(string value);
+ partial void OnNameChanged();
+ /// <summary>
/// There are no comments for IssuedToken in the schema.
/// </summary>
[global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("DatabaseModel", "FK_IssuedToken_Consumer", "IssuedTokens")]
diff --git a/projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs b/projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs
index e47a9de..b2eb132 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs
+++ b/projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs
@@ -1,4 +1,10 @@
-namespace WebFormsRelyingParty {
+//-----------------------------------------------------------------------
+// <copyright file="Model.IssuedAccessToken.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty {
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs b/projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs
index 08378de..1352e54 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs
+++ b/projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs
@@ -1,4 +1,10 @@
-namespace WebFormsRelyingParty {
+//-----------------------------------------------------------------------
+// <copyright file="Model.IssuedRequestToken.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty {
using System;
using System.Collections.Generic;
using System.Linq;
@@ -6,18 +12,45 @@
using DotNetOpenAuth.OAuth.ChannelElements;
public partial class IssuedRequestToken : IServiceProviderRequestToken {
+ /// <summary>
+ /// Gets or sets the callback associated specifically with this token, if any.
+ /// </summary>
+ /// <value>
+ /// The callback URI; or <c>null</c> if no callback was specifically assigned to this token.
+ /// </value>
public Uri Callback {
get { return this.CallbackAsString != null ? new Uri(this.CallbackAsString) : null; }
set { this.CallbackAsString = value != null ? value.AbsoluteUri : null; }
}
+ /// <summary>
+ /// Gets or sets the version of the Consumer that requested this token.
+ /// </summary>
+ /// <remarks>
+ /// This property is used to determine whether a <see cref="VerificationCode"/> must be
+ /// generated when the user authorizes the Consumer or not.
+ /// </remarks>
Version IServiceProviderRequestToken.ConsumerVersion {
get { return this.ConsumerVersionAsString != null ? new Version(this.ConsumerVersionAsString) : null; }
set { this.ConsumerVersionAsString = value != null ? value.ToString() : null; }
}
+ /// <summary>
+ /// Gets the consumer key that requested this token.
+ /// </summary>
string IServiceProviderRequestToken.ConsumerKey {
get { return this.Consumer.ConsumerKey; }
}
+
+ /// <summary>
+ /// Authorizes this request token to allow exchange for an access token.
+ /// </summary>
+ /// <remarks>
+ /// Call this method when the user has completed web-based authorization.
+ /// </remarks>
+ public void Authorize() {
+ this.User = Global.LoggedInUser;
+ Global.DataContext.SaveChanges();
+ }
}
}
diff --git a/projecttemplates/WebFormsRelyingParty/Model.User.cs b/projecttemplates/WebFormsRelyingParty/Model.User.cs
index b2ea2f4..1493603 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.User.cs
+++ b/projecttemplates/WebFormsRelyingParty/Model.User.cs
@@ -1,4 +1,10 @@
-namespace WebFormsRelyingParty {
+//-----------------------------------------------------------------------
+// <copyright file="Model.User.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty {
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/projecttemplates/WebFormsRelyingParty/Model.edmx b/projecttemplates/WebFormsRelyingParty/Model.edmx
index d2eed5a..bae6c17 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.edmx
+++ b/projecttemplates/WebFormsRelyingParty/Model.edmx
@@ -53,6 +53,7 @@
<Property Name="Callback" Type="nvarchar" MaxLength="2048" />
<Property Name="VerificationCodeFormat" Type="int" Nullable="false" />
<Property Name="VerificationCodeLength" Type="int" Nullable="false" />
+ <Property Name="Name" Type="nvarchar" MaxLength="50" />
</EntityType>
<EntityType Name="IssuedToken">
<Key>
@@ -237,7 +238,8 @@
<Property Name="VerificationCodeFormatAsInt" Type="Int32" Nullable="false" />
<Property Name="VerificationCodeLength" Type="Int32" Nullable="false" />
<Property Name="ConsumerId" Type="Int32" Nullable="false" />
- <NavigationProperty Name="IssuedToken" Relationship="DatabaseModel.FK_IssuedToken_Consumer" FromRole="Consumer" ToRole="IssuedTokens" /></EntityType>
+ <NavigationProperty Name="IssuedToken" Relationship="DatabaseModel.FK_IssuedToken_Consumer" FromRole="Consumer" ToRole="IssuedTokens" />
+ <Property Name="Name" Type="String" Nullable="true" /></EntityType>
<EntityType Name="IssuedToken" Abstract="true">
<Key>
<PropertyRef Name="TokenId" /></Key>
@@ -307,6 +309,7 @@
<EntitySetMapping Name="Consumer">
<EntityTypeMapping TypeName="IsTypeOf(DatabaseModel.Consumer)">
<MappingFragment StoreEntitySet="Consumer">
+ <ScalarProperty Name="Name" ColumnName="Name" />
<ScalarProperty Name="ConsumerId" ColumnName="ConsumerId" />
<ScalarProperty Name="VerificationCodeLength" ColumnName="VerificationCodeLength" />
<ScalarProperty Name="VerificationCodeFormatAsInt" ColumnName="VerificationCodeFormat" />
diff --git a/projecttemplates/WebFormsRelyingParty/OAuth.ashx b/projecttemplates/WebFormsRelyingParty/OAuth.ashx
new file mode 100644
index 0000000..6176757
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/OAuth.ashx
@@ -0,0 +1 @@
+<%@ WebHandler Language="C#" CodeBehind="OAuth.ashx.cs" Class="WebFormsRelyingParty.OAuth" %>
diff --git a/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs b/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs
new file mode 100644
index 0000000..faf0888
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuth.ashx.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.Messages;
+ using WebFormsRelyingParty.Code;
+
+ /// <summary>
+ /// Responds to incoming OAuth Service Provider messages.
+ /// </summary>
+ public class OAuth : IHttpHandler {
+ /// <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("~/Members/OAuthAuthorize.aspx");
+ } else {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
index afd2cec..0129010 100644
--- a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
+++ b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
@@ -88,9 +88,18 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Code\OAuthConsumerTokenManager.cs" />
+ <Compile Include="Code\OAuthServiceProvider.cs" />
<Compile Include="Code\OAuthServiceProviderTokenManager.cs" />
<Compile Include="Code\OAuthTokenManager.cs" />
<Compile Include="Code\Policies.cs" />
+ <Compile Include="Code\Utilities.cs" />
+ <Compile Include="Members\OAuthAuthorize.aspx.cs">
+ <DependentUpon>OAuthAuthorize.aspx</DependentUpon>
+ <SubType>ASPXCodeBehind</SubType>
+ </Compile>
+ <Compile Include="Members\OAuthAuthorize.aspx.designer.cs">
+ <DependentUpon>OAuthAuthorize.aspx</DependentUpon>
+ </Compile>
<Compile Include="Model.IssuedRequestToken.cs" />
<Compile Include="Model.IssuedAccessToken.cs" />
<Compile Include="Model.Consumer.cs" />
@@ -160,6 +169,9 @@
<DesignTime>True</DesignTime>
<DependentUpon>Model.edmx</DependentUpon>
</Compile>
+ <Compile Include="OAuth.ashx.cs">
+ <DependentUpon>OAuth.ashx</DependentUpon>
+ </Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<EntityDeploy Include="Model.edmx">
<Generator>EntityModelCodeGenerator</Generator>
@@ -251,6 +263,9 @@
</ItemGroup>
<ItemGroup>
<None Include="Admin\CreateDatabase.sql" />
+ <Content Include="bin\Microsoft.Contracts.dll" />
+ <Content Include="Members\OAuthAuthorize.aspx" />
+ <Content Include="OAuth.ashx" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\DotNetOpenAuth\DotNetOpenAuth.csproj">