summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.ClientAuthorization
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.ClientAuthorization')
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj76
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/AccessTokenParameters.cs96
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs66
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/GrantTypeEncoder.cs78
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs56
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.Designer.cs81
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.resx126
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientType.cs47
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IAuthorizationServer.cs196
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IClientDescription.cs138
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs66
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs83
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenFailedResponse.cs93
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRefreshRequest.cs45
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs105
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs93
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenSuccessResponse.cs157
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AuthenticatedClientRequestBase.cs42
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationFailedResponse.cs81
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs63
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationRequest.cs103
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationResponseType.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAccessTokenResponse.cs122
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAuthCodeResponse.cs50
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs71
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/GrantType.cs42
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenIssuingResponse.cs24
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequest.cs37
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IMessageWithClientState.cs21
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/ScopedAccessTokenRequest.cs41
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/TokenEndpointProtocolException.cs59
-rw-r--r--src/DotNetOpenAuth.OAuth2.ClientAuthorization/Properties/AssemblyInfo.cs58
33 files changed, 2466 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj
new file mode 100644
index 0000000..53ab1d0
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/DotNetOpenAuth.OAuth2.ClientAuthorization.csproj
@@ -0,0 +1,76 @@
+<?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>{CCF3728A-B3D7-404A-9BC6-75197135F2D7}</ProjectGuid>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <AssemblyName>DotNetOpenAuth.OAuth2.ClientAuthorization</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="OAuth2\AccessTokenParameters.cs" />
+ <Compile Include="OAuth2\ChannelElements\EndUserAuthorizationResponseTypeEncoder.cs" />
+ <Compile Include="OAuth2\ChannelElements\GrantTypeEncoder.cs" />
+ <Compile Include="OAuth2\ChannelElements\OAuth2ChannelBase.cs" />
+ <Compile Include="OAuth2\ClientAuthorizationStrings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>ClientAuthorizationStrings.resx</DependentUpon>
+ </Compile>
+ <Compile Include="OAuth2\ClientType.cs" />
+ <Compile Include="OAuth2\IAuthorizationServer.cs" />
+ <Compile Include="OAuth2\IClientDescription.cs" />
+ <Compile Include="OAuth2\Messages\AccessTokenAuthorizationCodeRequest.cs" />
+ <Compile Include="OAuth2\Messages\AccessTokenClientCredentialsRequest.cs" />
+ <Compile Include="OAuth2\Messages\AccessTokenFailedResponse.cs" />
+ <Compile Include="OAuth2\Messages\AccessTokenRefreshRequest.cs" />
+ <Compile Include="OAuth2\Messages\AccessTokenRequestBase.cs" />
+ <Compile Include="OAuth2\Messages\AccessTokenResourceOwnerPasswordCredentialsRequest.cs" />
+ <Compile Include="OAuth2\Messages\AccessTokenSuccessResponse.cs" />
+ <Compile Include="OAuth2\Messages\AuthenticatedClientRequestBase.cs" />
+ <Compile Include="OAuth2\Messages\EndUserAuthorizationFailedResponse.cs" />
+ <Compile Include="OAuth2\Messages\EndUserAuthorizationImplicitRequest.cs" />
+ <Compile Include="OAuth2\Messages\EndUserAuthorizationRequest.cs" />
+ <Compile Include="OAuth2\Messages\EndUserAuthorizationResponseType.cs" />
+ <Compile Include="OAuth2\Messages\EndUserAuthorizationSuccessAccessTokenResponse.cs" />
+ <Compile Include="OAuth2\Messages\EndUserAuthorizationSuccessAuthCodeResponse.cs" />
+ <Compile Include="OAuth2\Messages\EndUserAuthorizationSuccessResponseBase.cs" />
+ <Compile Include="OAuth2\Messages\GrantType.cs" />
+ <Compile Include="OAuth2\Messages\IAccessTokenIssuingResponse.cs" />
+ <Compile Include="OAuth2\Messages\IAccessTokenRequest.cs" />
+ <Compile Include="OAuth2\Messages\IAccessTokenRequestInternal.cs" />
+ <Compile Include="OAuth2\Messages\IMessageWithClientState.cs" />
+ <Compile Include="OAuth2\Messages\ScopedAccessTokenRequest.cs" />
+ <Compile Include="OAuth2\TokenEndpointProtocolException.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.OAuth2\DotNetOpenAuth.OAuth2.csproj">
+ <Project>{56459A6C-6BA2-4BAC-A9C0-27E3BD961FA6}</Project>
+ <Name>DotNetOpenAuth.OAuth2</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="OAuth2\ClientAuthorizationStrings.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>ClientAuthorizationStrings.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ </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.OAuth2.ClientAuthorization/OAuth2/AccessTokenParameters.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/AccessTokenParameters.cs
new file mode 100644
index 0000000..a6d6169
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/AccessTokenParameters.cs
@@ -0,0 +1,96 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenParameters.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2 {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+
+ /// <summary>
+ /// Describes the parameters to be fed into creating a response to an access token request.
+ /// </summary>
+ public class AccessTokenParameters : IDisposable {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenParameters"/> class.
+ /// </summary>
+ public AccessTokenParameters() {
+ this.IncludeRefreshToken = true;
+ this.AccessTokenLifetime = TimeSpan.FromHours(1);
+ }
+
+ /// <summary>
+ /// Gets or sets the access token lifetime.
+ /// </summary>
+ /// <value>
+ /// A positive timespan.
+ /// </value>
+ /// <remarks>
+ /// Note that within this lifetime, authorization <i>may</i> not be revokable.
+ /// Short lifetimes are recommended (e.g. one hour), particularly when the client is not authenticated or
+ /// the resources to which access is being granted are sensitive.
+ /// </remarks>
+ public TimeSpan AccessTokenLifetime { get; set; }
+
+ /// <summary>
+ /// Gets or sets the crypto service provider with the asymmetric private key to use for signing access tokens.
+ /// </summary>
+ /// <returns>A crypto service provider instance that contains the private key.</returns>
+ /// <value>Must not be null, and must contain the private key.</value>
+ /// <remarks>
+ /// The public key in the private/public key pair will be used by the resource
+ /// servers to validate that the access token is minted by a trusted authorization server.
+ /// </remarks>
+ public RSACryptoServiceProvider AccessTokenSigningKey { get; set; }
+
+ /// <summary>
+ /// Gets or sets the key to encrypt the access token.
+ /// </summary>
+ public RSACryptoServiceProvider ResourceServerEncryptionKey { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to provide the client with a refresh token, when applicable.
+ /// </summary>
+ /// <value>The default value is <c>true</c>.</value>
+ /// <remarks>>
+ /// The refresh token will never be provided when this value is false.
+ /// The refresh token <em>may</em> be provided when this value is true.
+ /// </remarks>
+ public bool IncludeRefreshToken { get; set; }
+
+ #region Implementation of IDisposable
+
+ /// <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);
+ }
+
+ /// <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) {
+ if (this.ResourceServerEncryptionKey != null) {
+ IDisposable value = this.ResourceServerEncryptionKey;
+ value.Dispose();
+ }
+
+ if (this.AccessTokenSigningKey != null) {
+ IDisposable value = this.AccessTokenSigningKey;
+ value.Dispose();
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs
new file mode 100644
index 0000000..2fba721
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/EndUserAuthorizationResponseTypeEncoder.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationResponseTypeEncoder.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.ChannelElements {
+ using System;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Reflection;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// Encodes/decodes the OAuth 2.0 response_type argument.
+ /// </summary>
+ internal class EndUserAuthorizationResponseTypeEncoder : IMessagePartEncoder {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationResponseTypeEncoder"/> class.
+ /// </summary>
+ public EndUserAuthorizationResponseTypeEncoder() {
+ }
+
+ #region IMessagePartEncoder Members
+
+ /// <summary>
+ /// Encodes the specified value.
+ /// </summary>
+ /// <param name="value">The value. Guaranteed to never be null.</param>
+ /// <returns>
+ /// The <paramref name="value"/> in string form, ready for message transport.
+ /// </returns>
+ public string Encode(object value) {
+ var responseType = (EndUserAuthorizationResponseType)value;
+ switch (responseType)
+ {
+ case EndUserAuthorizationResponseType.AccessToken:
+ return Protocol.ResponseTypes.Token;
+ case EndUserAuthorizationResponseType.AuthorizationCode:
+ return Protocol.ResponseTypes.Code;
+ default:
+ throw ErrorUtilities.ThrowFormat(MessagingStrings.UnexpectedMessagePartValue, Protocol.response_type, value);
+ }
+ }
+
+ /// <summary>
+ /// Decodes the specified value.
+ /// </summary>
+ /// <param name="value">The string value carried by the transport. Guaranteed to never be null, although it may be empty.</param>
+ /// <returns>
+ /// The deserialized form of the given string.
+ /// </returns>
+ /// <exception cref="FormatException">Thrown when the string value given cannot be decoded into the required object type.</exception>
+ public object Decode(string value) {
+ switch (value) {
+ case Protocol.ResponseTypes.Token:
+ return EndUserAuthorizationResponseType.AccessToken;
+ case Protocol.ResponseTypes.Code:
+ return EndUserAuthorizationResponseType.AuthorizationCode;
+ default:
+ throw ErrorUtilities.ThrowFormat(MessagingStrings.UnexpectedMessagePartValue, Protocol.response_type, value);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/GrantTypeEncoder.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/GrantTypeEncoder.cs
new file mode 100644
index 0000000..e0e8329
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/GrantTypeEncoder.cs
@@ -0,0 +1,78 @@
+//-----------------------------------------------------------------------
+// <copyright file="GrantTypeEncoder.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.ChannelElements {
+ using System;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Reflection;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// Encodes/decodes the OAuth 2.0 grant_type argument.
+ /// </summary>
+ internal class GrantTypeEncoder : IMessagePartEncoder {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="GrantTypeEncoder"/> class.
+ /// </summary>
+ public GrantTypeEncoder() {
+ }
+
+ #region IMessagePartEncoder Members
+
+ /// <summary>
+ /// Encodes the specified value.
+ /// </summary>
+ /// <param name="value">The value. Guaranteed to never be null.</param>
+ /// <returns>
+ /// The <paramref name="value"/> in string form, ready for message transport.
+ /// </returns>
+ public string Encode(object value) {
+ var responseType = (GrantType)value;
+ switch (responseType)
+ {
+ case GrantType.ClientCredentials:
+ return Protocol.GrantTypes.ClientCredentials;
+ case GrantType.AuthorizationCode:
+ return Protocol.GrantTypes.AuthorizationCode;
+ case GrantType.RefreshToken:
+ return Protocol.GrantTypes.RefreshToken;
+ case GrantType.Password:
+ return Protocol.GrantTypes.Password;
+ case GrantType.Assertion:
+ return Protocol.GrantTypes.Assertion;
+ default:
+ throw ErrorUtilities.ThrowFormat(MessagingStrings.UnexpectedMessagePartValue, Protocol.grant_type, value);
+ }
+ }
+
+ /// <summary>
+ /// Decodes the specified value.
+ /// </summary>
+ /// <param name="value">The string value carried by the transport. Guaranteed to never be null, although it may be empty.</param>
+ /// <returns>
+ /// The deserialized form of the given string.
+ /// </returns>
+ /// <exception cref="FormatException">Thrown when the string value given cannot be decoded into the required object type.</exception>
+ public object Decode(string value) {
+ switch (value) {
+ case Protocol.GrantTypes.ClientCredentials:
+ return GrantType.ClientCredentials;
+ case Protocol.GrantTypes.Assertion:
+ return GrantType.Assertion;
+ case Protocol.GrantTypes.Password:
+ return GrantType.Password;
+ case Protocol.GrantTypes.RefreshToken:
+ return GrantType.RefreshToken;
+ case Protocol.GrantTypes.AuthorizationCode:
+ return GrantType.AuthorizationCode;
+ default:
+ throw ErrorUtilities.ThrowFormat(MessagingStrings.UnexpectedMessagePartValue, Protocol.grant_type, value);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs
new file mode 100644
index 0000000..f2f674e
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ChannelElements/OAuth2ChannelBase.cs
@@ -0,0 +1,56 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuth2ChannelBase.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// The base messaging channel used by OAuth 2.0 parties.
+ /// </summary>
+ internal abstract class OAuth2ChannelBase : StandardMessageFactoryChannel {
+ /// <summary>
+ /// The protocol versions supported by this channel.
+ /// </summary>
+ private static readonly Version[] Versions = Protocol.AllVersions.Select(v => v.Version).ToArray();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuth2ChannelBase"/> class.
+ /// </summary>
+ /// <param name="messageTypes">The message types that are received by this channel.</param>
+ /// <param name="channelBindingElements">
+ /// The binding elements to use in sending and receiving messages.
+ /// The order they are provided is used for outgoing messgaes, and reversed for incoming messages.
+ /// </param>
+ internal OAuth2ChannelBase(Type[] messageTypes, params IChannelBindingElement[] channelBindingElements)
+ : base(Requires.NotNull(messageTypes, "messageTypes"), Versions, channelBindingElements) {
+ }
+
+ /// <summary>
+ /// Allows preprocessing and validation of message data before an appropriate message type is
+ /// selected or deserialized.
+ /// </summary>
+ /// <param name="fields">The received message data.</param>
+ protected override void FilterReceivedFields(IDictionary<string, string> fields) {
+ base.FilterReceivedFields(fields);
+
+ // Apply the OAuth 2.0 section 2.1 requirement:
+ // Parameters sent without a value MUST be treated as if they were omitted from the request.
+ // The authorization server SHOULD ignore unrecognized request parameters.
+ var emptyKeys = from pair in fields
+ where string.IsNullOrEmpty(pair.Value)
+ select pair.Key;
+ foreach (string emptyKey in emptyKeys.ToList()) {
+ fields.Remove(emptyKey);
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.Designer.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.Designer.cs
new file mode 100644
index 0000000..e7e1b6b
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.Designer.cs
@@ -0,0 +1,81 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.17614
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2 {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class ClientAuthorizationStrings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ClientAuthorizationStrings() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DotNetOpenAuth.OAuth2.ClientAuthorizationStrings", typeof(ClientAuthorizationStrings).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The request message type {0} should not be responded to with a refresh token..
+ /// </summary>
+ internal static string RefreshTokenInappropriateForRequestType {
+ get {
+ return ResourceManager.GetString("RefreshTokenInappropriateForRequestType", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The Authorization Server&apos;s token endpoint generated error {0}: &apos;{1}&apos;.
+ /// </summary>
+ internal static string TokenEndpointErrorFormat {
+ get {
+ return ResourceManager.GetString("TokenEndpointErrorFormat", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.resx b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.resx
new file mode 100644
index 0000000..da2dd73
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientAuthorizationStrings.resx
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="RefreshTokenInappropriateForRequestType" xml:space="preserve">
+ <value>The request message type {0} should not be responded to with a refresh token.</value>
+ </data>
+ <data name="TokenEndpointErrorFormat" xml:space="preserve">
+ <value>The Authorization Server's token endpoint generated error {0}: '{1}'</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientType.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientType.cs
new file mode 100644
index 0000000..9e8ed2a
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/ClientType.cs
@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------
+// <copyright file="ClientType.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2 {
+ /// <summary>
+ /// OAuth 2 Client types
+ /// </summary>
+ /// <remarks>
+ /// <para>Based on their ability to
+ /// authenticate securely with the authorization server (i.e. ability to
+ /// maintain the confidentiality of their client credentials).</para>
+ /// <para>The client type designation is based on the authorization server's
+ /// definition of secure authentication and its acceptable exposure
+ /// levels of client credentials.</para>
+ /// <para>The authorization server SHOULD NOT make assumptions about the client
+ /// type, nor accept the type information provided by the client
+ /// developer without first establishing trust.</para>
+ /// <para>A client application consisting of multiple components, each with its
+ /// own client type (e.g. a distributed client with both a confidential
+ /// server-based component and a public browser-based component), MUST
+ /// register each component separately as a different client to ensure
+ /// proper handling by the authorization server. The authorization
+ /// server MAY provider tools to manage such complex clients through a
+ /// single administration interface.</para>
+ /// </remarks>
+ public enum ClientType {
+ /// <summary>
+ /// Clients capable of maintaining the confidentiality of their
+ /// credentials (e.g. client implemented on a secure server with
+ /// restricted access to the client credentials), or capable of secure
+ /// client authentication using other means.
+ /// </summary>
+ Confidential,
+
+ /// <summary>
+ /// Clients incapable of maintaining the confidentiality of their
+ /// credentials (e.g. clients executing on the device used by the
+ /// resource owner such as an installed native application or a web
+ /// browser-based application), and incapable of secure client
+ /// authentication via any other means.
+ /// </summary>
+ Public,
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IAuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IAuthorizationServer.cs
new file mode 100644
index 0000000..605d007
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IAuthorizationServer.cs
@@ -0,0 +1,196 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAuthorizationServer.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2 {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// Provides host-specific authorization server services needed by this library.
+ /// </summary>
+ [ContractClass(typeof(IAuthorizationServerContract))]
+ public interface IAuthorizationServer {
+ /// <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>
+ ICryptoKeyStore CryptoKeyStore { get; }
+
+ /// <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>
+ INonceStore NonceStore { get; }
+
+ /// <summary>
+ /// Obtains parameters to go into the formulation of an access token.
+ /// </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>
+ AccessTokenParameters GetAccessTokenParameters(IAccessTokenRequest accessTokenRequestMessage);
+
+ /// <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>
+ IClientDescription GetClient(string clientIdentifier);
+
+ /// <summary>
+ /// Determines whether a described authorization is (still) valid.
+ /// </summary>
+ /// <param name="authorization">The authorization.</param>
+ /// <returns>
+ /// <c>true</c> if the original authorization is still valid; otherwise, <c>false</c>.
+ /// </returns>
+ /// <remarks>
+ /// <para>When establishing that an authorization is still valid,
+ /// it's very important to only match on recorded authorizations that
+ /// meet these criteria:</para>
+ /// 1) The client identifier matches.
+ /// 2) The user account matches.
+ /// 3) The scope on the recorded authorization must include all scopes in the given authorization.
+ /// 4) The date the recorded authorization was issued must be <em>no later</em> that the date the given authorization was issued.
+ /// <para>One possible scenario is where the user authorized a client, later revoked authorization,
+ /// and even later reinstated authorization. This subsequent recorded authorization
+ /// would not satisfy requirement #4 in the above list. This is important because the revocation
+ /// the user went through should invalidate all previously issued tokens as a matter of
+ /// security in the event the user was revoking access in order to sever authorization on a stolen
+ /// account or piece of hardware in which the tokens were stored. </para>
+ /// </remarks>
+ bool IsAuthorizationValid(IAuthorizationDescription authorization);
+
+ /// <summary>
+ /// Determines whether a given set of resource owner credentials is valid based on the authorization server's user database.
+ /// </summary>
+ /// <param name="userName">Username on the account.</param>
+ /// <param name="password">The user's password.</param>
+ /// <returns>
+ /// <c>true</c> if the given credentials are valid; otherwise, <c>false</c>.
+ /// </returns>
+ /// <exception cref="NotSupportedException">May be thrown if the authorization server does not support the resource owner password credential grant type.</exception>
+ bool IsResourceOwnerCredentialValid(string userName, string password);
+ }
+
+ /// <summary>
+ /// Code Contract for the <see cref="IAuthorizationServer"/> interface.
+ /// </summary>
+ [ContractClassFor(typeof(IAuthorizationServer))]
+ internal abstract class IAuthorizationServerContract : IAuthorizationServer {
+ /// <summary>
+ /// Prevents a default instance of the <see cref="IAuthorizationServerContract"/> class from being created.
+ /// </summary>
+ private IAuthorizationServerContract() {
+ }
+
+ /// <summary>
+ /// Gets the store for storeing crypto keys used to symmetrically encrypt and sign authorization codes and refresh tokens.
+ /// </summary>
+ ICryptoKeyStore IAuthorizationServer.CryptoKeyStore {
+ get {
+ Contract.Ensures(Contract.Result<ICryptoKeyStore>() != null);
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <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>
+ INonceStore IAuthorizationServer.NonceStore {
+ get {
+ Contract.Ensures(Contract.Result<INonceStore>() != null);
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <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>
+ IClientDescription IAuthorizationServer.GetClient(string clientIdentifier) {
+ Requires.NotNullOrEmpty(clientIdentifier, "clientIdentifier");
+ Contract.Ensures(Contract.Result<IClientDescription>() != null);
+ throw new NotImplementedException();
+ }
+
+ /// <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>
+ bool IAuthorizationServer.IsAuthorizationValid(IAuthorizationDescription authorization) {
+ Requires.NotNull(authorization, "authorization");
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Determines whether a given set of resource owner credentials is valid based on the authorization server's user database.
+ /// </summary>
+ /// <param name="userName">Username on the account.</param>
+ /// <param name="password">The user's password.</param>
+ /// <returns>
+ /// <c>true</c> if the given credentials are valid; otherwise, <c>false</c>.
+ /// </returns>
+ /// <exception cref="NotSupportedException">May be thrown if the authorization server does not support the resource owner password credential grant type.</exception>
+ bool IAuthorizationServer.IsResourceOwnerCredentialValid(string userName, string password) {
+ Contract.Requires(!string.IsNullOrEmpty(userName));
+ Contract.Requires(password != null);
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Obtains parameters to go into the formulation of an access token.
+ /// </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>
+ AccessTokenParameters IAuthorizationServer.GetAccessTokenParameters(IAccessTokenRequest accessTokenRequestMessage) {
+ Contract.Requires(accessTokenRequestMessage != null);
+ Contract.Ensures(Contract.Result<AccessTokenParameters>() != null);
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IClientDescription.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IClientDescription.cs
new file mode 100644
index 0000000..b4bc689
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/IClientDescription.cs
@@ -0,0 +1,138 @@
+//-----------------------------------------------------------------------
+// <copyright file="IClientDescription.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2 {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A description of a client from an Authorization Server's point of view.
+ /// </summary>
+ [ContractClass(typeof(IClientDescriptionContract))]
+ public interface IClientDescription {
+ /// <summary>
+ /// Gets the callback to use when an individual authorization request
+ /// does not include an explicit callback URI.
+ /// </summary>
+ /// <value>An absolute URL; or <c>null</c> if none is registered.</value>
+ Uri DefaultCallback { get; }
+
+ /// <summary>
+ /// Gets the type of the client.
+ /// </summary>
+ ClientType ClientType { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether a non-empty secret is registered for this client.
+ /// </summary>
+ bool HasNonEmptySecret { get; }
+
+ /// <summary>
+ /// Determines whether a callback URI included in a client's authorization request
+ /// is among those allowed callbacks for the registered client.
+ /// </summary>
+ /// <param name="callback">The absolute URI the client has requested the authorization result be received at. Never null.</param>
+ /// <returns>
+ /// <c>true</c> if the callback URL is allowable for this client; otherwise, <c>false</c>.
+ /// </returns>
+ /// <remarks>
+ /// <para>
+ /// At the point this method is invoked, the identity of the client has <em>not</em>
+ /// been confirmed. To avoid open redirector attacks, the alleged client's identity
+ /// is used to lookup a list of allowable callback URLs to make sure that the callback URL
+ /// the actual client is requesting is one of the expected ones.
+ /// </para>
+ /// <para>
+ /// From OAuth 2.0 section 2.1:
+ /// The authorization server SHOULD require the client to pre-register
+ /// their redirection URI or at least certain components such as the
+ /// scheme, host, port and path. If a redirection URI was registered,
+ /// the authorization server MUST compare any redirection URI received at
+ /// the authorization endpoint with the registered URI.
+ /// </para>
+ /// </remarks>
+ bool IsCallbackAllowed(Uri callback);
+
+ /// <summary>
+ /// Checks whether the specified client secret is correct.
+ /// </summary>
+ /// <param name="secret">The secret obtained from the client.</param>
+ /// <returns><c>true</c> if the secret matches the one in the authorization server's record for the client; <c>false</c> otherwise.</returns>
+ /// <remarks>
+ /// All string equality checks, whether checking secrets or their hashes,
+ /// should be done using <see cref="MessagingUtilities.EqualsConstantTime"/> to mitigate timing attacks.
+ /// </remarks>
+ bool IsValidClientSecret(string secret);
+ }
+
+ /// <summary>
+ /// Contract class for the <see cref="IClientDescription"/> interface.
+ /// </summary>
+ [ContractClassFor(typeof(IClientDescription))]
+ internal abstract class IClientDescriptionContract : IClientDescription {
+ #region IClientDescription Members
+
+ /// <summary>
+ /// Gets the type of the client.
+ /// </summary>
+ ClientType IClientDescription.ClientType {
+ get { throw new NotImplementedException(); }
+ }
+
+ /// <summary>
+ /// Gets the callback to use when an individual authorization request
+ /// does not include an explicit callback URI.
+ /// </summary>
+ /// <value>
+ /// An absolute URL; or <c>null</c> if none is registered.
+ /// </value>
+ Uri IClientDescription.DefaultCallback {
+ get {
+ Contract.Ensures(Contract.Result<Uri>() == null || Contract.Result<Uri>().IsAbsoluteUri);
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether a non-empty secret is registered for this client.
+ /// </summary>
+ bool IClientDescription.HasNonEmptySecret {
+ get { throw new NotImplementedException(); }
+ }
+
+ /// <summary>
+ /// Determines whether a callback URI included in a client's authorization request
+ /// is among those allowed callbacks for the registered client.
+ /// </summary>
+ /// <param name="callback">The requested callback URI.</param>
+ /// <returns>
+ /// <c>true</c> if the callback is allowed; otherwise, <c>false</c>.
+ /// </returns>
+ bool IClientDescription.IsCallbackAllowed(Uri callback) {
+ Requires.NotNull(callback, "callback");
+ Requires.True(callback.IsAbsoluteUri, "callback");
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Checks whether the specified client secret is correct.
+ /// </summary>
+ /// <param name="secret">The secret obtained from the client.</param>
+ /// <returns><c>true</c> if the secret matches the one in the authorization server's record for the client; <c>false</c> otherwise.</returns>
+ /// <remarks>
+ /// All string equality checks, whether checking secrets or their hashes,
+ /// should be done using <see cref="MessagingUtilities.EqualsConstantTime"/> to mitigate timing attacks.
+ /// </remarks>
+ bool IClientDescription.IsValidClientSecret(string secret) {
+ Requires.NotNullOrEmpty(secret, "secret");
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs
new file mode 100644
index 0000000..b8c9ede
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenAuthorizationCodeRequest.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenAuthorizationCodeRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text;
+
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A request from a Client to an Authorization Server to exchange an authorization code for an access token,
+ /// and (at the authorization server's option) a refresh token.
+ /// </summary>
+ internal class AccessTokenAuthorizationCodeRequest : AccessTokenRequestBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenAuthorizationCodeRequest"/> class.
+ /// </summary>
+ /// <param name="tokenEndpoint">The Authorization Server's access token endpoint URL.</param>
+ /// <param name="version">The version.</param>
+ protected AccessTokenAuthorizationCodeRequest(Uri tokenEndpoint, Version version)
+ : base(tokenEndpoint, version) {
+ }
+
+ /// <summary>
+ /// Gets the type of the grant.
+ /// </summary>
+ /// <value>The type of the grant.</value>
+ internal override GrantType GrantType {
+ get { return Messages.GrantType.AuthorizationCode; }
+ }
+
+ /// <summary>
+ /// Gets or sets the verification code previously communicated to the Client
+ /// in <see cref="EndUserAuthorizationSuccessAuthCodeResponse.AuthorizationCode"/>.
+ /// </summary>
+ /// <value>The verification code received from the authorization server.</value>
+ [MessagePart(Protocol.code, IsRequired = true)]
+ internal string AuthorizationCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the callback URL used in <see cref="EndUserAuthorizationRequest.Callback"/>
+ /// </summary>
+ /// <value>
+ /// The Callback URL used to obtain the Verification Code.
+ /// </value>
+ /// <remarks>
+ /// REQUIRED, if the redirect_uri parameter was included in the authorization request as described in Section 4.1.1, and their values MUST be identical.
+ /// </remarks>
+ [MessagePart(Protocol.redirect_uri, IsRequired = false)]
+ internal Uri Callback { get; set; }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ protected override HashSet<string> RequestedScope {
+ get { return ((IAuthorizationCarryingRequest)this).AuthorizationDescription.Scope; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs
new file mode 100644
index 0000000..48419eb
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs
@@ -0,0 +1,83 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenClientCredentialsRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A request for an access token for a client application that has its
+ /// own (non-user affiliated) client name and password.
+ /// </summary>
+ /// <remarks>
+ /// This is somewhat analogous to 2-legged OAuth.
+ /// </remarks>
+ internal class AccessTokenClientCredentialsRequest : ScopedAccessTokenRequest, IAuthorizationCarryingRequest, IAuthorizationDescription {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenClientCredentialsRequest"/> class.
+ /// </summary>
+ /// <param name="tokenEndpoint">The authorization server.</param>
+ /// <param name="version">The version.</param>
+ internal AccessTokenClientCredentialsRequest(Uri tokenEndpoint, Version version)
+ : base(tokenEndpoint, version) {
+ this.HttpMethods = HttpDeliveryMethods.PostRequest;
+ }
+
+ #region IAuthorizationCarryingRequest members
+
+ /// <summary>
+ /// Gets the authorization that the code or token describes.
+ /// </summary>
+ IAuthorizationDescription IAuthorizationCarryingRequest.AuthorizationDescription {
+ get { return this.CredentialsValidated ? this : null; }
+ }
+
+ #endregion
+
+ #region IAuthorizationDescription Members
+
+ /// <summary>
+ /// Gets the date this authorization was established or the token was issued.
+ /// </summary>
+ /// <value>A date/time expressed in UTC.</value>
+ DateTime IAuthorizationDescription.UtcIssued {
+ get { return DateTime.UtcNow; }
+ }
+
+ /// <summary>
+ /// Gets the name on the account whose data on the resource server is accessible using this authorization.
+ /// </summary>
+ string IAuthorizationDescription.User {
+ get { return null; }
+ }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ HashSet<string> IAuthorizationDescription.Scope {
+ get { return this.Scope; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets the type of the grant.
+ /// </summary>
+ /// <value>The type of the grant.</value>
+ internal override GrantType GrantType {
+ get { return Messages.GrantType.ClientCredentials; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the resource owner's credentials have been validated at the authorization server.
+ /// </summary>
+ internal bool CredentialsValidated { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenFailedResponse.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenFailedResponse.cs
new file mode 100644
index 0000000..8c4b1c3
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenFailedResponse.cs
@@ -0,0 +1,93 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenFailedResponse.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Net;
+
+ using Messaging;
+
+ /// <summary>
+ /// A response from the Authorization Server to the Client to indicate that a
+ /// request for an access token renewal failed, probably due to an invalid
+ /// refresh token.
+ /// </summary>
+ /// <remarks>
+ /// This message type is shared by the Web App, Rich App, and Username/Password profiles.
+ /// </remarks>
+ internal class AccessTokenFailedResponse : MessageBase, IHttpDirectResponse {
+ /// <summary>
+ /// A value indicating whether this error response is in result to a request that had invalid client credentials which were supplied in the HTTP Authorization header.
+ /// </summary>
+ private readonly bool invalidClientCredentialsInAuthorizationHeader;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenFailedResponse"/> class.
+ /// </summary>
+ /// <param name="request">The faulty request.</param>
+ internal AccessTokenFailedResponse(AccessTokenRequestBase request)
+ : base(request) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenFailedResponse"/> class.
+ /// </summary>
+ /// <param name="request">The faulty request.</param>
+ /// <param name="invalidClientCredentialsInAuthorizationHeader">A value indicating whether this error response is in result to a request that had invalid client credentials which were supplied in the HTTP Authorization header.</param>
+ internal AccessTokenFailedResponse(AccessTokenRequestBase request, bool invalidClientCredentialsInAuthorizationHeader)
+ : base(request) {
+ this.invalidClientCredentialsInAuthorizationHeader = invalidClientCredentialsInAuthorizationHeader;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenFailedResponse"/> class.
+ /// </summary>
+ /// <param name="version">The protocol version.</param>
+ internal AccessTokenFailedResponse(Version version = null)
+ : base(version ?? Protocol.Default.Version) {
+ }
+
+ #region IHttpDirectResponse Members
+
+ /// <summary>
+ /// Gets the HTTP status code that the direct response should be sent with.
+ /// </summary>
+ HttpStatusCode IHttpDirectResponse.HttpStatusCode {
+ get { return this.invalidClientCredentialsInAuthorizationHeader ? HttpStatusCode.Unauthorized : HttpStatusCode.BadRequest; }
+ }
+
+ /// <summary>
+ /// Gets the HTTP headers to add to the response.
+ /// </summary>
+ /// <value>May be an empty collection, but must not be <c>null</c>.</value>
+ WebHeaderCollection IHttpDirectResponse.Headers {
+ get { return new WebHeaderCollection(); }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets or sets the error.
+ /// </summary>
+ /// <value>One of the values given in <see cref="Protocol.AccessTokenRequestErrorCodes"/>.</value>
+ [MessagePart(Protocol.error, IsRequired = true)]
+ internal string Error { get; set; }
+
+ /// <summary>
+ /// Gets or sets a human readable description of the error.
+ /// </summary>
+ /// <value>Human-readable text providing additional information, used to assist in the understanding and resolution of the error that occurred.</value>
+ [MessagePart(Protocol.error_description, IsRequired = false)]
+ internal string ErrorDescription { get; set; }
+
+ /// <summary>
+ /// Gets or sets the location of the web page that describes the error and possible resolution.
+ /// </summary>
+ /// <value>A URI identifying a human-readable web page with information about the error, used to provide the end-user with additional information about the error.</value>
+ [MessagePart(Protocol.error_uri, IsRequired = false)]
+ internal Uri ErrorUri { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRefreshRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRefreshRequest.cs
new file mode 100644
index 0000000..685f697
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRefreshRequest.cs
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenRefreshRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A request from the client to the token endpoint for a new access token
+ /// in exchange for a refresh token that the client has previously obtained.
+ /// </summary>
+ internal class AccessTokenRefreshRequest : ScopedAccessTokenRequest {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenRefreshRequest"/> class.
+ /// </summary>
+ /// <param name="tokenEndpoint">The token endpoint.</param>
+ /// <param name="version">The version.</param>
+ protected AccessTokenRefreshRequest(Uri tokenEndpoint, Version version)
+ : base(tokenEndpoint, version) {
+ }
+
+ /// <summary>
+ /// Gets or sets the refresh token.
+ /// </summary>
+ /// <value>The refresh token.</value>
+ /// <remarks>
+ /// REQUIRED. The refresh token associated with the access token to be refreshed.
+ /// </remarks>
+ [MessagePart(Protocol.refresh_token, IsRequired = true)]
+ internal string RefreshToken { get; set; }
+
+ /// <summary>
+ /// Gets the type of the grant.
+ /// </summary>
+ /// <value>The type of the grant.</value>
+ internal override GrantType GrantType {
+ get { return Messages.GrantType.RefreshToken; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs
new file mode 100644
index 0000000..b9f4c56
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenRequestBase.cs
@@ -0,0 +1,105 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenRequestBase.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Configuration;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A message sent from the client to the authorization server to exchange a previously obtained grant for an access token.
+ /// </summary>
+ public abstract class AccessTokenRequestBase : AuthenticatedClientRequestBase, IAccessTokenRequestInternal, IDisposable {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenRequestBase"/> class.
+ /// </summary>
+ /// <param name="tokenEndpoint">The Authorization Server's access token endpoint URL.</param>
+ /// <param name="version">The version.</param>
+ protected AccessTokenRequestBase(Uri tokenEndpoint, Version version)
+ : base(tokenEndpoint, version) {
+ this.HttpMethods = HttpDeliveryMethods.PostRequest;
+ }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ HashSet<string> IAccessTokenRequest.Scope {
+ get { return this.RequestedScope; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the client requesting the access token has authenticated itself.
+ /// </summary>
+ /// <value>
+ /// Always true, because of our base class.
+ /// </value>
+ bool IAccessTokenRequest.ClientAuthenticated {
+ get { return true; }
+ }
+
+ /// <summary>
+ /// Gets or sets the access token creation parameters.
+ /// </summary>
+ /// <remarks>
+ /// This property's value is set by a binding element in the OAuth 2 channel.
+ /// </remarks>
+ AccessTokenParameters IAccessTokenRequestInternal.AccessTokenCreationParameters { get; set; }
+
+ /// <summary>
+ /// Gets the type of the grant.
+ /// </summary>
+ /// <value>The type of the grant.</value>
+ [MessagePart(Protocol.grant_type, IsRequired = true, Encoder = typeof(GrantTypeEncoder))]
+ internal abstract GrantType GrantType { get; }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ protected abstract HashSet<string> RequestedScope { get; }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose() {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <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) {
+ IAccessTokenRequestInternal self = this;
+ if (self.AccessTokenCreationParameters != null) {
+ self.AccessTokenCreationParameters.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Checks the message state for conformity to the protocol specification
+ /// and throws an exception if the message is invalid.
+ /// </summary>
+ /// <remarks>
+ /// <para>Some messages have required fields, or combinations of fields that must relate to each other
+ /// in specialized ways. After deserializing a message, this method checks the state of the
+ /// message to see if it conforms to the protocol.</para>
+ /// <para>Note that this property should <i>not</i> check signatures or perform any state checks
+ /// outside this scope of this particular message.</para>
+ /// </remarks>
+ /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception>
+ protected override void EnsureValidMessage() {
+ base.EnsureValidMessage();
+ ErrorUtilities.VerifyProtocol(
+ DotNetOpenAuthSection.Messaging.RelaxSslRequirements || this.Recipient.IsTransportSecure(),
+ OAuthStrings.HttpsRequired);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs
new file mode 100644
index 0000000..52e65be
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenResourceOwnerPasswordCredentialsRequest.cs
@@ -0,0 +1,93 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenResourceOwnerPasswordCredentialsRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A request from a Client to an Authorization Server to exchange the user's username and password for an access token.
+ /// </summary>
+ internal class AccessTokenResourceOwnerPasswordCredentialsRequest : ScopedAccessTokenRequest, IAuthorizationCarryingRequest, IAuthorizationDescription {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenResourceOwnerPasswordCredentialsRequest"/> class.
+ /// </summary>
+ /// <param name="accessTokenEndpoint">The access token endpoint.</param>
+ /// <param name="version">The protocol version.</param>
+ internal AccessTokenResourceOwnerPasswordCredentialsRequest(Uri accessTokenEndpoint, Version version)
+ : base(accessTokenEndpoint, version) {
+ }
+
+ #region IAuthorizationCarryingRequest members
+
+ /// <summary>
+ /// Gets the authorization that the code or token describes.
+ /// </summary>
+ IAuthorizationDescription IAuthorizationCarryingRequest.AuthorizationDescription {
+ get { return this.CredentialsValidated ? this : null; }
+ }
+
+ #endregion
+
+ #region IAuthorizationDescription Members
+
+ /// <summary>
+ /// Gets the date this authorization was established or the token was issued.
+ /// </summary>
+ /// <value>A date/time expressed in UTC.</value>
+ DateTime IAuthorizationDescription.UtcIssued {
+ get { return DateTime.UtcNow; }
+ }
+
+ /// <summary>
+ /// Gets the name on the account whose data on the resource server is accessible using this authorization.
+ /// </summary>
+ string IAuthorizationDescription.User {
+ get { return this.UserName; }
+ }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ HashSet<string> IAuthorizationDescription.Scope {
+ get { return this.Scope; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets the type of the grant.
+ /// </summary>
+ /// <value>The type of the grant.</value>
+ internal override GrantType GrantType {
+ get { return Messages.GrantType.Password; }
+ }
+
+ /// <summary>
+ /// Gets or sets the user's account username.
+ /// </summary>
+ /// <value>The username on the user's account.</value>
+ [MessagePart(Protocol.username, IsRequired = true)]
+ internal string UserName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user's password.
+ /// </summary>
+ /// <value>The password.</value>
+ [MessagePart(Protocol.password, IsRequired = true)]
+ internal string Password { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the resource owner's credentials have been validated at the authorization server.
+ /// </summary>
+ internal bool CredentialsValidated { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenSuccessResponse.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenSuccessResponse.cs
new file mode 100644
index 0000000..1de39a6
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AccessTokenSuccessResponse.cs
@@ -0,0 +1,157 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenSuccessResponse.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Net;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A response from the Authorization Server to the Client containing a delegation code
+ /// that the Client should use to obtain an access token.
+ /// </summary>
+ /// <remarks>
+ /// This message type is shared by the Web App, Rich App, and Username/Password profiles.
+ /// </remarks>
+ internal class AccessTokenSuccessResponse : MessageBase, IHttpDirectResponse, IAccessTokenIssuingResponse {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenSuccessResponse"/> class.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ internal AccessTokenSuccessResponse(AccessTokenRequestBase request)
+ : base(request) {
+ this.Scope = new HashSet<string>(OAuthUtilities.ScopeStringComparer);
+ this.TokenType = Protocol.AccessTokenTypes.Bearer;
+ }
+
+ /// <summary>
+ /// Gets the HTTP status code that the direct response should be sent with.
+ /// </summary>
+ /// <value>Always HttpStatusCode.OK</value>
+ HttpStatusCode IHttpDirectResponse.HttpStatusCode {
+ get { return HttpStatusCode.OK; }
+ }
+
+ /// <summary>
+ /// Gets the HTTP headers to add to the response.
+ /// </summary>
+ /// <value>May be an empty collection, but must not be <c>null</c>.</value>
+ WebHeaderCollection IHttpDirectResponse.Headers {
+ get {
+ return new WebHeaderCollection
+ {
+ { HttpResponseHeader.CacheControl, "no-store" },
+ { HttpResponseHeader.Pragma, "no-cache" },
+ };
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the access token.
+ /// </summary>
+ /// <value>The access token.</value>
+ [MessagePart(Protocol.access_token, IsRequired = true)]
+ public string AccessToken { get; internal set; }
+
+ /// <summary>
+ /// Gets or sets the token type.
+ /// </summary>
+ /// <value>Usually "bearer".</value>
+ /// <remarks>
+ /// Described in OAuth 2.0 section 7.1.
+ /// </remarks>
+ [MessagePart(Protocol.token_type, IsRequired = false)] // HACKHACK: This is actually required, but wasn't in older drafts of OAuth 2
+ public string TokenType { get; internal set; }
+
+ /// <summary>
+ /// Gets or sets the lifetime of the access token.
+ /// </summary>
+ /// <value>The lifetime.</value>
+ [MessagePart(Protocol.expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))]
+ public TimeSpan? Lifetime { get; internal set; }
+
+ /// <summary>
+ /// Gets or sets the refresh token.
+ /// </summary>
+ /// <value>The refresh token.</value>
+ /// <remarks>
+ /// OPTIONAL. The refresh token used to obtain new access tokens using the same end-user access grant as described in Section 6 (Refreshing an Access Token).
+ /// </remarks>
+ [MessagePart(Protocol.refresh_token, IsRequired = false)]
+ public string RefreshToken { get; internal set; }
+
+ /// <summary>
+ /// Gets the scope of access being requested.
+ /// </summary>
+ /// <value>The scope of the access request expressed as a list of space-delimited strings. The value of the scope parameter is defined by the authorization server. If the value contains multiple space-delimited strings, their order does not matter, and each string adds an additional access range to the requested scope.</value>
+ [MessagePart(Protocol.scope, IsRequired = false, Encoder = typeof(ScopeEncoder))]
+ public HashSet<string> Scope { get; private set; }
+
+ #region IAccessTokenIssuingResponse Members
+
+ /// <summary>
+ /// Gets or sets the lifetime of the access token.
+ /// </summary>
+ /// <value>
+ /// The lifetime.
+ /// </value>
+ TimeSpan? IAccessTokenIssuingResponse.Lifetime {
+ get { return this.Lifetime; }
+ set { this.Lifetime = value; }
+ }
+
+ #endregion
+
+ #region IAuthorizationCarryingRequest
+
+ /// <summary>
+ /// Gets the authorization that the token describes.
+ /// </summary>
+ IAuthorizationDescription IAuthorizationCarryingRequest.AuthorizationDescription {
+ get { return ((IAccessTokenCarryingRequest)this).AuthorizationDescription; }
+ }
+
+ #endregion
+
+ #region IAccessTokenCarryingRequest Members
+
+ /// <summary>
+ /// Gets or sets the authorization that the token describes.
+ /// </summary>
+ /// <value></value>
+ AccessToken IAccessTokenCarryingRequest.AuthorizationDescription { get; set; }
+
+ /// <summary>
+ /// Gets or sets the access token.
+ /// </summary>
+ string IAccessTokenCarryingRequest.AccessToken {
+ get { return this.AccessToken; }
+ set { this.AccessToken = value; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets or sets a value indicating whether a refresh token is or should be included in the response.
+ /// </summary>
+ internal bool HasRefreshToken { get; set; }
+
+ /// <summary>
+ /// Checks the message state for conformity to the protocol specification
+ /// and throws an exception if the message is invalid.
+ /// </summary>
+ /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception>
+ protected override void EnsureValidMessage() {
+ base.EnsureValidMessage();
+
+ // Per OAuth 2.0 section 4.4.3 (draft 23), refresh tokens should never be included
+ // in a response to an access token request that used the client credential grant type.
+ ErrorUtilities.VerifyProtocol(!this.HasRefreshToken || !(this.OriginatingRequest is AccessTokenClientCredentialsRequest), ClientAuthorizationStrings.RefreshTokenInappropriateForRequestType, this.OriginatingRequest.GetType().Name);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AuthenticatedClientRequestBase.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AuthenticatedClientRequestBase.cs
new file mode 100644
index 0000000..bc4d0ca
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/AuthenticatedClientRequestBase.cs
@@ -0,0 +1,42 @@
+//-----------------------------------------------------------------------
+// <copyright file="AuthenticatedClientRequestBase.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A direct message from the client to the authorization server that includes the client's credentials.
+ /// </summary>
+ public abstract class AuthenticatedClientRequestBase : MessageBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthenticatedClientRequestBase"/> class.
+ /// </summary>
+ /// <param name="tokenEndpoint">The Authorization Server's access token endpoint URL.</param>
+ /// <param name="version">The version.</param>
+ protected AuthenticatedClientRequestBase(Uri tokenEndpoint, Version version)
+ : base(version, MessageTransport.Direct, tokenEndpoint) {
+ }
+
+ /// <summary>
+ /// Gets the client identifier previously obtained from the Authorization Server.
+ /// </summary>
+ /// <value>The client identifier.</value>
+ [MessagePart(Protocol.client_id, IsRequired = true)]
+ public string ClientIdentifier { get; internal set; }
+
+ /// <summary>
+ /// Gets the client secret.
+ /// </summary>
+ /// <value>The client secret.</value>
+ /// <remarks>
+ /// REQUIRED. The client secret as described in Section 2.1 (Client Credentials). OPTIONAL if no client secret was issued.
+ /// </remarks>
+ [MessagePart(Protocol.client_secret, IsRequired = false)]
+ public string ClientSecret { get; internal set; }
+ }
+} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationFailedResponse.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationFailedResponse.cs
new file mode 100644
index 0000000..7cc8e82
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationFailedResponse.cs
@@ -0,0 +1,81 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationFailedResponse.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Runtime.Remoting.Messaging;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The message that an Authorization Server responds to a Client with when the user denies a user authorization request.
+ /// </summary>
+ public class EndUserAuthorizationFailedResponse : MessageBase, IMessageWithClientState {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationFailedResponse"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="version">The protocol version.</param>
+ internal EndUserAuthorizationFailedResponse(Uri clientCallback, Version version)
+ : base(version, MessageTransport.Indirect, clientCallback) {
+ Requires.NotNull(version, "version");
+ Requires.NotNull(clientCallback, "clientCallback");
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationFailedResponse"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="request">The authorization request from the user agent on behalf of the client.</param>
+ internal EndUserAuthorizationFailedResponse(Uri clientCallback, EndUserAuthorizationRequest request)
+ : base(((IProtocolMessage)request).Version, MessageTransport.Indirect, clientCallback) {
+ Requires.NotNull(request, "request");
+ ((IMessageWithClientState)this).ClientState = request.ClientState;
+ }
+
+ /// <summary>
+ /// Gets or sets the error.
+ /// </summary>
+ /// <value>
+ /// One of the values given in <see cref="Protocol.EndUserAuthorizationRequestErrorCodes"/>.
+ /// OR a numerical HTTP status code from the 4xx or 5xx
+ /// range, with the exception of the 400 (Bad Request) and
+ /// 401 (Unauthorized) status codes. For example, if the
+ /// service is temporarily unavailable, the authorization
+ /// server MAY return an error response with "error" set to
+ /// "503".
+ /// </value>
+ [MessagePart(Protocol.error, IsRequired = true)]
+ public string Error { get; set; }
+
+ /// <summary>
+ /// Gets or sets a human readable description of the error.
+ /// </summary>
+ /// <value>Human-readable text providing additional information, used to assist in the understanding and resolution of the error that occurred.</value>
+ [MessagePart(Protocol.error_description, IsRequired = false)]
+ public string ErrorDescription { get; set; }
+
+ /// <summary>
+ /// Gets or sets the location of the web page that describes the error and possible resolution.
+ /// </summary>
+ /// <value>A URI identifying a human-readable web page with information about the error, used to provide the end-user with additional information about the error.</value>
+ [MessagePart(Protocol.error_uri, IsRequired = false)]
+ public Uri ErrorUri { get; set; }
+
+ /// <summary>
+ /// Gets or sets some state as provided by the client in the authorization request.
+ /// </summary>
+ /// <value>An opaque value defined by the client.</value>
+ /// <remarks>
+ /// REQUIRED if the Client sent the value in the <see cref="EndUserAuthorizationRequest"/>.
+ /// </remarks>
+ [MessagePart(Protocol.state, IsRequired = false)]
+ string IMessageWithClientState.ClientState { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs
new file mode 100644
index 0000000..661e2ae
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationImplicitRequest.cs
@@ -0,0 +1,63 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationImplicitRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A message sent by a web application Client to the AuthorizationServer
+ /// via the user agent to obtain authorization from the user and prepare
+ /// to issue an access token to the client if permission is granted.
+ /// </summary>
+ [Serializable]
+ public class EndUserAuthorizationImplicitRequest : EndUserAuthorizationRequest, IAccessTokenRequestInternal {
+ /// <summary>
+ /// Gets or sets the grant type that the client expects of the authorization server.
+ /// </summary>
+ /// <value>Always <see cref="EndUserAuthorizationResponseType.AccessToken"/>. Other response types are not supported.</value>
+ [MessagePart(Protocol.response_type, IsRequired = true, Encoder = typeof(EndUserAuthorizationResponseTypeEncoder))]
+ private const EndUserAuthorizationResponseType ResponseTypeConst = EndUserAuthorizationResponseType.AccessToken;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationImplicitRequest"/> class.
+ /// </summary>
+ /// <param name="authorizationEndpoint">The Authorization Server's user authorization URL to direct the user to.</param>
+ /// <param name="version">The protocol version.</param>
+ protected EndUserAuthorizationImplicitRequest(Uri authorizationEndpoint, Version version)
+ : base(authorizationEndpoint, version) {
+ }
+
+ /// <summary>
+ /// Gets the grant type that the client expects of the authorization server.
+ /// </summary>
+ public override EndUserAuthorizationResponseType ResponseType {
+ get { return ResponseTypeConst; }
+ }
+
+ /// <summary>
+ /// Gets or sets the access token creation parameters.
+ /// </summary>
+ /// <remarks>
+ /// This property's value is set by a binding element in the OAuth 2 channel.
+ /// </remarks>
+ AccessTokenParameters IAccessTokenRequestInternal.AccessTokenCreationParameters { get; set; }
+
+ /// <summary>
+ /// Gets a value indicating whether the client requesting the access token has authenticated itself.
+ /// </summary>
+ /// <value>
+ /// Always false because authorization requests only include the client_id, without a secret.
+ /// </value>
+ bool IAccessTokenRequest.ClientAuthenticated {
+ get { return false; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationRequest.cs
new file mode 100644
index 0000000..f229cf9
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationRequest.cs
@@ -0,0 +1,103 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using DotNetOpenAuth.Configuration;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A message sent by a web application Client to the AuthorizationServer
+ /// via the user agent to obtain authorization from the user and prepare
+ /// to issue an access token to the client if permission is granted.
+ /// </summary>
+ [Serializable]
+ public class EndUserAuthorizationRequest : MessageBase {
+ /// <summary>
+ /// Gets the grant type that the client expects of the authorization server.
+ /// </summary>
+ /// <value>Always <see cref="EndUserAuthorizationResponseType.AuthorizationCode"/>. Other response types are not supported.</value>
+ [MessagePart(Protocol.response_type, IsRequired = true, Encoder = typeof(EndUserAuthorizationResponseTypeEncoder))]
+ private const EndUserAuthorizationResponseType ResponseTypeConst = EndUserAuthorizationResponseType.AuthorizationCode;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationRequest"/> class.
+ /// </summary>
+ /// <param name="authorizationEndpoint">The Authorization Server's user authorization URL to direct the user to.</param>
+ /// <param name="version">The protocol version.</param>
+ protected EndUserAuthorizationRequest(Uri authorizationEndpoint, Version version)
+ : base(version, MessageTransport.Indirect, authorizationEndpoint) {
+ Requires.NotNull(authorizationEndpoint, "authorizationEndpoint");
+ Requires.NotNull(version, "version");
+ this.HttpMethods = HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.PostRequest;
+ this.Scope = new HashSet<string>(OAuthUtilities.ScopeStringComparer);
+ }
+
+ /// <summary>
+ /// Gets the grant type that the client expects of the authorization server.
+ /// </summary>
+ public virtual EndUserAuthorizationResponseType ResponseType {
+ get { return ResponseTypeConst; }
+ }
+
+ /// <summary>
+ /// Gets or sets the identifier by which this client is known to the Authorization Server.
+ /// </summary>
+ [MessagePart(Protocol.client_id, IsRequired = true)]
+ public string ClientIdentifier { get; set; }
+
+ /// <summary>
+ /// Gets or sets the callback URL.
+ /// </summary>
+ /// <value>
+ /// An absolute URL to which the Authorization Server will redirect the User back after
+ /// the user has approved the authorization request.
+ /// </value>
+ /// <remarks>
+ /// REQUIRED unless a redirection URI has been established between the client and authorization server via other means. An absolute URI to which the authorization server will redirect the user-agent to when the end-user authorization step is completed. The authorization server MAY require the client to pre-register their redirection URI. The redirection URI MUST NOT include a query component as defined by [RFC3986] (Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax,” January 2005.) section 3 if the state parameter is present.
+ /// </remarks>
+ [MessagePart(Protocol.redirect_uri, IsRequired = false)]
+ public Uri Callback { get; set; }
+
+ /// <summary>
+ /// Gets or sets state of the client that should be sent back with the authorization response.
+ /// </summary>
+ /// <value>
+ /// An opaque value that Clients can use to maintain state associated with this request.
+ /// </value>
+ /// <remarks>
+ /// This data is proprietary to the client and should be considered an opaque string to the
+ /// authorization server.
+ /// </remarks>
+ [MessagePart(Protocol.state, IsRequired = false)]
+ public string ClientState { get; set; }
+
+ /// <summary>
+ /// Gets the scope of access being requested.
+ /// </summary>
+ /// <value>The scope of the access request expressed as a list of space-delimited strings. The value of the scope parameter is defined by the authorization server. If the value contains multiple space-delimited strings, their order does not matter, and each string adds an additional access range to the requested scope.</value>
+ [MessagePart(Protocol.scope, IsRequired = false, Encoder = typeof(ScopeEncoder))]
+ public HashSet<string> Scope { get; private set; }
+
+ /// <summary>
+ /// Checks the message state for conformity to the protocol specification
+ /// and throws an exception if the message is invalid.
+ /// </summary>
+ /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception>
+ protected override void EnsureValidMessage() {
+ base.EnsureValidMessage();
+
+ ErrorUtilities.VerifyProtocol(
+ DotNetOpenAuthSection.Messaging.RelaxSslRequirements || this.Recipient.IsTransportSecure(),
+ OAuthStrings.HttpsRequired);
+ ErrorUtilities.VerifyProtocol(this.Callback == null || this.Callback.IsAbsoluteUri, this, OAuthStrings.AbsoluteUriRequired, Protocol.redirect_uri);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationResponseType.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationResponseType.cs
new file mode 100644
index 0000000..75ece0f
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationResponseType.cs
@@ -0,0 +1,25 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationResponseType.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+
+ /// <summary>
+ /// An indication of what kind of response the client is requesting from the authorization server
+ /// after the user has granted authorized access.
+ /// </summary>
+ public enum EndUserAuthorizationResponseType {
+ /// <summary>
+ /// An access token should be returned immediately.
+ /// </summary>
+ AccessToken,
+
+ /// <summary>
+ /// An authorization code should be returned, which can later be exchanged for refresh and access tokens.
+ /// </summary>
+ AuthorizationCode,
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAccessTokenResponse.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAccessTokenResponse.cs
new file mode 100644
index 0000000..7a79e46
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAccessTokenResponse.cs
@@ -0,0 +1,122 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationSuccessAccessTokenResponse.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text;
+
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// The message sent by the Authorization Server to the Client via the user agent
+ /// to indicate that user authorization was granted, carrying only an access token,
+ /// and to return the user to the Client where they started their experience.
+ /// </summary>
+ internal class EndUserAuthorizationSuccessAccessTokenResponse : EndUserAuthorizationSuccessResponseBase, IAccessTokenIssuingResponse, IHttpIndirectResponse {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessAccessTokenResponse"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="version">The protocol version.</param>
+ internal EndUserAuthorizationSuccessAccessTokenResponse(Uri clientCallback, Version version)
+ : base(clientCallback, version) {
+ Requires.NotNull(version, "version");
+ Requires.NotNull(clientCallback, "clientCallback");
+ this.TokenType = Protocol.AccessTokenTypes.Bearer;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessAccessTokenResponse"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="request">The authorization request from the user agent on behalf of the client.</param>
+ internal EndUserAuthorizationSuccessAccessTokenResponse(Uri clientCallback, EndUserAuthorizationRequest request)
+ : base(clientCallback, request) {
+ Requires.NotNull(clientCallback, "clientCallback");
+ Requires.NotNull(request, "request");
+ ((IMessageWithClientState)this).ClientState = request.ClientState;
+ this.TokenType = Protocol.AccessTokenTypes.Bearer;
+ }
+
+ #region IAccessTokenCarryingRequest Members
+
+ /// <summary>
+ /// Gets or sets the authorization that the token describes.
+ /// </summary>
+ /// <value></value>
+ AccessToken IAccessTokenCarryingRequest.AuthorizationDescription { get; set; }
+
+ /// <summary>
+ /// Gets the authorization that the token describes.
+ /// </summary>
+ IAuthorizationDescription IAuthorizationCarryingRequest.AuthorizationDescription {
+ get { return ((IAccessTokenCarryingRequest)this).AuthorizationDescription; }
+ }
+
+ #endregion
+
+ #region IHttpIndirectResponse Members
+
+ /// <summary>
+ /// Gets a value indicating whether the payload for the message should be included
+ /// in the redirect fragment instead of the query string or POST entity.
+ /// </summary>
+ bool IHttpIndirectResponse.Include301RedirectPayloadInFragment {
+ get { return true; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets or sets the lifetime of the access token.
+ /// </summary>
+ /// <value>
+ /// The lifetime.
+ /// </value>
+ TimeSpan? IAccessTokenIssuingResponse.Lifetime {
+ get { return this.Lifetime; }
+ set { this.Lifetime = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the token type.
+ /// </summary>
+ /// <value>Usually "bearer".</value>
+ /// <remarks>
+ /// Described in OAuth 2.0 section 7.1.
+ /// </remarks>
+ [MessagePart(Protocol.token_type, IsRequired = true)]
+ public string TokenType { get; internal set; }
+
+ /// <summary>
+ /// Gets or sets the access token.
+ /// </summary>
+ /// <value>The access token.</value>
+ [MessagePart(Protocol.access_token, IsRequired = true)]
+ public string AccessToken { get; set; }
+
+ /// <summary>
+ /// Gets or sets the scope of the <see cref="AccessToken"/> if one is given; otherwise the scope of the authorization code.
+ /// </summary>
+ /// <value>The scope.</value>
+ [MessagePart(Protocol.scope, IsRequired = false, Encoder = typeof(ScopeEncoder))]
+ public new ICollection<string> Scope {
+ get { return base.Scope; }
+ protected set { base.Scope = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the lifetime of the authorization.
+ /// </summary>
+ /// <value>The lifetime.</value>
+ [MessagePart(Protocol.expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))]
+ internal TimeSpan? Lifetime { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAuthCodeResponse.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAuthCodeResponse.cs
new file mode 100644
index 0000000..9d6b015
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessAuthCodeResponse.cs
@@ -0,0 +1,50 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationSuccessAuthCodeResponse.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Diagnostics.Contracts;
+
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// The message sent by the Authorization Server to the Client via the user agent
+ /// to indicate that user authorization was granted, carrying an authorization code and possibly an access token,
+ /// and to return the user to the Client where they started their experience.
+ /// </summary>
+ internal class EndUserAuthorizationSuccessAuthCodeResponse : EndUserAuthorizationSuccessResponseBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessAuthCodeResponse"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="version">The protocol version.</param>
+ internal EndUserAuthorizationSuccessAuthCodeResponse(Uri clientCallback, Version version)
+ : base(clientCallback, version) {
+ Requires.NotNull(version, "version");
+ Requires.NotNull(clientCallback, "clientCallback");
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessAuthCodeResponse"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="request">The authorization request from the user agent on behalf of the client.</param>
+ internal EndUserAuthorizationSuccessAuthCodeResponse(Uri clientCallback, EndUserAuthorizationRequest request)
+ : base(clientCallback, request) {
+ Requires.NotNull(clientCallback, "clientCallback");
+ Requires.NotNull(request, "request");
+ ((IMessageWithClientState)this).ClientState = request.ClientState;
+ }
+
+ /// <summary>
+ /// Gets or sets the authorization code.
+ /// </summary>
+ /// <value>The authorization code.</value>
+ [MessagePart(Protocol.code, IsRequired = true)]
+ internal string AuthorizationCode { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs
new file mode 100644
index 0000000..ef0010e
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/EndUserAuthorizationSuccessResponseBase.cs
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------
+// <copyright file="EndUserAuthorizationSuccessResponseBase.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Security.Cryptography;
+
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// The message sent by the Authorization Server to the Client via the user agent
+ /// to indicate that user authorization was granted, and to return the user
+ /// to the Client where they started their experience.
+ /// </summary>
+ public abstract class EndUserAuthorizationSuccessResponseBase : MessageBase, IMessageWithClientState {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessResponseBase"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="version">The protocol version.</param>
+ internal EndUserAuthorizationSuccessResponseBase(Uri clientCallback, Version version)
+ : base(version, MessageTransport.Indirect, clientCallback) {
+ Requires.NotNull(version, "version");
+ Requires.NotNull(clientCallback, "clientCallback");
+ this.Scope = new HashSet<string>(OAuthUtilities.ScopeStringComparer);
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EndUserAuthorizationSuccessResponseBase"/> class.
+ /// </summary>
+ /// <param name="clientCallback">The URL to redirect to so the client receives the message. This may not be built into the request message if the client pre-registered the URL with the authorization server.</param>
+ /// <param name="request">The authorization request from the user agent on behalf of the client.</param>
+ internal EndUserAuthorizationSuccessResponseBase(Uri clientCallback, EndUserAuthorizationRequest request)
+ : base(request, clientCallback) {
+ Requires.NotNull(clientCallback, "clientCallback");
+ Requires.NotNull(request, "request");
+ ((IMessageWithClientState)this).ClientState = request.ClientState;
+ this.Scope = new HashSet<string>(OAuthUtilities.ScopeStringComparer);
+ this.Scope.ResetContents(request.Scope);
+ }
+
+ /// <summary>
+ /// Gets or sets some state as provided by the client in the authorization request.
+ /// </summary>
+ /// <value>An opaque value defined by the client.</value>
+ /// <remarks>
+ /// REQUIRED if the Client sent the value in the <see cref="EndUserAuthorizationRequest"/>.
+ /// </remarks>
+ [MessagePart(Protocol.state, IsRequired = false)]
+ string IMessageWithClientState.ClientState { get; set; }
+
+ /// <summary>
+ /// Gets or sets the scope of the <see cref="AccessToken"/> if one is given; otherwise the scope of the authorization code.
+ /// </summary>
+ /// <value>The scope.</value>
+ [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "By design")]
+ public ICollection<string> Scope { get; protected set; }
+
+ /// <summary>
+ /// Gets or sets the authorizing user's account name.
+ /// </summary>
+ internal string AuthorizingUsername { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/GrantType.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/GrantType.cs
new file mode 100644
index 0000000..a26d405
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/GrantType.cs
@@ -0,0 +1,42 @@
+//-----------------------------------------------------------------------
+// <copyright file="GrantType.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ /// <summary>
+ /// The types of authorizations that a client can use to obtain
+ /// a refresh token and/or an access token.
+ /// </summary>
+ internal enum GrantType {
+ /// <summary>
+ /// The client is providing the authorization code previously obtained from an end user authorization response.
+ /// </summary>
+ AuthorizationCode,
+
+ /// <summary>
+ /// The client is providing the end user's username and password to the authorization server.
+ /// </summary>
+ Password,
+
+ /// <summary>
+ /// The client is providing an assertion it obtained from another source.
+ /// </summary>
+ Assertion,
+
+ /// <summary>
+ /// The client is providing a refresh token.
+ /// </summary>
+ RefreshToken,
+
+ /// <summary>
+ /// No authorization to access a user's data has been given. The client is requesting
+ /// an access token authorized for its own private data. This fits the classic OAuth 1.0(a) "2-legged OAuth" scenario.
+ /// </summary>
+ /// <remarks>
+ /// When requesting an access token using the none access grant type (no access grant is included), the client is requesting access to the protected resources under its control, or those of another resource owner which has been previously arranged with the authorization server (the method of which is beyond the scope of this specification).
+ /// </remarks>
+ ClientCredentials,
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenIssuingResponse.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenIssuingResponse.cs
new file mode 100644
index 0000000..1a54aca
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenIssuingResponse.cs
@@ -0,0 +1,24 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAccessTokenIssuingResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A message sent from the Authorization Server to the client carrying an access token.
+ /// </summary>
+ internal interface IAccessTokenIssuingResponse : IAccessTokenCarryingRequest {
+ /// <summary>
+ /// Gets or sets the lifetime of the access token.
+ /// </summary>
+ /// <value>The lifetime.</value>
+ TimeSpan? Lifetime { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequest.cs
new file mode 100644
index 0000000..65378f9
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequest.cs
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAccessTokenRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// A request from a client that should be responded to directly with an access token.
+ /// </summary>
+ public interface IAccessTokenRequest : IMessage {
+ /// <summary>
+ /// Gets a value indicating whether the client requesting the access token has authenticated itself.
+ /// </summary>
+ /// <value>
+ /// <c>false</c> for implicit grant requests; otherwise, <c>true</c>.
+ /// </value>
+ bool ClientAuthenticated { get; }
+
+ /// <summary>
+ /// Gets the identifier of the client authorized to access protected data.
+ /// </summary>
+ string ClientIdentifier { get; }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ HashSet<string> Scope { get; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs
new file mode 100644
index 0000000..e218462
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IAccessTokenRequestInternal.cs
@@ -0,0 +1,25 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAccessTokenRequestInternal.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// Implemented by all message types whose response may contain an access token.
+ /// </summary>
+ public interface IAccessTokenRequestInternal : IAccessTokenRequest {
+ /// <summary>
+ /// Gets or sets the access token creation parameters.
+ /// </summary>
+ /// <remarks>
+ /// This property's value is set by a binding element in the OAuth 2 channel.
+ /// </remarks>
+ AccessTokenParameters AccessTokenCreationParameters { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IMessageWithClientState.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IMessageWithClientState.cs
new file mode 100644
index 0000000..71476f2
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/IMessageWithClientState.cs
@@ -0,0 +1,21 @@
+//-----------------------------------------------------------------------
+// <copyright file="IMessageWithClientState.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A message carrying client state the authorization server should preserve on behalf of the client
+ /// during an authorization.
+ /// </summary>
+ internal interface IMessageWithClientState : IProtocolMessage {
+ /// <summary>
+ /// Gets or sets the state of the client.
+ /// </summary>
+ /// <value>The state of the client.</value>
+ string ClientState { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/ScopedAccessTokenRequest.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/ScopedAccessTokenRequest.cs
new file mode 100644
index 0000000..0ea6efb
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/Messages/ScopedAccessTokenRequest.cs
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------
+// <copyright file="ScopedAccessTokenRequest.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.Messages {
+ using System;
+ using System.Collections.Generic;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+
+ /// <summary>
+ /// An access token request that includes a scope parameter.
+ /// </summary>
+ internal abstract class ScopedAccessTokenRequest : AccessTokenRequestBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ScopedAccessTokenRequest"/> class.
+ /// </summary>
+ /// <param name="tokenEndpoint">The Authorization Server's access token endpoint URL.</param>
+ /// <param name="version">The version.</param>
+ internal ScopedAccessTokenRequest(Uri tokenEndpoint, Version version)
+ : base(tokenEndpoint, version) {
+ this.Scope = new HashSet<string>(OAuthUtilities.ScopeStringComparer);
+ }
+
+ /// <summary>
+ /// Gets the set of scopes the Client would like the access token to provide access to.
+ /// </summary>
+ /// <value>A set of scopes. Never null.</value>
+ [MessagePart(Protocol.scope, IsRequired = false, Encoder = typeof(ScopeEncoder))]
+ internal HashSet<string> Scope { get; private set; }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ protected override HashSet<string> RequestedScope {
+ get { return this.Scope; }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/TokenEndpointProtocolException.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/TokenEndpointProtocolException.cs
new file mode 100644
index 0000000..308bfe2
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/OAuth2/TokenEndpointProtocolException.cs
@@ -0,0 +1,59 @@
+//-----------------------------------------------------------------------
+// <copyright file="TokenEndpointProtocolException.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2 {
+ using System;
+ using System.Collections.Generic;
+ using System.Globalization;
+ using System.Linq;
+ using System.Text;
+
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// Describes an error generated by an Authorization Server's token endpoint.
+ /// </summary>
+ public class TokenEndpointProtocolException : ProtocolException {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TokenEndpointProtocolException"/> class.
+ /// </summary>
+ /// <param name="error">A single error code from <see cref="Protocol.AccessTokenRequestErrorCodes"/>.</param>
+ /// <param name="description">A human-readable UTF-8 encoded text providing additional information, used to assist the client developer in understanding the error that occurred.</param>
+ /// <param name="moreInformation">A URI identifying a human-readable web page with information about the error, used to provide the client developer with additional information about the error.</param>
+ public TokenEndpointProtocolException(string error, string description = null, Uri moreInformation = null)
+ : base(string.Format(CultureInfo.CurrentCulture, ClientAuthorizationStrings.TokenEndpointErrorFormat, error, description)) {
+ Requires.NotNullOrEmpty(error, "error");
+
+ this.Error = error;
+ this.Description = description;
+ this.MoreInformation = moreInformation;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TokenEndpointProtocolException"/> class.
+ /// </summary>
+ /// <param name="innerException">The inner exception.</param>
+ public TokenEndpointProtocolException(Exception innerException)
+ : base(Protocol.AccessTokenRequestErrorCodes.InvalidRequest, innerException) {
+ this.Error = Protocol.AccessTokenRequestErrorCodes.InvalidRequest;
+ }
+
+ /// <summary>
+ /// Gets a single error code from <see cref="Protocol.AccessTokenRequestErrorCodes"/>.
+ /// </summary>
+ public string Error { get; private set; }
+
+ /// <summary>
+ /// Gets a human-readable UTF-8 encoded text providing additional information, used to assist the client developer in understanding the error that occurred.
+ /// </summary>
+ public string Description { get; private set; }
+
+ /// <summary>
+ /// Gets a URI identifying a human-readable web page with information about the error, used to provide the client developer with additional information about the error.
+ /// </summary>
+ public Uri MoreInformation { get; private set; }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.ClientAuthorization/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d536886
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.ClientAuthorization/Properties/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+//-----------------------------------------------------------------------
+// <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 OAuth 2.0")]
+[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("7d73990c-47c0-4256-9f20-a893add9e289")]
+
+[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.OAuth2.Client, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.AuthorizationServer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
+#else
+[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.Client")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.AuthorizationServer")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.Test")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
+#endif