summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--projecttemplates/RelyingPartyLogic/Model.Consumer.cs13
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs17
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs21
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs117
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthConsumerTokenManager.cs48
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthPrincipalAuthorizationPolicy.cs5
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs99
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthServiceProviderTokenManager.cs112
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthTokenManager.cs141
-rw-r--r--projecttemplates/RelyingPartyLogic/RelyingPartyLogic.csproj16
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx13
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs44
-rw-r--r--projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs48
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuth.ashx1
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs66
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx1
-rw-r--r--projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs51
-rw-r--r--projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj6
-rw-r--r--src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs12
-rw-r--r--src/DotNetOpenAuth/OAuth2/IConsumerDescription.cs4
-rw-r--r--src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs2
-rw-r--r--src/DotNetOpenAuth/OAuth2/ResourceServer.cs38
-rw-r--r--src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs12
23 files changed, 302 insertions, 585 deletions
diff --git a/projecttemplates/RelyingPartyLogic/Model.Consumer.cs b/projecttemplates/RelyingPartyLogic/Model.Consumer.cs
index a09029a..258a248 100644
--- a/projecttemplates/RelyingPartyLogic/Model.Consumer.cs
+++ b/projecttemplates/RelyingPartyLogic/Model.Consumer.cs
@@ -13,7 +13,7 @@ namespace RelyingPartyLogic {
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
- public partial class Consumer : IConsumerDescription {
+ public partial class Consumer : IConsumerDescription, DotNetOpenAuth.OAuth2.IConsumerDescription {
public VerificationCodeFormat VerificationCodeFormat {
get { return (VerificationCodeFormat)this.VerificationCodeFormatAsInt; }
set { this.VerificationCodeFormatAsInt = (int)value; }
@@ -36,5 +36,16 @@ namespace RelyingPartyLogic {
string IConsumerDescription.Key {
get { return this.ConsumerKey; }
}
+
+ #region IConsumerDescription Members
+
+ /// <summary>
+ /// Gets the consumer secret.
+ /// </summary>
+ string DotNetOpenAuth.OAuth2.IConsumerDescription.Secret {
+ get { return this.ConsumerSecret; }
+ }
+
+ #endregion
}
}
diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs
index e47e4ee..3700b65 100644
--- a/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs
+++ b/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs
@@ -12,9 +12,7 @@ namespace RelyingPartyLogic {
using System.Web;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
+ using DotNetOpenAuth.OAuth2;
public class OAuthAuthenticationModule : IHttpModule {
private HttpApplication application;
@@ -51,10 +49,13 @@ namespace RelyingPartyLogic {
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);
+ var tokenAnalyzer = new StandardAccessTokenAnalyzer(OAuthAuthorizationServer.AsymmetricKey, OAuthAuthorizationServer.AsymmetricKey);
+ var resourceServer = new ResourceServer(tokenAnalyzer);
+
+ IPrincipal principal;
+ var errorMessage = resourceServer.VerifyAccess(new HttpRequestInfo(this.application.Context.Request), out principal);
+ if (errorMessage == null) {
+ this.application.Context.User = principal;
}
}
@@ -70,7 +71,7 @@ namespace RelyingPartyLogic {
/// <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) {
+ if (this.application.User is DotNetOpenAuth.OAuth.ChannelElements.OAuthPrincipal) {
e.RolesPopulated = true;
}
}
diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs
index 35af472..f4e27a4 100644
--- a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs
+++ b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationManager.cs
@@ -15,6 +15,7 @@ namespace RelyingPartyLogic {
using System.ServiceModel.Security;
using DotNetOpenAuth;
using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth2;
/// <summary>
/// A WCF extension to authenticate incoming messages using OAuth.
@@ -28,15 +29,16 @@ namespace RelyingPartyLogic {
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;
- try {
- var auth = sp.ReadProtectedResourceAuthorization(httpDetails, requestUri);
- if (auth != null) {
- var accessToken = Database.DataContext.IssuedTokens.OfType<IssuedAccessToken>().First(token => token.Token == auth.AccessToken);
+ var httpDetails = operationContext.RequestContext.RequestMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
+ var requestUri = operationContext.RequestContext.RequestMessage.Properties["OriginalHttpRequestUri"] as Uri;
- var principal = sp.CreatePrincipal(auth);
+ var tokenAnalyzer = new StandardAccessTokenAnalyzer(OAuthAuthorizationServer.AsymmetricKey, OAuthAuthorizationServer.AsymmetricKey);
+ var resourceServer = new ResourceServer(tokenAnalyzer);
+
+ try {
+ IPrincipal principal;
+ var errorResponse = resourceServer.VerifyAccess(httpDetails, requestUri, out principal);
+ if (errorResponse == null) {
var policy = new OAuthPrincipalAuthorizationPolicy(principal);
var policies = new List<IAuthorizationPolicy> {
policy,
@@ -56,8 +58,7 @@ namespace RelyingPartyLogic {
};
// Only allow this method call if the access token scope permits it.
- string[] scopes = accessToken.Scope.Split('|');
- if (scopes.Contains(operationContext.IncomingMessageHeaders.Action)) {
+ if (principal.IsInRole(operationContext.IncomingMessageHeaders.Action)) {
return true;
}
}
diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs
new file mode 100644
index 0000000..ff8bbb4
--- /dev/null
+++ b/projecttemplates/RelyingPartyLogic/OAuthAuthorizationServer.cs
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthAuthorizationServer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace RelyingPartyLogic {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OAuth2;
+
+ /// <summary>
+ /// Provides OAuth 2.0 authorization server information to DotNetOpenAuth.
+ /// </summary>
+ public class OAuthAuthorizationServer : IAuthorizationServer {
+ internal static readonly RSAParameters AsymmetricKey;
+
+ private static readonly byte[] secret;
+
+ private readonly INonceStore nonceStore = new NonceDbStore();
+
+ static OAuthAuthorizationServer() {
+ // TODO: Replace this sample code with real code.
+ // For this sample, we just generate random secrets.
+ RandomNumberGenerator crypto = new RNGCryptoServiceProvider();
+ secret = new byte[16];
+ crypto.GetBytes(secret);
+
+ AsymmetricKey = new RSACryptoServiceProvider().ExportParameters(true);
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthAuthorizationServer"/> class.
+ /// </summary>
+ public OAuthAuthorizationServer() {
+ }
+
+ #region IAuthorizationServer Members
+
+ /// <summary>
+ /// Gets the secret used to symmetrically encrypt and sign authorization codes and refresh tokens.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// This secret should be kept strictly confidential in the authorization server(s)
+ /// and NOT shared with the resource server. Anyone with this secret can mint
+ /// tokens to essentially grant themselves access to anything they want.
+ /// </remarks>
+ public byte[] Secret {
+ get { return secret; }
+ }
+
+ /// <summary>
+ /// Gets the asymmetric private key to use for signing access tokens.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// The public key in the private/public key pair will be used by the resource
+ /// servers to validate that the access token is minted by a trusted authorization server.
+ /// </remarks>
+ public RSAParameters AccessTokenSigningPrivateKey {
+ get { return AsymmetricKey; }
+ }
+
+ /// <summary>
+ /// Gets the authorization code nonce store to use to ensure that authorization codes can only be used once.
+ /// </summary>
+ /// <value>The authorization code nonce store.</value>
+ public INonceStore VerificationCodeNonceStore {
+ get { return this.nonceStore; }
+ }
+
+ /// <summary>
+ /// Gets the client with a given identifier.
+ /// </summary>
+ /// <param name="clientIdentifier">The client identifier.</param>
+ /// <returns>The client registration. Never null.</returns>
+ /// <exception cref="ArgumentException">Thrown when no client with the given identifier is registered with this authorization server.</exception>
+ public IConsumerDescription GetClient(string clientIdentifier) {
+ return Database.DataContext.Consumers.First(c => c.ConsumerKey == clientIdentifier);
+ }
+
+ /// <summary>
+ /// Determines whether a described authorization is (still) valid.
+ /// </summary>
+ /// <param name="authorization">The authorization.</param>
+ /// <returns>
+ /// <c>true</c> if the original authorization is still valid; otherwise, <c>false</c>.
+ /// </returns>
+ /// <remarks>
+ /// <para>When establishing that an authorization is still valid,
+ /// it's very important to only match on recorded authorizations that
+ /// meet these criteria:</para>
+ /// 1) The client identifier matches.
+ /// 2) The user account matches.
+ /// 3) The scope on the recorded authorization must include all scopes in the given authorization.
+ /// 4) The date the recorded authorization was issued must be <em>no later</em> that the date the given authorization was issued.
+ /// <para>One possible scenario is where the user authorized a client, later revoked authorization,
+ /// and even later reinstated authorization. This subsequent recorded authorization
+ /// would not satisfy requirement #4 in the above list. This is important because the revocation
+ /// the user went through should invalidate all previously issued tokens as a matter of
+ /// security in the event the user was revoking access in order to sever authorization on a stolen
+ /// account or piece of hardware in which the tokens were stored. </para>
+ /// </remarks>
+ public bool IsAuthorizationValid(DotNetOpenAuth.OAuth2.ChannelElements.IAuthorizationDescription authorization) {
+ // We don't support revoking tokens yet.
+ return true;
+ }
+
+ #endregion
+ }
+}
diff --git a/projecttemplates/RelyingPartyLogic/OAuthConsumerTokenManager.cs b/projecttemplates/RelyingPartyLogic/OAuthConsumerTokenManager.cs
deleted file mode 100644
index 64e6be8..0000000
--- a/projecttemplates/RelyingPartyLogic/OAuthConsumerTokenManager.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthConsumerTokenManager.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace RelyingPartyLogic {
- 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/RelyingPartyLogic/OAuthPrincipalAuthorizationPolicy.cs b/projecttemplates/RelyingPartyLogic/OAuthPrincipalAuthorizationPolicy.cs
index ddd0b3f..482f44b 100644
--- a/projecttemplates/RelyingPartyLogic/OAuthPrincipalAuthorizationPolicy.cs
+++ b/projecttemplates/RelyingPartyLogic/OAuthPrincipalAuthorizationPolicy.cs
@@ -10,18 +10,19 @@ namespace RelyingPartyLogic {
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.Linq;
+ using System.Security.Principal;
using System.Web;
using DotNetOpenAuth.OAuth.ChannelElements;
public class OAuthPrincipalAuthorizationPolicy : IAuthorizationPolicy {
private readonly Guid uniqueId = Guid.NewGuid();
- private readonly OAuthPrincipal principal;
+ private readonly IPrincipal principal;
/// <summary>
/// Initializes a new instance of the <see cref="OAuthPrincipalAuthorizationPolicy"/> class.
/// </summary>
/// <param name="principal">The principal.</param>
- public OAuthPrincipalAuthorizationPolicy(OAuthPrincipal principal) {
+ public OAuthPrincipalAuthorizationPolicy(IPrincipal principal) {
this.principal = principal;
}
diff --git a/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs b/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
index 807da2d..9b6fb50 100644
--- a/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
+++ b/projecttemplates/RelyingPartyLogic/OAuthServiceProvider.cs
@@ -10,9 +10,9 @@ namespace RelyingPartyLogic {
using System.Linq;
using System.Web;
using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
+ using DotNetOpenAuth.OAuth2;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+ using DotNetOpenAuth.OAuth2.Messages;
public class OAuthServiceProvider {
private const string PendingAuthorizationRequestSessionKey = "PendingAuthorizationRequest";
@@ -20,28 +20,26 @@ namespace RelyingPartyLogic {
/// <summary>
/// The shared service description for this web site.
/// </summary>
- private static ServiceProviderDescription serviceDescription;
-
- private static OAuthServiceProviderTokenManager tokenManager;
+ private static AuthorizationServerDescription authorizationServerDescription;
/// <summary>
- /// The shared service provider object.
+ /// The shared authorization server.
/// </summary>
- private static ServiceProvider serviceProvider;
+ private static WebServerAuthorizationServer authorizationServer;
/// <summary>
- /// The lock to synchronize initialization of the <see cref="serviceProvider"/> field.
+ /// The lock to synchronize initialization of the <see cref="authorizationServer"/> field.
/// </summary>
- private static object initializerLock = new object();
+ private static readonly object InitializerLock = new object();
/// <summary>
/// Gets the service provider.
/// </summary>
/// <value>The service provider.</value>
- public static ServiceProvider ServiceProvider {
+ public static WebServerAuthorizationServer AuthorizationServer {
get {
EnsureInitialized();
- return serviceProvider;
+ return authorizationServer;
}
}
@@ -49,83 +47,28 @@ namespace RelyingPartyLogic {
/// Gets the service description.
/// </summary>
/// <value>The service description.</value>
- public static ServiceProviderDescription ServiceDescription {
+ public static AuthorizationServerDescription AuthorizationServerDescription {
get {
EnsureInitialized();
- return serviceDescription;
- }
- }
-
- public static UserAuthorizationRequest PendingAuthorizationRequest {
- get { return HttpContext.Current.Session[PendingAuthorizationRequestSessionKey] as UserAuthorizationRequest; }
- set { HttpContext.Current.Session[PendingAuthorizationRequestSessionKey] = value; }
- }
-
- public static Consumer PendingAuthorizationConsumer {
- get {
- ITokenContainingMessage message = PendingAuthorizationRequest;
- if (message == null) {
- throw new InvalidOperationException();
- }
-
- return Database.DataContext.IssuedTokens.OfType<IssuedRequestToken>().Include("Consumer").First(t => t.Token == message.Token).Consumer;
- }
- }
-
- public static void AuthorizePendingRequestToken() {
- var response = AuthorizePendingRequestTokenAndGetResponse();
- if (response != null) {
- serviceProvider.Channel.Send(response);
- }
- }
-
- public static OutgoingWebResponse AuthorizePendingRequestTokenAsWebResponse() {
- var response = AuthorizePendingRequestTokenAndGetResponse();
- if (response != null) {
- return serviceProvider.Channel.PrepareResponse(response);
- } else {
- return null;
+ return authorizationServerDescription;
}
}
- private static UserAuthorizationResponse AuthorizePendingRequestTokenAndGetResponse() {
- var pendingRequest = PendingAuthorizationRequest;
- if (pendingRequest == null) {
- throw new InvalidOperationException("No pending authorization request to authorize.");
- }
-
- ITokenContainingMessage msg = pendingRequest;
- var token = Database.DataContext.IssuedTokens.OfType<IssuedRequestToken>().First(t => t.Token == msg.Token);
- token.Authorize();
-
- PendingAuthorizationRequest = null;
- var response = serviceProvider.PrepareAuthorizationResponse(pendingRequest);
- return response;
- }
-
/// <summary>
- /// Initializes the <see cref="serviceProvider"/> field if it has not yet been initialized.
+ /// Initializes the <see cref="authorizationServer"/> 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 (authorizationServer == null) {
+ lock (InitializerLock) {
+ if (authorizationServerDescription == null) {
+ authorizationServerDescription = new AuthorizationServerDescription {
+ AuthorizationEndpoint = new Uri(Utilities.ApplicationRoot, "OAuth.ashx"),
+ TokenEndpoint = new Uri(Utilities.ApplicationRoot, "OAuth.ashx"),
};
}
- if (tokenManager == null) {
- tokenManager = new OAuthServiceProviderTokenManager();
- }
-
- if (serviceProvider == null) {
- serviceProvider = new ServiceProvider(serviceDescription, tokenManager);
+ if (authorizationServer == null) {
+ authorizationServer = new WebServerAuthorizationServer(new OAuthAuthorizationServer());
}
}
}
diff --git a/projecttemplates/RelyingPartyLogic/OAuthServiceProviderTokenManager.cs b/projecttemplates/RelyingPartyLogic/OAuthServiceProviderTokenManager.cs
deleted file mode 100644
index 4ae50ce..0000000
--- a/projecttemplates/RelyingPartyLogic/OAuthServiceProviderTokenManager.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthServiceProviderTokenManager.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace RelyingPartyLogic {
- 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 Database.DataContext.Consumers.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 Database.DataContext.IssuedTokens.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 Database.DataContext.IssuedTokens.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 Database.DataContext.IssuedTokens.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) {
- Database.DataContext.SaveChanges();
- }
-
- #endregion
- }
-}
diff --git a/projecttemplates/RelyingPartyLogic/OAuthTokenManager.cs b/projecttemplates/RelyingPartyLogic/OAuthTokenManager.cs
deleted file mode 100644
index fbf808c..0000000
--- a/projecttemplates/RelyingPartyLogic/OAuthTokenManager.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthTokenManager.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace RelyingPartyLogic {
- 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 Database.DataContext.IssuedTokens.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 = Database.DataContext.Consumers.First(c => c.ConsumerKey == request.ConsumerKey);
- } catch (InvalidOperationException) {
- throw new ArgumentOutOfRangeException();
- }
-
- var token = new IssuedRequestToken {
- Callback = request.Callback,
- Consumer = consumer,
- Token = response.Token,
- TokenSecret = response.TokenSecret,
- };
- string scope;
- if (request.ExtraData.TryGetValue("scope", out scope)) {
- token.Scope = scope;
- }
- Database.DataContext.AddToIssuedTokens(token);
- Database.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 = Database.DataContext.IssuedTokens.OfType<IssuedRequestToken>()
- .Include("User")
- .First(t => t.Consumer.ConsumerKey == consumerKey && t.Token == requestToken);
-
- var accessTokenEntity = new IssuedAccessToken {
- Token = accessToken,
- TokenSecret = accessTokenSecret,
- ExpirationDateUtc = null, // currently, our access tokens don't expire
- User = requestTokenEntity.User,
- Scope = requestTokenEntity.Scope,
- Consumer = requestTokenEntity.Consumer,
- };
-
- Database.DataContext.DeleteObject(requestTokenEntity);
- Database.DataContext.AddToIssuedTokens(accessTokenEntity);
- Database.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 = Database.DataContext.IssuedTokens.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/RelyingPartyLogic/RelyingPartyLogic.csproj b/projecttemplates/RelyingPartyLogic/RelyingPartyLogic.csproj
index 338622c..8f11aef 100644
--- a/projecttemplates/RelyingPartyLogic/RelyingPartyLogic.csproj
+++ b/projecttemplates/RelyingPartyLogic/RelyingPartyLogic.csproj
@@ -121,13 +121,11 @@
<Compile Include="Model.OpenIdAssociation.cs" />
<Compile Include="Model.User.cs" />
<Compile Include="NonceDbStore.cs" />
+ <Compile Include="OAuthAuthorizationServer.cs" />
<Compile Include="OAuthAuthenticationModule.cs" />
<Compile Include="OAuthAuthorizationManager.cs" />
- <Compile Include="OAuthConsumerTokenManager.cs" />
<Compile Include="OAuthPrincipalAuthorizationPolicy.cs" />
<Compile Include="OAuthServiceProvider.cs" />
- <Compile Include="OAuthServiceProviderTokenManager.cs" />
- <Compile Include="OAuthTokenManager.cs" />
<Compile Include="Policies.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RelyingPartyApplicationDbStore.cs" />
@@ -144,12 +142,12 @@
<Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project>
<Name>DotNetOpenAuth</Name>
</ProjectReference>
- <ProjectReference Include="..\RelyingPartyDatabase\RelyingPartyDatabase.dbproj">
- <Name>RelyingPartyDatabase</Name>
- <!-- Deploy the latest SQL script first, so that this project can embed the latest version. -->
- <Targets>Build;Deploy</Targets>
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
- </ProjectReference>
+ <ProjectReference Include="..\RelyingPartyDatabase\RelyingPartyDatabase.dbproj">
+ <Name>RelyingPartyDatabase</Name>
+ <!-- Deploy the latest SQL script first, so that this project can embed the latest version. -->
+ <Targets>Build;Deploy</Targets>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="CreateDatabase.sql" />
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx
index 7886157..7e07323 100644
--- a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx
@@ -29,19 +29,6 @@
<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
- <asp:Label runat="server" ID="serviceProviderDomainNameLabel" />
- 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
- <asp:Label runat="server" ID="consumerDomainNameLabel1" />, it may be possible for
- other users of
- <asp:Label runat="server" ID="consumerDomainNameLabel2" />
- to access your data. We recommend you deny access unless you are certain that you
- initiated this request directly with
- <asp:Label runat="server" ID="consumerDomainNameLabel3" />.
- </asp:Panel>
<script language="javascript" type="text/javascript">
//<![CDATA[
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs
index 16e48f0..cd523dd 100644
--- a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs
@@ -13,22 +13,23 @@ namespace WebFormsRelyingParty.Members {
using System.Web.UI.WebControls;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.Messages;
+ using DotNetOpenAuth.OAuth2.Messages;
+
using RelyingPartyLogic;
public partial class OAuthAuthorize : System.Web.UI.Page {
+ private EndUserAuthorizationRequest pendingRequest;
+
protected void Page_Load(object sender, EventArgs e) {
- if (!IsPostBack) {
- var pendingRequest = OAuthServiceProvider.PendingAuthorizationRequest;
- if (pendingRequest == null) {
- Response.Redirect("AccountInfo.aspx");
- }
+ this.pendingRequest = OAuthServiceProvider.AuthorizationServer.ReadAuthorizationRequest();
+ if (this.pendingRequest == null) {
+ Response.Redirect("AccountInfo.aspx");
+ }
+ if (!IsPostBack) {
this.csrfCheck.Value = Code.SiteUtilities.SetCsrfCookie();
- this.consumerNameLabel.Text = HttpUtility.HtmlEncode(OAuthServiceProvider.PendingAuthorizationConsumer.Name);
- this.OAuth10ConsumerWarning.Visible = pendingRequest.IsUnsafeRequest;
-
- this.serviceProviderDomainNameLabel.Text = HttpUtility.HtmlEncode(this.Request.Url.Host);
- this.consumerDomainNameLabel3.Text = this.consumerDomainNameLabel2.Text = this.consumerDomainNameLabel1.Text = HttpUtility.HtmlEncode(OAuthServiceProvider.PendingAuthorizationConsumer.Name);
+ var requestingClient = Database.DataContext.Consumers.First(c => c.ConsumerKey == this.pendingRequest.ClientIdentifier);
+ this.consumerNameLabel.Text = HttpUtility.HtmlEncode(requestingClient.Name);
} else {
Code.SiteUtilities.VerifyCsrfCookie(this.csrfCheck.Value);
}
@@ -36,31 +37,12 @@ namespace WebFormsRelyingParty.Members {
protected void yesButton_Click(object sender, EventArgs e) {
this.outerMultiView.SetActiveView(this.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(this.noCallbackView);
- } else {
- this.verifierMultiView.SetActiveView(this.verificationCodeView);
- string verifier = ServiceProvider.CreateVerificationCode(consumer.VerificationCodeFormat, consumer.VerificationCodeLength);
- this.verificationCodeLabel.Text = HttpUtility.HtmlEncode(verifier);
- requestToken.VerificationCode = verifier;
- tokenManager.UpdateToken(requestToken);
- }
+ OAuthServiceProvider.AuthorizationServer.ApproveAuthorizationRequest(this.pendingRequest, HttpContext.Current.User.Identity.Name);
}
protected void noButton_Click(object sender, EventArgs e) {
this.outerMultiView.SetActiveView(this.authorizationDeniedView);
- OAuthServiceProvider.PendingAuthorizationRequest = null;
+ OAuthServiceProvider.AuthorizationServer.RejectAuthorizationRequest(this.pendingRequest);
}
}
}
diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs
index 20d5ea9..19947de 100644
--- a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs
+++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.designer.cs
@@ -1,10 +1,9 @@
//------------------------------------------------------------------------------
// <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.
+// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
@@ -68,51 +67,6 @@ namespace WebFormsRelyingParty.Members {
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>
- /// serviceProviderDomainNameLabel 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 serviceProviderDomainNameLabel;
-
- /// <summary>
- /// consumerDomainNameLabel1 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 consumerDomainNameLabel1;
-
- /// <summary>
- /// consumerDomainNameLabel2 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 consumerDomainNameLabel2;
-
- /// <summary>
- /// consumerDomainNameLabel3 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 consumerDomainNameLabel3;
-
- /// <summary>
/// authorizationGrantedView control.
/// </summary>
/// <remarks>
diff --git a/projecttemplates/WebFormsRelyingParty/OAuth.ashx b/projecttemplates/WebFormsRelyingParty/OAuth.ashx
deleted file mode 100644
index 6176757..0000000
--- a/projecttemplates/WebFormsRelyingParty/OAuth.ashx
+++ /dev/null
@@ -1 +0,0 @@
-<%@ WebHandler Language="C#" CodeBehind="OAuth.ashx.cs" Class="WebFormsRelyingParty.OAuth" %>
diff --git a/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs b/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs
deleted file mode 100644
index cb7c819..0000000
--- a/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuth.ashx.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace 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 RelyingPartyLogic;
-
- /// <summary>
- /// Responds to incoming OAuth Service Provider messages.
- /// </summary>
- public class OAuth : IHttpHandler, IRequiresSessionState {
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuth"/> class.
- /// </summary>
- public OAuth() {
- }
-
- /// <summary>
- /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
- /// </summary>
- /// <returns>
- /// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
- /// </returns>
- public bool IsReusable {
- get { return true; }
- }
-
- /// <summary>
- /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
- /// </summary>
- /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
- public void ProcessRequest(HttpContext context) {
- var serviceProvider = OAuthServiceProvider.ServiceProvider;
- var requestMessage = serviceProvider.ReadRequest(new HttpRequestInfo(context.Request));
-
- UnauthorizedTokenRequest unauthorizedTokenRequestMessage;
- AuthorizedTokenRequest authorizedTokenRequestMessage;
- UserAuthorizationRequest userAuthorizationRequest;
- if ((unauthorizedTokenRequestMessage = requestMessage as UnauthorizedTokenRequest) != null) {
- var response = serviceProvider.PrepareUnauthorizedTokenMessage(unauthorizedTokenRequestMessage);
- serviceProvider.Channel.Send(response);
- } else if ((authorizedTokenRequestMessage = requestMessage as AuthorizedTokenRequest) != null) {
- var response = serviceProvider.PrepareAccessTokenMessage(authorizedTokenRequestMessage);
- serviceProvider.Channel.Send(response);
- } else if ((userAuthorizationRequest = requestMessage as UserAuthorizationRequest) != null) {
- // This is a browser opening to allow the user to authorize a request token,
- // so redirect to the authorization page, which will automatically redirect
- // to have the user log in if necessary.
- OAuthServiceProvider.PendingAuthorizationRequest = userAuthorizationRequest;
- HttpContext.Current.Response.Redirect("~/Members/OAuthAuthorize.aspx");
- } else {
- throw new InvalidOperationException();
- }
- }
- }
-}
diff --git a/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx b/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx
new file mode 100644
index 0000000..3d1cd86
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx
@@ -0,0 +1 @@
+<%@ WebHandler Language="C#" CodeBehind="OAuthTokenEndpoint.ashx.cs" Class="WebFormsRelyingParty.OAuthTokenEndpoint" %>
diff --git a/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs b/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs
new file mode 100644
index 0000000..ca9b399
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/OAuthTokenEndpoint.ashx.cs
@@ -0,0 +1,51 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthTokenEndpoint.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.OAuth2;
+ using RelyingPartyLogic;
+
+ /// <summary>
+ /// An OAuth 2.0 token endpoint.
+ /// </summary>
+ public class OAuthTokenEndpoint : IHttpHandler, IRequiresSessionState {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthTokenEndpoint"/> class.
+ /// </summary>
+ public OAuthTokenEndpoint() {
+ }
+
+ /// <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.AuthorizationServer;
+ IDirectResponseProtocolMessage response;
+ if (serviceProvider.TryPrepareAccessTokenResponse(new HttpRequestInfo(context.Request), out response)) {
+ serviceProvider.Channel.Send(response);
+ } else {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
index 8faeef5..eb81910 100644
--- a/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
+++ b/projecttemplates/WebFormsRelyingParty/WebFormsRelyingParty.csproj
@@ -153,8 +153,8 @@
<Compile Include="Members\Default.aspx.designer.cs">
<DependentUpon>Default.aspx</DependentUpon>
</Compile>
- <Compile Include="OAuth.ashx.cs">
- <DependentUpon>OAuth.ashx</DependentUpon>
+ <Compile Include="OAuthTokenEndpoint.ashx.cs">
+ <DependentUpon>OAuthTokenEndpoint.ashx</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Setup.aspx.cs">
@@ -235,7 +235,7 @@
<ItemGroup>
<Content Include="images\verisign.gif" />
<Content Include="Members\OAuthAuthorize.aspx" />
- <Content Include="OAuth.ashx" />
+ <Content Include="OAuthTokenEndpoint.ashx" />
<Content Include="PrivacyPolicy.aspx" />
</ItemGroup>
<ItemGroup>
diff --git a/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs b/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs
index c99fbc3..83b5191 100644
--- a/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs
+++ b/src/DotNetOpenAuth/OAuth2/IAuthorizationServer.cs
@@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OAuth2 {
[ContractClass(typeof(IAuthorizationServerContract))]
public interface IAuthorizationServer {
/// <summary>
- /// Gets the secret used to symmetrically encrypt and sign verification codes and refresh tokens.
+ /// Gets the secret used to symmetrically encrypt and sign authorization codes and refresh tokens.
/// </summary>
/// <remarks>
/// This secret should be kept strictly confidential in the authorization server(s)
@@ -39,9 +39,9 @@ namespace DotNetOpenAuth.OAuth2 {
RSAParameters AccessTokenSigningPrivateKey { get; }
/// <summary>
- /// Gets the verification code nonce store to use to ensure that verification codes can only be used once.
+ /// Gets the authorization code nonce store to use to ensure that authorization codes can only be used once.
/// </summary>
- /// <value>The verification code nonce store.</value>
+ /// <value>The authorization code nonce store.</value>
INonceStore VerificationCodeNonceStore { get; }
/// <summary>
@@ -89,7 +89,7 @@ namespace DotNetOpenAuth.OAuth2 {
}
/// <summary>
- /// Gets the secret used to symmetrically encrypt and sign verification codes and refresh tokens.
+ /// Gets the secret used to symmetrically encrypt and sign authorization codes and refresh tokens.
/// </summary>
/// <value></value>
/// <remarks>
@@ -117,9 +117,9 @@ namespace DotNetOpenAuth.OAuth2 {
}
/// <summary>
- /// Gets the verification code nonce store to use to ensure that verification codes can only be used once.
+ /// Gets the authorization code nonce store to use to ensure that authorization codes can only be used once.
/// </summary>
- /// <value>The verification code nonce store.</value>
+ /// <value>The authorization code nonce store.</value>
INonceStore IAuthorizationServer.VerificationCodeNonceStore {
get {
Contract.Ensures(Contract.Result<INonceStore>() != null);
diff --git a/src/DotNetOpenAuth/OAuth2/IConsumerDescription.cs b/src/DotNetOpenAuth/OAuth2/IConsumerDescription.cs
index f0fc20a..bfb3ecc 100644
--- a/src/DotNetOpenAuth/OAuth2/IConsumerDescription.cs
+++ b/src/DotNetOpenAuth/OAuth2/IConsumerDescription.cs
@@ -9,7 +9,7 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Security.Cryptography.X509Certificates;
/// <summary>
- /// A description of a consumer from a Service Provider's point of view.
+ /// A description of a client from an Authorization Server's point of view.
/// </summary>
public interface IConsumerDescription {
/// <summary>
@@ -18,7 +18,7 @@ namespace DotNetOpenAuth.OAuth2 {
string Secret { get; }
/// <summary>
- /// Gets the callback URI that this consumer has pre-registered with the service provider, if any.
+ /// Gets the callback URI that this client has pre-registered with the service provider, if any.
/// </summary>
/// <value>A URI that user authorization responses should be directed to; or <c>null</c> if no preregistered callback was arranged.</value>
Uri Callback { get; }
diff --git a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs
index d66c2d8..62cad53 100644
--- a/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs
+++ b/src/DotNetOpenAuth/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs
@@ -15,7 +15,7 @@ namespace DotNetOpenAuth.OAuth2.Messages {
/// to indicate that user authorization was granted, and to return the user
/// to the Client where they started their experience.
/// </summary>
- internal abstract class EndUserAuthorizationSuccessResponseBase : MessageBase, IMessageWithClientState {
+ public abstract class EndUserAuthorizationSuccessResponseBase : MessageBase, IMessageWithClientState {
/// <summary>
/// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessResponseBase"/> class.
/// </summary>
diff --git a/src/DotNetOpenAuth/OAuth2/ResourceServer.cs b/src/DotNetOpenAuth/OAuth2/ResourceServer.cs
index 534f741..3a86d29 100644
--- a/src/DotNetOpenAuth/OAuth2/ResourceServer.cs
+++ b/src/DotNetOpenAuth/OAuth2/ResourceServer.cs
@@ -10,6 +10,8 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net;
+ using System.Security.Principal;
+ using System.ServiceModel.Channels;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
@@ -97,5 +99,41 @@ namespace DotNetOpenAuth.OAuth2 {
return this.Channel.PrepareResponse(response);
}
}
+
+ /// <summary>
+ /// Discovers what access the client should have considering the access token in the current request.
+ /// </summary>
+ /// <param name="httpRequestInfo">The HTTP request info.</param>
+ /// <param name="principal">The principal that contains the user and roles that the access token is authorized for.</param>
+ /// <returns>
+ /// An error to return to the client if access is not authorized; <c>null</c> if access is granted.
+ /// </returns>
+ public virtual OutgoingWebResponse VerifyAccess(HttpRequestInfo httpRequestInfo, out IPrincipal principal) {
+ string username, scope;
+ var result = this.VerifyAccess(httpRequestInfo, out username, out scope);
+ if (result == null) {
+ principal = new OAuth.ChannelElements.OAuthPrincipal(username, scope != null ? scope.Split(' ') : new string[0]);
+ } else {
+ principal = null;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Discovers what access the client should have considering the access token in the current request.
+ /// </summary>
+ /// <param name="request">HTTP details from an incoming WCF message.</param>
+ /// <param name="requestUri">The URI of the WCF service endpoint.</param>
+ /// <param name="principal">The principal that contains the user and roles that the access token is authorized for.</param>
+ /// <returns>
+ /// An error to return to the client if access is not authorized; <c>null</c> if access is granted.
+ /// </returns>
+ public virtual OutgoingWebResponse VerifyAccess(HttpRequestMessageProperty request, Uri requestUri, out IPrincipal principal) {
+ Contract.Requires<ArgumentNullException>(request != null, "request");
+ Contract.Requires<ArgumentNullException>(requestUri != null, "requestUri");
+
+ return this.VerifyAccess(new HttpRequestInfo(request, requestUri), out principal);
+ }
}
}
diff --git a/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs b/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs
index 67ea1d6..66bc96d 100644
--- a/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs
+++ b/src/DotNetOpenAuth/OAuth2/WebServerAuthorizationServer.cs
@@ -48,8 +48,7 @@ namespace DotNetOpenAuth.OAuth2 {
public void ApproveAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, string username, Uri callback = null) {
Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
- var response = this.PrepareApproveAuthorizationRequest(authorizationRequest, callback);
- response.AuthorizingUsername = username;
+ var response = this.PrepareApproveAuthorizationRequest(authorizationRequest, username, callback);
this.Channel.Send(response);
}
@@ -101,8 +100,9 @@ namespace DotNetOpenAuth.OAuth2 {
return response;
}
- internal EndUserAuthorizationSuccessResponseBase PrepareApproveAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, Uri callback = null) {
+ public EndUserAuthorizationSuccessResponseBase PrepareApproveAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, string username, Uri callback = null) {
Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(username));
Contract.Ensures(Contract.Result<EndUserAuthorizationSuccessResponseBase>() != null);
if (callback == null) {
@@ -111,8 +111,7 @@ namespace DotNetOpenAuth.OAuth2 {
var client = this.AuthorizationServer.GetClientOrThrow(authorizationRequest.ClientIdentifier);
EndUserAuthorizationSuccessResponseBase response;
- switch (authorizationRequest.ResponseType)
- {
+ switch (authorizationRequest.ResponseType) {
case EndUserAuthorizationResponseType.AccessToken:
response = new EndUserAuthorizationSuccessAccessTokenResponse(callback, authorizationRequest);
break;
@@ -123,7 +122,8 @@ namespace DotNetOpenAuth.OAuth2 {
default:
throw ErrorUtilities.ThrowInternal("Unexpected response type.");
}
-
+
+ response.AuthorizingUsername = username;
return response;
}