//----------------------------------------------------------------------- // // Copyright (c) Outercurve Foundation. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenId { using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using DotNetOpenAuth.Configuration; using DotNetOpenAuth.Logging; using DotNetOpenAuth.Messaging; using Validation; /// /// A service that can perform discovery on OpenID identifiers. /// internal class IdentifierDiscoveryServices { /// /// The RP or OP that is hosting these services. /// private readonly IOpenIdHost host; /// /// Backing field for the property. /// private readonly IList discoveryServices = new List(2); /// /// Initializes a new instance of the class. /// /// The RP or OP that creates this instance. internal IdentifierDiscoveryServices(IOpenIdHost host) { Requires.NotNull(host, "host"); this.host = host; this.discoveryServices.AddRange(OpenIdElement.Configuration.RelyingParty.DiscoveryServices.CreateInstances(true, host.HostFactories)); } /// /// Gets the list of services that can perform discovery on identifiers given. /// public IList DiscoveryServices { get { return this.discoveryServices; } } /// /// Performs discovery on the specified identifier. /// /// The identifier to discover services for. /// The cancellation token. /// A non-null sequence of services discovered for the identifier. public async Task> DiscoverAsync(Identifier identifier, CancellationToken cancellationToken) { Requires.NotNull(identifier, "identifier"); IEnumerable results = Enumerable.Empty(); foreach (var discoverer in this.DiscoveryServices) { var discoveryResults = await discoverer.DiscoverAsync(identifier, cancellationToken); results = results.Concat(discoveryResults.Results.CacheGeneratedResults()); if (discoveryResults.AbortDiscoveryChain) { Logger.OpenId.InfoFormat("Further discovery on '{0}' was stopped by the {1} discovery service.", identifier, discoverer.GetType().Name); break; } } // If any OP Identifier service elements were found, we must not proceed // to use any Claimed Identifier services, per OpenID 2.0 sections 7.3.2.2 and 11.2. // For a discussion on this topic, see // http://groups.google.com/group/dotnetopenid/browse_thread/thread/4b5a8c6b2210f387/5e25910e4d2252c8 // Sometimes the IIdentifierDiscoveryService will automatically filter this for us, but // just to be sure, we'll do it here as well. if (!this.host.SecuritySettings.AllowDualPurposeIdentifiers) { results = results.CacheGeneratedResults(); // avoid performing discovery repeatedly var opIdentifiers = results.Where(result => result.ClaimedIdentifier == result.Protocol.ClaimedIdentifierForOPIdentifier); var claimedIdentifiers = results.Where(result => result.ClaimedIdentifier != result.Protocol.ClaimedIdentifierForOPIdentifier); results = opIdentifiers.Any() ? opIdentifiers : claimedIdentifiers; } return results; } } }