summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OpenIdOAuth
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2012-02-08 06:47:52 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2012-02-08 17:29:38 -0800
commitbef6c27a1b50519f23a5308547d65b55c8e98868 (patch)
tree60aa3a0c5d3e4e97d6f89df4a90f478c42fb1a12 /src/DotNetOpenAuth.OpenIdOAuth
parente40337bd6706ffdfd31a43124b0fd1e095ba7844 (diff)
downloadDotNetOpenAuth-bef6c27a1b50519f23a5308547d65b55c8e98868.zip
DotNetOpenAuth-bef6c27a1b50519f23a5308547d65b55c8e98868.tar.gz
DotNetOpenAuth-bef6c27a1b50519f23a5308547d65b55c8e98868.tar.bz2
Removed OAuth1's dependency on OpenID assemblies.
Related to #71
Diffstat (limited to 'src/DotNetOpenAuth.OpenIdOAuth')
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/DotNetOpenAuth.OpenIdOAuth.csproj58
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs33
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs30
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs161
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs97
-rw-r--r--src/DotNetOpenAuth.OpenIdOAuth/Properties/AssemblyInfo.cs53
6 files changed, 432 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/DotNetOpenAuth.OpenIdOAuth.csproj b/src/DotNetOpenAuth.OpenIdOAuth/DotNetOpenAuth.OpenIdOAuth.csproj
new file mode 100644
index 0000000..009eaf1
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenIdOAuth/DotNetOpenAuth.OpenIdOAuth.csproj
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.props))\EnlistmentInfo.props" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.props))' != '' " />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ </PropertyGroup>
+ <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.props" />
+ <PropertyGroup>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{4BFAA336-5DF3-4F27-82D3-06D13240E8AB}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>DotNetOpenAuth</RootNamespace>
+ <AssemblyName>DotNetOpenAuth.OpenIdOAuth</AssemblyName>
+ </PropertyGroup>
+ <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.Product.props" />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="OAuth\ChannelElements\ICombinedOpenIdProviderTokenManager.cs" />
+ <Compile Include="OAuth\ChannelElements\IOpenIdOAuthTokenManager.cs" />
+ <Compile Include="OAuth\ServiceProviderOpenIdProvider.cs" />
+ <Compile Include="OAuth\WebConsumerOpenIdRelyingParty.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\DotNetOpenAuth.Core\DotNetOpenAuth.Core.csproj">
+ <Project>{60426312-6AE5-4835-8667-37EDEA670222}</Project>
+ <Name>DotNetOpenAuth.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.OAuth.Consumer\DotNetOpenAuth.OAuth.Consumer.csproj">
+ <Project>{B202E40D-4663-4A2B-ACDA-865F88FF7CAA}</Project>
+ <Name>DotNetOpenAuth.OAuth.Consumer</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.OAuth.ServiceProvider\DotNetOpenAuth.OAuth.ServiceProvider.csproj">
+ <Project>{FED1923A-6D70-49B5-A37A-FB744FEC1C86}</Project>
+ <Name>DotNetOpenAuth.OAuth.ServiceProvider</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.OAuth\DotNetOpenAuth.OAuth.csproj">
+ <Project>{A288FCC8-6FCF-46DA-A45E-5F9281556361}</Project>
+ <Name>DotNetOpenAuth.OAuth</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.OpenId\DotNetOpenAuth.OpenId.csproj">
+ <Project>{3896A32A-E876-4C23-B9B8-78E17D134CD3}</Project>
+ <Name>DotNetOpenAuth.OpenId</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Org.Mentalis.Security.Cryptography\Org.Mentalis.Security.Cryptography.csproj">
+ <Project>{26DC877F-5987-48DD-9DDB-E62F2DE0E150}</Project>
+ <Name>Org.Mentalis.Security.Cryptography</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.targets" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " />
+</Project> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs
new file mode 100644
index 0000000..d6a7e93
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs
@@ -0,0 +1,33 @@
+//-----------------------------------------------------------------------
+// <copyright file="ICombinedOpenIdProviderTokenManager.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth.ChannelElements {
+ using DotNetOpenAuth.OpenId;
+
+ /// <summary>
+ /// An interface that providers that play a dual role as OpenID Provider
+ /// and OAuth Service Provider should implement on their token manager classes.
+ /// </summary>
+ /// <remarks>
+ /// This interface should be implemented by the same class that implements
+ /// <see cref="ITokenManager"/> in order to enable the OpenID+OAuth extension.
+ /// </remarks>
+ public interface ICombinedOpenIdProviderTokenManager : IOpenIdOAuthTokenManager, ITokenManager {
+ /// <summary>
+ /// Gets the OAuth consumer key for a given OpenID relying party realm.
+ /// </summary>
+ /// <param name="realm">The relying party's OpenID realm.</param>
+ /// <returns>The OAuth consumer key for a given OpenID realm.</returns>
+ /// <para>This is a security-critical function. Since OpenID requests
+ /// and OAuth extensions for those requests can be formulated by ANYONE
+ /// (no signing is required by the relying party), and since the response to
+ /// the authentication will include access the user is granted to the
+ /// relying party who CLAIMS to be from some realm, it is of paramount
+ /// importance that the realm is recognized as belonging to the consumer
+ /// key by the host service provider in order to protect against phishers.</para>
+ string GetConsumerKey(Realm realm);
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs
new file mode 100644
index 0000000..3f3c1d9
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs
@@ -0,0 +1,30 @@
+//-----------------------------------------------------------------------
+// <copyright file="IOpenIdOAuthTokenManager.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth.ChannelElements {
+ using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.OpenId.Extensions.OAuth;
+
+ /// <summary>
+ /// Additional methods an <see cref="ITokenManager"/> implementing class
+ /// may implement to support the OpenID+OAuth extension.
+ /// </summary>
+ public interface IOpenIdOAuthTokenManager {
+ /// <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>
+ void StoreOpenIdAuthorizedRequestToken(string consumerKey, AuthorizationApprovedResponse authorization);
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs
new file mode 100644
index 0000000..b590a90
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs
@@ -0,0 +1,161 @@
+//-----------------------------------------------------------------------
+// <copyright file="ServiceProviderOpenIdProvider.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Globalization;
+ using System.Security.Principal;
+ using System.ServiceModel.Channels;
+ using System.Web;
+ using DotNetOpenAuth.Configuration;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+ using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.OpenId.Extensions.OAuth;
+ using DotNetOpenAuth.OpenId.Messages;
+ using DotNetOpenAuth.OpenId.Provider;
+
+ /// <summary>
+ /// A web application that allows access via OAuth and can respond to OpenID+OAuth requests.
+ /// </summary>
+ /// <remarks>
+ /// <para>The Service Provider’s documentation should include:</para>
+ /// <list>
+ /// <item>The URLs (Request URLs) the Consumer will use when making OAuth requests, and the HTTP methods (i.e. GET, POST, etc.) used in the Request Token URL and Access Token URL.</item>
+ /// <item>Signature methods supported by the Service Provider.</item>
+ /// <item>Any additional request parameters that the Service Provider requires in order to obtain a Token. Service Provider specific parameters MUST NOT begin with oauth_.</item>
+ /// </list>
+ /// </remarks>
+ public class ServiceProviderOpenIdProvider : ServiceProvider {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServiceProviderOpenIdProvider"/> class.
+ /// </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)
+ : base(serviceDescription, tokenManager) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServiceProviderOpenIdProvider"/> class.
+ /// </summary>
+ /// <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)
+ : base(serviceDescription, tokenManager, messageTypeProvider) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServiceProviderOpenIdProvider"/> class.
+ /// </summary>
+ /// <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)
+ : base(serviceDescription, tokenManager, nonceStore) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServiceProviderOpenIdProvider"/> class.
+ /// </summary>
+ /// <param name="serviceDescription">The service description.</param>
+ /// <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)
+ : base(serviceDescription, tokenManager, nonceStore, messageTypeProvider) {
+ }
+
+ /// <summary>
+ /// Gets the OAuth authorization request included with an OpenID authentication
+ /// request, if there is one.
+ /// </summary>
+ /// <param name="openIdRequest">The OpenID authentication request.</param>
+ /// <returns>
+ /// The scope of access the relying party is requesting, or null if no OAuth request
+ /// is present.
+ /// </returns>
+ /// <remarks>
+ /// <para>Call this method rather than simply extracting the OAuth extension
+ /// out from the authentication request directly to ensure that the additional
+ /// security measures that are required are taken.</para>
+ /// </remarks>
+ public AuthorizationRequest ReadAuthorizationRequest(IHostProcessedRequest openIdRequest) {
+ Requires.NotNull(openIdRequest, "openIdRequest");
+ Requires.ValidState(this.TokenManager is ICombinedOpenIdProviderTokenManager);
+ var openidTokenManager = this.TokenManager as ICombinedOpenIdProviderTokenManager;
+ ErrorUtilities.VerifyOperation(openidTokenManager != null, OAuthStrings.OpenIdOAuthExtensionRequiresSpecialTokenManagerInterface, typeof(IOpenIdOAuthTokenManager).FullName);
+
+ var authzRequest = openIdRequest.GetExtension<AuthorizationRequest>();
+ if (authzRequest == null) {
+ return null;
+ }
+
+ // OpenID+OAuth spec section 9:
+ // The Combined Provider SHOULD verify that the consumer key passed in the
+ // request is authorized to be used for the realm passed in the request.
+ string expectedConsumerKey = openidTokenManager.GetConsumerKey(openIdRequest.Realm);
+ ErrorUtilities.VerifyProtocol(
+ string.Equals(expectedConsumerKey, authzRequest.Consumer, StringComparison.Ordinal),
+ OAuthStrings.OpenIdOAuthRealmConsumerKeyDoNotMatch);
+
+ return authzRequest;
+ }
+
+ /// <summary>
+ /// Attaches the authorization response to an OpenID authentication response.
+ /// </summary>
+ /// <param name="openIdAuthenticationRequest">The OpenID authentication request.</param>
+ /// <param name="consumerKey">The consumer key. Must be <c>null</c> if and only if <paramref name="scope"/> is null.</param>
+ /// <param name="scope">The approved access scope. Use <c>null</c> to indicate no access was granted. The empty string will be interpreted as some default level of access is granted.</param>
+ [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "We want to take IAuthenticationRequest because that's the only supported use case.")]
+ [Obsolete("Call the overload that doesn't take a consumerKey instead.")]
+ public void AttachAuthorizationResponse(IHostProcessedRequest openIdAuthenticationRequest, string consumerKey, string scope) {
+ Requires.NotNull(openIdAuthenticationRequest, "openIdAuthenticationRequest");
+ Requires.True((consumerKey == null) == (scope == null), null);
+ Requires.ValidState(this.TokenManager is ICombinedOpenIdProviderTokenManager);
+ var openidTokenManager = (ICombinedOpenIdProviderTokenManager)this.TokenManager;
+ ErrorUtilities.VerifyArgument(consumerKey == null || consumerKey == openidTokenManager.GetConsumerKey(openIdAuthenticationRequest.Realm), OAuthStrings.OpenIdOAuthRealmConsumerKeyDoNotMatch);
+
+ this.AttachAuthorizationResponse(openIdAuthenticationRequest, scope);
+ }
+
+ /// <summary>
+ /// Attaches the authorization response to an OpenID authentication response.
+ /// </summary>
+ /// <param name="openIdAuthenticationRequest">The OpenID authentication request.</param>
+ /// <param name="scope">The approved access scope. Use <c>null</c> to indicate no access was granted. The empty string will be interpreted as some default level of access is granted.</param>
+ [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "We want to take IAuthenticationRequest because that's the only supported use case.")]
+ public void AttachAuthorizationResponse(IHostProcessedRequest openIdAuthenticationRequest, string scope) {
+ Requires.NotNull(openIdAuthenticationRequest, "openIdAuthenticationRequest");
+ Requires.ValidState(this.TokenManager is ICombinedOpenIdProviderTokenManager);
+
+ var openidTokenManager = this.TokenManager as ICombinedOpenIdProviderTokenManager;
+ IOpenIdMessageExtension response;
+ if (scope != null) {
+ // Generate an authorized request token to return to the relying party.
+ string consumerKey = openidTokenManager.GetConsumerKey(openIdAuthenticationRequest.Realm);
+ var approvedResponse = new AuthorizationApprovedResponse {
+ RequestToken = this.TokenGenerator.GenerateRequestToken(consumerKey),
+ Scope = scope,
+ };
+ openidTokenManager.StoreOpenIdAuthorizedRequestToken(consumerKey, approvedResponse);
+ response = approvedResponse;
+ } else {
+ response = new AuthorizationDeclinedResponse();
+ }
+
+ openIdAuthenticationRequest.AddResponseExtension(response);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
new file mode 100644
index 0000000..0d1a602
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/WebConsumerOpenIdRelyingParty.cs
@@ -0,0 +1,97 @@
+//-----------------------------------------------------------------------
+// <copyright file="WebConsumerOpenIdRelyingParty.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+ using DotNetOpenAuth.OpenId.Extensions.OAuth;
+ using DotNetOpenAuth.OpenId.RelyingParty;
+
+ /// <summary>
+ /// A website or application that uses OAuth to access the Service Provider on behalf of the User
+ /// and can attach OAuth requests to outbound OpenID authentication requests.
+ /// </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 WebConsumerOpenIdRelyingParty : WebConsumer {
+ /// <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) {
+ }
+
+ /// <summary>
+ /// Attaches an OAuth authorization request to an outgoing OpenID authentication request.
+ /// </summary>
+ /// <param name="openIdAuthenticationRequest">The OpenID authentication request.</param>
+ /// <param name="scope">The scope of access that is requested of the service provider.</param>
+ public void AttachAuthorizationRequest(IAuthenticationRequest openIdAuthenticationRequest, string scope) {
+ Requires.NotNull(openIdAuthenticationRequest, "openIdAuthenticationRequest");
+
+ var authorizationRequest = new AuthorizationRequest {
+ Consumer = this.ConsumerKey,
+ Scope = scope,
+ };
+
+ openIdAuthenticationRequest.AddExtension(authorizationRequest);
+ }
+
+ /// <summary>
+ /// Processes an incoming authorization-granted message from an SP and obtains an access token.
+ /// </summary>
+ /// <param name="openIdAuthenticationResponse">The OpenID authentication response that may be carrying an authorized request token.</param>
+ /// <returns>
+ /// The access token, or null if OAuth authorization was denied by the user or service provider.
+ /// </returns>
+ /// <remarks>
+ /// 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 AuthorizedTokenResponse ProcessUserAuthorization(IAuthenticationResponse openIdAuthenticationResponse) {
+ Requires.NotNull(openIdAuthenticationResponse, "openIdAuthenticationResponse");
+ Requires.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) {
+ return null;
+ }
+
+ // Retrieve the OAuth extension
+ var positiveAuthorization = openIdAuthenticationResponse.GetExtension<AuthorizationApprovedResponse>();
+ if (positiveAuthorization == null) {
+ 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,
+ };
+
+ // Retrieve the access token and store it in the token manager.
+ openidTokenManager.StoreOpenIdAuthorizedRequestToken(this.ConsumerKey, positiveAuthorization);
+ var grantAccess = this.Channel.Request<AuthorizedTokenResponse>(requestAccess);
+ this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, positiveAuthorization.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret);
+
+ // Provide the caller with the access token so it may be associated with the user
+ // that is logging in.
+ return grantAccess;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenIdOAuth/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.OpenIdOAuth/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..08c3ec2
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenIdOAuth/Properties/AssemblyInfo.cs
@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------
+// <copyright file="AssemblyInfo.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+// We DON'T put an AssemblyVersionAttribute in here because it is generated in the build.
+
+using System;
+using System.Diagnostics.Contracts;
+using System.Net;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Permissions;
+using System.Web.UI;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("DotNetOpenAuth")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("DotNetOpenAuth")]
+[assembly: AssemblyCopyright("Copyright © 2011 Outercurve Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: NeutralResourcesLanguage("en-US")]
+[assembly: CLSCompliant(true)]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("F9AFC069-8291-497F-B2A1-3E4D1646C572")]
+[assembly: ContractVerification(true)]
+
+#if StrongNameSigned
+// See comment at top of this file. We need this so that strong-naming doesn't
+// keep this assembly from being useful to shared host (medium trust) web sites.
+[assembly: AllowPartiallyTrustedCallers]
+
+[assembly: InternalsVisibleTo("DotNetOpenAuth.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
+#else
+[assembly: InternalsVisibleTo("DotNetOpenAuth.Test")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
+#endif