//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation. All rights reserved.
//
//-----------------------------------------------------------------------
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;
using Validation;
///
/// A base class for all OAuth messages.
///
[Serializable]
public abstract class MessageBase : IDirectedProtocolMessage, IDirectResponseProtocolMessage {
///
/// A store for extra name/value data pairs that are attached to this message.
///
private Dictionary extraData = new Dictionary();
///
/// Gets a value indicating whether signing this message is required.
///
private MessageProtections protectionRequired;
///
/// Gets a value indicating whether this is a direct or indirect message.
///
private MessageTransport transport;
///
/// The URI to the remote endpoint to send this message to.
///
private MessageReceivingEndpoint recipient;
///
/// Backing store for the properties.
///
private IDirectedProtocolMessage originatingRequest;
///
/// Backing store for the properties.
///
private bool incoming;
#if DEBUG
///
/// Initializes static members of the class.
///
static MessageBase() {
LowSecurityMode = true;
}
#endif
///
/// Initializes a new instance of the class for direct response messages.
///
/// The level of protection the message requires.
/// The request that asked for this direct response.
/// The OAuth version.
protected MessageBase(MessageProtections protectionRequired, IDirectedProtocolMessage originatingRequest, Version version) {
Requires.NotNull(originatingRequest, "originatingRequest");
Requires.NotNull(version, "version");
this.protectionRequired = protectionRequired;
this.transport = MessageTransport.Direct;
this.originatingRequest = originatingRequest;
this.Version = version;
}
///
/// Initializes a new instance of the class for direct requests or indirect messages.
///
/// The level of protection the message requires.
/// A value indicating whether this message requires a direct or indirect transport.
/// The URI that a directed message will be delivered to.
/// The OAuth version.
protected MessageBase(MessageProtections protectionRequired, MessageTransport transport, MessageReceivingEndpoint recipient, Version version) {
Requires.NotNull(recipient, "recipient");
Requires.NotNull(version, "version");
this.protectionRequired = protectionRequired;
this.transport = transport;
this.recipient = recipient;
this.Version = version;
}
#region IProtocolMessage Properties
///
/// Gets the version of the protocol this message is prepared to implement.
///
Version IMessage.Version {
get { return this.Version; }
}
///
/// Gets the level of protection this message requires.
///
MessageProtections IProtocolMessage.RequiredProtection {
get { return this.RequiredProtection; }
}
///
/// Gets a value indicating whether this is a direct or indirect message.
///
MessageTransport IProtocolMessage.Transport {
get { return this.Transport; }
}
///
/// Gets the dictionary of additional name/value fields tacked on to this message.
///
IDictionary IMessage.ExtraData {
get { return this.ExtraData; }
}
#endregion
#region IDirectedProtocolMessage Members
///
/// Gets the URI to the Service Provider endpoint to send this message to.
///
Uri IDirectedProtocolMessage.Recipient {
get { return this.recipient != null ? this.recipient.Location : null; }
}
///
/// Gets the preferred method of transport for the message.
///
HttpDeliveryMethods IDirectedProtocolMessage.HttpMethods {
get { return this.HttpMethods; }
}
#endregion
#region IDirectResponseProtocolMessage Members
///
/// Gets the originating request message that caused this response to be formed.
///
IDirectedProtocolMessage IDirectResponseProtocolMessage.OriginatingRequest {
get { return this.originatingRequest; }
}
#endregion
///
/// Gets or sets a value indicating whether security sensitive strings are
/// emitted from the ToString() method.
///
internal static bool LowSecurityMode { get; set; }
///
/// Gets a value indicating whether this message was deserialized as an incoming message.
///
protected internal bool Incoming {
get { return this.incoming; }
}
///
/// Gets the version of the protocol this message is prepared to implement.
///
protected internal Version Version { get; private set; }
///
/// Gets the level of protection this message requires.
///
protected MessageProtections RequiredProtection {
get { return this.protectionRequired; }
}
///
/// Gets a value indicating whether this is a direct or indirect message.
///
protected MessageTransport Transport {
get { return this.transport; }
}
///
/// Gets the dictionary of additional name/value fields tacked on to this message.
///
protected IDictionary ExtraData {
get { return this.extraData; }
}
///
/// Gets the preferred method of transport for the message.
///
protected HttpDeliveryMethods HttpMethods {
get { return this.recipient != null ? this.recipient.AllowedMethods : HttpDeliveryMethods.None; }
}
///
/// Gets or sets the URI to the Service Provider endpoint to send this message to.
///
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();
}
}
}
///
/// Gets the originating request message that caused this response to be formed.
///
protected IDirectedProtocolMessage OriginatingRequest {
get { return this.originatingRequest; }
}
#region IProtocolMessage Methods
///
/// Checks the message state for conformity to the protocol specification
/// and throws an exception if the message is invalid.
///
void IMessage.EnsureValidMessage() {
this.EnsureValidMessage();
}
#endregion
///
/// Returns a human-friendly string describing the message and all serializable properties.
///
/// The channel that will carry this message.
///
/// The string representation of this object.
///
internal virtual string ToString(Channel channel) {
Requires.NotNull(channel, "channel");
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();
}
///
/// Sets a flag indicating that this message is received (as opposed to sent).
///
internal void SetAsIncoming() {
this.incoming = true;
}
///
/// Checks the message state for conformity to the protocol specification
/// and throws an exception if the message is invalid.
///
protected virtual void EnsureValidMessage() { }
}
}