summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OpenId/OpenId/Protocol.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OpenId/OpenId/Protocol.cs')
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/Protocol.cs472
1 files changed, 472 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Protocol.cs b/src/DotNetOpenAuth.OpenId/OpenId/Protocol.cs
new file mode 100644
index 0000000..a651f3c
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenId/OpenId/Protocol.cs
@@ -0,0 +1,472 @@
+// <auto-generated/> // disable StyleCop on this file
+//-----------------------------------------------------------------------
+// <copyright file="Protocol.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId {
+ using System;
+ using System.Collections.Generic;
+ using DotNetOpenAuth.Messaging;
+ using System.Globalization;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Diagnostics;
+
+ /// <summary>
+ /// An enumeration of the OpenID protocol versions supported by this library.
+ /// </summary>
+ public enum ProtocolVersion {
+ /// <summary>
+ /// OpenID Authentication 1.0
+ /// </summary>
+ V10,
+ /// <summary>
+ /// OpenID Authentication 1.1
+ /// </summary>
+ V11,
+ /// <summary>
+ /// OpenID Authentication 2.0
+ /// </summary>
+ V20,
+ }
+
+ /// <summary>
+ /// Tracks the several versions of OpenID this library supports and the unique
+ /// constants to each version used in the protocol.
+ /// </summary>
+ [DebuggerDisplay("OpenID {Version}")]
+ internal sealed class Protocol {
+ /// <summary>
+ /// The value of the openid.ns parameter in the OpenID 2.0 specification.
+ /// </summary>
+ internal const string OpenId2Namespace = "http://specs.openid.net/auth/2.0";
+
+ /// <summary>
+ /// Scans a list for matches with some element of the OpenID protocol,
+ /// searching from newest to oldest protocol for the first and best match.
+ /// </summary>
+ /// <typeparam name="T">The type of element retrieved from the <see cref="Protocol"/> instance.</typeparam>
+ /// <param name="elementOf">Takes a <see cref="Protocol"/> instance and returns an element of it.</param>
+ /// <param name="list">The list to scan for matches.</param>
+ /// <returns>The protocol with the element that matches some item in the list.</returns>
+ internal static Protocol FindBestVersion<T>(Func<Protocol, T> elementOf, IEnumerable<T> list) {
+ foreach (var protocol in Protocol.AllVersions) {
+ foreach (var item in list) {
+ if (item != null && item.Equals(elementOf(protocol)))
+ return protocol;
+ }
+ }
+ return null;
+ }
+
+ Protocol(QueryParameters queryBits) {
+ openidnp = queryBits;
+ openid = new QueryParameters(queryBits);
+ }
+
+ // Well-known, supported versions of the OpenID spec.
+ public static readonly Protocol V10 = new Protocol(new QueryParameters()) {
+ Version = new Version(1, 0),
+ XmlNamespace = "http://openid.net/xmlns/1.0",
+ QueryDeclaredNamespaceVersion = null,
+ ClaimedIdentifierServiceTypeURI = "http://openid.net/signon/1.0",
+ OPIdentifierServiceTypeURI = null, // not supported
+ ClaimedIdentifierForOPIdentifier = null, // not supported
+ RPReturnToTypeURI = null, // not supported
+ HtmlDiscoveryProviderKey = "openid.server",
+ HtmlDiscoveryLocalIdKey = "openid.delegate",
+ };
+ public static readonly Protocol V11 = new Protocol(new QueryParameters()) {
+ Version = new Version(1, 1),
+ XmlNamespace = "http://openid.net/xmlns/1.0",
+ QueryDeclaredNamespaceVersion = null,
+ ClaimedIdentifierServiceTypeURI = "http://openid.net/signon/1.1",
+ OPIdentifierServiceTypeURI = null, // not supported
+ ClaimedIdentifierForOPIdentifier = null, // not supported
+ RPReturnToTypeURI = null, // not supported
+ HtmlDiscoveryProviderKey = "openid.server",
+ HtmlDiscoveryLocalIdKey = "openid.delegate",
+ };
+ public static readonly Protocol V20 = new Protocol(new QueryParameters() {
+ Realm = "realm",
+ op_endpoint = "op_endpoint",
+ response_nonce = "response_nonce",
+ error_code = "error_code",
+ user_setup_url = null,
+ }) {
+ Version = new Version(2, 0),
+ XmlNamespace = null, // no longer applicable
+ QueryDeclaredNamespaceVersion = Protocol.OpenId2Namespace,
+ ClaimedIdentifierServiceTypeURI = "http://specs.openid.net/auth/2.0/signon",
+ OPIdentifierServiceTypeURI = "http://specs.openid.net/auth/2.0/server",
+ ClaimedIdentifierForOPIdentifier = "http://specs.openid.net/auth/2.0/identifier_select",
+ RPReturnToTypeURI = "http://specs.openid.net/auth/2.0/return_to",
+ HtmlDiscoveryProviderKey = "openid2.provider",
+ HtmlDiscoveryLocalIdKey = "openid2.local_id",
+ Args = new QueryArguments() {
+ SessionType = new QueryArguments.SessionTypes() {
+ NoEncryption = "no-encryption",
+ DH_SHA256 = "DH-SHA256",
+ DH_SHA384 = "DH-SHA384",
+ DH_SHA512 = "DH-SHA512",
+ },
+ SignatureAlgorithm = new QueryArguments.SignatureAlgorithms() {
+ HMAC_SHA256 = "HMAC-SHA256",
+ HMAC_SHA384 = "HMAC-SHA384",
+ HMAC_SHA512 = "HMAC-SHA512",
+ },
+ Mode = new QueryArguments.Modes() {
+ setup_needed = "setup_needed",
+ },
+ },
+ };
+
+ /// <summary>
+ /// A list of all supported OpenID versions, in order starting from newest version.
+ /// </summary>
+ public readonly static List<Protocol> AllVersions = new List<Protocol>() { V20, V11, V10 };
+
+ /// <summary>
+ /// A list of all supported OpenID versions, in order starting from newest version.
+ /// V1.1 and V1.0 are considered the same and only V1.1 is in the list.
+ /// </summary>
+ public readonly static List<Protocol> AllPracticalVersions = new List<Protocol>() { V20, V11 };
+
+ /// <summary>
+ /// The default (or most recent) supported version of the OpenID protocol.
+ /// </summary>
+ public readonly static Protocol Default = AllVersions[0];
+ public static Protocol Lookup(Version version) {
+ foreach (Protocol protocol in AllVersions) {
+ if (protocol.Version == version) return protocol;
+ }
+ throw new ArgumentOutOfRangeException("version");
+ }
+ public static Protocol Lookup(ProtocolVersion version) {
+ switch (version) {
+ case ProtocolVersion.V10: return Protocol.V10;
+ case ProtocolVersion.V11: return Protocol.V11;
+ case ProtocolVersion.V20: return Protocol.V20;
+ default: throw new ArgumentOutOfRangeException("version");
+ }
+ }
+ /// <summary>
+ /// Attempts to detect the right OpenID protocol version based on the contents
+ /// of an incoming OpenID <i>indirect</i> message or <i>direct request</i>.
+ /// </summary>
+ internal static Protocol Detect(IDictionary<string, string> query) {
+ Requires.NotNull(query, "query");
+ return query.ContainsKey(V20.openid.ns) ? V20 : V11;
+ }
+ /// <summary>
+ /// Attempts to detect the right OpenID protocol version based on the contents
+ /// of an incoming OpenID <i>direct</i> response message.
+ /// </summary>
+ internal static Protocol DetectFromDirectResponse(IDictionary<string, string> query) {
+ Requires.NotNull(query, "query");
+ return query.ContainsKey(V20.openidnp.ns) ? V20 : V11;
+ }
+ /// <summary>
+ /// Attemps to detect the highest OpenID protocol version supported given a set
+ /// of XRDS Service Type URIs included for some service.
+ /// </summary>
+ internal static Protocol Detect(IEnumerable<string> serviceTypeURIs) {
+ Requires.NotNull(serviceTypeURIs, "serviceTypeURIs");
+ return FindBestVersion(p => p.OPIdentifierServiceTypeURI, serviceTypeURIs) ??
+ FindBestVersion(p => p.ClaimedIdentifierServiceTypeURI, serviceTypeURIs) ??
+ FindBestVersion(p => p.RPReturnToTypeURI, serviceTypeURIs);
+ }
+
+ /// <summary>
+ /// The OpenID version that this <see cref="Protocol"/> instance describes.
+ /// </summary>
+ public Version Version;
+ /// <summary>
+ /// Returns the <see cref="ProtocolVersion"/> enum value for the <see cref="Protocol"/> instance.
+ /// </summary>
+ public ProtocolVersion ProtocolVersion {
+ get {
+ switch (Version.Major) {
+ case 1: return ProtocolVersion.V11;
+ case 2: return ProtocolVersion.V20;
+ default: throw new ArgumentException(null); // this should never happen
+ }
+ }
+ }
+ /// <summary>
+ /// The namespace of OpenId 1.x elements in XRDS documents.
+ /// </summary>
+ public string XmlNamespace;
+ /// <summary>
+ /// The value of the openid.ns parameter that appears on the query string
+ /// whenever data is passed between relying party and provider for OpenID 2.0
+ /// and later.
+ /// </summary>
+ public string QueryDeclaredNamespaceVersion;
+ /// <summary>
+ /// The XRD/Service/Type value discovered in an XRDS document when
+ /// "discovering" on a Claimed Identifier (http://andrewarnott.yahoo.com)
+ /// </summary>
+ public string ClaimedIdentifierServiceTypeURI;
+ /// <summary>
+ /// The XRD/Service/Type value discovered in an XRDS document when
+ /// "discovering" on an OP Identifier rather than a Claimed Identifier.
+ /// (http://yahoo.com)
+ /// </summary>
+ public string OPIdentifierServiceTypeURI;
+ /// <summary>
+ /// The XRD/Service/Type value discovered in an XRDS document when
+ /// "discovering" on a Realm URL and looking for the endpoint URL
+ /// that can receive authentication assertions.
+ /// </summary>
+ public string RPReturnToTypeURI;
+ /// <summary>
+ /// Used as the Claimed Identifier and the OP Local Identifier when
+ /// the User Supplied Identifier is an OP Identifier.
+ /// </summary>
+ public string ClaimedIdentifierForOPIdentifier;
+ /// <summary>
+ /// The value of the 'rel' attribute in an HTML document's LINK tag
+ /// when the same LINK tag's HREF attribute value contains the URL to an
+ /// OP Endpoint URL.
+ /// </summary>
+ public string HtmlDiscoveryProviderKey;
+ /// <summary>
+ /// The value of the 'rel' attribute in an HTML document's LINK tag
+ /// when the same LINK tag's HREF attribute value contains the URL to use
+ /// as the OP Local Identifier.
+ /// </summary>
+ public string HtmlDiscoveryLocalIdKey;
+ /// <summary>
+ /// Parts of the protocol that define parameter names that appear in the
+ /// query string. Each parameter name is prefixed with 'openid.'.
+ /// </summary>
+ public readonly QueryParameters openid;
+ /// <summary>
+ /// Parts of the protocol that define parameter names that appear in the
+ /// query string. Each parameter name is NOT prefixed with 'openid.'.
+ /// </summary>
+ public readonly QueryParameters openidnp;
+ /// <summary>
+ /// The various 'constants' that appear as parameter arguments (values).
+ /// </summary>
+ public QueryArguments Args = new QueryArguments();
+
+ internal sealed class QueryParameters {
+ /// <summary>
+ /// The value "openid."
+ /// </summary>
+ public readonly string Prefix = "openid.";
+ [SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily")]
+ public QueryParameters() { }
+ [SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily")]
+ public QueryParameters(QueryParameters addPrefixTo) {
+ ns = addPrefix(addPrefixTo.ns);
+ return_to = addPrefix(addPrefixTo.return_to);
+ Realm = addPrefix(addPrefixTo.Realm);
+ mode = addPrefix(addPrefixTo.mode);
+ error = addPrefix(addPrefixTo.error);
+ error_code = addPrefix(addPrefixTo.error_code);
+ identity = addPrefix(addPrefixTo.identity);
+ op_endpoint = addPrefix(addPrefixTo.op_endpoint);
+ response_nonce = addPrefix(addPrefixTo.response_nonce);
+ claimed_id = addPrefix(addPrefixTo.claimed_id);
+ expires_in = addPrefix(addPrefixTo.expires_in);
+ assoc_type = addPrefix(addPrefixTo.assoc_type);
+ assoc_handle = addPrefix(addPrefixTo.assoc_handle);
+ session_type = addPrefix(addPrefixTo.session_type);
+ is_valid = addPrefix(addPrefixTo.is_valid);
+ sig = addPrefix(addPrefixTo.sig);
+ signed = addPrefix(addPrefixTo.signed);
+ user_setup_url = addPrefix(addPrefixTo.user_setup_url);
+ invalidate_handle = addPrefix(addPrefixTo.invalidate_handle);
+ dh_modulus = addPrefix(addPrefixTo.dh_modulus);
+ dh_gen = addPrefix(addPrefixTo.dh_gen);
+ dh_consumer_public = addPrefix(addPrefixTo.dh_consumer_public);
+ dh_server_public = addPrefix(addPrefixTo.dh_server_public);
+ enc_mac_key = addPrefix(addPrefixTo.enc_mac_key);
+ mac_key = addPrefix(addPrefixTo.mac_key);
+ }
+ string addPrefix(string original) {
+ return (original != null) ? Prefix + original : null;
+ }
+ // These fields default to 1.x specifications, and are overridden
+ // as necessary by later versions in the Protocol class initializers.
+ // Null values in any version suggests that that feature is absent from that version.
+ public string ns = "ns";
+ public string return_to = "return_to";
+ public string Realm = "trust_root";
+ public string mode = "mode";
+ public string error = "error";
+ public string error_code = null;
+ public string identity = "identity";
+ public string op_endpoint = null;
+ public string response_nonce = null;
+ public string claimed_id = "claimed_id";
+ public string expires_in = "expires_in";
+ public string assoc_type = "assoc_type";
+ public string assoc_handle = "assoc_handle";
+ public string session_type = "session_type";
+ public string is_valid = "is_valid";
+ public string sig = "sig";
+ public string signed = "signed";
+ public string user_setup_url = "user_setup_url";
+ public string invalidate_handle = "invalidate_handle";
+ public string dh_modulus = "dh_modulus";
+ public string dh_gen = "dh_gen";
+ public string dh_consumer_public = "dh_consumer_public";
+ public string dh_server_public = "dh_server_public";
+ public string enc_mac_key = "enc_mac_key";
+ public string mac_key = "mac_key";
+
+#if CONTRACTS_FULL
+ /// <summary>
+ /// Verifies conditions that should be true for any valid state of this object.
+ /// </summary>
+ [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Called by code contracts.")]
+ [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
+ [ContractInvariantMethod]
+ private void ObjectInvariant() {
+ Contract.Invariant(!string.IsNullOrEmpty(this.Prefix));
+ }
+#endif
+ }
+
+ internal sealed class QueryArguments {
+ public ErrorCodes ErrorCode = new ErrorCodes();
+ public SessionTypes SessionType = new SessionTypes();
+ public SignatureAlgorithms SignatureAlgorithm = new SignatureAlgorithms();
+ public Modes Mode = new Modes();
+ public IsValidValues IsValid = new IsValidValues();
+
+ internal sealed class ErrorCodes {
+ public string UnsupportedType = "unsupported-type";
+ }
+ internal sealed class SessionTypes {
+ /// <summary>
+ /// A preference order list of all supported session types.
+ /// </summary>
+ public string[] All { get { return new[] { DH_SHA512, DH_SHA384, DH_SHA256, DH_SHA1, NoEncryption }; } }
+ public string[] AllDiffieHellman { get { return new[] { DH_SHA512, DH_SHA384, DH_SHA256, DH_SHA1 }; } }
+ public string DH_SHA1 = "DH-SHA1";
+ public string DH_SHA256;
+ public string DH_SHA384;
+ public string DH_SHA512;
+ public string NoEncryption = string.Empty;
+ public string Best {
+ get {
+ foreach (string algorithmName in All) {
+ if (algorithmName != null) {
+ return algorithmName;
+ }
+ }
+ throw new ProtocolException(); // really bad... we have no signing algorithms at all
+ }
+ }
+ }
+ internal sealed class SignatureAlgorithms {
+ /// <summary>
+ /// A preference order list of signature algorithms we support.
+ /// </summary>
+ public string[] All { get { return new[] { HMAC_SHA512, HMAC_SHA384, HMAC_SHA256, HMAC_SHA1 }; } }
+ public string HMAC_SHA1 = "HMAC-SHA1";
+ public string HMAC_SHA256;
+ public string HMAC_SHA384;
+ public string HMAC_SHA512;
+ public string Best {
+ get {
+ foreach (string algorithmName in All) {
+ if (algorithmName != null) {
+ return algorithmName;
+ }
+ }
+ throw new ProtocolException(); // really bad... we have no signing algorithms at all
+ }
+ }
+ }
+ internal sealed class Modes {
+ public string cancel = "cancel";
+ public string error = "error";
+ public string id_res = "id_res";
+ public string checkid_immediate = "checkid_immediate";
+ public string checkid_setup = "checkid_setup";
+ public string check_authentication = "check_authentication";
+ public string associate = "associate";
+ public string setup_needed = "id_res"; // V2 overrides this
+ }
+ internal sealed class IsValidValues {
+ public string True = "true";
+ public string False = "false";
+ }
+ }
+
+ /// <summary>
+ /// The maximum time a user can be allowed to take to complete authentication.
+ /// </summary>
+ /// <remarks>
+ /// This is used to calculate the length of time that nonces are stored.
+ /// This is internal until we can decide whether to leave this static, or make
+ /// it an instance member, or put it inside the IConsumerApplicationStore interface.
+ /// </remarks>
+ internal static TimeSpan MaximumUserAgentAuthenticationTime = TimeSpan.FromMinutes(5);
+ /// <summary>
+ /// The maximum permissible difference in clocks between relying party and
+ /// provider web servers, discounting time zone differences.
+ /// </summary>
+ /// <remarks>
+ /// This is used when storing/validating nonces from the provider.
+ /// If it is conceivable that a server's clock could be up to five minutes
+ /// off from true UTC time, then the maximum time skew should be set to
+ /// ten minutes to allow one server to be five minutes ahead and the remote
+ /// server to be five minutes behind and still be able to communicate.
+ /// </remarks>
+ internal static TimeSpan MaximumAllowableTimeSkew = TimeSpan.FromMinutes(10);
+
+ /// <summary>
+ /// Checks whether a given Protocol version practically equals this one
+ /// for purposes of verifying a match for assertion verification.
+ /// </summary>
+ /// <param name="other">The other version to check against this one.</param>
+ /// <returns><c>true</c> if this and the given Protocol versions are essentially the same.</returns>
+ /// <remarks>
+ /// OpenID v1.0 never had a spec, and 1.0 and 1.1 are indistinguishable because of that.
+ /// Therefore for assertion verification, 1.0 and 1.1 are considered equivalent.
+ /// </remarks>
+ public bool EqualsPractically(Protocol other) {
+ if (other == null) {
+ return false;
+ }
+
+ // Exact version match is definitely equality.
+ if (this.Version == other.Version) {
+ return true;
+ }
+
+ // If both protocol versions are 1.x, it doesn't matter if one
+ // is 1.0 and the other is 1.1 for assertion verification purposes.
+ if (this.Version.Major == 1 && other.Version.Major == 1) {
+ return true;
+ }
+
+ // Different version.
+ return false;
+ }
+
+ public override bool Equals(object obj) {
+ Protocol other = obj as Protocol;
+ if (other == null) {
+ return false;
+ }
+
+ return this.Version == other.Version;
+ }
+ public override int GetHashCode() {
+ return Version.GetHashCode();
+ }
+ public override string ToString() {
+ return string.Format(CultureInfo.CurrentCulture, "OpenID Authentication {0}.{1}", Version.Major, Version.Minor);
+ }
+ }
+}