summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs11
-rw-r--r--src/DotNetOpenAuth/Messaging/Channel.cs2
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagePartAttribute.cs20
-rw-r--r--src/DotNetOpenAuth/Messaging/MessageSerializer.cs2
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs108
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs3
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs3
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs2
10 files changed, 125 insertions, 30 deletions
diff --git a/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs b/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs
index da5275b..47e86f7 100644
--- a/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDescriptionTests.cs
@@ -12,13 +12,18 @@ namespace DotNetOpenAuth.Test.Messaging.Reflection {
[TestClass]
public class MessageDescriptionTests : MessagingTestBase {
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
- public void GetNull() {
- MessageDescription.Get(null);
+ public void GetNullType() {
+ MessageDescription.Get(null, new Version(1, 0));
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentNullException))]
+ public void GetNullVersion() {
+ MessageDescription.Get(typeof(Mocks.TestMessage), null);
}
[TestMethod, ExpectedException(typeof(ArgumentException))]
public void GetNonMessageType() {
- MessageDescription.Get(typeof(string));
+ MessageDescription.Get(typeof(string), new Version(1, 0));
}
}
}
diff --git a/src/DotNetOpenAuth/Messaging/Channel.cs b/src/DotNetOpenAuth/Messaging/Channel.cs
index 0f020cc..2db6b93 100644
--- a/src/DotNetOpenAuth/Messaging/Channel.cs
+++ b/src/DotNetOpenAuth/Messaging/Channel.cs
@@ -645,7 +645,7 @@ namespace DotNetOpenAuth.Messaging {
Debug.Assert(message != null, "message == null");
MessageDictionary dictionary = new MessageDictionary(message);
- MessageDescription description = MessageDescription.Get(message.GetType());
+ MessageDescription description = MessageDescription.Get(message.GetType(), message.ProtocolVersion);
description.EnsureMessagePartsPassBasicValidation(dictionary);
}
diff --git a/src/DotNetOpenAuth/Messaging/MessagePartAttribute.cs b/src/DotNetOpenAuth/Messaging/MessagePartAttribute.cs
index 248cb01..51a888e 100644
--- a/src/DotNetOpenAuth/Messaging/MessagePartAttribute.cs
+++ b/src/DotNetOpenAuth/Messaging/MessagePartAttribute.cs
@@ -12,7 +12,7 @@ namespace DotNetOpenAuth.Messaging {
/// <summary>
/// Applied to fields and properties that form a key/value in a protocol message.
/// </summary>
- [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = true, AllowMultiple = true)]
public sealed class MessagePartAttribute : Attribute {
/// <summary>
/// The overridden name to use as the serialized name for the property.
@@ -24,6 +24,7 @@ namespace DotNetOpenAuth.Messaging {
/// </summary>
public MessagePartAttribute() {
this.AllowEmpty = true;
+ this.MinVersionValue = new Version(0, 0);
}
/// <summary>
@@ -65,5 +66,22 @@ namespace DotNetOpenAuth.Messaging {
/// Gets or sets a custom encoder to use to translate the applied member to and from a string.
/// </summary>
public Type Encoder { get; set; }
+
+ /// <summary>
+ /// Gets or sets the minimum version of the protocol this attribute applies to
+ /// and overrides any attributes with lower values for this property.
+ /// </summary>
+ /// <value>Defaults to 0.0.</value>
+ public string MinVersion {
+ get { return this.MinVersionValue.ToString(); }
+ set { this.MinVersionValue = new Version(value); }
+ }
+
+ /// <summary>
+ /// Gets or sets the minimum version of the protocol this attribute applies to
+ /// and overrides any attributes with lower values for this property.
+ /// </summary>
+ /// <value>Defaults to 0.0.</value>
+ internal Version MinVersionValue { get; set; }
}
}
diff --git a/src/DotNetOpenAuth/Messaging/MessageSerializer.cs b/src/DotNetOpenAuth/Messaging/MessageSerializer.cs
index 1db0c57..cceab3d 100644
--- a/src/DotNetOpenAuth/Messaging/MessageSerializer.cs
+++ b/src/DotNetOpenAuth/Messaging/MessageSerializer.cs
@@ -84,7 +84,7 @@ namespace DotNetOpenAuth.Messaging {
ErrorUtilities.VerifyArgumentNotNull(message, "message");
// Before we deserialize the message, make sure all the required parts are present.
- MessageDescription.Get(this.messageType).EnsureMessagePartsPassBasicValidation(fields);
+ MessageDescription.Get(this.messageType, message.ProtocolVersion).EnsureMessagePartsPassBasicValidation(fields);
try {
foreach (var pair in fields) {
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
index 31b6c41..ae52679 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
@@ -20,12 +20,12 @@ namespace DotNetOpenAuth.Messaging.Reflection {
/// <summary>
/// A dictionary of reflected message types and the generated reflection information.
/// </summary>
- private static Dictionary<Type, MessageDescription> reflectedMessageTypes = new Dictionary<Type, MessageDescription>();
+ private static Dictionary<MessageTypeAndVersion, MessageDescription> reflectedMessageTypes = new Dictionary<MessageTypeAndVersion, MessageDescription>();
/// <summary>
/// The type of message this instance was generated from.
/// </summary>
- private Type messageType;
+ private MessageTypeAndVersion messageTypeAndVersion;
/// <summary>
/// A mapping between the serialized key names and their
@@ -36,19 +36,19 @@ namespace DotNetOpenAuth.Messaging.Reflection {
/// <summary>
/// Initializes a new instance of the <see cref="MessageDescription"/> class.
/// </summary>
- /// <param name="messageType">The type of message to reflect over.</param>
- private MessageDescription(Type messageType) {
- Debug.Assert(messageType != null, "messageType == null");
+ /// <param name="messageTypeAndVersion">The type and protocol version of the message to reflect over.</param>
+ private MessageDescription(MessageTypeAndVersion messageTypeAndVersion) {
+ ErrorUtilities.VerifyArgumentNotNull(messageTypeAndVersion, "messageTypeAndVersion");
- if (!typeof(IProtocolMessage).IsAssignableFrom(messageType)) {
+ if (!typeof(IProtocolMessage).IsAssignableFrom(messageTypeAndVersion.Type)) {
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
MessagingStrings.UnexpectedType,
typeof(IProtocolMessage),
- messageType));
+ messageTypeAndVersion.Type));
}
- this.messageType = messageType;
+ this.messageTypeAndVersion = messageTypeAndVersion;
this.ReflectMessageType();
}
@@ -65,17 +65,19 @@ namespace DotNetOpenAuth.Messaging.Reflection {
/// given message type.
/// </summary>
/// <param name="messageType">A type that implements <see cref="IProtocolMessage"/>.</param>
+ /// <param name="messageVersion">The protocol version of the message.</param>
/// <returns>A <see cref="MessageDescription"/> instance.</returns>
- internal static MessageDescription Get(Type messageType) {
- if (messageType == null) {
- throw new ArgumentNullException("messageType");
- }
+ internal static MessageDescription Get(Type messageType, Version messageVersion) {
+ ErrorUtilities.VerifyArgumentNotNull(messageType, "messageType");
+ ErrorUtilities.VerifyArgumentNotNull(messageVersion, "messageVersion");
+
+ MessageTypeAndVersion key = new MessageTypeAndVersion(messageType, messageVersion);
MessageDescription result;
- if (!reflectedMessageTypes.TryGetValue(messageType, out result)) {
+ if (!reflectedMessageTypes.TryGetValue(key, out result)) {
lock (reflectedMessageTypes) {
- if (!reflectedMessageTypes.TryGetValue(messageType, out result)) {
- reflectedMessageTypes[messageType] = result = new MessageDescription(messageType);
+ if (!reflectedMessageTypes.TryGetValue(key, out result)) {
+ reflectedMessageTypes[key] = result = new MessageDescription(key);
}
}
}
@@ -90,11 +92,15 @@ namespace DotNetOpenAuth.Messaging.Reflection {
internal void ReflectMessageType() {
this.mapping = new Dictionary<string, MessagePart>();
- Type currentType = this.messageType;
+ Type currentType = this.messageTypeAndVersion.Type;
do {
foreach (MemberInfo member in currentType.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) {
if (member is PropertyInfo || member is FieldInfo) {
- MessagePartAttribute partAttribute = member.GetCustomAttributes(typeof(MessagePartAttribute), true).OfType<MessagePartAttribute>().FirstOrDefault();
+ MessagePartAttribute partAttribute =
+ (from a in member.GetCustomAttributes(typeof(MessagePartAttribute), true).OfType<MessagePartAttribute>()
+ orderby a.MinVersionValue descending
+ where a.MinVersionValue <= this.messageTypeAndVersion.Version
+ select a).FirstOrDefault();
if (partAttribute != null) {
MessagePart part = new MessagePart(member, partAttribute);
this.mapping.Add(part.Name, part);
@@ -129,7 +135,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
string.Format(
CultureInfo.CurrentCulture,
MessagingStrings.RequiredParametersMissing,
- this.messageType.FullName,
+ this.messageTypeAndVersion.Type.FullName,
string.Join(", ", missingKeys)));
}
}
@@ -148,9 +154,73 @@ namespace DotNetOpenAuth.Messaging.Reflection {
string.Format(
CultureInfo.CurrentCulture,
MessagingStrings.RequiredNonEmptyParameterWasEmpty,
- this.messageType.FullName,
+ this.messageTypeAndVersion.Type.FullName,
string.Join(", ", emptyValuedKeys)));
}
}
+
+ /// <summary>
+ /// A struct used as the key to bundle message type and version.
+ /// </summary>
+ private struct MessageTypeAndVersion {
+ /// <summary>
+ /// Backing store for the <see cref="Type"/> property.
+ /// </summary>
+ private readonly Type type;
+
+ /// <summary>
+ /// Backing store for the <see cref="Version"/> property.
+ /// </summary>
+ private readonly Version version;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MessageTypeAndVersion"/> struct.
+ /// </summary>
+ /// <param name="messageType">Type of the message.</param>
+ /// <param name="messageVersion">The message version.</param>
+ internal MessageTypeAndVersion(Type messageType, Version messageVersion) {
+ ErrorUtilities.VerifyArgumentNotNull(messageType, "messageType");
+ ErrorUtilities.VerifyArgumentNotNull(messageVersion, "messageVersion");
+
+ this.type = messageType;
+ this.version = messageVersion;
+ }
+
+ /// <summary>
+ /// Gets the message type.
+ /// </summary>
+ internal Type Type { get { return this.type; } }
+
+ /// <summary>
+ /// Gets the message version.
+ /// </summary>
+ internal Version Version { get { return this.version; } }
+
+ /// <summary>
+ /// Indicates whether this instance and a specified object are equal.
+ /// </summary>
+ /// <param name="obj">Another object to compare to.</param>
+ /// <returns>
+ /// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
+ /// </returns>
+ public override bool Equals(object obj) {
+ if (obj is MessageTypeAndVersion) {
+ MessageTypeAndVersion other = (MessageTypeAndVersion)obj;
+ return this.type == other.type && this.version == other.version;
+ } else {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Returns the hash code for this instance.
+ /// </summary>
+ /// <returns>
+ /// A 32-bit signed integer that is the hash code for this instance.
+ /// </returns>
+ public override int GetHashCode() {
+ return this.type.GetHashCode();
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs
index 45399aa..fa4ac83 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs
@@ -36,7 +36,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
}
this.message = message;
- this.description = MessageDescription.Get(message.GetType());
+ this.description = MessageDescription.Get(message.GetType(), message.ProtocolVersion);
}
#region ICollection<KeyValuePair<string,string>> Properties
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
index 4a5129c..d23de38 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
@@ -136,7 +136,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
private static string GetSignedParameterOrder(ITamperResistantOpenIdMessage signedMessage) {
ErrorUtilities.VerifyArgumentNotNull(signedMessage, "signedMessage");
- MessageDescription description = MessageDescription.Get(signedMessage.GetType());
+ MessageDescription description = MessageDescription.Get(signedMessage.GetType(), signedMessage.ProtocolVersion);
var signedParts = from part in description.Mapping.Values
where (part.RequiredProtection & System.Net.Security.ProtectionLevel.Sign) != 0
select part.Name;
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
index 020f2dc..621054f 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
@@ -39,7 +39,8 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// </summary>
/// <value>Value: A valid association session type from Section 8.4 (Association Session Types). </value>
/// <remarks>Note: Unless using transport layer encryption, "no-encryption" MUST NOT be used. </remarks>
- [MessagePart("openid.session_type", IsRequired = true, AllowEmpty = false)]
+ [MessagePart("openid.session_type", IsRequired = true, AllowEmpty = true)]
+ [MessagePart("openid.session_type", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")]
internal string SessionType { get; set; }
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs
index 043a98c..6486fce 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs
@@ -54,7 +54,8 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// </summary>
/// <value>Value: A valid association session type from Section 8.4 (Association Session Types). </value>
/// <remarks>Note: Unless using transport layer encryption, "no-encryption" MUST NOT be used. </remarks>
- [MessagePart("session_type", IsRequired = true, AllowEmpty = false)]
+ [MessagePart("session_type", IsRequired = true, AllowEmpty = true)]
+ [MessagePart("session_type", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")]
internal string SessionType { get; set; }
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs b/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs
index e4ae233..bc00ac0 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs
@@ -24,7 +24,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// This particular value MUST be present for the request to be a valid OpenID Authentication 2.0 request. Future versions of the specification may define different values in order to allow message recipients to properly interpret the request.
/// </remarks>
[SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Read by reflection.")]
- [MessagePart("openid.ns", IsRequired = true, AllowEmpty = false)]
+ [MessagePart("openid.ns", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")]
#pragma warning disable 0414 // read by reflection
private readonly string OpenIdNamespace = Protocol.OpenId2Namespace;
#pragma warning restore 0414