//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation, Scott Hanselman. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Xrds {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.XPath;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
///
/// The Xrd element in an XRDS document.
///
internal class XrdElement : XrdsNode {
///
/// Initializes a new instance of the class.
///
/// The XRD element.
/// The parent.
public XrdElement(XPathNavigator xrdElement, XrdsDocument parent) :
base(xrdElement, parent) {
}
///
/// Gets the child service elements.
///
/// The services.
public IEnumerable Services {
get {
// We should enumerate them in priority order
List services = new List();
foreach (XPathNavigator node in Node.Select("xrd:Service", XmlNamespaceResolver)) {
services.Add(new ServiceElement(node, this));
}
services.Sort();
return services;
}
}
///
/// Gets a value indicating whether this XRD element's resolution at the XRI resolver was successful.
///
///
/// true if this XRD's resolution was successful; otherwise, false.
///
public bool IsXriResolutionSuccessful {
get {
return this.XriResolutionStatusCode == 100;
}
}
///
/// Gets the canonical ID (i-number) for this element.
///
public string CanonicalID {
get {
var n = Node.SelectSingleNode("xrd:CanonicalID", XmlNamespaceResolver);
return n != null ? n.Value : null;
}
}
///
/// Gets a value indicating whether the was verified.
///
public bool IsCanonicalIdVerified {
get {
var n = Node.SelectSingleNode("xrd:Status", XmlNamespaceResolver);
return n != null && string.Equals(n.GetAttribute("cid", string.Empty), "verified", StringComparison.Ordinal);
}
}
///
/// Gets the services for OP Identifiers.
///
public IEnumerable OpenIdProviderIdentifierServices {
get { return this.SearchForServiceTypeUris(p => p.OPIdentifierServiceTypeURI); }
}
///
/// Gets the services for Claimed Identifiers.
///
public IEnumerable OpenIdClaimedIdentifierServices {
get { return this.SearchForServiceTypeUris(p => p.ClaimedIdentifierServiceTypeURI); }
}
///
/// Gets the services that would be discoverable at an RP for return_to verification.
///
public IEnumerable OpenIdRelyingPartyReturnToServices {
get { return this.SearchForServiceTypeUris(p => p.RPReturnToTypeURI); }
}
///
/// Gets the services that would be discoverable at an RP for the UI extension icon.
///
public IEnumerable OpenIdRelyingPartyIcons {
get { return this.SearchForServiceTypeUris(p => "http://specs.openid.net/extensions/ui/icon"); }
}
///
/// Gets an enumeration of all Service/URI elements, sorted in priority order.
///
public IEnumerable ServiceUris {
get {
return from service in this.Services
from uri in service.UriElements
select uri;
}
}
///
/// Gets the XRI resolution status code.
///
private int XriResolutionStatusCode {
get {
var n = Node.SelectSingleNode("xrd:Status", XmlNamespaceResolver);
string codeString = null;
ErrorUtilities.VerifyProtocol(n != null && !string.IsNullOrEmpty(codeString = n.GetAttribute("code", string.Empty)), XrdsStrings.XriResolutionStatusMissing);
int code;
ErrorUtilities.VerifyProtocol(int.TryParse(codeString, out code) && code >= 100 && code < 400, XrdsStrings.XriResolutionStatusMissing);
return code;
}
}
///
/// Searches for service sub-elements that have Type URI sub-elements that match
/// one that we have for a known OpenID protocol version.
///
/// A function that selects what element of the OpenID Protocol we're interested in finding.
/// A sequence of service elements that match the search criteria, sorted in XRDS @priority attribute order.
internal IEnumerable SearchForServiceTypeUris(Func p) {
var xpath = new StringBuilder();
xpath.Append("xrd:Service[");
foreach (var protocol in Protocol.AllVersions) {
string typeUri = p(protocol);
if (typeUri == null) {
continue;
}
xpath.Append("xrd:Type/text()='");
xpath.Append(typeUri);
xpath.Append("' or ");
}
xpath.Length -= 4;
xpath.Append("]");
var services = new List();
foreach (XPathNavigator service in Node.Select(xpath.ToString(), XmlNamespaceResolver)) {
services.Add(new ServiceElement(service, this));
}
// Put the services in their own defined priority order
services.Sort();
return services;
}
}
}