Added some rarely used methods to sync metadata API with C++
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / ServiceProviderConfig.java
index 4eaf6cb..c607515 100644 (file)
@@ -1,4 +1,20 @@
 /*
+ * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
  * ServiceProviderConfig.java
  * 
  * A ServiceProviderConfig object holds an instance of the Shibboleth
  * configuration file should be noted while processing continues.
  * This strategy reports all the errors in all the files to the log
  * rather than stopping at the first error.
- * 
- * --------------------
- * Copyright 2002, 2004 
- * University Corporation for Advanced Internet Development, Inc. 
- * All rights reserved
- * [Thats all we have to say to protect ourselves]
- * Your permission to use this code is governed by "The Shibboleth License".
- * A copy may be found at http://shibboleth.internet2.edu/license.html
- * [Nothing in copyright law requires license text in every file.]
  */
 
 package edu.internet2.middleware.shibboleth.serviceprovider;
@@ -143,6 +150,7 @@ import java.util.Map;
 import java.util.TreeMap;
 
 import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlOptions;
 import org.opensaml.SAMLAssertion;
@@ -166,16 +174,21 @@ import x0.maceShibbolethTargetConfig1.ShibbolethTargetConfigDocument;
 import x0.maceShibbolethTargetConfig1.ApplicationDocument.Application;
 import x0.maceShibbolethTargetConfig1.ApplicationsDocument.Applications;
 import x0.maceShibbolethTargetConfig1.HostDocument.Host;
+import x0.maceShibbolethTargetConfig1.HostDocument.Host.Scheme.Enum;
 import x0.maceShibbolethTargetConfig1.PathDocument.Path;
 import edu.internet2.middleware.shibboleth.aap.AAP;
 import edu.internet2.middleware.shibboleth.aap.AttributeRule;
+import edu.internet2.middleware.shibboleth.aap.provider.XMLAAPProvider;
 import edu.internet2.middleware.shibboleth.common.Credentials;
+import edu.internet2.middleware.shibboleth.common.PluggableConfigurationComponent;
 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
 import edu.internet2.middleware.shibboleth.common.Trust;
 import edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust;
+import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
 import edu.internet2.middleware.shibboleth.metadata.Metadata;
 import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
+import edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadataProvider;
 import edu.internet2.middleware.shibboleth.xml.Parser;
 
 /**
@@ -193,7 +206,8 @@ public class ServiceProviderConfig {
        // Map key prefix for inline plugin configuration elements 
        private static final String INLINEURN = "urn:inlineBS:ID";
     
-    private static Logger log = Logger.getLogger(ServiceProviderConfig.class);
+    private static Logger initlog = Logger.getLogger(ContextListener.SHIBBOLETH_INIT+".Config");
+    private static Logger reqlog = Logger.getLogger(ServiceProviderConfig.class);
 
        private SPConfigType  // The XMLBean from the main config file
                config = null;    
@@ -213,6 +227,7 @@ public class ServiceProviderConfig {
                new TreeMap/*<String, Metadata>*/();
        
        public void addOrReplaceMetadataImplementor(String uri, Metadata m) {
+               initlog.info("addOrReplaceMetadataImplementor " + uri+ " as "+m.getClass());
            entityLocators.put(uri, m);
        }
        
