Added some rarely used methods to sync metadata API with C++
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / ServiceProviderConfig.java
index c934cef..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;
 
-import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -143,39 +150,45 @@ 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;
 import org.opensaml.SAMLAttribute;
 import org.opensaml.SAMLAttributeStatement;
 import org.opensaml.SAMLException;
-import org.opensaml.SAMLObject;
+import org.opensaml.SAMLSignedObject;
+import org.opensaml.artifact.Artifact;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
 
 import x0.maceShibboleth1.AttributeAcceptancePolicyDocument;
 import x0.maceShibbolethTargetConfig1.ApplicationDocument;
+import x0.maceShibbolethTargetConfig1.LocalConfigurationType;
 import x0.maceShibbolethTargetConfig1.PluggableType;
 import x0.maceShibbolethTargetConfig1.RequestMapDocument;
+import x0.maceShibbolethTargetConfig1.SPConfigDocument;
+import x0.maceShibbolethTargetConfig1.SPConfigType;
 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 x0.maceShibbolethTargetConfig1.SHIREDocument.SHIRE;
-import x0.maceShibbolethTargetConfig1.ShibbolethTargetConfigDocument.ShibbolethTargetConfig;
-import edu.internet2.middleware.shibboleth.common.AAP;
-import edu.internet2.middleware.shibboleth.common.AttributeRule;
+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.XML;
+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.EntityLocator;
 import edu.internet2.middleware.shibboleth.metadata.Metadata;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
+import edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadataProvider;
 import edu.internet2.middleware.shibboleth.xml.Parser;
 
 /**
@@ -190,12 +203,14 @@ import edu.internet2.middleware.shibboleth.xml.Parser;
  */
 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 ShibbolethTargetConfig  // The XMLBean from the main config file
-               config = null;              // (i.e. shibboleth.xml)
+       private SPConfigType  // The XMLBean from the main config file
+               config = null;    
        
        
        /*
@@ -208,22 +223,23 @@ public class ServiceProviderConfig {
         * for a given configured or default application.
         */
        
-       // Note EntityLocator extends and renames the old "Metadata" interface
-       private Map/*<String, EntityLocator>*/ entityLocators = 
-               new TreeMap/*<String, EntityLocator>*/();
+       private Map/*<String, Metadata>*/ entityLocators = 
+               new TreeMap/*<String, Metadata>*/();
        
