summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2009-11-13 01:18:20 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2009-11-13 01:18:20 -0800
commitb929b5106a544c10b6736640b86397938790f523 (patch)
tree9e3cd58afc20cb4804b0ee37ec8df13cdb48821d
parent75737b85f5dce833c4fed0b1c839150fc1e6c3dc (diff)
parentb71f75b5a02a72e13a6934524626ac21763ea87f (diff)
downloadDotNetOpenAuth-b929b5106a544c10b6736640b86397938790f523.zip
DotNetOpenAuth-b929b5106a544c10b6736640b86397938790f523.tar.gz
DotNetOpenAuth-b929b5106a544c10b6736640b86397938790f523.tar.bz2
Merge branch 'projecttemplateOAuth'
-rw-r--r--projecttemplates/WebFormsRelyingParty/Admin/CreateDatabase.sql99
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthAuthenticationModule.cs78
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthAuthorizationManager.cs67
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthConsumerTokenManager.cs48
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthPrincipalAuthorizationPolicy.cs53
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs120
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProviderTokenManager.cs112
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs143
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/Utilities.cs70
-rw-r--r--projecttemplates/WebFormsRelyingParty/Global.asax.cs1
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx67
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs63
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs133
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/Web.config9
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.Consumer.cs40
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.Designer.cs651
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs58
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs56
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.User.cs8
-rw-r--r--projecttemplates/WebFormsRelyingParty/Model.edmx179
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuth.ashx1
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs66
-rw-r--r--projecttemplates/WebFormsRelyingParty/Web.config24
-rw-r--r--projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj24
-rw-r--r--samples/OAuthConsumerWpf/MainWindow.xaml61
-rw-r--r--samples/OAuthConsumerWpf/MainWindow.xaml.cs49
-rw-r--r--samples/OAuthServiceProvider/App_Code/Global.cs10
27 files changed, 2266 insertions, 24 deletions
diff --git a/projecttemplates/WebFormsRelyingParty/Admin/CreateDatabase.sql b/projecttemplates/WebFormsRelyingParty/Admin/CreateDatabase.sql
index 2030155..52ca669 100644
--- a/projecttemplates/WebFormsRelyingParty/Admin/CreateDatabase.sql
+++ b/projecttemplates/WebFormsRelyingParty/Admin/CreateDatabase.sql
@@ -1,13 +1,36 @@
-/****** Object: Table [dbo].[User] Script Date: 10/08/2009 18:10:17 ******/
+SET ANSI_NULLS ON
+GO
+SET QUOTED_IDENTIFIER ON
+GO
+CREATE TABLE [dbo].[Consumer](
+ [ConsumerId] [int] IDENTITY(1,1) NOT NULL,
+ [ConsumerKey] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
+ [ConsumerSecret] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ [X509Certificate] [image] NULL,
+ [Callback] [nvarchar](2048) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ [VerificationCodeFormat] [int] NOT NULL,
+ [VerificationCodeLength] [int] NOT NULL,
+ [Name] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ CONSTRAINT [PK_Consumer] PRIMARY KEY CLUSTERED
+(
+ [ConsumerId] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+CREATE UNIQUE NONCLUSTERED INDEX [IX_Consumer] ON [dbo].[Consumer]
+(
+ [ConsumerKey] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[User](
[Id] [int] IDENTITY(1,1) NOT NULL,
- [FirstName] [nvarchar](50) NULL,
- [LastName] [nvarchar](50) NULL,
- [EmailAddress] [nvarchar](100) NULL,
+ [FirstName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ [LastName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ [EmailAddress] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[EmailAddressVerified] [bit] NOT NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
@@ -15,24 +38,51 @@ CREATE TABLE [dbo].[User](
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
-ALTER TABLE [dbo].[User] ADD CONSTRAINT [DF_User_EmailAddressVerified] DEFAULT ((0)) FOR [EmailAddressVerified]
-GO
-
-/****** Object: Table [dbo].[Role] Script Date: 10/08/2009 18:10:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Role](
[Id] [int] IDENTITY(1,1) NOT NULL,
- [Name] [nvarchar](50) NOT NULL,
+ [Name] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_Role] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
-/****** Object: Table [dbo].[UserRole] Script Date: 10/08/2009 18:10:17 ******/
+SET ANSI_NULLS ON
+GO
+SET QUOTED_IDENTIFIER ON
+GO
+SET ANSI_PADDING ON
+GO
+CREATE TABLE [dbo].[IssuedToken](
+ [TokenId] [int] IDENTITY(1,1) NOT NULL,
+ [ConsumerId] [int] NOT NULL,
+ [UserId] [int] NULL,
+ [Token] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
+ [TokenSecret] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
+ [CreatedOn] [datetime] NOT NULL,
+ [Callback] [nvarchar](2048) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ [VerificationCode] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ [ConsumerVersion] [varchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ [ExpirationDate] [datetime] NULL,
+ [IsAccessToken] [bit] NOT NULL,
+ [Scope] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
+ CONSTRAINT [PK_IssuedToken] PRIMARY KEY CLUSTERED
+(
+ [TokenId] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+SET ANSI_PADDING OFF
+GO
+CREATE UNIQUE NONCLUSTERED INDEX [IX_IssuedToken] ON [dbo].[IssuedToken]
+(
+ [Token] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
@@ -47,7 +97,6 @@ CREATE TABLE [dbo].[UserRole](
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
-/****** Object: Table [dbo].[AuthenticationToken] Script Date: 10/08/2009 18:10:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
@@ -55,15 +104,14 @@ GO
CREATE TABLE [dbo].[AuthenticationToken](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NOT NULL,
- [OpenIdClaimedIdentifier] [nvarchar](250) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL, -- very important that claimed_id comparisons be case sensitive
- [OpenIdFriendlyIdentifier] [nvarchar](250) NULL,
+ [OpenIdClaimedIdentifier] [nvarchar](250) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
+ [OpenIdFriendlyIdentifier] [nvarchar](250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_AuthenticationToken] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
-/****** Object: StoredProcedure [dbo].[AddUser] Script Date: 10/08/2009 18:10:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
@@ -106,7 +154,26 @@ AS
RETURN @userid
GO
-/****** Object: ForeignKey [FK_UserRole_Role] Script Date: 10/08/2009 18:10:17 ******/
+ALTER TABLE [dbo].[User] ADD CONSTRAINT [DF_User_EmailAddressVerified] DEFAULT ((0)) FOR [EmailAddressVerified]
+GO
+ALTER TABLE [dbo].[IssuedToken] ADD CONSTRAINT [DF_IssuedToken_CreatedOn] DEFAULT (getdate()) FOR [CreatedOn]
+GO
+ALTER TABLE [dbo].[IssuedToken] ADD CONSTRAINT [DF_IssuedToken_IsAccessToken] DEFAULT ((0)) FOR [IsAccessToken]
+GO
+ALTER TABLE [dbo].[IssuedToken] WITH CHECK ADD CONSTRAINT [FK_IssuedToken_Consumer] FOREIGN KEY([ConsumerId])
+REFERENCES [dbo].[Consumer] ([ConsumerId])
+ON UPDATE CASCADE
+ON DELETE CASCADE
+GO
+ALTER TABLE [dbo].[IssuedToken] CHECK CONSTRAINT [FK_IssuedToken_Consumer]
+GO
+ALTER TABLE [dbo].[IssuedToken] WITH CHECK ADD CONSTRAINT [FK_IssuedToken_User] FOREIGN KEY([UserId])
+REFERENCES [dbo].[User] ([Id])
+ON UPDATE CASCADE
+ON DELETE CASCADE
+GO
+ALTER TABLE [dbo].[IssuedToken] CHECK CONSTRAINT [FK_IssuedToken_User]
+GO
ALTER TABLE [dbo].[UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_Role] FOREIGN KEY([RoleId])
REFERENCES [dbo].[Role] ([Id])
ON UPDATE CASCADE
@@ -114,7 +181,6 @@ ON DELETE CASCADE
GO
ALTER TABLE [dbo].[UserRole] CHECK CONSTRAINT [FK_UserRole_Role]
GO
-/****** Object: ForeignKey [FK_UserRole_User] Script Date: 10/08/2009 18:10:17 ******/
ALTER TABLE [dbo].[UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([Id])
ON UPDATE CASCADE
@@ -122,7 +188,6 @@ ON DELETE CASCADE
GO
ALTER TABLE [dbo].[UserRole] CHECK CONSTRAINT [FK_UserRole_User]
GO
-/****** Object: ForeignKey [FK_AuthenticationToken_User] Script Date: 10/08/2009 18:10:17 ******/
ALTER TABLE [dbo].[AuthenticationToken] WITH CHECK ADD CONSTRAINT [FK_AuthenticationToken_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([Id])
ON UPDATE CASCADE
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthAuthenticationModule.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthAuthenticationModule.cs
new file mode 100644
index 0000000..426dce5
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthAuthenticationModule.cs
@@ -0,0 +1,78 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthAuthenticationModule.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.Principal;
+ using System.Web;
+ using System.Web.Security;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+
+ public class OAuthAuthenticationModule : IHttpModule {
+ private HttpApplication application;
+
+ #region IHttpModule Members
+
+ /// <summary>
+ /// Initializes a module and prepares it to handle requests.
+ /// </summary>
+ /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>
+ public void Init(HttpApplication context) {
+ this.application = context;
+ this.application.AuthenticateRequest += this.context_AuthenticateRequest;
+
+ // Register an event that allows us to override roles for OAuth requests.
+ var roleManager = (RoleManagerModule)this.application.Modules["RoleManager"];
+ roleManager.GetRoles += this.roleManager_GetRoles;
+ }
+
+ /// <summary>
+ /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
+ /// </summary>
+ public void Dispose() {
+ }
+
+ /// <summary>
+ /// Handles the AuthenticateRequest event of the HttpApplication.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+ private void context_AuthenticateRequest(object sender, EventArgs e) {
+ // Don't read OAuth messages directed at the OAuth controller or else we'll fail nonce checks.
+ if (this.IsOAuthControllerRequest()) {
+ return;
+ }
+
+ IDirectedProtocolMessage incomingMessage = OAuthServiceProvider.ServiceProvider.ReadRequest(new HttpRequestInfo(this.application.Context.Request));
+ var authorization = incomingMessage as AccessProtectedResourceRequest;
+ if (authorization != null) {
+ this.application.Context.User = OAuthServiceProvider.ServiceProvider.CreatePrincipal(authorization);
+ }
+ }
+
+ #endregion
+
+ private bool IsOAuthControllerRequest() {
+ return string.Equals(this.application.Context.Request.Url.AbsolutePath, "/OAuth.ashx", StringComparison.OrdinalIgnoreCase);
+ }
+
+ /// <summary>
+ /// Handles the GetRoles event of the roleManager control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="System.Web.Security.RoleManagerEventArgs"/> instance containing the event data.</param>
+ private void roleManager_GetRoles(object sender, RoleManagerEventArgs e) {
+ if (this.application.User is OAuthPrincipal) {
+ e.RolesPopulated = true;
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthAuthorizationManager.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthAuthorizationManager.cs
new file mode 100644
index 0000000..480e1b9
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthAuthorizationManager.cs
@@ -0,0 +1,67 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthAuthorizationManager.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.IdentityModel.Policy;
+ using System.Linq;
+ using System.Security.Principal;
+ using System.ServiceModel;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Security;
+ using DotNetOpenAuth;
+ using DotNetOpenAuth.OAuth;
+
+ /// <summary>
+ /// A WCF extension to authenticate incoming messages using OAuth.
+ /// </summary>
+ public class OAuthAuthorizationManager : ServiceAuthorizationManager {
+ public OAuthAuthorizationManager() {
+ }
+
+ protected override bool CheckAccessCore(OperationContext operationContext) {
+ if (!base.CheckAccessCore(operationContext)) {
+ return false;
+ }
+
+ HttpRequestMessageProperty httpDetails = operationContext.RequestContext.RequestMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
+ Uri requestUri = operationContext.RequestContext.RequestMessage.Properties["OriginalHttpRequestUri"] as Uri;
+ ServiceProvider sp = OAuthServiceProvider.ServiceProvider;
+ var auth = sp.ReadProtectedResourceAuthorization(httpDetails, requestUri);
+ if (auth != null) {
+ var accessToken = Global.DataContext.IssuedToken.OfType<IssuedAccessToken>().First(token => token.Token == auth.AccessToken);
+
+ var principal = sp.CreatePrincipal(auth);
+ var policy = new OAuthPrincipalAuthorizationPolicy(principal);
+ var policies = new List<IAuthorizationPolicy> {
+ policy,
+ };
+
+ var securityContext = new ServiceSecurityContext(policies.AsReadOnly());
+ if (operationContext.IncomingMessageProperties.Security != null) {
+ operationContext.IncomingMessageProperties.Security.ServiceSecurityContext = securityContext;
+ } else {
+ operationContext.IncomingMessageProperties.Security = new SecurityMessageProperty {
+ ServiceSecurityContext = securityContext,
+ };
+ }
+
+ securityContext.AuthorizationContext.Properties["Identities"] = new List<IIdentity> {
+ principal.Identity,
+ };
+
+ // Only allow this method call if the access token scope permits it.
+ string[] scopes = accessToken.Scope.Split('|');
+ if (scopes.Contains(operationContext.IncomingMessageHeaders.Action)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthConsumerTokenManager.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthConsumerTokenManager.cs
new file mode 100644
index 0000000..107934b
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthConsumerTokenManager.cs
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthConsumerTokenManager.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.OAuth.ChannelElements;
+
+ public class OAuthConsumerTokenManager : OAuthTokenManager, IConsumerTokenManager {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthConsumerTokenManager"/> class.
+ /// </summary>
+ /// <param name="consumerKey">The consumer key.</param>
+ /// <param name="consumerSecret">The consumer secret.</param>
+ public OAuthConsumerTokenManager(string consumerKey, string consumerSecret) {
+ if (String.IsNullOrEmpty(consumerKey)) {
+ throw new ArgumentNullException("consumerKey");
+ }
+ if (consumerSecret == null) {
+ throw new ArgumentNullException("consumerSecret");
+ }
+
+ this.ConsumerKey = consumerKey;
+ this.ConsumerSecret = consumerSecret;
+ }
+
+ #region IConsumerTokenManager Members
+
+ /// <summary>
+ /// Gets the consumer key.
+ /// </summary>
+ /// <value>The consumer key.</value>
+ public string ConsumerKey { get; private set; }
+
+ /// <summary>
+ /// Gets the consumer secret.
+ /// </summary>
+ /// <value>The consumer secret.</value>
+ public string ConsumerSecret { get; private set; }
+
+ #endregion
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthPrincipalAuthorizationPolicy.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthPrincipalAuthorizationPolicy.cs
new file mode 100644
index 0000000..b2c9a2d
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthPrincipalAuthorizationPolicy.cs
@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthPrincipalAuthorizationPolicy.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.IdentityModel.Claims;
+ using System.IdentityModel.Policy;
+ using System.Linq;
+ using System.Web;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+
+ public class OAuthPrincipalAuthorizationPolicy : IAuthorizationPolicy {
+ private readonly Guid uniqueId = Guid.NewGuid();
+ private readonly OAuthPrincipal principal;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthPrincipalAuthorizationPolicy"/> class.
+ /// </summary>
+ /// <param name="principal">The principal.</param>
+ public OAuthPrincipalAuthorizationPolicy(OAuthPrincipal principal) {
+ this.principal = principal;
+ }
+
+ #region IAuthorizationComponent Members
+
+ /// <summary>
+ /// Gets a unique ID for this instance.
+ /// </summary>
+ public string Id {
+ get { return this.uniqueId.ToString(); }
+ }
+
+ #endregion
+
+ #region IAuthorizationPolicy Members
+
+ public ClaimSet Issuer {
+ get { return ClaimSet.System; }
+ }
+
+ public bool Evaluate(EvaluationContext evaluationContext, ref object state) {
+ evaluationContext.AddClaimSet(this, new DefaultClaimSet(Claim.CreateNameClaim(this.principal.Identity.Name)));
+ evaluationContext.Properties["Principal"] = this.principal;
+ return true;
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs
new file mode 100644
index 0000000..b914315
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs
@@ -0,0 +1,120 @@
+//-----------------------------------------------------------------------
+// <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>().Include("Consumer").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();
+
+ PendingAuthorizationRequest = null;
+ var response = serviceProvider.PrepareAuthorizationResponse(pendingRequest);
+ if (response != null) {
+ serviceProvider.Channel.Send(response);
+ }
+ }
+
+ /// <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 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,
+ };
+ }
+
+ if (tokenManager == null) {
+ tokenManager = new OAuthServiceProviderTokenManager();
+ }
+
+ if (serviceProvider == null) {
+ serviceProvider = new ServiceProvider(serviceDescription, tokenManager);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProviderTokenManager.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProviderTokenManager.cs
new file mode 100644
index 0000000..224a181
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProviderTokenManager.cs
@@ -0,0 +1,112 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthServiceProviderTokenManager.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.OAuth.ChannelElements;
+
+ public class OAuthServiceProviderTokenManager : OAuthTokenManager, IServiceProviderTokenManager {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthServiceProviderTokenManager"/> class.
+ /// </summary>
+ public OAuthServiceProviderTokenManager() {
+ }
+
+ #region IServiceProviderTokenManager Members
+
+ /// <summary>
+ /// Gets the Consumer description for a given a Consumer Key.
+ /// </summary>
+ /// <param name="consumerKey">The Consumer Key.</param>
+ /// <returns>
+ /// A description of the consumer. Never null.
+ /// </returns>
+ /// <exception cref="KeyNotFoundException">Thrown if the consumer key cannot be found.</exception>
+ public IConsumerDescription GetConsumer(string consumerKey) {
+ try {
+ return Global.DataContext.Consumer.First(c => c.ConsumerKey == consumerKey);
+ } catch (InvalidOperationException) {
+ throw new KeyNotFoundException();
+ }
+ }
+
+ /// <summary>
+ /// Checks whether a given request token has already been authorized
+ /// by some user for use by the Consumer that requested it.
+ /// </summary>
+ /// <param name="requestToken">The Consumer's request token.</param>
+ /// <returns>
+ /// True if the request token has already been fully authorized by the user
+ /// who owns the relevant protected resources. False if the token has not yet
+ /// been authorized, has expired or does not exist.
+ /// </returns>
+ public bool IsRequestTokenAuthorized(string requestToken) {
+ return Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().Any(
+ t => t.Token == requestToken && t.User != null);
+ }
+
+ /// <summary>
+ /// Gets details on the named request token.
+ /// </summary>
+ /// <param name="token">The request token.</param>
+ /// <returns>A description of the token. Never null.</returns>
+ /// <exception cref="KeyNotFoundException">Thrown if the token cannot be found.</exception>
+ /// <remarks>
+ /// It is acceptable for implementations to find the token, see that it has expired,
+ /// delete it from the database and then throw <see cref="KeyNotFoundException"/>,
+ /// or alternatively it can return the expired token anyway and the OAuth channel will
+ /// log and throw the appropriate error.
+ /// </remarks>
+ public IServiceProviderRequestToken GetRequestToken(string token) {
+ try {
+ return Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().First(tok => tok.Token == token);
+ } catch (InvalidOperationException) {
+ throw new KeyNotFoundException();
+ }
+ }
+
+ /// <summary>
+ /// Gets details on the named access token.
+ /// </summary>
+ /// <param name="token">The access token.</param>
+ /// <returns>A description of the token. Never null.</returns>
+ /// <exception cref="KeyNotFoundException">Thrown if the token cannot be found.</exception>
+ /// <remarks>
+ /// It is acceptable for implementations to find the token, see that it has expired,
+ /// delete it from the database and then throw <see cref="KeyNotFoundException"/>,
+ /// or alternatively it can return the expired token anyway and the OAuth channel will
+ /// log and throw the appropriate error.
+ /// </remarks>
+ public IServiceProviderAccessToken GetAccessToken(string token) {
+ try {
+ return Global.DataContext.IssuedToken.OfType<IssuedAccessToken>().First(tok => tok.Token == token);
+ } catch (InvalidOperationException) {
+ throw new KeyNotFoundException();
+ }
+ }
+
+ /// <summary>
+ /// Persists any changes made to the token.
+ /// </summary>
+ /// <param name="token">The token whose properties have been changed.</param>
+ /// <remarks>
+ /// This library will invoke this method after making a set
+ /// of changes to the token as part of a web request to give the host
+ /// the opportunity to persist those changes to a database.
+ /// Depending on the object persistence framework the host site uses,
+ /// this method MAY not need to do anything (if changes made to the token
+ /// will automatically be saved without any extra handling).
+ /// </remarks>
+ public void UpdateToken(IServiceProviderRequestToken token) {
+ Global.DataContext.SaveChanges();
+ }
+
+ #endregion
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
new file mode 100644
index 0000000..ff757c9
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
@@ -0,0 +1,143 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthTokenManager.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.X509Certificates;
+ using System.Web;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+
+ /// <summary>
+ /// The token manager this web site uses in its roles both as
+ /// a consumer and as a service provider.
+ /// </summary>
+ public class OAuthTokenManager : ITokenManager {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthTokenManager"/> class.
+ /// </summary>
+ protected OAuthTokenManager() {
+ }
+
+ #region ITokenManager Members
+
+ /// <summary>
+ /// Gets the Token Secret given a request or access token.
+ /// </summary>
+ /// <param name="token">The request or access token.</param>
+ /// <returns>
+ /// The secret associated with the given token.
+ /// </returns>
+ /// <exception cref="ArgumentException">Thrown if the secret cannot be found for the given token.</exception>
+ public string GetTokenSecret(string token) {
+ try {
+ return Global.DataContext.IssuedToken.First(t => t.Token == token).TokenSecret;
+ } catch (InvalidOperationException) {
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ /// <summary>
+ /// Stores a newly generated unauthorized request token, secret, and optional
+ /// application-specific parameters for later recall.
+ /// </summary>
+ /// <param name="request">The request message that resulted in the generation of a new unauthorized request token.</param>
+ /// <param name="response">The response message that includes the unauthorized request token.</param>
+ /// <exception cref="ArgumentException">Thrown if the consumer key is not registered, or a required parameter was not found in the parameters collection.</exception>
+ /// <remarks>
+ /// Request tokens stored by this method SHOULD NOT associate any user account with this token.
+ /// It usually opens up security holes in your application to do so. Instead, you associate a user
+ /// account with access tokens (not request tokens) in the <see cref="ExpireRequestTokenAndStoreNewAccessToken"/>
+ /// method.
+ /// </remarks>
+ public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) {
+ Consumer consumer;
+ try {
+ consumer = Global.DataContext.Consumer.First(c => c.ConsumerKey == request.ConsumerKey);
+ } catch (InvalidOperationException) {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ var token = new IssuedRequestToken {
+ Callback = request.Callback,
+ Consumer = consumer,
+ CreatedOn = DateTime.Now,
+ Token = response.Token,
+ TokenSecret = response.TokenSecret,
+ };
+ string scope;
+ if (request.ExtraData.TryGetValue("scope", out scope)) {
+ token.Scope = scope;
+ }
+ Global.DataContext.AddToIssuedToken(token);
+ 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>()
+ .Include("User")
+ .First(t => t.Consumer.ConsumerKey == consumerKey && t.Token == requestToken);
+
+ var accessTokenEntity = new IssuedAccessToken {
+ Token = accessToken,
+ TokenSecret = accessTokenSecret,
+ ExpirationDate = null, // currently, our access tokens don't expire
+ CreatedOn = DateTime.Now,
+ User = requestTokenEntity.User,
+ Scope = requestTokenEntity.Scope,
+ Consumer = requestTokenEntity.Consumer,
+ };
+
+ Global.DataContext.DeleteObject(requestTokenEntity);
+ Global.DataContext.AddToIssuedToken(accessTokenEntity);
+ Global.DataContext.SaveChanges();
+ }
+
+ /// <summary>
+ /// Classifies a token as a request token or an access token.
+ /// </summary>
+ /// <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) {
+ IssuedToken tok = Global.DataContext.IssuedToken.FirstOrDefault(t => t.Token == token);
+ if (tok == null) {
+ return TokenType.InvalidToken;
+ } else {
+ return tok is IssuedAccessToken ? TokenType.AccessToken : TokenType.RequestToken;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs b/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs
new file mode 100644
index 0000000..25d293e
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs
@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------
+// <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 const string CsrfCookieName = "CsrfCookie";
+ private static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider();
+
+ /// <summary>
+ /// Gets the full URI of the web application root. Guaranteed to end in a slash.
+ /// </summary>
+ public static Uri ApplicationRoot {
+ get {
+ string appRoot = HttpContext.Current.Request.ApplicationPath;
+ if (!appRoot.EndsWith("/", StringComparison.Ordinal)) {
+ appRoot += "/";
+ }
+
+ return new Uri(HttpContext.Current.Request.Url, 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(CsrfCookieName, 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[CsrfCookieName];
+ if (cookie != null) {
+ if (cookie.Value == secret && !string.IsNullOrEmpty(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/Global.asax.cs b/projecttemplates/WebFormsRelyingParty/Global.asax.cs
index 15a1047..8a14dfc 100644
--- a/projecttemplates/WebFormsRelyingParty/Global.asax.cs
+++ b/projecttemplates/WebFormsRelyingParty/Global.asax.cs
@@ -148,6 +148,7 @@ namespace WebFormsRelyingParty {
if (DataContextTransactionSimple != null) {
DataContextTransactionSimple.Rollback();
DataContextTransactionSimple.Dispose();
+ DataContextTransactionSimple = null;
}
}
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx
new file mode 100644
index 0000000..349ac0a
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx
@@ -0,0 +1,67 @@
+<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
+ CodeBehind="OAuthAuthorize.aspx.cs" Inherits="WebFormsRelyingParty.Members.OAuthAuthorize" %>
+
+<asp:Content ID="Content2" ContentPlaceHolderID="Body" runat="server">
+ <h2>
+ Client authorization
+ </h2>
+ <asp:MultiView runat="server" ID="outerMultiView" ActiveViewIndex="0">
+ <asp:View runat="server" ID="getPermissionView">
+ <div style="background-color: Yellow">
+ <b>Warning</b>: Never give your login credentials to another web site or application.
+ </div>
+ <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>
+ <p>
+ If you grant access now, you can revoke it at any time by returning to this page.
+ </p>
+ <div style="display: none" id="responseButtonsDiv">
+ <asp:Button ID="yesButton" runat="server" Text="Yes" OnClick="yesButton_Click" />
+ <asp:Button ID="noButton" runat="server" Text="No" OnClick="noButton_Click" />
+ <asp:HiddenField runat="server" ID="csrfCheck" EnableViewState="false" />
+ </div>
+ <div id="javascriptDisabled">
+ <b>Javascript appears to be disabled in your browser. </b>This page requires Javascript
+ to be enabled to better protect your security.
+ </div>
+ <asp:Panel runat="server" BackColor="Red" ForeColor="White" Font-Bold="true" Visible="false" ID="OAuth10ConsumerWarning">
+ This website is registered with service_PROVIDER_DOMAIN_NAME to make authorization requests, but has not been configured to send requests securely. If you grant access but you did not initiate this request at consumer_DOMAIN_NAME, it may be possible for other users of consumer_DOMAIN_NAME to access your data. We recommend you deny access unless you are certain that you initiated this request directly with consumer_DOMAIN_NAME.
+ </asp:Panel>
+
+ <script language="javascript" type="text/javascript">
+ //<![CDATA[
+ // we use HTML to hide the action buttons and Javascript to show them
+ // to protect against click-jacking in an iframe whose javascript is disabled.
+ document.getElementById('responseButtonsDiv').style.display = 'block';
+ document.getElementById('javascriptDisabled').style.display = 'none';
+
+ // Frame busting code (to protect us from being hosted in an iframe).
+ // This protects us from click-jacking.
+ if (document.location !== window.top.location) {
+ window.top.location = document.location;
+ }
+ //]]>
+ </script>
+
+ </asp:View>
+ <asp:View ID="authorizationGrantedView" runat="server">
+ <p>Authorization has been granted.</p>
+ <asp:MultiView runat="server" ID="verifierMultiView" ActiveViewIndex="0">
+ <asp:View ID="verificationCodeView" runat="server">
+ <p>You must enter this verification code at the Consumer: <asp:Label runat="server"
+ ID="verificationCodeLabel" /> </p>
+ </asp:View>
+ <asp:View ID="noCallbackView" runat="server">
+ <p>You may now close this window and return to the Consumer. </p>
+ </asp:View>
+ </asp:MultiView>
+ </asp:View>
+ <asp:View ID="authorizationDeniedView" runat="server">
+ <p>Authorization has been denied. You're free to do whatever now. </p>
+ </asp:View>
+ </asp:MultiView>
+</asp:Content>
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs
new file mode 100644
index 0000000..f9a520b
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs
@@ -0,0 +1,63 @@
+//-----------------------------------------------------------------------
+// <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) {
+ var pendingRequest = OAuthServiceProvider.PendingAuthorizationRequest;
+ if (pendingRequest == null) {
+ Response.Redirect("~/");
+ }
+
+ this.csrfCheck.Value = Utilities.SetCsrfCookie();
+ this.consumerNameLabel.Text = HttpUtility.HtmlEncode(OAuthServiceProvider.PendingAuthorizationConsumer.Name);
+ OAuth10ConsumerWarning.Visible = pendingRequest.IsUnsafeRequest;
+ } else {
+ Utilities.VerifyCsrfCookie(this.csrfCheck.Value);
+ }
+ }
+
+ protected void yesButton_Click(object sender, EventArgs e) {
+ outerMultiView.SetActiveView(authorizationGrantedView);
+
+ var consumer = OAuthServiceProvider.PendingAuthorizationConsumer;
+ var tokenManager = OAuthServiceProvider.ServiceProvider.TokenManager;
+ var pendingRequest = OAuthServiceProvider.PendingAuthorizationRequest;
+ ITokenContainingMessage requestTokenMessage = pendingRequest;
+ var requestToken = tokenManager.GetRequestToken(requestTokenMessage.Token);
+
+ OAuthServiceProvider.AuthorizePendingRequestToken();
+
+ // The rest of this method only executes if we couldn't automatically
+ // redirect to the consumer.
+ if (pendingRequest.IsUnsafeRequest) {
+ this.verifierMultiView.SetActiveView(noCallbackView);
+ } else {
+ this.verifierMultiView.SetActiveView(verificationCodeView);
+ string verifier = ServiceProvider.CreateVerificationCode(consumer.VerificationCodeFormat, consumer.VerificationCodeLength);
+ this.verificationCodeLabel.Text = verifier;
+ requestToken.VerificationCode = verifier;
+ tokenManager.UpdateToken(requestToken);
+ }
+ }
+
+ protected void noButton_Click(object sender, EventArgs e) {
+ outerMultiView.SetActiveView(authorizationDeniedView);
+ OAuthServiceProvider.PendingAuthorizationRequest = null;
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs
new file mode 100644
index 0000000..3b41f3c
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs
@@ -0,0 +1,133 @@
+//------------------------------------------------------------------------------
+// <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>
+ /// outerMultiView 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 outerMultiView;
+
+ /// <summary>
+ /// getPermissionView 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 getPermissionView;
+
+ /// <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;
+
+ /// <summary>
+ /// OAuth10ConsumerWarning 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.Panel OAuth10ConsumerWarning;
+
+ /// <summary>
+ /// authorizationGrantedView 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 authorizationGrantedView;
+
+ /// <summary>
+ /// verifierMultiView 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 verifierMultiView;
+
+ /// <summary>
+ /// verificationCodeView 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 verificationCodeView;
+
+ /// <summary>
+ /// verificationCodeLabel 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 verificationCodeLabel;
+
+ /// <summary>
+ /// noCallbackView 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 noCallbackView;
+
+ /// <summary>
+ /// authorizationDeniedView 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 authorizationDeniedView;
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Members/Web.config b/projecttemplates/WebFormsRelyingParty/Members/Web.config
index aafc323..f95a16d 100644
--- a/projecttemplates/WebFormsRelyingParty/Members/Web.config
+++ b/projecttemplates/WebFormsRelyingParty/Members/Web.config
@@ -15,4 +15,13 @@
<deny users="?" />
</authorization>
</system.web>
+
+ <!-- Protect certain user pages from delegated (OAuth) clients. -->
+ <location path="AccountInfo.aspx">
+ <system.web>
+ <authorization>
+ <deny roles="delegated" />
+ </authorization>
+ </system.web>
+ </location>
</configuration>
diff --git a/projecttemplates/WebFormsRelyingParty/Model.Consumer.cs b/projecttemplates/WebFormsRelyingParty/Model.Consumer.cs
new file mode 100644
index 0000000..5076d6d
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Model.Consumer.cs
@@ -0,0 +1,40 @@
+//-----------------------------------------------------------------------
+// <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;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Web;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+
+ public partial class Consumer : IConsumerDescription {
+ public VerificationCodeFormat VerificationCodeFormat {
+ get { return (VerificationCodeFormat)this.VerificationCodeFormatAsInt; }
+ set { this.VerificationCodeFormatAsInt = (int)value; }
+ }
+
+ public X509Certificate2 Certificate {
+ get { return this.X509CertificateAsBinary != null ? new X509Certificate2(this.X509CertificateAsBinary) : null; }
+ set { this.X509CertificateAsBinary = value != null ? value.RawData : null; }
+ }
+
+ public Uri Callback {
+ get { return this.CallbackAsString != null ? new Uri(this.CallbackAsString) : null; }
+ set { this.CallbackAsString = value != null ? value.AbsoluteUri : null; }
+ }
+
+ string IConsumerDescription.Secret {
+ get { return this.ConsumerSecret; }
+ }
+
+ string IConsumerDescription.Key {
+ get { return this.ConsumerKey; }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Model.Designer.cs b/projecttemplates/WebFormsRelyingParty/Model.Designer.cs
index 321d83b..d265efa 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.Designer.cs
+++ b/projecttemplates/WebFormsRelyingParty/Model.Designer.cs
@@ -11,9 +11,11 @@
[assembly: global::System.Data.Objects.DataClasses.EdmSchemaAttribute()]
[assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("DatabaseModel", "UserRole", "Role", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(WebFormsRelyingParty.Role), "User", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(WebFormsRelyingParty.User))]
[assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("DatabaseModel", "UserAuthenticationToken", "User", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(WebFormsRelyingParty.User), "AuthenticationToken", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(WebFormsRelyingParty.AuthenticationToken))]
+[assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("DatabaseModel", "FK_IssuedToken_Consumer", "Consumer", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(WebFormsRelyingParty.Consumer), "IssuedTokens", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(WebFormsRelyingParty.IssuedToken))]
+[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/9/2009 7:05:56 AM
+// Generation date: 11/11/2009 10:26:25 PM
namespace WebFormsRelyingParty
{
@@ -93,6 +95,36 @@ namespace WebFormsRelyingParty
}
private global::System.Data.Objects.ObjectQuery<AuthenticationToken> _AuthenticationToken;
/// <summary>
+ /// There are no comments for Consumer in the schema.
+ /// </summary>
+ public global::System.Data.Objects.ObjectQuery<Consumer> Consumer
+ {
+ get
+ {
+ if ((this._Consumer == null))
+ {
+ this._Consumer = base.CreateQuery<Consumer>("[Consumer]");
+ }
+ return this._Consumer;
+ }
+ }
+ private global::System.Data.Objects.ObjectQuery<Consumer> _Consumer;
+ /// <summary>
+ /// There are no comments for IssuedToken in the schema.
+ /// </summary>
+ public global::System.Data.Objects.ObjectQuery<IssuedToken> IssuedToken
+ {
+ get
+ {
+ if ((this._IssuedToken == null))
+ {
+ this._IssuedToken = base.CreateQuery<IssuedToken>("[IssuedToken]");
+ }
+ return this._IssuedToken;
+ }
+ }
+ private global::System.Data.Objects.ObjectQuery<IssuedToken> _IssuedToken;
+ /// <summary>
/// There are no comments for Role in the schema.
/// </summary>
public void AddToRole(Role role)
@@ -113,6 +145,20 @@ namespace WebFormsRelyingParty
{
base.AddObject("AuthenticationToken", authenticationToken);
}
+ /// <summary>
+ /// There are no comments for Consumer in the schema.
+ /// </summary>
+ public void AddToConsumer(Consumer consumer)
+ {
+ base.AddObject("Consumer", consumer);
+ }
+ /// <summary>
+ /// There are no comments for IssuedToken in the schema.
+ /// </summary>
+ public void AddToIssuedToken(IssuedToken issuedToken)
+ {
+ base.AddObject("IssuedToken", issuedToken);
+ }
}
/// <summary>
/// There are no comments for DatabaseModel.AuthenticationToken in the schema.
@@ -515,5 +561,608 @@ namespace WebFormsRelyingParty
}
}
}
+ /// <summary>
+ /// There are no comments for IssuedToken in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("DatabaseModel", "FK_IssuedToken_User", "IssuedTokens")]
+ [global::System.Xml.Serialization.XmlIgnoreAttribute()]
+ [global::System.Xml.Serialization.SoapIgnoreAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public global::System.Data.Objects.DataClasses.EntityCollection<IssuedToken> IssuedToken
+ {
+ get
+ {
+ return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<IssuedToken>("DatabaseModel.FK_IssuedToken_User", "IssuedTokens");
+ }
+ set
+ {
+ if ((value != null))
+ {
+ ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedCollection<IssuedToken>("DatabaseModel.FK_IssuedToken_User", "IssuedTokens", value);
+ }
+ }
+ }
+ }
+ /// <summary>
+ /// There are no comments for DatabaseModel.Consumer in the schema.
+ /// </summary>
+ /// <KeyProperties>
+ /// ConsumerId
+ /// </KeyProperties>
+ [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="DatabaseModel", Name="Consumer")]
+ [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
+ [global::System.Serializable()]
+ public partial class Consumer : global::System.Data.Objects.DataClasses.EntityObject
+ {
+ /// <summary>
+ /// Create a new Consumer object.
+ /// </summary>
+ /// <param name="consumerKey">Initial value of ConsumerKey.</param>
+ /// <param name="verificationCodeLength">Initial value of VerificationCodeLength.</param>
+ /// <param name="consumerId">Initial value of ConsumerId.</param>
+ public static Consumer CreateConsumer(string consumerKey, int verificationCodeLength, int consumerId)
+ {
+ Consumer consumer = new Consumer();
+ consumer.ConsumerKey = consumerKey;
+ consumer.VerificationCodeLength = verificationCodeLength;
+ consumer.ConsumerId = consumerId;
+ return consumer;
+ }
+ /// <summary>
+ /// There are no comments for Property ConsumerKey in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string ConsumerKey
+ {
+ get
+ {
+ return this._ConsumerKey;
+ }
+ set
+ {
+ this.OnConsumerKeyChanging(value);
+ this.ReportPropertyChanging("ConsumerKey");
+ this._ConsumerKey = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false);
+ this.ReportPropertyChanged("ConsumerKey");
+ this.OnConsumerKeyChanged();
+ }
+ }
+ private string _ConsumerKey;
+ partial void OnConsumerKeyChanging(string value);
+ partial void OnConsumerKeyChanged();
+ /// <summary>
+ /// There are no comments for Property ConsumerSecret in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string ConsumerSecret
+ {
+ get
+ {
+ return this._ConsumerSecret;
+ }
+ set
+ {
+ this.OnConsumerSecretChanging(value);
+ this.ReportPropertyChanging("ConsumerSecret");
+ this._ConsumerSecret = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true);
+ this.ReportPropertyChanged("ConsumerSecret");
+ this.OnConsumerSecretChanged();
+ }
+ }
+ private string _ConsumerSecret;
+ partial void OnConsumerSecretChanging(string value);
+ partial void OnConsumerSecretChanged();
+ /// <summary>
+ /// There are no comments for Property X509CertificateAsBinary in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ private byte[] X509CertificateAsBinary
+ {
+ get
+ {
+ return global::System.Data.Objects.DataClasses.StructuralObject.GetValidValue(this._X509CertificateAsBinary);
+ }
+ set
+ {
+ this.OnX509CertificateAsBinaryChanging(value);
+ this.ReportPropertyChanging("X509CertificateAsBinary");
+ this._X509CertificateAsBinary = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true);
+ this.ReportPropertyChanged("X509CertificateAsBinary");
+ this.OnX509CertificateAsBinaryChanged();
+ }
+ }
+ private byte[] _X509CertificateAsBinary;
+ partial void OnX509CertificateAsBinaryChanging(byte[] value);
+ partial void OnX509CertificateAsBinaryChanged();
+ /// <summary>
+ /// There are no comments for Property CallbackAsString in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string CallbackAsString
+ {
+ get
+ {
+ return this._CallbackAsString;
+ }
+ set
+ {
+ this.OnCallbackAsStringChanging(value);
+ this.ReportPropertyChanging("CallbackAsString");
+ this._CallbackAsString = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true);
+ this.ReportPropertyChanged("CallbackAsString");
+ this.OnCallbackAsStringChanged();
+ }
+ }
+ private string _CallbackAsString;
+ partial void OnCallbackAsStringChanging(string value);
+ partial void OnCallbackAsStringChanged();
+ /// <summary>
+ /// There are no comments for Property VerificationCodeFormatAsInt in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ private int VerificationCodeFormatAsInt
+ {
+ get
+ {
+ return this._VerificationCodeFormatAsInt;
+ }
+ set
+ {
+ this.OnVerificationCodeFormatAsIntChanging(value);
+ this.ReportPropertyChanging("VerificationCodeFormatAsInt");
+ this._VerificationCodeFormatAsInt = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
+ this.ReportPropertyChanged("VerificationCodeFormatAsInt");
+ this.OnVerificationCodeFormatAsIntChanged();
+ }
+ }
+ private int _VerificationCodeFormatAsInt;
+ partial void OnVerificationCodeFormatAsIntChanging(int value);
+ partial void OnVerificationCodeFormatAsIntChanged();
+ /// <summary>
+ /// There are no comments for Property VerificationCodeLength in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public int VerificationCodeLength
+ {
+ get
+ {
+ return this._VerificationCodeLength;
+ }
+ set
+ {
+ this.OnVerificationCodeLengthChanging(value);
+ this.ReportPropertyChanging("VerificationCodeLength");
+ this._VerificationCodeLength = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
+ this.ReportPropertyChanged("VerificationCodeLength");
+ this.OnVerificationCodeLengthChanged();
+ }
+ }
+ private int _VerificationCodeLength;
+ partial void OnVerificationCodeLengthChanging(int value);
+ partial void OnVerificationCodeLengthChanged();
+ /// <summary>
+ /// There are no comments for Property ConsumerId in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public int ConsumerId
+ {
+ get
+ {
+ return this._ConsumerId;
+ }
+ set
+ {
+ this.OnConsumerIdChanging(value);
+ this.ReportPropertyChanging("ConsumerId");
+ this._ConsumerId = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
+ this.ReportPropertyChanged("ConsumerId");
+ this.OnConsumerIdChanged();
+ }
+ }
+ private int _ConsumerId;
+ 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")]
+ [global::System.Xml.Serialization.XmlIgnoreAttribute()]
+ [global::System.Xml.Serialization.SoapIgnoreAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public global::System.Data.Objects.DataClasses.EntityCollection<IssuedToken> IssuedToken
+ {
+ get
+ {
+ return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<IssuedToken>("DatabaseModel.FK_IssuedToken_Consumer", "IssuedTokens");
+ }
+ set
+ {
+ if ((value != null))
+ {
+ ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedCollection<IssuedToken>("DatabaseModel.FK_IssuedToken_Consumer", "IssuedTokens", value);
+ }
+ }
+ }
+ }
+ /// <summary>
+ /// There are no comments for DatabaseModel.IssuedToken in the schema.
+ /// </summary>
+ /// <KeyProperties>
+ /// TokenId
+ /// </KeyProperties>
+ [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="DatabaseModel", Name="IssuedToken")]
+ [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
+ [global::System.Serializable()]
+ [global::System.Runtime.Serialization.KnownTypeAttribute(typeof(global::WebFormsRelyingParty.IssuedRequestToken))]
+ [global::System.Runtime.Serialization.KnownTypeAttribute(typeof(global::WebFormsRelyingParty.IssuedAccessToken))]
+ public abstract partial class IssuedToken : global::System.Data.Objects.DataClasses.EntityObject
+ {
+ /// <summary>
+ /// There are no comments for Property TokenId in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public int TokenId
+ {
+ get
+ {
+ return this._TokenId;
+ }
+ set
+ {
+ this.OnTokenIdChanging(value);
+ this.ReportPropertyChanging("TokenId");
+ this._TokenId = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
+ this.ReportPropertyChanged("TokenId");
+ this.OnTokenIdChanged();
+ }
+ }
+ private int _TokenId;
+ partial void OnTokenIdChanging(int value);
+ partial void OnTokenIdChanged();
+ /// <summary>
+ /// There are no comments for Property Token in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string Token
+ {
+ get
+ {
+ return this._Token;
+ }
+ set
+ {
+ this.OnTokenChanging(value);
+ this.ReportPropertyChanging("Token");
+ this._Token = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false);
+ this.ReportPropertyChanged("Token");
+ this.OnTokenChanged();
+ }
+ }
+ private string _Token;
+ partial void OnTokenChanging(string value);
+ partial void OnTokenChanged();
+ /// <summary>
+ /// There are no comments for Property TokenSecret in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string TokenSecret
+ {
+ get
+ {
+ return this._TokenSecret;
+ }
+ set
+ {
+ this.OnTokenSecretChanging(value);
+ this.ReportPropertyChanging("TokenSecret");
+ this._TokenSecret = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false);
+ this.ReportPropertyChanged("TokenSecret");
+ this.OnTokenSecretChanged();
+ }
+ }
+ private string _TokenSecret;
+ partial void OnTokenSecretChanging(string value);
+ partial void OnTokenSecretChanged();
+ /// <summary>
+ /// There are no comments for Property CreatedOn in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public global::System.DateTime CreatedOn
+ {
+ get
+ {
+ return this._CreatedOn;
+ }
+ set
+ {
+ this.OnCreatedOnChanging(value);
+ this.ReportPropertyChanging("CreatedOn");
+ this._CreatedOn = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
+ this.ReportPropertyChanged("CreatedOn");
+ this.OnCreatedOnChanged();
+ }
+ }
+ private global::System.DateTime _CreatedOn;
+ partial void OnCreatedOnChanging(global::System.DateTime value);
+ partial void OnCreatedOnChanged();
+ /// <summary>
+ /// There are no comments for Property Scope in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string Scope
+ {
+ get
+ {
+ return this._Scope;
+ }
+ set
+ {
+ this.OnScopeChanging(value);
+ this.ReportPropertyChanging("Scope");
+ this._Scope = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true);
+ this.ReportPropertyChanged("Scope");
+ this.OnScopeChanged();
+ }
+ }
+ private string _Scope;
+ partial void OnScopeChanging(string value);
+ partial void OnScopeChanged();
+ /// <summary>
+ /// There are no comments for Consumer in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("DatabaseModel", "FK_IssuedToken_Consumer", "Consumer")]
+ [global::System.Xml.Serialization.XmlIgnoreAttribute()]
+ [global::System.Xml.Serialization.SoapIgnoreAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public Consumer Consumer
+ {
+ get
+ {
+ return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<Consumer>("DatabaseModel.FK_IssuedToken_Consumer", "Consumer").Value;
+ }
+ set
+ {
+ ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<Consumer>("DatabaseModel.FK_IssuedToken_Consumer", "Consumer").Value = value;
+ }
+ }
+ /// <summary>
+ /// There are no comments for Consumer in the schema.
+ /// </summary>
+ [global::System.ComponentModel.BrowsableAttribute(false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public global::System.Data.Objects.DataClasses.EntityReference<Consumer> ConsumerReference
+ {
+ get
+ {
+ return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<Consumer>("DatabaseModel.FK_IssuedToken_Consumer", "Consumer");
+ }
+ set
+ {
+ if ((value != null))
+ {
+ ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedReference<Consumer>("DatabaseModel.FK_IssuedToken_Consumer", "Consumer", value);
+ }
+ }
+ }
+ /// <summary>
+ /// There are no comments for User in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("DatabaseModel", "FK_IssuedToken_User", "User")]
+ [global::System.Xml.Serialization.XmlIgnoreAttribute()]
+ [global::System.Xml.Serialization.SoapIgnoreAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public User User
+ {
+ get
+ {
+ return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<User>("DatabaseModel.FK_IssuedToken_User", "User").Value;
+ }
+ set
+ {
+ ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<User>("DatabaseModel.FK_IssuedToken_User", "User").Value = value;
+ }
+ }
+ /// <summary>
+ /// There are no comments for User in the schema.
+ /// </summary>
+ [global::System.ComponentModel.BrowsableAttribute(false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public global::System.Data.Objects.DataClasses.EntityReference<User> UserReference
+ {
+ get
+ {
+ return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<User>("DatabaseModel.FK_IssuedToken_User", "User");
+ }
+ set
+ {
+ if ((value != null))
+ {
+ ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedReference<User>("DatabaseModel.FK_IssuedToken_User", "User", value);
+ }
+ }
+ }
+ }
+ /// <summary>
+ /// There are no comments for DatabaseModel.IssuedRequestToken in the schema.
+ /// </summary>
+ /// <KeyProperties>
+ /// TokenId
+ /// </KeyProperties>
+ [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="DatabaseModel", Name="IssuedRequestToken")]
+ [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
+ [global::System.Serializable()]
+ public partial class IssuedRequestToken : IssuedToken
+ {
+ /// <summary>
+ /// Create a new IssuedRequestToken object.
+ /// </summary>
+ /// <param name="tokenId">Initial value of TokenId.</param>
+ /// <param name="token">Initial value of Token.</param>
+ /// <param name="tokenSecret">Initial value of TokenSecret.</param>
+ /// <param name="createdOn">Initial value of CreatedOn.</param>
+ public static IssuedRequestToken CreateIssuedRequestToken(int tokenId, string token, string tokenSecret, global::System.DateTime createdOn)
+ {
+ IssuedRequestToken issuedRequestToken = new IssuedRequestToken();
+ issuedRequestToken.TokenId = tokenId;
+ issuedRequestToken.Token = token;
+ issuedRequestToken.TokenSecret = tokenSecret;
+ issuedRequestToken.CreatedOn = createdOn;
+ return issuedRequestToken;
+ }
+ /// <summary>
+ /// There are no comments for Property ConsumerVersionAsString in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ private string ConsumerVersionAsString
+ {
+ get
+ {
+ return this._ConsumerVersionAsString;
+ }
+ set
+ {
+ this.OnConsumerVersionAsStringChanging(value);
+ this.ReportPropertyChanging("ConsumerVersionAsString");
+ this._ConsumerVersionAsString = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false);
+ this.ReportPropertyChanged("ConsumerVersionAsString");
+ this.OnConsumerVersionAsStringChanged();
+ }
+ }
+ private string _ConsumerVersionAsString;
+ partial void OnConsumerVersionAsStringChanging(string value);
+ partial void OnConsumerVersionAsStringChanged();
+ /// <summary>
+ /// There are no comments for Property VerificationCode in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public string VerificationCode
+ {
+ get
+ {
+ return this._VerificationCode;
+ }
+ set
+ {
+ this.OnVerificationCodeChanging(value);
+ this.ReportPropertyChanging("VerificationCode");
+ this._VerificationCode = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true);
+ this.ReportPropertyChanged("VerificationCode");
+ this.OnVerificationCodeChanged();
+ }
+ }
+ private string _VerificationCode;
+ partial void OnVerificationCodeChanging(string value);
+ partial void OnVerificationCodeChanged();
+ /// <summary>
+ /// There are no comments for Property CallbackAsString in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ private string CallbackAsString
+ {
+ get
+ {
+ return this._CallbackAsString;
+ }
+ set
+ {
+ this.OnCallbackAsStringChanging(value);
+ this.ReportPropertyChanging("CallbackAsString");
+ this._CallbackAsString = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true);
+ this.ReportPropertyChanged("CallbackAsString");
+ this.OnCallbackAsStringChanged();
+ }
+ }
+ private string _CallbackAsString;
+ partial void OnCallbackAsStringChanging(string value);
+ partial void OnCallbackAsStringChanged();
+ }
+ /// <summary>
+ /// There are no comments for DatabaseModel.IssuedAccessToken in the schema.
+ /// </summary>
+ /// <KeyProperties>
+ /// TokenId
+ /// </KeyProperties>
+ [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="DatabaseModel", Name="IssuedAccessToken")]
+ [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
+ [global::System.Serializable()]
+ public partial class IssuedAccessToken : IssuedToken
+ {
+ /// <summary>
+ /// Create a new IssuedAccessToken object.
+ /// </summary>
+ /// <param name="tokenId">Initial value of TokenId.</param>
+ /// <param name="token">Initial value of Token.</param>
+ /// <param name="tokenSecret">Initial value of TokenSecret.</param>
+ /// <param name="createdOn">Initial value of CreatedOn.</param>
+ public static IssuedAccessToken CreateIssuedAccessToken(int tokenId, string token, string tokenSecret, global::System.DateTime createdOn)
+ {
+ IssuedAccessToken issuedAccessToken = new IssuedAccessToken();
+ issuedAccessToken.TokenId = tokenId;
+ issuedAccessToken.Token = token;
+ issuedAccessToken.TokenSecret = tokenSecret;
+ issuedAccessToken.CreatedOn = createdOn;
+ return issuedAccessToken;
+ }
+ /// <summary>
+ /// There are no comments for Property ExpirationDate in the schema.
+ /// </summary>
+ [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]
+ [global::System.Runtime.Serialization.DataMemberAttribute()]
+ public global::System.Nullable<global::System.DateTime> ExpirationDate
+ {
+ get
+ {
+ return this._ExpirationDate;
+ }
+ set
+ {
+ this.OnExpirationDateChanging(value);
+ this.ReportPropertyChanging("ExpirationDate");
+ this._ExpirationDate = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
+ this.ReportPropertyChanged("ExpirationDate");
+ this.OnExpirationDateChanged();
+ }
+ }
+ private global::System.Nullable<global::System.DateTime> _ExpirationDate;
+ partial void OnExpirationDateChanging(global::System.Nullable<global::System.DateTime> value);
+ partial void OnExpirationDateChanged();
}
}
diff --git a/projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs b/projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs
new file mode 100644
index 0000000..ab064c3
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Model.IssuedAccessToken.cs
@@ -0,0 +1,58 @@
+//-----------------------------------------------------------------------
+// <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;
+ using System.Web;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+
+ public partial class IssuedAccessToken : IServiceProviderAccessToken {
+ /// <summary>
+ /// Gets the roles that the OAuth principal should belong to.
+ /// </summary>
+ /// <value>
+ /// The roles that the user belongs to, or a subset of these according to the rights
+ /// granted when the user authorized the request token.
+ /// </value>
+ string[] IServiceProviderAccessToken.Roles {
+ get {
+ List<string> roles = new List<string>();
+
+ // Include the roles the user who authorized this OAuth token has.
+ roles.AddRange(this.User.Roles.Select(r => r.Name));
+
+ // Always add an extra role to indicate this is an OAuth-authorized request.
+ // This allows us to deny access to account management pages to OAuth requests.
+ roles.Add("delegated");
+
+ return roles.ToArray();
+ }
+ }
+
+ /// <summary>
+ /// Gets the username of the principal that will be impersonated by this access token.
+ /// </summary>
+ /// <value>
+ /// The name of the user who authorized the OAuth request token originally.
+ /// </value>
+ string IServiceProviderAccessToken.Username {
+ get {
+ // We don't really have the concept of a single username, but we
+ // can use any of the authentication tokens instead since that
+ // is what the rest of the web site expects.
+ if (!this.UserReference.IsLoaded) {
+ this.UserReference.Load();
+ }
+ if (!this.User.AuthenticationTokens.IsLoaded) {
+ this.User.AuthenticationTokens.Load();
+ }
+ return this.User.AuthenticationTokens.First().ClaimedIdentifier;
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs b/projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs
new file mode 100644
index 0000000..1352e54
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Model.IssuedRequestToken.cs
@@ -0,0 +1,56 @@
+//-----------------------------------------------------------------------
+// <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;
+ using System.Web;
+ 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 af72a25..f37aa6c 100644
--- a/projecttemplates/WebFormsRelyingParty/Model.edmx
+++ b/projecttemplates/WebFormsRelyingParty/Model.edmx
@@ -7,6 +7,8 @@
<Schema Namespace="DatabaseModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">
<EntityContainer Name="DatabaseModelStoreContainer">
<EntitySet Name="AuthenticationToken" EntityType="DatabaseModel.Store.AuthenticationToken" store:Type="Tables" Schema="dbo" />
+ <EntitySet Name="Consumer" EntityType="DatabaseModel.Store.Consumer" store:Type="Tables" Schema="dbo" />
+ <EntitySet Name="IssuedToken" EntityType="DatabaseModel.Store.IssuedToken" store:Type="Tables" Schema="dbo" />
<EntitySet Name="Role" EntityType="DatabaseModel.Store.Role" store:Type="Tables" Schema="dbo" />
<EntitySet Name="User" EntityType="DatabaseModel.Store.User" store:Type="Tables" Schema="dbo" />
<EntitySet Name="UserRole" EntityType="DatabaseModel.Store.UserRole" store:Type="Tables" Schema="dbo" />
@@ -14,6 +16,14 @@
<End Role="User" EntitySet="User" />
<End Role="AuthenticationToken" EntitySet="AuthenticationToken" />
</AssociationSet>
+ <AssociationSet Name="FK_IssuedToken_Consumer" Association="DatabaseModel.Store.FK_IssuedToken_Consumer">
+ <End Role="Consumer" EntitySet="Consumer" />
+ <End Role="IssuedToken" EntitySet="IssuedToken" />
+ </AssociationSet>
+ <AssociationSet Name="FK_IssuedToken_User" Association="DatabaseModel.Store.FK_IssuedToken_User">
+ <End Role="User" EntitySet="User" />
+ <End Role="IssuedToken" EntitySet="IssuedToken" />
+ </AssociationSet>
<AssociationSet Name="FK_UserRole_Role" Association="DatabaseModel.Store.FK_UserRole_Role">
<End Role="Role" EntitySet="Role" />
<End Role="UserRole" EntitySet="UserRole" />
@@ -32,6 +42,36 @@
<Property Name="OpenIdClaimedIdentifier" Type="nvarchar" Nullable="false" MaxLength="250" />
<Property Name="OpenIdFriendlyIdentifier" Type="nvarchar" MaxLength="250" />
</EntityType>
+ <EntityType Name="Consumer">
+ <Key>
+ <PropertyRef Name="ConsumerId" />
+ </Key>
+ <Property Name="ConsumerId" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
+ <Property Name="ConsumerKey" Type="nvarchar" Nullable="false" MaxLength="255" />
+ <Property Name="ConsumerSecret" Type="nvarchar" MaxLength="255" />
+ <Property Name="X509Certificate" Type="image" />
+ <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>
+ <PropertyRef Name="TokenId" />
+ </Key>
+ <Property Name="TokenId" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
+ <Property Name="ConsumerId" Type="int" Nullable="false" />
+ <Property Name="UserId" Type="int" />
+ <Property Name="Token" Type="nvarchar" Nullable="false" MaxLength="255" />
+ <Property Name="TokenSecret" Type="nvarchar" Nullable="false" MaxLength="255" />
+ <Property Name="CreatedOn" Type="datetime" Nullable="false" />
+ <Property Name="Callback" Type="nvarchar" MaxLength="2048" />
+ <Property Name="VerificationCode" Type="nvarchar" MaxLength="255" />
+ <Property Name="ConsumerVersion" Type="varchar" MaxLength="10" />
+ <Property Name="ExpirationDate" Type="datetime" />
+ <Property Name="IsAccessToken" Type="bit" Nullable="false" />
+ <Property Name="Scope" Type="nvarchar" MaxLength="255" />
+ </EntityType>
<EntityType Name="Role">
<Key>
<PropertyRef Name="Id" />
@@ -71,6 +111,34 @@
</Dependent>
</ReferentialConstraint>
</Association>
+ <Association Name="FK_IssuedToken_Consumer">
+ <End Role="Consumer" Type="DatabaseModel.Store.Consumer" Multiplicity="1">
+ <OnDelete Action="Cascade" />
+ </End>
+ <End Role="IssuedToken" Type="DatabaseModel.Store.IssuedToken" Multiplicity="*" />
+ <ReferentialConstraint>
+ <Principal Role="Consumer">
+ <PropertyRef Name="ConsumerId" />
+ </Principal>
+ <Dependent Role="IssuedToken">
+ <PropertyRef Name="ConsumerId" />
+ </Dependent>
+ </ReferentialConstraint>
+ </Association>
+ <Association Name="FK_IssuedToken_User">
+ <End Role="User" Type="DatabaseModel.Store.User" Multiplicity="0..1">
+ <OnDelete Action="Cascade" />
+ </End>
+ <End Role="IssuedToken" Type="DatabaseModel.Store.IssuedToken" Multiplicity="*" />
+ <ReferentialConstraint>
+ <Principal Role="User">
+ <PropertyRef Name="Id" />
+ </Principal>
+ <Dependent Role="IssuedToken">
+ <PropertyRef Name="UserId" />
+ </Dependent>
+ </ReferentialConstraint>
+ </Association>
<Association Name="FK_UserRole_Role">
<End Role="Role" Type="DatabaseModel.Store.Role" Multiplicity="1">
<OnDelete Action="Cascade" />
@@ -114,6 +182,14 @@
<AssociationSet Name="UserAuthenticationToken" Association="DatabaseModel.UserAuthenticationToken">
<End Role="User" EntitySet="User" />
<End Role="AuthenticationToken" EntitySet="AuthenticationToken" /></AssociationSet>
+ <EntitySet Name="Consumer" EntityType="DatabaseModel.Consumer" />
+ <EntitySet Name="IssuedToken" EntityType="DatabaseModel.IssuedToken" />
+ <AssociationSet Name="FK_IssuedToken_Consumer" Association="DatabaseModel.FK_IssuedToken_Consumer">
+ <End Role="Consumer" EntitySet="Consumer" />
+ <End Role="IssuedTokens" EntitySet="IssuedToken" /></AssociationSet>
+ <AssociationSet Name="FK_IssuedToken_User" Association="DatabaseModel.FK_IssuedToken_User">
+ <End Role="User" EntitySet="User" />
+ <End Role="IssuedTokens" EntitySet="IssuedToken" /></AssociationSet>
</EntityContainer>
<EntityType Name="AuthenticationToken" Abstract="false">
<Key>
@@ -145,14 +221,48 @@
<Property Name="EmailAddressVerified" Type="Boolean" Nullable="false" >
<Documentation>
<Summary>A value indicating whether the email address has been verified as actually owned by this user.</Summary></Documentation></Property>
- </EntityType>
+ <NavigationProperty Name="IssuedToken" Relationship="DatabaseModel.FK_IssuedToken_User" FromRole="User" ToRole="IssuedTokens" /></EntityType>
<Association Name="UserRole">
<End Role="Role" Type="DatabaseModel.Role" Multiplicity="*" />
<End Role="User" Type="DatabaseModel.User" Multiplicity="*" />
</Association>
<Association Name="UserAuthenticationToken">
<End Type="DatabaseModel.User" Role="User" Multiplicity="1" />
- <End Type="DatabaseModel.AuthenticationToken" Role="AuthenticationToken" Multiplicity="*" /></Association></Schema>
+ <End Type="DatabaseModel.AuthenticationToken" Role="AuthenticationToken" Multiplicity="*" /></Association>
+ <EntityType Name="Consumer">
+ <Key>
+ <PropertyRef Name="ConsumerId" /></Key>
+ <Property Name="ConsumerKey" Type="String" Nullable="false" />
+ <Property Name="ConsumerSecret" Type="String" Nullable="true" />
+ <Property Name="X509CertificateAsBinary" Type="Binary" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" a:GetterAccess="Private" />
+ <Property Name="CallbackAsString" Type="String" Nullable="true" />
+ <Property Name="VerificationCodeFormatAsInt" Type="Int32" Nullable="false" a:GetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" a:SetterAccess="Private" />
+ <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" />
+ <Property Name="Name" Type="String" Nullable="true" /></EntityType>
+ <EntityType Name="IssuedToken" Abstract="true">
+ <Key>
+ <PropertyRef Name="TokenId" /></Key>
+ <Property Name="TokenId" Type="Int32" Nullable="false" />
+ <Property Name="Token" Type="String" Nullable="false" />
+ <Property Name="TokenSecret" Type="String" Nullable="false" />
+ <Property Name="CreatedOn" Type="DateTime" Nullable="false" />
+ <NavigationProperty Name="Consumer" Relationship="DatabaseModel.FK_IssuedToken_Consumer" FromRole="IssuedTokens" ToRole="Consumer" />
+ <NavigationProperty Name="User" Relationship="DatabaseModel.FK_IssuedToken_User" FromRole="IssuedTokens" ToRole="User" />
+ <Property Name="Scope" Type="String" Nullable="true" /></EntityType>
+ <Association Name="FK_IssuedToken_Consumer">
+ <End Type="DatabaseModel.Consumer" Role="Consumer" Multiplicity="1" />
+ <End Type="DatabaseModel.IssuedToken" Role="IssuedTokens" Multiplicity="*" /></Association>
+ <Association Name="FK_IssuedToken_User">
+ <End Type="DatabaseModel.User" Role="User" Multiplicity="0..1" />
+ <End Type="DatabaseModel.IssuedToken" Role="IssuedTokens" Multiplicity="*" /></Association>
+ <EntityType Name="IssuedRequestToken" BaseType="DatabaseModel.IssuedToken">
+ <Property Name="ConsumerVersionAsString" Type="String" Nullable="false" a:GetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" a:SetterAccess="Private" />
+ <Property Name="VerificationCode" Type="String" Nullable="true" />
+ <Property Name="CallbackAsString" Type="String" Nullable="true" a:GetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" a:SetterAccess="Private" /></EntityType>
+ <EntityType Name="IssuedAccessToken" BaseType="DatabaseModel.IssuedToken">
+ <Property Name="ExpirationDate" Type="DateTime" Nullable="true" /></EntityType></Schema>
</edmx:ConceptualModels>
<!-- C-S mapping content -->
<edmx:Mappings>
@@ -198,7 +308,48 @@
<ScalarProperty Name="Id" ColumnName="Id" /></EndProperty>
<EndProperty Name="User">
<ScalarProperty Name="Id" ColumnName="UserId" /></EndProperty></AssociationSetMapping>
- </EntityContainerMapping>
+ <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" />
+ <ScalarProperty Name="CallbackAsString" ColumnName="Callback" />
+ <ScalarProperty Name="X509CertificateAsBinary" ColumnName="X509Certificate" />
+ <ScalarProperty Name="ConsumerSecret" ColumnName="ConsumerSecret" />
+ <ScalarProperty Name="ConsumerKey" ColumnName="ConsumerKey" /></MappingFragment></EntityTypeMapping></EntitySetMapping>
+ <EntitySetMapping Name="IssuedToken">
+ <EntityTypeMapping TypeName="IsTypeOf(DatabaseModel.IssuedToken)">
+ <MappingFragment StoreEntitySet="IssuedToken">
+ <ScalarProperty Name="Scope" ColumnName="Scope" />
+ <ScalarProperty Name="CreatedOn" ColumnName="CreatedOn" />
+ <ScalarProperty Name="TokenSecret" ColumnName="TokenSecret" />
+ <ScalarProperty Name="Token" ColumnName="Token" />
+ <ScalarProperty Name="TokenId" ColumnName="TokenId" /></MappingFragment></EntityTypeMapping>
+ <EntityTypeMapping TypeName="IsTypeOf(DatabaseModel.IssuedRequestToken)">
+ <MappingFragment StoreEntitySet="IssuedToken" >
+ <ScalarProperty Name="CallbackAsString" ColumnName="Callback" />
+ <ScalarProperty Name="ConsumerVersionAsString" ColumnName="ConsumerVersion" />
+ <ScalarProperty Name="VerificationCode" ColumnName="VerificationCode" />
+ <ScalarProperty Name="TokenId" ColumnName="TokenId" />
+ <Condition ColumnName="IsAccessToken" Value="0" /></MappingFragment></EntityTypeMapping>
+ <EntityTypeMapping TypeName="IsTypeOf(DatabaseModel.IssuedAccessToken)">
+ <MappingFragment StoreEntitySet="IssuedToken" >
+ <ScalarProperty Name="ExpirationDate" ColumnName="ExpirationDate" />
+ <ScalarProperty Name="TokenId" ColumnName="TokenId" />
+ <Condition ColumnName="IsAccessToken" Value="1" /></MappingFragment></EntityTypeMapping></EntitySetMapping>
+ <AssociationSetMapping Name="FK_IssuedToken_Consumer" TypeName="DatabaseModel.FK_IssuedToken_Consumer" StoreEntitySet="IssuedToken">
+ <EndProperty Name="IssuedTokens">
+ <ScalarProperty Name="TokenId" ColumnName="TokenId" /></EndProperty>
+ <EndProperty Name="Consumer">
+ <ScalarProperty Name="ConsumerId" ColumnName="ConsumerId" /></EndProperty></AssociationSetMapping>
+ <AssociationSetMapping Name="FK_IssuedToken_User" TypeName="DatabaseModel.FK_IssuedToken_User" StoreEntitySet="IssuedToken">
+ <EndProperty Name="IssuedTokens">
+ <ScalarProperty Name="TokenId" ColumnName="TokenId" /></EndProperty>
+ <EndProperty Name="User">
+ <ScalarProperty Name="Id" ColumnName="UserId" /></EndProperty>
+ <Condition ColumnName="UserId" IsNull="false" /></AssociationSetMapping></EntityContainerMapping>
</Mapping>
</edmx:Mappings>
</edmx:Runtime>
@@ -228,6 +379,26 @@
<ConnectorPoint PointX="6.5625" PointY="2.9129850260416665" /></InheritanceConnector>
<AssociationConnector Association="DatabaseModel.UserAuthenticationToken">
<ConnectorPoint PointX="4.625" PointY="2.0189925130208337" />
- <ConnectorPoint PointX="5.25" PointY="2.0189925130208337" /></AssociationConnector></Diagram></edmx:Diagrams>
+ <ConnectorPoint PointX="5.25" PointY="2.0189925130208337" /></AssociationConnector>
+ <EntityTypeShape EntityType="DatabaseModel.Consumer" Width="2.125" PointX="0.5" PointY="3.625" Height="2.1725878906249996" />
+ <EntityTypeShape EntityType="DatabaseModel.IssuedToken" Width="2" PointX="4.5" PointY="3.625" Height="2.1725878906249996" />
+ <AssociationConnector Association="DatabaseModel.FK_IssuedToken_Consumer" ManuallyRouted="false" >
+ <ConnectorPoint PointX="2.625" PointY="5.359375" />
+ <ConnectorPoint PointX="4.5" PointY="5.359375" />
+ </AssociationConnector>
+ <AssociationConnector Association="DatabaseModel.FK_IssuedToken_User" >
+ <ConnectorPoint PointX="3.6874995" PointY="3.4321907552083331" />
+ <ConnectorPoint PointX="3.6874995" PointY="4.005208333333333" />
+ <ConnectorPoint PointX="4.5" PointY="4.005208333333333" />
+ </AssociationConnector>
+ <EntityTypeShape EntityType="DatabaseModel.IssuedRequestToken" Width="2" PointX="4.25" PointY="6.25" Height="1.5956835937499996" />
+ <EntityTypeShape EntityType="DatabaseModel.IssuedAccessToken" Width="1.625" PointX="6.5" PointY="6.25" Height="1.2110807291666657" />
+ <InheritanceConnector EntityType="DatabaseModel.IssuedRequestToken">
+ <ConnectorPoint PointX="5.375" PointY="5.797587890625" />
+ <ConnectorPoint PointX="5.375" PointY="6.25" /></InheritanceConnector>
+ <InheritanceConnector EntityType="DatabaseModel.IssuedAccessToken">
+ <ConnectorPoint PointX="6.5" PointY="4.7112939453125" />
+ <ConnectorPoint PointX="7.34375" PointY="4.7112939453125" />
+ <ConnectorPoint PointX="7.34375" PointY="6.25" /></InheritanceConnector></Diagram></edmx:Diagrams>
</edmx:Designer>
</edmx:Edmx> \ No newline at end of file
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..274b5da
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+// <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 System.Web.SessionState;
+ 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, 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("~/Members/OAuthAuthorize.aspx");
+ } else {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Web.config b/projecttemplates/WebFormsRelyingParty/Web.config
index 3c7aaae..b38a25a 100644
--- a/projecttemplates/WebFormsRelyingParty/Web.config
+++ b/projecttemplates/WebFormsRelyingParty/Web.config
@@ -34,6 +34,13 @@
</system.net>
<!-- this is an optional configuration section where aspects of dotnetopenauth can be customized -->
<dotNetOpenAuth>
+ <messaging>
+ <untrustedWebRequest>
+ <whitelistHosts>
+ <add name="localhost" />
+ </whitelistHosts>
+ </untrustedWebRequest>
+ </messaging>
<openid>
<relyingParty>
<behaviors>
@@ -122,6 +129,7 @@
</httpHandlers>
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+ <add name="OAuthAuthenticationModule" type="WebFormsRelyingParty.Code.OAuthAuthenticationModule" />
</httpModules>
<roleManager enabled="true" defaultProvider="Database">
<providers>
@@ -146,6 +154,7 @@
<modules>
<remove name="ScriptModule" />
<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+ <add name="OAuthAuthenticationModule" type="WebFormsRelyingParty.Code.OAuthAuthenticationModule" />
</modules>
<handlers>
<remove name="WebServiceHandlerFactory-Integrated" />
@@ -169,6 +178,21 @@
</dependentAssembly>
</assemblyBinding>
</runtime>
+ <system.serviceModel>
+ <behaviors>
+ <serviceBehaviors>
+ <behavior name="DataApiBehavior">
+ <serviceMetadata httpGetEnabled="true" />
+ <serviceDebug includeExceptionDetailInFaults="true" />
+ <serviceAuthorization serviceAuthorizationManagerType="OAuthAuthorizationManager, __code" principalPermissionMode="Custom" />
+ </behavior>
+ </serviceBehaviors>
+ </behaviors>
+ <services>
+ <!--<service behaviorConfiguration="DataApiBehavior" name="DataApi">
+ </service>-->
+ </services>
+ </system.serviceModel>
<location path="default.aspx">
<system.web>
<authorization>
diff --git a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
index 43bdef4..4f6cdc6 100644
--- a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
+++ b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
@@ -87,7 +87,25 @@
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Code\OAuthAuthenticationModule.cs" />
+ <Compile Include="Code\OAuthAuthorizationManager.cs" />
+ <Compile Include="Code\OAuthConsumerTokenManager.cs" />
+ <Compile Include="Code\OAuthPrincipalAuthorizationPolicy.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" />
<Compile Include="Model.User.cs" />
<Compile Include="LoginFrame.aspx.cs">
<DependentUpon>LoginFrame.aspx</DependentUpon>
@@ -154,6 +172,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>
@@ -245,6 +266,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">
diff --git a/samples/OAuthConsumerWpf/MainWindow.xaml b/samples/OAuthConsumerWpf/MainWindow.xaml
index e948bd2..c59175c 100644
--- a/samples/OAuthConsumerWpf/MainWindow.xaml
+++ b/samples/OAuthConsumerWpf/MainWindow.xaml
@@ -72,5 +72,66 @@
<Label Grid.Row="3" Grid.Column="1" Name="wcfFavoriteSites" />
</Grid>
</TabItem>
+ <TabItem Header="Generic">
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
+ <RowDefinition Height="*" />
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="auto" />
+ <ColumnDefinition Width="*" />
+ <ColumnDefinition Width="auto" />
+ </Grid.ColumnDefinitions>
+ <Label Grid.Row="0">Request Token URL</Label>
+ <TextBox Grid.Column="1" x:Name="requestTokenUrlBox" />
+ <ComboBox Grid.Column="2" x:Name="requestTokenHttpMethod" SelectedIndex="1">
+ <ComboBox.Items>
+ <ComboBoxItem>GET</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Label Grid.Row="1">Authorize URL</Label>
+ <TextBox Grid.Row="1" Grid.Column="1" x:Name="authorizeUrlBox" />
+ <Label Grid.Row="1" Grid.Column="2">GET</Label>
+ <Label Grid.Row="2">Access Token URL</Label>
+ <TextBox Grid.Row="2" Grid.Column="1" x:Name="accessTokenUrlBox" />
+ <ComboBox Grid.Row="2" Grid.Column="2" x:Name="accessTokenHttpMethod" SelectedIndex="1">
+ <ComboBox.Items>
+ <ComboBoxItem>GET</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Label Grid.Row="3">Resource URL</Label>
+ <TextBox Grid.Row="3" Grid.Column="1" x:Name="resourceUrlBox" />
+ <ComboBox Grid.Row="3" Grid.Column="2" x:Name="resourceHttpMethodList" SelectedIndex="0">
+ <ComboBox.Items>
+ <ComboBoxItem>GET w/ header</ComboBoxItem>
+ <ComboBoxItem>GET w/ querystring</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Label Grid.Row="4">Consumer key</Label>
+ <TextBox Grid.Row="4" Grid.Column="1" x:Name="consumerKeyBox" Grid.ColumnSpan="2"/>
+ <Label Grid.Row="5">Consumer secret</Label>
+ <TextBox Grid.Row="5" Grid.Column="1" x:Name="consumerSecretBox" Grid.ColumnSpan="2"/>
+ <Label Grid.Row="6">OAuth version</Label>
+ <ComboBox Grid.Row="6" Grid.Column="1" SelectedIndex="1" x:Name="oauthVersion">
+ <ComboBox.Items>
+ <ComboBoxItem>1.0</ComboBoxItem>
+ <ComboBoxItem>1.0a</ComboBoxItem>
+ </ComboBox.Items>
+ </ComboBox>
+ <Button Grid.Row="7" Grid.Column="1" x:Name="beginButton" Click="beginButton_Click">Begin</Button>
+ <TextBox Grid.Column="0" Grid.Row="8" Grid.ColumnSpan="3" Name="resultsBox" IsReadOnly="True" />
+ </Grid>
+ </TabItem>
</TabControl>
</Window>
diff --git a/samples/OAuthConsumerWpf/MainWindow.xaml.cs b/samples/OAuthConsumerWpf/MainWindow.xaml.cs
index ebbeffc..93d77ea 100644
--- a/samples/OAuthConsumerWpf/MainWindow.xaml.cs
+++ b/samples/OAuthConsumerWpf/MainWindow.xaml.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Configuration;
+ using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
@@ -125,6 +126,7 @@
Authorize auth = new Authorize(
this.wcf,
(DesktopConsumer consumer, out string requestToken) => consumer.RequestUserAuthorization(requestArgs, null, out requestToken));
+ auth.Owner = this;
bool? result = auth.ShowDialog();
if (result.HasValue && result.Value) {
this.wcfAccessToken = auth.AccessToken;
@@ -149,5 +151,52 @@
return predicate(client);
}
}
+
+ private void beginButton_Click(object sender, RoutedEventArgs e) {
+ try {
+ var service = new ServiceProviderDescription {
+ RequestTokenEndpoint = new MessageReceivingEndpoint(requestTokenUrlBox.Text, requestTokenHttpMethod.SelectedIndex == 0 ? HttpDeliveryMethods.GetRequest : HttpDeliveryMethods.PostRequest),
+ UserAuthorizationEndpoint = new MessageReceivingEndpoint(authorizeUrlBox.Text, HttpDeliveryMethods.GetRequest),
+ AccessTokenEndpoint = new MessageReceivingEndpoint(accessTokenUrlBox.Text, accessTokenHttpMethod.SelectedIndex == 0 ? HttpDeliveryMethods.GetRequest : HttpDeliveryMethods.PostRequest),
+ TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
+ ProtocolVersion = oauthVersion.SelectedIndex == 0 ? ProtocolVersion.V10 : ProtocolVersion.V10a,
+ };
+ var tokenManager = new InMemoryTokenManager();
+ tokenManager.ConsumerKey = consumerKeyBox.Text;
+ tokenManager.ConsumerSecret = consumerSecretBox.Text;
+
+ var consumer = new DesktopConsumer(service, tokenManager);
+ string accessToken;
+ if (service.ProtocolVersion == ProtocolVersion.V10) {
+ string requestToken;
+ Uri authorizeUrl = consumer.RequestUserAuthorization(null, null, out requestToken);
+ Process.Start(authorizeUrl.AbsoluteUri);
+ MessageBox.Show("Click OK when you've authorized the app.");
+ var authorizationResponse = consumer.ProcessUserAuthorization(requestToken);
+ accessToken = authorizationResponse.AccessToken;
+ } else {
+ var authorizePopup = new Authorize(
+ consumer,
+ (DesktopConsumer c, out string requestToken) => c.RequestUserAuthorization(null, null, out requestToken));
+ authorizePopup.Owner = this;
+ bool? result = authorizePopup.ShowDialog();
+ if (result.HasValue && result.Value) {
+ accessToken = authorizePopup.AccessToken;
+ } else {
+ return;
+ }
+ }
+ HttpDeliveryMethods resourceHttpMethod = resourceHttpMethodList.SelectedIndex < 2 ? HttpDeliveryMethods.GetRequest : HttpDeliveryMethods.PostRequest;
+ if (resourceHttpMethodList.SelectedIndex == 1) {
+ resourceHttpMethod |= HttpDeliveryMethods.AuthorizationHeaderRequest;
+ }
+ var resourceEndpoint = new MessageReceivingEndpoint(resourceUrlBox.Text, resourceHttpMethod);
+ using (IncomingWebResponse resourceResponse = consumer.PrepareAuthorizedRequestAndSend(resourceEndpoint, accessToken)) {
+ resultsBox.Text = resourceResponse.GetResponseReader().ReadToEnd();
+ }
+ } catch (DotNetOpenAuth.Messaging.ProtocolException ex) {
+ MessageBox.Show(ex.Message);
+ }
+ }
}
}
diff --git a/samples/OAuthServiceProvider/App_Code/Global.cs b/samples/OAuthServiceProvider/App_Code/Global.cs
index b343dcd..10b3cba 100644
--- a/samples/OAuthServiceProvider/App_Code/Global.cs
+++ b/samples/OAuthServiceProvider/App_Code/Global.cs
@@ -92,7 +92,15 @@ public class Global : HttpApplication {
private void Application_Start(object sender, EventArgs e) {
log4net.Config.XmlConfigurator.Configure();
Logger.Info("Sample starting...");
- Constants.WebRootUrl = new Uri(HttpContext.Current.Request.Url, "/");
+ 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);
var tokenManager = new DatabaseTokenManager();
Global.TokenManager = tokenManager;
}