@@ -224,6 +239,7 @@ public class ServiceProviderConfig {
                new TreeMap/*<String, AAP>*/();
        
        public void addOrReplaceAAPImplementor(String uri, AAP a) {
+               initlog.info("addOrReplaceAAPImplementor " + uri+ " as "+a.getClass());
            attributePolicies.put(uri,a);
        }
        
@@ -235,6 +251,7 @@ public class ServiceProviderConfig {
                new TreeMap/*<String, Trust>*/();
        
        public void addOrReplaceTrustImplementor(String uri, Trust t) {
+               initlog.info("addOrReplaceTrustImplementor " + uri+ " as "+t.getClass());
            certificateValidators.put(uri,t);
        }
        
@@ -275,15 +292,13 @@ public class ServiceProviderConfig {
         */
 
        private static final String XMLTRUSTPROVIDERTYPE = 
-               "edu.internet2.middleware.shibboleth.common.provider.XMLTrust";
+               "edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust";
        private static final String XMLAAPPROVIDERTYPE = 
-               "edu.internet2.middleware.shibboleth.serviceprovider.XMLAAP";
+               "edu.internet2.middleware.shibboleth.aap.provider.XMLAAP";
        private static final String XMLFEDERATIONPROVIDERTYPE = 
-               "edu.internet2.middleware.shibboleth.common.provider.XMLMetadata";
-       private static final String XMLREVOCATIONPROVIDERTYPE =
-           "edu.internet2.middleware.shibboleth.common.provider.XMLRevocation";
+               "edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadata";
        private static final String XMLREQUESTMAPPROVIDERTYPE = 
-           "edu.internet2.middleware.shibboleth.serviceprovider.XMLRequestMap";
+           "edu.internet2.middleware.shibboleth.sp.provider.NativeRequestMapProvider";
        private static final String XMLCREDENTIALSPROVIDERTYPE = 
            "edu.internet2.middleware.shibboleth.common.Credentials";
        
@@ -314,14 +329,17 @@ public class ServiceProviderConfig {
                        throws ShibbolethConfigurationException {
            
            if (config!=null) {
-                       log.error("ServiceProviderConfig.loadConfigObjects may not be called twice for the same object.");
+                       initlog.error("ServiceProviderConfig.loadConfigObjects may not be called twice for the same object.");
                        throw new ShibbolethConfigurationException("Cannot reload configuration into same object.");
                }
+           
+           initlog.info("Loading SP configuration from "+configFilePath);
 
                Document configDoc;
         try {
                        configDoc = Parser.loadDom(configFilePath, true);
                } catch (Exception e) {
+                       initlog.error("XML Parser error "+e.toString());
             throw new ShibbolethConfigurationException("XML error in "+configFilePath);
         }
         loadConfigBean(configDoc);
@@ -349,30 +367,23 @@ public class ServiceProviderConfig {
         String urlhostname = url.getHost();
         String urlpath = url.getPath();
         int urlport = url.getPort();
-        if (urlport==0) {
-            if (urlscheme.equals("http"))
-                urlport=80;
-            else if (urlscheme.equals("https"))
-                urlport=443;
-        }
         
         // find Host entry for this virtual server
         Host[] hostArray = requestMap.getHostArray();
         for (int ihost=0;ihost<hostArray.length;ihost++) {
             Host host = hostArray[ihost];
-            String hostScheme = host.getScheme().toString();
+            Enum scheme = host.getScheme();
             String hostName = host.getName();
             String hostApplicationId = host.getApplicationId();
             long hostport = host.getPort();
-            if (hostport==0) {
-                if (hostScheme.equals("http"))
-                    hostport=80;
-                else if (hostScheme.equals("https"))
-                    hostport=443;
-            }
             
-            if (!urlscheme.equals(hostScheme) ||
-                !urlhostname.equals(hostName)||
+            if (scheme != null &&
+                !urlscheme.equals(scheme.toString()))
+                continue;
+            if (!urlhostname.equals(hostName))
+                continue;
+            if (hostport!=0 &&
+                urlport!=0 &&    
                 urlport!=hostport)
                 continue;
             
@@ -391,6 +402,7 @@ public class ServiceProviderConfig {
             }
         }
            
+        reqlog.debug("mapRequest mapped "+urlreq+" into "+applicationId);
            return applicationId;
        }
 
@@ -409,27 +421,40 @@ public class ServiceProviderConfig {
                Element documentElement = configDoc.getDocumentElement();
                // reprocess the already validated DOM to create a bean with typed fields
                // dump the trash (comments, processing instructions, extra whitespace)
-               
                try {
                        if (documentElement.getLocalName().equals("ShibbolethTargetConfig")) {
+                               initlog.debug("SP Configuration file is in 1.2 syntax.");
                                ShibbolethTargetConfigDocument configBeanDoc;
                                configBeanDoc = ShibbolethTargetConfigDocument.Factory.parse(configDoc,
                                                new XmlOptions().setLoadStripComments().setLoadStripProcinsts().setLoadStripWhitespace());
                                config = configBeanDoc.getShibbolethTargetConfig();
                        } else if (documentElement.getLocalName().equals("SPConfig")) {
+                               initlog.debug("SP Configuration file is in 1.3 syntax.");
                                SPConfigDocument configBeanDoc;
                                configBeanDoc = SPConfigDocument.Factory.parse(configDoc,
                                                new XmlOptions().setLoadStripComments().setLoadStripProcinsts().setLoadStripWhitespace());
                                config = configBeanDoc.getSPConfig();
                        } else {
+                               initlog.error("Root element not ShibbolethTargetConfig or SPConfig");
                                throw new XmlException("Root element not ShibbolethTargetConfig or SPConfig");
                        }
                } catch (XmlException e) {
                        // Since the DOM was already validated against the schema, errors will not typically occur here
-                       log.error("Error while parsing shibboleth configuration");
+                       initlog.error("Error while parsing shibboleth configuration");
                        throw new ShibbolethConfigurationException("Error while parsing shibboleth configuration");
                }
                
+               String loggerUrlString = config.getLogger();
+               if (loggerUrlString!=null) {
+                       try {
+                               URL loggerURL = new URL(loggerUrlString);
+                               initlog.warn("logging is being reconfigured by "+ loggerUrlString);
+                               PropertyConfigurator.configure(loggerURL);
+                       } catch (MalformedURLException e) {
+                               // This error is not serious enough to prevent initialization
+                               initlog.error("Ignoring invalid value for logger attribute "+loggerUrlString );
+                       }
+               }
                
                Applications apps = config.getApplications(); // <Applications>
                
@@ -475,8 +500,10 @@ public class ServiceProviderConfig {
                anyError |= processCredentials();
                anyError |= processPluggableRequestMapProvider();
                
-               if (anyError)
+               if (anyError) {
+                       initlog.error("SP Initialization terminated due to configuration errors");
                    throw new ShibbolethConfigurationException("Errors processing configuration file, see log");
+               }
        }
 
        
@@ -496,7 +523,7 @@ public class ServiceProviderConfig {
                        String pluggabletype = pluggable[i].getType();
                if (!pluggabletype.equals(
                        "edu.internet2.middleware.shibboleth.common.Credentials")) {
-                               log.error("Unsupported CredentialsProvider type "+pluggabletype);
+                               initlog.error("Unsupported CredentialsProvider type "+pluggabletype);
                                anyError=true;
                                continue;
                }
@@ -508,8 +535,7 @@ public class ServiceProviderConfig {
                 Node credentialsNode=credentialsProviderNode.getFirstChild();
                 credentials = new Credentials((Element)credentialsNode);
             } catch(Exception e) {
-                log.error("Cannot process Credentials element of Shibboleth configuration");
-                log.error(e);
+                initlog.error("Cannot process Credentials element of Shibboleth configuration",e);
                 anyError=true;
                 continue;
             }
@@ -594,15 +620,16 @@ public class ServiceProviderConfig {
        
        if (!pluggabletype.equals(builtinName)) {
            // Not the builtin type, try to load user class by name
+               initlog.info("loading user-specified pluggable class "+pluggabletype);
            try {
                 implclass = Class.forName(pluggabletype);
             } catch (ClassNotFoundException e) {
-                       log.error("Type value "+pluggabletype+" not found as supplied Java class");
+                       initlog.error("Type value "+pluggabletype+" not found as supplied Java class");
                    return null;
             }
            if (!interfaceClass.isAssignableFrom(implclass)||
                 !PluggableConfigurationComponent.class.isAssignableFrom(implclass)) {
-                       log.error(pluggabletype+" class does not support required interfaces.");
+                       initlog.error(pluggabletype+" class does not support required interfaces.");
                    return null;
            }
        }
@@ -611,7 +638,7 @@ public class ServiceProviderConfig {
         try {
             impl = (PluggableConfigurationComponent) implclass.newInstance();
         } catch (Exception e) {
-            log.error("Unable to instantiate "+pluggabletype);
+            initlog.error("Unable to instantiate "+pluggabletype);
             return null;
         }
        
@@ -622,10 +649,10 @@ public class ServiceProviderConfig {
                try {
                        Node fragment = pluggable.newDomNode();        // XML-Fragment node
                        Node pluggableNode = fragment.getFirstChild(); // PluggableType 
-                       Node contentNode=pluggableNode.getFirstChild();// root element
+                       Element contentNode=(Element) pluggableNode.getFirstChild();// root element
                        impl.initialize(contentNode);
                } catch (Exception e) {
-                       log.error("XML error " + e);
+                       initlog.error("XML error " + e);
                        return null;
                }
                
@@ -639,9 +666,9 @@ public class ServiceProviderConfig {
                        Document extdoc = Parser.loadDom(uri,true);
                        if (extdoc==null)
                            return null;
-                       impl.initialize(extdoc);
+                       impl.initialize(extdoc.getDocumentElement());
                } catch (Exception e) {
-                       log.error("XML error " + e);
+                       initlog.error("XML error " + e);
                        return null;
                }
        }
@@ -675,7 +702,7 @@ public class ServiceProviderConfig {
                }
                for (int i = 0;i<pluggable.length;i++) {
                    String uri = processPluggable(pluggable[i],
-                           XMLMetadataImpl.class,
+                           XMLMetadataProvider.class,
                            Metadata.class,
                            XMLFEDERATIONPROVIDERTYPE,
                            entityLocators);
@@ -701,12 +728,12 @@ public class ServiceProviderConfig {
                        Document sitedoc = Parser.loadDom(uri,true);
                        if (sitedoc==null)
                            return false;
-                       XMLMetadataImpl impl = new XMLMetadataImpl();
-                       impl.initialize(sitedoc);
+                       XMLMetadataProvider impl = new XMLMetadataProvider();
+                       impl.initialize(sitedoc.getDocumentElement());
                        addOrReplaceMetadataImplementor(uri,impl);
                } catch (Exception e) {
-                       log.error("Error while parsing Metadata file "+uri);
-                       log.error("XML error " + e);
+                       initlog.error("Error while parsing Metadata file "+uri);
+                       initlog.error("XML error " + e);
                        return false;
                }
            return true;
@@ -722,7 +749,7 @@ public class ServiceProviderConfig {
                PluggableType[] pluggable = appinfo.getApplicationConfig().getAAPProviderArray();
                for (int i = 0;i<pluggable.length;i++) {
                    String uri = processPluggable(pluggable[i],
-                           XMLAAPImpl.class,
+                               XMLAAPProvider.class,
                            AAP.class,
                            XMLAAPPROVIDERTYPE,
                            attributePolicies);
@@ -749,12 +776,12 @@ public class ServiceProviderConfig {
                        if (aapdoc==null)
                            return false;
                        AttributeAcceptancePolicyDocument aap = AttributeAcceptancePolicyDocument.Factory.parse(aapdoc);
-                       XMLAAPImpl impl = new XMLAAPImpl();
-                       impl.initialize(aapdoc);
+                       XMLAAPProvider impl = new XMLAAPProvider();
+                       impl.initialize(aapdoc.getDocumentElement());
                        addOrReplaceAAPImplementor(uri,impl);
                } catch (Exception e) {
-                       log.error("Error while parsing AAP file "+uri);
-                       log.error("XML error " + e);
+                       initlog.error("Error while parsing AAP file "+uri);
+                       initlog.error("XML error " + e);
                        return false;
                }
            return true;
@@ -795,11 +822,17 @@ public class ServiceProviderConfig {
        
        private boolean processPluggableRequestMapProvider(){
            LocalConfigurationType shire = config.getSHIRE();
+        if (shire==null)
+            shire = config.getLocal();
+        if (shire==null) {
+            initlog.error("No SHIRE or Local element.");
+            return true;
+        }
            PluggableType mapProvider = shire.getRequestMapProvider();
            
            String pluggabletype = mapProvider.getType();
            if (!pluggabletype.equals(XMLREQUESTMAPPROVIDERTYPE)) {
-               log.error("Unsupported RequestMapProvider type "+pluggabletype);
+               initlog.error("Unsupported RequestMapProvider type "+pluggabletype);
                return true;
            }
            
@@ -818,8 +851,8 @@ public class ServiceProviderConfig {
                    
                    requestMapDoc = RequestMapDocument.Factory.parse(contentNode);
                } catch (Exception e) {
-                   log.error("Error while parsing inline RequestMap");
-                   log.error("XML error " + e);
+                   initlog.error("Error while parsing inline RequestMap");
+                   initlog.error("XML error " + e);
                    return true;
                }
                
@@ -830,8 +863,8 @@ public class ServiceProviderConfig {
                        return true;
                    requestMapDoc = RequestMapDocument.Factory.parse(mapdoc);
                } catch (Exception e) {
-                   log.error("Error while parsing RequestMap file "+uri);
-                   log.error("XML error " + e);
+                   initlog.error("Error while parsing RequestMap file "+uri);
+                   initlog.error("XML error " + e);
                    return true;
                }
            }
@@ -934,29 +967,51 @@ public class ServiceProviderConfig {
                 * @param id ID of the IdP entity
                 * @return EntityDescriptor metadata object for that site.
                 */
-        public EntityDescriptor lookup(String id) {
+        public EntityDescriptor lookup(String id, boolean strict) {
                        Iterator iuris = groupUris.iterator();
                        while (iuris.hasNext()) {
                                String uri =(String) iuris.next();
                                Metadata locator=getMetadataImplementor(uri);
-                               EntityDescriptor entity = locator.lookup(id);
-                               if (entity!=null)
+                               EntityDescriptor entity = locator.lookup(id, strict);
+                               if (entity!=null) {
+                                       reqlog.debug("Metadata.lookup resolved Entity "+ id);
                                        return entity;
+                               }
                        }
+                       reqlog.warn("Metadata.lookup failed to resolve Entity "+ id);
                        return null;
                }
 
-        public EntityDescriptor lookup(Artifact artifact) {
+        public EntityDescriptor lookup(Artifact artifact, boolean strict) {
             Iterator iuris = groupUris.iterator();
             while (iuris.hasNext()) {
                 String uri =(String) iuris.next();
                 Metadata locator=getMetadataImplementor(uri);
-                EntityDescriptor entity = locator.lookup(artifact);
-                if (entity!=null)
+                EntityDescriptor entity = locator.lookup(artifact, strict);
+                if (entity!=null) {
+                                       reqlog.debug("Metadata.lookup resolved Artifact "+ artifact);
                     return entity;
+                }
             }
+                       reqlog.warn("Metadata.lookup failed to resolve Artifact "+ artifact);
             return null;
         }
+
+               public EntityDescriptor lookup(String id) {
+                       return lookup(id,true);
+               }
+
+               public EntityDescriptor lookup(Artifact artifact) {
+                       return lookup(artifact,true);
+               }
+
+               public EntityDescriptor getRootEntity() {
+                       return null;
+               }
+
+               public EntitiesDescriptor getRootEntities() {
+                       return null;
+               }
         
                /**
                 * Return the current array of objects that implement the Trust interface
@@ -1009,13 +1064,13 @@ public class ServiceProviderConfig {
                    // Foreach AAP in the collection
                        AAP[] providers = getAAPProviders();
             if (providers.length == 0) {
-                log.info("no filters specified, accepting entire assertion");
+                reqlog.info("no filters specified, accepting entire assertion");
                 return;
             }
                        for (int i=0;i<providers.length;i++) {
                                AAP aap = providers[i];
                                if (aap.anyAttribute()) {
-                    log.info("any attribute enabled, accepting entire assertion");
+                    reqlog.info("any attribute enabled, accepting entire assertion");
                                        continue;
                 }
             }
@@ -1042,14 +1097,14 @@ public class ServiceProviderConfig {
                                     rule.apply(attribute,role);
                                 }
                                 catch (SAMLException ex) {
-                                    log.info("no values remain, removing attribute");
+                                    reqlog.info("no values remain, removing attribute");
                                                                attributeStatement.removeAttribute(iattribute--);
                                     break;
                                 }
                             }
                         }
                         if (!ruleFound) {
-                            log.warn("no rule found for attribute (" + attribute.getName() + "), filtering it out");
+                            reqlog.warn("no rule found for attribute (" + attribute.getName() + "), filtering it out");
                             attributeStatement.removeAttribute(iattribute--);
                         }
                         iattribute++;
@@ -1061,7 +1116,7 @@ public class ServiceProviderConfig {
                                        }
                     catch (SAMLException ex) {
                         // The statement is now defunct.
-                        log.info("no attributes remain, removing statement");
+                        reqlog.info("no attributes remain, removing statement");
                                                assertion.removeStatement(istatement);
                                        }
                                }
@@ -1105,6 +1160,7 @@ public class ServiceProviderConfig {
                                if (trust.validate(token,role))
                                        return true;
                        }
+                       reqlog.warn("SAML object failed Trust validation.");
                        return false;
                }
                
@@ -1130,6 +1186,7 @@ public class ServiceProviderConfig {
                                if (trust.validate(certificateEE,certificateChain,descriptor))
                                        return true;
                        }
+                       reqlog.warn("X.509 Certificate failed Trust validate");
                        return false;
                }
 
@@ -1140,6 +1197,7 @@ public class ServiceProviderConfig {
                                if (trust.validate(certificateEE,certificateChain,descriptor,checkName))
                                        return true;
                        }
+                       reqlog.warn("X.509 Certificate failed Trust validate");
                        return false;
                }