-       public void addOrReplaceMetadataImplementor(String uri, EntityLocator m) {
+       public void addOrReplaceMetadataImplementor(String uri, Metadata m) {
+               initlog.info("addOrReplaceMetadataImplementor " + uri+ " as "+m.getClass());
            entityLocators.put(uri, m);
        }
        
-       public EntityLocator getMetadataImplementor(String uri) {
-           return (EntityLocator) entityLocators.get(uri);
+       public Metadata getMetadataImplementor(String uri) {
+           return (Metadata)entityLocators.get(uri);
        }
        
        private Map/*<String, AAP>*/ attributePolicies = 
                new TreeMap/*<String, AAP>*/();
        
        public void addOrReplaceAAPImplementor(String uri, AAP a) {
+               initlog.info("addOrReplaceAAPImplementor " + uri+ " as "+a.getClass());
            attributePolicies.put(uri,a);
        }
        
@@ -231,17 +247,19 @@ public class ServiceProviderConfig {
            return (AAP) attributePolicies.get(uri);
        }
        
-       private Map/*<String, ITrust>*/ certificateValidators = 
-               new TreeMap/*<String, ITrust>*/();
+       private Map/*<String, Trust>*/ certificateValidators = 
+               new TreeMap/*<String, Trust>*/();
        
-       public void addOrReplaceTrustImplementor(String uri, ITrust t) {
+       public void addOrReplaceTrustImplementor(String uri, Trust t) {
+               initlog.info("addOrReplaceTrustImplementor " + uri+ " as "+t.getClass());
            certificateValidators.put(uri,t);
        }
        
-       public ITrust getTrustImplementor(String uri) {
-           return (ITrust) certificateValidators.get(uri);
+       public Trust getTrustImplementor(String uri) {
+           return (Trust) certificateValidators.get(uri);
        }
        
+       private Trust[] defaultTrust = {new ShibbolethTrust()};
        
        /*
         * Objects created from the <Application(s)> elements.
@@ -272,22 +290,15 @@ public class ServiceProviderConfig {
        /*
         * A few constants
         */
-       private final String SCHEMADIR = "/schemas/";
-       private final String MAINSCHEMA = SCHEMADIR + XML.MAIN_SHEMA_ID;
-       private final String METADATASCHEMA = SCHEMADIR + XML.SHIB_SCHEMA_ID;
-       private final String TRUSTSCHEMA = SCHEMADIR + XML.TRUST_SCHEMA_ID;
-       private final String AAPSCHEMA = SCHEMADIR + XML.SHIB_SCHEMA_ID;
 
        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";
        
@@ -318,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);
@@ -353,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;
             
@@ -395,6 +402,7 @@ public class ServiceProviderConfig {
             }
         }
            
+        reqlog.debug("mapRequest mapped "+urlreq+" into "+applicationId);
            return applicationId;
        }
 
@@ -409,21 +417,44 @@ public class ServiceProviderConfig {
        private void loadConfigBean(Document configDoc) 
                throws ShibbolethConfigurationException {
            boolean anyError=false;
-               ShibbolethTargetConfigDocument configBeanDoc;
-        try {
-                       // reprocess the already validated DOM to create a bean with typed fields
-                       // dump the trash (comments, processing instructions, extra whitespace)
-                       configBeanDoc = ShibbolethTargetConfigDocument.Factory.parse(configDoc,
-                               new XmlOptions().setLoadStripComments().setLoadStripProcinsts().setLoadStripWhitespace());
-                       config=configBeanDoc.getShibbolethTargetConfig();
+               
+               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");
                }
                
-               // Extract the "root Element" object from the "Document" object
-               ShibbolethTargetConfig config = configBeanDoc.getShibbolethTargetConfig();
+               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>
                
@@ -446,12 +477,9 @@ public class ServiceProviderConfig {
                defaultApp.setCredentialUse(apps.getCredentialUse());
                defaultApp.setErrors(apps.getErrors());
                defaultApp.setFederationProviderArray(apps.getFederationProviderArray());
+               defaultApp.setMetadataProviderArray(apps.getMetadataProviderArray());
                defaultApp.setProviderId(apps.getProviderId());
-               defaultApp.setRevocationProviderArray(apps.getRevocationProviderArray());
                defaultApp.setSessions(apps.getSessions());
-               defaultApp.setSignedAssertions(apps.getSignedAssertions());
-               defaultApp.setSignedResponse(apps.getSignedResponse());
-               defaultApp.setSignRequest(apps.getSignRequest());
                defaultApp.setTrustProviderArray(apps.getTrustProviderArray());
                
                /*
@@ -472,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");
+               }
        }
 
        
@@ -481,7 +511,7 @@ public class ServiceProviderConfig {
         * Routine to handle CredentialProvider
         * 
         * <p>Note: This only handles in-line XML.
-        * Also, Credentials was an existing Origin class, so it doesn't
+        * Also, Credentials was an existing IdP class, so it doesn't
         * implement the new PluggableConfigurationComponent interface and
         * can't be loaded by generic plugin support.
         * </p>
@@ -493,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;
                }
@@ -505,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;
             }
@@ -564,7 +593,7 @@ public class ServiceProviderConfig {
      * object is stored in the appropriate Map.</p>
      * 
      * <p>The objects created implement two interfaces. Mostly they
-     * implement a configuration interface (EntityDescriptor, ITrust,
+     * implement a configuration interface (EntityDescriptor, Trust,
      * AAP, etc). However, for the purpose of this routine they also
      * must be declared to implement PluggableConfigurationComponent
      * and provide an initialize() method that parses a DOM Node 
@@ -584,7 +613,6 @@ public class ServiceProviderConfig {
                Class implclass,
                Class interfaceClass,
                String builtinName,
-               String schemaname,
                Map /*<String,PluggableConfigurationComponent>*/uriMap
                ) {
         
@@ -592,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;
            }
        }
@@ -609,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;
         }
        
@@ -620,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;
                }
                
@@ -633,17 +662,13 @@ public class ServiceProviderConfig {
                    return "";
                }
                
-            String tempname = impl.getSchemaPathname();
-            if (tempname!=null)
-                schemaname=tempname;
-            
                try {
                        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;
                }
        }
