diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2011-07-01 16:49:44 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2011-07-01 16:49:44 -0700 |
commit | b6f7a18b949acb4346754ae47fb07424076a3cd0 (patch) | |
tree | 4c23cb2b8174f3288cb0b787cff4c6ac432c6bef /src/DotNetOpenAuth.OAuth/OAuth/Messages | |
parent | f16525005555b86151b7a1c741aa29550635108a (diff) | |
download | DotNetOpenAuth-b6f7a18b949acb4346754ae47fb07424076a3cd0.zip DotNetOpenAuth-b6f7a18b949acb4346754ae47fb07424076a3cd0.tar.gz DotNetOpenAuth-b6f7a18b949acb4346754ae47fb07424076a3cd0.tar.bz2 |
First pass at dividing DotNetOpenAuth features into separate assemblies.
Nothing compiles at this point.
Diffstat (limited to 'src/DotNetOpenAuth.OAuth/OAuth/Messages')
12 files changed, 1154 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs new file mode 100644 index 0000000..f3231f0 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AccessProtectedResourceRequest.cs @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------- +// <copyright file="AccessProtectedResourceRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A message attached to a request for protected resources that provides the necessary + /// credentials to be granted access to those resources. + /// </summary> + public class AccessProtectedResourceRequest : SignedMessageBase, ITokenContainingMessage, IMessageWithBinaryData { + /// <summary> + /// A store for the binary data that is carried in the message. + /// </summary> + private List<MultipartPostPart> binaryData = new List<MultipartPostPart>(); + + /// <summary> + /// Initializes a new instance of the <see cref="AccessProtectedResourceRequest"/> class. + /// </summary> + /// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param> + /// <param name="version">The OAuth version.</param> + protected internal AccessProtectedResourceRequest(MessageReceivingEndpoint serviceProvider, Version version) + : base(MessageTransport.Direct, serviceProvider, version) { + } + + /// <summary> + /// Gets or sets the Token. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "This property IS accessible by a different name.")] + string ITokenContainingMessage.Token { + get { return this.AccessToken; } + set { this.AccessToken = value; } + } + + /// <summary> + /// Gets or sets the Access Token. + /// </summary> + /// <remarks> + /// In addition to just allowing OAuth to verify a valid message, + /// this property is useful on the Service Provider to verify that the access token + /// has proper authorization for the resource being requested, and to know the + /// context around which user provided the authorization. + /// </remarks> + [MessagePart("oauth_token", IsRequired = true)] + public string AccessToken { get; set; } + + #region IMessageWithBinaryData Members + + /// <summary> + /// Gets the parts of the message that carry binary data. + /// </summary> + /// <value>A list of parts. Never null.</value> + public IList<MultipartPostPart> BinaryData { + get { return this.binaryData; } + } + + /// <summary> + /// Gets a value indicating whether this message should be sent as multi-part POST. + /// </summary> + public bool SendAsMultipart { + get { return this.HttpMethod == "POST" && this.BinaryData.Count > 0; } + } + + #endregion + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/AuthorizedTokenRequest.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AuthorizedTokenRequest.cs new file mode 100644 index 0000000..02c6c1d --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AuthorizedTokenRequest.cs @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthorizedTokenRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Globalization; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A direct message sent by the Consumer to exchange an authorized Request Token + /// for an Access Token and Token Secret. + /// </summary> + /// <remarks> + /// The class is sealed because the OAuth spec forbids adding parameters to this message. + /// </remarks> + public sealed class AuthorizedTokenRequest : SignedMessageBase, ITokenContainingMessage { + /// <summary> + /// Initializes a new instance of the <see cref="AuthorizedTokenRequest"/> class. + /// </summary> + /// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param> + /// <param name="version">The OAuth version.</param> + internal AuthorizedTokenRequest(MessageReceivingEndpoint serviceProvider, Version version) + : base(MessageTransport.Direct, serviceProvider, version) { + } + + /// <summary> + /// Gets or sets the Token. + /// </summary> + string ITokenContainingMessage.Token { + get { return this.RequestToken; } + set { this.RequestToken = value; } + } + + /// <summary> + /// Gets or sets the verification code received by the Consumer from the Service Provider + /// in the <see cref="UserAuthorizationResponse.VerificationCode"/> property. + /// </summary> + [MessagePart("oauth_verifier", IsRequired = true, AllowEmpty = false, MinVersion = Protocol.V10aVersion)] + public string VerificationCode { get; set; } + + /// <summary> + /// Gets or sets the authorized Request Token used to obtain authorization. + /// </summary> + [MessagePart("oauth_token", IsRequired = true)] + internal string RequestToken { get; set; } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + protected override void EnsureValidMessage() { + base.EnsureValidMessage(); + + if (this.ExtraData.Count > 0) { + throw new ProtocolException(string.Format(CultureInfo.CurrentCulture, OAuthStrings.MessageNotAllowedExtraParameters, GetType().Name)); + } + } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/AuthorizedTokenResponse.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AuthorizedTokenResponse.cs new file mode 100644 index 0000000..0b14819 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/AuthorizedTokenResponse.cs @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthorizedTokenResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A direct message sent from Service Provider to Consumer in response to + /// a Consumer's <see cref="AuthorizedTokenRequest"/> request. + /// </summary> + public class AuthorizedTokenResponse : MessageBase, ITokenSecretContainingMessage { + /// <summary> + /// Initializes a new instance of the <see cref="AuthorizedTokenResponse"/> class. + /// </summary> + /// <param name="originatingRequest">The originating request.</param> + protected internal AuthorizedTokenResponse(AuthorizedTokenRequest originatingRequest) + : base(MessageProtections.None, originatingRequest, originatingRequest.Version) { + } + + /// <summary> + /// Gets or sets the Access Token assigned by the Service Provider. + /// </summary> + [MessagePart("oauth_token", IsRequired = true)] + public string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the Request or Access Token. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "This property IS accessible by a different name.")] + string ITokenContainingMessage.Token { + get { return this.AccessToken; } + set { this.AccessToken = value; } + } + + /// <summary> + /// Gets or sets the Request or Access Token secret. + /// </summary> + string ITokenSecretContainingMessage.TokenSecret { + get { return this.TokenSecret; } + set { this.TokenSecret = value; } + } + + /// <summary> + /// Gets the extra, non-OAuth parameters that will be included in the message. + /// </summary> + public new IDictionary<string, string> ExtraData { + get { return base.ExtraData; } + } + + /// <summary> + /// Gets or sets the Token Secret. + /// </summary> + [MessagePart("oauth_token_secret", IsRequired = true)] + protected internal string TokenSecret { get; set; } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/ITokenContainingMessage.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/ITokenContainingMessage.cs new file mode 100644 index 0000000..832b754 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/ITokenContainingMessage.cs @@ -0,0 +1,17 @@ +//----------------------------------------------------------------------- +// <copyright file="ITokenContainingMessage.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + /// <summary> + /// An interface implemented by all OAuth messages that have a request or access token property. + /// </summary> + public interface ITokenContainingMessage { + /// <summary> + /// Gets or sets the Request or Access Token. + /// </summary> + string Token { get; set; } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/ITokenSecretContainingMessage.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/ITokenSecretContainingMessage.cs new file mode 100644 index 0000000..95809ec --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/ITokenSecretContainingMessage.cs @@ -0,0 +1,17 @@ +//----------------------------------------------------------------------- +// <copyright file="ITokenSecretContainingMessage.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + /// <summary> + /// An interface implemented by all OAuth messages that have a request or access token and secret properties. + /// </summary> + public interface ITokenSecretContainingMessage : ITokenContainingMessage { + /// <summary> + /// Gets or sets the Request or Access Token secret. + /// </summary> + string TokenSecret { get; set; } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBase.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBase.cs new file mode 100644 index 0000000..1a0ba23 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/MessageBase.cs @@ -0,0 +1,281 @@ +//----------------------------------------------------------------------- +// <copyright file="MessageBase.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.Messaging.Reflection; + using DotNetOpenAuth.OAuth.ChannelElements; + + /// <summary> + /// A base class for all OAuth messages. + /// </summary> + [Serializable] + public abstract class MessageBase : IDirectedProtocolMessage, IDirectResponseProtocolMessage { + /// <summary> + /// A store for extra name/value data pairs that are attached to this message. + /// </summary> + private Dictionary<string, string> extraData = new Dictionary<string, string>(); + + /// <summary> + /// Gets a value indicating whether signing this message is required. + /// </summary> + private MessageProtections protectionRequired; + + /// <summary> + /// Gets a value indicating whether this is a direct or indirect message. + /// </summary> + private MessageTransport transport; + + /// <summary> + /// The URI to the remote endpoint to send this message to. + /// </summary> + private MessageReceivingEndpoint recipient; + + /// <summary> + /// Backing store for the <see cref="OriginatingRequest"/> properties. + /// </summary> + private IDirectedProtocolMessage originatingRequest; + + /// <summary> + /// Backing store for the <see cref="Incoming"/> properties. + /// </summary> + private bool incoming; + +#if DEBUG + /// <summary> + /// Initializes static members of the <see cref="MessageBase"/> class. + /// </summary> + static MessageBase() { + LowSecurityMode = true; + } +#endif + + /// <summary> + /// Initializes a new instance of the <see cref="MessageBase"/> class for direct response messages. + /// </summary> + /// <param name="protectionRequired">The level of protection the message requires.</param> + /// <param name="originatingRequest">The request that asked for this direct response.</param> + /// <param name="version">The OAuth version.</param> + protected MessageBase(MessageProtections protectionRequired, IDirectedProtocolMessage originatingRequest, Version version) { + Contract.Requires<ArgumentNullException>(originatingRequest != null); + Contract.Requires<ArgumentNullException>(version != null); + + this.protectionRequired = protectionRequired; + this.transport = MessageTransport.Direct; + this.originatingRequest = originatingRequest; + this.Version = version; + } + + /// <summary> + /// Initializes a new instance of the <see cref="MessageBase"/> class for direct requests or indirect messages. + /// </summary> + /// <param name="protectionRequired">The level of protection the message requires.</param> + /// <param name="transport">A value indicating whether this message requires a direct or indirect transport.</param> + /// <param name="recipient">The URI that a directed message will be delivered to.</param> + /// <param name="version">The OAuth version.</param> + protected MessageBase(MessageProtections protectionRequired, MessageTransport transport, MessageReceivingEndpoint recipient, Version version) { + Contract.Requires<ArgumentNullException>(recipient != null); + Contract.Requires<ArgumentNullException>(version != null); + + this.protectionRequired = protectionRequired; + this.transport = transport; + this.recipient = recipient; + this.Version = version; + } + + #region IProtocolMessage Properties + + /// <summary> + /// Gets the version of the protocol this message is prepared to implement. + /// </summary> + Version IMessage.Version { + get { return this.Version; } + } + + /// <summary> + /// Gets the level of protection this message requires. + /// </summary> + MessageProtections IProtocolMessage.RequiredProtection { + get { return this.RequiredProtection; } + } + + /// <summary> + /// Gets a value indicating whether this is a direct or indirect message. + /// </summary> + MessageTransport IProtocolMessage.Transport { + get { return this.Transport; } + } + + /// <summary> + /// Gets the dictionary of additional name/value fields tacked on to this message. + /// </summary> + IDictionary<string, string> IMessage.ExtraData { + get { return this.ExtraData; } + } + + #endregion + + #region IDirectedProtocolMessage Members + + /// <summary> + /// Gets the URI to the Service Provider endpoint to send this message to. + /// </summary> + Uri IDirectedProtocolMessage.Recipient { + get { return this.recipient != null ? this.recipient.Location : null; } + } + + /// <summary> + /// Gets the preferred method of transport for the message. + /// </summary> + HttpDeliveryMethods IDirectedProtocolMessage.HttpMethods { + get { return this.HttpMethods; } + } + + #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 a value indicating whether security sensitive strings are + /// emitted from the ToString() method. + /// </summary> + internal static bool LowSecurityMode { get; set; } + + /// <summary> + /// Gets a value indicating whether this message was deserialized as an incoming message. + /// </summary> + protected internal bool Incoming { + get { return this.incoming; } + } + + /// <summary> + /// Gets the version of the protocol this message is prepared to implement. + /// </summary> + protected internal Version Version { get; private set; } + + /// <summary> + /// Gets the level of protection this message requires. + /// </summary> + protected MessageProtections RequiredProtection { + get { return this.protectionRequired; } + } + + /// <summary> + /// Gets a value indicating whether this is a direct or indirect message. + /// </summary> + protected MessageTransport Transport { + get { return this.transport; } + } + + /// <summary> + /// Gets the dictionary of additional name/value fields tacked on to this message. + /// </summary> + protected IDictionary<string, string> ExtraData { + get { return this.extraData; } + } + + /// <summary> + /// Gets the preferred method of transport for the message. + /// </summary> + protected HttpDeliveryMethods HttpMethods { + get { return this.recipient != null ? this.recipient.AllowedMethods : HttpDeliveryMethods.None; } + } + + /// <summary> + /// Gets or sets the URI to the Service Provider endpoint to send this message to. + /// </summary> + protected Uri Recipient { + get { + return this.recipient != null ? this.recipient.Location : null; + } + + set { + if (this.recipient != null) { + this.recipient = new MessageReceivingEndpoint(value, this.recipient.AllowedMethods); + } else if (value != null) { + throw new InvalidOperationException(); + } + } + } + + /// <summary> + /// Gets the originating request message that caused this response to be formed. + /// </summary> + protected IDirectedProtocolMessage OriginatingRequest { + get { return this.originatingRequest; } + } + + #region IProtocolMessage Methods + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + void IMessage.EnsureValidMessage() { + this.EnsureValidMessage(); + } + + #endregion + + /// <summary> + /// Returns a human-friendly string describing the message and all serializable properties. + /// </summary> + /// <param name="channel">The channel that will carry this message.</param> + /// <returns> + /// The string representation of this object. + /// </returns> + internal virtual string ToString(Channel channel) { + Contract.Requires<ArgumentNullException>(channel != null); + + StringBuilder builder = new StringBuilder(); + builder.AppendFormat(CultureInfo.InvariantCulture, "{0} message", GetType().Name); + if (this.recipient != null) { + builder.AppendFormat(CultureInfo.InvariantCulture, " as {0} to {1}", this.recipient.AllowedMethods, this.recipient.Location); + } + builder.AppendLine(); + MessageDictionary dictionary = channel.MessageDescriptions.GetAccessor(this); + foreach (var pair in dictionary) { + string value = pair.Value; + if (pair.Key == "oauth_signature" && !LowSecurityMode) { + value = "xxxxxxxxxxxxx (not shown)"; + } + builder.Append('\t'); + builder.Append(pair.Key); + builder.Append(": "); + builder.AppendLine(value); + } + + return builder.ToString(); + } + + /// <summary> + /// Sets a flag indicating that this message is received (as opposed to sent). + /// </summary> + internal void SetAsIncoming() { + this.incoming = true; + } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + protected virtual void EnsureValidMessage() { } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/OAuth Messages.cd b/src/DotNetOpenAuth.OAuth/OAuth/Messages/OAuth Messages.cd new file mode 100644 index 0000000..f5526d2 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/OAuth Messages.cd @@ -0,0 +1,164 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1" GroupingSetting="Access"> + <Comment CommentText="Messages from Service Provider"> + <Position X="7.912" Y="0.715" Height="0.291" Width="2.02" /> + </Comment> + <Comment CommentText="Messages from Consumer"> + <Position X="4.36" Y="0.683" Height="0.291" Width="2.02" /> + </Comment> + <Class Name="DotNetOpenAuth.OAuth.Messages.UnauthorizedTokenRequest"> + <Position X="4.25" Y="1" Width="3" /> + <Compartments> + <Compartment Name="Internal" Collapsed="true" /> + <Compartment Name="Private" Collapsed="true" /> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA=</HashCode> + <FileName>OAuth\Messages\UnauthorizedTokenRequest.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.UnauthorizedTokenResponse"> + <Position X="7.5" Y="1.5" Width="3" /> + <Members> + <Property Name="ITokenContainingMessage.Token" Hidden="true" /> + <Property Name="ITokenSecretContainingMessage.TokenSecret" Hidden="true" /> + </Members> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAACAAAAAAAAAAEAAAAAAIAAIAAAIAAAAAAAAAA=</HashCode> + <FileName>OAuth\Messages\UnauthorizedTokenResponse.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.SignedMessageBase"> + <Position X="0.5" Y="1.5" Width="3.5" /> + <Members> + <Property Name="ITamperResistantOAuthMessage.ConsumerSecret" Hidden="true" /> + <Property Name="ITamperResistantOAuthMessage.HttpMethod" Hidden="true" /> + <Property Name="ITamperResistantOAuthMessage.SignatureMethod" Hidden="true" /> + <Property Name="ITamperResistantOAuthMessage.TokenSecret" Hidden="true" /> + <Property Name="ITamperResistantProtocolMessage.Signature" Hidden="true" /> + </Members> + <TypeIdentifier> + <HashCode>AIAAFAAAAIAAAAACgICAAgAAAgAAIAQAAAEAIgAQAAE=</HashCode> + <FileName>OAuth\Messages\SignedMessageBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.UserAuthorizationRequest"> + <Position X="4.25" Y="3" Width="3" /> + <Members> + <Property Name="ITokenContainingMessage.Token" Hidden="true" /> + </Members> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAACAAAAAAAAAAAAAAAAAIAAAAAAIAAAAAAAQAA=</HashCode> + <FileName>OAuth\Messages\UserAuthorizationRequest.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.UserAuthorizationResponse"> + <Position X="7.5" Y="4.5" Width="3" /> + <Members> + <Property Name="ITokenContainingMessage.Token" Hidden="true" /> + </Members> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAACAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>OAuth\Messages\UserAuthorizationResponse.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.AuthorizedTokenResponse"> + <Position X="7.5" Y="6.25" Width="3" /> + <Members> + <Property Name="ITokenContainingMessage.Token" Hidden="true" /> + <Property Name="ITokenSecretContainingMessage.TokenSecret" Hidden="true" /> + </Members> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAACAAAAAAAAAAAAAAAAEAAAIAAAIAAAAAAAAAA=</HashCode> + <FileName>OAuth\Messages\AuthorizedTokenResponse.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.AuthorizedTokenRequest"> + <Position X="4.25" Y="5.5" Width="3" /> + <Members> + <Property Name="ITokenContainingMessage.Token" Hidden="true" /> + </Members> + <Compartments> + <Compartment Name="Methods" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>AAAAAAACQAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>OAuth\Messages\AuthorizedTokenRequest.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.AccessProtectedResourceRequest"> + <Position X="4.25" Y="7.75" Width="3" /> + <Members> + <Property Name="ITokenContainingMessage.Token" Hidden="true" /> + </Members> + <TypeIdentifier> + <HashCode>AAAAAAACAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAA=</HashCode> + <FileName>OAuth\Messages\AccessProtectedResourceRequest.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Class Name="DotNetOpenAuth.OAuth.Messages.MessageBase"> + <Position X="11" Y="1" Width="3.5" /> + <Members> + <Field Name="extraData" Hidden="true" /> + <Property Name="IDirectedProtocolMessage.Recipient" Hidden="true" /> + <Method Name="IMessage.EnsureValidMessage" Hidden="true" /> + <Property Name="IMessage.ExtraData" Hidden="true" /> + <Property Name="IMessage.Version" Hidden="true" /> + <Property Name="IProtocolMessage.RequiredProtection" Hidden="true" /> + <Property Name="IProtocolMessage.Transport" Hidden="true" /> + <Field Name="protectionRequired" Hidden="true" /> + <Field Name="recipient" Hidden="true" /> + <Field Name="transport" Hidden="true" /> + </Members> + <Compartments> + <Compartment Name="Fields" Collapsed="true" /> + </Compartments> + <TypeIdentifier> + <HashCode>ICAMAAQAYAAAgAkEAIAIAAYACgAEYBAAIECBACAAAAA=</HashCode> + <FileName>OAuth\Messages\MessageBase.cs</FileName> + </TypeIdentifier> + <Lollipop Position="0.2" /> + </Class> + <Interface Name="DotNetOpenAuth.ChannelElements.ITamperResistantOAuthMessage"> + <Position X="11.25" Y="5.25" Width="2.5" /> + <TypeIdentifier> + <HashCode>AIAAAAAAAAAAAAAAAIAAAgAAAAAAIAQAAAAAAAAAAAA=</HashCode> + <FileName>ChannelElements\ITamperResistantOAuthMessage.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="DotNetOpenAuth.OAuth.Messages.ITokenContainingMessage"> + <Position X="1" Y="6" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAA=</HashCode> + <FileName>OAuth\Messages\ITokenContainingMessage.cs</FileName> + </TypeIdentifier> + </Interface> + <Interface Name="DotNetOpenAuth.OAuth.Messages.ITokenSecretContainingMessage"> + <Position X="1" Y="7.5" Width="2" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAA=</HashCode> + <FileName>OAuth\Messages\ITokenSecretContainingMessage.cs</FileName> + </TypeIdentifier> + </Interface> + <Font Name="Segoe UI" Size="9" /> +</ClassDiagram>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/SignedMessageBase.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/SignedMessageBase.cs new file mode 100644 index 0000000..6084fc0 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/SignedMessageBase.cs @@ -0,0 +1,197 @@ +//----------------------------------------------------------------------- +// <copyright file="SignedMessageBase.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.Messaging.Bindings; + using DotNetOpenAuth.OAuth.ChannelElements; + + /// <summary> + /// A base class for all signed OAuth messages. + /// </summary> + public class SignedMessageBase : MessageBase, ITamperResistantOAuthMessage, IExpiringProtocolMessage, IReplayProtectedProtocolMessage { + /// <summary> + /// The reference date and time for calculating time stamps. + /// </summary> + private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// <summary> + /// The number of seconds since 1/1/1970, consistent with the OAuth timestamp requirement. + /// </summary> + [MessagePart("oauth_timestamp", IsRequired = true)] + private long timestamp; + + /// <summary> + /// Initializes a new instance of the <see cref="SignedMessageBase"/> class. + /// </summary> + /// <param name="transport">A value indicating whether this message requires a direct or indirect transport.</param> + /// <param name="recipient">The URI that a directed message will be delivered to.</param> + /// <param name="version">The OAuth version.</param> + internal SignedMessageBase(MessageTransport transport, MessageReceivingEndpoint recipient, Version version) + : base(MessageProtections.All, transport, recipient, version) { + ITamperResistantOAuthMessage self = (ITamperResistantOAuthMessage)this; + HttpDeliveryMethods methods = ((IDirectedProtocolMessage)this).HttpMethods; + self.HttpMethod = MessagingUtilities.GetHttpVerb(methods); + } + + #region ITamperResistantOAuthMessage Members + + /// <summary> + /// Gets or sets the signature method used to sign the request. + /// </summary> + string ITamperResistantOAuthMessage.SignatureMethod { + get { return this.SignatureMethod; } + set { this.SignatureMethod = value; } + } + + /// <summary> + /// Gets or sets the Token Secret used to sign the message. + /// </summary> + string ITamperResistantOAuthMessage.TokenSecret { + get { return this.TokenSecret; } + set { this.TokenSecret = value; } + } + + /// <summary> + /// Gets or sets the Consumer key. + /// </summary> + [MessagePart("oauth_consumer_key", IsRequired = true)] + public string ConsumerKey { get; set; } + + /// <summary> + /// Gets or sets the Consumer Secret used to sign the message. + /// </summary> + string ITamperResistantOAuthMessage.ConsumerSecret { + get { return this.ConsumerSecret; } + set { this.ConsumerSecret = value; } + } + + /// <summary> + /// Gets or sets the HTTP method that will be used to transmit the message. + /// </summary> + string ITamperResistantOAuthMessage.HttpMethod { + get { return this.HttpMethod; } + set { this.HttpMethod = value; } + } + + /// <summary> + /// Gets or sets the URI to the Service Provider endpoint to send this message to. + /// </summary> + Uri ITamperResistantOAuthMessage.Recipient { + get { return this.Recipient; } + set { this.Recipient = value; } + } + + #endregion + + #region ITamperResistantProtocolMessage Members + + /// <summary> + /// Gets or sets the message signature. + /// </summary> + string ITamperResistantProtocolMessage.Signature { + get { return this.Signature; } + set { this.Signature = value; } + } + + #endregion + + #region IExpiringProtocolMessage Members + + /// <summary> + /// Gets or sets the OAuth timestamp of the message. + /// </summary> + DateTime IExpiringProtocolMessage.UtcCreationDate { + get { return epoch + TimeSpan.FromSeconds(this.timestamp); } + set { this.timestamp = (long)(value - epoch).TotalSeconds; } + } + + #endregion + + #region IReplayProtectedProtocolMessage Members + + /// <summary> + /// Gets the context within which the nonce must be unique. + /// </summary> + /// <value>The consumer key.</value> + string IReplayProtectedProtocolMessage.NonceContext { + get { return this.ConsumerKey; } + } + + /// <summary> + /// Gets or sets the message nonce used for replay detection. + /// </summary> + [MessagePart("oauth_nonce", IsRequired = true)] + string IReplayProtectedProtocolMessage.Nonce { get; set; } + + #endregion + + #region IMessageOriginalPayload Members + + /// <summary> + /// Gets or sets the original message parts, before any normalization or default values were assigned. + /// </summary> + IDictionary<string, string> IMessageOriginalPayload.OriginalPayload { + get { return this.OriginalPayload; } + set { this.OriginalPayload = value; } + } + + /// <summary> + /// Gets or sets the original message parts, before any normalization or default values were assigned. + /// </summary> + [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "By design")] + protected IDictionary<string, string> OriginalPayload { get; set; } + + #endregion + + /// <summary> + /// Gets or sets the signature method used to sign the request. + /// </summary> + [MessagePart("oauth_signature_method", IsRequired = true)] + protected string SignatureMethod { get; set; } + + /// <summary> + /// Gets or sets the Token Secret used to sign the message. + /// </summary> + protected string TokenSecret { get; set; } + + /// <summary> + /// Gets or sets the Consumer Secret used to sign the message. + /// </summary> + protected string ConsumerSecret { get; set; } + + /// <summary> + /// Gets or sets the HTTP method that will be used to transmit the message. + /// </summary> + protected string HttpMethod { get; set; } + + /// <summary> + /// Gets or sets the message signature. + /// </summary> + [MessagePart("oauth_signature", IsRequired = true)] + protected string Signature { get; set; } + + /// <summary> + /// Gets or sets the version of the protocol this message was created with. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Accessed via reflection.")] + [MessagePart("oauth_version", IsRequired = false)] + private string OAuthVersion { + get { + return Protocol.Lookup(Version).PublishedVersion; + } + + set { + if (value != this.OAuthVersion) { + throw new ArgumentOutOfRangeException("value"); + } + } + } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/UnauthorizedTokenRequest.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UnauthorizedTokenRequest.cs new file mode 100644 index 0000000..9214d91 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UnauthorizedTokenRequest.cs @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------- +// <copyright file="UnauthorizedTokenRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Collections.Generic; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth.ChannelElements; + + /// <summary> + /// A direct message sent from Consumer to Service Provider to request a Request Token. + /// </summary> + public class UnauthorizedTokenRequest : SignedMessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="UnauthorizedTokenRequest"/> class. + /// </summary> + /// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param> + /// <param name="version">The OAuth version.</param> + protected internal UnauthorizedTokenRequest(MessageReceivingEndpoint serviceProvider, Version version) + : base(MessageTransport.Direct, serviceProvider, version) { + } + + /// <summary> + /// Gets or sets the absolute URL to which the Service Provider will redirect the + /// User back when the Obtaining User Authorization step is completed. + /// </summary> + /// <value> + /// The callback URL; or <c>null</c> if the Consumer is unable to receive + /// callbacks or a callback URL has been established via other means. + /// </value> + [MessagePart("oauth_callback", IsRequired = true, AllowEmpty = false, MinVersion = Protocol.V10aVersion, Encoder = typeof(UriOrOobEncoding))] + public Uri Callback { get; set; } + + /// <summary> + /// Gets the extra, non-OAuth parameters that will be included in the message. + /// </summary> + public new IDictionary<string, string> ExtraData { + get { return base.ExtraData; } + } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/UnauthorizedTokenResponse.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UnauthorizedTokenResponse.cs new file mode 100644 index 0000000..0be9f63 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UnauthorizedTokenResponse.cs @@ -0,0 +1,100 @@ +//----------------------------------------------------------------------- +// <copyright file="UnauthorizedTokenResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Diagnostics.Contracts; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A direct message sent from Service Provider to Consumer in response to + /// a Consumer's <see cref="UnauthorizedTokenRequest"/> request. + /// </summary> + public class UnauthorizedTokenResponse : MessageBase, ITokenSecretContainingMessage { + /// <summary> + /// Initializes a new instance of the <see cref="UnauthorizedTokenResponse"/> class. + /// </summary> + /// <param name="requestMessage">The unauthorized request token message that this message is being generated in response to.</param> + /// <param name="requestToken">The request token.</param> + /// <param name="tokenSecret">The token secret.</param> + /// <remarks> + /// This constructor is used by the Service Provider to send the message. + /// </remarks> + protected internal UnauthorizedTokenResponse(UnauthorizedTokenRequest requestMessage, string requestToken, string tokenSecret) + : this(requestMessage, requestMessage.Version) { + Contract.Requires<ArgumentNullException>(requestToken != null); + Contract.Requires<ArgumentNullException>(tokenSecret != null); + + this.RequestToken = requestToken; + this.TokenSecret = tokenSecret; + } + + /// <summary> + /// Initializes a new instance of the <see cref="UnauthorizedTokenResponse"/> class. + /// </summary> + /// <param name="originatingRequest">The originating request.</param> + /// <param name="version">The OAuth version.</param> + /// <remarks>This constructor is used by the consumer to deserialize the message.</remarks> + protected internal UnauthorizedTokenResponse(UnauthorizedTokenRequest originatingRequest, Version version) + : base(MessageProtections.None, originatingRequest, version) { + } + + /// <summary> + /// Gets or sets the Request or Access Token. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "This property IS accessible by a different name.")] + string ITokenContainingMessage.Token { + get { return this.RequestToken; } + set { this.RequestToken = value; } + } + + /// <summary> + /// Gets or sets the Request or Access Token secret. + /// </summary> + string ITokenSecretContainingMessage.TokenSecret { + get { return this.TokenSecret; } + set { this.TokenSecret = value; } + } + + /// <summary> + /// Gets the extra, non-OAuth parameters that will be included in the message. + /// </summary> + public new IDictionary<string, string> ExtraData { + get { return base.ExtraData; } + } + + /// <summary> + /// Gets or sets the Request Token. + /// </summary> + [MessagePart("oauth_token", IsRequired = true)] + internal string RequestToken { get; set; } + + /// <summary> + /// Gets the original request for an unauthorized token. + /// </summary> + internal UnauthorizedTokenRequest RequestMessage { + get { return (UnauthorizedTokenRequest)this.OriginatingRequest; } + } + + /// <summary> + /// Gets or sets the Token Secret. + /// </summary> + [MessagePart("oauth_token_secret", IsRequired = true)] + protected internal string TokenSecret { get; set; } + + /// <summary> + /// Gets a value indicating whether the Service Provider recognized the callback parameter in the request. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Message serialization invoked.")] + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Message parts must be instance members.")] + [MessagePart("oauth_callback_confirmed", IsRequired = true, MinVersion = Protocol.V10aVersion)] + private bool CallbackConfirmed { + get { return true; } + } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/UserAuthorizationRequest.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UserAuthorizationRequest.cs new file mode 100644 index 0000000..a5823bb --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UserAuthorizationRequest.cs @@ -0,0 +1,82 @@ +//----------------------------------------------------------------------- +// <copyright file="UserAuthorizationRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A message used to redirect the user from a Consumer to a Service Provider's web site + /// so the Service Provider can ask the user to authorize the Consumer's access to some + /// protected resource(s). + /// </summary> + [Serializable] + public class UserAuthorizationRequest : MessageBase, ITokenContainingMessage { + /// <summary> + /// Initializes a new instance of the <see cref="UserAuthorizationRequest"/> class. + /// </summary> + /// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param> + /// <param name="requestToken">The request token.</param> + /// <param name="version">The OAuth version.</param> + internal UserAuthorizationRequest(MessageReceivingEndpoint serviceProvider, string requestToken, Version version) + : this(serviceProvider, version) { + this.RequestToken = requestToken; + } + + /// <summary> + /// Initializes a new instance of the <see cref="UserAuthorizationRequest"/> class. + /// </summary> + /// <param name="serviceProvider">The URI of the Service Provider endpoint to send this message to.</param> + /// <param name="version">The OAuth version.</param> + internal UserAuthorizationRequest(MessageReceivingEndpoint serviceProvider, Version version) + : base(MessageProtections.None, MessageTransport.Indirect, serviceProvider, version) { + } + + /// <summary> + /// Gets or sets the Request or Access Token. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "This property IS accessible by a different name.")] + string ITokenContainingMessage.Token { + get { return this.RequestToken; } + set { this.RequestToken = value; } + } + + /// <summary> + /// Gets the extra, non-OAuth parameters that will be included in the message. + /// </summary> + public new IDictionary<string, string> ExtraData { + get { return base.ExtraData; } + } + + /// <summary> + /// Gets a value indicating whether this is a safe OAuth authorization request. + /// </summary> + /// <value><c>true</c> if the Consumer is using OAuth 1.0a or later; otherwise, <c>false</c>.</value> + public bool IsUnsafeRequest { + get { return this.Version < Protocol.V10a.Version; } + } + + /// <summary> + /// Gets or sets the Request Token obtained in the previous step. + /// </summary> + /// <remarks> + /// The Service Provider MAY declare this parameter as REQUIRED, or + /// accept requests to the User Authorization URL without it, in which + /// case it will prompt the User to enter it manually. + /// </remarks> + [MessagePart("oauth_token", IsRequired = false)] + internal string RequestToken { get; set; } + + /// <summary> + /// Gets or sets a URL the Service Provider will use to redirect the User back + /// to the Consumer when Obtaining User Authorization is complete. Optional. + /// </summary> + [MessagePart("oauth_callback", IsRequired = false, MaxVersion = "1.0")] + internal Uri Callback { get; set; } + } +} diff --git a/src/DotNetOpenAuth.OAuth/OAuth/Messages/UserAuthorizationResponse.cs b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UserAuthorizationResponse.cs new file mode 100644 index 0000000..73fddc7 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth/OAuth/Messages/UserAuthorizationResponse.cs @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------- +// <copyright file="UserAuthorizationResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth.Messages { + using System; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A message used to redirect the user from a Service Provider to a Consumer's web site. + /// </summary> + /// <remarks> + /// The class is sealed because extra parameters are determined by the callback URI provided by the Consumer. + /// </remarks> + [Serializable] + public sealed class UserAuthorizationResponse : MessageBase, ITokenContainingMessage { + /// <summary> + /// Initializes a new instance of the <see cref="UserAuthorizationResponse"/> class. + /// </summary> + /// <param name="consumer">The URI of the Consumer endpoint to send this message to.</param> + /// <param name="version">The OAuth version.</param> + internal UserAuthorizationResponse(Uri consumer, Version version) + : base(MessageProtections.None, MessageTransport.Indirect, new MessageReceivingEndpoint(consumer, HttpDeliveryMethods.GetRequest), version) { + } + + /// <summary> + /// Gets or sets the Request or Access Token. + /// </summary> + string ITokenContainingMessage.Token { + get { return this.RequestToken; } + set { this.RequestToken = value; } + } + + /// <summary> + /// Gets or sets the verification code that must accompany the request to exchange the + /// authorized request token for an access token. + /// </summary> + /// <value>An unguessable value passed to the Consumer via the User and REQUIRED to complete the process.</value> + /// <remarks> + /// If the Consumer did not provide a callback URL, the Service Provider SHOULD display the value of the + /// verification code, and instruct the User to manually inform the Consumer that authorization is + /// completed. If the Service Provider knows a Consumer to be running on a mobile device or set-top box, + /// the Service Provider SHOULD ensure that the verifier value is suitable for manual entry. + /// </remarks> + [MessagePart("oauth_verifier", IsRequired = true, AllowEmpty = false, MinVersion = Protocol.V10aVersion)] + public string VerificationCode { get; set; } + + /// <summary> + /// Gets or sets the Request Token. + /// </summary> + [MessagePart("oauth_token", IsRequired = true)] + internal string RequestToken { get; set; } + } +} |