New Trust interface
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / ServiceProviderConfig.java
index 17a4241..adddd66 100644 (file)
@@ -135,6 +135,7 @@ package edu.internet2.middleware.shibboleth.serviceprovider;
 
 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;
@@ -147,32 +148,33 @@ import org.apache.xmlbeans.XmlOptions;
 import org.opensaml.SAMLAssertion;
 import org.opensaml.SAMLAttribute;
 import org.opensaml.SAMLAttributeStatement;
-import org.opensaml.SAMLObject;
+import org.opensaml.SAMLException;
+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 x0.maceShibboleth1.AttributeAcceptancePolicyDocument;
 import x0.maceShibbolethTargetConfig1.ApplicationDocument;
+import x0.maceShibbolethTargetConfig1.LocalConfigurationType;
 import x0.maceShibbolethTargetConfig1.PluggableType;
 import x0.maceShibbolethTargetConfig1.RequestMapDocument;
+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.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.common.Credentials;
 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.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.xml.Parser;
 
 /**
@@ -191,7 +193,7 @@ public class ServiceProviderConfig {
        private static final String INLINEURN = "urn:inlineBS:ID";
     private static Logger log = Logger.getLogger(ServiceProviderConfig.class);
 
-       private ShibbolethTargetConfig  // The XMLBean from the main config file
+       private SPConfigType  // The XMLBean from the main config file
                config = null;              // (i.e. shibboleth.xml)
        
        
@@ -205,16 +207,15 @@ 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) {
            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 = 
@@ -231,12 +232,12 @@ public class ServiceProviderConfig {
        private Map/*<String, ITrust>*/ certificateValidators = 
                new TreeMap/*<String, ITrust>*/();
        
