summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OpenId
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OpenId')
-rw-r--r--src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj4
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs2
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/IIdentifierDiscoveryService.cs67
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/IProviderEndpoint.cs144
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/IdentifierDiscoveryResult.cs497
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/ProviderEndpointDescription.cs134
-rw-r--r--src/DotNetOpenAuth.OpenId/Properties/AssemblyInfo.cs2
7 files changed, 847 insertions, 3 deletions
diff --git a/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj b/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj
index eeffeee..c7c5e77 100644
--- a/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj
+++ b/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj
@@ -83,6 +83,9 @@
<Compile Include="OpenId\Identifier.cs" />
<Compile Include="OpenId\IdentifierContract.cs" />
<Compile Include="OpenId\Extensions\ExtensionsInteropHelper.cs" />
+ <Compile Include="OpenId\IdentifierDiscoveryResult.cs" />
+ <Compile Include="OpenId\IIdentifierDiscoveryService.cs" />
+ <Compile Include="OpenId\IProviderEndpoint.cs" />
<Compile Include="OpenId\Messages\CheckAuthenticationRequest.cs" />
<Compile Include="OpenId\Messages\CheckAuthenticationResponse.cs" />
<Compile Include="OpenId\Messages\CheckIdRequest.cs" />
@@ -97,6 +100,7 @@
<Compile Include="OpenId\NoDiscoveryIdentifier.cs" />
<Compile Include="OpenId\OpenIdUtilities.cs" />
<Compile Include="OpenId\OpenIdXrdsHelper.cs" />
+ <Compile Include="OpenId\ProviderEndpointDescription.cs" />
<Compile Include="OpenId\Realm.cs" />
<Compile Include="OpenId\RelyingPartyDescription.cs" />
<Compile Include="OpenId\DiffieHellmanUtilities.cs" />
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs
index 2f1c7da..cc49a95 100644
--- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs
+++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs
@@ -46,7 +46,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
/// <param name="messageTypeProvider">A class prepared to analyze incoming messages and indicate what concrete
/// message types can deserialize from it.</param>
/// <param name="bindingElements">The binding elements to use in sending and receiving messages.</param>
- private OpenIdChannel(IMessageFactory messageTypeProvider, IChannelBindingElement[] bindingElements)
+ protected OpenIdChannel(IMessageFactory messageTypeProvider, IChannelBindingElement[] bindingElements)
: base(messageTypeProvider, bindingElements) {
Contract.Requires<ArgumentNullException>(messageTypeProvider != null);
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/IIdentifierDiscoveryService.cs b/src/DotNetOpenAuth.OpenId/OpenId/IIdentifierDiscoveryService.cs
new file mode 100644
index 0000000..fcea327
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenId/OpenId/IIdentifierDiscoveryService.cs
@@ -0,0 +1,67 @@
+//-----------------------------------------------------------------------
+// <copyright file="IIdentifierDiscoveryService.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.RelyingParty;
+
+ /// <summary>
+ /// A module that provides discovery services for OpenID identifiers.
+ /// </summary>
+ [ContractClass(typeof(IIdentifierDiscoveryServiceContract))]
+ public interface IIdentifierDiscoveryService {
+ /// <summary>
+ /// Performs discovery on the specified identifier.
+ /// </summary>
+ /// <param name="identifier">The identifier to perform discovery on.</param>
+ /// <param name="requestHandler">The means to place outgoing HTTP requests.</param>
+ /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param>
+ /// <returns>
+ /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty.
+ /// </returns>
+ [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "By design")]
+ [Pure]
+ IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain);
+ }
+
+ /// <summary>
+ /// Code contract for the <see cref="IIdentifierDiscoveryService"/> interface.
+ /// </summary>
+ [ContractClassFor(typeof(IIdentifierDiscoveryService))]
+ internal abstract class IIdentifierDiscoveryServiceContract : IIdentifierDiscoveryService {
+ /// <summary>
+ /// Prevents a default instance of the <see cref="IIdentifierDiscoveryServiceContract"/> class from being created.
+ /// </summary>
+ private IIdentifierDiscoveryServiceContract() {
+ }
+
+ #region IDiscoveryService Members
+
+ /// <summary>
+ /// Performs discovery on the specified identifier.
+ /// </summary>
+ /// <param name="identifier">The identifier to perform discovery on.</param>
+ /// <param name="requestHandler">The means to place outgoing HTTP requests.</param>
+ /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param>
+ /// <returns>
+ /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty.
+ /// </returns>
+ IEnumerable<IdentifierDiscoveryResult> IIdentifierDiscoveryService.Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) {
+ Contract.Requires<ArgumentNullException>(identifier != null);
+ Contract.Requires<ArgumentNullException>(requestHandler != null);
+ Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null);
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/IProviderEndpoint.cs b/src/DotNetOpenAuth.OpenId/OpenId/IProviderEndpoint.cs
new file mode 100644
index 0000000..5d8918d
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenId/OpenId/IProviderEndpoint.cs
@@ -0,0 +1,144 @@
+//-----------------------------------------------------------------------
+// <copyright file="IProviderEndpoint.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.RelyingParty {
+ using System;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Globalization;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+
+ /// <summary>
+ /// Information published about an OpenId Provider by the
+ /// OpenId discovery documents found at a user's Claimed Identifier.
+ /// </summary>
+ /// <remarks>
+ /// Because information provided by this interface is suppplied by a
+ /// user's individually published documents, it may be incomplete or inaccurate.
+ /// </remarks>
+ [ContractClass(typeof(IProviderEndpointContract))]
+ public interface IProviderEndpoint {
+ /// <summary>
+ /// Gets the detected version of OpenID implemented by the Provider.
+ /// </summary>
+ Version Version { get; }
+
+ /// <summary>
+ /// Gets the URL that the OpenID Provider receives authentication requests at.
+ /// </summary>
+ /// <value>
+ /// This value MUST be an absolute HTTP or HTTPS URL.
+ /// </value>
+ Uri Uri { get; }
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <typeparam name="T">The extension whose support is being queried.</typeparam>
+ /// <returns>True if support for the extension is advertised. False otherwise.</returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "No parameter at all.")]
+ [Obsolete("Use IAuthenticationRequest.DiscoveryResult.IsExtensionSupported instead.")]
+ bool IsExtensionSupported<T>() where T : IOpenIdMessageExtension, new();
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <param name="extensionType">The extension whose support is being queried.</param>
+ /// <returns>True if support for the extension is advertised. False otherwise.</returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ [Obsolete("Use IAuthenticationRequest.DiscoveryResult.IsExtensionSupported instead.")]
+ bool IsExtensionSupported(Type extensionType);
+ }
+
+ /// <summary>
+ /// Code contract for the <see cref="IProviderEndpoint"/> type.
+ /// </summary>
+ [ContractClassFor(typeof(IProviderEndpoint))]
+ internal abstract class IProviderEndpointContract : IProviderEndpoint {
+ /// <summary>
+ /// Prevents a default instance of the <see cref="IProviderEndpointContract"/> class from being created.
+ /// </summary>
+ private IProviderEndpointContract() {
+ }
+
+ #region IProviderEndpoint Members
+
+ /// <summary>
+ /// Gets the detected version of OpenID implemented by the Provider.
+ /// </summary>
+ Version IProviderEndpoint.Version {
+ get {
+ Contract.Ensures(Contract.Result<Version>() != null);
+ throw new System.NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Gets the URL that the OpenID Provider receives authentication requests at.
+ /// </summary>
+ Uri IProviderEndpoint.Uri {
+ get {
+ Contract.Ensures(Contract.Result<Uri>() != null);
+ throw new System.NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <typeparam name="T">The extension whose support is being queried.</typeparam>
+ /// <returns>
+ /// True if support for the extension is advertised. False otherwise.
+ /// </returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ bool IProviderEndpoint.IsExtensionSupported<T>() {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <param name="extensionType">The extension whose support is being queried.</param>
+ /// <returns>
+ /// True if support for the extension is advertised. False otherwise.
+ /// </returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ bool IProviderEndpoint.IsExtensionSupported(Type extensionType) {
+ Contract.Requires<ArgumentNullException>(extensionType != null);
+ Contract.Requires<ArgumentException>(typeof(IOpenIdMessageExtension).IsAssignableFrom(extensionType));
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/IdentifierDiscoveryResult.cs b/src/DotNetOpenAuth.OpenId/OpenId/IdentifierDiscoveryResult.cs
new file mode 100644
index 0000000..c851f24
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenId/OpenId/IdentifierDiscoveryResult.cs
@@ -0,0 +1,497 @@
+//-----------------------------------------------------------------------
+// <copyright file="IdentifierDiscoveryResult.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId {
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Globalization;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+ using DotNetOpenAuth.OpenId.RelyingParty;
+
+ /// <summary>
+ /// Represents a single OP endpoint from discovery on some OpenID Identifier.
+ /// </summary>
+ [DebuggerDisplay("ClaimedIdentifier: {ClaimedIdentifier}, ProviderEndpoint: {ProviderEndpoint}, OpenId: {Protocol.Version}")]
+ public sealed class IdentifierDiscoveryResult : IProviderEndpoint {
+ /// <summary>
+ /// Backing field for the <see cref="Protocol"/> property.
+ /// </summary>
+ private Protocol protocol;
+
+ /// <summary>
+ /// Backing field for the <see cref="ClaimedIdentifier"/> property.
+ /// </summary>
+ private Identifier claimedIdentifier;
+
+ /// <summary>
+ /// Backing field for the <see cref="FriendlyIdentifierForDisplay"/> property.
+ /// </summary>
+ private string friendlyIdentifierForDisplay;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IdentifierDiscoveryResult"/> class.
+ /// </summary>
+ /// <param name="providerEndpoint">The provider endpoint.</param>
+ /// <param name="claimedIdentifier">The Claimed Identifier.</param>
+ /// <param name="userSuppliedIdentifier">The User-supplied Identifier.</param>
+ /// <param name="providerLocalIdentifier">The Provider Local Identifier.</param>
+ /// <param name="servicePriority">The service priority.</param>
+ /// <param name="uriPriority">The URI priority.</param>
+ private IdentifierDiscoveryResult(ProviderEndpointDescription providerEndpoint, Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, int? servicePriority, int? uriPriority) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+ Contract.Requires<ArgumentNullException>(claimedIdentifier != null);
+ this.ProviderEndpoint = providerEndpoint.Uri;
+ this.Capabilities = new ReadOnlyCollection<string>(providerEndpoint.Capabilities);
+ this.Version = providerEndpoint.Version;
+ this.ClaimedIdentifier = claimedIdentifier;
+ this.ProviderLocalIdentifier = providerLocalIdentifier ?? claimedIdentifier;
+ this.UserSuppliedIdentifier = userSuppliedIdentifier;
+ this.ServicePriority = servicePriority;
+ this.ProviderEndpointPriority = uriPriority;
+ }
+
+ /// <summary>
+ /// Gets the detected version of OpenID implemented by the Provider.
+ /// </summary>
+ public Version Version { get; private set; }
+
+ /// <summary>
+ /// Gets the Identifier that was presented by the end user to the Relying Party,
+ /// or selected by the user at the OpenID Provider.
+ /// During the initiation phase of the protocol, an end user may enter
+ /// either their own Identifier or an OP Identifier. If an OP Identifier
+ /// is used, the OP may then assist the end user in selecting an Identifier
+ /// to share with the Relying Party.
+ /// </summary>
+ public Identifier UserSuppliedIdentifier { get; private set; }
+
+ /// <summary>
+ /// Gets the Identifier that the end user claims to control.
+ /// </summary>
+ public Identifier ClaimedIdentifier {
+ get {
+ return this.claimedIdentifier;
+ }
+
+ internal set {
+ // Take care to reparse the incoming identifier to make sure it's
+ // not a derived type that will override expected behavior.
+ // Elsewhere in this class, we count on the fact that this property
+ // is either UriIdentifier or XriIdentifier. MockIdentifier messes it up.
+ this.claimedIdentifier = value != null ? Identifier.Reparse(value) : null;
+ }
+ }
+
+ /// <summary>
+ /// Gets an alternate Identifier for an end user that is local to a
+ /// particular OP and thus not necessarily under the end user's
+ /// control.
+ /// </summary>
+ public Identifier ProviderLocalIdentifier { get; private set; }
+
+ /// <summary>
+ /// Gets a more user-friendly (but NON-secure!) string to display to the user as his identifier.
+ /// </summary>
+ /// <returns>A human-readable, abbreviated (but not secure) identifier the user MAY recognize as his own.</returns>
+ public string FriendlyIdentifierForDisplay {
+ get {
+ if (this.friendlyIdentifierForDisplay == null) {
+ XriIdentifier xri = this.ClaimedIdentifier as XriIdentifier;
+ UriIdentifier uri = this.ClaimedIdentifier as UriIdentifier;
+ if (xri != null) {
+ if (this.UserSuppliedIdentifier == null || String.Equals(this.UserSuppliedIdentifier, this.ClaimedIdentifier, StringComparison.OrdinalIgnoreCase)) {
+ this.friendlyIdentifierForDisplay = this.ClaimedIdentifier;
+ } else {
+ this.friendlyIdentifierForDisplay = this.UserSuppliedIdentifier;
+ }
+ } else if (uri != null) {
+ if (uri != this.Protocol.ClaimedIdentifierForOPIdentifier) {
+ string displayUri = uri.Uri.Host;
+
+ // We typically want to display the path, because that will often have the username in it.
+ // As Google Apps for Domains and the like become more popular, a standard /openid path
+ // will often appear, which is not helpful to identifying the user so we'll avoid including
+ // that path if it's present.
+ if (!string.Equals(uri.Uri.AbsolutePath, "/openid", StringComparison.OrdinalIgnoreCase)) {
+ displayUri += uri.Uri.AbsolutePath.TrimEnd('/');
+ }
+
+ // Multi-byte unicode characters get encoded by the Uri class for transit.
+ // Since this is for display purposes, we want to reverse this and display a readable
+ // representation of these foreign characters.
+ this.friendlyIdentifierForDisplay = Uri.UnescapeDataString(displayUri);
+ }
+ } else {
+ ErrorUtilities.ThrowInternal("ServiceEndpoint.ClaimedIdentifier neither XRI nor URI.");
+ this.friendlyIdentifierForDisplay = this.ClaimedIdentifier;
+ }
+ }
+
+ return this.friendlyIdentifierForDisplay;
+ }
+ }
+
+ /// <summary>
+ /// Gets the provider endpoint.
+ /// </summary>
+ public Uri ProviderEndpoint { get; private set; }
+
+ /// <summary>
+ /// Gets the @priority given in the XRDS document for this specific OP endpoint.
+ /// </summary>
+ public int? ProviderEndpointPriority { get; private set; }
+
+ /// <summary>
+ /// Gets the @priority given in the XRDS document for this service
+ /// (which may consist of several endpoints).
+ /// </summary>
+ public int? ServicePriority { get; private set; }
+
+ /// <summary>
+ /// Gets the collection of service type URIs found in the XRDS document describing this Provider.
+ /// </summary>
+ /// <value>Should never be null, but may be empty.</value>
+ public ReadOnlyCollection<string> Capabilities { get; private set; }
+
+ #region IProviderEndpoint Members
+
+ /// <summary>
+ /// Gets the URL that the OpenID Provider receives authentication requests at.
+ /// </summary>
+ /// <value>This value MUST be an absolute HTTP or HTTPS URL.</value>
+ Uri IProviderEndpoint.Uri {
+ get { return this.ProviderEndpoint; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets an XRDS sorting routine that uses the XRDS Service/@Priority
+ /// attribute to determine order.
+ /// </summary>
+ /// <remarks>
+ /// Endpoints lacking any priority value are sorted to the end of the list.
+ /// </remarks>
+ internal static Comparison<IdentifierDiscoveryResult> EndpointOrder {
+ get {
+ // Sort first by service type (OpenID 2.0, 1.1, 1.0),
+ // then by Service/@priority, then by Service/Uri/@priority
+ return (se1, se2) => {
+ int result = GetEndpointPrecedenceOrderByServiceType(se1).CompareTo(GetEndpointPrecedenceOrderByServiceType(se2));
+ if (result != 0) {
+ return result;
+ }
+ if (se1.ServicePriority.HasValue && se2.ServicePriority.HasValue) {
+ result = se1.ServicePriority.Value.CompareTo(se2.ServicePriority.Value);
+ if (result != 0) {
+ return result;
+ }
+ if (se1.ProviderEndpointPriority.HasValue && se2.ProviderEndpointPriority.HasValue) {
+ return se1.ProviderEndpointPriority.Value.CompareTo(se2.ProviderEndpointPriority.Value);
+ } else if (se1.ProviderEndpointPriority.HasValue) {
+ return -1;
+ } else if (se2.ProviderEndpointPriority.HasValue) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ if (se1.ServicePriority.HasValue) {
+ return -1;
+ } else if (se2.ServicePriority.HasValue) {
+ return 1;
+ } else {
+ // neither service defines a priority, so base ordering by uri priority.
+ if (se1.ProviderEndpointPriority.HasValue && se2.ProviderEndpointPriority.HasValue) {
+ return se1.ProviderEndpointPriority.Value.CompareTo(se2.ProviderEndpointPriority.Value);
+ } else if (se1.ProviderEndpointPriority.HasValue) {
+ return -1;
+ } else if (se2.ProviderEndpointPriority.HasValue) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ };
+ }
+ }
+
+ /// <summary>
+ /// Gets the protocol used by the OpenID Provider.
+ /// </summary>
+ internal Protocol Protocol {
+ get {
+ if (this.protocol == null) {
+ this.protocol = Protocol.Lookup(this.Version);
+ }
+
+ return this.protocol;
+ }
+ }
+
+ /// <summary>
+ /// Implements the operator ==.
+ /// </summary>
+ /// <param name="se1">The first service endpoint.</param>
+ /// <param name="se2">The second service endpoint.</param>
+ /// <returns>The result of the operator.</returns>
+ public static bool operator ==(IdentifierDiscoveryResult se1, IdentifierDiscoveryResult se2) {
+ return se1.EqualsNullSafe(se2);
+ }
+
+ /// <summary>
+ /// Implements the operator !=.
+ /// </summary>
+ /// <param name="se1">The first service endpoint.</param>
+ /// <param name="se2">The second service endpoint.</param>
+ /// <returns>The result of the operator.</returns>
+ public static bool operator !=(IdentifierDiscoveryResult se1, IdentifierDiscoveryResult se2) {
+ return !(se1 == se2);
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
+ /// </summary>
+ /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
+ /// <returns>
+ /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
+ /// </returns>
+ /// <exception cref="T:System.NullReferenceException">
+ /// The <paramref name="obj"/> parameter is null.
+ /// </exception>
+ public override bool Equals(object obj) {
+ var other = obj as IdentifierDiscoveryResult;
+ if (other == null) {
+ return false;
+ }
+
+ // We specifically do not check our ProviderSupportedServiceTypeUris array
+ // or the priority field
+ // as that is not persisted in our tokens, and it is not part of the
+ // important assertion validation that is part of the spec.
+ return
+ this.ClaimedIdentifier == other.ClaimedIdentifier &&
+ this.ProviderEndpoint == other.ProviderEndpoint &&
+ this.ProviderLocalIdentifier == other.ProviderLocalIdentifier &&
+ this.Protocol.EqualsPractically(other.Protocol);
+ }
+
+ /// <summary>
+ /// Serves as a hash function for a particular type.
+ /// </summary>
+ /// <returns>
+ /// A hash code for the current <see cref="T:System.Object"/>.
+ /// </returns>
+ public override int GetHashCode() {
+ return this.ClaimedIdentifier.GetHashCode();
+ }
+
+ /// <summary>
+ /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
+ /// </returns>
+ public override string ToString() {
+ StringBuilder builder = new StringBuilder();
+ builder.AppendLine("ClaimedIdentifier: " + this.ClaimedIdentifier);
+ builder.AppendLine("ProviderLocalIdentifier: " + this.ProviderLocalIdentifier);
+ builder.AppendLine("ProviderEndpoint: " + this.ProviderEndpoint);
+ builder.AppendLine("OpenID version: " + this.Version);
+ builder.AppendLine("Service Type URIs:");
+ foreach (string serviceTypeUri in this.Capabilities) {
+ builder.Append("\t");
+ builder.AppendLine(serviceTypeUri);
+ }
+ builder.Length -= Environment.NewLine.Length; // trim last newline
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <typeparam name="T">The extension whose support is being queried.</typeparam>
+ /// <returns>
+ /// True if support for the extension is advertised. False otherwise.
+ /// </returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "No parameter at all.")]
+ public bool IsExtensionSupported<T>() where T : IOpenIdMessageExtension, new() {
+ T extension = new T();
+ return this.IsExtensionSupported(extension);
+ }
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <param name="extensionType">The extension whose support is being queried.</param>
+ /// <returns>
+ /// True if support for the extension is advertised. False otherwise.
+ /// </returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ public bool IsExtensionSupported(Type extensionType) {
+ var extension = (IOpenIdMessageExtension)Activator.CreateInstance(extensionType);
+ return this.IsExtensionSupported(extension);
+ }
+
+ /// <summary>
+ /// Determines whether a given extension is supported by this endpoint.
+ /// </summary>
+ /// <param name="extension">An instance of the extension to check support for.</param>
+ /// <returns>
+ /// <c>true</c> if the extension is supported by this endpoint; otherwise, <c>false</c>.
+ /// </returns>
+ public bool IsExtensionSupported(IOpenIdMessageExtension extension) {
+ Contract.Requires<ArgumentNullException>(extension != null);
+
+ // Consider the primary case.
+ if (this.IsTypeUriPresent(extension.TypeUri)) {
+ return true;
+ }
+
+ // Consider the secondary cases.
+ if (extension.AdditionalSupportedTypeUris != null) {
+ if (extension.AdditionalSupportedTypeUris.Any(typeUri => this.IsTypeUriPresent(typeUri))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Creates a <see cref="IdentifierDiscoveryResult"/> instance to represent some OP Identifier.
+ /// </summary>
+ /// <param name="providerIdentifier">The provider identifier (actually the user-supplied identifier).</param>
+ /// <param name="providerEndpoint">The provider endpoint.</param>
+ /// <param name="servicePriority">The service priority.</param>
+ /// <param name="uriPriority">The URI priority.</param>
+ /// <returns>The created <see cref="IdentifierDiscoveryResult"/> instance</returns>
+ internal static IdentifierDiscoveryResult CreateForProviderIdentifier(Identifier providerIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+
+ Protocol protocol = Protocol.Lookup(providerEndpoint.Version);
+
+ return new IdentifierDiscoveryResult(
+ providerEndpoint,
+ protocol.ClaimedIdentifierForOPIdentifier,
+ providerIdentifier,
+ protocol.ClaimedIdentifierForOPIdentifier,
+ servicePriority,
+ uriPriority);
+ }
+
+ /// <summary>
+ /// Creates a <see cref="IdentifierDiscoveryResult"/> instance to represent some Claimed Identifier.
+ /// </summary>
+ /// <param name="claimedIdentifier">The claimed identifier.</param>
+ /// <param name="providerLocalIdentifier">The provider local identifier.</param>
+ /// <param name="providerEndpoint">The provider endpoint.</param>
+ /// <param name="servicePriority">The service priority.</param>
+ /// <param name="uriPriority">The URI priority.</param>
+ /// <returns>The created <see cref="IdentifierDiscoveryResult"/> instance</returns>
+ internal static IdentifierDiscoveryResult CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier providerLocalIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) {
+ return CreateForClaimedIdentifier(claimedIdentifier, null, providerLocalIdentifier, providerEndpoint, servicePriority, uriPriority);
+ }
+
+ /// <summary>
+ /// Creates a <see cref="IdentifierDiscoveryResult"/> instance to represent some Claimed Identifier.
+ /// </summary>
+ /// <param name="claimedIdentifier">The claimed identifier.</param>
+ /// <param name="userSuppliedIdentifier">The user supplied identifier.</param>
+ /// <param name="providerLocalIdentifier">The provider local identifier.</param>
+ /// <param name="providerEndpoint">The provider endpoint.</param>
+ /// <param name="servicePriority">The service priority.</param>
+ /// <param name="uriPriority">The URI priority.</param>
+ /// <returns>The created <see cref="IdentifierDiscoveryResult"/> instance</returns>
+ internal static IdentifierDiscoveryResult CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) {
+ return new IdentifierDiscoveryResult(providerEndpoint, claimedIdentifier, userSuppliedIdentifier, providerLocalIdentifier, servicePriority, uriPriority);
+ }
+
+ /// <summary>
+ /// Determines whether a given type URI is present on the specified provider endpoint.
+ /// </summary>
+ /// <param name="typeUri">The type URI.</param>
+ /// <returns>
+ /// <c>true</c> if the type URI is present on the specified provider endpoint; otherwise, <c>false</c>.
+ /// </returns>
+ internal bool IsTypeUriPresent(string typeUri) {
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(typeUri));
+ return this.Capabilities.Contains(typeUri);
+ }
+
+ /// <summary>
+ /// Sets the Capabilities property (this method is a test hook.)
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <remarks>The publicize.exe tool should work for the unit tests, but for some reason it fails on the build server.</remarks>
+ internal void SetCapabilitiesForTestHook(ReadOnlyCollection<string> value) {
+ this.Capabilities = value;
+ }
+
+ /// <summary>
+ /// Gets the priority rating for a given type of endpoint, allowing a
+ /// priority sorting of endpoints.
+ /// </summary>
+ /// <param name="endpoint">The endpoint to prioritize.</param>
+ /// <returns>An arbitary integer, which may be used for sorting against other returned values from this method.</returns>
+ private static double GetEndpointPrecedenceOrderByServiceType(IdentifierDiscoveryResult endpoint) {
+ // The numbers returned from this method only need to compare against other numbers
+ // from this method, which makes them arbitrary but relational to only others here.
+ if (endpoint.Capabilities.Contains(Protocol.V20.OPIdentifierServiceTypeURI)) {
+ return 0;
+ }
+ if (endpoint.Capabilities.Contains(Protocol.V20.ClaimedIdentifierServiceTypeURI)) {
+ return 1;
+ }
+ if (endpoint.Capabilities.Contains(Protocol.V11.ClaimedIdentifierServiceTypeURI)) {
+ return 2;
+ }
+ if (endpoint.Capabilities.Contains(Protocol.V10.ClaimedIdentifierServiceTypeURI)) {
+ return 3;
+ }
+ return 10;
+ }
+
+#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(this.ProviderEndpoint != null);
+ Contract.Invariant(this.ClaimedIdentifier != null);
+ Contract.Invariant(this.ProviderLocalIdentifier != null);
+ Contract.Invariant(this.Capabilities != null);
+ Contract.Invariant(this.Version != null);
+ Contract.Invariant(this.Protocol != null);
+ }
+#endif
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ProviderEndpointDescription.cs b/src/DotNetOpenAuth.OpenId/OpenId/ProviderEndpointDescription.cs
new file mode 100644
index 0000000..6514ffd
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenId/OpenId/ProviderEndpointDescription.cs
@@ -0,0 +1,134 @@
+//-----------------------------------------------------------------------
+// <copyright file="ProviderEndpointDescription.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId {
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+ using DotNetOpenAuth.OpenId.RelyingParty;
+
+ /// <summary>
+ /// Describes some OpenID Provider endpoint and its capabilities.
+ /// </summary>
+ /// <remarks>
+ /// This is an immutable type.
+ /// </remarks>
+ [Serializable]
+ internal sealed class ProviderEndpointDescription : IProviderEndpoint {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ProviderEndpointDescription"/> class.
+ /// </summary>
+ /// <param name="providerEndpoint">The OpenID Provider endpoint URL.</param>
+ /// <param name="openIdVersion">The OpenID version supported by this particular endpoint.</param>
+ internal ProviderEndpointDescription(Uri providerEndpoint, Version openIdVersion) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+ Contract.Requires<ArgumentNullException>(openIdVersion != null);
+
+ this.Uri = providerEndpoint;
+ this.Version = openIdVersion;
+ this.Capabilities = new ReadOnlyCollection<string>(EmptyList<string>.Instance);
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ProviderEndpointDescription"/> class.
+ /// </summary>
+ /// <param name="providerEndpoint">The URI the provider listens on for OpenID requests.</param>
+ /// <param name="serviceTypeURIs">The set of services offered by this endpoint.</param>
+ internal ProviderEndpointDescription(Uri providerEndpoint, IEnumerable<string> serviceTypeURIs) {
+ Contract.Requires<ArgumentNullException>(providerEndpoint != null);
+ Contract.Requires<ArgumentNullException>(serviceTypeURIs != null);
+
+ this.Uri = providerEndpoint;
+ this.Capabilities = new ReadOnlyCollection<string>(serviceTypeURIs.ToList());
+
+ Protocol opIdentifierProtocol = Protocol.FindBestVersion(p => p.OPIdentifierServiceTypeURI, serviceTypeURIs);
+ Protocol claimedIdentifierProviderVersion = Protocol.FindBestVersion(p => p.ClaimedIdentifierServiceTypeURI, serviceTypeURIs);
+ if (opIdentifierProtocol != null) {
+ this.Version = opIdentifierProtocol.Version;
+ } else if (claimedIdentifierProviderVersion != null) {
+ this.Version = claimedIdentifierProviderVersion.Version;
+ } else {
+ ErrorUtilities.ThrowProtocol(OpenIdStrings.ProviderVersionUnrecognized, this.Uri);
+ }
+ }
+
+ /// <summary>
+ /// Gets the URL that the OpenID Provider listens for incoming OpenID messages on.
+ /// </summary>
+ public Uri Uri { get; private set; }
+
+ /// <summary>
+ /// Gets the OpenID protocol version this endpoint supports.
+ /// </summary>
+ /// <remarks>
+ /// If an endpoint supports multiple versions, each version must be represented
+ /// by its own <see cref="ProviderEndpointDescription"/> object.
+ /// </remarks>
+ public Version Version { get; private set; }
+
+ /// <summary>
+ /// Gets the collection of service type URIs found in the XRDS document describing this Provider.
+ /// </summary>
+ internal ReadOnlyCollection<string> Capabilities { get; private set; }
+
+ #region IProviderEndpoint Members
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <typeparam name="T">The extension whose support is being queried.</typeparam>
+ /// <returns>
+ /// True if support for the extension is advertised. False otherwise.
+ /// </returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ bool IProviderEndpoint.IsExtensionSupported<T>() {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Checks whether the OpenId Identifier claims support for a given extension.
+ /// </summary>
+ /// <param name="extensionType">The extension whose support is being queried.</param>
+ /// <returns>
+ /// True if support for the extension is advertised. False otherwise.
+ /// </returns>
+ /// <remarks>
+ /// Note that a true or false return value is no guarantee of a Provider's
+ /// support for or lack of support for an extension. The return value is
+ /// determined by how the authenticating user filled out his/her XRDS document only.
+ /// The only way to be sure of support for a given extension is to include
+ /// the extension in the request and see if a response comes back for that extension.
+ /// </remarks>
+ bool IProviderEndpoint.IsExtensionSupported(Type extensionType) {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+#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(this.Capabilities != null);
+ }
+#endif
+ }
+}
diff --git a/src/DotNetOpenAuth.OpenId/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.OpenId/Properties/AssemblyInfo.cs
index a043ec6..af88627 100644
--- a/src/DotNetOpenAuth.OpenId/Properties/AssemblyInfo.cs
+++ b/src/DotNetOpenAuth.OpenId/Properties/AssemblyInfo.cs
@@ -18,8 +18,6 @@ using System.Security.Permissions;
using System.Web.UI;
[assembly: TagPrefix("DotNetOpenAuth.OpenId", "openid")]
-[assembly: TagPrefix("DotNetOpenAuth.OpenId.Provider", "op")]
-[assembly: TagPrefix("DotNetOpenAuth.OpenId.RelyingParty", "rp")]
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information