New Trust interface
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / serviceprovider / ServiceProviderConfig.java
index 9150267..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,7 +148,8 @@ 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;
@@ -155,20 +157,21 @@ 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.Metadata;
 import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
@@ -190,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)
        
        
@@ -229,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);
        }
        
        
@@ -267,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;    //TODO: is this needed anymore?
-       //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";
@@ -418,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>
                
@@ -444,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());
                
                /*
@@ -763,8 +758,8 @@ 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);
@@ -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();
@@ -875,7 +847,7 @@ public class ServiceProviderConfig {
         * query their value directly.
         */
        public class ApplicationInfo 
-               implements Metadata, ITrust {
+               implements Metadata, Trust {
                
                private Application applicationConfig;
         public Application getApplicationConfig() {
@@ -972,10 +944,10 @@ public class ServiceProviderConfig {
                 * 
                 * @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);
@@ -1007,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();
+        }
                
                
                /**
@@ -1084,33 +1073,20 @@ public class ServiceProviderConfig {
                 */
                public boolean 
                validate(
-                               Iterator revocations,  // Currently unused 
-                               RoleDescriptor role,
-                               SAMLObject token, 
-                               Metadata 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(RoleDescriptor role, SAMLObject token) {
-                       return validate(null,role,token,null);
-               }
 
                /**
                 * A method of ITrust that we must declare to claim that 
@@ -1125,6 +1101,26 @@ public class ServiceProviderConfig {
                        // 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;
+               }
        }