-       public void addOrReplaceTrustImplementor(String uri, ITrust t) {
+       public void addOrReplaceTrustImplementor(String uri, Trust t) {
            certificateValidators.put(uri,t);
        }
        
-       public ITrust getTrustImplementor(String uri) {
-           return (ITrust) certificateValidators.get(uri);
+       public Trust getTrustImplementor(String uri) {
+           return (Trust) certificateValidators.get(uri);
        }
        
        
@@ -269,11 +270,6 @@ 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";
@@ -320,8 +316,9 @@ public class ServiceProviderConfig {
                }
 
                Document configDoc;
-        configDoc = Parser.loadDom(configFilePath, true);
-        if (configDoc==null) {
+        try {
+                       configDoc = Parser.loadDom(configFilePath, true);
+               } catch (Exception e) {
             throw new ShibbolethConfigurationException("XML error in "+configFilePath);
         }
         loadConfigBean(configDoc);
@@ -419,7 +416,7 @@ public class ServiceProviderConfig {
                }
                
                // Extract the "root Element" object from the "Document" object
-               ShibbolethTargetConfig config = configBeanDoc.getShibbolethTargetConfig();
+               SPConfigType config = configBeanDoc.getShibbolethTargetConfig();
                
                Applications apps = config.getApplications(); // <Applications>
                
@@ -445,9 +442,6 @@ public class ServiceProviderConfig {
                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());
                
                /*
@@ -580,7 +574,7 @@ public class ServiceProviderConfig {
                Class implclass,
                Class interfaceClass,
                String builtinName,
-               String schemaname,
+               //String schemaname,
                Map /*<String,PluggableConfigurationComponent>*/uriMap
                ) {
         
@@ -629,10 +623,11 @@ public class ServiceProviderConfig {
                    return "";
                }
                
+            /*
             String tempname = impl.getSchemaPathname();
             if (tempname!=null)
                 schemaname=tempname;
-            
+            */
                try {
                        Document extdoc = Parser.loadDom(uri,true);
                        if (extdoc==null)
@@ -659,9 +654,9 @@ public class ServiceProviderConfig {
                for (int i = 0;i<pluggable.length;i++) {
                    String uri = processPluggable(pluggable[i],
                            XMLMetadataImpl.class,
-                           EntityLocator.class,
+                           Metadata.class,
                            XMLFEDERATIONPROVIDERTYPE,
-                           METADATASCHEMA,
+                           //METADATASCHEMA,
                            entityLocators);
                    if (uri==null)
                        anyError=true;
@@ -709,7 +704,7 @@ public class ServiceProviderConfig {
                            XMLAAPImpl.class,
                            AAP.class,
                            XMLAAPPROVIDERTYPE,
-                           AAPSCHEMA,
+                           //AAPSCHEMA,
                            attributePolicies);
                    if (uri==null)
                        anyError=true;
@@ -763,10 +758,10 @@ 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,
+                           //TRUSTSCHEMA,
                            certificateValidators);
                    if (uri==null)
                        anyError=true;
@@ -777,33 +772,10 @@ 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();
            PluggableType mapProvider = shire.getRequestMapProvider();
            
            String pluggabletype = mapProvider.getType();
@@ -874,8 +846,8 @@ public class ServiceProviderConfig {
         * can fetch the XMLBean by calling getApplicationConf() and 
         * query their value directly.
         */
-       class ApplicationInfo 
-               implements EntityLocator, ITrust {
+       public class ApplicationInfo 
+               implements Metadata, Trust {
                
                private Application applicationConfig;
         public Application getApplicationConfig() {
@@ -943,37 +915,39 @@ public class ServiceProviderConfig {
                 * @param id ID of the OriginSite entity
                 * @return EntityDescriptor metadata object for that site.
                 */
-               public EntityDescriptor getEntityDescriptor(String id) {
+        public EntityDescriptor lookup(String id) {
                        Iterator iuris = groupUris.iterator();
                        while (iuris.hasNext()) {
                                String uri =(String) iuris.next();
-                               EntityLocator locator=getMetadataImplementor(uri);
-                               EntityDescriptor entity = locator.getEntityDescriptor(id);
+                               Metadata locator=getMetadataImplementor(uri);
+                               EntityDescriptor entity = locator.lookup(id);
                                if (entity!=null)
                                        return entity;
                        }
                        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) {
+            Iterator iuris = groupUris.iterator();
+            while (iuris.hasNext()) {
+                String uri =(String) iuris.next();
+                Metadata locator=getMetadataImplementor(uri);
+                EntityDescriptor entity = locator.lookup(artifact);
+                if (entity!=null)
+                    return entity;
+            }
+            return null;
+        }
+        
                /**
                 * Return the current array of objects that implement the ITrust interface
                 * 
                 * @return ITrust[]
                 */
-               public ITrust[] getTrustProviders() {
+               public Trust[] getTrustProviders() {
                        Iterator iuris = groupUris.iterator();
                        int count = groupUris.size();
-                       ITrust[] trusts = new ITrust[count];
+                       Trust[] trusts = new Trust[count];
                        for (int i=0;i<count;i++) {
                                String uri =(String) iuris.next();
                                trusts[i]=getTrustImplementor(uri);
@@ -1005,59 +979,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) {
+                log.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()) {
+                    log.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) {
+                                    log.info("no values remain, removing attribute");
+                                                               attributeStatement.removeAttribute(iattribute--);
+                                    break;
+                                }
+                            }
+                        }
+                        if (!ruleFound) {
+                            log.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.
+                        log.info("no attributes remain, removing statement");
+                                               assertion.removeStatement(istatement);
                                        }
                                }
                        }
-               }
+
+            // Now see if we trashed it irrevocably.
+            assertion.checkValidity();
+        }
                
                
                /**
@@ -1082,33 +1073,20 @@ 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;
                        }
                        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 
@@ -1119,11 +1097,30 @@ public class ServiceProviderConfig {
                 * @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;
+                       }
+                       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;
+                       }
+                       return false;
+               }
        }