summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth/OAuth/Messages/SignedMessageBase.cs
blob: 6084fc0077a7e5453067f28c0583ef6db51f3f01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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");
				}
			}
		}
	}
}