From 0a90384a9c7d840e88d9636271e8393a514647a0 Mon Sep 17 00:00:00 2001 From: Leif Johansson Date: Tue, 28 Jul 2009 10:34:52 +0200 Subject: Import shibboleth ds 1.1.0 --- .../middleware/shibboleth/wayf/IdPSiteSet.html | 577 +++++++++++++++++++++ 1 file changed, 577 insertions(+) create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSet.html (limited to 'doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSet.html') diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSet.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSet.html new file mode 100644 index 0000000..af6f827 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSet.html @@ -0,0 +1,577 @@ + + + + +IdPSiteSet xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
+3    *
+4    * Licensed under the Apache License, Version 2.0 (the "License");
+5    * you may not use this file except in compliance with the License.
+6    * You may obtain a copy of the License at
+7    *
+8    * http://www.apache.org/licenses/LICENSE-2.0
+9    *
+10   * Unless required by applicable law or agreed to in writing, software
+11   * distributed under the License is distributed on an "AS IS" BASIS,
+12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+13   * See the License for the specific language governing permissions and
+14   * limitations under the License.
+15   */
+16  package edu.internet2.middleware.shibboleth.wayf;
+17  
+18  import java.io.File;
+19  import java.lang.reflect.Constructor;
+20  import java.net.MalformedURLException;
+21  import java.net.URL;
+22  import java.util.ArrayList;
+23  import java.util.Collection;
+24  import java.util.Enumeration;
+25  import java.util.HashMap;
+26  import java.util.HashSet;
+27  import java.util.List;
+28  import java.util.Map;
+29  import java.util.Set;
+30  import java.util.StringTokenizer;
+31  import java.util.TreeMap;
+32  
+33  import org.opensaml.saml2.metadata.EntitiesDescriptor;
+34  import org.opensaml.saml2.metadata.EntityDescriptor;
+35  import org.opensaml.saml2.metadata.IDPSSODescriptor;
+36  import org.opensaml.saml2.metadata.Organization;
+37  import org.opensaml.saml2.metadata.OrganizationDisplayName;
+38  import org.opensaml.saml2.metadata.OrganizationName;
+39  import org.opensaml.saml2.metadata.RoleDescriptor;
+40  import org.opensaml.saml2.metadata.SPSSODescriptor;
+41  import org.opensaml.saml2.metadata.provider.FileBackedHTTPMetadataProvider;
+42  import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider;
+43  import org.opensaml.saml2.metadata.provider.MetadataFilter;
+44  import org.opensaml.saml2.metadata.provider.MetadataFilterChain;
+45  import org.opensaml.saml2.metadata.provider.MetadataProvider;
+46  import org.opensaml.saml2.metadata.provider.MetadataProviderException;
+47  import org.opensaml.saml2.metadata.provider.ObservableMetadataProvider;
+48  import org.opensaml.xml.XMLObject;
+49  import org.opensaml.xml.parse.ParserPool;
+50  import org.slf4j.Logger;
+51  import org.slf4j.LoggerFactory;
+52  import org.w3c.dom.Element;
+53  import org.w3c.dom.NodeList;
+54  
+55  import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
+56  import edu.internet2.middleware.shibboleth.wayf.plugins.Plugin;
+57  import edu.internet2.middleware.shibboleth.wayf.plugins.PluginMetadataParameter;
+58  import edu.internet2.middleware.shibboleth.wayf.plugins.provider.BindingFilter;
+59  
+60  /**
+61   * 
+62   * Represents a collection of related sites as desribed by a single soirce of metadata. 
+63   * This is usually a federation.  When the WAYF looks to see which IdP sites to show, 
+64   * it trims the list so as to not show IdP's which do not trust the SP.
+65   *
+66   * This class is opaque outside this file.  The three static methods getSitesLists,
+67   * searchForMatchingOrigins and lookupIdP provide mechansims for accessing 
+68   * collections of IdPSiteSets.
+69   * 
+70   */
+71  
+72  public class IdPSiteSet implements ObservableMetadataProvider.Observer {
+73          
+74      /** Handle for error output. */
+75      private static final Logger LOG = LoggerFactory.getLogger(IdPSiteSet.class.getName());
+76  
+77      /** The OpenSaml metadat6a source. */
+78      private ObservableMetadataProvider metadata;
+79  
+80      /** Is the named SP in the current metadata set? */
+81      private Set<String> spNames = new HashSet<String>(0);
+82  
+83      /** Is the named IdP in the current metadata set? */
+84      private Set<String> idpNames = new HashSet<String>(0);
+85      
+86      /** What does the configuration identify this as? */
+87      private final String identifier;
+88      
+89      /** What name should we display for this set of entities? */
+90      private final String displayName;
+91      
+92      /** Where does the metadata exist? */
+93      private String location;
+94      
+95      /** What parameters do we pass in to which plugin? */
+96      private final Map<Plugin, PluginMetadataParameter> plugins = new HashMap<Plugin, PluginMetadataParameter>();
+97      
+98      /**
+99       * Create a new IdPSiteSet as described by the supplied XML segment. 
+100      * @param el - configuration details.
+101      * @param parserPool - the parsers we initialized above.
+102      * @param warnOnBadBinding if we just warn or give an error if an SP has bad entry points.
+103      * @throws ShibbolethConfigurationException - if something goes wrong.
+104      */
+105     protected IdPSiteSet(Element el, ParserPool parserPool, boolean warnOnBadBinding) throws ShibbolethConfigurationException {
+106 
+107         String spoolSpace;
+108         String delayString;
+109 
+110         this.identifier = el.getAttribute("identifier");
+111         this.displayName = el.getAttribute("displayName");
+112         location = el.getAttribute("url");
+113         if (null == location || location.length() == 0) {
+114             //
+115             // Sigh for a few releases this was documented as URI
+116             //
+117             location = el.getAttribute("url");
+118         }
+119         spoolSpace = el.getAttribute("backingFile");
+120         delayString = el.getAttribute("timeout");
+121         
+122         //
+123         // Configure the filters (before the metadata so we can add them before we start reading)
+124         //
+125         String ident;
+126         String className;
+127         ident = "<not specified>"; 
+128         className = "<not specified>"; 
+129         MetadataFilterChain filterChain = null;
+130         filterChain = new MetadataFilterChain();
+131         try {
+132             NodeList itemElements = el.getElementsByTagNameNS(XMLConstants.CONFIG_NS, "Filter");
+133             List <MetadataFilter> filters = new ArrayList<MetadataFilter>(1 + itemElements.getLength());
+134             
+135             //
+136             // We always have a binding filter
+137             //
+138             filters.add(new BindingFilter(warnOnBadBinding));
+139                 
+140             for (int i = 0; i < itemElements.getLength(); i++) {
+141                 Element element = (Element) itemElements.item(i);
+142    
+143                 ident = "<not specified>"; 
+144                 className = "<not specified>"; 
+145             
+146                 ident = element.getAttribute("identifier");
+147 
+148                 if (null == ident || ident.equals("")) {
+149                     LOG.error("Could not load filter with no identifier");
+150                     continue;
+151                 }
+152             
+153                 className = element.getAttribute("type");
+154                 if (null == className || className.equals("")) {
+155                     LOG.error("Filter " + identifier + " did not have a valid type");
+156                 }
+157                 //
+158                 // So try to get hold of the Filter
+159                 //
+160                 Class<MetadataFilter> filterClass = (Class<MetadataFilter>) Class.forName(className);
+161                 Class[] classParams = {Element.class};
+162                 Constructor<MetadataFilter> constructor = filterClass.getConstructor(classParams);
+163                 Object[] constructorParams = {element};
+164             
+165                 filters.add(constructor.newInstance(constructorParams));
+166             }
+167             filterChain.setFilters(filters);
+168         } catch (Exception e) {
+169             LOG.error("Could not load filter " + ident + "()" + className + ") for " + this.identifier, e);
+170             throw new ShibbolethConfigurationException("Could not load filter", e);
+171         }
+172     
+173         LOG.info("Loading Metadata for " + displayName);
+174         try {
+175             int delay;
+176             delay = 30000;
+177             if (null != delayString && !"".equals(delayString)) {
+178                 delay = Integer.parseInt(delayString);
+179             }
+180             
+181             URL url = new URL(location); 
+182             if ("file".equalsIgnoreCase(url.getProtocol())){
+183                 FilesystemMetadataProvider provider = new FilesystemMetadataProvider(new File(url.getFile()));
+184                 provider.setParserPool(parserPool);
+185                 if (null != filterChain) {
+186                     provider.setMetadataFilter(filterChain);
+187                 }
+188                 provider.initialize();
+189                 metadata = provider;
+190             } else {
+191                 if (spoolSpace == null || "".equals(spoolSpace)) {
+192                     throw new ShibbolethConfigurationException("backingFile must be specified for " + identifier);
+193                 }
+194                 
+195                 FileBackedHTTPMetadataProvider provider;
+196             
+197                 provider = new FileBackedHTTPMetadataProvider(location, delay, spoolSpace);
+198                 provider.setParserPool(parserPool);
+199                 if (null != filterChain) {
+200                     provider.setMetadataFilter(filterChain);
+201                 }
+202                 provider.initialize();
+203                 metadata = provider;
+204             }
+205         } catch (MetadataProviderException e) {
+206             throw new ShibbolethConfigurationException("Could not read " + location, e);
+207         } catch (NumberFormatException e) {
+208             throw new ShibbolethConfigurationException("Badly formed timeout " + delayString, e);
+209         } catch (MalformedURLException e) {
+210             throw new ShibbolethConfigurationException("Badly formed url ", e);
+211         }
+212         metadata.getObservers().add(this);
+213         onEvent(metadata);
+214     }
+215 
+216     /**
+217      * Based on 1.2 Origin.isMatch.  There must have been a reason for it...
+218      * [Kindas of] support for the search function in the wayf.  This return many false positives
+219      * but given the aim is to provide input for a pull down list...
+220      * 
+221      * @param entity   The entity to match.
+222      * @param str      The patten to match against.
+223      * @param config   Provides list of tokens to not lookup
+224      * @return         Whether this entity matches  
+225      */
+226 
+227     private static boolean isMatch(EntityDescriptor entity, String str, HandlerConfig config) {
+228         
+229         Enumeration input = new StringTokenizer(str);
+230         while (input.hasMoreElements()) {
+231             String currentToken = (String) input.nextElement();
+232 
+233             if (config.isIgnoredForMatch(currentToken)) {                           
+234                 continue;
+235             }
+236                 
+237             currentToken = currentToken.toLowerCase(); 
+238 
+239             if (entity.getEntityID().indexOf(currentToken) > -1) {
+240                 return true; 
+241             }
+242                                 
+243             Organization org = entity.getOrganization();
+244                 
+245             if (org != null) {
+246                         
+247                 List <OrganizationName> orgNames = org.getOrganizationNames();
+248                 for (OrganizationName name : orgNames) {
+249                     if (name.getName().getLocalString().indexOf(currentToken) > -1) {
+250                         return true;
+251                     }
+252                 }
+253                         
+254                 List <OrganizationDisplayName> orgDisplayNames = org.getDisplayNames();
+255                 for (OrganizationDisplayName name : orgDisplayNames) {
+256                     if (name.getName().getLocalString().indexOf(currentToken) > -1) {
+257                         return true;
+258                     }
+259                 }                                
+260             }
+261         }
+262         return false;
+263     }
+264 
+265     /**
+266      * Return all the Idp in the provided entities descriptor.  If SearchMatches
+267      * is non null it is populated with whatever of the IdPs matches the search string 
+268      * (as noted above). 
+269      * @param searchString to match with
+270      * @param config parameter to mathing
+271      * @param searchMatches if non null is filled with such of the sites which match the string
+272      * @return the sites which fit.
+273      */
+274     protected Map<String, IdPSite> getIdPSites(String searchString, 
+275                                                HandlerConfig config, 
+276                                                Collection<IdPSite> searchMatches)
+277     {
+278         XMLObject object;
+279         List <EntityDescriptor> entities;
+280         try {
+281             object = metadata.getMetadata();
+282         } catch (MetadataProviderException e) {
+283             LOG.error("Metadata for " + location + "could not be read", e);
+284             return null;
+285         }
+286         
+287         if (object == null) {
+288             return null;
+289         }
+290         
+291         //
+292         // Fill in entities approptiately
+293         //
+294         
+295         if (object instanceof EntityDescriptor) {
+296             entities = new ArrayList<EntityDescriptor>(1);
+297             entities.add((EntityDescriptor) object);
+298         } else if (object instanceof EntitiesDescriptor) {
+299 
+300             EntitiesDescriptor entitiesDescriptor = (EntitiesDescriptor) object; 
+301     
+302             entities = entitiesDescriptor.getEntityDescriptors();
+303         } else {
+304            return null;
+305         }
+306        
+307         //
+308         // populate the result (and the searchlist) from the entities list
+309         //
+310         
+311         TreeMap<String, IdPSite> result = new TreeMap <String,IdPSite>();
+312                     
+313         for (EntityDescriptor entity : entities) {
+314                 
+315             if (entity.isValid() && hasIdPRole(entity)) {
+316 
+317                 IdPSite site = new IdPSite(entity);
+318                 result.put(site.getName(), site);
+319                 if (searchMatches != null && isMatch(entity, searchString, config)) {           
+320 
+321                     searchMatches.add(site);
+322                 }
+323 
+324             }
+325         } // iterate over all entities
+326         return result;
+327     }
+328 
+329 
+330     /**
+331      * Return this sites (internal) identifier.
+332      * @return the identifier
+333      */
+334     protected String getIdentifier() {
+335         return identifier;
+336     }
+337 
+338     /**
+339      * Return the human friendly name for this siteset.
+340      * @return The friendly name
+341      */
+342     protected String getDisplayName() {
+343         return displayName;
+344     }
+345 
+346     /**
+347      * We do not need to look at a set if it doesn't know about the given SP.  However if
+348      * no SP is given (as per 1.1) then we do need to look.  This calls lets us know whether 
+349      * this set is a canddiate for looking into.
+350      * @param SPName the Sp we are interested in.
+351      * @return whether the site contains the SP.
+352      */
+353     protected boolean containsSP(String SPName) {
+354 
+355         //
+356         // Deal with the case where we do *not* want to search by
+357         // SP (also handles the 1.1 case)
+358         //
+359         
+360         if ((SPName == null) || (SPName.length() == 0)) {
+361             return true;
+362         }
+363 
+364         //
+365         // Get hold of the current object list so as to provoke observer to fire 
+366         // if needs be.
+367         // 
+368         
+369         XMLObject object;
+370         try {
+371             object = metadata.getMetadata();
+372         } catch (MetadataProviderException e) {
+373             return false;
+374         }
+375         //
+376         // Now lookup
+377         //
+378 
+379         if (object instanceof EntitiesDescriptor ||
+380             object instanceof EntityDescriptor) {
+381             return spNames.contains(SPName);
+382         } else {
+383             return false;
+384         }
+385     }
+386 
+387     /**
+388      * For plugin handling we need to know quickly if a metadataset contains the idp.
+389      * @param IdPName the IdP we are interested in.
+390      * @return whether the site contains the IdP.
+391      * 
+392      */
+393 
+394     protected boolean containsIdP(String IdPName) {
+395         
+396         if ((IdPName == null) || (IdPName.length() == 0)) {
+397             return true;
+398         }
+399 
+400         //
+401         // Get hold of the current object list so as to provoke observer to fire 
+402         // if needs be.
+403         // 
+404         
+405         XMLObject object;
+406         try {
+407             object = metadata.getMetadata();
+408         } catch (MetadataProviderException e) {
+409             return false;
+410         }
+411         if (object instanceof EntitiesDescriptor ||
+412             object instanceof EntityDescriptor) {
+413             return idpNames.contains(IdPName);
+414         } else {
+415             return false;
+416         }
+417     }
+418 
+419     //
+420     // Now deal with plugins - these are delcared to use but we are
+421     // responsible for their parameter
+422     //
+423 
+424     /**
+425      * Declares a plugin to the siteset.
+426      * @param plugin what to declare
+427      */
+428     protected void addPlugin(Plugin plugin) {
+429 
+430         if (plugins.containsKey(plugin)) {
+431             return;
+432         }
+433         
+434         PluginMetadataParameter param = plugin.refreshMetadata(metadata);
+435         
+436         plugins.put(plugin, param);
+437     }
+438 
+439     /**
+440      * Return the parameter that this plugin uses.
+441      * @param plugin
+442      * @return teh parameter.
+443      */
+444     protected PluginMetadataParameter paramFor(Plugin plugin) {
+445         return plugins.get(plugin);
+446     }
+447 
+448 
+449     /* (non-Javadoc)
+450      * @see org.opensaml.saml2.metadata.provider.ObservableMetadataProvider.Observer#onEvent(org.opensaml.saml2.metadata.provider.MetadataProvider)
+451      */
+452     public void onEvent(MetadataProvider provider) {
+453         Set<String> spNameSet = new HashSet<String>(0);
+454         Set<String> idpNameSet = new HashSet<String>(0);
+455 
+456         XMLObject obj; 
+457         try {
+458             obj = provider.getMetadata();
+459         } catch (MetadataProviderException e) {
+460             LOG.error("Couldn't read metadata for " + location, e);
+461             return;
+462         }
+463         if ((obj instanceof EntitiesDescriptor)) {
+464             EntitiesDescriptor entitiesDescriptor = (EntitiesDescriptor) obj;
+465             
+466             for (EntityDescriptor entity : entitiesDescriptor.getEntityDescriptors()) {
+467                 if (hasSPRole(entity)) {
+468                     spNameSet.add(entity.getEntityID());
+469                 }
+470                 if (hasIdPRole(entity)) {
+471                     idpNameSet.add(entity.getEntityID());
+472                 }
+473             }
+474         } else if (obj instanceof EntityDescriptor) {
+475             EntityDescriptor entity = (EntityDescriptor) obj;
+476             if (hasSPRole(entity)) {
+477                 spNameSet.add(entity.getEntityID());
+478             }
+479             if (hasIdPRole(entity)) {
+480                 idpNameSet.add(entity.getEntityID());
+481             }
+482         } else {
+483             LOG.error("Metadata for " + location + " isn't <EntitiesDescriptor> or <EntityDescriptor>");
+484             return;
+485         }
+486         //
+487         // Now that we have the new set sorted out commit it in
+488         //
+489         this.spNames = spNameSet;
+490         this.idpNames = idpNameSet;
+491         
+492         for (Plugin plugin:plugins.keySet()) {
+493             plugins.put(plugin, plugin.refreshMetadata(provider));
+494         }
+495     }
+496 
+497     /**
+498      * Enumerate all the roles and see whether this entity can be an IdP.
+499      * @param entity
+500      * @return true if one of the roles that entity has is IdPSSO
+501      */
+502     private static boolean hasIdPRole(EntityDescriptor entity) {
+503         List<RoleDescriptor> roles = entity.getRoleDescriptors();
+504         
+505         for (RoleDescriptor role:roles) {
+506            if (role instanceof IDPSSODescriptor) {
+507                //
+508                // So the entity knows how to be some sort of an Idp
+509                //
+510                return true;            
+511            }
+512         }
+513         return false;
+514     }
+515 
+516     /**
+517      * Enumerate all the roles and see whether this entity can be an SP.
+518      * @param entity
+519      * @return true if one of the roles that entity has is SPSSO
+520      */
+521     private static boolean hasSPRole(EntityDescriptor entity) {
+522         List<RoleDescriptor> roles = entity.getRoleDescriptors();
+523         
+524         for (RoleDescriptor role:roles) {
+525            if (role instanceof SPSSODescriptor) {
+526                //
+527                // "I can do that"
+528                //
+529                return true;
+530            }
+531         }
+532         return false;
+533     }
+534 
+535     /**
+536      * Return the idpSite for the given entity name.
+537      * @param idpName the entityname to look up
+538      * @return the associated idpSite
+539      * @throws WayfException
+540      */
+541     protected IdPSite getSite(String idpName) throws WayfException {
+542 
+543         try {
+544             return new IdPSite(metadata.getEntityDescriptor(idpName));
+545         } catch (MetadataProviderException e) {
+546             String s = "Couldn't resolve " + idpName + " in "  + getDisplayName();
+547             LOG.error(s, e);
+548             throw new WayfException(s, e);
+549         }
+550     }
+551     
+552     protected EntityDescriptor getEntity(String name) throws WayfException {
+553         try {
+554             return metadata.getEntityDescriptor(name);
+555         } catch (MetadataProviderException e) {
+556             String s = "Couldn't resolve " + name + " in "  + getDisplayName();
+557             LOG.error(s, e);
+558             throw new WayfException(s, e);
+559         }
+560         
+561     }
+562 }
+563 
+
+
+ + -- cgit v1.1