/// <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> public IEnumerable <IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) { abortDiscoveryChain = false; var uriIdentifier = identifier as UriIdentifier; if (uriIdentifier == null) { return(Enumerable.Empty <IdentifierDiscoveryResult>()); } var endpoints = new List <IdentifierDiscoveryResult>(); // Attempt YADIS discovery DiscoveryResult yadisResult = Yadis.Discover(requestHandler, uriIdentifier, identifier.IsDiscoverySecureEndToEnd); if (yadisResult != null) { if (yadisResult.IsXrds) { try { XrdsDocument xrds = new XrdsDocument(yadisResult.ResponseText); var xrdsEndpoints = xrds.XrdElements.CreateServiceEndpoints(yadisResult.NormalizedUri, uriIdentifier); // Filter out insecure endpoints if high security is required. if (uriIdentifier.IsDiscoverySecureEndToEnd) { xrdsEndpoints = xrdsEndpoints.Where(se => se.ProviderEndpoint.IsTransportSecure()); } endpoints.AddRange(xrdsEndpoints); } catch (XmlException ex) { Logger.Yadis.Error("Error while parsing the XRDS document. Falling back to HTML discovery.", ex); } } // Failing YADIS discovery of an XRDS document, we try HTML discovery. if (endpoints.Count == 0) { var htmlEndpoints = new List <IdentifierDiscoveryResult>(DiscoverFromHtml(yadisResult.NormalizedUri, uriIdentifier, yadisResult.ResponseText)); if (htmlEndpoints.Any()) { Logger.Yadis.DebugFormat("Total services discovered in HTML: {0}", htmlEndpoints.Count); Logger.Yadis.Debug(htmlEndpoints.ToStringDeferred(true)); endpoints.AddRange(htmlEndpoints.Where(ep => !uriIdentifier.IsDiscoverySecureEndToEnd || ep.ProviderEndpoint.IsTransportSecure())); if (endpoints.Count == 0) { Logger.Yadis.Info("No HTML discovered endpoints met the security requirements."); } } else { Logger.Yadis.Debug("HTML discovery failed to find any endpoints."); } } else { Logger.Yadis.Debug("Skipping HTML discovery because XRDS contained service endpoints."); } } return(endpoints); }
/// <summary> /// Downloads the XRDS document for this XRI. /// </summary> /// <param name="requestHandler">The request handler.</param> /// <returns>The XRDS document.</returns> private XrdsDocument DownloadXrds(IDirectWebRequestHandler requestHandler) { XrdsDocument doc; using (var xrdsResponse = Yadis.Request(requestHandler, this.XrdsUrl, this.IsDiscoverySecureEndToEnd)) { doc = new XrdsDocument(XmlReader.Create(xrdsResponse.ResponseStream)); } ErrorUtilities.VerifyProtocol(doc.IsXrdResolutionSuccessful, OpenIdStrings.XriResolutionFailed); return(doc); }
/// <summary> /// Downloads the XRDS document for this XRI. /// </summary> /// <param name="identifier">The identifier.</param> /// <param name="requestHandler">The request handler.</param> /// <returns>The XRDS document.</returns> private static XrdsDocument DownloadXrds(XriIdentifier identifier, IDirectWebRequestHandler requestHandler) { Requires.NotNull(identifier, "identifier"); Requires.NotNull(requestHandler, "requestHandler"); XrdsDocument doc; using (var xrdsResponse = Yadis.Request(requestHandler, GetXrdsUrl(identifier), identifier.IsDiscoverySecureEndToEnd)) { var readerSettings = MessagingUtilities.CreateUntrustedXmlReaderSettings(); doc = new XrdsDocument(XmlReader.Create(xrdsResponse.ResponseStream, readerSettings)); } ErrorUtilities.VerifyProtocol(doc.IsXrdResolutionSuccessful, OpenIdStrings.XriResolutionFailed); return(doc); }
/// <summary> /// Downloads the XRDS document for this XRI. /// </summary> /// <param name="identifier">The identifier.</param> /// <param name="requestHandler">The request handler.</param> /// <returns>The XRDS document.</returns> private static XrdsDocument DownloadXrds(XriIdentifier identifier, IDirectWebRequestHandler requestHandler) { Requires.NotNull(identifier, "identifier"); Requires.NotNull(requestHandler, "requestHandler"); Contract.Ensures(Contract.Result <XrdsDocument>() != null); XrdsDocument doc; using (var xrdsResponse = Yadis.Request(requestHandler, GetXrdsUrl(identifier), identifier.IsDiscoverySecureEndToEnd)) { doc = new XrdsDocument(XmlReader.Create(xrdsResponse.ResponseStream)); } ErrorUtilities.VerifyProtocol(doc.IsXrdResolutionSuccessful, OpenIdStrings.XriResolutionFailed); return(doc); }
/// <summary> /// Performs discovery on the Identifier. /// </summary> /// <param name="requestHandler">The web request handler to use for discovery.</param> /// <returns> /// An initialized structure containing the discovered provider endpoint information. /// </returns> internal override IEnumerable <ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler) { List <ServiceEndpoint> endpoints = new List <ServiceEndpoint>(); // Attempt YADIS discovery DiscoveryResult yadisResult = Yadis.Discover(requestHandler, this, IsDiscoverySecureEndToEnd); if (yadisResult != null) { if (yadisResult.IsXrds) { XrdsDocument xrds = new XrdsDocument(yadisResult.ResponseText); var xrdsEndpoints = xrds.CreateServiceEndpoints(yadisResult.NormalizedUri, this); // Filter out insecure endpoints if high security is required. if (IsDiscoverySecureEndToEnd) { xrdsEndpoints = xrdsEndpoints.Where(se => se.IsSecure); } endpoints.AddRange(xrdsEndpoints); } // Failing YADIS discovery of an XRDS document, we try HTML discovery. if (endpoints.Count == 0) { var htmlEndpoints = new List <ServiceEndpoint>(DiscoverFromHtml(yadisResult.NormalizedUri, this, yadisResult.ResponseText)); if (htmlEndpoints.Any()) { Logger.DebugFormat("Total services discovered in HTML: {0}", htmlEndpoints.Count); Logger.Debug(htmlEndpoints.ToStringDeferred(true)); endpoints.AddRange(htmlEndpoints.Where(ep => !IsDiscoverySecureEndToEnd || ep.IsSecure)); if (endpoints.Count == 0) { Logger.Info("No HTML discovered endpoints met the security requirements."); } } else { Logger.Debug("HTML discovery failed to find any endpoints."); } } else { Logger.Debug("Skipping HTML discovery because XRDS contained service endpoints."); } } return(endpoints); }
/// <summary> /// Searches for an XRDS document at the realm URL. /// </summary> /// <param name="requestHandler">The mechanism to use for sending HTTP requests.</param> /// <param name="allowRedirects">Whether redirects may be followed when discovering the Realm. /// This may be true when creating an unsolicited assertion, but must be /// false when performing return URL verification per 2.0 spec section 9.2.1.</param> /// <returns> /// The XRDS document if found; or <c>null</c> if no service document was discovered. /// </returns> internal virtual XrdsDocument Discover(IDirectWebRequestHandler requestHandler, bool allowRedirects) { // Attempt YADIS discovery DiscoveryResult yadisResult = Yadis.Discover(requestHandler, this.UriWithWildcardChangedToWww, false); if (yadisResult != null) { // Detect disallowed redirects, since realm discovery never allows them for security. ErrorUtilities.VerifyProtocol(allowRedirects || yadisResult.NormalizedUri == yadisResult.RequestUri, OpenIdStrings.RealmCausedRedirectUponDiscovery, yadisResult.RequestUri); if (yadisResult.IsXrds) { try { return new XrdsDocument(yadisResult.ResponseText); } catch (XmlException ex) { throw ErrorUtilities.Wrap(ex, XrdsStrings.InvalidXRDSDocument); } } } return null; }
/// <summary> /// Searches for an XRDS document at the realm URL, and if found, searches /// for a description of a relying party endpoints (OpenId login pages). /// </summary> /// <param name="requestHandler">The mechanism to use for sending HTTP requests.</param> /// <param name="allowRedirects">Whether redirects may be followed when discovering the Realm. /// This may be true when creating an unsolicited assertion, but must be /// false when performing return URL verification per 2.0 spec section 9.2.1.</param> /// <returns> /// The details of the endpoints if found, otherwise null. /// </returns> internal IEnumerable <RelyingPartyEndpointDescription> Discover(IDirectWebRequestHandler requestHandler, bool allowRedirects) { // Attempt YADIS discovery DiscoveryResult yadisResult = Yadis.Discover(requestHandler, this.UriWithWildcardChangedToWww, false); if (yadisResult != null) { // Detect disallowed redirects, since realm discovery never allows them for security. ErrorUtilities.VerifyProtocol(allowRedirects || yadisResult.NormalizedUri == yadisResult.RequestUri, OpenIdStrings.RealmCausedRedirectUponDiscovery, yadisResult.RequestUri); if (yadisResult.IsXrds) { try { XrdsDocument xrds = new XrdsDocument(yadisResult.ResponseText); return(xrds.FindRelyingPartyReceivingEndpoints()); } catch (XmlException ex) { throw ErrorUtilities.Wrap(ex, XrdsStrings.InvalidXRDSDocument); } } } return(Enumerable.Empty <RelyingPartyEndpointDescription>()); }
/// <summary> /// Downloads the XRDS document for this XRI. /// </summary> /// <param name="identifier">The identifier.</param> /// <param name="hostFactories">The host factories.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// The XRDS document. /// </returns> private static async Task <XrdsDocument> DownloadXrdsAsync(XriIdentifier identifier, IHostFactories hostFactories, CancellationToken cancellationToken) { Requires.NotNull(identifier, "identifier"); Requires.NotNull(hostFactories, "hostFactories"); XrdsDocument doc; using (var xrdsResponse = await Yadis.RequestAsync(GetXrdsUrl(identifier), identifier.IsDiscoverySecureEndToEnd, hostFactories, cancellationToken)) { xrdsResponse.EnsureSuccessStatusCode(); var readerSettings = MessagingUtilities.CreateUntrustedXmlReaderSettings(); ErrorUtilities.VerifyProtocol(xrdsResponse.Content != null, "XRDS request \"{0}\" returned no response.", GetXrdsUrl(identifier)); await xrdsResponse.Content.LoadIntoBufferAsync(); using (var xrdsStream = await xrdsResponse.Content.ReadAsStreamAsync()) { doc = new XrdsDocument(XmlReader.Create(xrdsStream, readerSettings)); } } ErrorUtilities.VerifyProtocol(doc.IsXrdResolutionSuccessful, OpenIdStrings.XriResolutionFailed); return(doc); }
/// <summary> /// Searches for an XRDS document at the realm URL. /// </summary> /// <param name="hostFactories">The host factories.</param> /// <param name="allowRedirects">Whether redirects may be followed when discovering the Realm. /// This may be true when creating an unsolicited assertion, but must be /// false when performing return URL verification per 2.0 spec section 9.2.1.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// The XRDS document if found; or <c>null</c> if no service document was discovered. /// </returns> internal virtual async Task <XrdsDocument> DiscoverAsync(IHostFactories hostFactories, bool allowRedirects, CancellationToken cancellationToken) { // Attempt YADIS discovery DiscoveryResult yadisResult = await Yadis.DiscoverAsync(hostFactories, this.UriWithWildcardChangedToWww, false, cancellationToken); if (yadisResult != null) { // Detect disallowed redirects, since realm discovery never allows them for security. ErrorUtilities.VerifyProtocol(allowRedirects || yadisResult.NormalizedUri == yadisResult.RequestUri, OpenIdStrings.RealmCausedRedirectUponDiscovery, yadisResult.RequestUri); if (yadisResult.IsXrds) { try { return(new XrdsDocument(yadisResult.ResponseText)); } catch (XmlException ex) { throw ErrorUtilities.Wrap(ex, XrdsStrings.InvalidXRDSDocument); } } } return(null); }
/// <summary> /// Performs discovery on the specified identifier. /// </summary> /// <param name="identifier">The identifier to perform discovery on.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. /// </returns> public async Task <IdentifierDiscoveryServiceResult> DiscoverAsync(Identifier identifier, CancellationToken cancellationToken) { Requires.NotNull(identifier, "identifier"); Verify.Operation(this.HostFactories != null, Strings.HostFactoriesRequired); cancellationToken.ThrowIfCancellationRequested(); var uriIdentifier = identifier as UriIdentifier; if (uriIdentifier == null) { return(new IdentifierDiscoveryServiceResult(Enumerable.Empty <IdentifierDiscoveryResult>())); } var endpoints = new List <IdentifierDiscoveryResult>(); // Attempt YADIS discovery DiscoveryResult yadisResult = await Yadis.DiscoverAsync(this.HostFactories, uriIdentifier, identifier.IsDiscoverySecureEndToEnd, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (yadisResult != null) { if (yadisResult.IsXrds) { try { XrdsDocument xrds = new XrdsDocument(yadisResult.ResponseText); var xrdsEndpoints = xrds.XrdElements.CreateServiceEndpoints(yadisResult.NormalizedUri, uriIdentifier); // Filter out insecure endpoints if high security is required. if (uriIdentifier.IsDiscoverySecureEndToEnd) { xrdsEndpoints = xrdsEndpoints.Where(se => se.ProviderEndpoint.IsTransportSecure()); } endpoints.AddRange(xrdsEndpoints); } catch (XmlException ex) { Logger.Yadis.ErrorException("Error while parsing the XRDS document. Falling back to HTML discovery.", ex); } } // Failing YADIS discovery of an XRDS document, we try HTML discovery. if (endpoints.Count == 0) { await yadisResult.TryRevertToHtmlResponseAsync(); var htmlEndpoints = new List <IdentifierDiscoveryResult>(DiscoverFromHtml(yadisResult.NormalizedUri, uriIdentifier, yadisResult.ResponseText)); if (htmlEndpoints.Any()) { Logger.Yadis.DebugFormat("Total services discovered in HTML: {0}", htmlEndpoints.Count); Logger.Yadis.Debug(htmlEndpoints.ToStringDeferred(true).ToString()); endpoints.AddRange(htmlEndpoints.Where(ep => !uriIdentifier.IsDiscoverySecureEndToEnd || ep.ProviderEndpoint.IsTransportSecure())); if (endpoints.Count == 0) { Logger.Yadis.Info("No HTML discovered endpoints met the security requirements."); } } else { Logger.Yadis.Debug("HTML discovery failed to find any endpoints."); } } else { Logger.Yadis.Debug("Skipping HTML discovery because XRDS contained service endpoints."); } } return(new IdentifierDiscoveryServiceResult(endpoints)); }