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.OpenId/OpenId/Extensions/ExtensionArgumentsManager.cs | |
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.OpenId/OpenId/Extensions/ExtensionArgumentsManager.cs')
-rw-r--r-- | src/DotNetOpenAuth.OpenId/OpenId/Extensions/ExtensionArgumentsManager.cs | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Extensions/ExtensionArgumentsManager.cs b/src/DotNetOpenAuth.OpenId/OpenId/Extensions/ExtensionArgumentsManager.cs new file mode 100644 index 0000000..0a78df1 --- /dev/null +++ b/src/DotNetOpenAuth.OpenId/OpenId/Extensions/ExtensionArgumentsManager.cs @@ -0,0 +1,223 @@ +//----------------------------------------------------------------------- +// <copyright file="ExtensionArgumentsManager.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Extensions { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// Manages the processing and construction of OpenID extensions parts. + /// </summary> + internal class ExtensionArgumentsManager { + /// <summary> + /// This contains a set of aliases that we must be willing to implicitly + /// match to namespaces for backward compatibility with other OpenID libraries. + /// </summary> + private static readonly Dictionary<string, string> typeUriToAliasAffinity = new Dictionary<string, string> { + { Extensions.SimpleRegistration.Constants.sreg_ns, Extensions.SimpleRegistration.Constants.sreg_compatibility_alias }, + { Extensions.ProviderAuthenticationPolicy.Constants.TypeUri, Extensions.ProviderAuthenticationPolicy.Constants.CompatibilityAlias }, + }; + + /// <summary> + /// The version of OpenID that the message is using. + /// </summary> + private Protocol protocol; + + /// <summary> + /// Whether extensions are being read or written. + /// </summary> + private bool isReadMode; + + /// <summary> + /// The alias manager that will track Type URI to alias mappings. + /// </summary> + private AliasManager aliasManager = new AliasManager(); + + /// <summary> + /// A complex dictionary where the key is the Type URI of the extension, + /// and the value is another dictionary of the name/value args of the extension. + /// </summary> + private Dictionary<string, IDictionary<string, string>> extensions = new Dictionary<string, IDictionary<string, string>>(); + + /// <summary> + /// Prevents a default instance of the <see cref="ExtensionArgumentsManager"/> class from being created. + /// </summary> + private ExtensionArgumentsManager() { } + + /// <summary> + /// Gets a value indicating whether the extensions are being read (as opposed to written). + /// </summary> + internal bool ReadMode { + get { return this.isReadMode; } + } + + /// <summary> + /// Creates a <see cref="ExtensionArgumentsManager"/> instance to process incoming extensions. + /// </summary> + /// <param name="query">The parameters in the OpenID message.</param> + /// <returns>The newly created instance of <see cref="ExtensionArgumentsManager"/>.</returns> + public static ExtensionArgumentsManager CreateIncomingExtensions(IDictionary<string, string> query) { + Contract.Requires<ArgumentNullException>(query != null); + var mgr = new ExtensionArgumentsManager(); + mgr.protocol = Protocol.Detect(query); + mgr.isReadMode = true; + string aliasPrefix = mgr.protocol.openid.ns + "."; + + // First pass looks for namespace aliases + foreach (var pair in query) { + if (pair.Key.StartsWith(aliasPrefix, StringComparison.Ordinal)) { + mgr.aliasManager.SetAlias(pair.Key.Substring(aliasPrefix.Length), pair.Value); + } + } + + // For backwards compatibility, add certain aliases if they aren't defined. + if (mgr.protocol.Version.Major < 2) { + foreach (var pair in typeUriToAliasAffinity) { + if (!mgr.aliasManager.IsAliasAssignedTo(pair.Key) && + !mgr.aliasManager.IsAliasUsed(pair.Value)) { + mgr.aliasManager.SetAlias(pair.Value, pair.Key); + } + } + } + + // Second pass looks for extensions using those aliases + foreach (var pair in query) { + if (!pair.Key.StartsWith(mgr.protocol.openid.Prefix, StringComparison.Ordinal)) { + continue; + } + string possibleAlias = pair.Key.Substring(mgr.protocol.openid.Prefix.Length); + int periodIndex = possibleAlias.IndexOf(".", StringComparison.Ordinal); + if (periodIndex >= 0) { + possibleAlias = possibleAlias.Substring(0, periodIndex); + } + string typeUri; + if ((typeUri = mgr.aliasManager.TryResolveAlias(possibleAlias)) != null) { + if (!mgr.extensions.ContainsKey(typeUri)) { + mgr.extensions[typeUri] = new Dictionary<string, string>(); + } + string key = periodIndex >= 0 ? pair.Key.Substring(mgr.protocol.openid.Prefix.Length + possibleAlias.Length + 1) : string.Empty; + mgr.extensions[typeUri].Add(key, pair.Value); + } + } + return mgr; + } + + /// <summary> + /// Creates a <see cref="ExtensionArgumentsManager"/> instance to prepare outgoing extensions. + /// </summary> + /// <param name="protocol">The protocol version used for the outgoing message.</param> + /// <returns> + /// The newly created instance of <see cref="ExtensionArgumentsManager"/>. + /// </returns> + public static ExtensionArgumentsManager CreateOutgoingExtensions(Protocol protocol) { + var mgr = new ExtensionArgumentsManager(); + mgr.protocol = protocol; + + // Affinity for certain alias for backwards compatibility + foreach (var pair in typeUriToAliasAffinity) { + mgr.aliasManager.SetAlias(pair.Value, pair.Key); + } + return mgr; + } + + /// <summary> + /// Adds query parameters for OpenID extensions to the request directed + /// at the OpenID provider. + /// </summary> + /// <param name="extensionTypeUri">The extension type URI.</param> + /// <param name="arguments">The arguments for this extension to add to the message.</param> + public void AddExtensionArguments(string extensionTypeUri, IDictionary<string, string> arguments) { + Contract.Requires<InvalidOperationException>(!this.ReadMode); + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(extensionTypeUri)); + Contract.Requires<ArgumentNullException>(arguments != null); + if (arguments.Count == 0) { + return; + } + + IDictionary<string, string> extensionArgs; + if (!this.extensions.TryGetValue(extensionTypeUri, out extensionArgs)) { + this.extensions.Add(extensionTypeUri, extensionArgs = new Dictionary<string, string>(arguments.Count)); + } + + ErrorUtilities.VerifyProtocol(extensionArgs.Count == 0, OpenIdStrings.ExtensionAlreadyAddedWithSameTypeURI, extensionTypeUri); + foreach (var pair in arguments) { + extensionArgs.Add(pair.Key, pair.Value); + } + } + + /// <summary> + /// Gets the actual arguments to add to a querystring or other response, + /// where type URI, alias, and actual key/values are all defined. + /// </summary> + /// <param name="includeOpenIdPrefix"> + /// <c>true</c> if the generated parameter names should include the 'openid.' prefix. + /// This should be <c>true</c> for all but direct response messages. + /// </param> + /// <returns>A dictionary of key=value pairs to add to the message to carry the extension.</returns> + internal IDictionary<string, string> GetArgumentsToSend(bool includeOpenIdPrefix) { + Contract.Requires<InvalidOperationException>(!this.ReadMode); + Dictionary<string, string> args = new Dictionary<string, string>(); + foreach (var typeUriAndExtension in this.extensions) { + string typeUri = typeUriAndExtension.Key; + var extensionArgs = typeUriAndExtension.Value; + if (extensionArgs.Count == 0) { + continue; + } + string alias = this.aliasManager.GetAlias(typeUri); + + // send out the alias declaration + string openidPrefix = includeOpenIdPrefix ? this.protocol.openid.Prefix : string.Empty; + args.Add(openidPrefix + this.protocol.openidnp.ns + "." + alias, typeUri); + string prefix = openidPrefix + alias; + foreach (var pair in extensionArgs) { + string key = prefix; + if (pair.Key.Length > 0) { + key += "." + pair.Key; + } + args.Add(key, pair.Value); + } + } + return args; + } + + /// <summary> + /// Gets the fields carried by a given OpenId extension. + /// </summary> + /// <param name="extensionTypeUri">The type URI of the extension whose fields are being queried for.</param> + /// <returns> + /// The fields included in the given extension, or null if the extension is not present. + /// </returns> + internal IDictionary<string, string> GetExtensionArguments(string extensionTypeUri) { + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(extensionTypeUri)); + Contract.Requires<InvalidOperationException>(this.ReadMode); + + IDictionary<string, string> extensionArgs; + this.extensions.TryGetValue(extensionTypeUri, out extensionArgs); + return extensionArgs; + } + + /// <summary> + /// Gets whether any arguments for a given extension are present. + /// </summary> + /// <param name="extensionTypeUri">The extension Type URI in question.</param> + /// <returns><c>true</c> if this extension is present; <c>false</c> otherwise.</returns> + internal bool ContainsExtension(string extensionTypeUri) { + return this.extensions.ContainsKey(extensionTypeUri); + } + + /// <summary> + /// Gets the type URIs of all discovered extensions in the message. + /// </summary> + /// <returns>A sequence of the type URIs.</returns> + internal IEnumerable<string> GetExtensionTypeUris() { + return this.extensions.Keys; + } + } +} |