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 --- .../shibboleth/wayf/DiscoveryResponseBuilder.html | 61 ++ .../shibboleth/wayf/DiscoveryResponseImpl.html | 63 ++ .../wayf/DiscoveryResponseUnmarshaller.html | 51 + .../shibboleth/wayf/DiscoveryServiceHandler.html | 1016 ++++++++++++++++++++ .../middleware/shibboleth/wayf/HandlerConfig.html | 236 +++++ .../middleware/shibboleth/wayf/IdPSite.html | 231 +++++ .../middleware/shibboleth/wayf/IdPSiteSet.html | 577 +++++++++++ .../shibboleth/wayf/IdPSiteSetEntry.html | 71 ++ .../wayf/LogbackConfigurationChangeListener.html | 86 ++ .../shibboleth/wayf/LogbackLoggingService.html | 78 ++ .../middleware/shibboleth/wayf/Version.html | 45 + .../middleware/shibboleth/wayf/WayfException.html | 61 ++ .../middleware/shibboleth/wayf/WayfService.html | 332 +++++++ .../middleware/shibboleth/wayf/XMLConstants.html | 47 + .../middleware/shibboleth/wayf/package-frame.html | 66 ++ .../shibboleth/wayf/package-summary.html | 137 +++ .../middleware/shibboleth/wayf/plugins/Plugin.html | 173 ++++ .../shibboleth/wayf/plugins/PluginContext.html | 45 + .../wayf/plugins/PluginMetadataParameter.html | 44 + .../wayf/plugins/WayfRequestHandled.html | 31 + .../shibboleth/wayf/plugins/package-frame.html | 33 + .../shibboleth/wayf/plugins/package-summary.html | 82 ++ .../wayf/plugins/provider/BindingFilter.html | 190 ++++ .../wayf/plugins/provider/ListFilter.html | 198 ++++ .../wayf/plugins/provider/SamlCookiePlugin.html | 558 +++++++++++ .../wayf/plugins/provider/package-frame.html | 36 + .../wayf/plugins/provider/package-summary.html | 87 ++ 27 files changed, 4635 insertions(+) create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseBuilder.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseImpl.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseUnmarshaller.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryServiceHandler.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/HandlerConfig.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSite.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSet.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSetEntry.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackConfigurationChangeListener.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackLoggingService.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/Version.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfException.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfService.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/XMLConstants.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-frame.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-summary.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/Plugin.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginContext.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginMetadataParameter.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/WayfRequestHandled.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-frame.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-summary.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/BindingFilter.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/ListFilter.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/SamlCookiePlugin.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-frame.html create mode 100644 doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-summary.html (limited to 'doc/src-xref/edu/internet2/middleware/shibboleth/wayf') diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseBuilder.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseBuilder.html new file mode 100644 index 0000000..07ceb25 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseBuilder.html @@ -0,0 +1,61 @@ + + + + +DiscoveryResponseBuilder xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright [2006] [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  
+17  /**
+18   * 
+19   */
+20  
+21  package edu.internet2.middleware.shibboleth.wayf;
+22  
+23  import org.opensaml.common.impl.AbstractSAMLObjectBuilder;
+24  import org.opensaml.common.xml.SAMLConstants;
+25  
+26  /**
+27   * Builder of {@link org.opensaml.saml2.metadata.impl.SingleLogoutServiceImpl}.
+28   */
+29  public class DiscoveryResponseBuilder extends AbstractSAMLObjectBuilder<DiscoveryResponseImpl> {
+30  
+31      /**
+32       * Constructor
+33       */
+34      public DiscoveryResponseBuilder() {
+35  
+36      }
+37  
+38      /** {@inheritDoc} */
+39      public DiscoveryResponseImpl buildObject() {
+40          return buildObject(SAMLConstants.SAML20MD_NS, DiscoveryResponseImpl.DEFAULT_ELEMENT_LOCAL_NAME, SAMLConstants.SAML20MD_PREFIX);
+41      }
+42  
+43      /** {@inheritDoc} */
+44      public DiscoveryResponseImpl buildObject(String namespaceURI, String localName, String namespacePrefix) {
+45          return new DiscoveryResponseImpl(namespaceURI, localName, namespacePrefix);
+46      }
+47  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseImpl.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseImpl.html new file mode 100644 index 0000000..92c9612 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseImpl.html @@ -0,0 +1,63 @@ + + + + +DiscoveryResponseImpl xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright [2006] [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  
+17  /**
+18   * 
+19   */
+20  
+21  package edu.internet2.middleware.shibboleth.wayf;
+22  
+23  import org.opensaml.saml2.metadata.IndexedEndpoint;
+24  import org.opensaml.saml2.metadata.impl.IndexedEndpointImpl;
+25  
+26  /**
+27   * This plugs into the standard opensaml2 parser framework to allow us to get use <code> DiscoverResponse </code>
+28   * elements in our extensions.
+29   */
+30  public class DiscoveryResponseImpl extends IndexedEndpointImpl implements IndexedEndpoint {
+31  
+32      /** Namespace for Discovery Service metadata extensions. */
+33      
+34      public static final String METADATA_NS = "urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol";
+35      /** Name of the element inside the Extensions. */
+36      
+37      protected static final String DEFAULT_ELEMENT_LOCAL_NAME = "DiscoveryResponse";
+38      
+39      /**
+40       * Constructor.
+41       * 
+42       * @param namespaceURI the Uri
+43       * @param elementLocalName the local name
+44       * @param namespacePrefix the prefix
+45       */
+46      protected DiscoveryResponseImpl(String namespaceURI, String elementLocalName, String namespacePrefix) {
+47          super(namespaceURI, elementLocalName, namespacePrefix);
+48      }
+49  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseUnmarshaller.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseUnmarshaller.html new file mode 100644 index 0000000..45cb6f2 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryResponseUnmarshaller.html @@ -0,0 +1,51 @@ + + + + +DiscoveryResponseUnmarshaller xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright [2006] [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  
+17  /**
+18   * 
+19   */
+20  
+21  package edu.internet2.middleware.shibboleth.wayf;
+22  
+23  import org.opensaml.saml2.metadata.impl.IndexedEndpointUnmarshaller;
+24  import org.opensaml.xml.XMLObject;
+25  import org.opensaml.xml.io.UnmarshallingException;
+26  import org.w3c.dom.Attr;
+27  
+28  /**
+29   * A thread safe Unmarshaller for {@link org.opensaml.saml2.metadata.SingleLogoutService} objects.
+30   */
+31  public class DiscoveryResponseUnmarshaller extends IndexedEndpointUnmarshaller {
+32  
+33      /** {@inheritDoc} */
+34      protected void processAttribute(XMLObject samlObject, Attr attribute) throws UnmarshallingException {
+35          super.processAttribute(samlObject, attribute);
+36      }
+37  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryServiceHandler.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryServiceHandler.html new file mode 100644 index 0000000..9f4e4ed --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/DiscoveryServiceHandler.html @@ -0,0 +1,1016 @@ + + + + +DiscoveryServiceHandler xref + + + +
View Javadoc
+
+1   /**
+2    * Copyright [2006] [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.IOException;
+19  import java.io.UnsupportedEncodingException;
+20  import java.net.MalformedURLException;
+21  import java.net.URL;
+22  import java.net.URLDecoder;
+23  import java.net.URLEncoder;
+24  import java.util.ArrayList;
+25  import java.util.Collection;
+26  import java.util.Comparator;
+27  import java.util.Date;
+28  import java.util.HashSet;
+29  import java.util.Hashtable;
+30  import java.util.List;
+31  import java.util.Locale;
+32  import java.util.Map;
+33  import java.util.Set;
+34  import java.util.TreeSet;
+35  
+36  import javax.servlet.RequestDispatcher;
+37  import javax.servlet.ServletException;
+38  import javax.servlet.http.HttpServletRequest;
+39  import javax.servlet.http.HttpServletResponse;
+40  
+41  import org.opensaml.saml2.common.Extensions;
+42  import org.opensaml.saml2.metadata.EntityDescriptor;
+43  import org.opensaml.saml2.metadata.RoleDescriptor;
+44  import org.opensaml.saml2.metadata.SPSSODescriptor;
+45  import org.opensaml.xml.XMLObject;
+46  import org.slf4j.Logger;
+47  import org.slf4j.LoggerFactory;
+48  import org.w3c.dom.Element;
+49  import org.w3c.dom.NodeList;
+50  
+51  import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
+52  import edu.internet2.middleware.shibboleth.wayf.plugins.Plugin;
+53  import edu.internet2.middleware.shibboleth.wayf.plugins.PluginContext;
+54  import edu.internet2.middleware.shibboleth.wayf.plugins.PluginMetadataParameter;
+55  import edu.internet2.middleware.shibboleth.wayf.plugins.WayfRequestHandled;
+56  
+57  /**
+58    * Specific handler for each version of the Discovery Service. 
+59    */
+60  public class DiscoveryServiceHandler {
+61  
+62      /*
+63       * Protcol parameters - Old.
+64       */
+65      /**
+66       * Shire is the SP Assertion Consumer endpoint.
+67       */
+68      private static final String SHIRE_PARAM_NAME = "shire";
+69      /**
+70       * TargetName is where we are trying to get to.
+71       */
+72      private static final String TARGET_PARAM_NAME = "target";
+73      /**
+74       * time is to do with replay attack.
+75       */
+76      private static final String TIME_PARAM_NAME = "time";
+77      /**
+78       * This is the ID (in the metadata) of the SP.
+79       */
+80      private static final String PROVIDERID_PARAM_NAME = "providerId";
+81      
+82      /*
+83       * Protocol parameters - New
+84       */
+85      /**
+86       * The SP id.
+87       */
+88      private static final String ENTITYID_PARAM_NAME = "entityID";
+89      /**
+90       * Where to send the request back to.
+91       */
+92      private static final String RETURN_PARAM_NAME = "return";
+93      /**
+94       * "return" is an invalid attribute, so we use returnX.
+95       */
+96      private static final String RETURN_ATTRIBUTE_NAME = "returnX";
+97      /**
+98       * Alternatively the index of where to send the address back to.
+99       */
+100     private static final String RETURN_INDEX_NAME = "returnIndex";
+101     
+102     /**
+103      * What value to put the ID of the selected metadata into.
+104      */
+105     private static final String RETURNID_PARAM_NAME = "returnIDParam";
+106     
+107     /**
+108      * What returnIDParam defaults to.
+109      */
+110     private static final String RETURNID_DEFAULT_VALUE = "entityID";
+111     /**
+112      * Whether we are allowed to interact.
+113      */
+114     private static final String ISPASSIVE_PARAM_NAME = "isPassive";
+115     
+116     /**
+117      * Whether we understand this or not.
+118      */
+119     private static final String POLICY_PARAM_NAME = "policy";
+120 
+121     /**
+122      * The only policy we know about.
+123      */
+124     private static final String KNOWN_POLICY_NAME 
+125         = "urn:oasis:names:tc:SAML:profiles:SSO:idp-discoveryprotocol:single";
+126     
+127     /**
+128      * Mandatory Serialization constant.
+129      */
+130     private static final  Logger LOG = LoggerFactory.getLogger(DiscoveryServiceHandler.class.getName());
+131 
+132     /**
+133      * The location defines the last part of the URL which distinguished this handler. 
+134      */
+135     private final String location;
+136     
+137     /**
+138      * If isDefault is true then if there is a mismatch then this handler is used.  
+139      */
+140     private final boolean isDefault;
+141     
+142     /**
+143      * Config handles detailed behavior.
+144      */
+145     private final HandlerConfig config;
+146     
+147     /**
+148      * The list of all the metadata providers that this discovery handler believes in.
+149      */
+150     private final List <IdPSiteSet> siteSets;
+151     
+152     /**
+153      * The list of all the plugins that this hanlder has had configured.
+154      */
+155     private final List <Plugin> plugins;
+156     
+157     /**
+158      * Constructor to create and configure the handler.
+159      * @param config - DOM Element with configuration information.
+160      * @param federations - Supplies all known providers which will be included if so configured.
+161      * @param plugins - Supplies all known plugins which will be included if configured in. 
+162      * @param defaultConfig - The default configurations.
+163      * @throws ShibbolethConfigurationException - if we find something odd in the config file. 
+164      */
+165     protected DiscoveryServiceHandler(Element config, 
+166                                       Hashtable <String, IdPSiteSet> federations,
+167                                       Hashtable <String, Plugin> plugins, 
+168                                       HandlerConfig defaultConfig) throws ShibbolethConfigurationException
+169     {
+170         siteSets = new ArrayList <IdPSiteSet>(federations.size());
+171         this.plugins = new ArrayList <Plugin>(plugins.size());
+172 
+173         //
+174         // Collect the Configuration from the XML
+175         //
+176         
+177         this.config = new HandlerConfig(config, defaultConfig);
+178         
+179         location = config.getAttribute("location");
+180         
+181         if (location == null || location.equals("")) {
+182                 
+183                 LOG.error("DiscoveryService must have a location specified");
+184                 throw new ShibbolethConfigurationException("DiscoveryService must have a location specified");  
+185         }
+186         
+187         //
+188         // Is this the default WAYF?
+189         //
+190         
+191         String attribute = config.getAttribute("default");
+192         if (attribute != null && !attribute.equals("")) {
+193                 isDefault = Boolean.valueOf(attribute).booleanValue();
+194         } else {
+195                 isDefault = true;
+196         }
+197         
+198         //
+199         // Which federations (sitesets) do we care about?
+200         //
+201         
+202         NodeList list = config.getElementsByTagName("Federation");
+203                 
+204         for (int i = 0; i < list.getLength(); i++ ) {
+205                     
+206             attribute = ((Element) list.item(i)).getAttribute("identifier");
+207                     
+208                 IdPSiteSet siteset = federations.get(attribute);
+209                 
+210                 if (siteset == null) {
+211                     LOG.error("Handler " + location + ": could not find metadata for <Federation> with identifier " + attribute + ".");
+212                     throw new ShibbolethConfigurationException(
+213                            "Handler " + location + ": could not find metadata for  <Federation> identifier " + attribute + ".");
+214                 }
+215                 
+216                 siteSets.add(siteset);
+217         }
+218 
+219         if (siteSets.size() == 0) {
+220             //
+221             // No Federations explicitly named pick em all
+222             //
+223             siteSets.addAll(federations.values());
+224         }
+225         
+226         //
+227         // Now, which plugins?
+228         //
+229 
+230         list = config.getElementsByTagName("PluginInstance");
+231         
+232         for (int i = 0; i < list.getLength(); i++ ) {
+233                     
+234             attribute = ((Element) list.item(i)).getAttribute("identifier");
+235                     
+236                 Plugin plugin = plugins.get(attribute);
+237                 
+238                 if (plugin == null) {
+239                     LOG.error("Handler " + location + ": could not find plugin for identifier " + attribute);
+240                     throw new ShibbolethConfigurationException(
+241                               "Handler " + location + ": could not find plugin for identifier " + attribute);
+242                 }
+243                 
+244                 this.plugins.add(plugin);
+245         }
+246 
+247         //
+248         // So now tell every IdPSite about every plugin.
+249         //
+250         // Note that there is only one idpsite per metadatafile per WAYF and that the discovery 
+251         // services share them, so the data explosion is only number(IdpSites) * number(Plugins) not
+252         // number(IdpSites) * number(Plugins) * number(DiscoverHandlers)
+253         
+254         for (IdPSiteSet site: siteSets) {
+255             for (Plugin plugin: this.plugins) {
+256                 site.addPlugin(plugin);
+257             }
+258         }
+259     }
+260     
+261     
+262     //
+263     // Standard Beany Methods
+264     //
+265     /**
+266      * The 'Name' of the service. the path used to identify the ServiceHandler.
+267      * @return the path used to identify the ServiceHandler.
+268      */
+269     
+270     protected String getLocation() {
+271         return location;
+272     }
+273 
+274     /**
+275      * Whether this is the default service.
+276      * @return is it?
+277      */
+278     protected boolean isDefault() {
+279         return isDefault;
+280     }
+281     
+282     //
+283     // Now the bits that deal with the user request
+284     //
+285 
+286     public void doGet(HttpServletRequest req, HttpServletResponse res) {
+287         
+288         String policy = req.getParameter(POLICY_PARAM_NAME);
+289         
+290         if (null != policy && !KNOWN_POLICY_NAME.equals(policy)) {
+291             //
+292             // unknown policy
+293             //
+294             LOG.error("Unknown policy " + policy);
+295             handleError(req, res, "Unknown policy " + policy);
+296             return;
+297         }
+298         
+299         //
+300         // Decide how to route the request based on query string
+301         //
+302         String requestType = req.getParameter("action");
+303         
+304         if (requestType == null || requestType.equals("")) {
+305             requestType = "lookup";
+306         }
+307         
+308         try {
+309 
+310             if (requestType.equals("search")) {
+311                     
+312                 String parameter = req.getParameter("string"); 
+313                 if (parameter != null && parameter.equals("")) {
+314                         parameter = null;
+315                 }
+316                 handleLookup(req, res, parameter);
+317                     
+318             } else if (requestType.equals("selection")) {
+319                     
+320                 handleSelection(req, res);
+321             } else {
+322                 handleLookup(req, res, null);
+323             }
+324         } catch (WayfException we) {
+325             LOG.error("Error processing DS request:", we);
+326             handleError(req, res, we.getLocalizedMessage());
+327         } catch (WayfRequestHandled we) {
+328             //
+329             // Yuck - a sucess path involving an exception
+330             //
+331         }
+332 
+333     }
+334         
+335     /**
+336      * When the WAYF user has selected something we look it up, tell the plugins and then dispatch to the Idp.
+337      *  
+338      * @param req - standard J2EE stuff
+339      * @param res - standard J2EE stuff
+340      * @throws WayfRequestHandled - if one of the plugins has done the dispatch
+341      * @throws WayfException - if we had an errors
+342      */
+343     private void handleSelection(HttpServletRequest req, 
+344                                  HttpServletResponse res) throws WayfRequestHandled, WayfException 
+345      {
+346             
+347         String idpName = req.getParameter("origin");
+348         LOG.debug("Processing handle selection: " + idpName);
+349 
+350         String sPName = getSPId(req);
+351 
+352         if (idpName == null || idpName.equals("")) {
+353             handleLookup(req, res, null);
+354             return;
+355         }
+356 
+357         if (getValue(req, SHIRE_PARAM_NAME) == null) {
+358             //
+359             // 2.0 protocol
+360             //
+361             setupReturnAddress(sPName, req);
+362         }
+363         //
+364         // Notify plugins
+365         //
+366         IdPSite site = null; 
+367         
+368         for (Plugin plugin:plugins) {
+369             for (IdPSiteSet idPSiteSet: siteSets) {
+370                 PluginMetadataParameter param = idPSiteSet.paramFor(plugin);
+371                 plugin.selected(req, res, param, idpName);
+372                 if (site == null && idPSiteSet.containsIdP(idpName)) {
+373                     site = idPSiteSet.getSite(idpName);
+374                 }
+375             }
+376         }
+377         
+378         if (site == null) {
+379             handleLookup(req, res, null);
+380         } else {
+381             forwardRequest(req, res, site);
+382         }
+383     }
+384 
+385 
+386     /**
+387      * This sets up the parameter RETURN_ATTRIBUTE_NAME with the return address 
+388      * harvested from the reqest.
+389      * <ul><le>If a "return" parameter is present we check in the metadata for spoofing 
+390      *         and then set up from there </le>
+391      *     <le>If "returnID" is specified we get this from the metadata</le>
+392      *     <le>If nothing is provided we get the default from the metadata (if provided)</le>
+393      *     <le>Otherwise we whine</le>
+394      * </ul>     
+395      * @param spName - the name of the Service provider.
+396      * @param req - The request.
+397      * @throws WayfException - if we spot spoofing or there is no defaumlt 
+398      */
+399     private void setupReturnAddress(String spName, HttpServletRequest req) throws WayfException{
+400         
+401         DiscoveryResponseImpl[] discoveryServices;
+402         Set<XMLObject> objects = new HashSet<XMLObject>();
+403         String defaultName = null;
+404         
+405         for (IdPSiteSet metadataProvider:siteSets) {
+406             
+407             //
+408             // Only do work if the SP makes sense
+409             //
+410 
+411             if (metadataProvider.containsSP(spName)) {
+412                
+413                 //
+414                 // The name makes sense so let's get the entity and from that
+415                 // all of its roles
+416                 //
+417                 
+418                 EntityDescriptor entity = metadataProvider.getEntity(spName);
+419                 List<RoleDescriptor> roles = entity.getRoleDescriptors();
+420                 
+421                 for (RoleDescriptor role:roles) {
+422                     
+423                     //
+424                     // Check every role
+425                     //
+426                     
+427                     if (role instanceof SPSSODescriptor) {
+428                         
+429                         //
+430                         // And grab hold of all the extensions for SPSSO descriptors
+431                         //
+432                         
+433                         Extensions exts = role.getExtensions();
+434                         if (exts != null) {
+435                             objects.addAll(exts.getOrderedChildren());
+436                         }
+437                     }
+438                 }
+439             }
+440         }
+441         
+442         //
+443         // Now, let's strip out everything which isn't a DiscoveryService
+444         //
+445         
+446         discoveryServices = new DiscoveryResponseImpl[objects.size()];
+447         int dsCount = 0;
+448         
+449         for (XMLObject obj:objects) {
+450             if (obj instanceof DiscoveryResponseImpl) {
+451                 DiscoveryResponseImpl ds = (DiscoveryResponseImpl) obj;
+452                 discoveryServices[dsCount++] = ds;
+453                 if (ds.isDefault() || null == defaultName) {
+454                     defaultName = ds.getLocation();
+455                 }
+456             }
+457         }
+458         
+459         //
+460         // Now process the return parameters.  The name is either a parameter
+461         // called RETURN_PARAM_NAME or an attributes called RETURN_ATTRIBUTE_NAME
+462         //
+463         String returnName = req.getParameter(RETURN_PARAM_NAME);
+464         
+465         if (returnName == null || returnName.length() == 0) {
+466             returnName = getValue(req, RETURN_ATTRIBUTE_NAME);
+467         }
+468         
+469         //
+470         // Return index is only ever a parameter
+471         //
+472         
+473         String returnIndex = req.getParameter(RETURN_INDEX_NAME);
+474         
+475         if (returnName != null && returnName.length() != 0) {
+476             //
+477             // Given something so we have to police it.
+478             //
+479             String nameNoParam = returnName;
+480             URL providedReturnURL;
+481             int index = nameNoParam.indexOf('?');
+482             boolean found = false;
+483             
+484             if (index >= 0) {
+485                 nameNoParam = nameNoParam.substring(0,index);
+486             }
+487             
+488             try {
+489                 providedReturnURL = new URL(nameNoParam);                
+490             } catch (MalformedURLException e) {
+491                 throw new WayfException("Couldn't parse provided return name " + nameNoParam, e);
+492             }
+493             
+494             
+495             for (DiscoveryResponseImpl disc: discoveryServices) {
+496                 if (equalsURL(disc, providedReturnURL)) {
+497                     found = true;
+498                     break;
+499                 }
+500             }
+501             if (!found) {
+502                 throw new WayfException("Couldn't find endpoint " + nameNoParam + " in metadata");
+503             }
+504         } else if (returnIndex != null && returnIndex.length() != 0) {
+505             
+506             int index; 
+507             try {
+508                 index = Integer.parseInt(returnIndex);
+509             } catch (NumberFormatException e) {
+510                 throw new WayfException("Couldn't convert " + returnIndex + " into an index");
+511             }
+512             //
+513             // So look throught to find the endpoint with the correct index
+514             //
+515 
+516             boolean found = false;
+517             
+518             for (DiscoveryResponseImpl disc: discoveryServices) {
+519                 if (index  == disc.getIndex()) {
+520                     found = true;
+521                     returnName = disc.getLocation();
+522                     break;
+523                 }
+524             }
+525             if (!found) {
+526                 throw new WayfException("Couldn't not find endpoint " + returnIndex + "in metadata");
+527             }
+528         } else {
+529             //
+530             // No name, not index, so we want the default
+531             //
+532             returnName = defaultName;
+533         }
+534         //
+535         // So by now returnName has the correct value, either harvested from or
+536         // policed against the metadata
+537         //
+538         req.setAttribute(RETURN_ATTRIBUTE_NAME, returnName);
+539     }
+540 
+541     /**
+542      * Helper function to see whather the provided endpoint in the metadata matches the 
+543      * provided return URL in the request.
+544      * 
+545      * @param discovery
+546      * @param providedName
+547      * @return
+548      */
+549     private static boolean equalsURL(DiscoveryResponseImpl discovery, URL providedName) {
+550         
+551         //
+552         // Nothing provided - no match
+553         //
+554         if (null == discovery) {
+555             return false;
+556         }
+557         
+558         URL discoveryName;
+559         try {
+560             discoveryName = new URL(discovery.getLocation());
+561         } catch (MalformedURLException e) {
+562             //
+563             // Something bad happened.  Log it (it is only of interest to the sysadmin, not to the user)
+564             //
+565             LOG.warn("Found invalid discovery end point : " + discovery.getLocation(), e);
+566             return false;
+567         }
+568         
+569         return providedName.equals(discoveryName);
+570         
+571     }
+572 
+573     /**
+574      * Displays a Discovery Service selection page, having first consulted the plugins as needed.
+575      * @param req Describes the request
+576      * @param res Describes the response
+577      * @param searchName What are we looking for?
+578      * 
+579      * @throws WayfRequestHandled if a plugin has dealt with the request
+580      * @throws WayfException in case of an error.
+581      */
+582     private void handleLookup(HttpServletRequest req, 
+583                               HttpServletResponse res, 
+584                               String searchName) throws WayfException, WayfRequestHandled {
+585         
+586         String shire = getValue(req, SHIRE_PARAM_NAME);
+587         String providerId = getSPId(req);
+588         boolean twoZeroProtocol = (shire == null);
+589         boolean isPassive = (twoZeroProtocol && 
+590                              "true".equalsIgnoreCase(getValue(req, ISPASSIVE_PARAM_NAME)));
+591 
+592         Collection <IdPSiteSetEntry> siteLists = null;
+593         Collection<IdPSite> searchResults = null;
+594         
+595         if (config.getProvideListOfLists()) {
+596             siteLists = new ArrayList <IdPSiteSetEntry>(siteSets.size());
+597         }
+598 
+599         Collection <IdPSite> sites = null;
+600         Comparator<IdPSite> comparator = new IdPSite.Compare(req);
+601        
+602         if (config.getProvideList()) {
+603             sites = new TreeSet<IdPSite>(comparator);
+604         }
+605 
+606         if (searchName != null && !searchName.equals("")) {
+607             searchResults = new TreeSet<IdPSite>(comparator);
+608         }
+609 
+610         LOG.debug("Processing Idp Lookup for : " + providerId);
+611 
+612         //
+613         // Iterate over all the sitesets and if they know about the SP pass them to the plugins
+614         // and then add them too the list
+615         //
+616 
+617         PluginContext[] ctx = new PluginContext[plugins.size()];
+618         List<IdPSite> hintList = new ArrayList<IdPSite>();
+619         
+620         if (twoZeroProtocol) {
+621             setupReturnAddress(providerId, req);
+622         }
+623         //
+624         // By having siteLists and sites as parameters we only iterate over 
+625         // the metadata arrays once.
+626         //
+627         try {   
+628             for (IdPSiteSet metadataProvider:siteSets) {
+629                 
+630                 //
+631                 // Only do work if the SP makes sense
+632                 //
+633 
+634                 if (metadataProvider.containsSP(providerId) || !config.getLookupSp()) {
+635 
+636                     Collection <IdPSite> search = null;
+637                     
+638                     if (searchResults != null) {
+639                         search = new TreeSet<IdPSite>(comparator);
+640                     }
+641 
+642                     Map <String, IdPSite> theseSites = metadataProvider.getIdPSites(searchName, config, search);
+643                     
+644                     //
+645                     // Consult the plugins
+646                     //
+647                     for (int i = 0; i < plugins.size(); i++) {
+648                             
+649                         Plugin plugin = plugins.get(i);
+650                         
+651                         if (searchResults == null) {
+652                             //
+653                             // This was a search
+654                             //
+655                             ctx[i] = plugin.lookup(req, 
+656                                                    res, 
+657                                                    metadataProvider.paramFor(plugin), 
+658                                                    theseSites, 
+659                                                    ctx[i], 
+660                                                    hintList);
+661                         } else {
+662                             ctx[i] = plugin.search(req, 
+663                                                    res, 
+664                                                    metadataProvider.paramFor(plugin), 
+665                                                    searchName, 
+666                                                    theseSites, 
+667                                                    ctx[i], 
+668                                                    searchResults, 
+669                                                    hintList);
+670                         }
+671                     }
+672                     
+673                     if (null == theseSites || theseSites.isEmpty()) {
+674                         continue;
+675                     }
+676                     
+677                     //
+678                         
+679                     // Accumulate any per-metadata provider information
+680                     // 
+681             
+682                     Collection<IdPSite> values = new TreeSet<IdPSite>(comparator);
+683                     if (null != theseSites) {
+684                         values.addAll(theseSites.values());
+685                     }
+686                     
+687                     if (siteLists != null) {
+688                         siteLists.add(new IdPSiteSetEntry(metadataProvider,values));
+689                     }
+690                             
+691                     if (sites != null) {
+692                         sites.addAll(values);
+693                     }
+694                     
+695                     if (searchResults != null) {
+696                         searchResults.addAll(search);
+697                     }
+698                 }
+699             }
+700             
+701             if (isPassive) {
+702                 //
+703                 // No GUI intervention.
+704                 //
+705                 if (0 != hintList.size()) {
+706                     //
+707                     // We found a candidate, hand it back
+708                     //
+709                     forwardRequest(req, res, hintList.get(0));
+710                 } else {
+711                     forwardRequest(req, res, null);
+712                 }   
+713                 return;
+714             }
+715             
+716             //
+717             // Now set up all the funky stuff that the JSP needs.  Firstly the protocol
+718             // specific parameters which will come back to us
+719             //
+720             
+721             if (twoZeroProtocol) {
+722                 //
+723                 // The return address was set up in setupReturnAddress
+724                 //
+725                 String returnString = (String) req.getAttribute(RETURN_ATTRIBUTE_NAME);
+726                 if (null == returnString || 0 == returnString.length()) {
+727                     throw new WayfException("Parameter " + RETURN_PARAM_NAME + " not supplied");
+728                 }
+729 
+730                 String returnId = getValue(req, RETURNID_PARAM_NAME);
+731                 if (null == returnId || 0 == returnId.length()) {
+732                     returnId = RETURNID_DEFAULT_VALUE;
+733                 }
+734                 //
+735                 // Return *means* something so we cannot use it as an attribute
+736                 //
+737                 req.setAttribute(RETURN_ATTRIBUTE_NAME, returnString);
+738                 req.setAttribute(RETURNID_PARAM_NAME, returnId);
+739                 req.setAttribute(ENTITYID_PARAM_NAME, providerId);
+740                 
+741             } else {
+742                 String target = getValue(req, TARGET_PARAM_NAME);
+743                 if (null == target || 0 == target.length()) {
+744                     throw new WayfException("Could not extract target from provided parameters");
+745                 }
+746                 req.setAttribute(SHIRE_PARAM_NAME, shire);
+747                 req.setAttribute(TARGET_PARAM_NAME, target);
+748                 req.setAttribute(PROVIDERID_PARAM_NAME, providerId);
+749                 //
+750                 // Time is in unix format
+751                 //
+752                 req.setAttribute("time", new Long(new Date().getTime() / 1000).toString()); 
+753                 
+754             }
+755             
+756             //
+757             // Setup the stuff that the GUI wants.  
+758             //
+759                 
+760             setDisplayLanguage(sites, req);
+761             req.setAttribute("sites", sites);
+762             if (null != siteLists) {
+763                 for (IdPSiteSetEntry siteSetEntry:siteLists) {
+764                     setDisplayLanguage(siteSetEntry.getSites(), req);
+765                 }
+766             }
+767                 
+768             req.setAttribute("siteLists", siteLists);
+769             req.setAttribute("requestURL", req.getRequestURI().toString());
+770 
+771             if (searchResults != null) {
+772                 if (searchResults.size() != 0) {
+773                     setDisplayLanguage(searchResults, req);
+774                     req.setAttribute("searchresults", searchResults);
+775                 } else {
+776                     req.setAttribute("searchResultsEmpty", "true");
+777                 }
+778             }
+779 
+780             if (hintList.size() > 0) {
+781                 setDisplayLanguage(hintList, req);
+782                 req.setAttribute("cookieList", hintList);
+783             }
+784 
+785             LOG.debug("Displaying WAYF selection page.");
+786             RequestDispatcher rd = req.getRequestDispatcher(config.getJspFile());
+787 
+788             //
+789             // And off to the jsp
+790             //
+791             rd.forward(req, res);
+792         } catch (IOException ioe) {
+793             LOG.error("Problem displaying WAYF UI.\n" +  ioe.getMessage());
+794             throw new WayfException("Problem displaying WAYF UI", ioe);
+795         } catch (ServletException se) {
+796             LOG.error("Problem displaying WAYF UI.\n" +  se.getMessage());
+797             throw new WayfException("Problem displaying WAYF UI", se);
+798         }
+799     }
+800 
+801     /**
+802      * Prior to display we set the display language from the
+803      * browser. There is probably a proper way to do this using
+804      * jsp, but I want to keep the API between JSP and java the same 1.3->2.0
+805      * @param sites - the sites we need to impact
+806      * @param req - from whiuch we get the locale
+807      */
+808     private void setDisplayLanguage(Collection<IdPSite> sites, HttpServletRequest req) {
+809         
+810         if (null == sites) {
+811             return;
+812         }
+813         Locale locale = req.getLocale();
+814         if (null == locale) {
+815             Locale.getDefault();
+816         }
+817         String lang = locale.getLanguage();
+818 
+819         for (IdPSite site : sites) {
+820             site.setDisplayLanguage(lang);
+821         }
+822     }
+823 
+824 
+825     /**
+826      * Uses an HTTP Status 307 redirect to forward the user to the IdP or the SP.
+827      * 
+828      * @param req request under consideration
+829      * @param res response under construction
+830      * @param site The Idp
+831      * @throws WayfException if bad things happen.
+832      */
+833     public static void forwardRequest(HttpServletRequest req, HttpServletResponse res, IdPSite site)
+834                     throws WayfException {
+835 
+836         String shire = getValue(req, SHIRE_PARAM_NAME);
+837         String providerId = getSPId(req);
+838         boolean twoZeroProtocol = (shire == null);
+839 
+840         if (!twoZeroProtocol) {
+841             String handleService = site.getAddressForWAYF(); 
+842             if (handleService != null ) {
+843 
+844                 String target = getValue(req, TARGET_PARAM_NAME);
+845                 if (null == target || 0 == target.length()) {
+846                     throw new WayfException("Could not extract target from provided parameters");
+847                 }
+848 
+849                 LOG.info("Redirecting to selected Handle Service: " + handleService);
+850                 try {
+851                     StringBuffer buffer = new StringBuffer(handleService +  
+852                        "?" + TARGET_PARAM_NAME + "=");
+853                     buffer.append(URLEncoder.encode(target, "UTF-8"));
+854                     buffer.append("&" + SHIRE_PARAM_NAME + "=");
+855                     buffer.append(URLEncoder.encode(shire, "UTF-8"));
+856                     buffer.append("&" + PROVIDERID_PARAM_NAME + "=");
+857                     buffer.append(URLEncoder.encode(providerId, "UTF-8"));
+858                          
+859                     //
+860                     // Time is as per U**X
+861                     //
+862                     buffer.append("&" +  TIME_PARAM_NAME + "=");
+863                     buffer.append(new Long(new Date().getTime() / 1000).toString());
+864                     res.sendRedirect(buffer.toString());
+865                 } catch (IOException ioe) {
+866                     //
+867                     // That failed.  
+868                     //
+869                     throw new WayfException("Error forwarding to IdP: \n" + ioe.getMessage());
+870                 }
+871             } else {
+872                 String s = "Error finding to IdP: " + site.getDisplayName(req); 
+873                 LOG.error(s);
+874                 throw new WayfException(s);
+875             }
+876         } else {
+877             String returnUrl = (String) req.getAttribute(RETURN_ATTRIBUTE_NAME);
+878             
+879             if (null == returnUrl || 0 == returnUrl.length()) {
+880                 throw new WayfException("Could not find return parameter");
+881             }
+882             try {
+883                 returnUrl = URLDecoder.decode(returnUrl, "UTF-8");
+884             } catch (UnsupportedEncodingException e) {
+885                 throw new WayfException("Did not understand parameter ", e);
+886             }
+887             String redirect;
+888             if (site != null) {
+889                 StringBuffer buffer = new StringBuffer(returnUrl);
+890                 //
+891                 // If we were given anybody to lookup, construct the URL
+892                 //
+893                 String returnParam = getValue(req, RETURNID_PARAM_NAME);
+894                 if (null == returnParam || 0 == returnParam.length()) {
+895                     returnParam = RETURNID_DEFAULT_VALUE;
+896                 }              
+897                 //
+898                 // Do we add a '?' or a '&' for the parameters
+899                 //
+900 
+901                 if (returnUrl.indexOf('?') >= 0) {
+902                     //
+903                     // there is a parameter already.  Add a '&'
+904                     //
+905                     buffer.append("&" + returnParam + "=");
+906                 } else {
+907                     //
+908                     // No parameter.  Use ?
+909                     //
+910                     buffer.append("?" + returnParam + "=");
+911                 }
+912                 buffer.append(site.getName());
+913                 redirect =  buffer.toString();
+914             } else {
+915                 //
+916                 // Just send it back
+917                 //
+918                 redirect = returnUrl;
+919             }
+920             
+921             LOG.debug("Dispatching to " + redirect);
+922             
+923             try {
+924                 res.sendRedirect(redirect);
+925             } catch (IOException ioe) {
+926                 //
+927                 // That failed.  
+928                 //
+929                 throw new WayfException("Error forwarding back to Sp: \n" + ioe.getMessage());
+930             }         
+931         }
+932     }
+933 
+934     /**
+935      * Handles all "recoverable" errors in WAYF processing by logging the error and forwarding the user to an
+936      * appropriate error page.
+937      * 
+938      * @param req request under consideration
+939      * @param res response under construction
+940      * @param message - what so say
+941      */
+942     private void handleError(HttpServletRequest req, HttpServletResponse res, String message) {
+943 
+944         LOG.debug("Displaying WAYF error page.");
+945         req.setAttribute("errorText", message);
+946         req.setAttribute("requestURL", req.getRequestURI().toString());
+947         RequestDispatcher rd = req.getRequestDispatcher(config.getErrorJspFile());
+948 
+949         try {
+950             rd.forward(req, res);
+951         } catch (IOException ioe) {
+952             LOG.error("Problem trying to display WAYF error page: " + ioe.toString());
+953         } catch (ServletException se) {
+954             LOG.error("Problem trying to display WAYF error page: " + se.toString());
+955         }
+956     }
+957 
+958     /**
+959      * Gets the value for the parameter either from the parameter or from jsp.
+960      * @param req - the request.
+961      * @param name - the name of the parameter.
+962      * @return - result
+963      */
+964     private static String getValue(HttpServletRequest req, String name) {
+965 
+966         
+967         String value = req.getParameter(name); 
+968         if (value != null) {
+969             return value;
+970         }
+971         return (String) req.getAttribute(name);
+972     }
+973 
+974     private static String getSPId(HttpServletRequest req) throws WayfException {
+975 
+976         //
+977         // Try first with 2.0 version
+978         //
+979         String param = req.getParameter(ENTITYID_PARAM_NAME);
+980         if (param != null && !(param.length() == 0)) {
+981             return param;
+982         } 
+983         
+984         param = (String) req.getAttribute(ENTITYID_PARAM_NAME);
+985         if (param != null && !(param.length() == 0)) {
+986             return param;
+987         }       
+988         //
+989         // So Try with 1.3 version
+990         //
+991         param = req.getParameter(PROVIDERID_PARAM_NAME);
+992         if (param != null && !(param.length() == 0)) {
+993             return param;
+994         } 
+995         
+996         param = (String) req.getAttribute(PROVIDERID_PARAM_NAME);
+997         if (param != null && !(param.length() == 0)) {
+998             return param;
+999         } 
+1000         throw new WayfException("Could not locate SP identifier in parameters");
+1001     }   
+1002 }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/HandlerConfig.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/HandlerConfig.html new file mode 100644 index 0000000..3e688b3 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/HandlerConfig.html @@ -0,0 +1,236 @@ + + + + +HandlerConfig 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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  import java.util.HashSet;
+20  
+21  import org.slf4j.Logger;
+22  import org.slf4j.LoggerFactory;
+23  import org.w3c.dom.Element;
+24  import org.w3c.dom.NodeList;
+25  
+26  import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
+27  
+28  /**
+29   * Class used by the DiscoveryServiceHandler to handle run time behaviour. 
+30   */
+31  
+32  public class HandlerConfig {
+33  
+34      /**
+35       * How to get debug output out.
+36       */
+37      private static final Logger LOG = LoggerFactory.getLogger(HandlerConfig.class.getName());
+38      
+39      /** A set of names which are ignored when doing a search. */
+40      private final HashSet <String> ignoredForMatch;
+41          
+42      /** Where to find the GUI description jsp file. */
+43      private final String jspFile;
+44      
+45      /** Where to find the error jsp file. */
+46      private final String errorJspFile;
+47          
+48      /** Do we give the jsp file an array of arrays of IdPs? */
+49      private final boolean provideListOfLists;
+50          
+51      /** Do we give the jsp file a flat list of IdPs? */
+52      private final boolean provideList;
+53      
+54      /** Do we do a pre-filter by SP name in for each metadata provider. */
+55      private final boolean lookupSp; 
+56      
+57      /** Do we warn on the bad binding. */
+58      private final boolean warnOnBadBinding;
+59   
+60      /** Build the 'default default' configuation. */ 
+61      public HandlerConfig() {
+62          //
+63          // 'Sensible' default values
+64          //
+65          jspFile = "/wayf.jsp";
+66          errorJspFile = "/wayfError.jsp";
+67          provideList = true;
+68          provideListOfLists = false;
+69          lookupSp = true;
+70          ignoredForMatch = new HashSet <String>(); 
+71          warnOnBadBinding = false;
+72      }
+73          
+74          
+75      /**
+76       * 
+77       * Parse the Supplied XML element into a new WayfConfig Object.
+78       * @param config - The XML with the configuration info.
+79       * @param defaultValue - The default if nothing is specified.
+80       * @throws ShibbolethConfigurationException - if we see somethin wrong.
+81       */
+82      public HandlerConfig(Element config, HandlerConfig defaultValue) throws ShibbolethConfigurationException {
+83          
+84          String attribute;   
+85          LOG.debug("Loading global configuration properties.");
+86  
+87          NodeList list = config.getElementsByTagName("SearchIgnore");
+88          
+89          if (list.getLength() == 0) {
+90              
+91              ignoredForMatch = defaultValue.ignoredForMatch;
+92  
+93          } else { 
+94              
+95              ignoredForMatch = new HashSet<String>();        
+96                  
+97              for (int i = 0; i < list.getLength(); i++ ) {
+98                      
+99                      NodeList inner = ((Element) list.item(i)).getElementsByTagName("IgnoreText");
+100                     
+101                     for(int j = 0; j < inner.getLength(); j++) {
+102                             
+103                             addIgnoredForMatch(inner.item(j).getTextContent());
+104                     }
+105                 }
+106         }
+107 
+108         attribute = config.getAttribute("jspFile");
+109         if (attribute != null && !attribute.equals("")) {
+110                 jspFile = attribute;
+111         } else {
+112                 jspFile = defaultValue.jspFile;
+113         }
+114         
+115         attribute = config.getAttribute("errorJspFile");
+116         if (attribute != null && !attribute.equals("")) {
+117                 errorJspFile = attribute;
+118         } else {
+119                 errorJspFile = defaultValue.errorJspFile;
+120         }
+121         
+122         attribute = config.getAttribute("provideList");
+123         if (attribute != null && !attribute.equals("")) {
+124                 provideList = Boolean.valueOf(attribute).booleanValue();
+125         } else { 
+126                 provideList = defaultValue.provideList;
+127         }
+128 
+129         attribute = config.getAttribute("provideListOfList");
+130         if (attribute != null && !attribute.equals("")) {
+131                 provideListOfLists = Boolean.valueOf(attribute).booleanValue();
+132         } else {
+133                 provideListOfLists = defaultValue.provideListOfLists;
+134         }
+135         
+136         attribute = config.getAttribute("showUnusableIdPs");
+137         if (attribute != null && !attribute.equals("")) {
+138                 lookupSp = !Boolean.valueOf(attribute).booleanValue();
+139         } else {
+140                 lookupSp = defaultValue.lookupSp;
+141         }
+142         
+143         attribute = config.getAttribute("warnOnBadBinding");
+144         if (null != attribute && !attribute.equals("")) {
+145                 warnOnBadBinding = Boolean.valueOf(attribute).booleanValue();
+146         } else {
+147             warnOnBadBinding = false;
+148         }
+149     }
+150     
+151 
+152     /**
+153      * Determines if a particular string token should be used for matching when a user searches for origins.
+154      * 
+155      * @param str - The string to lookup.
+156      * @return whether it is or not.
+157      */
+158     public boolean isIgnoredForMatch(String str) {
+159 
+160         return ignoredForMatch.contains(str.toLowerCase());
+161     }
+162 
+163     /**
+164      * Sets the tokens that should be ignored when a user searches for an origin site.
+165      * 
+166      * @param s
+167      *            The ignored tokens are passed as a single string, each separated by whitespace
+168      */
+169     private void addIgnoredForMatch(String s) {
+170 
+171             ignoredForMatch.add(s.toLowerCase());
+172     }
+173 
+174     /**
+175      * Get the name of the jsp File this instance uses.
+176      * @return the name.
+177      */
+178     public String getJspFile() {
+179             return jspFile;
+180     }
+181     
+182     /**
+183      * Get the name of the error jsp File this instance uses.
+184      * @return the name.
+185      */
+186     public String getErrorJspFile() {
+187             return errorJspFile;
+188     }
+189     
+190     /**
+191      * Do we provide a list of lists of IdPs?.
+192      * @return whether we do or not.
+193      */
+194     public boolean getProvideListOfLists() {
+195             return provideListOfLists;
+196     }
+197     
+198     /**
+199      * Do we provide a list of IdPs?.
+200      * @return whether we provide a list of IdPs?.
+201      */
+202     public boolean getProvideList() {
+203         return provideList;
+204     }
+205     
+206     /**
+207      * Do we lookup the SP or just return all the IdPs?.
+208      * @return whether or not we lookup the SP
+209      */
+210     public boolean getLookupSp() {  
+211         return lookupSp;  
+212     }
+213     
+214     /**
+215      * Do ignore badly formed bindings or just warn
+216      * @return whether we warn.
+217      */
+218     public boolean getWarnOnBadBinding() {  
+219         return warnOnBadBinding;  
+220     }
+221     
+222 }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSite.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSite.html new file mode 100644 index 0000000..a139c6d --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSite.html @@ -0,0 +1,231 @@ + + + + +IdPSite 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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  import java.util.Comparator;
+20  import java.util.List;
+21  import java.util.Locale;
+22  
+23  import javax.servlet.http.HttpServletRequest;
+24  
+25  import org.opensaml.saml2.metadata.EntityDescriptor;
+26  import org.opensaml.saml2.metadata.Organization;
+27  import org.opensaml.saml2.metadata.OrganizationDisplayName;
+28  import org.opensaml.saml2.metadata.SingleSignOnService;
+29  
+30  /**
+31   * A class which abstracts an IdP for the sake of the WAYF display.  Given an {@link EntityDescriptor} as
+32   * input it provides bean style get functions for the name (EntityId), the display name 
+33   * (a hybrid of Organization name or EntityId and the IdP's SSO connection point.
+34   * 
+35   */
+36  public class IdPSite {
+37  
+38      /** The OpenSaml element that this stands for. */
+39      private EntityDescriptor entity;
+40      
+41      /** The language we set up */
+42      private String displayLanguage;
+43      
+44      /**
+45       * Create a new element from the provided Entity.
+46       * @param entityParam - What to create from
+47       */
+48      public IdPSite(EntityDescriptor entityParam) {
+49          entity = entityParam;
+50      }
+51      
+52      /**
+53       * Get the name for the enclosed entity. 
+54       * @return the name for the enclosed entity.
+55       */
+56      public String getName() {
+57              return entity.getEntityID();
+58      }
+59      
+60      /**
+61       * Get the user friendly name for the entity, collecting the locale from the 
+62       * browser if possible
+63       * @param req the request
+64       * @return a user friendly name.
+65       */
+66      public String getDisplayName(HttpServletRequest req) {
+67          //
+68          // Get the browser locale, failing that the server one
+69          //
+70          Locale locale = req.getLocale();
+71          if (null == locale) {
+72              Locale.getDefault();
+73          }
+74          String lang = locale.getLanguage();
+75              
+76          return getDisplayName(lang);
+77      }
+78      /**
+79       * Get the user friendly name for the entity, using provided language
+80       * @param lang the language.
+81       * 
+82       * @return a user friendly name.
+83       */
+84      private String getDisplayName(String lang) {
+85          Organization org = entity.getOrganization();
+86      
+87          if (org == null) {
+88              return entity.getEntityID();
+89          } 
+90          
+91          List<OrganizationDisplayName> list = org.getDisplayNames();
+92  
+93          //
+94          // Lookup first by locale
+95          //
+96          
+97          for (OrganizationDisplayName name:list) {
+98              if (null !=name && lang.equals(name.getName().getLanguage())) {
+99                  return name.getName().getLocalString();
+100             }
+101         }
+102         
+103         //
+104         // If that doesn't work then anything goes
+105         //
+106         
+107         for (OrganizationDisplayName name:list) {
+108             if (null !=name && null != name.getName().getLocalString()) {
+109                 return name.getName().getLocalString();
+110             }
+111         }
+112      
+113         //
+114         // If there is still nothing then use the entity Id
+115         //
+116         return entity.getEntityID();
+117     }
+118     /**
+119      * Get the user friendly name for the entity, the language we previouslt set up
+120      * @param lang the language.
+121      * 
+122      * @return a user friendly name.
+123      */
+124     public String getDisplayName() {
+125         return getDisplayName(displayLanguage);
+126     }
+127     
+128     /**
+129      * Comparison so we can sort the output for jsp.
+130      * @param o What to compare against
+131      * @return numeric encoding of comparison 
+132      * @see java.lang.Comparator
+133      */
+134     protected int compareTo(Object o, HttpServletRequest req) {
+135             
+136 
+137         String myDisplayName;
+138         String otherDisplayName;
+139         IdPSite other;
+140 
+141         if (equals(o)) {
+142             return 0;
+143         }
+144 
+145         myDisplayName = getDisplayName(req);
+146         if (null == myDisplayName) {
+147             myDisplayName = "";
+148         } 
+149         
+150         other = (IdPSite) o;
+151         otherDisplayName = other.getDisplayName(req);
+152         if (null == otherDisplayName) {
+153             otherDisplayName = "";
+154         }
+155 
+156         int result = myDisplayName.toLowerCase().compareTo(otherDisplayName.toLowerCase());
+157         if (result == 0) {
+158                 result = myDisplayName.compareTo(otherDisplayName);
+159         }
+160         return result;
+161     }
+162 
+163     /**
+164      * When a user has selected an IdP, this provides the address to which we redirect.
+165      * @return http address for the IdP this represents.  
+166      */
+167     public String getAddressForWAYF() {
+168         List<SingleSignOnService> ssoList;
+169         
+170         ssoList = entity.getIDPSSODescriptor(XMLConstants.SHIB_NS).getSingleSignOnServices();
+171         
+172         for (SingleSignOnService signOnService: ssoList) {
+173             if (XMLConstants.IDP_SSO_BINDING.equals(signOnService.getBinding())) {
+174                 return signOnService.getLocation();
+175             }
+176         }
+177         return null;
+178     }
+179 
+180     /**
+181      * Prior to display we set the display language from the
+182      * browser. There is probably a proper way to do this using
+183      * jsp, but I want to keep the API between JSP and java the same 1.3->2.0
+184      * @param lang the language to set
+185      */
+186     public void setDisplayLanguage(String lang) {
+187         this.displayLanguage = lang;
+188     }
+189     
+190     public static class Compare implements Comparator<IdPSite> {
+191 
+192         /**
+193          * This allows us to set up sorted lists of entities with respect to
+194          * the browser request.
+195          * 
+196          * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+197          */
+198         private HttpServletRequest req = null;
+199         
+200         private Compare() {
+201             //
+202             // No public method
+203         }
+204         
+205         public Compare(HttpServletRequest req) {
+206             this.req = req;
+207         }
+208         
+209         public int compare(IdPSite o1, IdPSite o2) {
+210             // TODO Auto-generated method stub
+211             return o1.compareTo(o2, req);
+212         }
+213         
+214     }
+215 
+216 }       
+217 
+
+
+ + 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 
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSetEntry.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSetEntry.html new file mode 100644 index 0000000..cc3ae38 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/IdPSiteSetEntry.html @@ -0,0 +1,71 @@ + + + + +IdPSiteSetEntry 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.util.Collection;
+19  /**
+20   * This is just a container class for tieing together a set of IdPs to a name - this being what
+21   * is sent to the JSP for display purposes.
+22   */
+23  public class IdPSiteSetEntry {
+24          
+25      /** The metadata provider. */
+26      private final IdPSiteSet siteSet;
+27      
+28      /** The IdPs associated with that metadata provider. */
+29      private final Collection<IdPSite> sites;
+30      
+31      /**
+32       * Create an object which contains just these two objects.
+33       * @param siteSetParam the metadata provider.
+34       * @param sitesParam the list of IdPs. 
+35       */
+36      public IdPSiteSetEntry(IdPSiteSet siteSetParam, Collection<IdPSite> sitesParam) {
+37          this.siteSet = siteSetParam;
+38          this.sites = sitesParam;
+39      }
+40      
+41      /** 
+42       * Return something to display for this set of sites. 
+43       * @return the name as defined in the configuration
+44       */
+45      public String getName() {
+46          return siteSet.getDisplayName();
+47      }
+48      
+49      /**
+50       * Return the list of associated sites. 
+51       * @return a collection of IdPs.
+52       */
+53      public Collection<IdPSite> getSites() {
+54          return sites;
+55      }
+56  
+57  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackConfigurationChangeListener.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackConfigurationChangeListener.html new file mode 100644 index 0000000..e4560ba --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackConfigurationChangeListener.html @@ -0,0 +1,86 @@ + + + + +LogbackConfigurationChangeListener xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright [2007] [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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  import org.opensaml.util.resource.Resource;
+20  import org.opensaml.util.resource.ResourceChangeListener;
+21  import org.opensaml.util.resource.ResourceException;
+22  import org.slf4j.LoggerFactory;
+23  
+24  import ch.qos.logback.classic.LoggerContext;
+25  import ch.qos.logback.classic.joran.JoranConfigurator;
+26  import ch.qos.logback.core.joran.spi.JoranException;
+27  import ch.qos.logback.core.status.ErrorStatus;
+28  import ch.qos.logback.core.status.InfoStatus;
+29  import ch.qos.logback.core.status.StatusManager;
+30  
+31  /** Callback that may be registered for a watch logback configuration file. */
+32  public class LogbackConfigurationChangeListener implements ResourceChangeListener {
+33  
+34      /** {@inheritDoc} */
+35      public void onResourceCreate(Resource resource) {
+36          configureLogback(resource);
+37      }
+38  
+39      /** {@inheritDoc} */
+40      public void onResourceDelete(Resource resource) {
+41          // do nothing
+42      }
+43  
+44      /** {@inheritDoc} */
+45      public void onResourceUpdate(Resource resource) {
+46          configureLogback(resource);
+47      }
+48  
+49      /**
+50       * Configures logback using the given resource as the Joran configuration file.
+51       * 
+52       * @param configuration logback configuration file
+53       */
+54      protected void configureLogback(Resource configuration) {
+55          LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
+56          StatusManager statusManager = loggerContext.getStatusManager();
+57          statusManager.add(new InfoStatus("Loading logging configuration file: " + configuration.getLocation(), this));
+58          try {
+59              loggerContext.reset();
+60              JoranConfigurator configurator = new JoranConfigurator();
+61              configurator.setContext(loggerContext);
+62              configurator.doConfigure(configuration.getInputStream());
+63              loggerContext.start();
+64          } catch (JoranException e) {
+65              statusManager.add(new ErrorStatus("Error loading logging configuration file: "
+66                      + configuration.getLocation(), this, e));
+67          } catch (ResourceException e) {
+68              statusManager.add(new ErrorStatus("Error loading logging configuration file: "
+69                      + configuration.getLocation(), this, e));
+70          }
+71      }
+72  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackLoggingService.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackLoggingService.html new file mode 100644 index 0000000..53ef169 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/LogbackLoggingService.html @@ -0,0 +1,78 @@ + + + + +LogbackLoggingService xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright [2007] [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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  import java.util.Timer;
+20  
+21  import org.opensaml.util.resource.FilesystemResource;
+22  import org.opensaml.util.resource.Resource;
+23  import org.opensaml.util.resource.ResourceChangeWatcher;
+24  import org.opensaml.util.resource.ResourceException;
+25  import org.slf4j.LoggerFactory;
+26  
+27  import ch.qos.logback.classic.LoggerContext;
+28  import ch.qos.logback.core.status.ErrorStatus;
+29  import ch.qos.logback.core.status.StatusManager;
+30  
+31  /**
+32   * Simple logging service that watches for logback configuration file changes and reloads the file when a change occurs.
+33   */
+34  public class LogbackLoggingService {
+35      
+36      /** Timer used periodically read the logging configuration file. */
+37      private Timer taskTimer;
+38  
+39      /**
+40       * Constructor.
+41       *
+42       * @param loggingConfigurationFile logback configuration file
+43       * @param pollingFrequency frequency the configuration file should be checked for changes
+44       */
+45      public LogbackLoggingService(String loggingConfigurationFile, long pollingFrequency) {        
+46          LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
+47          StatusManager statusManager = loggerContext.getStatusManager();
+48          
+49          try{
+50              Resource configResource = new FilesystemResource(loggingConfigurationFile);
+51              LogbackConfigurationChangeListener configChangeListener = new LogbackConfigurationChangeListener();
+52              configChangeListener.onResourceCreate(configResource);
+53              
+54              ResourceChangeWatcher resourceWatcher = new ResourceChangeWatcher(configResource, pollingFrequency, 5);
+55              resourceWatcher.getResourceListeners().add(configChangeListener);
+56              
+57              taskTimer = new Timer(true);
+58              taskTimer.schedule(resourceWatcher, 0, pollingFrequency);
+59          }catch(ResourceException e){
+60              statusManager.add(new ErrorStatus("Error loading logging configuration file: "
+61                      + loggingConfigurationFile, this, e));
+62          }
+63      }
+64  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/Version.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/Version.html new file mode 100644 index 0000000..0598401 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/Version.html @@ -0,0 +1,45 @@ + + + + +Version xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright 2008 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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  /** Class for printing the version of this library. */
+20  public class Version {
+21  
+22      /**
+23       * Main entry point to program.
+24       * 
+25       * @param args command line arguments
+26       */
+27      public static void main(String[] args) {
+28          Package pkg = Version.class.getPackage();
+29          System.out.println(pkg.getImplementationTitle() + " version " + pkg.getImplementationVersion());
+30      }
+31  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfException.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfException.html new file mode 100644 index 0000000..886c6c8 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfException.html @@ -0,0 +1,61 @@ + + + + +WayfException 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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  
+20  /**
+21   * Signals that an error has occurred while processing a Shibboleth WAYF request.
+22   * 
+23   * @author Walter Hoehn wassa&#064;columbia.edu
+24   */
+25  
+26  public class WayfException extends Exception {
+27  
+28      /** Required serialization constant. */ 
+29      private static final long serialVersionUID = 8426660801169338914L;
+30      
+31      /**
+32       * Constructor with a description and an exception.
+33       * @param s description
+34       * @param e something bad having happened.
+35       */
+36      public WayfException(String s, Throwable e) {
+37          super(s, e);
+38      }
+39  
+40      /**
+41       * Constructure with just a description.
+42       * @param s description
+43       */
+44      public WayfException(String s) {
+45          super(s);
+46      }
+47  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfService.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfService.html new file mode 100644 index 0000000..488e3a0 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/WayfService.html @@ -0,0 +1,332 @@ + + + + +WayfService 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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  import java.io.FileInputStream;
+20  import java.io.FileNotFoundException;
+21  import java.lang.reflect.Constructor;
+22  import java.util.ArrayList;
+23  import java.util.Hashtable;
+24  import java.util.Iterator;
+25  import java.util.List;
+26  
+27  import javax.servlet.GenericServlet;
+28  import javax.servlet.ServletException;
+29  import javax.servlet.http.HttpServlet;
+30  import javax.servlet.http.HttpServletRequest;
+31  import javax.servlet.http.HttpServletResponse;
+32  import javax.xml.namespace.QName;
+33  
+34  import org.opensaml.DefaultBootstrap;
+35  import org.opensaml.xml.Configuration;
+36  import org.opensaml.xml.parse.BasicParserPool;
+37  import org.opensaml.xml.util.DatatypeHelper;
+38  import org.slf4j.Logger;
+39  import org.slf4j.LoggerFactory;
+40  import org.w3c.dom.Document;
+41  import org.w3c.dom.Element;
+42  import org.w3c.dom.NodeList;
+43  
+44  import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
+45  import edu.internet2.middleware.shibboleth.wayf.plugins.Plugin;
+46  
+47  /**
+48   * A servlet implementation of the Shibboleth WAYF service. Allows a browser
+49   * user to select from among a group of origin sites. User selection is
+50   * optionally cached and the user is forwarded to the HandleService appropriate
+51   * to his selection.
+52   */
+53  public class WayfService extends HttpServlet {
+54  
+55      /** Required constant for serializaton. */
+56      private static final long serialVersionUID = 5244503011625804940L;
+57      
+58      /** Handle for outputting error and other messages. */
+59      private static final Logger LOG = LoggerFactory.getLogger(WayfService.class.getName());
+60  
+61      /** Where to get the configuration. */
+62      private String wayfConfigFileLocation;
+63      
+64      /** Logging service. */
+65      private LogbackLoggingService logService;
+66  
+67      /** All the different Discovery Services we deal with. */
+68      private List <DiscoveryServiceHandler> discoveryServices = new ArrayList <DiscoveryServiceHandler>();
+69      
+70      /**
+71       * Initialize the Discovery Service.
+72       * 
+73       * @throws ServletException in the case of something bad happening
+74       *  
+75       * @see GenericServlet#init()
+76       */
+77      public void init() throws ServletException {
+78  
+79          super.init();
+80          
+81          wayfConfigFileLocation = getServletContext().getInitParameter("WAYFConfigFileLocation");
+82          if (wayfConfigFileLocation == null) {
+83              wayfConfigFileLocation = getServletConfig().getInitParameter("WAYFConfigFileLocation");
+84          }
+85          if (wayfConfigFileLocation == null) {
+86              wayfConfigFileLocation = "/wayfconfig.xml";
+87          }
+88  
+89  
+90          try {
+91              //
+92              // Initialize logging
+93              //
+94              String wayfLogfile = getServletContext().getInitParameter("WAYFLogConfig");
+95              if (null == wayfLogfile) {
+96                  wayfLogfile = getServletConfig().getInitParameter("WAYFLogConfig");
+97              }
+98              long pollingFrequency = 1000*60*5;
+99              
+100             String wayfLogfilePollFrequency = getServletContext().getInitParameter("WAYFLogConfigPollFrequency");
+101             if (null == wayfLogfilePollFrequency) {
+102                 wayfLogfilePollFrequency = getServletConfig().getInitParameter("WAYFLogConfigPollFrequency");              
+103             }
+104             if(!DatatypeHelper.isEmpty(wayfLogfilePollFrequency)){
+105                 pollingFrequency = Long.parseLong(wayfLogfilePollFrequency);
+106             }
+107             if (wayfLogfile != null) {
+108                 logService = new LogbackLoggingService(wayfLogfile, pollingFrequency);
+109             }
+110 
+111             LOG.info("Logging initiated");
+112             
+113             //
+114             // Initialize OpenSAML 2 library
+115             //
+116             DefaultBootstrap.bootstrap();   
+117         
+118             BasicParserPool parser = new BasicParserPool();
+119             parser.setNamespaceAware(true);
+120             Document doc;
+121             try {
+122                 doc = parser.parse(new FileInputStream(wayfConfigFileLocation));
+123             } catch (FileNotFoundException e) {
+124                 LOG.error("Could not parse " + wayfConfigFileLocation, e);
+125                 throw new ShibbolethConfigurationException("Could not parse " + wayfConfigFileLocation, e);
+126             }            
+127             NodeList itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS, 
+128                                                                                     "Default");
+129             
+130             HandlerConfig defaultHandlerConfig;
+131             
+132             if (itemElements.getLength() == 1) {
+133                     
+134                 Element element = (Element) itemElements.item(0);
+135                 String attribute = element.getAttribute("location");
+136                 
+137                 if (attribute != null && !attribute.equals("")) {
+138                         
+139                     LOG.error("<Default> element cannot contain a location attribute");
+140                     throw new ShibbolethConfigurationException("<Default> element cannot contain a location attribute");
+141                         
+142                 }
+143     
+144                 attribute = element.getAttribute("default");
+145                 
+146                 if (attribute != null && !attribute.equals("")) {
+147     
+148                     LOG.error("<Default> element cannot contain a default attribute");
+149                     throw new ShibbolethConfigurationException("<Default> element cannot contain a default attribute");
+150                     
+151                 }
+152     
+153                 itemElements = element.getElementsByTagName("Federation");
+154                 
+155                 if (itemElements.getLength() != 0) {
+156                         
+157                     LOG.error("<Default> element cannot contain <Federation> elements");
+158                     throw new ShibbolethConfigurationException("<Default> element cannot contain <Federation> elements");
+159     
+160                 }
+161                                         
+162                 defaultHandlerConfig = new HandlerConfig(element, new HandlerConfig());
+163         
+164             } else if (itemElements.getLength() == 0) {
+165     
+166                     defaultHandlerConfig = new HandlerConfig();
+167             
+168             } else {
+169                     LOG.error("Must specify exactly one <Default> element");
+170                     throw new ShibbolethConfigurationException("Must specify exactly one <Default> element");
+171             }
+172             //
+173             // Extra types
+174             //
+175             QName response = new QName(DiscoveryResponseImpl.METADATA_NS, DiscoveryResponseImpl.DEFAULT_ELEMENT_LOCAL_NAME);
+176             
+177             Configuration.getUnmarshallerFactory().registerUnmarshaller(response, new DiscoveryResponseUnmarshaller());
+178             Configuration.getBuilderFactory().registerBuilder(response, new DiscoveryResponseBuilder());
+179                                           
+180             //
+181             // Load metadata
+182             //
+183             Hashtable <String, IdPSiteSet> siteSets = new Hashtable <String, IdPSiteSet>();
+184     
+185             itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS,
+186                             "MetadataProvider");
+187             
+188             for (int i = 0; i < itemElements.getLength(); i++) {
+189                     
+190                 Element element = (Element) itemElements.item(i);
+191                 
+192                 IdPSiteSet siteset = new IdPSiteSet(element, parser, defaultHandlerConfig.getWarnOnBadBinding());
+193                 
+194                 siteSets.put(siteset.getIdentifier(), siteset);
+195             }
+196             if (siteSets.size() < 1) {
+197                 LOG.error("No Metadata Provider metadata loaded.");
+198                 throw new ShibbolethConfigurationException("Could not load SAML metadata.");
+199             }
+200             //
+201             // Load plugins
+202             //
+203             
+204             Hashtable <String, Plugin> plugins = new Hashtable <String, Plugin>();
+205     
+206             itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS,
+207                             "Plugin");
+208             
+209             for (int i = 0; i < itemElements.getLength(); i++) {
+210                     
+211                 Plugin plugin;
+212                 
+213                 Element element = (Element) itemElements.item(i);
+214                 
+215                 String identifier = element.getAttribute("identifier");
+216         
+217                 if (null == identifier || identifier.equals("")) {
+218                         LOG.error("Could not load plugin with no identifier");
+219                         continue;
+220                 }
+221                 
+222                 String className = element.getAttribute("type");
+223                 if (null == className || className.equals("")) {
+224                         LOG.error("Plugin " + identifier + " did not have a valid type");
+225                 }
+226                 //
+227                 // So try to get hold of the plugin
+228                 //
+229                 try {
+230                     Class<Plugin> pluginClass = (Class<Plugin>) Class.forName(className);
+231                     Class[] classParams = {Element.class};
+232                     Constructor<Plugin> pluginConstructor = pluginClass.getConstructor(classParams);
+233                     Object[] constructorParams = {element};
+234                     
+235                     plugin = pluginConstructor.newInstance(constructorParams);
+236                         
+237                 } catch (Exception e) {
+238                     LOG.error("Plugin " + identifier + " could not be loaded ", e);
+239                     continue;
+240                 } 
+241                 
+242                 plugins.put(identifier, plugin);
+243             }
+244             
+245             
+246             //
+247             // Load service handlers
+248             //
+249             itemElements = doc.getDocumentElement().getElementsByTagNameNS(XMLConstants.CONFIG_NS,
+250                             "DiscoveryServiceHandler");
+251             
+252             for (int i = 0; i < itemElements.getLength(); i++) {
+253                     
+254                 discoveryServices.add(new DiscoveryServiceHandler((Element)itemElements.item(i), 
+255                                       siteSets, 
+256                                       plugins, 
+257                                       defaultHandlerConfig));
+258     
+259             }
+260     
+261         } catch (Exception e) {
+262         //
+263         // All other exceptions are from the parsing
+264         //
+265         if (LOG != null) {
+266                 LOG.error("Error parsing DS configuration file.", e);
+267         }
+268         throw new ServletException("Error parsing DS configuration file.", e);
+269     }
+270 
+271     LOG.info("DS initialization completed.");
+272 }
+273 
+274     /**
+275      * Handle an HTTP GET.  Just passes out to the appropriate handler.
+276      * @param req described the request.
+277      * @param res contains the response.
+278      * @see HttpServlet#doGet(HttpServletRequest, HttpServletResponse)
+279      */
+280     public void doGet(HttpServletRequest req, HttpServletResponse res) {
+281             
+282         LOG.info("Handling DS request.");
+283         // Tell the browser not to cache the WAYF page
+284         res.setHeader("Cache-Control", "no-cache");
+285         res.setHeader("Pragma", "no-cache");
+286         res.setDateHeader("Expires", 0);
+287 
+288         DiscoveryServiceHandler serviceHandler = lookupServiceHandler(req); 
+289         
+290         serviceHandler.doGet(req, res);
+291            
+292     }
+293 
+294     /**
+295      * Given a request (an HTTP Get) find the apropriate DiscoveryService (from the name).
+296      * @param req desribed the request
+297      * @return the apropriate DiscoveryService.
+298      */
+299     private DiscoveryServiceHandler lookupServiceHandler(HttpServletRequest req) {
+300 
+301         Iterator<DiscoveryServiceHandler> it = discoveryServices.iterator();
+302         String requestURL = req.getRequestURL().toString(); 
+303         DiscoveryServiceHandler defaultHandler = null;
+304         
+305         while (it.hasNext()) {
+306             DiscoveryServiceHandler handler = it.next();
+307             
+308             if (requestURL.matches(handler.getLocation())) {
+309                 return handler;
+310             }
+311             if (defaultHandler == null || handler.isDefault()) {
+312                 defaultHandler = handler;
+313             }
+314         }
+315         LOG.warn("Could not find Discovery service Handler for " + requestURL);
+316         return defaultHandler;
+317     }    
+318 }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/XMLConstants.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/XMLConstants.html new file mode 100644 index 0000000..9be262d --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/XMLConstants.html @@ -0,0 +1,47 @@ + + + + +XMLConstants 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  
+17  package edu.internet2.middleware.shibboleth.wayf;
+18  
+19  /**
+20   * Holder class for various XML constants (namespaces and so forth).
+21   */
+22  public class XMLConstants {
+23  
+24      /** Shibboleth XML namespace. */
+25      public static final String SHIB_NS = "urn:mace:shibboleth:1.0";
+26  
+27      /** SSO Binding name. */
+28      public static final String IDP_SSO_BINDING = "urn:mace:shibboleth:1.0:profiles:AuthnRequest";
+29  
+30      /** Namespace for Discovery Service configuration. */
+31      public static final String CONFIG_NS = "urn:mace:shibboleth:wayf:config:1.0";
+32      
+33  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-frame.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-frame.html new file mode 100644 index 0000000..579ca32 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-frame.html @@ -0,0 +1,66 @@ + + + + + + Shibboleth Discovery Service 1.1.0 Reference Package edu.internet2.middleware.shibboleth.wayf + + + + +

+ edu.internet2.middleware.shibboleth.wayf +

+ +

Classes

+ + + + + \ No newline at end of file diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-summary.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-summary.html new file mode 100644 index 0000000..0bc1365 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/package-summary.html @@ -0,0 +1,137 @@ + + + + + + Shibboleth Discovery Service 1.1.0 Reference Package edu.internet2.middleware.shibboleth.wayf + + + +
+ +
+
+ +
+ +

Package edu.internet2.middleware.shibboleth.wayf

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Class Summary
+ Compare +
+ DiscoveryResponseBuilder +
+ DiscoveryResponseImpl +
+ DiscoveryResponseUnmarshaller +
+ DiscoveryServiceHandler +
+ HandlerConfig +
+ IdPSite +
+ IdPSiteSet +
+ IdPSiteSetEntry +
+ LogbackConfigurationChangeListener +
+ LogbackLoggingService +
+ Version +
+ WayfException +
+ WayfService +
+ XMLConstants +
+ +
+ +
+
+ +
+
+ Copyright © 2006-2009 Internet2. All Rights Reserved. + + \ No newline at end of file diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/Plugin.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/Plugin.html new file mode 100644 index 0000000..0c6391a --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/Plugin.html @@ -0,0 +1,173 @@ + + + + +Plugin xref + + + +
View Javadoc
+
+1   /**
+2    * Copyright [2006] [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.plugins;
+17  
+18  import java.util.Collection;
+19  import java.util.List;
+20  import java.util.Map;
+21  
+22  import javax.servlet.http.HttpServletRequest;
+23  import javax.servlet.http.HttpServletResponse;
+24  
+25  import org.opensaml.saml2.metadata.provider.MetadataProvider;
+26  
+27  import edu.internet2.middleware.shibboleth.wayf.IdPSite;
+28  
+29  /**
+30   * 
+31   * The Plugin interface is used to affect the 'hints' that the WAYF offers to the users.  
+32   * <p>
+33   * The WAYF can register any number of plugins.  Each plugin is called when the metadata is loaded or realoaded
+34   * (so it can do any indexing) and at the three entry points into the WAYF - Lookup (main entry), Search and Select.
+35   * Plugins are called in the order in which they are declared to the WAYF. 
+36   * <p>
+37   * Each plugin is called once when the user has made a selection.
+38   * <p>
+39   * For Search and Lookup, each plugin is called multiple times, once for each metadata provider which has 
+40   * been declared to this particular WAYF instance.  The plugin can return a context which is handed to subsequent calls.
+41   * <p>
+42   * The idea is that each plugin can affect the displayed lists of IdPs.  As a reminder the WAYF displays two lists of 
+43   * IdPs - the complete list, displayed either as a single list or a list of lists, and the hint list (which was
+44   * previously only populated from the _saml_idp cookie.  In the search case the WAYF displays a third list of
+45   * the search hits. 
+46   * <p>
+47   * When the plugin in called it is given the current set of potential IdPs as a Map from EntityID to {@link IdPSite}
+48   * and lists representing the current hint list and search results.  A Plugin can remove an entry from 
+49   * the map or the lists.  Additionally it can insert an IdPSite found in the Map into the hint or search lists.
+50   * Thus the plugin can restrict the number of sites that the WAYF instance displays in the 'complete list' and
+51   * can add or remove IdPs from the hint list.
+52   * <p>
+53   * At any stage the plugin can take control of the current request and redirect or forward it.  It signals that
+54   * it has done this to the WAYF by means of an exception.
+55   * <p> 
+56   *  The _saml_idp cookie handling code is written as a WAYF plugin.  Other plugins have been written to allow IdPs
+57   *  to be presented as hints based on the client's IP address or to redirect back to the SP once the choice of
+58   *  IdP has been made.
+59   *  <p>
+60   *  Object implementing this interface are created during WAYF discovery service initialization.  There are 
+61   *  expected to implement a constructor which takes a {@link org.w3c.dom.Element} as the only parameter and they are 
+62   *  created via this constructor, with the parameter being the appropriate section of the WAYF configuration file 
+63   *  
+64   * @version Discussion
+65   *
+66   */
+67  public interface Plugin {
+68  
+69          /**
+70           *  Whenever the WAYF discoveres that the metadata is stale, it reloads it and calls each plugin at this method.
+71           * 
+72           * @param metadata - where to get the data from.
+73           * @return the value which will be provided as input to subsequent calls to {@link #lookup Lookup} and 
+74           * {@link #search Search}
+75           */
+76          PluginMetadataParameter refreshMetadata(MetadataProvider metadata);
+77          
+78          /**
+79           * The WAYF calls each plugin at this entry point when it is first contacted.  
+80           * 
+81           * @param req - Describes the current request.  A Plugin might use it to find any appropriate cookies 
+82           * @param res - Describes the current response.  A Plugin might use it to redirect a the request. 
+83           * @param parameter Describes the metadata.
+84           * @param context Any processing context returned from a previous call.
+85           * @param validIdps The list of IdPs which is currently views as possibly matches for the pattern. 
+86           *                  The Key is the EntityId for the IdP and the value the object which describes 
+87           *                  the Idp 
+88           * @param idpList The set of Idps which are currently considered as potential hints.    
+89           * @return a context to hand to subsequent calls
+90           * @throws WayfRequestHandled if the plugin has handled the request (for instance it has
+91           * issues a redirect)
+92           *
+93           * Each plugin is called multiple times,
+94           * once for each metadata provider which is registered (Depending on the precise configuration of the WAYF
+95           * metadata providers whose metadata does not include the target may be dropped).  Initially the plugin is
+96           * called with a context parameter of <code>null</code>.  In subsequent calls, the value returned from
+97           * the previous call is passed in as the context parameter. 
+98           * 
+99           * The plugin may remove IdPSite objects from the validIdps list.
+100          * 
+101          * The plugin may add or remove them to the idpList.  IdPSite Objects which are to be added to the idpList 
+102          * should be looked up by EntityIdName in validIdps by EntityId.  Hence any metadata processing shoudl 
+103          * store the entityID. 
+104          * 
+105          */
+106         PluginContext lookup(HttpServletRequest req, 
+107                                                  HttpServletResponse res, 
+108                                                  PluginMetadataParameter parameter, 
+109                                                  Map<String, IdPSite> validIdps, 
+110                                                  PluginContext context, 
+111                                                  List<IdPSite> idpList) throws WayfRequestHandled;
+112 
+113         /**
+114          * This method is called when the user specified a search operation.  The processing is similar to 
+115          * that described for {@link #lookup lookup}.
+116          * Two additional paramaters are provided, the search parameter which was provided, and the current 
+117          * proposed list of candidate IdPs.  The plugin is at liberty to alter both the list of hints and the 
+118          * list of valid IdPs. 
+119          * 
+120          * @param req Describes the current request.  The Plugin could use it to find any appropriate cookies 
+121          * @param res Describes the result - this is needed if (for instance) a plung needs to change cookie values
+122          * @param parameter Describes the metadata
+123          * @param pattern The Search pattern provided
+124          * @param validIdps The list of IdPs which is currently views as possibly matches for the pattern.  
+125          *                  The Key is the Idp Name an the value the idp
+126          * @param context Any processing context returned from a previous call.
+127          * @param searchResult the resukt of any search
+128          * @param idpList The set of Idps which are currently considered as potential hints.  Each Idp is associated
+129          * with a numeric weight, where the lower the number is the more likely the IdP is to be a candidate.  
+130          * As descibed above the WAYF uses this to provide hint list to the GUI (or even to dispatch 
+131          * immediately to the IdP).  
+132          * @return a context to hand to subsequent calls
+133          * @throws WayfRequestHandled if the plugin has handled the request (for instance it has
+134          * issues a redirect)
+135          */
+136         PluginContext search(HttpServletRequest req, 
+137                                         HttpServletResponse res, 
+138                                         PluginMetadataParameter parameter, 
+139                                         String pattern, 
+140                                         Map<String, IdPSite> validIdps, 
+141                                         PluginContext context, 
+142                                         Collection<IdPSite> searchResult,
+143                                         List<IdPSite> idpList) throws WayfRequestHandled;
+144         
+145         /**
+146          * This method is called, for every plugin, after a user has selected an IdP.  The plugin is expected 
+147          * to use it to update any in memory state (via the {@link PluginMetadataParameter} parameter or permananent 
+148          * state (for instance by writing back a cookie.
+149          * @param req Describes the current request. 
+150          * @param res Describes the current response
+151          * @param parameter  Describes the metadata
+152          * @throws WayfRequestHandled if the plugin has handled the request (for instance it has
+153          * issues a redirect)
+154          */
+155         void selected(HttpServletRequest req, 
+156                       HttpServletResponse res, 
+157                       PluginMetadataParameter parameter, 
+158                       String idP) throws WayfRequestHandled;
+159 }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginContext.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginContext.html new file mode 100644 index 0000000..23967b7 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginContext.html @@ -0,0 +1,45 @@ + + + + +PluginContext xref + + + +
View Javadoc
+
+1   /**
+2    * Copyright [2006] [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  
+17  package edu.internet2.middleware.shibboleth.wayf.plugins;
+18  
+19  /**
+20   * This is a marker interface.
+21   * <p>
+22   * Objects which implement PluginContext are passed between sucessive calls to a plugins implementations of
+23   * {@link Plugin#lookup lookup} and {@link Plugin#search search} as the plugin 
+24   * is called for each {@link org.opensaml.saml2.metadata.provider.MetadataProvider}.
+25   * <p>
+26   * @author Rod Widdowson
+27   * @version Discussion
+28   */
+29  public interface PluginContext {
+30  
+31  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginMetadataParameter.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginMetadataParameter.html new file mode 100644 index 0000000..e07d9e0 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/PluginMetadataParameter.html @@ -0,0 +1,44 @@ + + + + +PluginMetadataParameter xref + + + +
View Javadoc
+
+1   /**
+2    * Copyright [2006] [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.plugins;
+17  
+18  
+19  /**
+20   * The PluginParameter is a marker interface which a WAYF {@link Plugin} can use to associate extra information 
+21   * with the metadata.  Each plugin returns a PluginParameter from {@link Plugin#refreshMetadata RefreshMetadata}
+22   * and this is in turn presented back to then Plugin when it is called  during WAYF processing. 
+23   * <p>
+24   * @author Rod Widdowson
+25   * @version Discussion
+26   *
+27   */
+28  public interface PluginMetadataParameter {
+29  
+30  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/WayfRequestHandled.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/WayfRequestHandled.html new file mode 100644 index 0000000..bb9d473 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/WayfRequestHandled.html @@ -0,0 +1,31 @@ + + + + +WayfRequestHandled xref + + + +
View Javadoc
+
+1   package edu.internet2.middleware.shibboleth.wayf.plugins;
+2   
+3   /**
+4    * 
+5    * This Exception can be signalled by a plugin to indicate to the WAYF that it has handled the 
+6    * request and all processing should stop.
+7    * 
+8    * @author Rod Widdowson
+9    */
+10  public class WayfRequestHandled extends Exception {
+11  
+12     /**
+13      * Required Serialization constant.
+14      */
+15      private static final long serialVersionUID = 3022489208153734092L;
+16  
+17  }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-frame.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-frame.html new file mode 100644 index 0000000..856f7b5 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-frame.html @@ -0,0 +1,33 @@ + + + + + + Shibboleth Discovery Service 1.1.0 Reference Package edu.internet2.middleware.shibboleth.wayf.plugins + + + + +

+ edu.internet2.middleware.shibboleth.wayf.plugins +

+ +

Classes

+ + + + + \ No newline at end of file diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-summary.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-summary.html new file mode 100644 index 0000000..2c26dfd --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/package-summary.html @@ -0,0 +1,82 @@ + + + + + + Shibboleth Discovery Service 1.1.0 Reference Package edu.internet2.middleware.shibboleth.wayf.plugins + + + +
+ +
+
+ +
+ +

Package edu.internet2.middleware.shibboleth.wayf.plugins

+ + + + + + + + + + + + + + + + + + + + + +
Class Summary
+ Plugin +
+ PluginContext +
+ PluginMetadataParameter +
+ WayfRequestHandled +
+ +
+ +
+
+ +
+
+ Copyright © 2006-2009 Internet2. All Rights Reserved. + + \ No newline at end of file diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/BindingFilter.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/BindingFilter.html new file mode 100644 index 0000000..9a234f3 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/BindingFilter.html @@ -0,0 +1,190 @@ + + + + +BindingFilter xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright 2008 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  
+17  package edu.internet2.middleware.shibboleth.wayf.plugins.provider;
+18  
+19  import java.util.Iterator;
+20  import java.util.List;
+21  
+22  import org.opensaml.saml2.common.Extensions;
+23  import org.opensaml.saml2.metadata.EntitiesDescriptor;
+24  import org.opensaml.saml2.metadata.EntityDescriptor;
+25  import org.opensaml.saml2.metadata.RoleDescriptor;
+26  import org.opensaml.saml2.metadata.SPSSODescriptor;
+27  import org.opensaml.saml2.metadata.provider.FilterException;
+28  import org.opensaml.saml2.metadata.provider.MetadataFilter;
+29  import org.opensaml.xml.XMLObject;
+30  import org.slf4j.Logger;
+31  import org.slf4j.LoggerFactory;
+32  
+33  import edu.internet2.middleware.shibboleth.wayf.DiscoveryResponseImpl;
+34  import edu.internet2.middleware.shibboleth.wayf.HandlerConfig;
+35  
+36  /**
+37   * See SDSJ-48.  If we get a DS endpoint then we need to check that the binding is provided
+38   * and that it is correct.
+39   * 
+40   * @author Rod Widdowson
+41   *
+42   */
+43  public class BindingFilter implements MetadataFilter {
+44  
+45      /**
+46       * Log for the warning. 
+47       */
+48      private static final Logger LOG = LoggerFactory.getLogger(BindingFilter.class.getName());
+49      
+50      /**
+51       * Set if we just want to warn on failure.
+52       */
+53      private final boolean warnOnFailure;
+54      
+55      /**
+56       * Only the protected constructor should be visible.
+57       */
+58      private BindingFilter() {
+59          this.warnOnFailure = false;
+60      }
+61      
+62      /**
+63       * Initialize the filter.
+64       * @param warn do we warn or do we fail if we see badness?
+65       */
+66      public BindingFilter(boolean warn) {
+67          this.warnOnFailure = warn;
+68      }
+69      
+70      /**
+71       * Apply the filter.
+72       * @see org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml.XMLObject)
+73       * @param metadata what to filter.
+74       * @throws FilterException if it sees any missed or bad bindings.
+75       */
+76      public void doFilter(XMLObject metadata) throws FilterException {
+77  
+78          if (metadata instanceof EntitiesDescriptor) {
+79              
+80              checkEntities((EntitiesDescriptor) metadata);
+81              
+82          } else if (metadata instanceof EntityDescriptor) {
+83              EntityDescriptor entity = (EntityDescriptor) metadata;
+84              
+85              if (!checkEntity(entity)) {
+86                  if (warnOnFailure) {
+87                      LOG.warn("Badly formatted binding for " + entity.getEntityID());
+88                  } else {
+89                      LOG.error("Badly formatted binding for top level entity " + entity.getEntityID());
+90                  }
+91              }
+92          }
+93      }
+94  
+95      /**
+96       * If the entity has an SP characteristic, and it has a DS endpoint
+97       * then check its binding.
+98       * 
+99       * @param entity what to check.
+100      * @return true if all is OK.
+101      */
+102     private static boolean checkEntity(EntityDescriptor entity) {
+103         List<RoleDescriptor> roles = entity.getRoleDescriptors();
+104         
+105         for (RoleDescriptor role:roles) {
+106             
+107             //
+108             // Check every role
+109             //
+110             if (role instanceof SPSSODescriptor) {
+111                 
+112                 //
+113                 // Grab hold of all the extensions for SPSSO descriptors
+114                 //
+115                 
+116                 Extensions exts = role.getExtensions();
+117                 if (exts != null) {
+118                     //
+119                     // We have some children check them form <DiscoveryResponse>
+120                     //
+121                     List<XMLObject> children = exts.getOrderedChildren();
+122                     
+123                     for (XMLObject obj : children) {
+124                         if (obj instanceof DiscoveryResponseImpl) {
+125                             //
+126                             // And check or the binding
+127                             //
+128                             DiscoveryResponseImpl ds = (DiscoveryResponseImpl) obj;
+129                             String binding = ds.getBinding(); 
+130 
+131                             if (!DiscoveryResponseImpl.METADATA_NS.equals(binding)) {
+132                                 return false;
+133                             }
+134                         }
+135                     }
+136                 }
+137             }
+138         }
+139         return true;
+140     }
+141     
+142     /**
+143      * Check an EntitiesDescriptor call checkentities for the Entities and ourselves
+144      *  recursively for the EntitesDescriptors.
+145      *  
+146      * @param entities what to check.
+147      */
+148     private void checkEntities(EntitiesDescriptor entities) {
+149         List<EntitiesDescriptor> childEntities = entities.getEntitiesDescriptors();
+150         List<EntityDescriptor> children = entities.getEntityDescriptors();
+151         
+152         if (children != null) {
+153             Iterator<EntityDescriptor> itr;
+154             EntityDescriptor entity;
+155             itr = children.iterator();
+156             
+157             while (itr.hasNext()) {
+158                 entity = itr.next();
+159                 if (!checkEntity(entity)) { 
+160                     if (warnOnFailure) {
+161                         LOG.warn("Badly formatted binding for " + entity.getEntityID());
+162                     } else {
+163                         LOG.error("Badly formatted binding for " + entity.getEntityID() + ". Entity has been removed");
+164                         itr.remove();
+165                     }
+166                 }
+167             }
+168         }
+169         
+170         if (childEntities != null) {
+171             for (EntitiesDescriptor descriptor : childEntities) {
+172                 checkEntities(descriptor);
+173             }
+174         }
+175     }
+176 }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/ListFilter.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/ListFilter.html new file mode 100644 index 0000000..270ec3e --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/ListFilter.html @@ -0,0 +1,198 @@ + + + + +ListFilter xref + + + +
View Javadoc
+
+1   /*
+2    * Copyright 2008 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  
+17  package edu.internet2.middleware.shibboleth.wayf.plugins.provider;
+18  
+19  import java.util.HashSet;
+20  import java.util.Iterator;
+21  import java.util.List;
+22  import java.util.Set;
+23  
+24  import org.opensaml.saml2.metadata.EntitiesDescriptor;
+25  import org.opensaml.saml2.metadata.EntityDescriptor;
+26  import org.opensaml.saml2.metadata.provider.FilterException;
+27  import org.opensaml.saml2.metadata.provider.MetadataFilter;
+28  import org.opensaml.xml.XMLObject;
+29  import org.slf4j.Logger;
+30  import org.slf4j.LoggerFactory;
+31  import org.w3c.dom.Element;
+32  import org.w3c.dom.NodeList;
+33  
+34  import edu.internet2.middleware.shibboleth.wayf.HandlerConfig;
+35  import edu.internet2.middleware.shibboleth.wayf.XMLConstants;
+36  
+37  /**
+38   * See SDSJ-57.  Explicit 
+39   * 
+40   * @author Rod Widdowson
+41   *
+42   */
+43  public class ListFilter implements MetadataFilter {
+44  
+45      /**
+46       * Log for any messages.
+47       */
+48      private static final Logger LOG = LoggerFactory.getLogger(ListFilter.class.getName());
+49      
+50      /**
+51       * Set if this is a blacklist.
+52       */
+53      private boolean excludeEntries;
+54      
+55      /**
+56       * The list of entities.
+57       */
+58      private final Set<String> filterEntities;
+59      
+60      /**
+61       * The name of the filter (needed for debug).
+62       */
+63      private final String filterName;
+64      
+65      /**
+66       * Only the protected constructor should be visible.
+67       */
+68      private ListFilter() {
+69          this.excludeEntries = false;
+70          this.filterEntities = new HashSet<String>(0);
+71          this.filterName = "anonymous";
+72      }
+73      
+74      /**
+75       * Initialize the filter.
+76       * @param config the configuration
+77       *
+78       * The configuration looks liken this
+79       * <code> <Filter identifier="WhiteList" 
+80       *                type ="edu.internet2.middleware.shibboleth.wayf.plugins.provider.ListFilter"
+81       *                excludeEntries = "true" >
+82       *        <EntityId>foo</EntityId>
+83       *        [...]
+84       *        </Filter>
+85       *  </code>
+86       */
+87      public ListFilter(Element config) {
+88          String excludeEntriesValue;
+89          this.filterEntities = new HashSet<String>(10);
+90          this.filterName = config.getAttribute("identifier");
+91          excludeEntriesValue = config.getAttribute("excludeEntries");
+92          
+93          if (null == excludeEntriesValue || 0 == excludeEntriesValue.length()) {
+94              this.excludeEntries = true;
+95          } else {
+96              this.excludeEntries = Boolean.getBoolean(excludeEntriesValue);
+97          }
+98          
+99          NodeList itemElements = config.getElementsByTagNameNS(XMLConstants.CONFIG_NS, "EntityId");
+100         
+101         if (excludeEntries) {
+102             LOG.debug("Populating blacklist " + filterName);
+103         } else {
+104             LOG.debug("Populating whitelist " + filterName);
+105         }  
+106         
+107         for (int i = 0; i < itemElements.getLength(); i++) {
+108             Element element = (Element) itemElements.item(i);
+109             String entityId = element.getTextContent();
+110             
+111             LOG.debug("\t" + entityId);
+112             this.filterEntities.add(entityId);
+113         }
+114     }
+115     
+116     /**
+117      * Apply the filter.
+118      * @see org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml.XMLObject)
+119      * @param metadata what to filter.
+120      * @throws FilterException if it sees any missed or bad bindings.
+121      */
+122     public void doFilter(XMLObject metadata) throws FilterException {
+123 
+124         if (metadata instanceof EntitiesDescriptor) { 
+125             filterEntities((EntitiesDescriptor)metadata);
+126         } else if (metadata instanceof EntityDescriptor) {
+127             EntityDescriptor entity = (EntityDescriptor) metadata;
+128             String entityName = entity.getEntityID();
+129             
+130             if (excludeEntries) {
+131                 if (filterEntities.contains(entityName)) {
+132                     LOG.error("Metadata provider contains a single <EntityDescriptor> (" + entityName + 
+133                               ") which is in exclude list");
+134                 }
+135             } else if (!filterEntities.contains(entity.getEntityID())) {
+136                 LOG.error("Metadata provider contains a single <EntityDescriptor>  (" + entityName + 
+137                           ") which is not on include list");
+138             }
+139         }
+140     }
+141 
+142     /**
+143      * Filter an EntitiesDescriptor .  We do this explictly for the Entities and call ourselves
+144      *  recursively for the EntitesDescriptors.
+145      *  
+146      * @param entities what to check.
+147      */
+148     private void filterEntities(EntitiesDescriptor entities) {
+149         String entitiesName = entities.getName();
+150         List<EntitiesDescriptor> childEntities = entities.getEntitiesDescriptors();
+151         List<EntityDescriptor> children = entities.getEntityDescriptors();
+152         
+153         //
+154         // Go through and apply the filter
+155         //
+156 
+157         if (children != null) {
+158             Iterator<EntityDescriptor> itr;
+159             EntityDescriptor entity;
+160             itr = children.iterator();
+161             
+162             while (itr.hasNext()) {
+163                 entity = itr.next();
+164                 String entityName = entity.getEntityID();
+165                 if (excludeEntries) {
+166 
+167                     if (filterEntities.contains(entityName)) {
+168                         LOG.debug("Filter " + filterName + ": Removing blacklisted "  + entityName + " from " + entitiesName);
+169                         itr.remove();
+170                     }
+171                 } else if (!filterEntities.contains(entityName)) {
+172                     LOG.debug("Filter " + filterName + ": Removing non-whitelisted "  + entityName + " from " + entitiesName);
+173                     itr.remove();
+174                 }
+175             } 
+176         }
+177         
+178         if (childEntities != null) {
+179             for (EntitiesDescriptor descriptor : childEntities) {
+180                 filterEntities(descriptor);
+181             }
+182         }
+183     }
+184 }
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/SamlCookiePlugin.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/SamlCookiePlugin.html new file mode 100644 index 0000000..9e6528e --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/SamlCookiePlugin.html @@ -0,0 +1,558 @@ + + + + +SamlCookiePlugin xref + + + +
View Javadoc
+
+1   package edu.internet2.middleware.shibboleth.wayf.plugins.provider;
+2   
+3   import java.io.UnsupportedEncodingException;
+4   import java.net.URLDecoder;
+5   import java.net.URLEncoder;
+6   import java.util.ArrayList;
+7   import java.util.Collection;
+8   import java.util.Iterator;
+9   import java.util.List;
+10  import java.util.Map;
+11  
+12  import javax.servlet.http.Cookie;
+13  import javax.servlet.http.HttpServletRequest;
+14  import javax.servlet.http.HttpServletResponse;
+15  
+16  import org.apache.log4j.Logger;
+17  import org.opensaml.saml2.metadata.provider.MetadataProvider;
+18  import org.opensaml.xml.util.Base64;
+19  import org.w3c.dom.Element;
+20  
+21  import edu.internet2.middleware.shibboleth.wayf.DiscoveryServiceHandler;
+22  import edu.internet2.middleware.shibboleth.wayf.IdPSite;
+23  import edu.internet2.middleware.shibboleth.wayf.WayfException;
+24  import edu.internet2.middleware.shibboleth.wayf.plugins.Plugin;
+25  import edu.internet2.middleware.shibboleth.wayf.plugins.PluginContext;
+26  import edu.internet2.middleware.shibboleth.wayf.plugins.PluginMetadataParameter;
+27  import edu.internet2.middleware.shibboleth.wayf.plugins.WayfRequestHandled;
+28  
+29  /**
+30   * This is a test implementation of the saml cookie lookup stuff to 
+31   * see whether it fits the plugin architecture.
+32   * 
+33   * @author Rod Widdowson
+34   *
+35   */
+36  public class SamlCookiePlugin implements Plugin {
+37          
+38      /**
+39       * The parameter which controls the cache.
+40       */
+41      private static final String PARAMETER_NAME = "cache";
+42  
+43      /**
+44       * Parameter to say make it last a long time.
+45       */
+46      private static final String PARAMETER_PERM = "perm";
+47  
+48      /**
+49       * Parameter to say just keep this as long as the brower is open.
+50       */
+51      private static final String PARAMETER_SESSION = "session";
+52      
+53      /**
+54       * Handle for logging. 
+55       */
+56      private static Logger log = Logger.getLogger(SamlCookiePlugin.class.getName());
+57  
+58      /**
+59       * As specified in the SAML2 profiles specification.
+60       */
+61      private static final String COOKIE_NAME = "_saml_idp";
+62  
+63      /**
+64       * By default we keep the cookie around for a week.
+65       */
+66      private static final int DEFAULT_CACHE_EXPIRATION = 6048000;
+67      
+68      /**
+69       * Do we always go where the cookie tells us, or do we just provide the cookie as a hint.
+70       */
+71      private boolean alwaysFollow;
+72  
+73      /**
+74       * Is our job to clean up the cookie. 
+75       */
+76      private boolean deleteCookie;
+77      
+78      /**
+79       * Lipservice towards having a common domain cookie. 
+80       */
+81      private String cacheDomain; 
+82      
+83      /**
+84       * How long the cookie our will be active? 
+85       */
+86      private int cacheExpiration;
+87      
+88      /**
+89       * This constructor is called during wayf initialization with it's
+90       * own little bit of XML config.
+91       * 
+92       * @param element - further information to be gleaned from the DOM.
+93       */
+94      public SamlCookiePlugin(Element element) {
+95          /*
+96           * <Plugin idenfifier="WayfCookiePlugin" 
+97           *         type="edu.internet2.middleware.shibboleth.wayf.plugins.provider.SamlCookiePlugin"
+98           *         alwaysFollow = "FALSE"
+99           *         deleteCookie = "FALSE"
+100          *         cacheExpiration = "number" 
+101          *         cacheDomain = "string"/> 
+102          */
+103         log.info("New plugin");
+104         String s;
+105 
+106         s = element.getAttribute("alwaysFollow");
+107         if (s != null && !s.equals("") ) {
+108             alwaysFollow = Boolean.valueOf(s).booleanValue();
+109         } else {
+110             alwaysFollow = true;
+111         }
+112             
+113         s = element.getAttribute("deleteCookie");
+114         if (s != null && !s.equals("")) {
+115             deleteCookie = Boolean.valueOf(s).booleanValue();
+116         } else {
+117             deleteCookie = false;
+118         }
+119             
+120         s = element.getAttribute("cacheDomain");
+121         if ((s != null) && !s.equals("")) {
+122             cacheDomain = s;
+123         } else {
+124             cacheDomain = "";
+125         }
+126         
+127         s  = element.getAttribute("cacheExpiration");
+128         if ((s != null) && !s.equals("")) {
+129             
+130             try {
+131 
+132                 cacheExpiration = Integer.parseInt(s);
+133             } catch (NumberFormatException ex) {
+134                     
+135                 log.error("Invalid CacheExpiration value - " + s);
+136                 cacheExpiration = DEFAULT_CACHE_EXPIRATION;                       
+137             }
+138         } else {
+139             cacheExpiration = DEFAULT_CACHE_EXPIRATION;
+140         }
+141     }
+142     
+143     /**
+144      * Create a plugin with the hard-wired default settings.
+145      */
+146     private SamlCookiePlugin() {
+147         alwaysFollow = false;
+148         deleteCookie = false;
+149         cacheExpiration = DEFAULT_CACHE_EXPIRATION;
+150     }
+151 
+152     /**
+153      * This is the 'hook' in the lookup part of Discovery Service processing. 
+154      * 
+155      * @param req - Describes the current request.  Used to find any appropriate cookies 
+156      * @param res - Describes the current response.  Used to redirect the request. 
+157      * @param parameter - Describes the metadata.
+158      * @param context - Any processing context returned from a previous call. We set this on first call and
+159      *                  use non null to indicate that we don't go there again.
+160      * @param validIdps The list of IdPs which is currently views as possibly matches for the pattern. 
+161      *                  The Key is the EntityId for the IdP and the value the object which describes 
+162      *                  the Idp 
+163      * @param idpList The set of Idps which are currently considered as potential hints.    
+164      * @return a context to hand to subsequent calls
+165      * @throws WayfRequestHandled if the plugin has handled the request.
+166      * issues a redirect)
+167      * 
+168      * @see edu.internet2.middleware.shibboleth.wayf.plugins.Plugin#lookup
+169      */
+170     public PluginContext lookup(HttpServletRequest req,
+171                                 HttpServletResponse res,  
+172                                 PluginMetadataParameter parameter, 
+173                                 Map<String, IdPSite> validIdps,
+174                                 PluginContext context,
+175                                 List <IdPSite> idpList) throws WayfRequestHandled {
+176             
+177         if (context != null) {
+178             //
+179             // We only need to be called once
+180             //
+181             return context;
+182         }
+183             
+184         if (deleteCookie) {
+185             deleteCookie(req, res);
+186             //
+187             // Only need to be called once - so set up a parameter
+188             //
+189             return new Context() ;
+190         } 
+191         List <String> idps = getIdPCookie(req, res, cacheDomain).getIdPList();
+192             
+193         for (String idpName : idps) {
+194             IdPSite idp = validIdps.get(idpName);
+195             if (idp != null) {
+196                 if (alwaysFollow) {
+197                     try {
+198                         DiscoveryServiceHandler.forwardRequest(req, res, idp);
+199                     } catch (WayfException e) {
+200                         // Do nothing we are going to throw anyway
+201                         ;
+202                     }
+203                     throw new WayfRequestHandled();
+204                 }
+205                 //
+206                 // This IDP is ok 
+207                 //
+208                 idpList.add(idp);
+209             }
+210         } 
+211             
+212         return null;
+213     }
+214 
+215     /**
+216      * Plugin point which is called when the data is refreshed.
+217      * @param metadata - where to get the data from.
+218      * @return the value which will be provided as input to subsequent calls
+219      * @see edu.internet2.middleware.shibboleth.wayf.plugins.Plugin#refreshMetadata
+220      */
+221     public PluginMetadataParameter refreshMetadata(MetadataProvider metadata) {
+222         //
+223         // We don't care about metadata - we are given all that we need
+224         //
+225         return null;
+226     }
+227 
+228     /**
+229      * Plgin point for searching.
+230      * 
+231      * @throws WayfRequestHandled 
+232      * @param req Describes the current request. 
+233      * @param res Describes the current response.
+234      * @param parameter Describes the metadata.
+235      * @param pattern What we are searchign for. 
+236      * @param validIdps The list of IdPs which is currently views as possibly matches for the pattern. 
+237      *                  The Key is the EntityId for the IdP and the value the object which describes 
+238      *                  the Idp 
+239      * @param context Any processing context returned from a previous call. We set this on first call and
+240      *                use non null to indicate that we don't go there again.
+241      * @param searchResult What the search yielded. 
+242      * @param idpList The set of Idps which are currently considered as potential hints.    
+243      * @return a context to hand to subsequent calls.
+244      * @see edu.internet2.middleware.shibboleth.wayf.plugins.Plugin#search
+245      * @throws WayfRequestHandled if the plugin has handled the request.
+246      * 
+247      */
+248     public PluginContext search(HttpServletRequest req,
+249                                 HttpServletResponse res, 
+250                                 PluginMetadataParameter parameter, 
+251                                 String pattern,
+252                                 Map<String, IdPSite> validIdps,
+253                                 PluginContext context,
+254                                 Collection<IdPSite> searchResult,
+255                                 List<IdPSite> idpList) throws WayfRequestHandled {
+256         //
+257         // Don't distinguish between lookup and search
+258         //
+259         return lookup(req, res, parameter, validIdps, context, idpList);
+260     }
+261 
+262     /**
+263      * Plugin point for selection.
+264      * 
+265      * @see edu.internet2.middleware.shibboleth.wayf.plugins.Plugin#selected(javax.servlet.http.HttpServletRequest.
+266      *  javax.servlet.http.HttpServletResponse, 
+267      *  edu.internet2.middleware.shibboleth.wayf.plugins.PluginMetadataParameter, 
+268      *  java.lang.String)
+269      * @param req Describes the current request. 
+270      * @param res Describes the current response.
+271      * @param parameter Describes the metadata.
+272      * @param idP Describes the idp.
+273      * 
+274      */
+275     public void selected(HttpServletRequest req, HttpServletResponse res,
+276                          PluginMetadataParameter parameter, String idP) {
+277             
+278         SamlIdPCookie cookie = getIdPCookie(req, res, cacheDomain);
+279         String param = req.getParameter(PARAMETER_NAME);
+280         
+281         if (null == param || param.equals("")) {
+282             return;
+283         } else if (param.equalsIgnoreCase(PARAMETER_SESSION)) {
+284             cookie.addIdPName(idP, -1);
+285         } else if (param.equalsIgnoreCase(PARAMETER_PERM)) {
+286             cookie.addIdPName(idP, cacheExpiration);
+287         }
+288     }
+289     
+290     //
+291     // Private classes for internal use
+292     //
+293     
+294     /**
+295      * This is just a marker tag.
+296      */
+297     private static class Context implements PluginContext {}
+298     
+299     /** 
+300      * Class to abstract away the saml cookie for us.
+301      */
+302     public final class SamlIdPCookie  {
+303 
+304             
+305         /**
+306          * The associated request.
+307          */
+308         private final HttpServletRequest req;
+309         /**
+310          * The associated response.
+311          */
+312         private final HttpServletResponse res;
+313         /**
+314          * The associated domain.
+315          */
+316         private final String domain;
+317         /**
+318          * The IdPs.
+319          */
+320         private final List <String> idPList = new ArrayList<String>();
+321             
+322         /**
+323          * Constructs a <code>SamlIdPCookie</code> from the provided string (which is the raw data. 
+324          * 
+325          * @param codedData
+326          *            the information read from the cookie
+327          * @param request Describes the current request. 
+328          * @param response Describes the current response.
+329          * @param domainName - if non null the domain for any *created* cookie.
+330          */
+331         private SamlIdPCookie(String codedData, 
+332                               HttpServletRequest request, 
+333                               HttpServletResponse response, 
+334                               String domainName) {
+335                     
+336             this.req = request;
+337             this.res = response;
+338             this.domain = domainName;
+339                     
+340             int start;
+341             int end;
+342                     
+343             if (codedData == null || codedData.equals(""))  {
+344                 log.info("Empty cookie");
+345                 return;
+346             }
+347             //
+348             // An earlier version saved the cookie without URL encoding it, hence there may be 
+349             // spaces which in turn means we may be quoted.  Strip any quotes.
+350             //
+351             if (codedData.charAt(0) == '"' && codedData.charAt(codedData.length()-1) == '"') {
+352                 codedData = codedData.substring(1,codedData.length()-1);
+353             }
+354                     
+355             try {
+356                 codedData = URLDecoder.decode(codedData, "UTF-8");
+357             } catch (UnsupportedEncodingException e) {
+358                 log.error("could not decode cookie");
+359                 return;
+360             }
+361                     
+362             start = 0;
+363             end = codedData.indexOf(' ', start);
+364             while (end > 0) {
+365                 String value = codedData.substring(start, end);
+366                 start = end + 1;
+367                 end = codedData.indexOf(' ', start);
+368                 if (!value.equals("")) {
+369                     idPList.add(new String(Base64.decode(value)));
+370                 }
+371             }
+372             if (start < codedData.length()) {
+373                 String value = codedData.substring(start);
+374                 if (!value.equals("")) {
+375                     idPList.add(new String(Base64.decode(value)));
+376                 }
+377             }
+378         }
+379         /**
+380          * Create a SamlCookie with no data inside.
+381          * @param domainName - if non null, the domain of the new cookie 
+382          * @param request Describes the current request. 
+383          * @param response Describes the current response.
+384          *
+385          */
+386         private SamlIdPCookie(HttpServletRequest request, HttpServletResponse response, String domainName) {
+387             this.req = request;
+388             this.res = response;
+389             this.domain = domainName;
+390         }
+391 
+392         /**
+393          * Add the specified Shibboleth IdP Name to the cookie list or move to 
+394          * the front and then write it back.
+395          * 
+396          * We always add to the front (and remove from wherever it was)
+397          * 
+398          * @param idPName    - The name to be added
+399          * @param expiration - The expiration of the cookie or zero if it is to be unchanged
+400          */
+401         private void addIdPName(String idPName, int expiration) {
+402 
+403             idPList.remove(idPName);
+404             idPList.add(0, idPName);
+405 
+406             writeCookie(expiration);
+407         }
+408             
+409         /**
+410          * Delete the <b>entire<\b> cookie contents
+411          */
+412 
+413 
+414         /**
+415          * Remove origin from the cachedata and write it back.
+416          * 
+417          * @param origin what to remove.
+418          * @param expiration How long it will live.
+419          */
+420             
+421         public void deleteIdPName(String origin, int expiration) {
+422             idPList.remove(origin);
+423             writeCookie(expiration);
+424         }
+425 
+426         /**
+427          * Write back the cookie.
+428          * 
+429          * @param expiration How long it will live
+430          */
+431         private void writeCookie(int expiration) {
+432             Cookie cookie = getCookie(req);
+433                     
+434             if (idPList.size() == 0) {
+435                 //
+436                 // Nothing to write, so delete the cookie
+437                 //
+438                 cookie.setPath("/");
+439                 cookie.setMaxAge(0);
+440                 res.addCookie(cookie);
+441                 return;
+442             }
+443 
+444             //
+445             // Otherwise encode up the cookie
+446             //
+447             StringBuffer buffer = new StringBuffer();
+448             Iterator <String> it = idPList.iterator();
+449                     
+450             while (it.hasNext()) {
+451                 String next = it.next();
+452                 String what = new String(Base64.encodeBytes(next.getBytes()));
+453                 buffer.append(what).append(' ');
+454             }
+455                     
+456             String value;
+457             try {
+458                 value = URLEncoder.encode(buffer.toString(), "UTF-8");
+459             } catch (UnsupportedEncodingException e) {
+460                 log.error("Could not encode cookie");
+461                 return;
+462             }
+463                     
+464             if (cookie == null) { 
+465                 cookie = new Cookie(COOKIE_NAME, value);
+466             } else {
+467                 cookie.setValue(value);
+468             }
+469             cookie.setComment("Used to cache selection of a user's Shibboleth IdP");
+470             cookie.setPath("/");
+471 
+472 
+473             cookie.setMaxAge(expiration);
+474                     
+475             if (domain != null && domain != "") {
+476                 cookie.setDomain(domain);
+477             }
+478             res.addCookie(cookie);
+479             
+480         }
+481     
+482         /**
+483          * Return the list of Idps for this cookie.
+484          * @return The list.
+485          */
+486         public List <String> getIdPList() {
+487             return idPList;
+488         }
+489     }
+490 
+491     /**
+492      * Extract the cookie from a request.
+493      * @param req the request.
+494      * @return the cookie.
+495      */
+496     private static Cookie getCookie(HttpServletRequest req) {
+497             
+498         Cookie[] cookies = req.getCookies();
+499         if (cookies != null) {
+500             for (int i = 0; i < cookies.length; i++) {
+501                 if (cookies[i].getName().equals(COOKIE_NAME)) { 
+502                     return cookies[i];
+503                 }
+504             }
+505         }
+506         return null;
+507     }
+508 
+509     /**
+510      * Delete the cookie from the response.
+511      * @param req The request.
+512      * @param res The response.
+513      */
+514     private static void deleteCookie(HttpServletRequest req, HttpServletResponse res) {
+515         Cookie cookie = getCookie(req);
+516             
+517         if (cookie == null) { 
+518             return; 
+519         }
+520             
+521         cookie.setPath("/");
+522         cookie.setMaxAge(0);
+523         res.addCookie(cookie);
+524     }
+525     /**
+526      * Load up the cookie and convert it into a SamlIdPCookie.  If there is no
+527      * underlying cookie return a null one.
+528      * @param req The request.
+529      * @param res The response.
+530      * @param domain - if this is set then any <b>created</b> cookies are set to this domain
+531      * @return the new object. 
+532      */
+533     
+534     private SamlIdPCookie getIdPCookie(HttpServletRequest req, HttpServletResponse res, String domain) {
+535         Cookie cookie = getCookie(req);
+536             
+537         if (cookie == null) {
+538             return new SamlIdPCookie(req, res, domain);
+539         } else {
+540             return new SamlIdPCookie(cookie.getValue(), req, res, domain);
+541         }
+542     }
+543 }
+544 
+
+
+ + diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-frame.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-frame.html new file mode 100644 index 0000000..5eb51b5 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-frame.html @@ -0,0 +1,36 @@ + + + + + + Shibboleth Discovery Service 1.1.0 Reference Package edu.internet2.middleware.shibboleth.wayf.plugins.provider + + + + +

+ edu.internet2.middleware.shibboleth.wayf.plugins.provider +

+ +

Classes

+ + + + + \ No newline at end of file diff --git a/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-summary.html b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-summary.html new file mode 100644 index 0000000..2f91e22 --- /dev/null +++ b/doc/src-xref/edu/internet2/middleware/shibboleth/wayf/plugins/provider/package-summary.html @@ -0,0 +1,87 @@ + + + + + + Shibboleth Discovery Service 1.1.0 Reference Package edu.internet2.middleware.shibboleth.wayf.plugins.provider + + + +
+ +
+
+ +
+ +

Package edu.internet2.middleware.shibboleth.wayf.plugins.provider

+ + + + + + + + + + + + + + + + + + + + + + + + +
Class Summary
+ BindingFilter +
+ Context +
+ ListFilter +
+ SamlCookiePlugin +
+ SamlIdPCookie +
+ +
+ +
+
+ +
+
+ Copyright © 2006-2009 Internet2. All Rights Reserved. + + \ No newline at end of file -- cgit v1.1