summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs3
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj7
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs111
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/InMemoryTokenManager.cs147
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs214
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs59
-rw-r--r--samples/OAuth2ProtectedWebApi/Code/AuthorizationServerHost.cs156
-rw-r--r--samples/OAuth2ProtectedWebApi/Code/BearerTokenHandler.cs7
-rw-r--r--samples/OAuth2ProtectedWebApi/Code/MemoryCryptoKeyStore.cs54
-rw-r--r--samples/OAuth2ProtectedWebApi/Code/MemoryNonceStore.cs14
-rw-r--r--samples/OAuth2ProtectedWebApi/Controllers/TokenController.cs6
-rw-r--r--samples/OAuth2ProtectedWebApi/OAuth2ProtectedWebApi.csproj4
-rw-r--r--samples/OAuthClient/OAuthClient.csproj5
-rw-r--r--samples/OAuthConsumer/GoogleAddressBook.aspx.cs37
-rw-r--r--samples/OAuthConsumer/GoogleApps2Legged.aspx.cs22
-rw-r--r--samples/OAuthConsumer/OAuthConsumer.csproj3
-rw-r--r--samples/OAuthConsumer/SampleWcf.aspx.cs50
-rw-r--r--samples/OAuthConsumer/SignInWithTwitter.aspx.cs7
-rw-r--r--samples/OAuthConsumer/Twitter.aspx.cs47
-rw-r--r--samples/OAuthConsumer/Web.config4
-rw-r--r--samples/OAuthConsumer/Yammer.aspx.cs43
-rw-r--r--samples/OAuthConsumerWpf/Authorize.xaml.cs17
-rw-r--r--samples/OAuthConsumerWpf/Authorize2.xaml.cs4
-rw-r--r--samples/OAuthConsumerWpf/InMemoryTokenManager.cs58
-rw-r--r--samples/OAuthConsumerWpf/MainWindow.xaml42
-rw-r--r--samples/OAuthConsumerWpf/MainWindow.xaml.cs104
-rw-r--r--samples/OAuthConsumerWpf/OAuthConsumerWpf.csproj1
-rw-r--r--samples/OAuthServiceProvider/Code/Constants.cs4
-rw-r--r--samples/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs5
-rw-r--r--samples/OpenIdProviderWebForms/Code/OAuthHybrid.cs4
-rw-r--r--samples/OpenIdRelyingPartyWebForms/Code/State.cs7
-rw-r--r--samples/OpenIdRelyingPartyWebForms/Global.asax.cs32
-rw-r--r--samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs8
-rw-r--r--samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj3
-rw-r--r--samples/OpenIdRelyingPartyWebForms/loginPlusOAuth.aspx.cs5
-rw-r--r--samples/OpenIdRelyingPartyWebForms/loginPlusOAuthSampleOP.aspx.cs25
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs127
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs79
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs60
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthTokenManager.cs38
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs12
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs160
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs52
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs35
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs104
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs50
-rw-r--r--src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj8
-rw-r--r--src/DotNetOpenAuth.AspNet/WebResources.Designer.cs11
-rw-r--r--src/DotNetOpenAuth.AspNet/WebResources.resx3
-rw-r--r--src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj2
-rw-r--r--src/DotNetOpenAuth.Core/MachineKeyUtil.cs (renamed from src/DotNetOpenAuth.AspNet/MachineKeyUtil.cs)4
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/Bindings/HardCodedKeyCryptoKeyStore.cs98
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs9
-rw-r--r--src/DotNetOpenAuth.Core/Strings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth.Core/Strings.resx3
-rw-r--r--src/DotNetOpenAuth.OAuth.Common/DotNetOpenAuth.OAuth.Common.csproj1
-rw-r--r--src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthIdentity.cs64
-rw-r--r--src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthPrincipal.cs98
-rw-r--r--src/DotNetOpenAuth.OAuth.Common/Properties/AssemblyInfo.cs4
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj14
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs39
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs19
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs67
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs108
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs76
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs336
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs258
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs130
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs79
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs40
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs65
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs42
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs15
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/ServiceProviderDescription.cs85
-rw-r--r--src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs87
-rw-r--r--src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj3
-rw-r--r--src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuth1Principal.cs34
-rw-r--r--src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs14
-rw-r--r--src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProviderHostDescription.cs (renamed from src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs)8
-rw-r--r--src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs (renamed from src/DotNetOpenAuth.OAuth/OAuthReporting.cs)6
-rw-r--r--src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj3
-rw-r--r--src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs10
-rw-r--r--src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ClientDescription.cs33
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client.UI/OAuth2/ClientAuthorizationView.cs10
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs2
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs2
-rw-r--r--src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/ResourceServer.cs5
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs8
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs41
91 files changed, 1575 insertions, 2466 deletions
diff --git a/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs b/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs
index 452a898..3d37e1f 100644
--- a/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs
+++ b/projecttemplates/RelyingPartyLogic/OAuthAuthenticationModule.cs
@@ -8,6 +8,7 @@ namespace RelyingPartyLogic {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Security.Claims;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
@@ -84,7 +85,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 DotNetOpenAuth.OAuth.ChannelElements.OAuthPrincipal) {
+ if (this.application.User is ClaimsPrincipal) {
e.RolesPopulated = true;
}
}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
index 9f74693..19f26b5 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
+++ b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
@@ -101,9 +101,6 @@
<Compile Include="GoogleConsumer.cs" />
<Compile Include="HttpAsyncHandlerBase.cs" />
<Compile Include="InMemoryClientAuthorizationTracker.cs" />
- <Compile Include="InMemoryTokenManager.cs">
- <SubType>Code</SubType>
- </Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TwitterConsumer.cs" />
<Compile Include="Util.cs" />
@@ -138,6 +135,10 @@
<Project>{60426312-6AE5-4835-8667-37EDEA670222}</Project>
<Name>DotNetOpenAuth.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\src\DotNetOpenAuth.OAuth.Common\DotNetOpenAuth.OAuth.Common.csproj">
+ <Project>{115217c5-22cd-415c-a292-0dd0238cdd89}</Project>
+ <Name>DotNetOpenAuth.OAuth.Common</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\DotNetOpenAuth.OAuth.Consumer\DotNetOpenAuth.OAuth.Consumer.csproj">
<Project>{B202E40D-4663-4A2B-ACDA-865F88FF7CAA}</Project>
<Name>DotNetOpenAuth.OAuth.Consumer</Name>
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs
index cd3c5fe..a7c062e 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs
@@ -4,10 +4,10 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.ApplicationBlock
-{
+namespace DotNetOpenAuth.ApplicationBlock {
using System;
using System.Collections.Generic;
+ using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -20,6 +20,7 @@ namespace DotNetOpenAuth.ApplicationBlock
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+ using System.Web;
using System.Xml;
using System.Xml.Linq;
using DotNetOpenAuth.Messaging;
@@ -29,17 +30,15 @@ namespace DotNetOpenAuth.ApplicationBlock
/// <summary>
/// A consumer capable of communicating with Google Data APIs.
/// </summary>
- public static class GoogleConsumer
- {
+ public class GoogleConsumer : Consumer {
/// <summary>
/// The Consumer to use for accessing Google data APIs.
/// </summary>
- public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription {
- RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
- UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthAuthorizeToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
- AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetAccessToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- };
+ public static readonly ServiceProviderDescription ServiceDescription =
+ new ServiceProviderDescription(
+ "https://www.google.com/accounts/OAuthGetRequestToken",
+ "https://www.google.com/accounts/OAuthAuthorizeToken",
+ "https://www.google.com/accounts/OAuthGetAccessToken");
/// <summary>
/// A mapping between Google's applications and their URI scope values.
@@ -69,11 +68,22 @@ namespace DotNetOpenAuth.ApplicationBlock
private static readonly Uri GetContactsEndpoint = new Uri("http://www.google.com/m8/feeds/contacts/default/full/");
/// <summary>
+ /// Initializes a new instance of the <see cref="GoogleConsumer"/> class.
+ /// </summary>
+ public GoogleConsumer() {
+ this.ServiceProvider = ServiceDescription;
+ this.ConsumerKey = ConfigurationManager.AppSettings["googleConsumerKey"];
+ this.ConsumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"];
+ this.TemporaryCredentialStorage = HttpContext.Current != null
+ ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage()
+ : new MemoryTemporaryCredentialStorage();
+ }
+
+ /// <summary>
/// The many specific authorization scopes Google offers.
/// </summary>
[Flags]
- public enum Applications : long
- {
+ public enum Applications : long {
/// <summary>
/// The Gmail address book.
/// </summary>
@@ -156,74 +166,33 @@ namespace DotNetOpenAuth.ApplicationBlock
}
/// <summary>
- /// The service description to use for accessing Google data APIs using an X509 certificate.
+ /// Gets the scope URI in Google's format.
/// </summary>
- /// <param name="signingCertificate">The signing certificate.</param>
- /// <returns>A service description that can be used to create an instance of
- /// <see cref="DesktopConsumer"/> or <see cref="WebConsumer"/>. </returns>
- public static ServiceProviderDescription CreateRsaSha1ServiceDescription(X509Certificate2 signingCertificate) {
- if (signingCertificate == null) {
- throw new ArgumentNullException("signingCertificate");
- }
-
- return new ServiceProviderDescription {
- RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
- UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthAuthorizeToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
- AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetAccessToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new RsaSha1ConsumerSigningBindingElement(signingCertificate) },
- };
+ /// <param name="scope">The scope, which may include one or several Google applications.</param>
+ /// <returns>A space-delimited list of URIs for the requested Google applications.</returns>
+ public static string GetScopeUri(Applications scope) {
+ return string.Join(" ", Util.GetIndividualFlags(scope).Select(app => DataScopeUris[(Applications)app]).ToArray());
}
/// <summary>
/// Requests authorization from Google to access data from a set of Google applications.
/// </summary>
- /// <param name="consumer">The Google consumer previously constructed using <see cref="CreateWebConsumer" /> or <see cref="CreateDesktopConsumer" />.</param>
/// <param name="requestedAccessScope">The requested access scope.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that completes with the asynchronous operation.
/// </returns>
- /// <exception cref="System.ArgumentNullException">consumer</exception>
- public static async Task RequestAuthorizationAsync(WebConsumer consumer, Applications requestedAccessScope, CancellationToken cancellationToken = default(CancellationToken)) {
- if (consumer == null) {
- throw new ArgumentNullException("consumer");
- }
-
+ public Task<Uri> RequestUserAuthorizationAsync(Applications requestedAccessScope, CancellationToken cancellationToken = default(CancellationToken)) {
var extraParameters = new Dictionary<string, string> {
{ "scope", GetScopeUri(requestedAccessScope) },
};
Uri callback = Util.GetCallbackUrlFromContext();
- var request = await consumer.PrepareRequestUserAuthorizationAsync(callback, extraParameters, null, cancellationToken);
- var redirectingResponse = await consumer.Channel.PrepareResponseAsync(request, cancellationToken);
- redirectingResponse.Send();
- }
-
- /// <summary>
- /// Requests authorization from Google to access data from a set of Google applications.
- /// </summary>
- /// <param name="consumer">The Google consumer previously constructed using <see cref="CreateWebConsumer" /> or <see cref="CreateDesktopConsumer" />.</param>
- /// <param name="requestedAccessScope">The requested access scope.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The URI to redirect to and the request token.
- /// </returns>
- /// <exception cref="System.ArgumentNullException">consumer</exception>
- public static Task<Tuple<Uri, string>> RequestAuthorizationAsync(DesktopConsumer consumer, Applications requestedAccessScope, CancellationToken cancellationToken = default(CancellationToken)) {
- if (consumer == null) {
- throw new ArgumentNullException("consumer");
- }
-
- var extraParameters = new Dictionary<string, string> {
- { "scope", GetScopeUri(requestedAccessScope) },
- };
-
- return consumer.RequestUserAuthorizationAsync(extraParameters, null, cancellationToken);
+ return this.RequestUserAuthorizationAsync(callback, extraParameters, cancellationToken);
}
/// <summary>
/// Gets the Gmail address book's contents.
/// </summary>
- /// <param name="consumer">The Google consumer.</param>
/// <param name="accessToken">The access token previously retrieved.</param>
/// <param name="maxResults">The maximum number of entries to return. If you want to receive all of the contacts, rather than only the default maximum, you can specify a very large number here.</param>
/// <param name="startIndex">The 1-based index of the first result to be retrieved (for paging).</param>
@@ -231,15 +200,10 @@ namespace DotNetOpenAuth.ApplicationBlock
/// <returns>
/// An XML document returned by Google.
/// </returns>
- /// <exception cref="System.ArgumentNullException">consumer</exception>
- public static async Task<XDocument> GetContactsAsync(ConsumerBase consumer, string accessToken, int maxResults = 25, int startIndex = 1, CancellationToken cancellationToken = default(CancellationToken)) {
- if (consumer == null) {
- throw new ArgumentNullException("consumer");
- }
-
+ public async Task<XDocument> GetContactsAsync(AccessToken accessToken, int maxResults = 25, int startIndex = 1, CancellationToken cancellationToken = default(CancellationToken)) {
// Enable gzip compression. Google only compresses the response for recognized user agent headers. - Mike Lim
var handler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip };
- using (var httpClient = consumer.CreateHttpClient(accessToken, handler)) {
+ using (var httpClient = this.CreateHttpClient(accessToken, handler)) {
var request = new HttpRequestMessage(HttpMethod.Get, GetContactsEndpoint);
request.Content = new FormUrlEncodedContent(
new Dictionary<string, string>() {
@@ -255,7 +219,7 @@ namespace DotNetOpenAuth.ApplicationBlock
}
}
- public static async Task PostBlogEntryAsync(ConsumerBase consumer, string accessToken, string blogUrl, string title, XElement body, CancellationToken cancellationToken) {
+ public async Task PostBlogEntryAsync(AccessToken accessToken, string blogUrl, string title, XElement body, CancellationToken cancellationToken = default(CancellationToken)) {
string feedUrl;
var getBlogHome = WebRequest.Create(blogUrl);
using (var blogHomeResponse = getBlogHome.GetResponse()) {
@@ -285,7 +249,7 @@ namespace DotNetOpenAuth.ApplicationBlock
var request = new HttpRequestMessage(HttpMethod.Post, feedUrl);
request.Content = new StreamContent(ms);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/atom+xml");
- using (var httpClient = consumer.CreateHttpClient(accessToken)) {
+ using (var httpClient = this.CreateHttpClient(accessToken)) {
using (var response = await httpClient.SendAsync(request, cancellationToken)) {
if (response.StatusCode == HttpStatusCode.Created) {
// Success
@@ -296,14 +260,5 @@ namespace DotNetOpenAuth.ApplicationBlock
}
}
}
-
- /// <summary>
- /// Gets the scope URI in Google's format.
- /// </summary>
- /// <param name="scope">The scope, which may include one or several Google applications.</param>
- /// <returns>A space-delimited list of URIs for the requested Google applications.</returns>
- public static string GetScopeUri(Applications scope) {
- return string.Join(" ", Util.GetIndividualFlags(scope).Select(app => DataScopeUris[(Applications)app]).ToArray());
- }
}
}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/InMemoryTokenManager.cs b/samples/DotNetOpenAuth.ApplicationBlock/InMemoryTokenManager.cs
deleted file mode 100644
index 35f6c08..0000000
--- a/samples/DotNetOpenAuth.ApplicationBlock/InMemoryTokenManager.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="InMemoryTokenManager.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.ApplicationBlock {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
- using DotNetOpenAuth.OpenId.Extensions.OAuth;
-
-#if SAMPLESONLY
- /// <summary>
- /// A token manager that only retains tokens in memory.
- /// Meant for SHORT TERM USE TOKENS ONLY.
- /// </summary>
- /// <remarks>
- /// A likely application of this class is for "Sign In With Twitter",
- /// where the user only signs in without providing any authorization to access
- /// Twitter APIs except to authenticate, since that access token is only useful once.
- /// </remarks>
- internal class InMemoryTokenManager : IConsumerTokenManager, IOpenIdOAuthTokenManager {
- private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
-
- /// <summary>
- /// Initializes a new instance of the <see cref="InMemoryTokenManager"/> class.
- /// </summary>
- /// <param name="consumerKey">The consumer key.</param>
- /// <param name="consumerSecret">The consumer secret.</param>
- public InMemoryTokenManager(string consumerKey, string consumerSecret) {
- if (string.IsNullOrEmpty(consumerKey)) {
- throw new ArgumentNullException("consumerKey");
- }
-
- this.ConsumerKey = consumerKey;
- this.ConsumerSecret = consumerSecret;
- }
-
- /// <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; }
-
- #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) {
- return this.tokensAndSecrets[token];
- }
-
- /// <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) {
- this.tokensAndSecrets[response.Token] = response.TokenSecret;
- }
-
- /// <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) {
- this.tokensAndSecrets.Remove(requestToken);
- this.tokensAndSecrets[accessToken] = accessTokenSecret;
- }
-
- /// <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) {
- throw new NotImplementedException();
- }
-
- #endregion
-
- #region IOpenIdOAuthTokenManager Members
-
- /// <summary>
- /// Stores a new request token obtained over an OpenID request.
- /// </summary>
- /// <param name="consumerKey">The consumer key.</param>
- /// <param name="authorization">The authorization message carrying the request token and authorized access scope.</param>
- /// <remarks>
- /// <para>The token secret is the empty string.</para>
- /// <para>Tokens stored by this method should be short-lived to mitigate
- /// possible security threats. Their lifetime should be sufficient for the
- /// relying party to receive the positive authentication assertion and immediately
- /// send a follow-up request for the access token.</para>
- /// </remarks>
- public void StoreOpenIdAuthorizedRequestToken(string consumerKey, AuthorizationApprovedResponse authorization) {
- this.tokensAndSecrets[authorization.RequestToken] = string.Empty;
- }
-
- #endregion
- }
-#else
-#error The InMemoryTokenManager class is only for samples as it forgets all tokens whenever the application restarts! You should implement IConsumerTokenManager in your own app that stores tokens in a persistent store (like a SQL database).
-#endif
-} \ No newline at end of file
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs
index e665d96..16f1c92 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs
@@ -30,27 +30,23 @@ namespace DotNetOpenAuth.ApplicationBlock {
/// <summary>
/// A consumer capable of communicating with Twitter.
/// </summary>
- public static class TwitterConsumer {
+ public class TwitterConsumer : Consumer {
/// <summary>
/// The description of Twitter's OAuth protocol URIs for use with actually reading/writing
/// a user's private Twitter data.
/// </summary>
- public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription {
- RequestTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/request_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- UserAuthorizationEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/authorize", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- AccessTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/access_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- };
+ public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription(
+ "https://api.twitter.com/oauth/request_token",
+ "https://api.twitter.com/oauth/authorize",
+ "https://api.twitter.com/oauth/access_token");
/// <summary>
/// The description of Twitter's OAuth protocol URIs for use with their "Sign in with Twitter" feature.
/// </summary>
- public static readonly ServiceProviderDescription SignInWithTwitterServiceDescription = new ServiceProviderDescription {
- RequestTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/request_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- UserAuthorizationEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/authenticate", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- AccessTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/access_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- };
+ public static readonly ServiceProviderDescription SignInWithTwitterServiceDescription = new ServiceProviderDescription(
+ "https://api.twitter.com/oauth/request_token",
+ "https://api.twitter.com/oauth/authenticate",
+ "https://api.twitter.com/oauth/access_token");
/// <summary>
/// The URI to get a user's favorites.
@@ -69,21 +65,26 @@ namespace DotNetOpenAuth.ApplicationBlock {
private static readonly Uri VerifyCredentialsEndpoint = new Uri("http://api.twitter.com/1/account/verify_credentials.xml");
/// <summary>
- /// The consumer used for the Sign in to Twitter feature.
+ /// Initializes a new instance of the <see cref="TwitterConsumer"/> class.
/// </summary>
- private static WebConsumer signInConsumer;
-
- /// <summary>
- /// The lock acquired to initialize the <see cref="signInConsumer"/> field.
- /// </summary>
- private static object signInConsumerInitLock = new object();
+ public TwitterConsumer() {
+ this.ServiceProvider = ServiceDescription;
+ this.ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"];
+ this.ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"];
+ this.TemporaryCredentialStorage = HttpContext.Current != null
+ ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage()
+ : new MemoryTemporaryCredentialStorage();
+ }
/// <summary>
- /// Initializes static members of the <see cref="TwitterConsumer"/> class.
+ /// Initializes a new instance of the <see cref="TwitterConsumer"/> class.
/// </summary>
- static TwitterConsumer() {
- // Twitter can't handle the Expect 100 Continue HTTP header.
- ServicePointManager.FindServicePoint(GetFavoritesEndpoint).Expect100Continue = false;
+ /// <param name="consumerKey">The consumer key.</param>
+ /// <param name="consumerSecret">The consumer secret.</param>
+ public TwitterConsumer(string consumerKey, string consumerSecret)
+ : this() {
+ this.ConsumerKey = consumerKey;
+ this.ConsumerSecret = consumerSecret;
}
/// <summary>
@@ -96,46 +97,68 @@ namespace DotNetOpenAuth.ApplicationBlock {
}
}
+ public static Consumer CreateConsumer(bool forWeb = true) {
+ string consumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"];
+ string consumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"];
+ if (IsTwitterConsumerConfigured) {
+ ITemporaryCredentialStorage storage = forWeb ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage() : new MemoryTemporaryCredentialStorage();
+ return new Consumer(consumerKey, consumerSecret, ServiceDescription, storage) {
+ HostFactories = new TwitterHostFactories(),
+ };
+ } else {
+ throw new InvalidOperationException("No Twitter OAuth consumer key and secret could be found in web.config AppSettings.");
+ }
+ }
+
/// <summary>
- /// Gets the consumer to use for the Sign in to Twitter feature.
+ /// Prepares a redirect that will send the user to Twitter to sign in.
/// </summary>
- /// <value>The twitter sign in.</value>
- private static WebConsumer TwitterSignIn {
- get {
- if (signInConsumer == null) {
- lock (signInConsumerInitLock) {
- if (signInConsumer == null) {
- signInConsumer = new WebConsumer(SignInWithTwitterServiceDescription, ShortTermUserSessionTokenManager);
- }
- }
- }
-
- return signInConsumer;
+ /// <param name="forceNewLogin">if set to <c>true</c> the user will be required to re-enter their Twitter credentials even if already logged in to Twitter.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The redirect message.
+ /// </returns>
+ public static async Task<Uri> StartSignInWithTwitterAsync(bool forceNewLogin = false, CancellationToken cancellationToken = default(CancellationToken)) {
+ var redirectParameters = new Dictionary<string, string>();
+ if (forceNewLogin) {
+ redirectParameters["force_login"] = "true";
}
- }
+ Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_");
- private static InMemoryTokenManager ShortTermUserSessionTokenManager {
- get {
- var store = HttpContext.Current.Session;
- var tokenManager = (InMemoryTokenManager)store["TwitterShortTermUserSessionTokenManager"];
- if (tokenManager == null) {
- string consumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"];
- string consumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"];
- if (IsTwitterConsumerConfigured) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- store["TwitterShortTermUserSessionTokenManager"] = tokenManager;
- } else {
- throw new InvalidOperationException("No Twitter OAuth consumer key and secret could be found in web.config AppSettings.");
- }
- }
+ var consumer = CreateConsumer();
+ consumer.ServiceProvider = SignInWithTwitterServiceDescription;
+ Uri redirectUrl = await consumer.RequestUserAuthorizationAsync(callback, cancellationToken: cancellationToken);
+ return redirectUrl;
+ }
- return tokenManager;
+ /// <summary>
+ /// Checks the incoming web request to see if it carries a Twitter authentication response,
+ /// and provides the user's Twitter screen name and unique id if available.
+ /// </summary>
+ /// <param name="completeUrl">The URL that came back from the service provider to complete the authorization.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// A tuple with the screen name and Twitter unique user ID if successful; otherwise <c>null</c>.
+ /// </returns>
+ public static async Task<Tuple<string, int>> TryFinishSignInWithTwitterAsync(Uri completeUrl = null, CancellationToken cancellationToken = default(CancellationToken)) {
+ var consumer = CreateConsumer();
+ consumer.ServiceProvider = SignInWithTwitterServiceDescription;
+ var response = await consumer.ProcessUserAuthorizationAsync(completeUrl ?? HttpContext.Current.Request.Url, cancellationToken: cancellationToken);
+ if (response == null) {
+ return null;
}
+
+ string screenName = response.ExtraData["screen_name"];
+ int userId = int.Parse(response.ExtraData["user_id"]);
+ return Tuple.Create(screenName, userId);
}
- public static async Task<JArray> GetUpdatesAsync(
- ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
- using (var httpClient = twitter.CreateHttpClient(accessToken)) {
+ public async Task<JArray> GetUpdatesAsync(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ if (String.IsNullOrEmpty(accessToken.Token)) {
+ throw new ArgumentNullException("accessToken.Token");
+ }
+
+ using (var httpClient = this.CreateHttpClient(accessToken)) {
using (var response = await httpClient.GetAsync(GetFriendTimelineStatusEndpoint, cancellationToken)) {
response.EnsureSuccessStatusCode();
string jsonString = await response.Content.ReadAsStringAsync();
@@ -145,8 +168,12 @@ namespace DotNetOpenAuth.ApplicationBlock {
}
}
- public static async Task<XDocument> GetFavorites(ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
- using (var httpClient = twitter.CreateHttpClient(accessToken)) {
+ public async Task<XDocument> GetFavorites(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ if (String.IsNullOrEmpty(accessToken.Token)) {
+ throw new ArgumentNullException("accessToken.Token");
+ }
+
+ using (var httpClient = this.CreateHttpClient(accessToken)) {
using (HttpResponseMessage response = await httpClient.GetAsync(GetFavoritesEndpoint, cancellationToken)) {
response.EnsureSuccessStatusCode();
return XDocument.Parse(await response.Content.ReadAsStringAsync());
@@ -154,7 +181,7 @@ namespace DotNetOpenAuth.ApplicationBlock {
}
}
- public static async Task<XDocument> UpdateProfileBackgroundImageAsync(ConsumerBase twitter, string accessToken, string image, bool tile, CancellationToken cancellationToken) {
+ public async Task<XDocument> UpdateProfileBackgroundImageAsync(AccessToken accessToken, string image, bool tile, CancellationToken cancellationToken) {
var imageAttachment = new StreamContent(File.OpenRead(image));
imageAttachment.Headers.ContentType = new MediaTypeHeaderValue("image/" + Path.GetExtension(image).Substring(1).ToLowerInvariant());
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UpdateProfileBackgroundImageEndpoint);
@@ -163,7 +190,7 @@ namespace DotNetOpenAuth.ApplicationBlock {
content.Add(new StringContent(tile.ToString().ToLowerInvariant()), "tile");
request.Content = content;
request.Headers.ExpectContinue = false;
- using (var httpClient = twitter.CreateHttpClient(accessToken)) {
+ using (var httpClient = this.CreateHttpClient(accessToken)) {
using (HttpResponseMessage response = await httpClient.SendAsync(request, cancellationToken)) {
response.EnsureSuccessStatusCode();
string responseString = await response.Content.ReadAsStringAsync();
@@ -172,19 +199,19 @@ namespace DotNetOpenAuth.ApplicationBlock {
}
}
- public static Task<XDocument> UpdateProfileImageAsync(ConsumerBase twitter, string accessToken, string pathToImage, CancellationToken cancellationToken = default(CancellationToken)) {
+ public Task<XDocument> UpdateProfileImageAsync(AccessToken accessToken, string pathToImage, CancellationToken cancellationToken = default(CancellationToken)) {
string contentType = "image/" + Path.GetExtension(pathToImage).Substring(1).ToLowerInvariant();
- return UpdateProfileImageAsync(twitter, accessToken, File.OpenRead(pathToImage), contentType, cancellationToken);
+ return this.UpdateProfileImageAsync(accessToken, File.OpenRead(pathToImage), contentType, cancellationToken);
}
- public static async Task<XDocument> UpdateProfileImageAsync(ConsumerBase twitter, string accessToken, Stream image, string contentType, CancellationToken cancellationToken = default(CancellationToken)) {
+ public async Task<XDocument> UpdateProfileImageAsync(AccessToken accessToken, Stream image, string contentType, CancellationToken cancellationToken = default(CancellationToken)) {
var imageAttachment = new StreamContent(image);
imageAttachment.Headers.ContentType = new MediaTypeHeaderValue(contentType);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UpdateProfileImageEndpoint);
var content = new MultipartFormDataContent();
content.Add(imageAttachment, "image", "twitterPhoto");
request.Content = content;
- using (var httpClient = twitter.CreateHttpClient(accessToken)) {
+ using (var httpClient = this.CreateHttpClient(accessToken)) {
using (HttpResponseMessage response = await httpClient.SendAsync(request, cancellationToken)) {
response.EnsureSuccessStatusCode();
string responseString = await response.Content.ReadAsStringAsync();
@@ -193,8 +220,8 @@ namespace DotNetOpenAuth.ApplicationBlock {
}
}
- public static async Task<XDocument> VerifyCredentialsAsync(ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
- using (var httpClient = twitter.CreateHttpClient(accessToken)) {
+ public async Task<XDocument> VerifyCredentialsAsync(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ using (var httpClient = this.CreateHttpClient(accessToken)) {
using (var response = await httpClient.GetAsync(VerifyCredentialsEndpoint, cancellationToken)) {
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync()) {
@@ -204,57 +231,26 @@ namespace DotNetOpenAuth.ApplicationBlock {
}
}
- public static async Task<string> GetUsername(ConsumerBase twitter, string accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
- XDocument xml = await VerifyCredentialsAsync(twitter, accessToken, cancellationToken);
+ public async Task<string> GetUsername(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) {
+ XDocument xml = await this.VerifyCredentialsAsync(accessToken, cancellationToken);
XPathNavigator nav = xml.CreateNavigator();
return nav.SelectSingleNode("/user/screen_name").Value;
}
- /// <summary>
- /// Prepares a redirect that will send the user to Twitter to sign in.
- /// </summary>
- /// <param name="forceNewLogin">if set to <c>true</c> the user will be required to re-enter their Twitter credentials even if already logged in to Twitter.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The redirect message.
- /// </returns>
- /// <remarks>
- /// Call <see cref="OutgoingWebResponse.Send" /> or
- /// <c>return StartSignInWithTwitter().<see cref="MessagingUtilities.AsActionResult">AsActionResult()</see></c>
- /// to actually perform the redirect.
- /// </remarks>
- public static async Task<HttpResponseMessage> StartSignInWithTwitterAsync(bool forceNewLogin = false, CancellationToken cancellationToken = default(CancellationToken)) {
- var redirectParameters = new Dictionary<string, string>();
- if (forceNewLogin) {
- redirectParameters["force_login"] = "true";
- }
- Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_");
- var request = await TwitterSignIn.PrepareRequestUserAuthorizationAsync(callback, null, redirectParameters, cancellationToken);
- return await TwitterSignIn.Channel.PrepareResponseAsync(request, cancellationToken);
- }
+ private class TwitterHostFactories : IHostFactories {
+ private static readonly IHostFactories underlyingFactories = new DefaultOAuthHostFactories();
- /// <summary>
- /// Checks the incoming web request to see if it carries a Twitter authentication response,
- /// and provides the user's Twitter screen name and unique id if available.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// A tuple with the screen name and Twitter unique user ID if successful; otherwise <c>null</c>.
- /// </returns>
- public static async Task<Tuple<string, int>> TryFinishSignInWithTwitterAsync(CancellationToken cancellationToken = default(CancellationToken)) {
- var response = await TwitterSignIn.ProcessUserAuthorizationAsync(cancellationToken: cancellationToken);
- if (response == null) {
- return null;
+ public HttpMessageHandler CreateHttpMessageHandler() {
+ return new WebRequestHandler();
}
- string screenName = response.ExtraData["screen_name"];
- int userId = int.Parse(response.ExtraData["user_id"]);
-
- // If we were going to make this LOOK like OpenID even though it isn't,
- // this seems like a reasonable, secure claimed id to allow the user to assume.
- ////OpenId.Identifier fake_claimed_id = string.Format(CultureInfo.InvariantCulture, "http://twitter.com/{0}#{1}", screenName, userId);
+ public HttpClient CreateHttpClient(HttpMessageHandler handler = null) {
+ var client = underlyingFactories.CreateHttpClient(handler);
- return Tuple.Create(screenName, userId);
+ // Twitter can't handle the Expect 100 Continue HTTP header.
+ client.DefaultRequestHeaders.ExpectContinue = false;
+ return client;
+ }
}
}
}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs
index cedcbf7..1dff5b6 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs
@@ -4,61 +4,48 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.ApplicationBlock
-{
+namespace DotNetOpenAuth.ApplicationBlock {
using System;
using System.Collections.Generic;
+ using System.Configuration;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+ using System.Web;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
- public static class YammerConsumer
- {
+ public class YammerConsumer : Consumer {
/// <summary>
/// The Consumer to use for accessing Google data APIs.
/// </summary>
- public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription {
- RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.yammer.com/oauth/request_token", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest),
- UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.yammer.com/oauth/authorize", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest),
- AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.yammer.com/oauth/access_token", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new PlaintextSigningBindingElement() },
- ProtocolVersion = ProtocolVersion.V10,
- };
+ public static readonly ServiceProviderDescription ServiceDescription =
+ new ServiceProviderDescription(
+ "https://www.yammer.com/oauth/request_token",
+ "https://www.yammer.com/oauth/authorize",
+ "https://www.yammer.com/oauth/access_token");
- public static DesktopConsumer CreateConsumer(IConsumerTokenManager tokenManager) {
- return new DesktopConsumer(ServiceDescription, tokenManager);
+ public YammerConsumer() {
+ this.ServiceProvider = ServiceDescription;
+ this.ConsumerKey = ConfigurationManager.AppSettings["YammerConsumerKey"];
+ this.ConsumerSecret = ConfigurationManager.AppSettings["YammerConsumerSecret"];
+ this.TemporaryCredentialStorage = HttpContext.Current != null
+ ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage()
+ : new MemoryTemporaryCredentialStorage();
}
- public static Task<Tuple<Uri, string>> PrepareRequestAuthorizationAsync(DesktopConsumer consumer, CancellationToken cancellationToken = default(CancellationToken)) {
- if (consumer == null) {
- throw new ArgumentNullException("consumer");
+ /// <summary>
+ /// Gets a value indicating whether the Twitter consumer key and secret are set in the web.config file.
+ /// </summary>
+ public static bool IsConsumerConfigured {
+ get {
+ return !string.IsNullOrEmpty(ConfigurationManager.AppSettings["yammerConsumerKey"]) &&
+ !string.IsNullOrEmpty(ConfigurationManager.AppSettings["yammerConsumerSecret"]);
}
-
- return consumer.RequestUserAuthorizationAsync(null, null, cancellationToken);
- }
-
- public static async Task<AuthorizedTokenResponse> CompleteAuthorizationAsync(DesktopConsumer consumer, string requestToken, string userCode, CancellationToken cancellationToken = default(CancellationToken)) {
- // Because Yammer has a proprietary callback_token parameter, and it's passed
- // with the message that specifically bans extra arguments being passed, we have
- // to cheat by adding the data to the URL itself here.
- var customServiceDescription = new ServiceProviderDescription {
- RequestTokenEndpoint = ServiceDescription.RequestTokenEndpoint,
- UserAuthorizationEndpoint = ServiceDescription.UserAuthorizationEndpoint,
- AccessTokenEndpoint = new MessageReceivingEndpoint(ServiceDescription.AccessTokenEndpoint.Location.AbsoluteUri + "?oauth_verifier=" + Uri.EscapeDataString(userCode), HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest),
- TamperProtectionElements = ServiceDescription.TamperProtectionElements,
- ProtocolVersion = ProtocolVersion.V10,
- };
-
- // To use a custom service description we also must create a new WebConsumer.
- var customConsumer = new DesktopConsumer(customServiceDescription, consumer.TokenManager);
- var response = await customConsumer.ProcessUserAuthorizationAsync(requestToken, userCode, cancellationToken);
- return response;
}
}
}
diff --git a/samples/OAuth2ProtectedWebApi/Code/AuthorizationServerHost.cs b/samples/OAuth2ProtectedWebApi/Code/AuthorizationServerHost.cs
index 73c5864..843280b 100644
--- a/samples/OAuth2ProtectedWebApi/Code/AuthorizationServerHost.cs
+++ b/samples/OAuth2ProtectedWebApi/Code/AuthorizationServerHost.cs
@@ -1,49 +1,181 @@
-namespace OAuth2ProtectedWebApi {
+namespace OAuth2ProtectedWebApi.Code {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
+ using System.Web.Security;
using DotNetOpenAuth.Messaging.Bindings;
using DotNetOpenAuth.OAuth2;
using DotNetOpenAuth.OAuth2.ChannelElements;
using DotNetOpenAuth.OAuth2.Messages;
using OAuth2ProtectedWebApi.Code;
+ /// <summary>
+ /// Provides application-specific policy and persistence for OAuth 2.0 authorization servers.
+ /// </summary>
public class AuthorizationServerHost : IAuthorizationServerHost {
- private static ICryptoKeyStore cryptoKeyStore = MemoryCryptoKeyStore.Instance;
-
- private static INonceStore nonceStore = new MemoryNonceStore();
+ /// <summary>
+ /// Storage for the cryptographic keys used to protect authorization codes, refresh tokens and access tokens.
+ /// </summary>
+ /// <remarks>
+ /// A single, hard-coded symmetric key is hardly adequate. Applications that rely on decent security should
+ /// replace this implementation with one that actually stores and retrieves keys in some persistent store
+ /// (e.g. a database). DotNetOpenAuth will automatically take care of generating, rotating, and expiring keys
+ /// if you provide a real implementation of this interface.
+ /// TODO: Consider replacing use of <see cref="HardCodedKeyCryptoKeyStore"/> with a real persisted database table.
+ /// </remarks>
+ internal static readonly ICryptoKeyStore HardCodedCryptoKeyStore = new HardCodedKeyCryptoKeyStore("p7J1L24Qj4KGYUOrnfENF0XAhqn6rZc5dx4nxvI22Kg=");
+ /// <summary>
+ /// Gets the store for storing crypto keys used to symmetrically encrypt and sign authorization codes and refresh tokens.
+ /// </summary>
+ /// <remarks>
+ /// This store should be kept strictly confidential in the authorization server(s)
+ /// and NOT shared with the resource server. Anyone with these secrets can mint
+ /// tokens to essentially grant themselves access to anything they want.
+ /// </remarks>
public ICryptoKeyStore CryptoKeyStore {
- get { return cryptoKeyStore; }
+ get { return HardCodedCryptoKeyStore; }
}
+ /// <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 NonceStore {
- get { return nonceStore; }
+ get {
+ // TODO: Consider implementing a nonce store to mitigate replay attacks on authorization codes.
+ return null;
+ }
}
+ /// <summary>
+ /// Acquires the access token and related parameters that go into the formulation of the token endpoint's response to a client.
+ /// </summary>
+ /// <param name="accessTokenRequestMessage">Details regarding the resources that the access token will grant access to, and the identity of the client
+ /// that will receive that access.
+ /// Based on this information the receiving resource server can be determined and the lifetime of the access
+ /// token can be set based on the sensitivity of the resources.</param>
+ /// <returns>
+ /// A non-null parameters instance that DotNetOpenAuth will dispose after it has been used.
+ /// </returns>
public AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage) {
- var accessToken = new AuthorizationServerAccessToken();
- accessToken.Lifetime = TimeSpan.FromHours(1);
- accessToken.SymmetricKeyStore = this.CryptoKeyStore;
+ // If your resource server and authorization server are different web apps,
+ // consider using asymmetric keys instead of symmetric ones by setting different
+ // properties on the access token below.
+ var accessToken = new AuthorizationServerAccessToken {
+ Lifetime = TimeSpan.FromHours(1),
+ SymmetricKeyStore = this.CryptoKeyStore,
+ };
var result = new AccessTokenResult(accessToken);
return result;
}
+ /// <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 IClientDescription GetClient(string clientIdentifier) {
- return new ClientDescription("zzz", new Uri("http://www.microsoft.com/en-us/default.aspx"), ClientType.Confidential);
+ // TODO: Consider adding a clients table in your database to track actual client accounts
+ // with authenticating secrets.
+ // For now, just allow all clients regardless of ID, and consider them "Public" clients.
+ return new AnyCallbackClient();
}
+ /// <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(IAuthorizationDescription authorization) {
+ // If your application supports access revocation (highly recommended),
+ // this method should return false if the specified authorization is not
+ // discovered in your current authorizations table.
+ //// TODO: code here
+
return true;
}
+ /// <summary>
+ /// Determines whether a given set of resource owner credentials is valid based on the authorization server's user database
+ /// and if so records an authorization entry such that subsequent calls to <see cref="IsAuthorizationValid" /> would
+ /// return <c>true</c>.
+ /// </summary>
+ /// <param name="userName">Username on the account.</param>
+ /// <param name="password">The user's password.</param>
+ /// <param name="accessRequest">The access request the credentials came with.
+ /// This may be useful if the authorization server wishes to apply some policy based on the client that is making the request.</param>
+ /// <returns>
+ /// A value that describes the result of the authorization check.
+ /// </returns>
+ /// <exception cref="System.NotSupportedException"></exception>
public AutomatedUserAuthorizationCheckResponse CheckAuthorizeResourceOwnerCredentialGrant(string userName, string password, IAccessTokenRequest accessRequest) {
- throw new NotSupportedException();
+ // TODO: Consider only accepting resource owner credential grants from specific clients
+ // based on accessRequest.ClientIdentifier and accessRequest.ClientAuthenticated.
+ if (Membership.ValidateUser(userName, password)) {
+ // Add an entry to your authorization table to record that access was granted so that
+ // you can conditionally return true from IsAuthorizationValid when the row is discovered.
+ //// TODO: code here
+
+ // Inform DotNetOpenAuth that it may proceed to issue an access token.
+ return new AutomatedUserAuthorizationCheckResponse(accessRequest, true, Membership.GetUser(userName).UserName);
+ } else {
+ return new AutomatedUserAuthorizationCheckResponse(accessRequest, false, null);
+ }
}
+ /// <summary>
+ /// Determines whether an access token request given a client credential grant should be authorized
+ /// and if so records an authorization entry such that subsequent calls to <see cref="IsAuthorizationValid" /> would
+ /// return <c>true</c>.
+ /// </summary>
+ /// <param name="accessRequest">The access request the credentials came with.
+ /// This may be useful if the authorization server wishes to apply some policy based on the client that is making the request.</param>
+ /// <returns>
+ /// A value that describes the result of the authorization check.
+ /// </returns>
+ /// <exception cref="System.NotSupportedException"></exception>
public AutomatedAuthorizationCheckResponse CheckAuthorizeClientCredentialsGrant(IAccessTokenRequest accessRequest) {
- throw new NotSupportedException();
+ // TODO: Consider implementing this if your application should support clients that access data that
+ // doesn't belong to specific people, or clients that have elevated privileges and can access other
+ // people's data.
+ if (accessRequest.ClientAuthenticated) {
+ // Before returning a positive response, be *very careful* to validate the requested access scope
+ // to make sure it is appropriate for the requesting client.
+ throw new NotSupportedException();
+ } else {
+ // Only authenticated clients should be given access.
+ return new AutomatedAuthorizationCheckResponse(accessRequest, false);
+ }
+ }
+
+ private class AnyCallbackClient : ClientDescription {
+ public override bool IsCallbackAllowed(Uri callback) {
+ return true;
+ }
}
}
} \ No newline at end of file
diff --git a/samples/OAuth2ProtectedWebApi/Code/BearerTokenHandler.cs b/samples/OAuth2ProtectedWebApi/Code/BearerTokenHandler.cs
index 04296b4..23ec087 100644
--- a/samples/OAuth2ProtectedWebApi/Code/BearerTokenHandler.cs
+++ b/samples/OAuth2ProtectedWebApi/Code/BearerTokenHandler.cs
@@ -9,12 +9,15 @@
using DotNetOpenAuth.OAuth2;
+ /// <summary>
+ /// An HTTP server message handler that detects OAuth 2 bearer tokens in the authorization header
+ /// and applies the appropriate principal to the request when found.
+ /// </summary>
public class BearerTokenHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
if (request.Headers.Authorization != null) {
if (request.Headers.Authorization.Scheme == "Bearer") {
- string bearer = request.Headers.Authorization.Parameter;
- var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(MemoryCryptoKeyStore.Instance));
+ var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(AuthorizationServerHost.HardCodedCryptoKeyStore));
var principal = await resourceServer.GetPrincipalAsync(request, cancellationToken);
HttpContext.Current.User = principal;
Thread.CurrentPrincipal = principal;
diff --git a/samples/OAuth2ProtectedWebApi/Code/MemoryCryptoKeyStore.cs b/samples/OAuth2ProtectedWebApi/Code/MemoryCryptoKeyStore.cs
deleted file mode 100644
index 2bed4fd..0000000
--- a/samples/OAuth2ProtectedWebApi/Code/MemoryCryptoKeyStore.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-namespace OAuth2ProtectedWebApi.Code {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- using DotNetOpenAuth.Messaging.Bindings;
-
- internal class MemoryCryptoKeyStore : ICryptoKeyStore {
- private Dictionary<string, Dictionary<string, CryptoKey>> keys = new Dictionary<string, Dictionary<string, CryptoKey>>();
-
- private MemoryCryptoKeyStore() {
- }
-
- internal static ICryptoKeyStore Instance = new MemoryCryptoKeyStore();
-
- public CryptoKey GetKey(string bucket, string handle) {
- Dictionary<string, CryptoKey> keyBucket;
- if (this.keys.TryGetValue(bucket, out keyBucket)) {
- CryptoKey key;
- if (keyBucket.TryGetValue(handle, out key)) {
- return key;
- }
- }
-
- return null;
- }
-
- public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
- Dictionary<string, CryptoKey> keyBucket;
- if (this.keys.TryGetValue(bucket, out keyBucket)) {
- foreach (var cryptoKey in keyBucket) {
- yield return cryptoKey;
- }
- }
- }
-
- public void StoreKey(string bucket, string handle, CryptoKey key) {
- Dictionary<string, CryptoKey> keyBucket;
- if (!this.keys.TryGetValue(bucket, out keyBucket)) {
- keyBucket = this.keys[bucket] = new Dictionary<string, CryptoKey>();
- }
-
- keyBucket[handle] = key;
- }
-
- public void RemoveKey(string bucket, string handle) {
- Dictionary<string, CryptoKey> keyBucket;
- if (this.keys.TryGetValue(bucket, out keyBucket)) {
- keyBucket.Remove(handle);
- }
- }
- }
-} \ No newline at end of file
diff --git a/samples/OAuth2ProtectedWebApi/Code/MemoryNonceStore.cs b/samples/OAuth2ProtectedWebApi/Code/MemoryNonceStore.cs
deleted file mode 100644
index 3bec259..0000000
--- a/samples/OAuth2ProtectedWebApi/Code/MemoryNonceStore.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace OAuth2ProtectedWebApi.Code {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- using DotNetOpenAuth.Messaging.Bindings;
-
- internal class MemoryNonceStore : INonceStore {
- public bool StoreNonce(string context, string nonce, DateTime timestampUtc) {
- return true;
- }
- }
-} \ No newline at end of file
diff --git a/samples/OAuth2ProtectedWebApi/Controllers/TokenController.cs b/samples/OAuth2ProtectedWebApi/Controllers/TokenController.cs
index 2e2873a..a6ecf32 100644
--- a/samples/OAuth2ProtectedWebApi/Controllers/TokenController.cs
+++ b/samples/OAuth2ProtectedWebApi/Controllers/TokenController.cs
@@ -1,14 +1,12 @@
namespace OAuth2ProtectedWebApi.Controllers {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using DotNetOpenAuth.OAuth2;
+ using OAuth2ProtectedWebApi.Code;
+
public class TokenController : ApiController {
// POST /api/token
public Task<HttpResponseMessage> Post(HttpRequestMessage request) {
diff --git a/samples/OAuth2ProtectedWebApi/OAuth2ProtectedWebApi.csproj b/samples/OAuth2ProtectedWebApi/OAuth2ProtectedWebApi.csproj
index 811ba5a..cffbec4 100644
--- a/samples/OAuth2ProtectedWebApi/OAuth2ProtectedWebApi.csproj
+++ b/samples/OAuth2ProtectedWebApi/OAuth2ProtectedWebApi.csproj
@@ -128,8 +128,6 @@
<Compile Include="Code\AuthorizationServerHost.cs" />
<Compile Include="Code\BearerTokenHandler.cs" />
<Compile Include="Code\HttpHeaderAttribute.cs" />
- <Compile Include="Code\MemoryCryptoKeyStore.cs" />
- <Compile Include="Code\MemoryNonceStore.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\TokenController.cs" />
<Compile Include="Controllers\UserController.cs" />
@@ -285,7 +283,7 @@
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
- <DevelopmentServerPort>0</DevelopmentServerPort>
+ <DevelopmentServerPort>11473</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:23603/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
diff --git a/samples/OAuthClient/OAuthClient.csproj b/samples/OAuthClient/OAuthClient.csproj
index eb216b1..3c94f38 100644
--- a/samples/OAuthClient/OAuthClient.csproj
+++ b/samples/OAuthClient/OAuthClient.csproj
@@ -102,9 +102,7 @@
</None>
</ItemGroup>
<ItemGroup>
- <Compile Include="..\DotNetOpenAuth.ApplicationBlock\InMemoryTokenManager.cs">
- <Link>Code\InMemoryTokenManager.cs</Link>
- </Compile>
+ <Compile Include="Code\Logging.cs" />
<Compile Include="Facebook.aspx.cs">
<DependentUpon>Facebook.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -134,7 +132,6 @@
<Compile Include="TracePage.aspx.designer.cs">
<DependentUpon>TracePage.aspx</DependentUpon>
</Compile>
- <Compile Include="Code\Logging.cs" />
<Compile Include="Code\TracePageAppender.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WindowsLive.aspx.cs">
diff --git a/samples/OAuthConsumer/GoogleAddressBook.aspx.cs b/samples/OAuthConsumer/GoogleAddressBook.aspx.cs
index 8a2a816..ad25536 100644
--- a/samples/OAuthConsumer/GoogleAddressBook.aspx.cs
+++ b/samples/OAuthConsumer/GoogleAddressBook.aspx.cs
@@ -2,6 +2,7 @@
using System;
using System.Configuration;
using System.Linq;
+ using System.Net;
using System.Text;
using System.Web;
using System.Web.UI;
@@ -14,50 +15,34 @@
/// A page to demonstrate downloading a Gmail address book using OAuth.
/// </summary>
public partial class GoogleAddressBook : System.Web.UI.Page {
- private string AccessToken {
- get { return (string)Session["GoogleAccessToken"]; }
+ private AccessToken AccessToken {
+ get { return (AccessToken)Session["GoogleAccessToken"]; }
set { Session["GoogleAccessToken"] = value; }
}
- private InMemoryTokenManager TokenManager {
- get {
- var tokenManager = (InMemoryTokenManager)Application["GoogleTokenManager"];
- if (tokenManager == null) {
- string consumerKey = ConfigurationManager.AppSettings["googleConsumerKey"];
- string consumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"];
- if (!string.IsNullOrEmpty(consumerKey)) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- Application["GoogleTokenManager"] = tokenManager;
- }
- }
-
- return tokenManager;
- }
- }
-
protected async void Page_Load(object sender, EventArgs e) {
- if (this.TokenManager != null) {
+ var google = new GoogleConsumer();
+ if (google.ConsumerKey != null) {
this.MultiView1.ActiveViewIndex = 1;
if (!IsPostBack) {
- var google = new WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager);
-
// Is Google calling back with authorization?
- var accessTokenResponse = await google.ProcessUserAuthorizationAsync(new HttpRequestWrapper(Request), Response.ClientDisconnectedToken);
+ var accessTokenResponse = await google.ProcessUserAuthorizationAsync(this.Request.Url);
if (accessTokenResponse != null) {
this.AccessToken = accessTokenResponse.AccessToken;
- } else if (this.AccessToken == null) {
+ } else if (this.AccessToken.Token == null) {
// If we don't yet have access, immediately request it.
- await GoogleConsumer.RequestAuthorizationAsync(google, GoogleConsumer.Applications.Contacts);
+ Uri redirectUri = await google.RequestUserAuthorizationAsync(GoogleConsumer.Applications.Contacts);
+ this.Response.Redirect(redirectUri.AbsoluteUri);
}
}
}
}
protected async void getAddressBookButton_Click(object sender, EventArgs e) {
- var google = new WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager);
+ var google = new GoogleConsumer();
- XDocument contactsDocument = await GoogleConsumer.GetContactsAsync(google, this.AccessToken, 5, 1, Response.ClientDisconnectedToken);
+ XDocument contactsDocument = await google.GetContactsAsync(this.AccessToken, 5, 1, Response.ClientDisconnectedToken);
var contacts = from entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom"))
select new { Name = entry.Element(XName.Get("title", "http://www.w3.org/2005/Atom")).Value, Email = entry.Element(XName.Get("email", "http://schemas.google.com/g/2005")).Attribute("address").Value };
StringBuilder tableBuilder = new StringBuilder();
diff --git a/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs b/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs
index af490cf..cff24ea 100644
--- a/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs
+++ b/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs
@@ -12,26 +12,10 @@
using DotNetOpenAuth.OAuth.Messages;
public partial class GoogleApps2Legged : System.Web.UI.Page {
- private InMemoryTokenManager TokenManager {
- get {
- var tokenManager = (InMemoryTokenManager)Application["GoogleTokenManager"];
- if (tokenManager == null) {
- string consumerKey = ConfigurationManager.AppSettings["googleConsumerKey"];
- string consumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"];
- if (!string.IsNullOrEmpty(consumerKey)) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- Application["GoogleTokenManager"] = tokenManager;
- }
- }
-
- return tokenManager;
- }
- }
-
protected async void Page_Load(object sender, EventArgs e) {
- var google = new WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager);
- string accessToken = await google.RequestNewClientAccountAsync(cancellationToken: Response.ClientDisconnectedToken);
- using (var httpClient = google.CreateHttpClient(accessToken)) {
+ var google = new GoogleConsumer();
+ var accessToken = await google.RequestNewClientAccountAsync();
+ using (var httpClient = google.CreateHttpClient(accessToken.AccessToken)) {
await httpClient.GetAsync("http://someUri", Response.ClientDisconnectedToken);
}
}
diff --git a/samples/OAuthConsumer/OAuthConsumer.csproj b/samples/OAuthConsumer/OAuthConsumer.csproj
index 12553c3..94bed9c 100644
--- a/samples/OAuthConsumer/OAuthConsumer.csproj
+++ b/samples/OAuthConsumer/OAuthConsumer.csproj
@@ -107,9 +107,6 @@
</None>
</ItemGroup>
<ItemGroup>
- <Compile Include="..\DotNetOpenAuth.ApplicationBlock\InMemoryTokenManager.cs">
- <Link>Code\InMemoryTokenManager.cs</Link>
- </Compile>
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
diff --git a/samples/OAuthConsumer/SampleWcf.aspx.cs b/samples/OAuthConsumer/SampleWcf.aspx.cs
index 9c32f59..4e0d6cd 100644
--- a/samples/OAuthConsumer/SampleWcf.aspx.cs
+++ b/samples/OAuthConsumer/SampleWcf.aspx.cs
@@ -24,9 +24,9 @@
public partial class SampleWcf : System.Web.UI.Page {
protected async void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
- if (Session["WcfTokenManager"] != null) {
- WebConsumer consumer = this.CreateConsumer();
- var accessTokenMessage = await consumer.ProcessUserAuthorizationAsync(new HttpRequestWrapper(Request), Response.ClientDisconnectedToken);
+ var consumer = this.CreateConsumer();
+ if (consumer.ConsumerKey != null) {
+ var accessTokenMessage = await consumer.ProcessUserAuthorizationAsync(this.Request.Url);
if (accessTokenMessage != null) {
Session["WcfAccessToken"] = accessTokenMessage.AccessToken;
this.authorizationLabel.Text = "Authorized! Access token: " + accessTokenMessage.AccessToken;
@@ -36,7 +36,7 @@
}
protected async void getAuthorizationButton_Click(object sender, EventArgs e) {
- WebConsumer consumer = this.CreateConsumer();
+ var consumer = this.CreateConsumer();
UriBuilder callback = new UriBuilder(Request.Url);
callback.Query = null;
string[] scopes = (from item in this.scopeList.Items.OfType<ListItem>()
@@ -44,11 +44,10 @@
select item.Value).ToArray();
string scope = string.Join("|", scopes);
var requestParams = new Dictionary<string, string> {
- { "scope", scope },
- };
- var response = await consumer.PrepareRequestUserAuthorizationAsync(callback.Uri, requestParams, null, Response.ClientDisconnectedToken);
- var responseMessage = await consumer.Channel.PrepareResponseAsync(response, Response.ClientDisconnectedToken);
- await responseMessage.SendAsync(new HttpResponseWrapper(Response), Response.ClientDisconnectedToken);
+ { "scope", scope },
+ };
+ Uri redirectUri = await consumer.RequestUserAuthorizationAsync(callback.Uri, requestParams);
+ this.Response.Redirect(redirectUri.AbsoluteUri);
}
protected async void getNameButton_Click(object sender, EventArgs e) {
@@ -80,16 +79,15 @@
private async Task<T> CallServiceAsync<T>(Func<DataApiClient, T> predicate) {
DataApiClient client = new DataApiClient();
var serviceEndpoint = new MessageReceivingEndpoint(client.Endpoint.Address.Uri, HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest);
- var accessToken = Session["WcfAccessToken"] as string;
- if (accessToken == null) {
+ var accessToken = (AccessToken)(Session["WcfAccessToken"] ?? default(AccessToken));
+ if (accessToken.Token == null) {
throw new InvalidOperationException("No access token!");
}
var httpRequest = new HttpRequestMessage(HttpMethod.Post, client.Endpoint.Address.Uri);
- using (WebConsumer consumer = this.CreateConsumer()) {
- using (var handler = consumer.CreateMessageHandler(accessToken)) {
- handler.ApplyAuthorization(httpRequest);
- }
+ var consumer = this.CreateConsumer();
+ using (var handler = consumer.CreateMessageHandler(accessToken)) {
+ handler.ApplyAuthorization(httpRequest);
}
HttpRequestMessageProperty httpDetails = new HttpRequestMessageProperty();
@@ -100,27 +98,17 @@
}
}
- private WebConsumer CreateConsumer() {
+ private Consumer CreateConsumer() {
string consumerKey = "sampleconsumer";
string consumerSecret = "samplesecret";
- var tokenManager = Session["WcfTokenManager"] as InMemoryTokenManager;
- if (tokenManager == null) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- Session["WcfTokenManager"] = tokenManager;
- }
MessageReceivingEndpoint oauthEndpoint = new MessageReceivingEndpoint(
new Uri("http://localhost:65169/OAuth.ashx"),
HttpDeliveryMethods.PostRequest);
- WebConsumer consumer = new WebConsumer(
- new ServiceProviderDescription {
- RequestTokenEndpoint = oauthEndpoint,
- UserAuthorizationEndpoint = oauthEndpoint,
- AccessTokenEndpoint = oauthEndpoint,
- TamperProtectionElements = new DotNetOpenAuth.Messaging.ITamperProtectionChannelBindingElement[] {
- new HmacSha1SigningBindingElement(),
- },
- },
- tokenManager);
+ var consumer = new Consumer(
+ consumerKey,
+ consumerSecret,
+ new ServiceProviderDescription(oauthEndpoint.Location.AbsoluteUri, oauthEndpoint.Location.AbsoluteUri, oauthEndpoint.Location.AbsoluteUri),
+ new CookieTemporaryCredentialStorage());
return consumer;
}
diff --git a/samples/OAuthConsumer/SignInWithTwitter.aspx.cs b/samples/OAuthConsumer/SignInWithTwitter.aspx.cs
index f90d557..93462d5 100644
--- a/samples/OAuthConsumer/SignInWithTwitter.aspx.cs
+++ b/samples/OAuthConsumer/SignInWithTwitter.aspx.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
+ using System.Net;
using System.Web;
using System.Web.Security;
using System.Web.UI;
@@ -19,7 +20,7 @@
this.MultiView1.ActiveViewIndex = 1;
if (!IsPostBack) {
- var tuple = await TwitterConsumer.TryFinishSignInWithTwitterAsync(Response.ClientDisconnectedToken);
+ var tuple = await TwitterConsumer.TryFinishSignInWithTwitterAsync();
if (tuple != null) {
string screenName = tuple.Item1;
int userId = tuple.Item2;
@@ -35,8 +36,8 @@
}
protected async void signInButton_Click(object sender, ImageClickEventArgs e) {
- var response = await TwitterConsumer.StartSignInWithTwitterAsync(this.forceLoginCheckbox.Checked, Response.ClientDisconnectedToken);
- await response.SendAsync();
+ Uri redirectUri = await TwitterConsumer.StartSignInWithTwitterAsync(this.forceLoginCheckbox.Checked, Response.ClientDisconnectedToken);
+ this.Response.Redirect(redirectUri.AbsoluteUri);
}
}
} \ No newline at end of file
diff --git a/samples/OAuthConsumer/Twitter.aspx.cs b/samples/OAuthConsumer/Twitter.aspx.cs
index 6ff6993..6b298cc 100644
--- a/samples/OAuthConsumer/Twitter.aspx.cs
+++ b/samples/OAuthConsumer/Twitter.aspx.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
+ using System.Net;
using System.Text;
using System.Web;
using System.Web.UI;
@@ -14,51 +15,33 @@
using DotNetOpenAuth.OAuth;
public partial class Twitter : System.Web.UI.Page {
- private string AccessToken {
- get { return (string)Session["TwitterAccessToken"]; }
+ private AccessToken AccessToken {
+ get { return (AccessToken)(Session["TwitterAccessToken"] ?? new AccessToken()); }
set { Session["TwitterAccessToken"] = value; }
}
- private InMemoryTokenManager TokenManager {
- get {
- var tokenManager = (InMemoryTokenManager)Application["TwitterTokenManager"];
- if (tokenManager == null) {
- string consumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"];
- string consumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"];
- if (!string.IsNullOrEmpty(consumerKey)) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- Application["TwitterTokenManager"] = tokenManager;
- }
- }
-
- return tokenManager;
- }
- }
-
protected async void Page_Load(object sender, EventArgs e) {
- if (this.TokenManager != null) {
+ var twitter = new TwitterConsumer();
+ if (twitter.ConsumerKey != null) {
this.MultiView1.ActiveViewIndex = 1;
if (!IsPostBack) {
- var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager);
-
// Is Twitter calling back with authorization?
- var accessTokenResponse = await twitter.ProcessUserAuthorizationAsync(new HttpRequestWrapper(Request), Response.ClientDisconnectedToken);
+ var accessTokenResponse = await twitter.ProcessUserAuthorizationAsync(this.Request.Url);
if (accessTokenResponse != null) {
this.AccessToken = accessTokenResponse.AccessToken;
- } else if (this.AccessToken == null) {
+ } else {
// If we don't yet have access, immediately request it.
- var message = await twitter.PrepareRequestUserAuthorizationAsync(Response.ClientDisconnectedToken);
- var response = await twitter.Channel.PrepareResponseAsync(message, Response.ClientDisconnectedToken);
- await response.SendAsync();
+ Uri redirectUri = await twitter.RequestUserAuthorizationAsync(MessagingUtilities.GetPublicFacingUrl());
+ this.Response.Redirect(redirectUri.AbsoluteUri);
}
}
}
}
protected async void downloadUpdates_Click(object sender, EventArgs e) {
- var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager);
- var statusesJson = await TwitterConsumer.GetUpdatesAsync(twitter, this.AccessToken, Response.ClientDisconnectedToken);
+ var twitter = new TwitterConsumer();
+ var statusesJson = await twitter.GetUpdatesAsync(this.AccessToken);
StringBuilder tableBuilder = new StringBuilder();
tableBuilder.Append("<table><tr><td>Name</td><td>Update</td></tr>");
@@ -83,13 +66,11 @@
return;
}
- var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager);
- XDocument imageResult = await TwitterConsumer.UpdateProfileImageAsync(
- twitter,
+ var twitter = new TwitterConsumer();
+ XDocument imageResult = await twitter.UpdateProfileImageAsync(
this.AccessToken,
this.profilePhoto.PostedFile.InputStream,
- this.profilePhoto.PostedFile.ContentType,
- Response.ClientDisconnectedToken);
+ this.profilePhoto.PostedFile.ContentType);
this.photoUploadedLabel.Visible = true;
}
}
diff --git a/samples/OAuthConsumer/Web.config b/samples/OAuthConsumer/Web.config
index 3580fe6..69dab78 100644
--- a/samples/OAuthConsumer/Web.config
+++ b/samples/OAuthConsumer/Web.config
@@ -37,8 +37,8 @@
<!-- Fill in your various consumer keys and secrets here to make the sample work. -->
<!-- You must get these values by signing up with each individual service provider. -->
<!-- Twitter sign-up: https://twitter.com/oauth_clients -->
- <add key="twitterConsumerKey" value="" />
- <add key="twitterConsumerSecret" value="" />
+ <add key="twitterConsumerKey" value="5ZxhT5fqIodtU8fa7mA0w" />
+ <add key="twitterConsumerSecret" value="pZxtR63tLeMc8sd4rOqnZQqQjmfLiUMEWMokYFIjKq4" />
<!-- Google sign-up: https://www.google.com/accounts/ManageDomains -->
<add key="googleConsumerKey" value="anonymous"/>
<add key="googleConsumerSecret" value="anonymous"/>
diff --git a/samples/OAuthConsumer/Yammer.aspx.cs b/samples/OAuthConsumer/Yammer.aspx.cs
index 57169fc..b1031ae 100644
--- a/samples/OAuthConsumer/Yammer.aspx.cs
+++ b/samples/OAuthConsumer/Yammer.aspx.cs
@@ -11,48 +11,27 @@
using DotNetOpenAuth.OAuth;
public partial class Yammer : System.Web.UI.Page {
- private string RequestToken {
- get { return (string)ViewState["YammerRequestToken"]; }
- set { ViewState["YammerRequestToken"] = value; }
- }
-
- private string AccessToken {
- get { return (string)Session["YammerAccessToken"]; }
+ private AccessToken AccessToken {
+ get { return (AccessToken)Session["YammerAccessToken"]; }
set { Session["YammerAccessToken"] = value; }
}
- private InMemoryTokenManager TokenManager {
- get {
- var tokenManager = (InMemoryTokenManager)Application["YammerTokenManager"];
- if (tokenManager == null) {
- string consumerKey = ConfigurationManager.AppSettings["YammerConsumerKey"];
- string consumerSecret = ConfigurationManager.AppSettings["YammerConsumerSecret"];
- if (!string.IsNullOrEmpty(consumerKey)) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- Application["YammerTokenManager"] = tokenManager;
- }
- }
-
- return tokenManager;
- }
- }
-
protected void Page_Load(object sender, EventArgs e) {
- if (this.TokenManager != null) {
+ var yammer = new YammerConsumer();
+ if (yammer.ConsumerKey != null) {
this.MultiView1.SetActiveView(this.BeginAuthorizationView);
}
}
protected void getYammerMessages_Click(object sender, EventArgs e) {
- var yammer = new WebConsumer(YammerConsumer.ServiceDescription, this.TokenManager);
+ var yammer = new YammerConsumer();
+
+ // TODO: code here
}
protected async void obtainAuthorizationButton_Click(object sender, EventArgs e) {
- var yammer = YammerConsumer.CreateConsumer(this.TokenManager);
- var tuple = await YammerConsumer.PrepareRequestAuthorizationAsync(yammer, Response.ClientDisconnectedToken);
- Uri popupWindowLocation = tuple.Item1;
- string requestToken = tuple.Item2;
- this.RequestToken = requestToken;
+ var yammer = new YammerConsumer();
+ Uri popupWindowLocation = await yammer.RequestUserAuthorizationAsync(MessagingUtilities.GetPublicFacingUrl());
string javascript = "window.open('" + popupWindowLocation.AbsoluteUri + "');";
this.Page.ClientScript.RegisterStartupScript(GetType(), "YammerPopup", javascript, true);
this.MultiView1.SetActiveView(this.CompleteAuthorizationView);
@@ -63,8 +42,8 @@
return;
}
- var yammer = YammerConsumer.CreateConsumer(this.TokenManager);
- var authorizationResponse = await YammerConsumer.CompleteAuthorizationAsync(yammer, this.RequestToken, this.yammerUserCode.Text, Response.ClientDisconnectedToken);
+ var yammer = new YammerConsumer();
+ var authorizationResponse = await yammer.ProcessUserAuthorizationAsync(this.yammerUserCode.Text);
if (authorizationResponse != null) {
this.accessTokenLabel.Text = HttpUtility.HtmlEncode(authorizationResponse.AccessToken);
this.MultiView1.SetActiveView(this.AuthorizationCompleteView);
diff --git a/samples/OAuthConsumerWpf/Authorize.xaml.cs b/samples/OAuthConsumerWpf/Authorize.xaml.cs
index 92035d3..78c9c70 100644
--- a/samples/OAuthConsumerWpf/Authorize.xaml.cs
+++ b/samples/OAuthConsumerWpf/Authorize.xaml.cs
@@ -21,33 +21,28 @@
/// Interaction logic for Authorize.xaml
/// </summary>
public partial class Authorize : Window {
- private DesktopConsumer consumer;
- private string requestToken;
+ private Consumer consumer;
- internal Authorize(DesktopConsumer consumer, Func<DesktopConsumer, Task<Tuple<Uri, string>>> fetchUriCallback) {
+ internal Authorize(Consumer consumer, Func<Consumer, Task<Uri>> fetchUriCallback) {
this.InitializeComponent();
this.consumer = consumer;
Cursor original = this.Cursor;
this.Cursor = Cursors.Wait;
Task.Run(async delegate {
- var tuple = await fetchUriCallback(this.consumer);
- Uri browserAuthorizationLocation = tuple.Item1;
- this.requestToken = tuple.Item2;
+ Uri browserAuthorizationLocation = await fetchUriCallback(this.consumer);
System.Diagnostics.Process.Start(browserAuthorizationLocation.AbsoluteUri);
- this.Dispatcher.BeginInvoke(new Action(() => {
+ await this.Dispatcher.BeginInvoke(new Action(() => {
this.Cursor = original;
finishButton.IsEnabled = true;
}));
});
}
- internal delegate Uri FetchUri(DesktopConsumer consumer, out string requestToken);
-
- internal string AccessToken { get; set; }
+ internal AccessToken AccessToken { get; set; }
private async void finishButton_Click(object sender, RoutedEventArgs e) {
- var grantedAccess = await this.consumer.ProcessUserAuthorizationAsync(this.requestToken, this.verifierBox.Text);
+ var grantedAccess = await this.consumer.ProcessUserAuthorizationAsync(this.verifierBox.Text);
this.AccessToken = grantedAccess.AccessToken;
DialogResult = true;
Close();
diff --git a/samples/OAuthConsumerWpf/Authorize2.xaml.cs b/samples/OAuthConsumerWpf/Authorize2.xaml.cs
index f45af5c..829d323 100644
--- a/samples/OAuthConsumerWpf/Authorize2.xaml.cs
+++ b/samples/OAuthConsumerWpf/Authorize2.xaml.cs
@@ -31,6 +31,10 @@
get { return this.clientAuthorizationView.Authorization; }
}
+ public ClientAuthorizationView ClientAuthorizationView {
+ get { return this.clientAuthorizationView; }
+ }
+
private void clientAuthorizationView_Completed(object sender, ClientAuthorizationCompleteEventArgs e) {
this.DialogResult = e.Authorization != null;
this.Close();
diff --git a/samples/OAuthConsumerWpf/InMemoryTokenManager.cs b/samples/OAuthConsumerWpf/InMemoryTokenManager.cs
deleted file mode 100644
index 5266404..0000000
--- a/samples/OAuthConsumerWpf/InMemoryTokenManager.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="InMemoryTokenManager.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.Samples.OAuthConsumerWpf {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
-
- internal class InMemoryTokenManager : IConsumerTokenManager {
- private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
-
- internal InMemoryTokenManager() {
- }
-
- public string ConsumerKey { get; internal set; }
-
- public string ConsumerSecret { get; internal set; }
-
- #region ITokenManager Members
-
- public string GetConsumerSecret(string consumerKey) {
- if (consumerKey == this.ConsumerKey) {
- return this.ConsumerSecret;
- } else {
- throw new ArgumentException("Unrecognized consumer key.", "consumerKey");
- }
- }
-
- public string GetTokenSecret(string token) {
- return this.tokensAndSecrets[token];
- }
-
- public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) {
- this.tokensAndSecrets[response.Token] = response.TokenSecret;
- }
-
- public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
- this.tokensAndSecrets.Remove(requestToken);
- this.tokensAndSecrets[accessToken] = accessTokenSecret;
- }
-
- /// <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) {
- throw new NotImplementedException();
- }
-
- #endregion
- }
-}
diff --git a/samples/OAuthConsumerWpf/MainWindow.xaml b/samples/OAuthConsumerWpf/MainWindow.xaml
index 48eb0c4..979bc7e 100644
--- a/samples/OAuthConsumerWpf/MainWindow.xaml
+++ b/samples/OAuthConsumerWpf/MainWindow.xaml
@@ -92,30 +92,20 @@
</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.Column="2">POST</Label>
<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="2" Grid.Column="2">POST</Label>
<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>
+ <ComboBoxItem>GET w/ header</ComboBoxItem>
+ <ComboBoxItem>GET w/ querystring</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
</ComboBox.Items>
</ComboBox>
<Label Grid.Row="4">Consumer key</Label>
@@ -123,10 +113,9 @@
<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 Grid.Row="6" Grid.Column="1" SelectedIndex="0" x:Name="oauthVersion">
<ComboBox.Items>
- <ComboBoxItem>1.0</ComboBoxItem>
- <ComboBoxItem>1.0a</ComboBoxItem>
+ <ComboBoxItem>RFC 5849</ComboBoxItem>
</ComboBox.Items>
</ComboBox>
<Button Grid.Row="7" Grid.Column="1" x:Name="beginButton" Click="beginButton_Click">Begin</Button>
@@ -153,27 +142,26 @@
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="1" TabIndex="202">Token Endpoint URL</Label>
- <TextBox Grid.Row="1" Grid.Column="1" x:Name="oauth2TokenEndpointBox" Text="http://localhost:18916/OAuthTokenEndpoint.ashx" TabIndex="203" />
+ <TextBox Grid.Row="1" Grid.Column="1" x:Name="oauth2TokenEndpointBox" Text="http://localhost:23603/api/token" TabIndex="203" />
<Label Grid.Row="1" Grid.Column="2" TabIndex="204">POST</Label>
<Label Grid.Row="2" TabIndex="205">User Authorization URL</Label>
- <TextBox Grid.Row="2" Grid.Column="1" x:Name="oauth2AuthorizationUrlBox" Text="http://localhost:18916/Account/Authorize" TabIndex="206" />
+ <TextBox Grid.Row="2" Grid.Column="1" x:Name="oauth2AuthorizationUrlBox" Text="http://localhost:23603/user/Authorize" TabIndex="206" />
<Label Grid.Row="2" Grid.Column="2" TabIndex="207">GET</Label>
<Label Grid.Row="0" TabIndex="200">Grant Type</Label>
<ComboBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" x:Name="flowBox" SelectedIndex="0" TabIndex="201">
<ComboBox.Items>
<ComboBoxItem>Authorization Code</ComboBoxItem>
<ComboBoxItem>Implicit Grant</ComboBoxItem>
- <ComboBoxItem>Resource Owner Password Credentials</ComboBoxItem>
+ <!--<ComboBoxItem>Resource Owner Password Credentials</ComboBoxItem>-->
</ComboBox.Items>
</ComboBox>
<Label Grid.Row="3" TabIndex="207">Resource URL</Label>
- <TextBox Grid.Row="3" Grid.Column="1" x:Name="oauth2ResourceUrlBox" Text="http://localhost:18916/" TabIndex="208" />
+ <TextBox Grid.Row="3" Grid.Column="1" x:Name="oauth2ResourceUrlBox" Text="http://localhost:23603/api/values" TabIndex="208" />
<ComboBox Grid.Row="3" Grid.Column="2" x:Name="oauth2ResourceHttpMethodList" SelectedIndex="0" TabIndex="209">
<ComboBox.Items>
- <ComboBoxItem>GET w/ header</ComboBoxItem>
- <ComboBoxItem>GET w/ querystring</ComboBoxItem>
- <ComboBoxItem>POST</ComboBoxItem>
- </ComboBox.Items>
+ <ComboBoxItem>GET</ComboBoxItem>
+ <ComboBoxItem>POST</ComboBoxItem>
+ </ComboBox.Items>
</ComboBox>
<Label Grid.Row="4" TabIndex="210">Client Identifier</Label>
<TextBox Grid.Row="4" Grid.Column="1" x:Name="oauth2ClientIdentifierBox" Grid.ColumnSpan="2" Text="a" TabIndex="211" />
@@ -184,7 +172,7 @@
<Label Grid.Row="7" TabIndex="216">OAuth 2.0 version</Label>
<ComboBox Grid.Row="7" Grid.Column="1" SelectedIndex="0" x:Name="oauth2Version" TabIndex="217">
<ComboBox.Items>
- <ComboBoxItem>2.0 DRAFT 16</ComboBoxItem>
+ <ComboBoxItem>RFC 6749</ComboBoxItem>
</ComboBox.Items>
</ComboBox>
<Button Grid.Row="8" Grid.Column="1" x:Name="oauth2BeginButton" Click="oauth2BeginButton_Click" TabIndex="218">Begin</Button>
diff --git a/samples/OAuthConsumerWpf/MainWindow.xaml.cs b/samples/OAuthConsumerWpf/MainWindow.xaml.cs
index 1e1f1ab..d58df8c 100644
--- a/samples/OAuthConsumerWpf/MainWindow.xaml.cs
+++ b/samples/OAuthConsumerWpf/MainWindow.xaml.cs
@@ -28,9 +28,8 @@
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
- private InMemoryTokenManager googleTokenManager = new InMemoryTokenManager();
- private DesktopConsumer google;
- private string googleAccessToken;
+ private GoogleConsumer google;
+ private DotNetOpenAuth.OAuth.AccessToken googleAccessToken;
private UserAgentClient wcf;
private IAuthorizationState wcfAccessToken;
@@ -42,17 +41,12 @@
}
private void InitializeGoogleConsumer() {
- this.googleTokenManager.ConsumerKey = ConfigurationManager.AppSettings["googleConsumerKey"];
- this.googleTokenManager.ConsumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"];
-
string pfxFile = ConfigurationManager.AppSettings["googleConsumerCertificateFile"];
- if (string.IsNullOrEmpty(pfxFile)) {
- this.google = new DesktopConsumer(GoogleConsumer.ServiceDescription, this.googleTokenManager);
- } else {
+ this.google = new GoogleConsumer();
+ if (!string.IsNullOrEmpty(pfxFile)) {
string pfxPassword = ConfigurationManager.AppSettings["googleConsumerCertificatePassword"];
var signingCertificate = new X509Certificate2(pfxFile, pfxPassword);
- var service = GoogleConsumer.CreateRsaSha1ServiceDescription(signingCertificate);
- this.google = new DesktopConsumer(service, this.googleTokenManager);
+ this.google.ConsumerCertificate = signingCertificate;
}
}
@@ -65,7 +59,7 @@
}
private async void beginAuthorizationButton_Click(object sender, RoutedEventArgs e) {
- if (string.IsNullOrEmpty(this.googleTokenManager.ConsumerKey)) {
+ if (string.IsNullOrEmpty(this.google.ConsumerKey)) {
MessageBox.Show(this, "You must modify the App.config or OAuthConsumerWpf.exe.config file for this application to include your Google OAuth consumer key first.", "Configuration required", MessageBoxButton.OK, MessageBoxImage.Stop);
return;
}
@@ -73,15 +67,13 @@
var auth = new Authorize(
this.google,
consumer =>
- GoogleConsumer.RequestAuthorizationAsync(
- consumer,
- GoogleConsumer.Applications.Contacts | GoogleConsumer.Applications.Blogger));
+ ((GoogleConsumer)consumer).RequestUserAuthorizationAsync(GoogleConsumer.Applications.Contacts | GoogleConsumer.Applications.Blogger));
bool? result = auth.ShowDialog();
if (result.HasValue && result.Value) {
this.googleAccessToken = auth.AccessToken;
this.postButton.IsEnabled = true;
- XDocument contactsDocument = await GoogleConsumer.GetContactsAsync(this.google, this.googleAccessToken);
+ XDocument contactsDocument = await this.google.GetContactsAsync(this.googleAccessToken);
var contacts = from entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom"))
select new { Name = entry.Element(XName.Get("title", "http://www.w3.org/2005/Atom")).Value, Email = entry.Element(XName.Get("email", "http://schemas.google.com/g/2005")).Attribute("address").Value };
this.contactsGrid.Children.Clear();
@@ -100,7 +92,7 @@
private async void postButton_Click(object sender, RoutedEventArgs e) {
XElement postBodyXml = XElement.Parse(this.postBodyBox.Text);
- await GoogleConsumer.PostBlogEntryAsync(this.google, this.googleAccessToken, this.blogUrlBox.Text, this.postTitleBox.Text, postBodyXml, CancellationToken.None);
+ await this.google.PostBlogEntryAsync(this.googleAccessToken, this.blogUrlBox.Text, this.postTitleBox.Text, postBodyXml);
}
private async void beginWcfAuthorizationButton_Click(object sender, RoutedEventArgs e) {
@@ -136,48 +128,27 @@
private async void beginButton_Click(object sender, RoutedEventArgs e) {
try {
- var service = new ServiceProviderDescription {
- RequestTokenEndpoint =
- new MessageReceivingEndpoint(
- this.requestTokenUrlBox.Text,
- this.requestTokenHttpMethod.SelectedIndex == 0 ? HttpDeliveryMethods.GetRequest : HttpDeliveryMethods.PostRequest),
- UserAuthorizationEndpoint = new MessageReceivingEndpoint(this.authorizeUrlBox.Text, HttpDeliveryMethods.GetRequest),
- AccessTokenEndpoint =
- new MessageReceivingEndpoint(
- this.accessTokenUrlBox.Text,
- this.accessTokenHttpMethod.SelectedIndex == 0 ? HttpDeliveryMethods.GetRequest : HttpDeliveryMethods.PostRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- ProtocolVersion = this.oauthVersion.SelectedIndex == 0 ? ProtocolVersion.V10 : ProtocolVersion.V10a,
- };
- var tokenManager = new InMemoryTokenManager();
- tokenManager.ConsumerKey = this.consumerKeyBox.Text;
- tokenManager.ConsumerSecret = this.consumerSecretBox.Text;
-
- var consumer = new DesktopConsumer(service, tokenManager);
- string accessToken;
- if (service.ProtocolVersion == ProtocolVersion.V10) {
- var tuple = await consumer.RequestUserAuthorizationAsync(null, null);
- Uri authorizeUrl = tuple.Item1;
- string requestToken = tuple.Item2;
- Process.Start(authorizeUrl.AbsoluteUri);
- MessageBox.Show(this, "Click OK when you've authorized the app.");
- var authorizationResponse = await consumer.ProcessUserAuthorizationAsync(requestToken, null);
- accessToken = authorizationResponse.AccessToken;
+ var service = new ServiceProviderDescription(
+ this.requestTokenUrlBox.Text,
+ this.authorizeUrlBox.Text,
+ this.accessTokenUrlBox.Text);
+
+ var consumer = new Consumer(this.consumerKeyBox.Text, this.consumerSecretBox.Text, service, new MemoryTemporaryCredentialStorage());
+ DotNetOpenAuth.OAuth.AccessToken accessToken;
+ var authorizePopup = new Authorize(consumer, c => c.RequestUserAuthorizationAsync(null, null));
+ authorizePopup.Owner = this;
+ bool? result = authorizePopup.ShowDialog();
+ if (result.HasValue && result.Value) {
+ accessToken = authorizePopup.AccessToken;
} else {
- var authorizePopup = new Authorize(consumer, c => c.RequestUserAuthorizationAsync(null, null));
- authorizePopup.Owner = this;
- bool? result = authorizePopup.ShowDialog();
- if (result.HasValue && result.Value) {
- accessToken = authorizePopup.AccessToken;
- } else {
- return;
- }
+ return;
}
+
HttpMethod resourceHttpMethod = this.resourceHttpMethodList.SelectedIndex < 2 ? HttpMethod.Get : HttpMethod.Post;
using (var handler = consumer.CreateMessageHandler(accessToken)) {
handler.Location = this.resourceHttpMethodList.SelectedIndex == 1
- ? OAuth1HttpMessageHandlerBase.OAuthParametersLocation.AuthorizationHttpHeader
- : OAuth1HttpMessageHandlerBase.OAuthParametersLocation.QueryString;
+ ? OAuth1HttpMessageHandlerBase.OAuthParametersLocation.AuthorizationHttpHeader
+ : OAuth1HttpMessageHandlerBase.OAuthParametersLocation.QueryString;
using (var httpClient = consumer.CreateHttpClient(handler)) {
var request = new HttpRequestMessage(resourceHttpMethod, this.resourceUrlBox.Text);
using (var resourceResponse = await httpClient.SendAsync(request)) {
@@ -203,28 +174,19 @@
var authorizePopup = new Authorize2(client);
authorizePopup.Authorization.Scope.AddRange(OAuthUtilities.SplitScopes(this.oauth2ScopeBox.Text));
- authorizePopup.Authorization.Callback = new Uri("http://localhost:59721/");
+ authorizePopup.Authorization.Callback = new Uri("http://www.microsoft.com/en-us/default.aspx");
authorizePopup.Owner = this;
+ authorizePopup.ClientAuthorizationView.RequestImplicitGrant = flowBox.SelectedIndex == 1;
bool? result = authorizePopup.ShowDialog();
if (result.HasValue && result.Value) {
- var requestUri = new UriBuilder(this.oauth2ResourceUrlBox.Text);
- if (this.oauth2ResourceHttpMethodList.SelectedIndex > 0) {
- requestUri.AppendQueryArgument("access_token", authorizePopup.Authorization.AccessToken);
- }
-
- var request = (HttpWebRequest)WebRequest.Create(requestUri.Uri);
- request.Method = this.oauth2ResourceHttpMethodList.SelectedIndex < 2 ? "GET" : "POST";
- if (this.oauth2ResourceHttpMethodList.SelectedIndex == 0) {
- await client.AuthorizeRequestAsync(request, authorizePopup.Authorization, CancellationToken.None);
- }
-
- using (var resourceResponse = request.GetResponse()) {
- using (var responseStream = new StreamReader(resourceResponse.GetResponseStream())) {
- this.oauth2ResultsBox.Text = responseStream.ReadToEnd();
+ var request = new HttpRequestMessage(
+ new HttpMethod(((ComboBoxItem)this.oauth2ResourceHttpMethodList.SelectedValue).Content.ToString()),
+ this.oauth2ResourceUrlBox.Text);
+ using (var httpClient = new HttpClient(client.CreateAuthorizingHandler(authorizePopup.Authorization))) {
+ using (var resourceResponse = await httpClient.SendAsync(request)) {
+ this.oauth2ResultsBox.Text = await resourceResponse.Content.ReadAsStringAsync();
}
}
- } else {
- return;
}
} catch (Messaging.ProtocolException ex) {
MessageBox.Show(this, ex.Message);
diff --git a/samples/OAuthConsumerWpf/OAuthConsumerWpf.csproj b/samples/OAuthConsumerWpf/OAuthConsumerWpf.csproj
index 2ef9b6f..ee06daa 100644
--- a/samples/OAuthConsumerWpf/OAuthConsumerWpf.csproj
+++ b/samples/OAuthConsumerWpf/OAuthConsumerWpf.csproj
@@ -153,7 +153,6 @@
<Compile Include="Authorize.xaml.cs">
<DependentUpon>Authorize.xaml</DependentUpon>
</Compile>
- <Compile Include="InMemoryTokenManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
diff --git a/samples/OAuthServiceProvider/Code/Constants.cs b/samples/OAuthServiceProvider/Code/Constants.cs
index 3e629f0..9115f1c 100644
--- a/samples/OAuthServiceProvider/Code/Constants.cs
+++ b/samples/OAuthServiceProvider/Code/Constants.cs
@@ -10,9 +10,9 @@
public static class Constants {
public static Uri WebRootUrl { get; set; }
- public static ServiceProviderDescription SelfDescription {
+ public static ServiceProviderHostDescription SelfDescription {
get {
- ServiceProviderDescription description = new ServiceProviderDescription {
+ var description = new ServiceProviderHostDescription {
AccessTokenEndpoint = new MessageReceivingEndpoint(new Uri(WebRootUrl, "/OAuth.ashx"), HttpDeliveryMethods.PostRequest),
RequestTokenEndpoint = new MessageReceivingEndpoint(new Uri(WebRootUrl, "/OAuth.ashx"), HttpDeliveryMethods.PostRequest),
UserAuthorizationEndpoint = new MessageReceivingEndpoint(new Uri(WebRootUrl, "/OAuth.ashx"), HttpDeliveryMethods.PostRequest),
diff --git a/samples/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs b/samples/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs
index a25f4c5..4ce60bb 100644
--- a/samples/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs
+++ b/samples/OAuthServiceProvider/Code/OAuthPrincipalAuthorizationPolicy.cs
@@ -4,18 +4,19 @@
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/samples/OpenIdProviderWebForms/Code/OAuthHybrid.cs b/samples/OpenIdProviderWebForms/Code/OAuthHybrid.cs
index 8e64bfb..f96e87e 100644
--- a/samples/OpenIdProviderWebForms/Code/OAuthHybrid.cs
+++ b/samples/OpenIdProviderWebForms/Code/OAuthHybrid.cs
@@ -37,8 +37,8 @@ namespace OpenIdProviderWebForms.Code {
internal static ServiceProviderOpenIdProvider ServiceProvider { get; private set; }
- internal static ServiceProviderDescription GetServiceDescription() {
- return new ServiceProviderDescription {
+ internal static ServiceProviderHostDescription GetServiceDescription() {
+ return new ServiceProviderHostDescription {
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
};
}
diff --git a/samples/OpenIdRelyingPartyWebForms/Code/State.cs b/samples/OpenIdRelyingPartyWebForms/Code/State.cs
index c8147e5..c8cef80 100644
--- a/samples/OpenIdRelyingPartyWebForms/Code/State.cs
+++ b/samples/OpenIdRelyingPartyWebForms/Code/State.cs
@@ -1,5 +1,6 @@
namespace OpenIdRelyingPartyWebForms {
using System.Web;
+ using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
@@ -28,8 +29,8 @@ namespace OpenIdRelyingPartyWebForms {
set { HttpContext.Current.Session["PapePolicies"] = value; }
}
- public static string GoogleAccessToken {
- get { return HttpContext.Current.Session["GoogleAccessToken"] as string; }
+ public static AccessToken GoogleAccessToken {
+ get { return (AccessToken)(HttpContext.Current.Session["GoogleAccessToken"] ?? new AccessToken()); }
set { HttpContext.Current.Session["GoogleAccessToken"] = value; }
}
@@ -38,7 +39,7 @@ namespace OpenIdRelyingPartyWebForms {
FetchResponse = null;
FriendlyLoginName = null;
PapePolicies = null;
- GoogleAccessToken = null;
+ GoogleAccessToken = new AccessToken();
}
}
} \ No newline at end of file
diff --git a/samples/OpenIdRelyingPartyWebForms/Global.asax.cs b/samples/OpenIdRelyingPartyWebForms/Global.asax.cs
index 6283987..8460d49 100644
--- a/samples/OpenIdRelyingPartyWebForms/Global.asax.cs
+++ b/samples/OpenIdRelyingPartyWebForms/Global.asax.cs
@@ -18,7 +18,7 @@
get {
var googleWebConsumer = (WebConsumerOpenIdRelyingParty)HttpContext.Current.Application["GoogleWebConsumer"];
if (googleWebConsumer == null) {
- googleWebConsumer = new WebConsumerOpenIdRelyingParty(GoogleConsumer.ServiceDescription, GoogleTokenManager);
+ googleWebConsumer = new WebConsumerOpenIdRelyingParty { ServiceProvider = GoogleConsumer.ServiceDescription };
HttpContext.Current.Application["GoogleWebConsumer"] = googleWebConsumer;
}
@@ -26,36 +26,6 @@
}
}
- internal static InMemoryTokenManager GoogleTokenManager {
- get {
- var tokenManager = (InMemoryTokenManager)HttpContext.Current.Application["GoogleTokenManager"];
- if (tokenManager == null) {
- string consumerKey = ConfigurationManager.AppSettings["googleConsumerKey"];
- string consumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"];
- if (!string.IsNullOrEmpty(consumerKey)) {
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- HttpContext.Current.Application["GoogleTokenManager"] = tokenManager;
- }
- }
-
- return tokenManager;
- }
- }
-
- internal static InMemoryTokenManager OwnSampleOPHybridTokenManager {
- get {
- var tokenManager = (InMemoryTokenManager)HttpContext.Current.Application["OwnSampleOPHybridTokenManager"];
- if (tokenManager == null) {
- string consumerKey = new Uri(HttpContext.Current.Request.Url, HttpContext.Current.Request.ApplicationPath).AbsoluteUri;
- string consumerSecret = "some crazy secret";
- tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
- HttpContext.Current.Application["OwnSampleOPHybridTokenManager"] = tokenManager;
- }
-
- return tokenManager;
- }
- }
-
public static string ToString(NameValueCollection collection) {
using (StringWriter sw = new StringWriter()) {
foreach (string key in collection.Keys) {
diff --git a/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs b/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs
index 2cbac9a..2b3b51d 100644
--- a/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs
+++ b/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs
@@ -10,7 +10,7 @@
public partial class DisplayGoogleContacts : System.Web.UI.Page {
protected async void Page_Load(object sender, EventArgs e) {
- if (!string.IsNullOrEmpty(State.GoogleAccessToken)) {
+ if (!string.IsNullOrEmpty(State.GoogleAccessToken.Token)) {
this.MultiView1.ActiveViewIndex = 1;
if (State.FetchResponse != null && State.FetchResponse.Attributes.Contains(WellKnownAttributes.Contact.Email)) {
this.emailLabel.Text = State.FetchResponse.Attributes[WellKnownAttributes.Contact.Email].Values[0];
@@ -18,7 +18,11 @@
this.emailLabel.Text = "unavailable";
}
this.claimedIdLabel.Text = this.User.Identity.Name;
- var contactsDocument = await GoogleConsumer.GetContactsAsync(Global.GoogleWebConsumer, State.GoogleAccessToken, cancellationToken: Response.ClientDisconnectedToken);
+ var google = new GoogleConsumer {
+ ConsumerKey = Global.GoogleWebConsumer.ConsumerKey,
+ ConsumerSecret = Global.GoogleWebConsumer.ConsumerSecret,
+ };
+ var contactsDocument = await google.GetContactsAsync(State.GoogleAccessToken);
this.RenderContacts(contactsDocument);
}
}
diff --git a/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj b/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj
index cf12262..7c6d03a 100644
--- a/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj
+++ b/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj
@@ -100,9 +100,6 @@
</Content>
</ItemGroup>
<ItemGroup>
- <Compile Include="..\DotNetOpenAuth.ApplicationBlock\InMemoryTokenManager.cs">
- <Link>Code\InMemoryTokenManager.cs</Link>
- </Compile>
<Compile Include="ajaxlogin.aspx.cs">
<DependentUpon>ajaxlogin.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
diff --git a/samples/OpenIdRelyingPartyWebForms/loginPlusOAuth.aspx.cs b/samples/OpenIdRelyingPartyWebForms/loginPlusOAuth.aspx.cs
index bffd539..0e6eae0 100644
--- a/samples/OpenIdRelyingPartyWebForms/loginPlusOAuth.aspx.cs
+++ b/samples/OpenIdRelyingPartyWebForms/loginPlusOAuth.aspx.cs
@@ -4,6 +4,7 @@
using System.Web;
using System.Web.Security;
using DotNetOpenAuth.ApplicationBlock;
+ using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.Messages;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
@@ -25,7 +26,7 @@
switch (authResponse.Status) {
case AuthenticationStatus.Authenticated:
State.FetchResponse = authResponse.GetExtension<FetchResponse>();
- AuthorizedTokenResponse accessToken = await Global.GoogleWebConsumer.ProcessUserAuthorizationAsync(authResponse, Response.ClientDisconnectedToken);
+ AccessTokenResponse accessToken = await Global.GoogleWebConsumer.ProcessUserAuthorizationAsync(authResponse, Response.ClientDisconnectedToken);
if (accessToken != null) {
State.GoogleAccessToken = accessToken.AccessToken;
FormsAuthentication.SetAuthCookie(authResponse.ClaimedIdentifier, false);
@@ -56,7 +57,7 @@
// that is properly registered with Google.
// We will customize the realm to use http or https based on what the
// return_to URL will be (which will be this page).
- Realm realm = Request.Url.Scheme + Uri.SchemeDelimiter + Global.GoogleTokenManager.ConsumerKey + "/";
+ Realm realm = Request.Url.Scheme + Uri.SchemeDelimiter + (new GoogleConsumer()).ConsumerKey + "/";
IAuthenticationRequest authReq = await relyingParty.CreateRequestAsync(GoogleOPIdentifier, realm, cancellationToken: Response.ClientDisconnectedToken);
// Prepare the OAuth extension
diff --git a/samples/OpenIdRelyingPartyWebForms/loginPlusOAuthSampleOP.aspx.cs b/samples/OpenIdRelyingPartyWebForms/loginPlusOAuthSampleOP.aspx.cs
index 91ec642..6133a86 100644
--- a/samples/OpenIdRelyingPartyWebForms/loginPlusOAuthSampleOP.aspx.cs
+++ b/samples/OpenIdRelyingPartyWebForms/loginPlusOAuthSampleOP.aspx.cs
@@ -1,5 +1,6 @@
namespace OpenIdRelyingPartyWebForms {
using System;
+ using System.Web;
using System.Web.Security;
using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.Messaging;
@@ -23,24 +24,19 @@
}
protected void identifierBox_LoggingIn(object sender, OpenIdEventArgs e) {
- ServiceProviderDescription serviceDescription = new ServiceProviderDescription {
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- };
-
- var consumer = new WebConsumerOpenIdRelyingParty(serviceDescription, Global.OwnSampleOPHybridTokenManager);
+ var consumer = CreateConsumer();
consumer.AttachAuthorizationRequest(e.Request, "http://tempuri.org/IDataApi/GetName");
}
protected async void identifierBox_LoggedIn(object sender, OpenIdEventArgs e) {
State.FetchResponse = e.Response.GetExtension<FetchResponse>();
- ServiceProviderDescription serviceDescription = new ServiceProviderDescription {
- AccessTokenEndpoint = new MessageReceivingEndpoint(new Uri(e.Response.Provider.Uri, "/access_token.ashx"), HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
+ var serviceDescription = new ServiceProviderDescription {
+ TokenRequestEndpoint = new Uri(e.Response.Provider.Uri, "/access_token.ashx"),
};
- var consumer = new WebConsumerOpenIdRelyingParty(serviceDescription, Global.OwnSampleOPHybridTokenManager);
-
- AuthorizedTokenResponse accessToken = await consumer.ProcessUserAuthorizationAsync(e.Response);
+ var consumer = CreateConsumer();
+ consumer.ServiceProvider = serviceDescription;
+ AccessTokenResponse accessToken = await consumer.ProcessUserAuthorizationAsync(e.Response);
if (accessToken != null) {
this.MultiView1.SetActiveView(this.AuthorizationGiven);
@@ -58,5 +54,12 @@
protected void identifierBox_Failed(object sender, OpenIdEventArgs e) {
this.MultiView1.SetActiveView(this.AuthenticationFailed);
}
+
+ private static WebConsumerOpenIdRelyingParty CreateConsumer() {
+ var consumer = new WebConsumerOpenIdRelyingParty();
+ consumer.ConsumerKey = new Uri(HttpContext.Current.Request.Url, HttpContext.Current.Request.ApplicationPath).AbsoluteUri;
+ consumer.ConsumerSecret = "some crazy secret";
+ return consumer;
+ }
}
}
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs
deleted file mode 100644
index efc382f..0000000
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="AuthenticationOnlyCookieOAuthTokenManager.cs" company="Microsoft">
-// Copyright (c) Microsoft. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.AspNet.Clients {
- using System;
- using System.Text;
- using System.Web;
- using System.Web.Security;
-
- /// <summary>
- /// Stores OAuth tokens in the current request's cookie
- /// </summary>
- public class AuthenticationOnlyCookieOAuthTokenManager : IOAuthTokenManager {
- /// <summary>
- /// Key used for token cookie
- /// </summary>
- protected const string TokenCookieKey = "OAuthTokenSecret";
-
- /// <summary>
- /// Primary request context.
- /// </summary>
- private readonly HttpContextBase primaryContext;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="AuthenticationOnlyCookieOAuthTokenManager"/> class.
- /// </summary>
- public AuthenticationOnlyCookieOAuthTokenManager() {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="AuthenticationOnlyCookieOAuthTokenManager"/> class.
- /// </summary>
- /// <param name="context">The current request context.</param>
- public AuthenticationOnlyCookieOAuthTokenManager(HttpContextBase context) {
- this.primaryContext = context;
- }
-
- /// <summary>
- /// Gets the effective HttpContext object to use.
- /// </summary>
- protected HttpContextBase Context {
- get {
- return this.primaryContext ?? new HttpContextWrapper(HttpContext.Current);
- }
- }
-
- /// <summary>
- /// Gets the token secret from the specified token.
- /// </summary>
- /// <param name="token">The token.</param>
- /// <returns>
- /// The token's secret
- /// </returns>
- public virtual string GetTokenSecret(string token) {
- HttpCookie cookie = this.Context.Request.Cookies[TokenCookieKey];
- if (cookie == null || string.IsNullOrEmpty(cookie.Values[token])) {
- return null;
- }
-
- string secret = DecodeAndUnprotectToken(token, cookie.Values[token]);
- return secret;
- }
-
- /// <summary>
- /// Replaces the request token with access token.
- /// </summary>
- /// <param name="requestToken">The request token.</param>
- /// <param name="accessToken">The access token.</param>
- /// <param name="accessTokenSecret">The access token secret.</param>
- public virtual void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) {
- var cookie = new HttpCookie(TokenCookieKey) {
- Value = string.Empty,
- Expires = DateTime.UtcNow.AddDays(-5)
- };
- this.Context.Response.Cookies.Set(cookie);
- }
-
- /// <summary>
- /// Stores the request token together with its secret.
- /// </summary>
- /// <param name="requestToken">The request token.</param>
- /// <param name="requestTokenSecret">The request token secret.</param>
- public virtual void StoreRequestToken(string requestToken, string requestTokenSecret) {
- var cookie = new HttpCookie(TokenCookieKey) {
- HttpOnly = true
- };
-
- if (FormsAuthentication.RequireSSL) {
- cookie.Secure = true;
- }
-
- var encryptedToken = ProtectAndEncodeToken(requestToken, requestTokenSecret);
- cookie.Values[requestToken] = encryptedToken;
-
- this.Context.Response.Cookies.Set(cookie);
- }
-
- /// <summary>
- /// Protect and url-encode the specified token secret.
- /// </summary>
- /// <param name="token">The token to be used as a key.</param>
- /// <param name="tokenSecret">The token secret to be protected</param>
- /// <returns>The encrypted and protected string.</returns>
- protected static string ProtectAndEncodeToken(string token, string tokenSecret)
- {
- byte[] cookieBytes = Encoding.UTF8.GetBytes(tokenSecret);
- var secretBytes = MachineKeyUtil.Protect(cookieBytes, TokenCookieKey, "Token:" + token);
- return HttpServerUtility.UrlTokenEncode(secretBytes);
- }
-
- /// <summary>
- /// Url-decode and unprotect the specified encrypted token string.
- /// </summary>
- /// <param name="token">The token to be used as a key.</param>
- /// <param name="encryptedToken">The encrypted token to be decrypted</param>
- /// <returns>The original token secret</returns>
- protected static string DecodeAndUnprotectToken(string token, string encryptedToken)
- {
- byte[] cookieBytes = HttpServerUtility.UrlTokenDecode(encryptedToken);
- byte[] clearBytes = MachineKeyUtil.Unprotect(cookieBytes, TokenCookieKey, "Token:" + token);
- return Encoding.UTF8.GetString(clearBytes);
- }
- }
-} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs
deleted file mode 100644
index 398ee85..0000000
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="CookieOAuthTokenManager.cs" company="Microsoft">
-// Copyright (c) Microsoft. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.AspNet.Clients {
- using System.Web;
- using System.Web.Security;
-
- /// <summary>
- /// Stores OAuth tokens in the current request's cookie.
- /// </summary>
- /// <remarks>
- /// This class is different from the <see cref="AuthenticationOnlyCookieOAuthTokenManager"/> in that
- /// it also stores the access token after the authentication has succeeded.
- /// </remarks>
- public class CookieOAuthTokenManager : AuthenticationOnlyCookieOAuthTokenManager {
- /// <summary>
- /// Initializes a new instance of the <see cref="CookieOAuthTokenManager"/> class.
- /// </summary>
- public CookieOAuthTokenManager() {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="CookieOAuthTokenManager"/> class.
- /// </summary>
- /// <param name="context">The current request context.</param>
- public CookieOAuthTokenManager(HttpContextBase context)
- : base(context) {
- }
-
- /// <summary>
- /// Gets the token secret from the specified token.
- /// </summary>
- /// <param name="token">The token.</param>
- /// <returns>
- /// The token's secret
- /// </returns>
- public override string GetTokenSecret(string token) {
- string secret = base.GetTokenSecret(token);
- if (secret != null) {
- return secret;
- }
-
- // The base class checks for cookies in the Request object.
- // Here we check in the Response object as well because we
- // may have set it earlier in the request life cycle.
- HttpCookie cookie = this.Context.Response.Cookies[TokenCookieKey];
- if (cookie == null || string.IsNullOrEmpty(cookie.Values[token])) {
- return null;
- }
-
- secret = DecodeAndUnprotectToken(token, cookie.Values[token]);
- return secret;
- }
-
- /// <summary>
- /// Replaces the request token with access token.
- /// </summary>
- /// <param name="requestToken">The request token.</param>
- /// <param name="accessToken">The access token.</param>
- /// <param name="accessTokenSecret">The access token secret.</param>
- public override void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) {
- var cookie = new HttpCookie(TokenCookieKey) {
- HttpOnly = true
- };
-
- if (FormsAuthentication.RequireSSL) {
- cookie.Secure = true;
- }
-
- var encryptedToken = ProtectAndEncodeToken(accessToken, accessTokenSecret);
- cookie.Values[accessToken] = encryptedToken;
-
- this.Context.Response.Cookies.Set(cookie);
- }
- }
-} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs
index cc35b76..1b6318f 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs
@@ -11,6 +11,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+ using System.Web;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
@@ -20,13 +21,13 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// The dot net open auth web consumer.
/// </summary>
- public class DotNetOpenAuthWebConsumer : IOAuthWebWorker, IDisposable {
+ public class DotNetOpenAuthWebConsumer : IOAuthWebWorker {
#region Constants and Fields
/// <summary>
/// The _web consumer.
/// </summary>
- private readonly WebConsumer webConsumer;
+ private readonly Consumer webConsumer;
#endregion
@@ -41,11 +42,15 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <param name="tokenManager">
/// The token manager.
/// </param>
- public DotNetOpenAuthWebConsumer(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) {
+ public DotNetOpenAuthWebConsumer(ServiceProviderDescription serviceDescription, string consumerKey, string consumerSecret) {
Requires.NotNull(serviceDescription, "serviceDescription");
- Requires.NotNull(tokenManager, "tokenManager");
- this.webConsumer = new WebConsumer(serviceDescription, tokenManager);
+ this.webConsumer = new Consumer {
+ ServiceProvider = serviceDescription,
+ ConsumerKey = consumerKey,
+ ConsumerSecret = consumerSecret,
+ TemporaryCredentialStorage = new CookieTemporaryCredentialStorage(),
+ };
}
#endregion
@@ -53,7 +58,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// Gets the DotNetOpenAuth <see cref="WebConsumer"/> instance that can be used to make OAuth 1.0 authorized HTTP requests.
/// </summary>
- public WebConsumer Consumer {
+ public Consumer Consumer {
get { return this.webConsumer; }
}
@@ -63,8 +68,8 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// Creates an HTTP message handler that authorizes outgoing web requests.
/// </summary>
/// <param name="accessToken">The access token.</param>
- public HttpMessageHandler CreateMessageHandler(string accessToken) {
- Requires.NotNullOrEmpty(accessToken, "accessToken");
+ public HttpMessageHandler CreateMessageHandler(AccessToken accessToken) {
+ Requires.NotNullOrEmpty(accessToken.Token, "accessToken");
return this.Consumer.CreateMessageHandler(accessToken);
}
@@ -76,8 +81,12 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <returns>
/// The response message.
/// </returns>
- public Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(CancellationToken cancellationToken = default(CancellationToken)) {
- return this.webConsumer.ProcessUserAuthorizationAsync(cancellationToken: cancellationToken);
+ public Task<AccessTokenResponse> ProcessUserAuthorizationAsync(HttpContextBase context = null, CancellationToken cancellationToken = default(CancellationToken)) {
+ if (context == null) {
+ context = new HttpContextWrapper(HttpContext.Current);
+ }
+
+ return this.webConsumer.ProcessUserAuthorizationAsync(context.Request.Url, cancellationToken: cancellationToken);
}
/// <summary>
@@ -88,37 +97,10 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <returns>
/// The response message.
/// </returns>
- public async Task<HttpResponseMessage> RequestAuthenticationAsync(Uri callback, CancellationToken cancellationToken = default(CancellationToken)) {
- var redirectParameters = new Dictionary<string, string>();
- UserAuthorizationRequest request = await this.webConsumer.PrepareRequestUserAuthorizationAsync(
- callback, null, redirectParameters, cancellationToken);
- var response = await this.webConsumer.Channel.PrepareResponseAsync(request, cancellationToken);
- return response;
- }
-
- #endregion
-
- #region IDisposable members
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- /// <filterpriority>2</filterpriority>
- public void Dispose() {
- this.Dispose(true);
- GC.SuppressFinalize(this);
+ public Task<Uri> RequestAuthenticationAsync(Uri callback, CancellationToken cancellationToken = default(CancellationToken)) {
+ return this.webConsumer.RequestUserAuthorizationAsync(callback, cancellationToken: cancellationToken);
}
#endregion
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool disposing) {
- if (disposing) {
- this.webConsumer.Dispose();
- }
- }
}
}
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthTokenManager.cs
deleted file mode 100644
index 92f1c22..0000000
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthTokenManager.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="IOAuthTokenManager.cs" company="Microsoft">
-// Copyright (c) Microsoft. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.AspNet.Clients {
- /// <summary>
- /// A token manager for use by a web site in its role as a consumer of
- /// an individual ServiceProvider.
- /// </summary>
- /// <remarks>
- /// This interface is used by clients of the DotNetOpenAuth.AspNet classes.
- /// </remarks>
- public interface IOAuthTokenManager {
- /// <summary>
- /// Gets the token secret from the specified token.
- /// </summary>
- /// <param name="token">The token.</param>
- /// <returns>The token's secret</returns>
- string GetTokenSecret(string token);
-
- /// <summary>
- /// Stores the request token together with its secret.
- /// </summary>
- /// <param name="requestToken">The request token.</param>
- /// <param name="requestTokenSecret">The request token secret.</param>
- void StoreRequestToken(string requestToken, string requestTokenSecret);
-
- /// <summary>
- /// Replaces the request token with access token.
- /// </summary>
- /// <param name="requestToken">The request token.</param>
- /// <param name="accessToken">The access token.</param>
- /// <param name="accessTokenSecret">The access token secret.</param>
- void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret);
- }
-} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs
index 7763add..e3ee3e8 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/IOAuthWebWorker.cs
@@ -10,7 +10,9 @@ namespace DotNetOpenAuth.AspNet.Clients {
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+ using System.Web;
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.Messages;
/// <summary>
@@ -21,23 +23,23 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// Creates an HTTP message handler that authorizes outgoing web requests.
/// </summary>
/// <param name="accessToken">The access token.</param>
- HttpMessageHandler CreateMessageHandler(string accessToken);
+ HttpMessageHandler CreateMessageHandler(AccessToken accessToken);
/// <summary>
/// The process user authorization.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
- /// The response message.
+ /// The access token, if obtained; otherwise <c>null</c>.
/// </returns>
- Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(CancellationToken cancellationToken = default(CancellationToken));
+ Task<AccessTokenResponse> ProcessUserAuthorizationAsync(HttpContextBase context = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// The request authentication.
/// </summary>
/// <param name="callback">The callback.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The response message</returns>
- Task<HttpResponseMessage> RequestAuthenticationAsync(Uri callback, CancellationToken cancellationToken = default(CancellationToken));
+ /// <returns>The URL to redirect the user agent to.</returns>
+ Task<Uri> RequestAuthenticationAsync(Uri callback, CancellationToken cancellationToken = default(CancellationToken));
}
}
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs
deleted file mode 100644
index a97e5d8..0000000
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/InMemoryOAuthTokenManager.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="InMemoryOAuthTokenManager.cs" company="Microsoft">
-// Copyright (c) Microsoft. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.AspNet.Clients {
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using System.Web;
- using DotNetOpenAuth.OAuth;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
- using Validation;
-
- /// <summary>
- /// An implementation of IOAuthTokenManager which stores keys in memory.
- /// </summary>
- public sealed class InMemoryOAuthTokenManager : IConsumerTokenManager {
- #region Constants and Fields
-
- /// <summary>
- /// The _tokens and secrets.
- /// </summary>
- private readonly Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
-
- #endregion
-
- #region Constructors and Destructors
-
- /// <summary>
- /// Initializes a new instance of the <see cref="InMemoryOAuthTokenManager"/> class.
- /// </summary>
- /// <param name="consumerKey">
- /// The consumer key.
- /// </param>
- /// <param name="consumerSecret">
- /// The consumer secret.
- /// </param>
- public InMemoryOAuthTokenManager(string consumerKey, string consumerSecret) {
- Requires.NotNull(consumerKey, "consumerKey");
- Requires.NotNull(consumerSecret, "consumerSecret");
-
- this.ConsumerKey = consumerKey;
- this.ConsumerSecret = consumerSecret;
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the consumer key.
- /// </summary>
- public string ConsumerKey { get; private set; }
-
- /// <summary>
- /// Gets the consumer secret.
- /// </summary>
- public string ConsumerSecret { get; private set; }
-
- #endregion
-
- #region Public Methods and Operators
-
- /// <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.ProcessUserAuthorizationAsync(HttpRequestBase, CancellationToken)"/>
- /// or
- /// <see cref="DesktopConsumer.ProcessUserAuthorizationAsync(string, string, CancellationToken)"/>
- /// 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) {
- this.tokensAndSecrets.Remove(requestToken);
- this.tokensAndSecrets[accessToken] = accessTokenSecret;
- }
-
- /// <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) {
- return this.tokensAndSecrets[token];
- }
-
- /// <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) {
- throw new NotImplementedException();
- }
-
- /// <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) {
- this.tokensAndSecrets[response.Token] = response.TokenSecret;
- }
-
- #endregion
- }
-}
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs
index 7aa1dd4..637bbd0 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs
@@ -28,21 +28,10 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// Describes the OAuth service provider endpoints for LinkedIn.
/// </summary>
- public static readonly ServiceProviderDescription LinkedInServiceDescription = new ServiceProviderDescription {
- RequestTokenEndpoint =
- new MessageReceivingEndpoint(
- "https://api.linkedin.com/uas/oauth/requestToken",
- HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- UserAuthorizationEndpoint =
- new MessageReceivingEndpoint(
- "https://www.linkedin.com/uas/oauth/authenticate",
- HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- AccessTokenEndpoint =
- new MessageReceivingEndpoint(
- "https://api.linkedin.com/uas/oauth/accessToken",
- HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- };
+ public static readonly ServiceProviderDescription LinkedInServiceDescription = new ServiceProviderDescription(
+ "https://api.linkedin.com/uas/oauth/requestToken",
+ "https://www.linkedin.com/uas/oauth/authenticate",
+ "https://api.linkedin.com/uas/oauth/accessToken");
#endregion
@@ -51,28 +40,10 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// Initializes a new instance of the <see cref="LinkedInClient"/> class.
/// </summary>
- /// <remarks>
- /// Tokens exchanged during the OAuth handshake are stored in cookies.
- /// </remarks>
- /// <param name="consumerKey">
- /// The LinkedIn app's consumer key.
- /// </param>
- /// <param name="consumerSecret">
- /// The LinkedIn app's consumer secret.
- /// </param>
- [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
- Justification = "We can't dispose the object because we still need it through the app lifetime.")]
- public LinkedInClient(string consumerKey, string consumerSecret)
- : this(consumerKey, consumerSecret, new CookieOAuthTokenManager()) { }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LinkedInClient"/> class.
- /// </summary>
/// <param name="consumerKey">The consumer key.</param>
/// <param name="consumerSecret">The consumer secret.</param>
- /// <param name="tokenManager">The token manager.</param>
- public LinkedInClient(string consumerKey, string consumerSecret, IOAuthTokenManager tokenManager)
- : base("linkedIn", LinkedInServiceDescription, new SimpleConsumerTokenManager(consumerKey, consumerSecret, tokenManager)) {
+ public LinkedInClient(string consumerKey, string consumerSecret)
+ : base("linkedIn", LinkedInServiceDescription, consumerKey, consumerSecret) {
}
#endregion
@@ -89,12 +60,11 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// </returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "We don't care if the request fails.")]
- protected override async Task<AuthenticationResult> VerifyAuthenticationCoreAsync(AuthorizedTokenResponse response, CancellationToken cancellationToken = default(CancellationToken)) {
+ protected override async Task<AuthenticationResult> VerifyAuthenticationCoreAsync(AccessTokenResponse response, CancellationToken cancellationToken = default(CancellationToken)) {
// See here for Field Selectors API http://developer.linkedin.com/docs/DOC-1014
const string ProfileRequestUrl = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,industry,summary)";
- string accessToken = response.AccessToken;
-
+ var accessToken = response.AccessToken;
var authorizingHandler = this.WebWorker.CreateMessageHandler(accessToken);
try {
using (var httpClient = new HttpClient(authorizingHandler)) {
@@ -108,7 +78,8 @@ namespace DotNetOpenAuth.AspNet.Clients {
string userName = firstName + " " + lastName;
var extraData = new Dictionary<string, string>();
- extraData.Add("accesstoken", accessToken);
+ extraData.Add("accesstoken", accessToken.Token);
+ extraData.Add("accesstokensecret", accessToken.Secret);
extraData.Add("name", userName);
extraData.AddDataIfNotEmpty(document, "headline");
extraData.AddDataIfNotEmpty(document, "summary");
@@ -123,8 +94,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
}
}
}
- }
- catch (Exception exception) {
+ } catch (Exception exception) {
return new AuthenticationResult(exception);
}
}
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs
index ffe5c07..03006f2 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/OAuthClient.cs
@@ -33,34 +33,14 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// Name of the provider.
/// </param>
/// <param name="serviceDescription">
- /// The service description.
- /// </param>
- /// <param name="consumerKey">
- /// The consumer key.
- /// </param>
- /// <param name="consumerSecret">
- /// The consumer secret.
- /// </param>
- protected OAuthClient(
- string providerName, ServiceProviderDescription serviceDescription, string consumerKey, string consumerSecret)
- : this(providerName, serviceDescription, new InMemoryOAuthTokenManager(consumerKey, consumerSecret)) { }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuthClient"/> class.
- /// </summary>
- /// <param name="providerName">
- /// Name of the provider.
- /// </param>
- /// <param name="serviceDescription">
/// The service Description.
/// </param>
/// <param name="tokenManager">
/// The token Manager.
/// </param>
- [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "I don't know how to ensure this rule is followed given this API")]
protected OAuthClient(
- string providerName, ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager)
- : this(providerName, new DotNetOpenAuthWebConsumer(serviceDescription, tokenManager)) {
+ string providerName, ServiceProviderDescription serviceDescription, string consumerKey, string consumerSecret)
+ : this(providerName, new DotNetOpenAuthWebConsumer(serviceDescription, consumerKey, consumerSecret)) {
}
/// <summary>
@@ -128,7 +108,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// An instance of <see cref="AuthenticationResult" /> containing authentication result.
/// </returns>
public virtual async Task<AuthenticationResult> VerifyAuthenticationAsync(HttpContextBase context, CancellationToken cancellationToken = default(CancellationToken)) {
- AuthorizedTokenResponse response = await this.WebWorker.ProcessUserAuthorizationAsync(cancellationToken);
+ AccessTokenResponse response = await this.WebWorker.ProcessUserAuthorizationAsync(context, cancellationToken);
if (response == null) {
return AuthenticationResult.Failed;
}
@@ -139,7 +119,8 @@ namespace DotNetOpenAuth.AspNet.Clients {
var wrapExtraData = result.ExtraData.IsReadOnly
? new Dictionary<string, string>(result.ExtraData)
: result.ExtraData;
- wrapExtraData["accesstoken"] = response.AccessToken;
+ wrapExtraData["accesstoken"] = response.AccessToken.Token;
+ wrapExtraData["accesstokensecret"] = response.AccessToken.Secret;
AuthenticationResult wrapResult = new AuthenticationResult(
result.IsSuccessful,
@@ -174,14 +155,14 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// Check if authentication succeeded after user is redirected back from the service provider.
/// </summary>
- /// <param name="response">
- /// The response token returned from service provider
+ /// <param name="accessToken">
+ /// The access token returned from service provider
/// </param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// Authentication result
/// </returns>
- protected abstract Task<AuthenticationResult> VerifyAuthenticationCoreAsync(AuthorizedTokenResponse response, CancellationToken cancellationToken);
+ protected abstract Task<AuthenticationResult> VerifyAuthenticationCoreAsync(AccessTokenResponse accessToken, CancellationToken cancellationToken);
#endregion
}
}
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs
deleted file mode 100644
index 899204c..0000000
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/SimpleConsumerTokenManager.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="SimpleConsumerTokenManager.cs" company="Microsoft">
-// Copyright (c) Microsoft. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.AspNet.Clients {
- using System;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using Validation;
-
- /// <summary>
- /// Simple wrapper around IConsumerTokenManager
- /// </summary>
- public class SimpleConsumerTokenManager : IConsumerTokenManager {
- /// <summary>
- /// Store the token manager.
- /// </summary>
- private readonly IOAuthTokenManager tokenManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="SimpleConsumerTokenManager"/> class.
- /// </summary>
- /// <param name="consumerKey">The consumer key.</param>
- /// <param name="consumerSecret">The consumer secret.</param>
- /// <param name="tokenManager">The OAuth token manager.</param>
- public SimpleConsumerTokenManager(string consumerKey, string consumerSecret, IOAuthTokenManager tokenManager) {
- Requires.NotNullOrEmpty(consumerKey, "consumerKey");
- Requires.NotNullOrEmpty(consumerSecret, "consumerSecret");
- Requires.NotNull(tokenManager, "oAuthTokenManager");
-
- this.ConsumerKey = consumerKey;
- this.ConsumerSecret = consumerSecret;
- this.tokenManager = tokenManager;
- }
-
- /// <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;
- }
-
- /// <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) {
- return this.tokenManager.GetTokenSecret(token);
- }
-
- /// <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>
- public void StoreNewRequestToken(DotNetOpenAuth.OAuth.Messages.UnauthorizedTokenRequest request, DotNetOpenAuth.OAuth.Messages.ITokenSecretContainingMessage response) {
- this.tokenManager.StoreRequestToken(response.Token, response.TokenSecret);
- }
-
- /// <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>
- public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
- this.tokenManager.ReplaceRequestTokenWithAccessToken(requestToken, accessToken, accessTokenSecret);
- }
-
- /// <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) {
- throw new NotSupportedException();
- }
- }
-} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs
index 0f5e0db..88bb530 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/TwitterClient.cs
@@ -28,51 +28,23 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// The description of Twitter's OAuth protocol URIs for use with their "Sign in with Twitter" feature.
/// </summary>
- public static readonly ServiceProviderDescription TwitterServiceDescription = new ServiceProviderDescription {
- RequestTokenEndpoint =
- new MessageReceivingEndpoint(
- "https://api.twitter.com/oauth/request_token",
- HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- UserAuthorizationEndpoint =
- new MessageReceivingEndpoint(
- "https://api.twitter.com/oauth/authenticate",
- HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- AccessTokenEndpoint =
- new MessageReceivingEndpoint(
- "https://api.twitter.com/oauth/access_token",
- HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
- TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
- };
+ public static readonly ServiceProviderDescription TwitterServiceDescription =
+ new ServiceProviderDescription(
+ "https://api.twitter.com/oauth/request_token",
+ "https://api.twitter.com/oauth/authenticate",
+ "https://api.twitter.com/oauth/access_token");
#endregion
#region Constructors and Destructors
/// <summary>
- /// Initializes a new instance of the <see cref="TwitterClient"/> class with the specified consumer key and consumer secret.
- /// </summary>
- /// <remarks>
- /// Tokens exchanged during the OAuth handshake are stored in cookies.
- /// </remarks>
- /// <param name="consumerKey">
- /// The consumer key.
- /// </param>
- /// <param name="consumerSecret">
- /// The consumer secret.
- /// </param>
- [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
- Justification = "We can't dispose the object because we still need it through the app lifetime.")]
- public TwitterClient(string consumerKey, string consumerSecret)
- : this(consumerKey, consumerSecret, new AuthenticationOnlyCookieOAuthTokenManager()) { }
-
- /// <summary>
/// Initializes a new instance of the <see cref="TwitterClient"/> class.
/// </summary>
/// <param name="consumerKey">The consumer key.</param>
/// <param name="consumerSecret">The consumer secret.</param>
- /// <param name="tokenManager">The token manager.</param>
- public TwitterClient(string consumerKey, string consumerSecret, IOAuthTokenManager tokenManager)
- : base("twitter", TwitterServiceDescription, new SimpleConsumerTokenManager(consumerKey, consumerSecret, tokenManager)) {
+ public TwitterClient(string consumerKey, string consumerSecret)
+ : base("twitter", TwitterServiceDescription, consumerKey, consumerSecret) {
}
#endregion
@@ -89,17 +61,17 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// </returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "We don't care if the request for additional data fails.")]
- protected override async Task<AuthenticationResult> VerifyAuthenticationCoreAsync(AuthorizedTokenResponse response, CancellationToken cancellationToken) {
- string accessToken = response.AccessToken;
+ protected override async Task<AuthenticationResult> VerifyAuthenticationCoreAsync(AccessTokenResponse response, CancellationToken cancellationToken) {
string userId = response.ExtraData["user_id"];
string userName = response.ExtraData["screen_name"];
var profileRequestUrl = new Uri("https://api.twitter.com/1/users/show.xml?user_id="
+ MessagingUtilities.EscapeUriDataStringRfc3986(userId));
- var authorizingHandler = this.WebWorker.CreateMessageHandler(accessToken);
+ var authorizingHandler = this.WebWorker.CreateMessageHandler(response.AccessToken);
var extraData = new Dictionary<string, string>();
- extraData.Add("accesstoken", accessToken);
+ extraData.Add("accesstoken", response.AccessToken.Token);
+ extraData.Add("accesstokensecret", response.AccessToken.Secret);
try {
using (var httpClient = new HttpClient(authorizingHandler)) {
using (HttpResponseMessage profileResponse = await httpClient.GetAsync(profileRequestUrl, cancellationToken)) {
diff --git a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
index 7a9d49b..b3b52d9 100644
--- a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
+++ b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
@@ -50,12 +50,6 @@
<Compile Include="AuthenticationResult.cs" />
<Compile Include="Clients\DictionaryExtensions.cs" />
<Compile Include="Clients\OAuth2\WindowsLiveClient.cs" />
- <Compile Include="Clients\OAuth\AuthenticationOnlyCookieOAuthTokenManager.cs">
- <SubType>Code</SubType>
- </Compile>
- <Compile Include="Clients\OAuth\CookieOAuthTokenManager.cs" />
- <Compile Include="Clients\OAuth\IOAuthTokenManager.cs" />
- <Compile Include="Clients\OAuth\SimpleConsumerTokenManager.cs" />
<Compile Include="IAuthenticationClient.cs" />
<Compile Include="Clients\OAuth2\FacebookClient.cs" />
<Compile Include="Clients\OAuth2\FacebookGraphData.cs" />
@@ -65,7 +59,6 @@
<Compile Include="Clients\OAuth2\MicrosoftClient.cs" />
<Compile Include="Clients\OAuth2\MicrosoftClientUserData.cs" />
<Compile Include="Clients\OAuth\DotNetOpenAuthWebConsumer.cs" />
- <Compile Include="Clients\OAuth\InMemoryOAuthTokenManager.cs" />
<Compile Include="Clients\OAuth\IOAuthWebWorker.cs" />
<Compile Include="Clients\OAuth\LinkedInClient.cs" />
<Compile Include="Clients\OAuth\OAuthClient.cs" />
@@ -73,7 +66,6 @@
<Compile Include="Clients\OpenID\GoogleOpenIdClient.cs" />
<Compile Include="Clients\OpenID\OpenIdClient.cs" />
<Compile Include="Clients\OpenID\YahooOpenIdClient.cs" />
- <Compile Include="MachineKeyUtil.cs" />
<Compile Include="UriHelper.cs" />
<Compile Include="IOpenAuthDataProvider.cs" />
<Compile Include="OpenAuthAuthenticationTicketHelper.cs" />
diff --git a/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs b/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs
index fd79a73..da1d1ca 100644
--- a/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs
+++ b/src/DotNetOpenAuth.AspNet/WebResources.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.544
+// Runtime Version:4.0.30319.18033
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -79,15 +79,6 @@ namespace DotNetOpenAuth.AspNet {
}
/// <summary>
- /// Looks up a localized string similar to The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the &apos;decryptionKey&apos; and &apos;validationKey&apos; attributes are explicitly specified in the &lt;machineKey&gt; configuration section..
- /// </summary>
- internal static string Generic_CryptoFailure {
- get {
- return ResourceManager.GetString("Generic_CryptoFailure", resourceCulture);
- }
- }
-
- /// <summary>
/// Looks up a localized string similar to An OAuth data provider has already been registered for this application..
/// </summary>
internal static string OAuthDataProviderRegistered {
diff --git a/src/DotNetOpenAuth.AspNet/WebResources.resx b/src/DotNetOpenAuth.AspNet/WebResources.resx
index c1552e9..a491579 100644
--- a/src/DotNetOpenAuth.AspNet/WebResources.resx
+++ b/src/DotNetOpenAuth.AspNet/WebResources.resx
@@ -123,9 +123,6 @@
<data name="FailedToEncryptTicket" xml:space="preserve">
<value>Unable to encrypt the authentication ticket.</value>
</data>
- <data name="Generic_CryptoFailure" xml:space="preserve">
- <value>The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the 'decryptionKey' and 'validationKey' attributes are explicitly specified in the &lt;machineKey&gt; configuration section.</value>
- </data>
<data name="OAuthDataProviderRegistered" xml:space="preserve">
<value>An OAuth data provider has already been registered for this application.</value>
</data>
diff --git a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
index 7877cf0..253528b 100644
--- a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
+++ b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
@@ -22,10 +22,12 @@
<Compile Include="Assumes.cs" />
<Compile Include="IHostFactories.cs" />
<Compile Include="IRequireHostFactories.cs" />
+ <Compile Include="MachineKeyUtil.cs" />
<Compile Include="Messaging\Base64WebEncoder.cs" />
<Compile Include="Messaging\Bindings\AsymmetricCryptoKeyStoreWrapper.cs" />
<Compile Include="Messaging\Bindings\CryptoKey.cs" />
<Compile Include="Messaging\Bindings\CryptoKeyCollisionException.cs" />
+ <Compile Include="Messaging\Bindings\HardCodedKeyCryptoKeyStore.cs" />
<Compile Include="Messaging\Bindings\ICryptoKeyStore.cs" />
<Compile Include="Messaging\Bindings\MemoryCryptoKeyStore.cs" />
<Compile Include="Messaging\BinaryDataBagFormatter.cs" />
diff --git a/src/DotNetOpenAuth.AspNet/MachineKeyUtil.cs b/src/DotNetOpenAuth.Core/MachineKeyUtil.cs
index eb2020b..eceb38c 100644
--- a/src/DotNetOpenAuth.AspNet/MachineKeyUtil.cs
+++ b/src/DotNetOpenAuth.Core/MachineKeyUtil.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.AspNet {
+namespace DotNetOpenAuth {
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -183,7 +183,7 @@ namespace DotNetOpenAuth.AspNet {
}
// if we reached this point, some cryptographic operation failed
- throw new CryptographicException(WebResources.Generic_CryptoFailure);
+ throw new CryptographicException(Strings.Generic_CryptoFailure);
}
/// <summary>
diff --git a/src/DotNetOpenAuth.Core/Messaging/Bindings/HardCodedKeyCryptoKeyStore.cs b/src/DotNetOpenAuth.Core/Messaging/Bindings/HardCodedKeyCryptoKeyStore.cs
new file mode 100644
index 0000000..c828616
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Messaging/Bindings/HardCodedKeyCryptoKeyStore.cs
@@ -0,0 +1,98 @@
+//-----------------------------------------------------------------------
+// <copyright file="HardCodedKeyCryptoKeyStore.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Messaging.Bindings {
+ using System;
+ using System.Collections.Generic;
+ using Validation;
+
+ /// <summary>
+ /// A trivial implementation of <see cref="ICryptoKeyStore"/> that has only one fixed key.
+ /// This is meant for simple, low-security applications. Greater security requires an
+ /// implementation of <see cref="ICryptoKeyStore"/> that actually stores and retrieves
+ /// keys from a persistent store.
+ /// </summary>
+ public class HardCodedKeyCryptoKeyStore : ICryptoKeyStore {
+ /// <summary>
+ /// The handle to report for the hard-coded key.
+ /// </summary>
+ private const string HardCodedKeyHandle = "fxd";
+
+ /// <summary>
+ /// The one crypto key singleton instance.
+ /// </summary>
+ private readonly CryptoKey OneCryptoKey;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HardCodedKeyCryptoKeyStore"/> class.
+ /// </summary>
+ /// <param name="secretAsBase64">The 256-bit secret as a base64 encoded string.</param>
+ public HardCodedKeyCryptoKeyStore(string secretAsBase64)
+ : this(Convert.FromBase64String(Requires.NotNull(secretAsBase64, "secretAsBase64"))) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HardCodedKeyCryptoKeyStore"/> class.
+ /// </summary>
+ /// <param name="secret">The 256-bit secret.</param>
+ public HardCodedKeyCryptoKeyStore(byte[] secret) {
+ Requires.NotNull(secret, "secret");
+ this.OneCryptoKey = new CryptoKey(secret, DateTime.MaxValue.AddDays(-2).ToUniversalTime());
+ }
+
+ #region ICryptoKeyStore Members
+
+ /// <summary>
+ /// Gets the key in a given bucket and handle.
+ /// </summary>
+ /// <param name="bucket">The bucket name. Case sensitive.</param>
+ /// <param name="handle">The key handle. Case sensitive.</param>
+ /// <returns>
+ /// The cryptographic key, or <c>null</c> if no matching key was found.
+ /// </returns>
+ public CryptoKey GetKey(string bucket, string handle) {
+ if (handle == HardCodedKeyHandle) {
+ return OneCryptoKey;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Gets a sequence of existing keys within a given bucket.
+ /// </summary>
+ /// <param name="bucket">The bucket name. Case sensitive.</param>
+ /// <returns>
+ /// A sequence of handles and keys, ordered by descending <see cref="CryptoKey.ExpiresUtc" />.
+ /// </returns>
+ public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
+ return new[] { new KeyValuePair<string, CryptoKey>(HardCodedKeyHandle, OneCryptoKey) };
+ }
+
+ /// <summary>
+ /// Stores a cryptographic key.
+ /// </summary>
+ /// <param name="bucket">The name of the bucket to store the key in. Case sensitive.</param>
+ /// <param name="handle">The handle to the key, unique within the bucket. Case sensitive.</param>
+ /// <param name="key">The key to store.</param>
+ /// <exception cref="System.NotSupportedException"></exception>
+ public void StoreKey(string bucket, string handle, CryptoKey key) {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Removes the key.
+ /// </summary>
+ /// <param name="bucket">The bucket name. Case sensitive.</param>
+ /// <param name="handle">The key handle. Case sensitive.</param>
+ /// <exception cref="System.NotSupportedException"></exception>
+ public void RemoveKey(string bucket, string handle) {
+ throw new NotSupportedException();
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
index 501b5b2..38abe4a 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
@@ -393,6 +393,15 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Gets the public facing URL for the given incoming HTTP request.
+ /// </summary>
+ /// <returns>The URI that the outside world used to create this request.</returns>
+ public static Uri GetPublicFacingUrl() {
+ ErrorUtilities.VerifyHttpContext();
+ return GetPublicFacingUrl(new HttpRequestWrapper(HttpContext.Current.Request));
+ }
+
+ /// <summary>
/// Wraps a response message as an MVC <see cref="ActionResult"/> so it can be conveniently returned from an MVC controller's action method.
/// </summary>
/// <param name="response">The response message.</param>
diff --git a/src/DotNetOpenAuth.Core/Strings.Designer.cs b/src/DotNetOpenAuth.Core/Strings.Designer.cs
index 9eefd62..b96f68a 100644
--- a/src/DotNetOpenAuth.Core/Strings.Designer.cs
+++ b/src/DotNetOpenAuth.Core/Strings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.18010
+// Runtime Version:4.0.30319.18033
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -97,6 +97,15 @@ namespace DotNetOpenAuth {
}
/// <summary>
+ /// Looks up a localized string similar to The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the &apos;decryptionKey&apos; and &apos;validationKey&apos; attributes are explicitly specified in the &lt;machineKey&gt; configuration section..
+ /// </summary>
+ internal static string Generic_CryptoFailure {
+ get {
+ return ResourceManager.GetString("Generic_CryptoFailure", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The HostFactories property must be set first..
/// </summary>
internal static string HostFactoriesRequired {
diff --git a/src/DotNetOpenAuth.Core/Strings.resx b/src/DotNetOpenAuth.Core/Strings.resx
index 133fe6f..1c2aee2 100644
--- a/src/DotNetOpenAuth.Core/Strings.resx
+++ b/src/DotNetOpenAuth.Core/Strings.resx
@@ -144,4 +144,7 @@
<data name="HostFactoriesRequired" xml:space="preserve">
<value>The HostFactories property must be set first.</value>
</data>
+ <data name="Generic_CryptoFailure" xml:space="preserve">
+ <value>The provided data could not be decrypted. If the current application is deployed in a web farm configuration, ensure that the 'decryptionKey' and 'validationKey' attributes are explicitly specified in the &lt;machineKey&gt; configuration section.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OAuth.Common/DotNetOpenAuth.OAuth.Common.csproj b/src/DotNetOpenAuth.OAuth.Common/DotNetOpenAuth.OAuth.Common.csproj
index 89638d6..95549fe 100644
--- a/src/DotNetOpenAuth.OAuth.Common/DotNetOpenAuth.OAuth.Common.csproj
+++ b/src/DotNetOpenAuth.OAuth.Common/DotNetOpenAuth.OAuth.Common.csproj
@@ -21,7 +21,6 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
- <Compile Include="OAuth\ChannelElements\OAuthIdentity.cs" />
<Compile Include="OAuth\ChannelElements\OAuthPrincipal.cs" />
<Compile Include="OAuth\DefaultOAuthHostFactories.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthIdentity.cs b/src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthIdentity.cs
deleted file mode 100644
index 28e0333..0000000
--- a/src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthIdentity.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthIdentity.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Diagnostics.CodeAnalysis;
- using System.Runtime.InteropServices;
- using System.Security.Principal;
- using DotNetOpenAuth.Messaging;
- using Validation;
-
- /// <summary>
- /// Represents an OAuth consumer that is impersonating a known user on the system.
- /// </summary>
- [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "Not cocreatable.")]
- [Serializable]
- [ComVisible(true)]
- public class OAuthIdentity : IIdentity {
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuthIdentity"/> class.
- /// </summary>
- /// <param name="username">The username.</param>
- internal OAuthIdentity(string username) {
- Requires.NotNullOrEmpty(username, "username");
- this.Name = username;
- }
-
- #region IIdentity Members
-
- /// <summary>
- /// Gets the type of authentication used.
- /// </summary>
- /// <value>The constant "OAuth"</value>
- /// <returns>
- /// The type of authentication used to identify the user.
- /// </returns>
- public string AuthenticationType {
- get { return "OAuth"; }
- }
-
- /// <summary>
- /// Gets a value indicating whether the user has been authenticated.
- /// </summary>
- /// <value>The value <c>true</c></value>
- /// <returns>true if the user was authenticated; otherwise, false.
- /// </returns>
- public bool IsAuthenticated {
- get { return true; }
- }
-
- /// <summary>
- /// Gets the name of the user who authorized the OAuth token the consumer is using for authorization.
- /// </summary>
- /// <returns>
- /// The name of the user on whose behalf the code is running.
- /// </returns>
- public string Name { get; private set; }
-
- #endregion
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthPrincipal.cs b/src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthPrincipal.cs
index 65d7042..988d727 100644
--- a/src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthPrincipal.cs
+++ b/src/DotNetOpenAuth.OAuth.Common/OAuth/ChannelElements/OAuthPrincipal.cs
@@ -1,6 +1,6 @@
//-----------------------------------------------------------------------
-// <copyright file="OAuthPrincipal.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
+// <copyright file="OAuthPrincipal.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
@@ -11,87 +11,35 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;
+ using System.Security.Claims;
using System.Security.Principal;
+ using Validation;
+
/// <summary>
- /// Represents an OAuth consumer that is impersonating a known user on the system.
+ /// Utilities for dealing with OAuth claims and principals.
/// </summary>
- [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "Not cocreatable.")]
- [Serializable]
- [ComVisible(true)]
- public class OAuthPrincipal : IPrincipal {
- /// <summary>
- /// The roles this user belongs to.
- /// </summary>
- private ICollection<string> roles;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuthPrincipal"/> class.
- /// </summary>
- /// <param name="userName">The username.</param>
- /// <param name="roles">The roles this user belongs to.</param>
- public OAuthPrincipal(string userName, string[] roles)
- : this(new OAuthIdentity(userName), roles) {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuthPrincipal"/> class.
- /// </summary>
- /// <param name="identity">The identity.</param>
- /// <param name="roles">The roles this user belongs to.</param>
- internal OAuthPrincipal(OAuthIdentity identity, string[] roles) {
- this.Identity = identity;
- this.roles = roles;
- }
-
- /// <summary>
- /// Gets or sets the access token used to create this principal.
- /// </summary>
- /// <value>A non-empty string.</value>
- public string AccessToken { get; protected set; }
-
+ internal static class OAuthPrincipal {
/// <summary>
- /// Gets the roles that this principal has as a ReadOnlyCollection.
+ /// Creates a new instance of ClaimsPrincipal.
/// </summary>
- public ReadOnlyCollection<string> Roles
- {
- get { return new ReadOnlyCollection<string>(this.roles.ToList()); }
- }
-
- #region IPrincipal Members
-
- /// <summary>
- /// Gets the identity of the current principal.
- /// </summary>
- /// <value></value>
+ /// <param name="userName">Name of the user.</param>
+ /// <param name="roles">The roles.</param>
/// <returns>
- /// The <see cref="T:System.Security.Principal.IIdentity"/> object associated with the current principal.
+ /// A new instance of GenericPrincipal with a GenericIdentity, having the same username and roles as this OAuthPrincipal and OAuthIdentity
/// </returns>
- public IIdentity Identity { get; private set; }
-
- /// <summary>
- /// Determines whether the current principal belongs to the specified role.
- /// </summary>
- /// <param name="role">The name of the role for which to check membership.</param>
- /// <returns>
- /// true if the current principal is a member of the specified role; otherwise, false.
- /// </returns>
- /// <remarks>
- /// The role membership check uses <see cref="StringComparer.OrdinalIgnoreCase"/>.
- /// </remarks>
- public bool IsInRole(string role) {
- return this.roles.Contains(role, StringComparer.OrdinalIgnoreCase);
- }
-
- #endregion
-
- /// <summary>
- /// Creates a new instance of GenericPrincipal based on this OAuthPrincipal.
- /// </summary>
- /// <returns>A new instance of GenericPrincipal with a GenericIdentity, having the same username and roles as this OAuthPrincipal and OAuthIdentity</returns>
- public GenericPrincipal CreateGenericPrincipal()
- {
- return new GenericPrincipal(new GenericIdentity(this.Identity.Name), this.roles.ToArray());
+ internal static ClaimsPrincipal CreatePrincipal(string userName, IEnumerable<string> roles = null) {
+ Requires.NotNullOrEmpty(userName, "userName");
+
+ var claims = new List<Claim>();
+ claims.Add(new Claim(ClaimsIdentity.DefaultNameClaimType, userName));
+ if (roles != null) {
+ claims.AddRange(roles.Select(scope => new Claim(ClaimsIdentity.DefaultRoleClaimType, scope)));
+ }
+
+ var claimsIdentity = new ClaimsIdentity(claims, "OAuth 2 Bearer");
+ var principal = new ClaimsPrincipal(claimsIdentity);
+ return principal;
}
}
}
diff --git a/src/DotNetOpenAuth.OAuth.Common/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.OAuth.Common/Properties/AssemblyInfo.cs
index a3afcd7..ee7b802 100644
--- a/src/DotNetOpenAuth.OAuth.Common/Properties/AssemblyInfo.cs
+++ b/src/DotNetOpenAuth.OAuth.Common/Properties/AssemblyInfo.cs
@@ -35,9 +35,13 @@ using System.Web.UI;
// keep this assembly from being useful to shared host (medium trust) web sites.
[assembly: AllowPartiallyTrustedCallers]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.ResourceServer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth.ServiceProvider, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
[assembly: InternalsVisibleTo("DotNetOpenAuth.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
#else
+[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.ResourceServer")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth.ServiceProvider")]
[assembly: InternalsVisibleTo("DotNetOpenAuth.Test")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
#endif
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj
index 922b860..173bb3e 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj
+++ b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj
@@ -19,17 +19,17 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
- <Compile Include="OAuth\ChannelElements\IConsumerTokenManager.cs" />
- <Compile Include="OAuth\ChannelElements\OAuthConsumerChannel.cs" />
- <Compile Include="OAuth\ChannelElements\OAuthConsumerMessageFactory.cs" />
- <Compile Include="OAuth\ChannelElements\RsaSha1ConsumerSigningBindingElement.cs" />
- <Compile Include="OAuth\ConsumerBase.cs" />
- <Compile Include="OAuth\DesktopConsumer.cs" />
+ <Compile Include="OAuth\AccessToken.cs" />
+ <Compile Include="OAuth\AccessTokenResponse.cs" />
+ <Compile Include="OAuth\ITemporaryCredentialStorage.cs" />
+ <Compile Include="OAuth\Consumer.cs" />
+ <Compile Include="OAuth\CookieTemporaryCredentialStorage.cs" />
+ <Compile Include="OAuth\MemoryTemporaryCredentialStorage.cs" />
<Compile Include="OAuth\OAuth1HmacSha1HttpMessageHandler.cs" />
<Compile Include="OAuth\OAuth1HttpMessageHandlerBase.cs" />
<Compile Include="OAuth\OAuth1PlainTextMessageHandler.cs" />
<Compile Include="OAuth\OAuth1RsaSha1HttpMessageHandler.cs" />
- <Compile Include="OAuth\WebConsumer.cs" />
+ <Compile Include="OAuth\ServiceProviderDescription.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>
</SubType>
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs
new file mode 100644
index 0000000..20e3ec4
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessToken.cs
@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessToken.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ /// <summary>
+ /// An OAuth 1.0 access token and secret.
+ /// </summary>
+ public struct AccessToken {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessToken"/> struct.
+ /// </summary>
+ /// <param name="token">The token.</param>
+ /// <param name="secret">The secret.</param>
+ public AccessToken(string token, string secret)
+ : this() {
+ this.Token = token;
+ this.Secret = secret;
+ }
+
+ /// <summary>
+ /// Gets or sets the token.
+ /// </summary>
+ /// <value>
+ /// The token.
+ /// </value>
+ public string Token { get; set; }
+
+ /// <summary>
+ /// Gets or sets the token secret.
+ /// </summary>
+ /// <value>
+ /// The secret.
+ /// </value>
+ public string Secret { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs
new file mode 100644
index 0000000..dd35400
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/AccessTokenResponse.cs
@@ -0,0 +1,19 @@
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Specialized;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ public class AccessTokenResponse {
+ public AccessTokenResponse(string accessToken, string tokenSecret, NameValueCollection extraData) {
+ this.AccessToken = new AccessToken(accessToken, tokenSecret);
+ this.ExtraData = extraData;
+ }
+
+ public AccessToken AccessToken { get; set; }
+
+ public NameValueCollection ExtraData { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs
deleted file mode 100644
index 74ec3be..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/IConsumerTokenManager.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="IConsumerTokenManager.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- /// <summary>
- /// A token manager for use by a web site in its role as a consumer of
- /// an individual ServiceProvider.
- /// </summary>
- public interface IConsumerTokenManager : ITokenManager {
- /// <summary>
- /// Gets the consumer key.
- /// </summary>
- /// <value>The consumer key.</value>
- string ConsumerKey { get; }
-
- /// <summary>
- /// Gets the consumer secret.
- /// </summary>
- /// <value>The consumer secret.</value>
- string ConsumerSecret { get; }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs
deleted file mode 100644
index a10ff09..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerChannel.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthConsumerChannel.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Text;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.Messaging.Bindings;
- using Validation;
-
- /// <summary>
- /// The messaging channel for OAuth 1.0(a) Consumers.
- /// </summary>
- internal class OAuthConsumerChannel : OAuthChannel {
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuthConsumerChannel" /> class.
- /// </summary>
- /// <param name="signingBindingElement">The binding element to use for signing.</param>
- /// <param name="store">The web application store to use for nonces.</param>
- /// <param name="tokenManager">The token manager instance to use.</param>
- /// <param name="securitySettings">The security settings.</param>
- /// <param name="messageFactory">The message factory.</param>
- /// <param name="hostFactories">The host factories.</param>
- [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Diagnostics.Contracts.__ContractsRuntime.Requires<System.ArgumentNullException>(System.Boolean,System.String,System.String)", Justification = "Code contracts"), SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "securitySettings", Justification = "Code contracts")]
- internal OAuthConsumerChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IConsumerTokenManager tokenManager, ConsumerSecuritySettings securitySettings, IMessageFactory messageFactory = null, IHostFactories hostFactories = null)
- : base(
- signingBindingElement,
- tokenManager,
- securitySettings,
- messageFactory ?? new OAuthConsumerMessageFactory(),
- InitializeBindingElements(signingBindingElement, store),
- hostFactories) {
- Requires.NotNull(tokenManager, "tokenManager");
- Requires.NotNull(securitySettings, "securitySettings");
- Requires.NotNull(signingBindingElement, "signingBindingElement");
- }
-
- /// <summary>
- /// Gets the consumer secret for a given consumer key.
- /// </summary>
- /// <param name="consumerKey">The consumer key.</param>
- /// <returns>The consumer secret.</returns>
- protected override string GetConsumerSecret(string consumerKey) {
- var consumerTokenManager = (IConsumerTokenManager)this.TokenManager;
- ErrorUtilities.VerifyInternal(consumerKey == consumerTokenManager.ConsumerKey, "The token manager consumer key and the consumer key set earlier do not match!");
- return consumerTokenManager.ConsumerSecret;
- }
-
- /// <summary>
- /// Initializes the binding elements for the OAuth channel.
- /// </summary>
- /// <param name="signingBindingElement">The signing binding element.</param>
- /// <param name="store">The nonce store.</param>
- /// <returns>
- /// An array of binding elements used to initialize the channel.
- /// </returns>
- private static new IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store) {
- return OAuthChannel.InitializeBindingElements(signingBindingElement, store).ToArray();
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
deleted file mode 100644
index e79749f..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/OAuthConsumerMessageFactory.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuthConsumerMessageFactory.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Collections.Generic;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth.Messages;
-
- /// <summary>
- /// An OAuth-protocol specific implementation of the <see cref="IMessageFactory"/>
- /// interface.
- /// </summary>
- public class OAuthConsumerMessageFactory : IMessageFactory {
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuthConsumerMessageFactory"/> class.
- /// </summary>
- protected internal OAuthConsumerMessageFactory() {
- }
-
- #region IMessageFactory Members
-
- /// <summary>
- /// Analyzes an incoming request message payload to discover what kind of
- /// message is embedded in it and returns the type, or null if no match is found.
- /// </summary>
- /// <param name="recipient">The intended or actual recipient of the request message.</param>
- /// <param name="fields">The name/value pairs that make up the message payload.</param>
- /// <returns>
- /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can
- /// deserialize to. Null if the request isn't recognized as a valid protocol message.
- /// </returns>
- /// <remarks>
- /// The request messages are:
- /// UserAuthorizationResponse
- /// </remarks>
- public virtual IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) {
- MessageBase message = null;
-
- if (fields.ContainsKey("oauth_token")) {
- Protocol protocol = fields.ContainsKey("oauth_verifier") ? Protocol.V10a : Protocol.V10;
- message = new UserAuthorizationResponse(recipient.Location, protocol.Version);
- }
-
- if (message != null) {
- message.SetAsIncoming();
- }
-
- return message;
- }
-
- /// <summary>
- /// Analyzes an incoming request message payload to discover what kind of
- /// message is embedded in it and returns the type, or null if no match is found.
- /// </summary>
- /// <param name="request">
- /// The message that was sent as a request that resulted in the response.
- /// Null on a Consumer site that is receiving an indirect message from the Service Provider.
- /// </param>
- /// <param name="fields">The name/value pairs that make up the message payload.</param>
- /// <returns>
- /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can
- /// deserialize to. Null if the request isn't recognized as a valid protocol message.
- /// </returns>
- /// <remarks>
- /// The response messages are:
- /// UnauthorizedTokenResponse
- /// AuthorizedTokenResponse
- /// </remarks>
- public virtual IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) {
- MessageBase message = null;
-
- // All response messages have the oauth_token field.
- if (!fields.ContainsKey("oauth_token")) {
- return null;
- }
-
- // All direct message responses should have the oauth_token_secret field.
- if (!fields.ContainsKey("oauth_token_secret")) {
- Logger.OAuth.Error("An OAuth message was expected to contain an oauth_token_secret but didn't.");
- return null;
- }
-
- var unauthorizedTokenRequest = request as UnauthorizedTokenRequest;
- var authorizedTokenRequest = request as AuthorizedTokenRequest;
- if (unauthorizedTokenRequest != null) {
- Protocol protocol = fields.ContainsKey("oauth_callback_confirmed") ? Protocol.V10a : Protocol.V10;
- message = new UnauthorizedTokenResponse(unauthorizedTokenRequest, protocol.Version);
- } else if (authorizedTokenRequest != null) {
- message = new AuthorizedTokenResponse(authorizedTokenRequest);
- } else {
- Logger.OAuth.ErrorFormat("Unexpected response message given the request type {0}", request.GetType().Name);
- throw new ProtocolException(OAuthStrings.InvalidIncomingMessage);
- }
-
- if (message != null) {
- message.SetAsIncoming();
- }
-
- return message;
- }
-
- #endregion
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs
deleted file mode 100644
index d492e33..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ChannelElements/RsaSha1ConsumerSigningBindingElement.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="RsaSha1ConsumerSigningBindingElement.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Diagnostics.CodeAnalysis;
- using System.Security.Cryptography;
- using System.Security.Cryptography.X509Certificates;
- using System.Text;
- using DotNetOpenAuth.Messaging;
- using Validation;
-
- /// <summary>
- /// A binding element that signs outgoing messages and verifies the signature on incoming messages.
- /// </summary>
- [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sha", Justification = "Acronym")]
- public class RsaSha1ConsumerSigningBindingElement : RsaSha1SigningBindingElement {
- /// <summary>
- /// Initializes a new instance of the <see cref="RsaSha1ConsumerSigningBindingElement"/> class.
- /// </summary>
- /// <param name="signingCertificate">The certificate used to sign outgoing messages.</param>
- public RsaSha1ConsumerSigningBindingElement(X509Certificate2 signingCertificate) {
- Requires.NotNull(signingCertificate, "signingCertificate");
-
- this.SigningCertificate = signingCertificate;
- }
-
- /// <summary>
- /// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers.
- /// </summary>
- public X509Certificate2 SigningCertificate { get; set; }
-
- /// <summary>
- /// Determines whether the signature on some message is valid.
- /// </summary>
- /// <param name="message">The message to check the signature on.</param>
- /// <returns>
- /// <c>true</c> if the signature on the message is valid; otherwise, <c>false</c>.
- /// </returns>
- protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Calculates a signature for a given message.
- /// </summary>
- /// <param name="message">The message to sign.</param>
- /// <returns>The signature for the message.</returns>
- /// <remarks>
- /// This method signs the message per OAuth 1.0 section 9.3.
- /// </remarks>
- protected override string GetSignature(ITamperResistantOAuthMessage message) {
- ErrorUtilities.VerifyOperation(this.SigningCertificate != null, OAuthStrings.X509CertificateNotProvidedForSigning);
-
- string signatureBaseString = ConstructSignatureBaseString(message, this.Channel.MessageDescriptions.GetAccessor(message));
- byte[] data = Encoding.ASCII.GetBytes(signatureBaseString);
- var provider = (RSACryptoServiceProvider)this.SigningCertificate.PrivateKey;
- byte[] binarySignature = provider.SignData(data, "SHA1");
- string base64Signature = Convert.ToBase64String(binarySignature);
- return base64Signature;
- }
-
- /// <summary>
- /// Creates a new object that is a copy of the current instance.
- /// </summary>
- /// <returns>
- /// A new object that is a copy of this instance.
- /// </returns>
- protected override ITamperProtectionChannelBindingElement Clone() {
- return new RsaSha1ConsumerSigningBindingElement(this.SigningCertificate);
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs
new file mode 100644
index 0000000..560e536
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/Consumer.cs
@@ -0,0 +1,336 @@
+//-----------------------------------------------------------------------
+// <copyright file="Consumer.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using System.Net;
+ using System.Net.Http;
+ using System.Security.Cryptography.X509Certificates;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using System.Web;
+ using DotNetOpenAuth.Configuration;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+ using Validation;
+
+ /// <summary>
+ /// Base class for <see cref="WebConsumer"/> and <see cref="DesktopConsumer"/> types.
+ /// </summary>
+ public class Consumer {
+ /// <summary>
+ /// The host factories.
+ /// </summary>
+ private IHostFactories hostFactories;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Consumer"/> class.
+ /// </summary>
+ public Consumer() {
+ this.HostFactories = new DefaultOAuthHostFactories();
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Consumer"/> class.
+ /// </summary>
+ /// <param name="consumerKey">The consumer key.</param>
+ /// <param name="consumerSecret">The consumer secret.</param>
+ /// <param name="serviceProvider">The service provider.</param>
+ /// <param name="temporaryCredentialStorage">The temporary credential storage.</param>
+ public Consumer(
+ string consumerKey,
+ string consumerSecret,
+ ServiceProviderDescription serviceProvider,
+ ITemporaryCredentialStorage temporaryCredentialStorage) {
+ this.ConsumerKey = consumerKey;
+ this.ConsumerSecret = consumerSecret;
+ this.ServiceProvider = serviceProvider;
+ this.TemporaryCredentialStorage = temporaryCredentialStorage;
+ }
+
+ /// <summary>
+ /// Gets or sets the object with factories for host-customizable services.
+ /// </summary>
+ public IHostFactories HostFactories {
+ get {
+ return this.hostFactories;
+ }
+
+ set {
+ Requires.NotNull(value, "value");
+ this.hostFactories = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets the Consumer Key used to communicate with the Service Provider.
+ /// </summary>
+ public string ConsumerKey { get; set; }
+
+ /// <summary>
+ /// Gets or sets the consumer secret.
+ /// </summary>
+ /// <value>
+ /// The consumer secret.
+ /// </value>
+ public string ConsumerSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the consumer certificate.
+ /// </summary>
+ /// <value>
+ /// The consumer certificate.
+ /// </value>
+ /// <remarks>
+ /// If set, this causes all outgoing messages to be signed with the certificate instead of the consumer secret.
+ /// </remarks>
+ public X509Certificate2 ConsumerCertificate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Service Provider that will be accessed.
+ /// </summary>
+ public ServiceProviderDescription ServiceProvider { get; set; }
+
+ /// <summary>
+ /// Gets the persistence store for tokens and secrets.
+ /// </summary>
+ public ITemporaryCredentialStorage TemporaryCredentialStorage { get; set; }
+
+ /// <summary>
+ /// Obtains an access token for a new account at the Service Provider via 2-legged OAuth.
+ /// </summary>
+ /// <param name="requestParameters">Any applicable parameters to include in the query string of the token request.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>The access token.</returns>
+ public async Task<AccessTokenResponse> RequestNewClientAccountAsync(IEnumerable<KeyValuePair<string, string>> requestParameters = null, CancellationToken cancellationToken = default(CancellationToken)) {
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+ Verify.Operation(this.ServiceProvider != null, Strings.RequiredPropertyNotYetPreset, "ServiceProvider");
+
+ using (var handler = this.CreateMessageHandler()) {
+ using (var client = this.CreateHttpClient(handler)) {
+ string identifier, secret;
+
+ var requestUri = new UriBuilder(this.ServiceProvider.TemporaryCredentialsRequestEndpoint);
+ requestUri.AppendQueryArgument(Protocol.CallbackParameter, "oob");
+ requestUri.AppendQueryArgs(requestParameters);
+ var request = new HttpRequestMessage(this.ServiceProvider.TemporaryCredentialsRequestEndpointMethod, requestUri.Uri);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ identifier = responseData[Protocol.TokenParameter];
+ secret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(identifier), MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(secret != null, MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+ }
+
+ // Immediately exchange the temporary credential for an access token.
+ handler.AccessToken = identifier;
+ handler.AccessTokenSecret = secret;
+ request = new HttpRequestMessage(this.ServiceProvider.TokenRequestEndpointMethod, this.ServiceProvider.TokenRequestEndpoint);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ string accessToken = responseData[Protocol.TokenParameter];
+ string tokenSecret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(accessToken), MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(tokenSecret != null, MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+
+ responseData.Remove(Protocol.TokenParameter);
+ responseData.Remove(Protocol.TokenSecretParameter);
+ return new AccessTokenResponse(accessToken, tokenSecret, responseData);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Prepares an OAuth message that begins an authorization request that will
+ /// redirect the user to the Service Provider to provide that authorization.
+ /// </summary>
+ /// <param name="callback">The absolute URI that the Service Provider should redirect the
+ /// User Agent to upon successful authorization, or <c>null</c> to signify an out of band return.</param>
+ /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The URL to direct the user agent to for user authorization.
+ /// </returns>
+ public async Task<Uri> RequestUserAuthorizationAsync(Uri callback = null, IEnumerable<KeyValuePair<string, string>> requestParameters = null, CancellationToken cancellationToken = default(CancellationToken)) {
+ Requires.NotNull(callback, "callback");
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+ Verify.Operation(this.TemporaryCredentialStorage != null, Strings.RequiredPropertyNotYetPreset, "TemporaryCredentialStorage");
+ Verify.Operation(this.ServiceProvider != null, Strings.RequiredPropertyNotYetPreset, "ServiceProvider");
+
+ // Obtain temporary credentials before the redirect.
+ using (var client = this.CreateHttpClient(new AccessToken())) {
+ var requestUri = new UriBuilder(this.ServiceProvider.TemporaryCredentialsRequestEndpoint);
+ requestUri.AppendQueryArgument(Protocol.CallbackParameter, callback != null ? callback.AbsoluteUri : "oob");
+ requestUri.AppendQueryArgs(requestParameters);
+ var request = new HttpRequestMessage(this.ServiceProvider.TemporaryCredentialsRequestEndpointMethod, requestUri.Uri);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ ErrorUtilities.VerifyProtocol(string.Equals(responseData[Protocol.CallbackConfirmedParameter], "true", StringComparison.Ordinal), MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.CallbackConfirmedParameter);
+ string identifier = responseData[Protocol.TokenParameter];
+ string secret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(identifier), MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(secret != null, MessagingStrings.RequiredParametersMissing, typeof(UnauthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+
+ // Save the temporary credential we received so that after user authorization
+ // we can use it to obtain the access token.
+ cancellationToken.ThrowIfCancellationRequested();
+ this.TemporaryCredentialStorage.SaveTemporaryCredential(identifier, secret);
+
+ // Construct the user authorization URL so our caller can direct a browser to it.
+ var authorizationEndpoint = new UriBuilder(this.ServiceProvider.ResourceOwnerAuthorizationEndpoint);
+ authorizationEndpoint.AppendQueryArgument(Protocol.TokenParameter, identifier);
+ return authorizationEndpoint.Uri;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Obtains an access token after a successful user authorization.
+ /// </summary>
+ /// <param name="authorizationCompleteUri">The URI used to redirect back to the consumer that contains a message from the service provider.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The access token assigned by the Service Provider, or <c>null</c> if no response was detected in the specified URL.
+ /// </returns>
+ public async Task<AccessTokenResponse> ProcessUserAuthorizationAsync(Uri authorizationCompleteUri, CancellationToken cancellationToken = default(CancellationToken)) {
+ Requires.NotNull(authorizationCompleteUri, "authorizationCompleteUri");
+ Verify.Operation(this.TemporaryCredentialStorage != null, Strings.RequiredPropertyNotYetPreset, "TemporaryCredentialStorage");
+
+ // Parse the response and verify that it meets spec requirements.
+ var queryString = HttpUtility.ParseQueryString(authorizationCompleteUri.Query);
+ string identifier = queryString[Protocol.TokenParameter];
+ string verifier = queryString[Protocol.VerifierParameter];
+
+ if (identifier == null) {
+ // We assume there is no response message here at all, and return null to indicate that.
+ return null;
+ }
+
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(identifier), MessagingStrings.RequiredNonEmptyParameterWasEmpty, typeof(UserAuthorizationResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(verifier), MessagingStrings.RequiredNonEmptyParameterWasEmpty, typeof(UserAuthorizationResponse).Name, Protocol.VerifierParameter);
+
+ var temporaryCredential = this.TemporaryCredentialStorage.RetrieveTemporaryCredential();
+ Verify.Operation(string.Equals(temporaryCredential.Key, identifier, StringComparison.Ordinal), "Temporary credential identifiers do not match.");
+
+ return await this.ProcessUserAuthorizationAsync(verifier, cancellationToken);
+ }
+
+ /// <summary>
+ /// Obtains an access token after a successful user authorization.
+ /// </summary>
+ /// <param name="verifier">The verifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>
+ /// The access token assigned by the Service Provider.
+ /// </returns>
+ public async Task<AccessTokenResponse> ProcessUserAuthorizationAsync(string verifier, CancellationToken cancellationToken = default(CancellationToken)) {
+ Requires.NotNull(verifier, "verifier");
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+ Verify.Operation(this.TemporaryCredentialStorage != null, Strings.RequiredPropertyNotYetPreset, "TemporaryCredentialStorage");
+ Verify.Operation(this.ServiceProvider != null, Strings.RequiredPropertyNotYetPreset, "ServiceProvider");
+
+ var temporaryCredential = this.TemporaryCredentialStorage.RetrieveTemporaryCredential();
+
+ using (var client = this.CreateHttpClient(new AccessToken(temporaryCredential.Key, temporaryCredential.Value))) {
+ var requestUri = new UriBuilder(this.ServiceProvider.TokenRequestEndpoint);
+ requestUri.AppendQueryArgument(Protocol.VerifierParameter, verifier);
+ var request = new HttpRequestMessage(this.ServiceProvider.TokenRequestEndpointMethod, requestUri.Uri);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
+
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ string accessToken = responseData[Protocol.TokenParameter];
+ string tokenSecret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(accessToken), MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(tokenSecret != null, MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
+
+ responseData.Remove(Protocol.TokenParameter);
+ responseData.Remove(Protocol.TokenSecretParameter);
+ return new AccessTokenResponse(accessToken, tokenSecret, responseData);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Creates a message handler that signs outbound requests with a previously obtained authorization.
+ /// </summary>
+ /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
+ /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
+ /// <returns>
+ /// A message handler.
+ /// </returns>
+ /// <remarks>
+ /// Overrides of this method may allow various derived types of handlers to be returned,
+ /// enabling consumers that use RSA or other signing methods.
+ /// </remarks>
+ public virtual OAuth1HttpMessageHandlerBase CreateMessageHandler(AccessToken accessToken = default(AccessToken), HttpMessageHandler innerHandler = null) {
+ Verify.Operation(this.ConsumerKey != null, Strings.RequiredPropertyNotYetPreset, "ConsumerKey");
+
+ innerHandler = innerHandler ?? this.HostFactories.CreateHttpMessageHandler();
+ OAuth1HttpMessageHandlerBase handler;
+ if (this.ConsumerCertificate != null) {
+ handler = new OAuth1RsaSha1HttpMessageHandler(innerHandler) {
+ SigningCertificate = this.ConsumerCertificate,
+ };
+ } else {
+ handler = new OAuth1HmacSha1HttpMessageHandler(innerHandler);
+ }
+
+ handler.ConsumerKey = this.ConsumerKey;
+ handler.ConsumerSecret = this.ConsumerSecret;
+ handler.AccessToken = accessToken.Token;
+ handler.AccessTokenSecret = accessToken.Secret;
+
+ return handler;
+ }
+
+ /// <summary>
+ /// Creates the HTTP client.
+ /// </summary>
+ /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
+ /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
+ /// <returns>The HttpClient to use.</returns>
+ public HttpClient CreateHttpClient(AccessToken accessToken, HttpMessageHandler innerHandler = null) {
+ var handler = this.CreateMessageHandler(accessToken, innerHandler);
+ var client = this.HostFactories.CreateHttpClient(handler);
+ return client;
+ }
+
+ /// <summary>
+ /// Creates the HTTP client.
+ /// </summary>
+ /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
+ /// <returns>The HttpClient to use.</returns>
+ public HttpClient CreateHttpClient(OAuth1HttpMessageHandlerBase innerHandler) {
+ Requires.NotNull(innerHandler, "innerHandler");
+
+ var client = this.HostFactories.CreateHttpClient(innerHandler);
+ return client;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
deleted file mode 100644
index 1bea2c5..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
+++ /dev/null
@@ -1,258 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="ConsumerBase.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Threading;
- using System.Threading.Tasks;
- using DotNetOpenAuth.Configuration;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.Messaging.Bindings;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
- using Validation;
-
- /// <summary>
- /// Base class for <see cref="WebConsumer"/> and <see cref="DesktopConsumer"/> types.
- /// </summary>
- public class ConsumerBase : IDisposable {
- /// <summary>
- /// Initializes a new instance of the <see cref="ConsumerBase"/> class.
- /// </summary>
- /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
- /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- protected ConsumerBase(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) {
- Requires.NotNull(serviceDescription, "serviceDescription");
- Requires.NotNull(tokenManager, "tokenManager");
-
- ITamperProtectionChannelBindingElement signingElement = serviceDescription.CreateTamperProtectionElement();
- INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge);
- this.SecuritySettings = OAuthElement.Configuration.Consumer.SecuritySettings.CreateSecuritySettings();
- this.OAuthChannel = new OAuthConsumerChannel(signingElement, store, tokenManager, this.SecuritySettings);
- this.ServiceProvider = serviceDescription;
-
- OAuthReporting.RecordFeatureAndDependencyUse(this, serviceDescription, tokenManager, null);
- }
-
- /// <summary>
- /// Gets the Consumer Key used to communicate with the Service Provider.
- /// </summary>
- public string ConsumerKey {
- get { return this.TokenManager.ConsumerKey; }
- }
-
- /// <summary>
- /// Gets the Service Provider that will be accessed.
- /// </summary>
- public ServiceProviderDescription ServiceProvider { get; private set; }
-
- /// <summary>
- /// Gets the persistence store for tokens and secrets.
- /// </summary>
- public IConsumerTokenManager TokenManager {
- get { return (IConsumerTokenManager)this.OAuthChannel.TokenManager; }
- }
-
- /// <summary>
- /// Gets the channel to use for sending/receiving messages.
- /// </summary>
- public Channel Channel {
- get { return this.OAuthChannel; }
- }
-
- /// <summary>
- /// Gets the security settings for this consumer.
- /// </summary>
- internal ConsumerSecuritySettings SecuritySettings { get; private set; }
-
- /// <summary>
- /// Gets or sets the channel to use for sending/receiving messages.
- /// </summary>
- internal OAuthChannel OAuthChannel { get; set; }
-
- /// <summary>
- /// Creates a message handler that signs outbound requests with a previously obtained authorization.
- /// </summary>
- /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
- /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
- /// <returns>
- /// A message handler.
- /// </returns>
- public OAuth1HttpMessageHandlerBase CreateMessageHandler(string accessToken = null, HttpMessageHandler innerHandler = null) {
- return new OAuth1HmacSha1HttpMessageHandler() {
- ConsumerKey = this.ConsumerKey,
- ConsumerSecret = this.TokenManager.ConsumerSecret,
- AccessToken = accessToken,
- AccessTokenSecret = accessToken != null ? this.TokenManager.GetTokenSecret(accessToken) : null,
- InnerHandler = innerHandler ?? this.Channel.HostFactories.CreateHttpMessageHandler(),
- };
- }
-
- /// <summary>
- /// Creates the HTTP client.
- /// </summary>
- /// <param name="accessToken">The access token to authorize outbound HTTP requests with.</param>
- /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
- /// <returns>The HttpClient to use.</returns>
- public HttpClient CreateHttpClient(string accessToken, HttpMessageHandler innerHandler = null) {
- Requires.NotNullOrEmpty(accessToken, "accessToken");
-
- var handler = this.CreateMessageHandler(accessToken, innerHandler);
- var client = this.Channel.HostFactories.CreateHttpClient(handler);
- return client;
- }
-
- /// <summary>
- /// Creates the HTTP client.
- /// </summary>
- /// <param name="innerHandler">The inner handler that actually sends the HTTP message on the network.</param>
- /// <returns>The HttpClient to use.</returns>
- public HttpClient CreateHttpClient(OAuth1HttpMessageHandlerBase innerHandler) {
- Requires.NotNull(innerHandler, "innerHandler");
-
- var client = this.Channel.HostFactories.CreateHttpClient(innerHandler);
- return client;
- }
-
- /// <summary>
- /// Obtains an access token for a new account at the Service Provider via 2-legged OAuth.
- /// </summary>
- /// <param name="requestParameters">Any applicable parameters to include in the query string of the token request.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The access token.</returns>
- /// <remarks>
- /// The token secret is stored in the <see cref="TokenManager"/>.
- /// </remarks>
- public async Task<string> RequestNewClientAccountAsync(IDictionary<string, string> requestParameters = null, CancellationToken cancellationToken = default(CancellationToken)) {
- // Obtain an unauthorized request token. Force use of OAuth 1.0 (not 1.0a) so that
- // we are not expected to provide an oauth_verifier which doesn't apply in 2-legged OAuth.
- var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint, Protocol.V10.Version) {
- ConsumerKey = this.ConsumerKey,
- };
- var tokenAccessor = this.Channel.MessageDescriptions.GetAccessor(token);
- tokenAccessor.AddExtraParameters(requestParameters);
- var requestTokenResponse = await this.Channel.RequestAsync<UnauthorizedTokenResponse>(token, cancellationToken);
- this.TokenManager.StoreNewRequestToken(token, requestTokenResponse);
-
- var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, Protocol.V10.Version) {
- RequestToken = requestTokenResponse.RequestToken,
- ConsumerKey = this.ConsumerKey,
- };
- var grantAccess = await this.Channel.RequestAsync<AuthorizedTokenResponse>(requestAccess, cancellationToken);
- this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestTokenResponse.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
- return grantAccess.AccessToken;
- }
-
- #region IDisposable Members
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose() {
- this.Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- #endregion
-
- /// <summary>
- /// Creates a web request prepared with OAuth authorization
- /// that may be further tailored by adding parameters by the caller.
- /// </summary>
- /// <param name="endpoint">The URL and method on the Service Provider to send the request to.</param>
- /// <param name="accessToken">The access token that permits access to the protected resource.</param>
- /// <returns>The initialized WebRequest object.</returns>
- protected internal AccessProtectedResourceRequest CreateAuthorizingMessage(MessageReceivingEndpoint endpoint, string accessToken) {
- Requires.NotNull(endpoint, "endpoint");
- Requires.NotNullOrEmpty(accessToken, "accessToken");
-
- AccessProtectedResourceRequest message = new AccessProtectedResourceRequest(endpoint, this.ServiceProvider.Version) {
- AccessToken = accessToken,
- ConsumerKey = this.ConsumerKey,
- };
-
- return message;
- }
-
- /// <summary>
- /// Prepares an OAuth message that begins an authorization request that will
- /// redirect the user to the Service Provider to provide that authorization.
- /// </summary>
- /// <param name="callback">An optional Consumer URL that the Service Provider should redirect the
- /// User Agent to upon successful authorization.</param>
- /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
- /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The pending user agent redirect based message to be sent as an HttpResponse.
- /// </returns>
- [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "3#", Justification = "Two results")]
- protected internal async Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) {
- // Obtain an unauthorized request token. Assume the OAuth version given in the service description.
- var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint, this.ServiceProvider.Version) {
- ConsumerKey = this.ConsumerKey,
- Callback = callback,
- };
- var tokenAccessor = this.Channel.MessageDescriptions.GetAccessor(token);
- tokenAccessor.AddExtraParameters(requestParameters);
- var requestTokenResponse = await this.Channel.RequestAsync<UnauthorizedTokenResponse>(token, cancellationToken);
- this.TokenManager.StoreNewRequestToken(token, requestTokenResponse);
-
- // Fine-tune our understanding of the SP's supported OAuth version if it's wrong.
- if (this.ServiceProvider.Version != requestTokenResponse.Version) {
- Logger.OAuth.WarnFormat("Expected OAuth service provider at endpoint {0} to use OAuth {1} but {2} was detected. Adjusting service description to new version.", this.ServiceProvider.RequestTokenEndpoint.Location, this.ServiceProvider.Version, requestTokenResponse.Version);
- this.ServiceProvider.ProtocolVersion = Protocol.Lookup(requestTokenResponse.Version).ProtocolVersion;
- }
-
- // Request user authorization. The OAuth version will automatically include
- // or drop the callback that we're setting here.
- ITokenContainingMessage assignedRequestToken = requestTokenResponse;
- var requestAuthorization = new UserAuthorizationRequest(this.ServiceProvider.UserAuthorizationEndpoint, assignedRequestToken.Token, requestTokenResponse.Version) {
- Callback = callback,
- };
- var requestAuthorizationAccessor = this.Channel.MessageDescriptions.GetAccessor(requestAuthorization);
- requestAuthorizationAccessor.AddExtraParameters(redirectParameters);
- return requestAuthorization;
- }
-
- /// <summary>
- /// Exchanges a given request token for access token.
- /// </summary>
- /// <param name="requestToken">The request token that the user has authorized.</param>
- /// <param name="verifier">The verifier code.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The access token assigned by the Service Provider.
- /// </returns>
- protected async Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(string requestToken, string verifier, CancellationToken cancellationToken = default(CancellationToken)) {
- Requires.NotNullOrEmpty(requestToken, "requestToken");
-
- var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, this.ServiceProvider.Version) {
- RequestToken = requestToken,
- VerificationCode = verifier,
- ConsumerKey = this.ConsumerKey,
- };
- var grantAccess = await this.Channel.RequestAsync<AuthorizedTokenResponse>(requestAccess, cancellationToken);
- this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
- return grantAccess;
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool disposing) {
- if (disposing) {
- this.Channel.Dispose();
- }
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs
new file mode 100644
index 0000000..25941e6
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs
@@ -0,0 +1,130 @@
+//-----------------------------------------------------------------------
+// <copyright file="CookieTemporaryCredentialStorage.cs" company="Microsoft">
+// Copyright (c) Microsoft. All rights reserved.
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+ using System.Web;
+ using System.Web.Security;
+ using Validation;
+
+ /// <summary>
+ /// Provides temporary credential storage by persisting them in a protected cookie on the
+ /// user agent (i.e. browser).
+ /// </summary>
+ public class CookieTemporaryCredentialStorage : ITemporaryCredentialStorage {
+ /// <summary>
+ /// Key used for token cookie
+ /// </summary>
+ protected const string TokenCookieKey = "DNOAOAuth1TempCredential";
+
+ /// <summary>
+ /// Primary request context.
+ /// </summary>
+ private readonly HttpContextBase httpContext;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CookieTemporaryCredentialsStorage"/> class
+ /// using <see cref="HttpContext.Current"/> as the source for the context to read and write cookies to.
+ /// </summary>
+ public CookieTemporaryCredentialStorage()
+ : this(new HttpContextWrapper(HttpContext.Current)) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CookieTemporaryCredentialsStorage"/> class.
+ /// </summary>
+ /// <param name="httpContext">The HTTP context from and to which to access cookies.</param>
+ public CookieTemporaryCredentialStorage(HttpContextBase httpContext) {
+ Requires.NotNull(httpContext, "httpContext");
+ this.httpContext = httpContext;
+ }
+
+ #region ITemporaryCredentialsStorage Members
+
+ /// <summary>
+ /// Saves the temporary credential.
+ /// </summary>
+ /// <param name="identifier">The identifier.</param>
+ /// <param name="secret">The secret.</param>
+ public void SaveTemporaryCredential(string identifier, string secret) {
+ var cookie = new HttpCookie(TokenCookieKey) {
+ HttpOnly = true
+ };
+
+ if (FormsAuthentication.RequireSSL) {
+ cookie.Secure = true;
+ }
+
+ var encryptedToken = ProtectAndEncodeToken(identifier, secret);
+ cookie.Values[identifier] = encryptedToken;
+
+ this.httpContext.Response.Cookies.Set(cookie);
+ }
+
+ /// <summary>
+ /// Obtains the temporary credential identifier and secret, if available.
+ /// </summary>
+ /// <returns>
+ /// An initialized key value pair if credentials are available; otherwise both key and value are <c>null</c>.
+ /// </returns>
+ /// <exception cref="System.NotImplementedException"></exception>
+ public KeyValuePair<string, string> RetrieveTemporaryCredential() {
+ HttpCookie cookie = this.httpContext.Request.Cookies[TokenCookieKey];
+ if (cookie == null || cookie.Values.Count == 0) {
+ return new KeyValuePair<string, string>();
+ }
+
+ string identifier = cookie.Values.GetKey(0);
+ string secret = DecodeAndUnprotectToken(identifier, cookie.Values[identifier]);
+ return new KeyValuePair<string, string>(identifier, secret);
+ }
+
+ /// <summary>
+ /// Clears the temporary credentials from storage.
+ /// </summary>
+ /// <remarks>
+ /// DotNetOpenAuth calls this when the credentials are no longer needed.
+ /// </remarks>
+ public void ClearTemporaryCredential() {
+ var cookie = new HttpCookie(TokenCookieKey) {
+ Value = string.Empty,
+ Expires = DateTime.UtcNow.AddDays(-5),
+ };
+ this.httpContext.Response.Cookies.Set(cookie);
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Protect and url-encode the specified token secret.
+ /// </summary>
+ /// <param name="token">The token to be used as a key.</param>
+ /// <param name="tokenSecret">The token secret to be protected</param>
+ /// <returns>The encrypted and protected string.</returns>
+ protected static string ProtectAndEncodeToken(string token, string tokenSecret) {
+ byte[] cookieBytes = Encoding.UTF8.GetBytes(tokenSecret);
+ var secretBytes = MachineKeyUtil.Protect(cookieBytes, TokenCookieKey, "Token:" + token);
+ return HttpServerUtility.UrlTokenEncode(secretBytes);
+ }
+
+ /// <summary>
+ /// Url-decode and unprotect the specified encrypted token string.
+ /// </summary>
+ /// <param name="token">The token to be used as a key.</param>
+ /// <param name="encryptedToken">The encrypted token to be decrypted</param>
+ /// <returns>The original token secret</returns>
+ protected static string DecodeAndUnprotectToken(string token, string encryptedToken) {
+ byte[] cookieBytes = HttpServerUtility.UrlTokenDecode(encryptedToken);
+ byte[] clearBytes = MachineKeyUtil.Unprotect(cookieBytes, TokenCookieKey, "Token:" + token);
+ return Encoding.UTF8.GetString(clearBytes);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs
deleted file mode 100644
index a1bfd2d..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/DesktopConsumer.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="DesktopConsumer.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Threading;
- using System.Threading.Tasks;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
-
- /// <summary>
- /// Used by a desktop application to use OAuth to access the Service Provider on behalf of the User.
- /// </summary>
- /// <remarks>
- /// The methods on this class are thread-safe. Provided the properties are set and not changed
- /// afterward, a single instance of this class may be used by an entire desktop application safely.
- /// </remarks>
- public class DesktopConsumer : ConsumerBase {
- /// <summary>
- /// Initializes a new instance of the <see cref="DesktopConsumer"/> class.
- /// </summary>
- /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
- /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public DesktopConsumer(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager)
- : base(serviceDescription, tokenManager) {
- }
-
- /// <summary>
- /// Begins an OAuth authorization request.
- /// </summary>
- /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
- /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The URL to open a browser window to allow the user to provide authorization and the request token.
- /// </returns>
- [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Two results")]
- public async Task<Tuple<Uri, string>> RequestUserAuthorizationAsync(IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) {
- var message = await this.PrepareRequestUserAuthorizationAsync(null, requestParameters, redirectParameters, cancellationToken);
- var response = await this.Channel.PrepareResponseAsync(message, cancellationToken);
- return Tuple.Create(response.GetDirectUriRequest(), message.RequestToken);
- }
-
- /// <summary>
- /// Exchanges a given request token for access token.
- /// </summary>
- /// <param name="requestToken">The request token that the user has authorized.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The access token assigned by the Service Provider.</returns>
- [Obsolete("Use the ProcessUserAuthorization method that takes a verifier parameter instead.")]
- public Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(string requestToken, CancellationToken cancellationToken = default(CancellationToken)) {
- return this.ProcessUserAuthorizationAsync(requestToken, null, cancellationToken);
- }
-
- /// <summary>
- /// Exchanges a given request token for access token.
- /// </summary>
- /// <param name="requestToken">The request token that the user has authorized.</param>
- /// <param name="verifier">The verifier code typed in by the user. Must not be <c>Null</c> for OAuth 1.0a service providers and later.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The access token assigned by the Service Provider.
- /// </returns>
- public new Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(string requestToken, string verifier, CancellationToken cancellationToken = default(CancellationToken)) {
- if (this.ServiceProvider.Version >= Protocol.V10a.Version) {
- ErrorUtilities.VerifyNonZeroLength(verifier, "verifier");
- }
-
- return base.ProcessUserAuthorizationAsync(requestToken, verifier, cancellationToken);
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs
new file mode 100644
index 0000000..428749a
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ITemporaryCredentialStorage.cs
@@ -0,0 +1,40 @@
+//-----------------------------------------------------------------------
+// <copyright file="ITemporaryCredentialStorage.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// A token manager for use by an OAuth Consumer to store a temporary credential
+ /// (previously known as "unauthorized request token and secret").
+ /// </summary>
+ /// <remarks>
+ /// The credentials stored here are obtained as described in:
+ /// http://tools.ietf.org/html/rfc5849#section-2.1
+ /// </remarks>
+ public interface ITemporaryCredentialStorage {
+ /// <summary>
+ /// Saves the specified temporary credential for later retrieval.
+ /// </summary>
+ /// <param name="identifier">The identifier.</param>
+ /// <param name="secret">The secret.</param>
+ void SaveTemporaryCredential(string identifier, string secret);
+
+ /// <summary>
+ /// Obtains a temporary credential secret, if available.
+ /// </summary>
+ /// <returns>The temporary credential identifier secret if available; otherwise a key value pair whose strings are left in their uninitialized <c>null</c> state.</returns>
+ KeyValuePair<string, string> RetrieveTemporaryCredential();
+
+ /// <summary>
+ /// Clears the temporary credentials from storage.
+ /// </summary>
+ /// <remarks>
+ /// DotNetOpenAuth calls this when the credentials are no longer needed.
+ /// </remarks>
+ void ClearTemporaryCredential();
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs
new file mode 100644
index 0000000..832084d
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/MemoryTemporaryCredentialStorage.cs
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------
+// <copyright file="MemoryTemporaryCredentialStorage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ /// <summary>
+ /// Non-persistent memory storage for temporary credentials.
+ /// Useful for installed apps (not redirection based web apps).
+ /// </summary>
+ public class MemoryTemporaryCredentialStorage : ITemporaryCredentialStorage {
+ /// <summary>
+ /// The identifier.
+ /// </summary>
+ private string identifier;
+
+ /// <summary>
+ /// The secret.
+ /// </summary>
+ private string secret;
+
+ #region ITemporaryCredentialStorage Members
+
+ /// <summary>
+ /// Saves the specified temporary credential for later retrieval.
+ /// </summary>
+ /// <param name="identifier">The identifier.</param>
+ /// <param name="secret">The secret.</param>
+ public void SaveTemporaryCredential(string identifier, string secret) {
+ this.identifier = identifier;
+ this.secret = secret;
+ }
+
+ /// <summary>
+ /// Obtains a temporary credential secret, if available.
+ /// </summary>
+ /// <returns>
+ /// The temporary credential secret if available; otherwise <c>null</c>.
+ /// </returns>
+ public KeyValuePair<string, string> RetrieveTemporaryCredential() {
+ return new KeyValuePair<string, string>(this.identifier, this.secret);
+ }
+
+ /// <summary>
+ /// Clears the temporary credentials from storage.
+ /// </summary>
+ /// <param name="identifier">The identifier of the credentials to clear.</param>
+ /// <remarks>
+ /// DotNetOpenAuth calls this when the credentials are no longer needed.
+ /// </remarks>
+ public void ClearTemporaryCredential() {
+ this.identifier = null;
+ this.secret = null;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs
index 17d7b7a..aa462f3 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs
@@ -154,6 +154,10 @@ namespace DotNetOpenAuth.OAuth {
// Add parameters and signature to request.
switch (this.Location) {
case OAuthParametersLocation.AuthorizationHttpHeader:
+ // Some oauth parameters may have been put in the query string of the original message.
+ // We want to move any that we find into the authorization header.
+ oauthParameters.Add(ExtractOAuthParametersFromQueryString(request));
+
request.Headers.Authorization = new AuthenticationHeaderValue(Protocol.AuthorizationHeaderScheme, MessagingUtilities.AssembleAuthorizationHeader(oauthParameters.AsKeyValuePairs()));
break;
case OAuthParametersLocation.QueryString:
@@ -258,6 +262,38 @@ namespace DotNetOpenAuth.OAuth {
}
/// <summary>
+ /// Collects and removes all query string parameters beginning with "oauth_" from the specified request,
+ /// and returns them as a collection.
+ /// </summary>
+ /// <param name="request">The request whose query string should be searched for "oauth_" parameters.</param>
+ /// <returns>The collection of parameters that were removed from the query string.</returns>
+ private static NameValueCollection ExtractOAuthParametersFromQueryString(HttpRequestMessage request) {
+ Requires.NotNull(request, "request");
+
+ var extracted = new NameValueCollection();
+ if (!string.IsNullOrEmpty(request.RequestUri.Query)) {
+ var queryString = HttpUtility.ParseQueryString(request.RequestUri.Query);
+ foreach (var pair in queryString.AsKeyValuePairs()) {
+ if (pair.Key.StartsWith(Protocol.ParameterPrefix, StringComparison.Ordinal)) {
+ extracted.Add(pair.Key, pair.Value);
+ }
+ }
+
+ if (extracted.Count > 0) {
+ foreach (string key in extracted) {
+ queryString.Remove(key);
+ }
+
+ var modifiedRequestUri = new UriBuilder(request.RequestUri);
+ modifiedRequestUri.Query = MessagingUtilities.CreateQueryString(queryString.AsKeyValuePairs());
+ request.RequestUri = modifiedRequestUri.Uri;
+ }
+ }
+
+ return extracted;
+ }
+
+ /// <summary>
/// Constructs the "Signature Base String" as described in http://tools.ietf.org/html/rfc5849#section-3.4.1
/// </summary>
/// <param name="request">The HTTP request message.</param>
@@ -319,12 +355,6 @@ namespace DotNetOpenAuth.OAuth {
if (request.RequestUri.Query != null) {
// NameValueCollection does support non-unique keys, as long as you use it carefully.
nvc = HttpUtility.ParseQueryString(request.RequestUri.Query);
-
- // Remove any parameters beginning with "oauth_"
- var keysToRemove = nvc.Cast<string>().Where(k => k.StartsWith(Protocol.ParameterPrefix, StringComparison.Ordinal)).ToList();
- foreach (string key in keysToRemove) {
- nvc.Remove(key);
- }
} else {
nvc = new NameValueCollection(8);
}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs
index fd2ad65..129ebc2 100644
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OAuth {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
@@ -20,6 +21,20 @@ namespace DotNetOpenAuth.OAuth {
/// </summary>
public class OAuth1RsaSha1HttpMessageHandler : OAuth1HttpMessageHandlerBase {
/// <summary>
+ /// Initializes a new instance of the <see cref="OAuth1RsaSha1HttpMessageHandler"/> class.
+ /// </summary>
+ public OAuth1RsaSha1HttpMessageHandler() {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuth1RsaSha1HttpMessageHandler"/> class.
+ /// </summary>
+ /// <param name="innerHandler">The inner handler which is responsible for processing the HTTP response messages.</param>
+ public OAuth1RsaSha1HttpMessageHandler(HttpMessageHandler innerHandler)
+ : base(innerHandler) {
+ }
+
+ /// <summary>
/// Gets or sets the certificate used to sign outgoing messages. Used only by Consumers.
/// </summary>
public X509Certificate2 SigningCertificate { get; set; }
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ServiceProviderDescription.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ServiceProviderDescription.cs
new file mode 100644
index 0000000..2d07af4
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ServiceProviderDescription.cs
@@ -0,0 +1,85 @@
+//-----------------------------------------------------------------------
+// <copyright file="ServiceProviderDescription.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net.Http;
+ using System.Text;
+ using System.Threading.Tasks;
+ using Validation;
+
+ /// <summary>
+ /// Describes an OAuth 1.0 service provider.
+ /// </summary>
+ public class ServiceProviderDescription {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServiceProviderDescription" /> class.
+ /// </summary>
+ public ServiceProviderDescription() {
+ this.TemporaryCredentialsRequestEndpointMethod = HttpMethod.Post;
+ this.TokenRequestEndpointMethod = HttpMethod.Post;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServiceProviderDescription"/> class.
+ /// </summary>
+ /// <param name="temporaryCredentialsRequestEndpoint">The temporary credentials request endpoint.</param>
+ /// <param name="resourceOwnerAuthorizationEndpoint">The resource owner authorization endpoint.</param>
+ /// <param name="tokenRequestEndpoint">The token request endpoint.</param>
+ public ServiceProviderDescription(
+ string temporaryCredentialsRequestEndpoint, string resourceOwnerAuthorizationEndpoint, string tokenRequestEndpoint)
+ : this() {
+ if (temporaryCredentialsRequestEndpoint != null) {
+ this.TemporaryCredentialsRequestEndpoint = new Uri(temporaryCredentialsRequestEndpoint, UriKind.Absolute);
+ }
+
+ if (resourceOwnerAuthorizationEndpoint != null) {
+ this.ResourceOwnerAuthorizationEndpoint = new Uri(resourceOwnerAuthorizationEndpoint, UriKind.Absolute);
+ }
+
+ if (tokenRequestEndpoint != null) {
+ this.TokenRequestEndpoint = new Uri(tokenRequestEndpoint, UriKind.Absolute);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the temporary credentials request endpoint.
+ /// </summary>
+ /// <value>
+ /// The temporary credentials request endpoint.
+ /// </value>
+ public Uri TemporaryCredentialsRequestEndpoint { get; set; }
+
+ /// <summary>
+ /// Gets or sets the HTTP method to use with the temporary credentials request endpoint.
+ /// </summary>
+ public HttpMethod TemporaryCredentialsRequestEndpointMethod { get; set; }
+
+ /// <summary>
+ /// Gets the resource owner authorization endpoint.
+ /// </summary>
+ /// <value>
+ /// The resource owner authorization endpoint.
+ /// May be <c>null</c> for 2-legged OAuth.
+ /// </value>
+ public Uri ResourceOwnerAuthorizationEndpoint { get; set; }
+
+ /// <summary>
+ /// Gets the token request endpoint.
+ /// </summary>
+ /// <value>
+ /// The token request endpoint.
+ /// </value>
+ public Uri TokenRequestEndpoint { get; set; }
+
+ /// <summary>
+ /// Gets or sets the HTTP method to use with the token request endpoint.
+ /// </summary>
+ public HttpMethod TokenRequestEndpointMethod { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs
deleted file mode 100644
index 49a54a0..0000000
--- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="WebConsumer.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth {
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Web;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OAuth.ChannelElements;
- using DotNetOpenAuth.OAuth.Messages;
- using Validation;
-
- /// <summary>
- /// A website or application that uses OAuth to access the Service Provider on behalf of the User.
- /// </summary>
- /// <remarks>
- /// The methods on this class are thread-safe. Provided the properties are set and not changed
- /// afterward, a single instance of this class may be used by an entire web application safely.
- /// </remarks>
- public class WebConsumer : ConsumerBase {
- /// <summary>
- /// Initializes a new instance of the <see cref="WebConsumer"/> class.
- /// </summary>
- /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
- /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public WebConsumer(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager)
- : base(serviceDescription, tokenManager) {
- }
-
- /// <summary>
- /// Begins an OAuth authorization request and redirects the user to the Service Provider
- /// to provide that authorization. Upon successful authorization, the user is redirected
- /// back to the current page.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
- /// <remarks>
- /// Requires HttpContext.Current.
- /// </remarks>
- public Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(CancellationToken cancellationToken = default(CancellationToken)) {
- Uri callback = this.Channel.GetRequestFromContext().GetPublicFacingUrl().StripQueryArgumentsWithPrefix(Protocol.ParameterPrefix);
- return this.PrepareRequestUserAuthorizationAsync(callback, null, null, cancellationToken);
- }
-
- /// <summary>
- /// Prepares an OAuth message that begins an authorization request that will
- /// redirect the user to the Service Provider to provide that authorization.
- /// </summary>
- /// <param name="callback">
- /// An optional Consumer URL that the Service Provider should redirect the
- /// User Agent to upon successful authorization.
- /// </param>
- /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param>
- /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns>
- public new Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) {
- return base.PrepareRequestUserAuthorizationAsync(callback, requestParameters, redirectParameters, cancellationToken);
- }
-
- /// <summary>
- /// Processes an incoming authorization-granted message from an SP and obtains an access token.
- /// </summary>
- /// <param name="request">The incoming HTTP request.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>
- /// The access token, or null if no incoming authorization message was recognized.
- /// </returns>
- public async Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(HttpRequestBase request = null, CancellationToken cancellationToken = default(CancellationToken)) {
- request = request ?? this.Channel.GetRequestFromContext();
-
- var authorizationMessage = await this.Channel.TryReadFromRequestAsync<UserAuthorizationResponse>(cancellationToken, request);
- if (authorizationMessage != null) {
- string requestToken = authorizationMessage.RequestToken;
- string verifier = authorizationMessage.VerificationCode;
- return await this.ProcessUserAuthorizationAsync(requestToken, verifier, cancellationToken);
- } else {
- return null;
- }
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj
index 815a341..8e87ad4 100644
--- a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj
+++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj
@@ -19,18 +19,19 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
+ <Compile Include="OAuthReporting.cs" />
<Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" />
<Compile Include="OAuth\ChannelElements\IServiceProviderAccessToken.cs" />
<Compile Include="OAuth\ChannelElements\IServiceProviderRequestToken.cs" />
<Compile Include="OAuth\ChannelElements\IServiceProviderTokenManager.cs" />
<Compile Include="OAuth\ChannelElements\ITokenGenerator.cs" />
- <Compile Include="OAuth\ChannelElements\OAuth1Principal.cs" />
<Compile Include="OAuth\ChannelElements\OAuthServiceProviderChannel.cs" />
<Compile Include="OAuth\ChannelElements\OAuthServiceProviderMessageFactory.cs" />
<Compile Include="OAuth\ChannelElements\RsaSha1ServiceProviderSigningBindingElement.cs" />
<Compile Include="OAuth\ChannelElements\StandardTokenGenerator.cs" />
<Compile Include="OAuth\ChannelElements\TokenHandlingBindingElement.cs" />
<Compile Include="OAuth\ServiceProvider.cs" />
+ <Compile Include="OAuth\ServiceProviderHostDescription.cs" />
<Compile Include="OAuth\VerificationCodeFormat.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>
diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuth1Principal.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuth1Principal.cs
deleted file mode 100644
index ff44a45..0000000
--- a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ChannelElements/OAuth1Principal.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OAuth1Principal.cs" company="Outercurve Foundation">
-// Copyright (c) Outercurve Foundation. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOpenAuth.OAuth.ChannelElements {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.Text;
- using Validation;
-
- /// <summary>
- /// Represents an OAuth consumer that is impersonating a known user on the system.
- /// </summary>
- [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "Not cocreatable.")]
- [Serializable]
- [ComVisible(true)]
- internal class OAuth1Principal : OAuthPrincipal {
- /// <summary>
- /// Initializes a new instance of the <see cref="OAuth1Principal"/> class.
- /// </summary>
- /// <param name="token">The access token.</param>
- internal OAuth1Principal(IServiceProviderAccessToken token)
- : base(token.Username, token.Roles) {
- Requires.NotNull(token, "token");
-
- this.AccessToken = token.Token;
- }
- }
-}
diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs
index de7ff7c..5e6cfb3 100644
--- a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs
+++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs
@@ -55,7 +55,7 @@ namespace DotNetOpenAuth.OAuth {
/// </summary>
/// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param>
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager)
+ public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager)
: this(serviceDescription, tokenManager, new OAuthServiceProviderMessageFactory(tokenManager)) {
}
@@ -65,7 +65,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param>
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
/// <param name="messageTypeProvider">An object that can figure out what type of message is being received for deserialization.</param>
- public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider)
+ public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider)
: this(serviceDescription, tokenManager, OAuthElement.Configuration.ServiceProvider.ApplicationStore.CreateInstance(GetHttpApplicationStore(), null), messageTypeProvider) {
Requires.NotNull(serviceDescription, "serviceDescription");
Requires.NotNull(tokenManager, "tokenManager");
@@ -78,7 +78,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param>
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
/// <param name="nonceStore">The nonce store.</param>
- public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore)
+ public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore)
: this(serviceDescription, tokenManager, nonceStore, new OAuthServiceProviderMessageFactory(tokenManager)) {
}
@@ -89,7 +89,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
/// <param name="nonceStore">The nonce store.</param>
/// <param name="messageTypeProvider">An object that can figure out what type of message is being received for deserialization.</param>
- public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider) {
+ public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider) {
Requires.NotNull(serviceDescription, "serviceDescription");
Requires.NotNull(tokenManager, "tokenManager");
Requires.NotNull(nonceStore, "nonceStore");
@@ -107,7 +107,7 @@ namespace DotNetOpenAuth.OAuth {
/// <summary>
/// Gets the description of this Service Provider.
/// </summary>
- public ServiceProviderDescription ServiceDescription { get; private set; }
+ public ServiceProviderHostDescription ServiceDescription { get; private set; }
/// <summary>
/// Gets or sets the generator responsible for generating new tokens and secrets.
@@ -412,11 +412,11 @@ namespace DotNetOpenAuth.OAuth {
/// </summary>
/// <param name="request">The request.</param>
/// <returns>The <see cref="IPrincipal"/> instance that can be used for access control of resources.</returns>
- public OAuthPrincipal CreatePrincipal(AccessProtectedResourceRequest request) {
+ public IPrincipal CreatePrincipal(AccessProtectedResourceRequest request) {
Requires.NotNull(request, "request");
IServiceProviderAccessToken accessToken = this.TokenManager.GetAccessToken(request.AccessToken);
- return new OAuth1Principal(accessToken);
+ return OAuthPrincipal.CreatePrincipal(accessToken.Username, accessToken.Roles);
}
#region IDisposable Members
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProviderHostDescription.cs
index 6dbe6ea..33834eb 100644
--- a/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs
+++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProviderHostDescription.cs
@@ -1,5 +1,5 @@
//-----------------------------------------------------------------------
-// <copyright file="ServiceProviderDescription.cs" company="Outercurve Foundation">
+// <copyright file="ServiceProviderHostDescription.cs" company="Outercurve Foundation">
// Copyright (c) Outercurve Foundation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
@@ -15,7 +15,7 @@ namespace DotNetOpenAuth.OAuth {
/// <summary>
/// A description of the endpoints on a Service Provider.
/// </summary>
- public class ServiceProviderDescription {
+ public class ServiceProviderHostDescription {
/// <summary>
/// The field used to store the value of the <see cref="RequestTokenEndpoint"/> property.
/// </summary>
@@ -23,9 +23,9 @@ namespace DotNetOpenAuth.OAuth {
private MessageReceivingEndpoint requestTokenEndpoint;
/// <summary>
- /// Initializes a new instance of the <see cref="ServiceProviderDescription"/> class.
+ /// Initializes a new instance of the <see cref="ServiceProviderHostDescription"/> class.
/// </summary>
- public ServiceProviderDescription() {
+ public ServiceProviderHostDescription() {
this.ProtocolVersion = Protocol.Default.ProtocolVersion;
}
diff --git a/src/DotNetOpenAuth.OAuth/OAuthReporting.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs
index e2c0aab..8171e1a 100644
--- a/src/DotNetOpenAuth.OAuth/OAuthReporting.cs
+++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs
@@ -25,7 +25,7 @@ namespace DotNetOpenAuth {
/// <param name="service">The service.</param>
/// <param name="tokenManager">The token manager.</param>
/// <param name="nonceStore">The nonce store.</param>
- internal static void RecordFeatureAndDependencyUse(object value, ServiceProviderDescription service, ITokenManager tokenManager, INonceStore nonceStore) {
+ internal static void RecordFeatureAndDependencyUse(object value, ServiceProviderHostDescription service, ITokenManager tokenManager, INonceStore nonceStore) {
Requires.NotNull(value, "value");
Requires.NotNull(service, "service");
Requires.NotNull(tokenManager, "tokenManager");
@@ -45,9 +45,7 @@ namespace DotNetOpenAuth {
builder.Append(nonceStore.GetType().Name);
}
builder.Append(" ");
- builder.Append(service.Version);
- builder.Append(" ");
- builder.Append(service.UserAuthorizationEndpoint);
+ builder.Append(service.UserAuthorizationEndpoint.Location);
Reporting.ObservedFeatures.Add(builder.ToString());
Reporting.Touch();
}
diff --git a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj
index 58e09b0..af9aea9 100644
--- a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj
+++ b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj
@@ -25,7 +25,6 @@
<Compile Include="Configuration\OAuthServiceProviderElement.cs" />
<Compile Include="Configuration\OAuthServiceProviderSecuritySettingsElement.cs" />
<Compile Include="Messaging\ITamperProtectionChannelBindingElement.cs" />
- <Compile Include="OAuthReporting.cs" />
<Compile Include="OAuth\ChannelElements\ITokenManager.cs" />
<Compile Include="OAuth\ChannelElements\OAuthHttpMethodBindingElement.cs" />
<Compile Include="OAuth\ChannelElements\PlaintextSigningBindingElement.cs" />
@@ -35,13 +34,13 @@
<Compile Include="OAuth\ChannelElements\UriOrOobEncoding.cs" />
<Compile Include="OAuth\ConsumerSecuritySettings.cs" />
<Compile Include="OAuth\Messages\ITokenSecretContainingMessage.cs" />
+ <Compile Include="OAuth\Messages\MessageBaseSimple.cs" />
<Compile Include="OAuth\OAuthStrings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>OAuthStrings.resx</DependentUpon>
</Compile>
<Compile Include="OAuth\SecuritySettings.cs" />
- <Compile Include="OAuth\ServiceProviderDescription.cs" />
<Compile Include="OAuth\Messages\ITokenContainingMessage.cs" />
<Compile Include="OAuth\Messages\SignedMessageBase.cs" />
<Compile Include="OAuth\ChannelElements\SigningBindingElementBase.cs" />
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs
new file mode 100644
index 0000000..23822d3
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBaseSimple.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DotNetOpenAuth.OAuth.Messages {
+ class MessageBaseSimple {
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs b/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs
index 72f0ff4..049fd58 100644
--- a/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs
+++ b/src/DotNetOpenAuth.OAuth/OAuth/Protocol.cs
@@ -60,6 +60,31 @@ namespace DotNetOpenAuth.OAuth {
internal const string AuthorizationHeaderScheme = "OAuth";
/// <summary>
+ /// The name of the 'oauth_callback' parameter.
+ /// </summary>
+ internal const string CallbackParameter = "oauth_callback";
+
+ /// <summary>
+ /// The name of the 'oauth_callback_confirmed' parameter.
+ /// </summary>
+ internal const string CallbackConfirmedParameter = "oauth_callback_confirmed";
+
+ /// <summary>
+ /// The name of the 'oauth_token' parameter.
+ /// </summary>
+ internal const string TokenParameter = "oauth_token";
+
+ /// <summary>
+ /// The name of the 'oauth_token_secret' parameter.
+ /// </summary>
+ internal const string TokenSecretParameter = "oauth_token_secret";
+
+ /// <summary>
+ /// The name of the 'oauth_verifier' parameter.
+ /// </summary>
+ internal const string VerifierParameter = "oauth_verifier";
+
+ /// <summary>
/// Gets the <see cref="Protocol"/> instance with values initialized for V1.0 of the protocol.
/// </summary>
internal static readonly Protocol V10 = new Protocol {
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ClientDescription.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ClientDescription.cs
index a10e1aa..6d77f14 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ClientDescription.cs
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ClientDescription.cs
@@ -22,15 +22,36 @@ namespace DotNetOpenAuth.OAuth2 {
private readonly string secret;
/// <summary>
- /// Initializes a new instance of the <see cref="ClientDescription"/> class.
+ /// Initializes a new instance of the <see cref="ClientDescription"/> class
+ /// to represent a confidential client (one that has an authenticating secret.)
/// </summary>
/// <param name="secret">The secret.</param>
/// <param name="defaultCallback">The default callback.</param>
- /// <param name="clientType">Type of the client.</param>
- public ClientDescription(string secret, Uri defaultCallback, ClientType clientType) {
+ public ClientDescription(string secret, Uri defaultCallback) {
+ Requires.NotNullOrEmpty(secret, "secret");
+ Requires.NotNull(defaultCallback, "defaultCallback");
+
this.secret = secret;
this.DefaultCallback = defaultCallback;
- this.ClientType = clientType;
+ this.ClientType = ClientType.Confidential;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ClientDescription"/> class
+ /// to represent a public client (one that does not have an authenticating secret.)
+ /// </summary>
+ /// <param name="defaultCallback">The default callback.</param>
+ public ClientDescription(Uri defaultCallback) {
+ Requires.NotNull(defaultCallback, "defaultCallback");
+
+ this.DefaultCallback = defaultCallback;
+ this.ClientType = ClientType.Public;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ClientDescription"/> class.
+ /// </summary>
+ protected ClientDescription() {
}
#region IClientDescription Members
@@ -42,12 +63,12 @@ namespace DotNetOpenAuth.OAuth2 {
/// <value>
/// An absolute URL; or <c>null</c> if none is registered.
/// </value>
- public Uri DefaultCallback { get; private set; }
+ public Uri DefaultCallback { get; protected set; }
/// <summary>
/// Gets the type of the client.
/// </summary>
- public ClientType ClientType { get; private set; }
+ public ClientType ClientType { get; protected set; }
/// <summary>
/// Gets a value indicating whether a non-empty secret is registered for this client.
diff --git a/src/DotNetOpenAuth.OAuth2.Client.UI/OAuth2/ClientAuthorizationView.cs b/src/DotNetOpenAuth.OAuth2.Client.UI/OAuth2/ClientAuthorizationView.cs
index 002202e..8f1c5f6 100644
--- a/src/DotNetOpenAuth.OAuth2.Client.UI/OAuth2/ClientAuthorizationView.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client.UI/OAuth2/ClientAuthorizationView.cs
@@ -95,6 +95,14 @@ namespace DotNetOpenAuth.OAuth2 {
}
/// <summary>
+ /// Gets or sets a value indicating whether the implicit grant type should be used instead of the authorization code grant.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if [request implicit grant]; otherwise, <c>false</c>.
+ /// </value>
+ public bool RequestImplicitGrant { get; set; }
+
+ /// <summary>
/// Called when the authorization flow has been completed.
/// </summary>
protected virtual void OnCompleted() {
@@ -113,7 +121,7 @@ namespace DotNetOpenAuth.OAuth2 {
protected override async void OnLoad(EventArgs e) {
base.OnLoad(e);
- Uri authorizationUrl = await this.Client.RequestUserAuthorizationAsync(this.Authorization);
+ Uri authorizationUrl = await this.Client.RequestUserAuthorizationAsync(this.Authorization, implicitResponseType: this.RequestImplicitGrant);
this.webBrowser1.Navigate(authorizationUrl.AbsoluteUri); // use AbsoluteUri to workaround bug in WebBrowser that calls Uri.ToString instead of Uri.AbsoluteUri leading to escaping errors.
}
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs
index 9ebca32..92f882f 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/BearerTokenHttpMessageHandler.cs
@@ -75,7 +75,7 @@ namespace DotNetOpenAuth.OAuth2 {
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
string bearerToken = this.BearerToken;
if (bearerToken == null) {
- ErrorUtilities.VerifyProtocol(!this.Authorization.AccessTokenExpirationUtc.HasValue || this.Authorization.AccessTokenExpirationUtc < DateTime.UtcNow || this.Authorization.RefreshToken != null, ClientStrings.AuthorizationExpired);
+ ErrorUtilities.VerifyProtocol(!this.Authorization.AccessTokenExpirationUtc.HasValue || this.Authorization.AccessTokenExpirationUtc >= DateTime.UtcNow || this.Authorization.RefreshToken != null, ClientStrings.AuthorizationExpired);
if (this.Authorization.AccessTokenExpirationUtc.HasValue && this.Authorization.AccessTokenExpirationUtc.Value < DateTime.UtcNow) {
ErrorUtilities.VerifyProtocol(this.Authorization.RefreshToken != null, ClientStrings.AccessTokenRefreshFailed);
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
index 62dc311..65f3e1d 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
@@ -121,7 +121,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
// Typically the fragment is not available because the browser doesn't send it to a web server
// but this request may have been fabricated by an installed desktop app, in which case
// the fragment is available.
- string fragment = request.GetPublicFacingUrl().Fragment;
+ string fragment = request.Url.Fragment;
if (!string.IsNullOrEmpty(fragment)) {
foreach (var pair in HttpUtility.ParseQueryString(fragment.Substring(1)).ToDictionary()) {
fields.Add(pair.Key, pair.Value);
diff --git a/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/ResourceServer.cs b/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/ResourceServer.cs
index 7bc7c91..88ce451 100644
--- a/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/ResourceServer.cs
+++ b/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/ResourceServer.cs
@@ -11,6 +11,7 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Linq;
using System.Net;
using System.Net.Http;
+ using System.Security.Claims;
using System.Security.Principal;
using System.ServiceModel.Channels;
using System.Text;
@@ -167,10 +168,8 @@ namespace DotNetOpenAuth.OAuth2 {
string principalUserName = !string.IsNullOrEmpty(accessToken.User)
? this.ResourceOwnerPrincipalPrefix + accessToken.User
: this.ClientPrincipalPrefix + accessToken.ClientIdentifier;
- string[] principalScope = accessToken.Scope != null ? accessToken.Scope.ToArray() : new string[0];
- var principal = new OAuthPrincipal(principalUserName, principalScope);
- return principal;
+ return OAuthPrincipal.CreatePrincipal(principalUserName, accessToken.Scope);
}
/// <summary>
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs
index f827857..1c0c5fb 100644
--- a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs
+++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs
@@ -41,7 +41,7 @@ namespace DotNetOpenAuth.OAuth {
/// </summary>
/// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param>
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager)
+ public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager)
: base(serviceDescription, tokenManager) {
}
@@ -51,7 +51,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="serviceDescription">The service description.</param>
/// <param name="tokenManager">The token manager.</param>
/// <param name="messageTypeProvider">The message type provider.</param>
- public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider)
+ public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider)
: base(serviceDescription, tokenManager, messageTypeProvider) {
}
@@ -61,7 +61,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="serviceDescription">The service description.</param>
/// <param name="tokenManager">The token manager.</param>
/// <param name="nonceStore">The nonce store.</param>
- public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore)
+ public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore)
: base(serviceDescription, tokenManager, nonceStore) {
}
@@ -72,7 +72,7 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="tokenManager">The token manager.</param>
/// <param name="nonceStore">The nonce store.</param>
/// <param name="messageTypeProvider">The message type provider.</param>
- public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider)
+ public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider)
: base(serviceDescription, tokenManager, nonceStore, messageTypeProvider) {
}
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
index a19d505..dce51c2 100644
--- a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
+++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
@@ -8,9 +8,11 @@ namespace DotNetOpenAuth.OAuth {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+ using System.Web;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
@@ -26,14 +28,13 @@ namespace DotNetOpenAuth.OAuth {
/// The methods on this class are thread-safe. Provided the properties are set and not changed
/// afterward, a single instance of this class may be used by an entire web application safely.
/// </remarks>
- public class WebConsumerOpenIdRelyingParty : WebConsumer {
+ public class WebConsumerOpenIdRelyingParty : Consumer {
/// <summary>
/// Initializes a new instance of the <see cref="WebConsumerOpenIdRelyingParty"/> class.
/// </summary>
/// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param>
/// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param>
- public WebConsumerOpenIdRelyingParty(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager)
- : base(serviceDescription, tokenManager) {
+ public WebConsumerOpenIdRelyingParty() {
}
/// <summary>
@@ -64,11 +65,8 @@ namespace DotNetOpenAuth.OAuth {
/// The access token, if granted, is automatically stored in the <see cref="ConsumerBase.TokenManager" />.
/// The token manager instance must implement <see cref="IOpenIdOAuthTokenManager" />.
/// </remarks>
- public async Task<AuthorizedTokenResponse> ProcessUserAuthorizationAsync(IAuthenticationResponse openIdAuthenticationResponse, CancellationToken cancellationToken = default(CancellationToken)) {
+ public async Task<AccessTokenResponse> ProcessUserAuthorizationAsync(IAuthenticationResponse openIdAuthenticationResponse, CancellationToken cancellationToken = default(CancellationToken)) {
Requires.NotNull(openIdAuthenticationResponse, "openIdAuthenticationResponse");
- RequiresEx.ValidState(this.TokenManager is IOpenIdOAuthTokenManager);
- var openidTokenManager = this.TokenManager as IOpenIdOAuthTokenManager;
- ErrorUtilities.VerifyOperation(openidTokenManager != null, OAuthStrings.OpenIdOAuthExtensionRequiresSpecialTokenManagerInterface, typeof(IOpenIdOAuthTokenManager).FullName);
// The OAuth extension is only expected in positive assertion responses.
if (openIdAuthenticationResponse.Status != AuthenticationStatus.Authenticated) {
@@ -81,21 +79,24 @@ namespace DotNetOpenAuth.OAuth {
return null;
}
- // Prepare a message to exchange the request token for an access token.
- // We are careful to use a v1.0 message version so that the oauth_verifier is not required.
- var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, Protocol.V10.Version) {
- RequestToken = positiveAuthorization.RequestToken,
- ConsumerKey = this.ConsumerKey,
- };
+ using (var client = this.CreateHttpClient(new AccessToken(positiveAuthorization.RequestToken, string.Empty))) {
+ var request = new HttpRequestMessage(this.ServiceProvider.TokenRequestEndpointMethod, this.ServiceProvider.TokenRequestEndpoint);
+ using (var response = await client.SendAsync(request, cancellationToken)) {
+ response.EnsureSuccessStatusCode();
- // Retrieve the access token and store it in the token manager.
- openidTokenManager.StoreOpenIdAuthorizedRequestToken(this.ConsumerKey, positiveAuthorization);
- var grantAccess = await this.Channel.RequestAsync<AuthorizedTokenResponse>(requestAccess, cancellationToken);
- this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, positiveAuthorization.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
+ // Parse the response and ensure that it meets the requirements of the OAuth 1.0 spec.
+ string content = await response.Content.ReadAsStringAsync();
+ var responseData = HttpUtility.ParseQueryString(content);
+ string accessToken = responseData[Protocol.TokenParameter];
+ string tokenSecret = responseData[Protocol.TokenSecretParameter];
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(accessToken), MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenParameter);
+ ErrorUtilities.VerifyProtocol(tokenSecret != null, MessagingStrings.RequiredParametersMissing, typeof(AuthorizedTokenResponse).Name, Protocol.TokenSecretParameter);
- // Provide the caller with the access token so it may be associated with the user
- // that is logging in.
- return grantAccess;
+ responseData.Remove(Protocol.TokenParameter);
+ responseData.Remove(Protocol.TokenSecretParameter);
+ return new AccessTokenResponse(accessToken, tokenSecret, responseData);
+ }
+ }
}
}
}