The HS now validates providerId -> authN consumer URL unions against federation metadata.
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 26 Mar 2004 07:30:24 +0000 (07:30 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 26 Mar 2004 07:30:24 +0000 (07:30 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@937 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/edu/internet2/middleware/shibboleth/common/TargetFederationComponent.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/hs/HandleServlet.java
src/edu/internet2/middleware/shibboleth/log/LoggingContextListener.java
src/edu/internet2/middleware/shibboleth/metadata/provider/XMLMetadataLoadWrapper.java

diff --git a/src/edu/internet2/middleware/shibboleth/common/TargetFederationComponent.java b/src/edu/internet2/middleware/shibboleth/common/TargetFederationComponent.java
new file mode 100644 (file)
index 0000000..48d9096
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.common;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.servlet.http.HttpServlet;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+
+import edu.internet2.middleware.shibboleth.metadata.Metadata;
+import edu.internet2.middleware.shibboleth.metadata.MetadataException;
+import edu.internet2.middleware.shibboleth.metadata.Provider;
+
+/**
+ * @author Walter Hoehn (wassa@columbia.edu)
+ */
+public class TargetFederationComponent extends HttpServlet implements Metadata {
+
+       private static Logger   log                     = Logger.getLogger(TargetFederationComponent.class.getName());
+
+       private ArrayList               fedMetadata     = new ArrayList();
+
+       protected void addFederationProvider(Element element) {
+               log.debug("Found Federation Provider configuration element.");
+               if (!element.getTagName().equals("FederationProvider")) {
+                       log.error("Error while attemtping to load Federation Provider.  Malformed provider specificaion.");
+                       return;
+               }
+
+               try {
+                       fedMetadata.add(FederationProviderFactory.loadProvider(element));
+               } catch (MetadataException e) {
+                       log.error("Unable to load Federation Provider.  Skipping...");
+               }
+       }
+
+       protected int providerCount() {
+               return fedMetadata.size();
+       }
+
+       public Provider lookup(String providerId) {
+
+               Iterator iterator = fedMetadata.iterator();
+               while (iterator.hasNext()) {
+                       Provider provider = ((Metadata) iterator.next()).lookup(providerId);
+                       if (provider != null) {
+                               return provider;
+                       }
+               }
+               return null;
+       }
+}
+
+class FederationProviderFactory {
+
+       private static Logger   log     = Logger.getLogger(FederationProviderFactory.class.getName());
+
+       public static Metadata loadProvider(Element e) throws MetadataException {
+
+               String className = e.getAttribute("type");
+               if (className == null || className.equals("")) {
+                       log.error("Federation Provider requires specification of the attribute \"type\".");
+                       throw new MetadataException("Failed to initialize Federation Provider.");
+               } else {
+                       try {
+                               Class[] params = {Class.forName("org.w3c.dom.Element"),};
+                               return (Metadata) Class.forName(className).getConstructor(params).newInstance(new Object[]{e});
+                       } catch (Exception loaderException) {
+                               log.error("Failed to load Federation Provider implementation class: " + loaderException);
+                               if (loaderException instanceof InvocationTargetException) {
+                                       log.error("Root cause: " + ((InvocationTargetException)loaderException).getTargetException());
+                               }
+                               throw new MetadataException("Failed to initialize Federation Provider.");
+                       }
+               }
+       }
+}
index 888295b..00f242f 100644 (file)
@@ -33,7 +33,6 @@ import java.util.Date;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
 import javax.servlet.UnavailableException;
-import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -52,16 +51,26 @@ import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
 import sun.misc.BASE64Decoder;
+
+import com.sun.corba.se.internal.core.EndPoint;
+
 import edu.internet2.middleware.shibboleth.common.AuthNPrincipal;
 import edu.internet2.middleware.shibboleth.common.Credentials;
 import edu.internet2.middleware.shibboleth.common.NameIdentifierMapping;
 import edu.internet2.middleware.shibboleth.common.NameIdentifierMappingException;
 import edu.internet2.middleware.shibboleth.common.OriginConfig;
+import edu.internet2.middleware.shibboleth.common.RelyingParty;
 import edu.internet2.middleware.shibboleth.common.ServiceProviderMapperException;
 import edu.internet2.middleware.shibboleth.common.ShibPOSTProfile;
 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
+import edu.internet2.middleware.shibboleth.common.ShibbolethOriginConfig;
+import edu.internet2.middleware.shibboleth.common.TargetFederationComponent;
+import edu.internet2.middleware.shibboleth.metadata.Endpoint;
+import edu.internet2.middleware.shibboleth.metadata.Provider;
+import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.SPProviderRole;
 
-public class HandleServlet extends HttpServlet {
+public class HandleServlet extends TargetFederationComponent {
 
        private static Logger                   log                             = Logger.getLogger(HandleServlet.class.getName());
        private static Logger                   transactionLog  = Logger.getLogger("Shibboleth-TRANSACTION");
@@ -116,6 +125,16 @@ public class HandleServlet extends HttpServlet {
                        throw new ShibbolethConfigurationException("Could not load origin configuration.");
                }
 
+               //Load metadata
+               itemElements = originConfig.getDocumentElement().getElementsByTagNameNS(
+                               ShibbolethOriginConfig.originConfigNamespace, "FederationProvider");
+               for (int i = 0; i < itemElements.getLength(); i++) {
+                       addFederationProvider((Element) itemElements.item(i));
+               }
+               if (providerCount() < 1) {
+                       log.error("No Federation Provider metadata loaded.");
+                       throw new ShibbolethConfigurationException("Could not load federation metadata.");
+               }
        }
 
        public void init() throws ServletException {
@@ -153,10 +172,23 @@ public class HandleServlet extends HttpServlet {
 
                        HSRelyingParty relyingParty = targetMapper.getRelyingParty(req.getParameter("providerId"));
 
+                       //Get the authN info
                        String username = configuration.getAuthHeaderName().equalsIgnoreCase("REMOTE_USER")
                                        ? req.getRemoteUser()
                                        : req.getHeader(configuration.getAuthHeaderName());
 
+                       //Make sure that the selected relying party configuration is appropriate for this
+                       //acceptance URL
+                       if (!relyingParty.isLegacyProvider()) {
+                               if (isValidAssertionConsumerURL(relyingParty, req.getParameter("shire"))) {
+                                       log.info("Supplied consumer URL validated for this provider.");
+                               } else {
+                                       log.error("Supplied assertion consumer service URL (" + req.getParameter("shire")
+                                                       + ") is NOT valid for provider (" + relyingParty.getProviderId() + ").");
+                                       throw new InvalidClientDataException("Invalid assertion consumer service URL.");
+                               }
+                       }
+
                        SAMLNameIdentifier nameId = nameMapper.getNameIdentifierName(relyingParty.getHSNameFormatId(),
                                        new AuthNPrincipal(username), relyingParty, relyingParty.getIdentityProvider());
 
@@ -175,9 +207,9 @@ public class HandleServlet extends HttpServlet {
                        createForm(req, res, buf);
 
                        if (relyingParty.isLegacyProvider()) {
-                               transactionLog.info("Authentication assertion issued to legacy provider (SHIRE: " + req.getParameter("shire")
-                                               + ") on behalf of principal (" + username
-                                               + ") for resource (" + req.getParameter("target") + "). Name Identifier: (" + nameId.getName()
+                               transactionLog.info("Authentication assertion issued to legacy provider (SHIRE: "
+                                               + req.getParameter("shire") + ") on behalf of principal (" + username + ") for resource ("
+                                               + req.getParameter("target") + "). Name Identifier: (" + nameId.getName()
                                                + "). Name Identifier Format: (" + nameId.getFormat() + ").");
                        } else {
                                transactionLog.info("Authentication assertion issued to provider (" + req.getParameter("providerId")
@@ -268,6 +300,35 @@ public class HandleServlet extends HttpServlet {
                }
        }
 
+       protected boolean isValidAssertionConsumerURL(RelyingParty relyingParty, String shireURL)
+                       throws InvalidClientDataException {
+
+               Provider provider = lookup(relyingParty.getProviderId());
+               if (provider == null) {
+                       log.info("No metadata found for provider: (" + relyingParty.getProviderId() + ").");
+                       throw new InvalidClientDataException("Request if from an unkown Service Provider.");
+               }
+
+               ProviderRole[] roles = provider.getRoles();
+               if (roles.length == 0) {
+                       log.info("Inappropriate metadata for provider.");
+                       return false;
+               }
+
+               for (int i = 0; roles.length > i; i++) {
+                       if (roles[i] instanceof SPProviderRole) {
+                               Endpoint[] endpoints = ((SPProviderRole) roles[i]).getAssertionConsumerServiceURLs();
+                               for (int j = 0; endpoints.length > j; j++) {
+                                       if (shireURL.equals(endpoints[j].getLocation())) {
+                                               return true;
+                                       }
+                               }
+                       }
+               }
+               log.info("Supplied consumer URL not found in metadata.");
+               return false;
+       }
+
        class InvalidClientDataException extends Exception {
 
                public InvalidClientDataException(String message) {
index b0d9e73..e2db7b5 100644 (file)
@@ -75,7 +75,7 @@ public class LoggingContextListener implements ServletContextListener {
 
                // rootAppender.setLayout(new PatternLayout("%-5p %-41X{serviceId} %d{ISO8601} (%c:%L) - %m%n"));
                // Logger.getRootLogger().setLevel((Level) Level.DEBUG);
-               Logger.getRootLogger().setLevel((Level) Level.INFO);
+               Logger.getRootLogger().setLevel((Level) Level.DEBUG);
                rootAppender.setLayout(new PatternLayout("%d{ISO8601} %-5p %-41X{serviceId} - %m%n"));
 
                try {
@@ -128,7 +128,7 @@ public class LoggingContextListener implements ServletContextListener {
                        configureErrorLog(errorLogNode);
                } else {
                        // started out at INFO for logging config messages
-                       Logger.getRootLogger().setLevel((Level) Level.WARN);
+                       Logger.getRootLogger().setLevel((Level) Level.DEBUG);
                }
 
                // turn these off by default
index f73e6e9..0e5a9e4 100644 (file)
@@ -32,6 +32,7 @@ import java.util.StringTokenizer;
 
 import org.apache.log4j.Logger;
 import org.apache.xerces.parsers.DOMParser;
+import org.w3c.dom.Element;
 import org.xml.sax.EntityResolver;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.InputSource;
@@ -55,8 +56,12 @@ public class XMLMetadataLoadWrapper extends ResourceWatchdog implements Metadata
        private Metadata                currentMeta;
        private DOMParser               parser;
 
+       public XMLMetadataLoadWrapper(Element configuration) throws MetadataException, ResourceNotAvailableException {
+               this(configuration.getAttribute("uri"));
+       }
+
        public XMLMetadataLoadWrapper(String sitesFileLocation) throws MetadataException, ResourceNotAvailableException {
-               super(new ShibResource(sitesFileLocation));
+               super(new ShibResource(sitesFileLocation, XMLMetadataLoadWrapper.class));
 
                parser = new DOMParser();
                try {