summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OpenId/OpenId/Extensions/AttributeExchange/AXUtilities.cs
blob: 6e873f7cf8132eca38817748aeff7ad78e538054 (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
//-----------------------------------------------------------------------
// <copyright file="AXUtilities.cs" company="Outercurve Foundation">
//     Copyright (c) Outercurve Foundation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
	using System;
	using System.Collections.Generic;
	using System.Globalization;

	using DotNetOpenAuth.Logging;
	using DotNetOpenAuth.Messaging;
	using Validation;

	/// <summary>
	/// Helper methods shared by multiple messages in the Attribute Exchange extension.
	/// </summary>
	public static class AXUtilities {
		/// <summary>
		/// Adds a request for an attribute considering it 'required'.
		/// </summary>
		/// <param name="collection">The attribute request collection.</param>
		/// <param name="typeUri">The type URI of the required attribute.</param>
		public static void AddRequired(this ICollection<AttributeRequest> collection, string typeUri) {
			Requires.NotNull(collection, "collection");
			collection.Add(new AttributeRequest(typeUri, true));
		}

		/// <summary>
		/// Adds a request for an attribute without considering it 'required'.
		/// </summary>
		/// <param name="collection">The attribute request collection.</param>
		/// <param name="typeUri">The type URI of the requested attribute.</param>
		public static void AddOptional(this ICollection<AttributeRequest> collection, string typeUri) {
			Requires.NotNull(collection, "collection");
			collection.Add(new AttributeRequest(typeUri, false));
		}

		/// <summary>
		/// Adds a given attribute with one or more values to the request for storage.
		/// Applicable to Relying Parties only.
		/// </summary>
		/// <param name="collection">The collection of <see cref="AttributeValues"/> to add to.</param>
		/// <param name="typeUri">The type URI of the attribute.</param>
		/// <param name="values">The attribute values.</param>
		public static void Add(this ICollection<AttributeValues> collection, string typeUri, params string[] values) {
			Requires.NotNull(collection, "collection");
			collection.Add(new AttributeValues(typeUri, values));
		}

		/// <summary>
		/// Serializes a set of attribute values to a dictionary of fields to send in the message.
		/// </summary>
		/// <param name="fields">The dictionary to fill with serialized attributes.</param>
		/// <param name="attributes">The attributes.</param>
		internal static void SerializeAttributes(IDictionary<string, string> fields, IEnumerable<AttributeValues> attributes) {
			Requires.NotNull(fields, "fields");
			Requires.NotNull(attributes, "attributes");

			AliasManager aliasManager = new AliasManager();
			foreach (var att in attributes) {
				string alias = aliasManager.GetAlias(att.TypeUri);
				fields.Add("type." + alias, att.TypeUri);
				if (att.Values == null) {
					continue;
				}
				if (att.Values.Count != 1) {
					fields.Add("count." + alias, att.Values.Count.ToString(CultureInfo.InvariantCulture));
					for (int i = 0; i < att.Values.Count; i++) {
						fields.Add(string.Format(CultureInfo.InvariantCulture, "value.{0}.{1}", alias, i + 1), att.Values[i]);
					}
				} else {
					fields.Add("value." + alias, att.Values[0]);
				}
			}
		}

		/// <summary>
		/// Deserializes attribute values from an incoming set of message data.
		/// </summary>
		/// <param name="fields">The data coming in with the message.</param>
		/// <returns>The attribute values found in the message.</returns>
		internal static IEnumerable<AttributeValues> DeserializeAttributes(IDictionary<string, string> fields) {
			AliasManager aliasManager = ParseAliases(fields);
			foreach (string alias in aliasManager.Aliases) {
				AttributeValues att = new AttributeValues(aliasManager.ResolveAlias(alias));
				int count = 1;
				bool countSent = false;
				string countString;
				if (fields.TryGetValue("count." + alias, out countString)) {
					if (!int.TryParse(countString, out count) || count < 0) {
						Logger.OpenId.ErrorFormat("Failed to parse count.{0} value to a non-negative integer.", alias);
						continue;
					}
					countSent = true;
				}
				if (countSent) {
					for (int i = 1; i <= count; i++) {
						string value;
						if (fields.TryGetValue(string.Format(CultureInfo.InvariantCulture, "value.{0}.{1}", alias, i), out value)) {
							att.Values.Add(value);
						} else {
							Logger.OpenId.ErrorFormat("Missing value for attribute '{0}'.", att.TypeUri);
							continue;
						}
					}
				} else {
					string value;
					if (fields.TryGetValue("value." + alias, out value)) {
						att.Values.Add(value);
					} else {
						Logger.OpenId.ErrorFormat("Missing value for attribute '{0}'.", att.TypeUri);
						continue;
					}
				}
				yield return att;
			}
		}

		/// <summary>
		/// Reads through the attributes included in the response to discover
		/// the alias-TypeURI relationships.
		/// </summary>
		/// <param name="fields">The data included in the extension message.</param>
		/// <returns>The alias manager that provides lookup between aliases and type URIs.</returns>
		private static AliasManager ParseAliases(IDictionary<string, string> fields) {
			Requires.NotNull(fields, "fields");

			AliasManager aliasManager = new AliasManager();
			const string TypePrefix = "type.";
			foreach (var pair in fields) {
				if (!pair.Key.StartsWith(TypePrefix, StringComparison.Ordinal)) {
					continue;
				}
				string alias = pair.Key.Substring(TypePrefix.Length);
				if (alias.IndexOfAny(FetchRequest.IllegalAliasCharacters) >= 0) {
					Logger.OpenId.ErrorFormat("Illegal characters in alias name '{0}'.", alias);
					continue;
				}
				aliasManager.SetAlias(alias, pair.Value);
			}
			return aliasManager;
		}
	}
}