summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.sln1
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj32
-rw-r--r--src/DotNetOpenAuth/Messaging/TimespanSecondsEncoder.cs (renamed from src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/TimespanSecondsEncoder.cs)8
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs45
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs52
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapMessageFactory.cs107
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/UriOrOutOfBandEncoding.cs83
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ConsumerBase.cs67
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenFailedResponse.cs50
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenSuccessResponse.cs46
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithConsumerNamePasswordRequest.cs41
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithDelegationCodeRequest.cs79
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithSamlRequest.cs45
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs204
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentDeniedResponse.cs44
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentGrantedResponse.cs47
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentRequest.cs60
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordFailedResponse.cs51
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordRequest.cs76
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordSuccessResponse.cs37
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Protocol.cs105
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.Designer.cs72
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.resx123
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WebConsumer.cs65
24 files changed, 1537 insertions, 3 deletions
diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln
index 55d43e8..cfa9cd4 100644
--- a/src/DotNetOpenAuth.sln
+++ b/src/DotNetOpenAuth.sln
@@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specs", "Specs", "{CD57219F
..\doc\specs\ICAM_OpenID20Profile.pdf = ..\doc\specs\ICAM_OpenID20Profile.pdf
..\doc\specs\OAuth Core 1.0.htm = ..\doc\specs\OAuth Core 1.0.htm
..\doc\specs\OAuth Core 1.0a (Draft 3).htm = ..\doc\specs\OAuth Core 1.0a (Draft 3).htm
+ ..\doc\specs\OAuthWRAP-v0.9.7.2.pdf = ..\doc\specs\OAuthWRAP-v0.9.7.2.pdf
..\doc\specs\OpenID OAuth Extension.htm = ..\doc\specs\OpenID OAuth Extension.htm
..\doc\specs\openid-attribute-exchange-1_0.html = ..\doc\specs\openid-attribute-exchange-1_0.html
..\doc\specs\openid-authentication-1_1.html = ..\doc\specs\openid-authentication-1_1.html
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index 3bfecae..fec065d 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -445,7 +445,7 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\PapeUtilities.cs" />
<Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\PolicyRequest.cs" />
<Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\PolicyResponse.cs" />
- <Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\TimespanSecondsEncoder.cs" />
+ <Compile Include="Messaging\TimespanSecondsEncoder.cs" />
<Compile Include="OpenId\Extensions\SimpleRegistration\ClaimsRequest.cs" />
<Compile Include="OpenId\Extensions\SimpleRegistration\ClaimsResponse.cs" />
<Compile Include="OpenId\Extensions\SimpleRegistration\Constants.cs" />
@@ -586,6 +586,30 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="Messaging\StandardWebRequestHandler.cs" />
<Compile Include="Messaging\MessageReceivingEndpoint.cs" />
<Compile Include="Reporting.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\OAuthWrapChannel.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\OAuthWrapMessageFactory.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\UriOrOutOfBandEncoding.cs" />
+ <Compile Include="OAuthWrap\ConsumerBase.cs" />
+ <Compile Include="OAuthWrap\Messages\AccessTokenFailedResponse.cs" />
+ <Compile Include="OAuthWrap\Messages\AccessTokenSuccessResponse.cs" />
+ <Compile Include="OAuthWrap\Messages\AccessTokenWithConsumerNamePasswordRequest.cs" />
+ <Compile Include="OAuthWrap\Messages\AccessTokenWithSamlRequest.cs" />
+ <Compile Include="OAuthWrap\Messages\MessageBase.cs" />
+ <Compile Include="OAuthWrap\Messages\AccessTokenWithDelegationCodeRequest.cs" />
+ <Compile Include="OAuthWrap\Messages\UserAuthorizationInUserAgentDeniedResponse.cs" />
+ <Compile Include="OAuthWrap\Messages\UserAuthorizationInUserAgentRequest.cs" />
+ <Compile Include="OAuthWrap\Messages\UserAuthorizationInUserAgentGrantedResponse.cs" />
+ <Compile Include="OAuthWrap\Messages\UserAuthorizationViaUsernamePasswordFailedResponse.cs" />
+ <Compile Include="OAuthWrap\Messages\UserAuthorizationViaUsernamePasswordRequest.cs" />
+ <Compile Include="OAuthWrap\Messages\UserAuthorizationViaUsernamePasswordSuccessResponse.cs" />
+ <Compile Include="OAuthWrap\Protocol.cs" />
+ <Compile Include="OAuthWrap\SimpleAuthStrings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>SimpleAuthStrings.resx</DependentUpon>
+ </Compile>
+ <Compile Include="OAuthWrap\AuthorizationServerDescription.cs" />
+ <Compile Include="OAuthWrap\WebConsumer.cs" />
<Compile Include="Util.cs" />
<Compile Include="OAuth\Protocol.cs" />
<Compile Include="OAuth\ServiceProvider.cs" />
@@ -698,6 +722,10 @@ http://opensource.org/licenses/ms-pl.html
<EmbeddedResource Include="OpenId\RelyingParty\OpenIdRelyingPartyAjaxControlBase.js">
<Copyright>$(StandardCopyright)</Copyright>
</EmbeddedResource>
+ <EmbeddedResource Include="OAuthWrap\SimpleAuthStrings.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>SimpleAuthStrings.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
<EmbeddedResource Include="Strings.sr.resx" />
<EmbeddedResource Include="Xrds\XrdsStrings.sr.resx" />
</ItemGroup>
@@ -730,4 +758,4 @@ http://opensource.org/licenses/ms-pl.html
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(ProjectRoot)tools\DotNetOpenAuth.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/TimespanSecondsEncoder.cs b/src/DotNetOpenAuth/Messaging/TimespanSecondsEncoder.cs
index cc3f7cc..3ad1bd8 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/TimespanSecondsEncoder.cs
+++ b/src/DotNetOpenAuth/Messaging/TimespanSecondsEncoder.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy {
+namespace DotNetOpenAuth.Messaging {
using System;
using System.Globalization;
using DotNetOpenAuth.Messaging.Reflection;
@@ -13,6 +13,12 @@ namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy {
/// Encodes and decodes the <see cref="TimeSpan"/> as an integer of total seconds.
/// </summary>
internal class TimespanSecondsEncoder : IMessagePartEncoder {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TimespanSecondsEncoder"/> class.
+ /// </summary>
+ internal TimespanSecondsEncoder() {
+ }
+
#region IMessagePartEncoder Members
/// <summary>
diff --git a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs
new file mode 100644
index 0000000..8f8f218
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------
+// <copyright file="AuthorizationServerDescription.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// A description of an OAuth WRAP Authorization Server.
+ /// </summary>
+ public class AuthorizationServerDescription {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthorizationServerDescription"/> class.
+ /// </summary>
+ public AuthorizationServerDescription() {
+ this.Version = Protocol.DefaultVersion;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthorizationServerDescription"/> class.
+ /// </summary>
+ /// <param name="endpointUrl">The endpoint URL of the Token Issuer.</param>
+ public AuthorizationServerDescription(Uri endpointUrl)
+ : this() {
+ this.EndpointUrl = endpointUrl;
+ }
+
+ /// <summary>
+ /// Gets or sets the endpoint URL of the Token Issuer.
+ /// </summary>
+ /// <value>The endpoint URL.</value>
+ public Uri EndpointUrl { get; set; }
+
+ /// <summary>
+ /// Gets or sets the version of the OAuth WRAP protocol to use with this Token Issuer.
+ /// </summary>
+ /// <value>The version.</value>
+ public Version Version { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs
new file mode 100644
index 0000000..3c2065f
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs
@@ -0,0 +1,52 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthWrapChannel.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The channel for the OAuth WRAP protocol.
+ /// </summary>
+ internal class OAuthWrapChannel : Channel {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthWrapChannel"/> class.
+ /// </summary>
+ internal OAuthWrapChannel()
+ : base(new OAuthWrapMessageFactory()) {
+ }
+
+ /// <summary>
+ /// Gets the protocol message that may be in the given HTTP response.
+ /// </summary>
+ /// <param name="response">The response that is anticipated to contain an protocol message.</param>
+ /// <returns>
+ /// The deserialized message parts, if found. Null otherwise.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown when the response is not valid.</exception>
+ protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Queues a message for sending in the response stream where the fields
+ /// are sent in the response stream in querystring style.
+ /// </summary>
+ /// <param name="response">The message to send as a response.</param>
+ /// <returns>
+ /// The pending user agent redirect based message to be sent as an HttpResponse.
+ /// </returns>
+ /// <remarks>
+ /// This method implements spec OAuth V1.0 section 5.3.
+ /// </remarks>
+ protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapMessageFactory.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapMessageFactory.cs
new file mode 100644
index 0000000..62cceb8
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapMessageFactory.cs
@@ -0,0 +1,107 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthWrapMessageFactory.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuthWrap.Messages;
+
+ /// <summary>
+ /// The message factory for OAuth WRAP messages.
+ /// </summary>
+ internal class OAuthWrapMessageFactory : IMessageFactory {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuthWrapMessageFactory"/> class.
+ /// </summary>
+ internal OAuthWrapMessageFactory() {
+ }
+
+ #region IMessageFactory Members
+
+ /// <summary>
+ /// Analyzes an incoming request message payload to discover what kind of
+ /// message is embedded in it and returns the type, or null if no match is found.
+ /// </summary>
+ /// <param name="recipient">The intended or actual recipient of the request message.</param>
+ /// <param name="fields">The name/value pairs that make up the message payload.</param>
+ /// <returns>
+ /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ public IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) {
+ Version version = Protocol.DefaultVersion;
+
+ if (fields.ContainsKey(Protocol.sa_consumer_key) && fields.ContainsKey(Protocol.sa_callback)) {
+ return new UserAuthorizationInUserAgentRequest(recipient.Location, version);
+ }
+
+ if (fields.ContainsKey(Protocol.sa_consumer_key) && fields.ContainsKey(Protocol.sa_delegation_code)) {
+ return new AccessTokenWithDelegationCodeRequest(recipient.Location, version);
+ }
+
+ if (fields.ContainsKey(Protocol.sa_name)) {
+ return new AccessTokenWithConsumerNamePasswordRequest(version);
+ }
+
+ if (fields.ContainsKey(Protocol.sa_username)) {
+ return new UserAuthorizationViaUsernamePasswordRequest(version);
+ }
+
+ if (fields.ContainsKey(Protocol.sa_saml)) {
+ return new AccessTokenWithSamlRequest(version);
+ }
+
+ if (fields.ContainsKey(Protocol.sa_delegation_code)) {
+ return new UserAuthorizationInUserAgentGrantedResponse(recipient.Location, version);
+ }
+
+ if (fields.ContainsKey(Protocol.sa_error_reason)) {
+ return new UserAuthorizationInUserAgentDeniedResponse(recipient.Location, version);
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Analyzes an incoming request message payload to discover what kind of
+ /// message is embedded in it and returns the type, or null if no match is found.
+ /// </summary>
+ /// <param name="request">The message that was sent as a request that resulted in the response.</param>
+ /// <param name="fields">The name/value pairs that make up the message payload.</param>
+ /// <returns>
+ /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ public IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) {
+ Version version = Protocol.DefaultVersion;
+
+ var accessTokenRequest = request as AccessTokenWithDelegationCodeRequest;
+ if (accessTokenRequest != null) {
+ if (fields.ContainsKey(Protocol.sa_token)) {
+ return new AccessTokenSuccessResponse(accessTokenRequest);
+ } else {
+ return new AccessTokenFailedResponse(accessTokenRequest);
+ }
+ }
+
+ var userAuthorization = request as UserAuthorizationViaUsernamePasswordRequest;
+ if (userAuthorization != null) {
+ if (fields.ContainsKey(Protocol.sa_delegation_code)) {
+ return new UserAuthorizationViaUsernamePasswordSuccessResponse(userAuthorization);
+ } else {
+ return new UserAuthorizationViaUsernamePasswordFailedResponse(userAuthorization);
+ }
+ }
+
+ return null;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/UriOrOutOfBandEncoding.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/UriOrOutOfBandEncoding.cs
new file mode 100644
index 0000000..2917cba
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/UriOrOutOfBandEncoding.cs
@@ -0,0 +1,83 @@
+//-----------------------------------------------------------------------
+// <copyright file="UriOrOutOfBandEncoding.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Reflection;
+
+ /// <summary>
+ /// An URI encoder that translates null <see cref="Uri"/> references as "out_of_band"
+ /// instead of an empty/missing argument.
+ /// </summary>
+ /// <remarks>
+ /// This class is functionality equivalent to the <see cref="DotNetOpenAuth.OAuth.ChannelElements.UriOrOobEncoding"/>
+ /// encoding element, except that instead of using "oob" for null Uri values,
+ /// "out_of_band" is used.
+ /// </remarks>
+ internal class UriOrOutOfBandEncoding : IMessagePartNullEncoder {
+ /// <summary>
+ /// The string constant "oob", used to indicate an out-of-band configuration.
+ /// </summary>
+ private const string OutOfBandConfiguration = "out_of_band";
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UriOrOutOfBandEncoding"/> class.
+ /// </summary>
+ public UriOrOutOfBandEncoding() {
+ }
+
+ #region IMessagePartNullEncoder Members
+
+ /// <summary>
+ /// Gets the string representation to include in a serialized message
+ /// when the message part has a <c>null</c> value.
+ /// </summary>
+ /// <value></value>
+ public string EncodedNullValue {
+ get { return OutOfBandConfiguration; }
+ }
+
+ #endregion
+
+ #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) {
+ ErrorUtilities.VerifyArgumentNotNull(value, "value");
+
+ Uri uriValue = (Uri)value;
+ return uriValue.AbsoluteUri;
+ }
+
+ /// <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) {
+ if (string.Equals(value, OutOfBandConfiguration, StringComparison.Ordinal)) {
+ return null;
+ } else {
+ return new Uri(value, UriKind.Absolute);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ConsumerBase.cs b/src/DotNetOpenAuth/OAuthWrap/ConsumerBase.cs
new file mode 100644
index 0000000..d45562d
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ConsumerBase.cs
@@ -0,0 +1,67 @@
+//-----------------------------------------------------------------------
+// <copyright file="ConsumerBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A base class for common OAuth WRAP Consumer behaviors.
+ /// </summary>
+ public class ConsumerBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ConsumerBase"/> class.
+ /// </summary>
+ /// <param name="tokenIssuer">The token issuer.</param>
+ protected ConsumerBase(AuthorizationServerDescription tokenIssuer) {
+ ErrorUtilities.VerifyArgumentNotNull(tokenIssuer, "tokenIssuer");
+ this.TokenIssuer = tokenIssuer;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ConsumerBase"/> class.
+ /// </summary>
+ /// <param name="tokenIssuerEndpoint">The token issuer endpoint.</param>
+ protected ConsumerBase(Uri tokenIssuerEndpoint)
+ : this(new AuthorizationServerDescription(tokenIssuerEndpoint)) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ConsumerBase"/> class.
+ /// </summary>
+ /// <param name="tokenIssuerEndpoint">The token issuer endpoint.</param>
+ protected ConsumerBase(string tokenIssuerEndpoint)
+ : this(new Uri(tokenIssuerEndpoint)) {
+ }
+
+ /// <summary>
+ /// Gets the token issuer.
+ /// </summary>
+ /// <value>The token issuer.</value>
+ public AuthorizationServerDescription TokenIssuer { get; private set; }
+
+ /// <summary>
+ /// Gets the channel.
+ /// </summary>
+ /// <value>The channel.</value>
+ public Channel Channel { get; private set; }
+
+ /// <summary>
+ /// Adds the necessary HTTP header to an HTTP request for protected resources
+ /// so that the Service Provider will allow the request through.
+ /// </summary>
+ /// <param name="request">The request for protected resources from the service provider.</param>
+ /// <param name="accessToken">The access token previously obtained from the Token Issuer.</param>
+ public static void AuthorizeRequest(HttpWebRequest request, string accessToken) {
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ request.Headers[HttpRequestHeader.Authorization] = Protocol.HttpAuthorizationScheme + " " + accessToken;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenFailedResponse.cs
new file mode 100644
index 0000000..dc0dd97
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenFailedResponse.cs
@@ -0,0 +1,50 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenFailedResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The direct response message that may contain the reason the access token
+ /// was NOT returned from the Token Issuer to the Consumer.
+ /// </summary>
+ internal class AccessTokenFailedResponse : MessageBase, IHttpDirectResponse {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenFailedResponse"/> class.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ internal AccessTokenFailedResponse(AccessTokenWithDelegationCodeRequest request)
+ : base(request) {
+ }
+
+ #region IHttpDirectResponse Members
+
+ /// <summary>
+ /// Gets the HTTP status code that the direct respones should be sent with.
+ /// </summary>
+ /// <value><see cref="HttpStatusCode.Unauthorized"/></value>
+ HttpStatusCode IHttpDirectResponse.HttpStatusCode {
+ get { return HttpStatusCode.Unauthorized; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets or sets the error reason.
+ /// </summary>
+ /// <value>
+ /// The reason for the failure. Among other values, it may be <c>null</c>
+ /// or expired_delegation_code.
+ /// </value>
+ [MessagePart(Protocol.sa_error_reason, IsRequired = false, AllowEmpty = true)]
+ internal string ErrorReason { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenSuccessResponse.cs
new file mode 100644
index 0000000..d38a2e1
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenSuccessResponse.cs
@@ -0,0 +1,46 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenSuccessResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The direct response message that contains the access token from the Token Issuer
+ /// to the Consumer.
+ /// </summary>
+ internal class AccessTokenSuccessResponse : MessageBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenSuccessResponse"/> class.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ internal AccessTokenSuccessResponse(AccessTokenWithDelegationCodeRequest request)
+ : base(request) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenSuccessResponse"/> class.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ internal AccessTokenSuccessResponse(AccessTokenWithConsumerNamePasswordRequest request)
+ : base(request) {
+ }
+
+ /// <summary>
+ /// Gets or sets the access token.
+ /// </summary>
+ /// <value>The token.</value>
+ [MessagePart(Protocol.sa_token, IsRequired = true, AllowEmpty = false)]
+ internal string Token { get; set; }
+
+ /// <summary>
+ /// Gets or sets the lifetime of the access token.
+ /// </summary>
+ /// <value>The lifetime.</value>
+ [MessagePart(Protocol.sa_token_expires_in, IsRequired = false, AllowEmpty = false, Encoder = typeof(TimespanSecondsEncoder))]
+ internal TimeSpan? Lifetime { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithConsumerNamePasswordRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithConsumerNamePasswordRequest.cs
new file mode 100644
index 0000000..605e27e
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithConsumerNamePasswordRequest.cs
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenWithConsumerNamePasswordRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A request for an access token for a consumer application that has its
+ /// own (non-user affiliated) consumer name and password.
+ /// </summary>
+ internal class AccessTokenWithConsumerNamePasswordRequest : MessageBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenWithConsumerNamePasswordRequest"/> class.
+ /// </summary>
+ /// <param name="version">The version.</param>
+ internal AccessTokenWithConsumerNamePasswordRequest(Version version)
+ : base(version) {
+ }
+
+ /// <summary>
+ /// Gets or sets the account name.
+ /// </summary>
+ /// <value>The consumer name.</value>
+ [MessagePart(Protocol.sa_name, IsRequired = true, AllowEmpty = false)]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the account password.
+ /// </summary>
+ /// <value>The password.</value>
+ [MessagePart(Protocol.sa_password, IsRequired = true, AllowEmpty = true)]
+ public string Password { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithDelegationCodeRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithDelegationCodeRequest.cs
new file mode 100644
index 0000000..4374657
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithDelegationCodeRequest.cs
@@ -0,0 +1,79 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenWithDelegationCodeRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuthWrap.ChannelElements;
+
+ /// <summary>
+ /// A message sent by the Consumer directly to the Token Issuer to exchange
+ /// the delegation code for an Access Token.
+ /// </summary>
+ internal class AccessTokenWithDelegationCodeRequest : MessageBase, IDirectedProtocolMessage {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenWithDelegationCodeRequest"/> class.
+ /// </summary>
+ /// <param name="tokenIssuer">The token issuer.</param>
+ /// <param name="version">The version.</param>
+ internal AccessTokenWithDelegationCodeRequest(Uri tokenIssuer, Version version)
+ : base(version, MessageTransport.Direct, tokenIssuer) {
+ this.HttpMethods = HttpDeliveryMethods.PostRequest;
+ }
+
+ /// <summary>
+ /// Gets or sets the consumer key.
+ /// </summary>
+ /// <value>The consumer key.</value>
+ [MessagePart(Protocol.sa_consumer_key, IsRequired = true, AllowEmpty = false)]
+ internal string ConsumerKey { get; set; }
+
+ /// <summary>
+ /// Gets or sets the consumer secret.
+ /// </summary>
+ /// <value>The consumer secret.</value>
+ [MessagePart(Protocol.sa_consumer_secret, IsRequired = true, AllowEmpty = false)]
+ internal string ConsumerSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the delegation code.
+ /// </summary>
+ /// <value>The delegation code.</value>
+ [MessagePart(Protocol.sa_delegation_code, IsRequired = true, AllowEmpty = false)]
+ internal string DelegationCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the callback URL.
+ /// </summary>
+ /// <value>
+ /// An absolute URL to which the Token Issuer will redirect the User back after
+ /// the user has approved the authorization request.
+ /// </value>
+ /// <remarks>
+ /// Consumers which are unable to receive callbacks MUST use <c>null</c> to indicate it
+ /// will receive the Verification Code out of band.
+ /// </remarks>
+ [MessagePart(Protocol.sa_callback, IsRequired = true, AllowEmpty = false, Encoder = typeof(UriOrOutOfBandEncoding))]
+ internal Uri Callback { get; set; }
+
+ /// <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(this.Recipient.IsTransportSecure(), SimpleAuthStrings.HttpsRequired);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithSamlRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithSamlRequest.cs
new file mode 100644
index 0000000..1a610ed
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/AccessTokenWithSamlRequest.cs
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessTokenWithSamlRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A request for an access token for a consumer application that can
+ /// issue a SAML assertion to prove its identity.
+ /// </summary>
+ internal class AccessTokenWithSamlRequest : MessageBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessTokenWithSamlRequest"/> class.
+ /// </summary>
+ /// <param name="version">The version.</param>
+ internal AccessTokenWithSamlRequest(Version version)
+ : base(version) {
+ }
+
+ /// <summary>
+ /// Gets or sets the SAML token.
+ /// </summary>
+ /// <value>A SAML token serialized as an XML document.</value>
+ [MessagePart(Protocol.sa_saml, IsRequired = true, AllowEmpty = false)]
+ public string Saml { get; set; }
+
+ /// <summary>
+ /// Gets or sets the SWT.
+ /// </summary>
+ /// <value>The SWT (TODO: what is that?).</value>
+ /// <remarks>
+ /// The spec says that the SWT parameter is required for certain scenarios,
+ /// so we mark it as optional here since the scenario may or may not apply.
+ /// </remarks>
+ [MessagePart(Protocol.sa_swt, IsRequired = false, AllowEmpty = false)]
+ public string Swt { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
new file mode 100644
index 0000000..ad4612a
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
@@ -0,0 +1,204 @@
+//-----------------------------------------------------------------------
+// <copyright file="MessageBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using System.Collections.Generic;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A common message base class for OAuth WRAP messages.
+ /// </summary>
+ public class MessageBase : IDirectedProtocolMessage, IDirectResponseProtocolMessage {
+ /// <summary>
+ /// A dictionary to contain extra message data.
+ /// </summary>
+ private Dictionary<string, string> extraData = new Dictionary<string, string>();
+
+ /// <summary>
+ /// The originating request.
+ /// </summary>
+ private IDirectedProtocolMessage originatingRequest;
+
+ /// <summary>
+ /// The backing field for the <see cref="IMessage.Version"/> property.
+ /// </summary>
+ private Version version;
+
+ /// <summary>
+ /// A value indicating whether this message is a direct or indirect message.
+ /// </summary>
+ private MessageTransport messageTransport;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessageBase"/> class
+ /// that is used for direct response messages.
+ /// </summary>
+ /// <param name="version">The version.</param>
+ protected MessageBase(Version version) {
+ ErrorUtilities.VerifyArgumentNotNull(version, "version");
+ this.messageTransport = MessageTransport.Direct;
+ this.version = version;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessageBase"/> class.
+ /// </summary>
+ /// <param name="request">The originating request.</param>
+ protected MessageBase(IDirectedProtocolMessage request) {
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ this.originatingRequest = request;
+ this.messageTransport = MessageTransport.Direct;
+ this.version = request.Version;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessageBase"/> class
+ /// that is used for directed messages.
+ /// </summary>
+ /// <param name="version">The version.</param>
+ /// <param name="messageTransport">The message transport.</param>
+ /// <param name="recipient">The recipient.</param>
+ protected MessageBase(Version version, MessageTransport messageTransport, Uri recipient) {
+ ErrorUtilities.VerifyArgumentNotNull(version, "version");
+ ErrorUtilities.VerifyArgumentNotNull(recipient, "recipient");
+
+ this.version = version;
+ this.messageTransport = messageTransport;
+ this.Recipient = recipient;
+ this.HttpMethods = HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.PostRequest;
+ }
+
+ #region IMessage Properties
+
+ /// <summary>
+ /// Gets the version of the protocol or extension this message is prepared to implement.
+ /// </summary>
+ /// <remarks>
+ /// Implementations of this interface should ensure that this property never returns null.
+ /// </remarks>
+ Version IMessage.Version {
+ get { return this.version; }
+ }
+
+ /// <summary>
+ /// Gets the extra, non-standard Protocol parameters included in the message.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// Implementations of this interface should ensure that this property never returns null.
+ /// </remarks>
+ public IDictionary<string, string> ExtraData {
+ get { return this.extraData; }
+ }
+
+ #endregion
+
+ #region IProtocolMessage Members
+
+ /// <summary>
+ /// Gets the level of protection this message requires.
+ /// </summary>
+ /// <value><see cref="MessageProtections.None"/></value>
+ MessageProtections IProtocolMessage.RequiredProtection {
+ get { return MessageProtections.None; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this is a direct or indirect message.
+ /// </summary>
+ /// <value></value>
+ MessageTransport IProtocolMessage.Transport {
+ get { return this.messageTransport; }
+ }
+
+ #endregion
+
+ #region IDirectedProtocolMessage Members
+
+ /// <summary>
+ /// Gets the preferred method of transport for the message.
+ /// </summary>
+ /// <remarks>
+ /// For indirect messages this will likely be GET+POST, which both can be simulated in the user agent:
+ /// the GET with a simple 301 Redirect, and the POST with an HTML form in the response with javascript
+ /// to automate submission.
+ /// </remarks>
+ HttpDeliveryMethods IDirectedProtocolMessage.HttpMethods {
+ get { return this.HttpMethods; }
+ }
+
+ /// <summary>
+ /// Gets the URL of the intended receiver of this message.
+ /// </summary>
+ Uri IDirectedProtocolMessage.Recipient {
+ get { return this.Recipient; }
+ }
+
+ #endregion
+
+ #region IDirectResponseProtocolMessage Members
+
+ /// <summary>
+ /// Gets the originating request message that caused this response to be formed.
+ /// </summary>
+ IDirectedProtocolMessage IDirectResponseProtocolMessage.OriginatingRequest {
+ get { return this.originatingRequest; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets or sets the preferred method of transport for the message.
+ /// </summary>
+ /// <remarks>
+ /// For indirect messages this will likely be GET+POST, which both can be simulated in the user agent:
+ /// the GET with a simple 301 Redirect, and the POST with an HTML form in the response with javascript
+ /// to automate submission.
+ /// </remarks>
+ protected HttpDeliveryMethods HttpMethods { get; set; }
+
+ /// <summary>
+ /// Gets the URL of the intended receiver of this message.
+ /// </summary>
+ protected Uri Recipient { get; private set; }
+
+ #region IMessage Methods
+
+ /// <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>
+ void IMessage.EnsureValidMessage() {
+ this.EnsureValidMessage();
+ }
+
+ #endregion
+
+ /// <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 virtual void EnsureValidMessage() {
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentDeniedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentDeniedResponse.cs
new file mode 100644
index 0000000..44268c5
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentDeniedResponse.cs
@@ -0,0 +1,44 @@
+//-----------------------------------------------------------------------
+// <copyright file="UserAuthorizationInUserAgentDeniedResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The message the Token Issuer MAY use to send the user back to the Consumer
+ /// following the user's denial to grant Consumer with authorization of
+ /// access to requested resources.
+ /// </summary>
+ public class UserAuthorizationInUserAgentDeniedResponse : MessageBase, IDirectedProtocolMessage {
+ /// <summary>
+ /// A constant parameter that indicates the user refused to grant the requested authorization.
+ /// </summary>
+ [MessagePart(Protocol.sa_error_reason, IsRequired = true)]
+ private const string ErrorReason = Protocol.sa_error_reason_denied;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserAuthorizationInUserAgentDeniedResponse"/> class.
+ /// </summary>
+ /// <param name="consumerCallback">The recipient of the message.</param>
+ /// <param name="version">The version.</param>
+ internal UserAuthorizationInUserAgentDeniedResponse(Uri consumerCallback, Version version) :
+ base(version, MessageTransport.Indirect, consumerCallback) {
+ }
+
+ /// <summary>
+ /// Gets or sets the state of the consumer.
+ /// </summary>
+ /// <value>
+ /// An opaque value that Consumers can use to maintain state associated with this request.
+ /// </value>
+ /// <remarks>
+ /// If this value is present, the Token Issuer MUST return it to the Consumer's callback URL.
+ /// </remarks>
+ [MessagePart(Protocol.sa_consumer_state, IsRequired = false, AllowEmpty = true)]
+ public string ConsumerState { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentGrantedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentGrantedResponse.cs
new file mode 100644
index 0000000..ae43d5c
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentGrantedResponse.cs
@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------
+// <copyright file="UserAuthorizationInUserAgentGrantedResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The message sent by the Token Issuer to the Consumer via the user agent
+ /// to indicate that user authorization was granted, and to return the user
+ /// to the Consumer where they started their experience.
+ /// </summary>
+ internal class UserAuthorizationInUserAgentGrantedResponse : MessageBase, IDirectedProtocolMessage {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserAuthorizationInUserAgentGrantedResponse"/> class.
+ /// </summary>
+ /// <param name="consumerCallback">The consumer callback.</param>
+ /// <param name="version">The protocol version.</param>
+ internal UserAuthorizationInUserAgentGrantedResponse(Uri consumerCallback, Version version)
+ : base(version, MessageTransport.Indirect, consumerCallback) {
+ }
+
+ /// <summary>
+ /// Gets or sets the delegation code.
+ /// </summary>
+ /// <value>
+ /// The long-lived credential assigned by the Token Issuer to this Consumer for
+ /// use in accessing the authorizing user's protected resources.
+ /// </value>
+ [MessagePart(Protocol.sa_delegation_code, IsRequired = true, AllowEmpty = true)]
+ internal string DelegationCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the state of the consumer as provided by the consumer in the
+ /// authorization request.
+ /// </summary>
+ /// <value>The state of the consumer.</value>
+ /// <remarks>
+ /// REQUIRED if the Consumer sent the value in the <see cref="UserAuthorizationRequestInUserAgentRequest"/>.
+ /// </remarks>
+ [MessagePart(Protocol.sa_consumer_state, IsRequired = false, AllowEmpty = true)]
+ internal string ConsumerState { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentRequest.cs
new file mode 100644
index 0000000..7e5191f
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationInUserAgentRequest.cs
@@ -0,0 +1,60 @@
+//-----------------------------------------------------------------------
+// <copyright file="UserAuthorizationInUserAgentRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuthWrap.ChannelElements;
+
+ /// <summary>
+ /// A message sent by the Consumer to the Token Issuer via the user agent
+ /// to get the Token Issuer to obtain authorization from the user and prepare
+ /// to issue an access token to the Consumer if permission is granted.
+ /// </summary>
+ public class UserAuthorizationInUserAgentRequest : MessageBase, IDirectedProtocolMessage {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserAuthorizationInUserAgentRequest"/> class.
+ /// </summary>
+ /// <param name="tokenIssuer">The token issuer URL to direct the user to.</param>
+ /// <param name="version">The protocol version.</param>
+ public UserAuthorizationInUserAgentRequest(Uri tokenIssuer, Version version)
+ : base(version, MessageTransport.Indirect, tokenIssuer) {
+ }
+
+ /// <summary>
+ /// Gets or sets the consumer key.
+ /// </summary>
+ /// <value>The consumer key.</value>
+ [MessagePart(Protocol.sa_consumer_key, IsRequired = true, AllowEmpty = false)]
+ public string ConsumerKey { get; set; }
+
+ /// <summary>
+ /// Gets or sets the callback URL.
+ /// </summary>
+ /// <value>
+ /// An absolute URL to which the Token Issuer will redirect the User back after
+ /// the user has approved the authorization request.
+ /// </value>
+ /// <remarks>
+ /// Consumers which are unable to receive callbacks MUST use <c>null</c> to indicate it
+ /// will receive the Delegation Code out of band.
+ /// </remarks>
+ [MessagePart(Protocol.sa_callback, IsRequired = true, AllowEmpty = false, Encoder = typeof(UriOrOutOfBandEncoding))]
+ public Uri Callback { get; set; }
+
+ /// <summary>
+ /// Gets or sets the state of the consumer.
+ /// </summary>
+ /// <value>
+ /// An opaque value that Consumers can use to maintain state associated with this request.
+ /// </value>
+ /// <remarks>
+ /// If this value is present, the Token Issuer MUST return it to the Consumer's callback URL.
+ /// </remarks>
+ [MessagePart(Protocol.sa_consumer_state, IsRequired = false, AllowEmpty = true)]
+ public string ConsumerState { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordFailedResponse.cs
new file mode 100644
index 0000000..4a6fdf4
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordFailedResponse.cs
@@ -0,0 +1,51 @@
+//-----------------------------------------------------------------------
+// <copyright file="UserAuthorizationViaUsernamePasswordFailedResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A response from the Token Issuer to the Consumer to indicate that a
+ /// request for a delegation code failed, probably due to an invalid
+ /// username and password.
+ /// </summary>
+ internal class UserAuthorizationViaUsernamePasswordFailedResponse : MessageBase, IHttpDirectResponse {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserAuthorizationViaUsernamePasswordFailedResponse"/> class.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ internal UserAuthorizationViaUsernamePasswordFailedResponse(UserAuthorizationViaUsernamePasswordRequest request)
+ : base(request) {
+ }
+
+ #region IHttpDirectResponse Members
+
+ /// <summary>
+ /// Gets the HTTP status code that the direct respones should be sent with.
+ /// </summary>
+ /// <value><see cref="HttpStatusCode.Unauthorized"/></value>
+ HttpStatusCode IHttpDirectResponse.HttpStatusCode {
+ get { return HttpStatusCode.Unauthorized; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets or sets the error reason.
+ /// </summary>
+ /// <value>
+ /// The reason for the failure. Among other values, it may be <c>null</c>
+ /// or invalid_user_credentials.
+ /// </value>
+ [MessagePart(Protocol.sa_error_reason, IsRequired = false, AllowEmpty = true)]
+ internal string ErrorReason { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordRequest.cs
new file mode 100644
index 0000000..cf01940
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordRequest.cs
@@ -0,0 +1,76 @@
+//-----------------------------------------------------------------------
+// <copyright file="UserAuthorizationViaUsernamePasswordRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A request for a delegation code in exchnage for a user's confidential
+ /// username and password.
+ /// </summary>
+ /// <remarks>
+ /// After this request has been sent, the consumer application MUST discard
+ /// the confidential user credentials and use the delegation code going forward.
+ /// </remarks>
+ internal class UserAuthorizationViaUsernamePasswordRequest : MessageBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserAuthorizationViaUsernamePasswordRequest"/> class.
+ /// </summary>
+ /// <param name="version">The version.</param>
+ internal UserAuthorizationViaUsernamePasswordRequest(Version version)
+ : base(version) {
+ }
+
+ /// <summary>
+ /// Gets or sets the consumer key.
+ /// </summary>
+ /// <value>The consumer key.</value>
+ [MessagePart(Protocol.sa_consumer_key, IsRequired = true, AllowEmpty = false)]
+ internal string ConsumerKey { get; set; }
+
+ /// <summary>
+ /// Gets or sets the consumer secret.
+ /// </summary>
+ /// <value>The consumer secret.</value>
+ [MessagePart(Protocol.sa_consumer_secret, IsRequired = true, AllowEmpty = false)]
+ internal string ConsumerSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the username.
+ /// </summary>
+ /// <value>The name of the user.</value>
+ [MessagePart(Protocol.sa_username, IsRequired = true, AllowEmpty = false)]
+ internal string UserName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user's password.
+ /// </summary>
+ /// <value>The password.</value>
+ [MessagePart(Protocol.sa_password, IsRequired = true, AllowEmpty = false)]
+ internal string Password { get; set; }
+
+ /// <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(this.Recipient.IsTransportSecure(), SimpleAuthStrings.HttpsRequired);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordSuccessResponse.cs
new file mode 100644
index 0000000..11c9a20
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UserAuthorizationViaUsernamePasswordSuccessResponse.cs
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------
+// <copyright file="UserAuthorizationViaUsernamePasswordSuccessResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A response from the Token Issuer to the Consumer containing a delegation code
+ /// that the Consumer should use to obtain an access token.
+ /// </summary>
+ internal class UserAuthorizationViaUsernamePasswordSuccessResponse : MessageBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserAuthorizationViaUsernamePasswordSuccessResponse"/> class.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ internal UserAuthorizationViaUsernamePasswordSuccessResponse(UserAuthorizationViaUsernamePasswordRequest request)
+ : base(request) {
+ }
+
+ /// <summary>
+ /// Gets or sets the delegation code.
+ /// </summary>
+ /// <value>
+ /// The long-lived credential assigned by the Token Issuer to this Consumer for
+ /// use in accessing the authorizing user's protected resources.
+ /// </value>
+ [MessagePart(Protocol.sa_delegation_code, IsRequired = true, AllowEmpty = true)]
+ internal string DelegationCode { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/Protocol.cs b/src/DotNetOpenAuth/OAuthWrap/Protocol.cs
new file mode 100644
index 0000000..59d77c1
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/Protocol.cs
@@ -0,0 +1,105 @@
+// <auto-generated/> // disable StyleCop on this file
+//-----------------------------------------------------------------------
+// <copyright file="Protocol.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap {
+ using System;
+
+ /// <summary>
+ /// Protocol constants for OAuth WRAP.
+ /// </summary>
+ internal class Protocol {
+ /// <summary>
+ /// The default (latest) version of the OAuth WRAP protocol.
+ /// </summary>
+ internal static readonly Version DefaultVersion = V10;
+
+ /// <summary>
+ /// The initial (1.0) version of OAuth WRAP.
+ /// </summary>
+ internal static readonly Version V10 = new Version(1, 0);
+
+ /// <summary>
+ /// The HTTP authorization scheme "SimpleAPIAuth";
+ /// </summary>
+ internal const string HttpAuthorizationScheme = "SimpleAPIAuth";
+
+ /// <summary>
+ /// The "sa_consumer_state" string.
+ /// </summary>
+ internal const string sa_consumer_state = "sa_consumer_state";
+
+ /// <summary>
+ /// The "sa_callback" string.
+ /// </summary>
+ internal const string sa_callback = "sa_callback";
+
+ /// <summary>
+ /// The "sa_consumer_key" string.
+ /// </summary>
+ internal const string sa_consumer_key = "sa_consumer_key";
+
+ /// <summary>
+ /// The "sa_consumer_secret" string.
+ /// </summary>
+ internal const string sa_consumer_secret = "sa_consumer_secret";
+
+ /// <summary>
+ /// The "sa_delegation_code" string.
+ /// </summary>
+ internal const string sa_delegation_code = "sa_delegation_code";
+
+ /// <summary>
+ /// The "sa_error_reason" string.
+ /// </summary>
+ internal const string sa_error_reason = "sa_error_reason";
+
+ /// <summary>
+ /// The "user_denied" string.
+ /// </summary>
+ internal const string sa_error_reason_denied = "user_denied";
+
+ /// <summary>
+ /// The "sa_token" string.
+ /// </summary>
+ internal const string sa_token = "sa_token";
+
+ /// <summary>
+ /// The "sa_token_expires_in" string.
+ /// </summary>
+ internal const string sa_token_expires_in = "sa_token_expires_in";
+
+ /// <summary>
+ /// The "expired_delegation_code" string.
+ /// </summary>
+ internal const string expired_delegation_code = "expired_delegation_code";
+
+ /// <summary>
+ /// The "sa_username" string.
+ /// </summary>
+ internal const string sa_username = "sa_username";
+
+ /// <summary>
+ /// The "sa_password" string.
+ /// </summary>
+ internal const string sa_password = "sa_password";
+
+ /// <summary>
+ /// The "sa_name" string.
+ /// </summary>
+ internal const string sa_name = "sa_name";
+
+ /// <summary>
+ /// The "sa_SAML" string.
+ /// </summary>
+ internal const string sa_saml = "sa_SAML";
+
+ /// <summary>
+ /// The "sa_SWT" string.
+ /// </summary>
+ internal const string sa_swt = "sa_SWT";
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.Designer.cs b/src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.Designer.cs
new file mode 100644
index 0000000..8cf74ed
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30118.0
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap {
+ 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 SimpleAuthStrings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal SimpleAuthStrings() {
+ }
+
+ /// <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.OAuthWrap.SimpleAuthStrings", typeof(SimpleAuthStrings).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 This message can only be sent over HTTPS..
+ /// </summary>
+ internal static string HttpsRequired {
+ get {
+ return ResourceManager.GetString("HttpsRequired", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.resx b/src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.resx
new file mode 100644
index 0000000..b8a8d62
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/SimpleAuthStrings.resx
@@ -0,0 +1,123 @@
+<?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="HttpsRequired" xml:space="preserve">
+ <value>This message can only be sent over HTTPS.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth/OAuthWrap/WebConsumer.cs b/src/DotNetOpenAuth/OAuthWrap/WebConsumer.cs
new file mode 100644
index 0000000..3470b62
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/WebConsumer.cs
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------
+// <copyright file="WebConsumer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuthWrap.Messages;
+
+ /// <summary>
+ /// An OAuth WRAP consumer designed for web applications.
+ /// </summary>
+ public class WebConsumer : ConsumerBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebConsumer"/> class.
+ /// </summary>
+ /// <param name="tokenIssuer">The token issuer.</param>
+ public WebConsumer(AuthorizationServerDescription tokenIssuer)
+ : base(tokenIssuer) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebConsumer"/> class.
+ /// </summary>
+ /// <param name="tokenIssuerEndpoint">The token issuer endpoint.</param>
+ public WebConsumer(Uri tokenIssuerEndpoint)
+ : base(tokenIssuerEndpoint) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WebConsumer"/> class.
+ /// </summary>
+ /// <param name="tokenIssuerEndpoint">The token issuer endpoint.</param>
+ public WebConsumer(string tokenIssuerEndpoint)
+ : base(tokenIssuerEndpoint) {
+ }
+
+ public UserAuthorizationInUserAgentRequest PrepareRequestUserAuthorization(string consumerKey) {
+ var request = new UserAuthorizationInUserAgentRequest(this.TokenIssuer.EndpointUrl, this.TokenIssuer.Version);
+ request.ConsumerKey = consumerKey;
+ request.Callback = this.Channel.GetRequestFromContext().UrlBeforeRewriting;
+ return request;
+ }
+
+ public IDirectedProtocolMessage ProcessUserAuthorization() {
+ return this.ProcessUserAuthorization(this.Channel.GetRequestFromContext());
+ }
+
+ public IDirectedProtocolMessage ProcessUserAuthorization(HttpRequestInfo request) {
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ IDirectedProtocolMessage message = this.Channel.ReadFromRequest();
+ if (message != null) {
+ ErrorUtilities.VerifyProtocol(
+ message is UserAuthorizationInUserAgentGrantedResponse || message is UserAuthorizationInUserAgentDeniedResponse,
+ MessagingStrings.UnexpectedMessageReceivedOfMany);
+ }
+ return message;
+ }
+ }
+}