@@ -659,13 +684,27 @@ public class ServiceProviderConfig {
         */
        private boolean processPluggableMetadata(ApplicationInfo appinfo) {
            boolean anyError = false;
-               PluggableType[] pluggable = appinfo.getApplicationConfig().getFederationProviderArray();
+               PluggableType[] pluggable1 = appinfo.getApplicationConfig().getFederationProviderArray();
+               PluggableType[] pluggable2 = appinfo.getApplicationConfig().getMetadataProviderArray();
+               PluggableType[] pluggable;
+               if (pluggable1.length==0) {
+                       pluggable=pluggable2;
+               } else if (pluggable2.length==0) {
+                       pluggable=pluggable1;
+               } else {
+                       pluggable = new PluggableType[pluggable1.length+pluggable2.length];
+                       for (int i=0;i<pluggable2.length;i++) {
+                               pluggable[i]=pluggable2[i];
+                       }
+                       for (int i=0;i<pluggable1.length;i++) {
+                               pluggable[i+pluggable2.length]=pluggable1[i];
+                       }
+               }
                for (int i = 0;i<pluggable.length;i++) {
                    String uri = processPluggable(pluggable[i],
-                           XMLMetadataImpl.class,
-                           EntityLocator.class,
+                           XMLMetadataProvider.class,
+                           Metadata.class,
                            XMLFEDERATIONPROVIDERTYPE,
-                           METADATASCHEMA,
                            entityLocators);
                    if (uri==null)
                        anyError=true;
@@ -689,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;
@@ -710,10 +749,9 @@ 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,
-                           AAPSCHEMA,
                            attributePolicies);
                    if (uri==null)
                        anyError=true;
@@ -738,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;
@@ -767,10 +805,9 @@ public class ServiceProviderConfig {
                PluggableType[] pluggable = appinfo.getApplicationConfig().getTrustProviderArray();
                for (int i = 0;i<pluggable.length;i++) {
                    String uri = processPluggable(pluggable[i],
-                           XMLTrustImpl.class,
-                           ITrust.class,
+                           ShibbolethTrust.class,
+                           Trust.class,
                            XMLTRUSTPROVIDERTYPE,
-                           TRUSTSCHEMA,
                            certificateValidators);
                    if (uri==null)
                        anyError=true;
@@ -781,38 +818,21 @@ public class ServiceProviderConfig {
                return anyError;
        }
 
-       /**
-        * Reload XML Trust configuration after file changed.
-        * @param uri Path to Trust XML configuration
-        * @return true if file reloaded.
-        */
-       public boolean reloadTrust(String uri) {
-           if (getTrustImplementor(uri)!=null||
-                   uri.startsWith(INLINEURN))
-               return false;
-               try {
-                       Document trustdoc = Parser.loadDom(uri,true);
-                       if (trustdoc==null)
-                           return false;
-                       XMLTrustImpl impl = new XMLTrustImpl();
-                       impl.initialize(trustdoc);
-                       addOrReplaceTrustImplementor(uri,impl);
-               } catch (Exception e) {
-                       log.error("Error while parsing Trust file "+uri);
-                       log.error("XML error " + e);
-                       return false;
-               }
-           return true;
-       }
        
        
        private boolean processPluggableRequestMapProvider(){
-           SHIRE shire = config.getSHIRE();
+           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;
            }
            
@@ -831,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;
                }
                
@@ -843,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;
                }
            }
@@ -854,7 +874,7 @@ public class ServiceProviderConfig {
        }
 
        
-       
+       // Generate Map keys for inline plugin configuration Elements
        private int inlinenum = 1;
        private String genDummyUri() {
                return INLINEURN+Integer.toString(inlinenum++);
@@ -879,7 +899,7 @@ public class ServiceProviderConfig {
         * query their value directly.
         */
        public class ApplicationInfo 
-               implements EntityLocator, ITrust {
+               implements Metadata, Trust {
                
                private Application applicationConfig;
         public Application getApplicationConfig() {
@@ -944,40 +964,66 @@ public class ServiceProviderConfig {
                 * function in the new interface that will use the new term, but
                 * it does the same thing.</p>
                 *  
-                * @param id ID of the OriginSite entity
+                * @param id ID of the IdP entity
                 * @return EntityDescriptor metadata object for that site.
                 */
-               public EntityDescriptor getEntityDescriptor(String id) {
+        public EntityDescriptor lookup(String id, boolean strict) {
                        Iterator iuris = groupUris.iterator();
                        while (iuris.hasNext()) {
                                String uri =(String) iuris.next();
-                               EntityLocator locator=getMetadataImplementor(uri);
-                               EntityDescriptor entity = locator.getEntityDescriptor(id);
-                               if (entity!=null)
+                               Metadata locator=getMetadataImplementor(uri);
+                               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;
                }
-               
-               /**
-                * Convenience function to fulfill Metadata interface contract.
-                * 
-                * @param id ID of OriginSite
-                * @return Provider object for that Site.
-                */
-               public Provider lookup(String id) {
-                       return getEntityDescriptor(id);
+
+        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, 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 ITrust interface
+                * Return the current array of objects that implement the Trust interface
                 * 
-                * @return ITrust[]
+                * @return Trust[]
                 */
-               public ITrust[] getTrustProviders() {
-                       Iterator iuris = groupUris.iterator();
-                       int count = groupUris.size();
-                       ITrust[] trusts = new ITrust[count];
+               public Trust[] getTrustProviders() {
+                       Iterator iuris = trustUris.iterator();
+                       int count = trustUris.size();
+                       if (count==0)
+                               return defaultTrust;
+                       Trust[] trusts = new Trust[count];
                        for (int i=0;i<count;i++) {
                                String uri =(String) iuris.next();
                                trusts[i]=getTrustImplementor(uri);
@@ -1009,59 +1055,76 @@ public class ServiceProviderConfig {
                 * Empty SAML elements get removed from the assertion.
                 * This can yield an AttributeAssertion with no attributes. 
                 * 
-                * @param entity     Origin site that sent the assertion
                 * @param assertion  SAML Attribute Assertion
+         * @param role     Role that issued the assertion
+                * @throws SAMLException  Raised if assertion is mangled beyond repair
                 */
-               void applyAAP(EntityDescriptor entity, SAMLAssertion assertion) {
+               void applyAAP(SAMLAssertion assertion, RoleDescriptor role) throws SAMLException {
                    
                    // Foreach AAP in the collection
                        AAP[] providers = getAAPProviders();
+            if (providers.length == 0) {
+                reqlog.info("no filters specified, accepting entire assertion");
+                return;
+            }
                        for (int i=0;i<providers.length;i++) {
                                AAP aap = providers[i];
-                               if (aap.isAnyAttribute())
+                               if (aap.anyAttribute()) {
+                    reqlog.info("any attribute enabled, accepting entire assertion");
                                        continue;
-                               
-                               // Foreach Statement in the Assertion
-                               Iterator statements = assertion.getStatements();
-                               int istatement=0;
-                               while (statements.hasNext()) {
-                                       Object statement = statements.next();
-                                       if (statement instanceof SAMLAttributeStatement) {
-                                               SAMLAttributeStatement attributeStatement = 
-                                                       (SAMLAttributeStatement) statement;
-                                               
-                                               // Foreach Attribute in the AttributeStatement
-                                               Iterator attributes = attributeStatement.getAttributes();
-                                               int iattribute=0;
-                                               while (attributes.hasNext()) {
-                                                       SAMLAttribute attribute = 
-                                                               (SAMLAttribute) attributes.next();
-                                                       String name = attribute.getName();
-                                                       String namespace = attribute.getNamespace();
-                                                       AttributeRule rule = aap.lookup(name,namespace);
-                                                       if (rule==null) {
-                                                               // TODO Not sure, but code appears to keep unknown attributes
-                                                               log.warn("No rule found for attribute "+name);
-                                                               iattribute++;
-                                                               continue;
-                                                       }
-                                                       rule.apply(entity,attribute);
-                                                       if (!attribute.getValues().hasNext())
-                                                               attributeStatement.removeAttribute(iattribute);
-                                                       else
-                                                               iattribute++;
-                                                               
-                                               }
-                                               if (!attributeStatement.getAttributes().hasNext())
-                                                       assertion.removeStatement(istatement);
-                                               else
-                                                       istatement++;
-                                       } else {
-                                               istatement++;
+                }
+            }
+            
+                       // Foreach Statement in the Assertion
+                       Iterator statements = assertion.getStatements();
+                       int istatement=0;
+                       while (statements.hasNext()) {
+                               Object statement = statements.next();
+                               if (statement instanceof SAMLAttributeStatement) {
+                                       SAMLAttributeStatement attributeStatement =     (SAMLAttributeStatement) statement;
+                                       
+                    // Check each attribute, applying any matching rules.
+                                       Iterator attributes = attributeStatement.getAttributes();
+                                       int iattribute=0;
+                                       while (attributes.hasNext()) {
+                                               SAMLAttribute attribute = (SAMLAttribute) attributes.next();
+                        boolean ruleFound = false;
+                        for (int i=0;i<providers.length;i++) {
+                                               AttributeRule rule = providers[i].lookup(attribute.getName(),attribute.getNamespace());
+                                               if (rule!=null) {
+                                                   ruleFound = true;
+                                try {
+                                    rule.apply(attribute,role);
+                                }
+                                catch (SAMLException ex) {
+                                    reqlog.info("no values remain, removing attribute");
+                                                               attributeStatement.removeAttribute(iattribute--);
+                                    break;
+                                }
+                            }
+                        }
+                        if (!ruleFound) {
+                            reqlog.warn("no rule found for attribute (" + attribute.getName() + "), filtering it out");
+                            attributeStatement.removeAttribute(iattribute--);
+                        }
+                        iattribute++;
+                                       }
+                    
+                    try {
+                        attributeStatement.checkValidity();
+                        istatement++;
+                                       }
+                    catch (SAMLException ex) {
+                        // The statement is now defunct.
+                        reqlog.info("no attributes remain, removing statement");
+                                               assertion.removeStatement(istatement);
                                        }
                                }
                        }
-               }
+
+            // Now see if we trashed it irrevocably.
+            assertion.checkValidity();
+        }
                
                
                /**
@@ -1076,7 +1139,7 @@ public class ServiceProviderConfig {
 
                
                /**
-                * Convenience method implementing ITrust.validate() across 
+                * Convenience method implementing Trust.validate() across 
                 * the collection of implementing objects. Returns true if
                 * any Trust implementor approves the signatures in the object.
                 * 
@@ -1086,48 +1149,65 @@ public class ServiceProviderConfig {
                 */
                public boolean 
                validate(
-                               Iterator revocations,  // Currently unused 
-                               ProviderRole role,
-                               SAMLObject token, 
-                               EntityLocator dummy    // "this" is an EntityLocator 
+                               SAMLSignedObject token, 
+                               RoleDescriptor role
                                        ) {
                        
-                       // TODO If revocations are supported, "this" will provide them
-                       
-                       ITrust[] trustProviders = getTrustProviders();
+       
+                       Trust[] trustProviders = getTrustProviders();
                        for (int i=0;i<trustProviders.length;i++) {
-                               ITrust trust = trustProviders[i];
-                               if (trust.validate(null,role,token,this))
+                               Trust trust = trustProviders[i];
+                               if (trust.validate(token,role))
                                        return true;
                        }
+                       reqlog.warn("SAML object failed Trust validation.");
                        return false;
                }
                
-               /**
-                * Simpler version of validate that avoids dummy arguments
-                * 
-                * @param role  Entity that sent Token (from Metadata)
-                * @param token Signed SAMLObject
-                * @return
-                */
-               public boolean validate(ProviderRole role, SAMLObject token) {
-                       return validate(null,role,token,null);
-               }
 
                /**
-                * A method of ITrust that we must declare to claim that 
-                * ApplicationInfo implements ITrust. However, no code in the
-                * ServiceProvider calls this (probably an Origin thing).
+                * A method of Trust that we must declare to claim that 
+                * ApplicationInfo implements Trust. However, no code in the
+                * ServiceProvider calls this (probably an IdP thing).
                 * 
                 * @param revocations
                 * @param role
                 * @return  This dummy always returns false.
                 */
-               public boolean attach(Iterator revocations, ProviderRole role) {
+               public boolean attach(Iterator revocations, RoleDescriptor role) {
                        // Unused
                        return false;
                }
-               
+
+               public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor) {
+                       Trust[] trustProviders = getTrustProviders();
+                       for (int i=0;i<trustProviders.length;i++) {
+                               Trust trust = trustProviders[i];
+                               if (trust.validate(certificateEE,certificateChain,descriptor))
+                                       return true;
+                       }
+                       reqlog.warn("X.509 Certificate failed Trust validate");
+                       return false;
+               }
+
+               public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor, boolean checkName) {
+                       Trust[] trustProviders = getTrustProviders();
+                       for (int i=0;i<trustProviders.length;i++) {
+                               Trust trust = trustProviders[i];
+                               if (trust.validate(certificateEE,certificateChain,descriptor,checkName))
+                                       return true;
+                       }
+                       reqlog.warn("X.509 Certificate failed Trust validate");
+                       return false;
+               }
+        
+        public String getProviderId() {
+            String entityId = this.applicationConfig.getProviderId();
+            if (entityId==null && this!=defaultApplicationInfo) {
+                entityId = defaultApplicationInfo.getProviderId();
+            }
+            return entityId;
+        }
        }
        
 
@@ -1137,5 +1217,11 @@ public class ServiceProviderConfig {
                super();
            }
        }
+
+
+
+    public Credentials getCredentials() {
+        return credentials;
+    }
        
 }