com.google.step2.discovery.XrdLocationSelector Maven / Gradle / Ivy
/**
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.google.step2.discovery;
import static com.google.step2.discovery.RelTypes.setOf;
import org.openid4java.discovery.UrlIdentifier;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Various strategies for finding the URI pointing to a relevant XRD(S) document.
*
* The goal of XRD location selection is to find a suitable URI from a
* host-meta document that is likely to point to an XRD(S) file with
* metadata about the (user or IdP) identifier in question.
*
*/
public class XrdLocationSelector {
// specifies a link that points to an XRD(S) document that includes meta
// data about OpenID OPs. Whether the document is old-style XRDS or new-style
// XRD depends on the (MIME) type specified in the Link.
public static final RelType REL_OPENID_OP_XRD =
new RelType("http://reltype.google.com/openid/xrd-op");
// specifies a link that points to an XRD(S) document that includes meta
// data about OpenID RPs. Whether the document is old-style XRDS or new-style
// XRD depends on the (MIME) type specified in the Link.
public static final RelType REL_OPENID_RP_XRD =
new RelType("http://reltype.google.com/openid/xrd-rp");
// specifies a link that points to an XRD(S) document that includes meta
// data about OpenID. Whether the document is old-style XRDS or new-style
// XRD depends on the (MIME) type specified in the Link.
public static final RelType REL_OPENID_XRD =
new RelType("http://reltype.google.com/openid/xrd");
// specifies a link that points to an XRD(S) document that includes some
// meta-data.
public static final RelType REL_DESCRIBED_BY = new RelType("describedby");
// When looking for an XRD that may have information about the OpenID
// OP in it, we first look for a link that has the most specific rel-types,
// and if that link doesn't exist, start looking for less specific rel-types.
private static final Ordering OP_PREFERENCE_ORDER = new Ordering(
setOf(REL_DESCRIBED_BY, REL_OPENID_OP_XRD),
setOf(REL_DESCRIBED_BY, REL_OPENID_XRD),
setOf(REL_DESCRIBED_BY));
// When looking for an XRD that may have information about the OpenID
// RP in it, we first look for a link that has the most specific rel-types,
// and if that link doesn't exist, start looking for less specific rel-types.
@SuppressWarnings("unused")
private static final Ordering RP_PREFERENCE_ORDER = new Ordering(
setOf(REL_DESCRIBED_BY, REL_OPENID_RP_XRD),
setOf(REL_DESCRIBED_BY, REL_OPENID_XRD),
setOf(REL_DESCRIBED_BY));
/**
* Returns a URI that points directly to the claimed id's XRD(S) document.
* The user's XRD(S) document should contain the pointer to the OP.
*/
public URI findUserXrdUriForOp(HostMeta hostMeta, String mimeType,
UrlIdentifier claimedId) {
LinkPattern pattern = getMatchingLink(hostMeta.getLinkPatterns(), mimeType);
if (pattern == null) {
return null;
}
UriTemplate template = new UriTemplate(pattern.getUriPattern());
return template.map(URI.create(claimedId.getIdentifier()));
}
/**
* Finds, in /host-meta, a pointer to a site-wide XRD(S) document. Normally,
* this would simply be the URI in Link: entry with rel-type "describedby".
* But sites can annotate the link with further rel-types, indicating whether
* the XRD(S) pointed to is likely to contain OpenID-related information or
* even more specifically, OP or RP-related information.
*
* @param hostMeta the host-meta we're searching through.
* @param mimeType the mime-type of the link we're interested in.
*/
public URI findSiteXrdUriForOp(HostMeta hostMeta, String mimeType) {
Link link = getMatchingLink(hostMeta.getLinks(), mimeType);
return (link == null) ? null : link.getUri();
}
/**
* Returns a link or link-pattern (from the collection passed in) that matches
* the requirements of OP discovery. That is, it needs to have the the
* specified mime-type, and is preferrably rel-typed as (describedby,
* http://reltype.google.com/openid/xrd-op) (although less specific rel-types
* are also considered if the most specific one cannot be found).
*/
private T getMatchingLink(Collection links,
String mimeType) {
// bring links into a sortable datatype, and only use those
// that seem to point to files of the right MIME type
List sortableLinks = filterByMimeType(links, mimeType);
if (sortableLinks.size() < 1) {
return null;
}
// sort according to OpenID discovery preference:
// since we're looking for an OP for a site, we'll look for something
// labeled REL_OPENID_OP_XRD (and describedby) first, then for something
// labeled REL_OPENID_XRD (and describedby), then for something simply
// labeled "describedby".
Collections.sort(sortableLinks, OP_PREFERENCE_ORDER);
// make sure that the first link in fact points to something that we think
// might have OpenID data in it.
T candidate = sortableLinks.get(0);
RelTypes candidateRelTypes = candidate.getRelationships();
for (RelTypes validRelTypes : OP_PREFERENCE_ORDER.getAllRelTypeSets()) {
if (candidateRelTypes.containsAll(validRelTypes)) {
// yes, the first Link in the list lists a combination of RelTypes
// that's acceptable
return candidate;
}
}
// the first Link in the (sorted) list doesn't contain a combination of
// acceptable RelTypes
return null;
}
/**
* Discards all links from a host-meta that aren't the right MIME type.
*/
private List filterByMimeType(Collection links,
String mimeType) {
ArrayList result = new ArrayList();
for (T link : links) {
if (mimeType.equals(link.getMimeType())) {
result.add(link);
}
}
return result;
}
/**
* Helper class that implements an induced order, i.e., can order lists
* according to the priority of RelType sets. For example, if the
* list of rel-types passed to the constructor is:
*
* (foo bar), (foo), (bla)
*
* then this class can order a list of links with associated rel-types such
* that links that have both "foo" and "bar" rel-types come first, then
* (other) links with rel-type "foo", then links with rel-type "bla", and
* then all other links.
*/
private static class Ordering implements Comparator {
private final List rels;
private final Integer maxValue;
public Ordering(RelTypes... rels) {
this.rels = Arrays.asList(rels);
this.maxValue = rels.length;
}
public int compare(LinkBase o1, LinkBase o2) {
return getOrdinal(o1).compareTo(getOrdinal(o2));
}
public List getAllRelTypeSets() {
return rels;
}
private Integer getOrdinal(LinkBase o2) {
for(int i = 0; i < rels.size(); i++) {
if (o2.getRelationships().containsAll(rels.get(i))) {
return i;
}
}
return maxValue;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy