Metadata support for old and new schemas, and API changes.
authorcantor <cantor@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Thu, 3 Mar 2005 00:17:22 +0000 (00:17 +0000)
committercantor <cantor@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Thu, 3 Mar 2005 00:17:22 +0000 (00:17 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@1267 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

41 files changed:
src/edu/internet2/middleware/shibboleth/common/Constants.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/common/ServiceProviderMapper.java
src/edu/internet2/middleware/shibboleth/common/ShibBrowserProfile.java
src/edu/internet2/middleware/shibboleth/common/TargetFederationComponent.java
src/edu/internet2/middleware/shibboleth/common/XML.java
src/edu/internet2/middleware/shibboleth/idp/IdPResponder.java
src/edu/internet2/middleware/shibboleth/metadata/AffiliationDescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/AttributeAuthorityDescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/AttributeAuthorityRole.java [deleted file]
src/edu/internet2/middleware/shibboleth/metadata/AttributeConsumingService.java [moved from src/edu/internet2/middleware/shibboleth/metadata/Provider.java with 76% similarity]
src/edu/internet2/middleware/shibboleth/metadata/AuthnAuthorityDescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/ContactPerson.java
src/edu/internet2/middleware/shibboleth/metadata/Endpoint.java
src/edu/internet2/middleware/shibboleth/metadata/EndpointManager.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/EntitiesDescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/EntityDescriptor.java
src/edu/internet2/middleware/shibboleth/metadata/EntityLocator.java [deleted file]
src/edu/internet2/middleware/shibboleth/metadata/IDPProviderRole.java [deleted file]
src/edu/internet2/middleware/shibboleth/metadata/IDPSSODescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/IndexedEndpoint.java [moved from src/edu/internet2/middleware/shibboleth/metadata/AttributeConsumerRole.java with 93% similarity]
src/edu/internet2/middleware/shibboleth/metadata/KeyDescriptor.java
src/edu/internet2/middleware/shibboleth/metadata/Metadata.java
src/edu/internet2/middleware/shibboleth/metadata/Organization.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/PDPDescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/RoleDescriptor.java [moved from src/edu/internet2/middleware/shibboleth/metadata/ProviderRole.java with 78% similarity]
src/edu/internet2/middleware/shibboleth/metadata/SAML2Metadata.java [deleted file]
src/edu/internet2/middleware/shibboleth/metadata/SPProviderRole.java [deleted file]
src/edu/internet2/middleware/shibboleth/metadata/SPSSODescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/SSODescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/ScopedRoleDescriptor.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/metadata/provider/XMLMetadata.java
src/edu/internet2/middleware/shibboleth/metadata/provider/XMLMetadataLoadWrapper.java
src/edu/internet2/middleware/shibboleth/metadata/provider/XMLMetadataProvider.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/serviceprovider/AttributeRequestor.java
src/edu/internet2/middleware/shibboleth/serviceprovider/ITrust.java
src/edu/internet2/middleware/shibboleth/serviceprovider/SAML2MetadataImpl.java [deleted file]
src/edu/internet2/middleware/shibboleth/serviceprovider/ServiceProviderConfig.java
src/edu/internet2/middleware/shibboleth/serviceprovider/ShibBinding.java
src/edu/internet2/middleware/shibboleth/serviceprovider/XMLMetadataImpl.java
src/edu/internet2/middleware/shibboleth/serviceprovider/XMLTrustImpl.java
tests/edu/internet2/middleware/shibboleth/metadata/MetadataTests.java

diff --git a/src/edu/internet2/middleware/shibboleth/common/Constants.java b/src/edu/internet2/middleware/shibboleth/common/Constants.java
new file mode 100755 (executable)
index 0000000..2681180
--- /dev/null
@@ -0,0 +1,17 @@
+package edu.internet2.middleware.shibboleth.common;
+
+/**
+ * @author Scott Cantor
+ *
+ */
+public class Constants {
+    
+    /** Shibboleth "transient" NameIdentifier Format */
+    public static final String SHIB_NAMEID_FORMAT_URI = "urn:mace:shibboleth:1.0:nameIdentifier";
+
+    /** Shibboleth attribute profile AttributeNamespace */
+    public static final String SHIB_ATTRIBUTE_NAMESPACE_URI = "urn:mace:shibboleth:1.0:attributeNamespace:uri";
+    
+    /** Shibboleth AuthnRequest profile URI */
+    public static final String SHIB_AUTHNREQUEST_PROFILE_URI = "urn:mace:shibboleth:1.0:profiles:AuthnRequest";
+}
index 7d354c2..4d53250 100644 (file)
@@ -37,8 +37,9 @@ import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
 import edu.internet2.middleware.shibboleth.idp.IdPConfig;
+import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
 import edu.internet2.middleware.shibboleth.metadata.Metadata;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
+import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
 
 /**
  * Class for determining the effective relying party from the unique id of the service provider. Checks first for an
@@ -130,20 +131,19 @@ public class ServiceProviderMapper {
 
        private RelyingParty findRelyingPartyByGroup(String providerIdFromTarget) {
 
-               Provider provider = metaData.lookup(providerIdFromTarget);
+               EntityDescriptor provider = metaData.lookup(providerIdFromTarget);
                if (provider != null) {
-                       String[] groups = provider.getGroups();
-                       for (int i = 0; groups.length > i; i++) {
-                               // We need to iterate backward because the groups go from least to most specific
-                               String group = groups[groups.length - 1 - i];
-                               if (relyingParties.containsKey(group)) {
-                                       log.info("Found matching Relying Party for group (" + group + ").");
-                                       return (RelyingParty) relyingParties.get(group);
+                       EntitiesDescriptor parent = provider.getEntitiesDescriptor();
+                       while (parent != null) {
+                               if (relyingParties.containsKey(parent.getName())) {
+                                       log.info("Found matching Relying Party for group (" + parent.getName() + ").");
+                                       return (RelyingParty)relyingParties.get(parent.getName());
                                } else {
-                                       log
-                                                       .debug("Provider is a member of group (" + group
-                                                                       + "), but no matching Relying Party was found.");
+                                       log.debug("Provider is a member of group (" +
+                            parent.getName() +
+                            "), but no matching Relying Party was found.");
                                }
+                parent = parent.getEntitiesDescriptor();
                        }
                }
                return null;
index fe176d0..6ca659c 100644 (file)
@@ -58,9 +58,9 @@ import org.opensaml.SAMLSignedObject;
 import org.opensaml.TrustException;
 
 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.IDPProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.IDPSSODescriptor;
 import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderContext;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
@@ -249,11 +249,11 @@ public class ShibBrowserProfile implements SAMLBrowserProfile {
         ServiceProviderConfig config = context.getServiceProviderConfig();
         ApplicationInfo appinfo = config.getApplication(applicationId);
         
-        entity = appinfo.getEntityDescriptor(asn_issuer);
+        entity = appinfo.lookup(asn_issuer);
         providerId=asn_issuer;
         if (entity==null) {
             providerId=qualifier;
-            entity= appinfo.getEntityDescriptor(qualifier);
+            entity= appinfo.lookup(qualifier);
         }
         if (entity==null) {
             log.error("assertion issuer not found in metadata(Issuer ="+
@@ -262,17 +262,7 @@ public class ShibBrowserProfile implements SAMLBrowserProfile {
         }
         issuer.append(providerId);
         
-        // From the Metadata, get the HS and from it the key
-        ProviderRole[] roles = entity.getRoles();
-        for (int i=0;i<roles.length;i++) {
-            ProviderRole role = roles[i];
-            if (role instanceof IDPProviderRole) {
-                // TODO: Sync up with new SAML metadata profile (uses SAML protocol string instead of SHIB_NS)
-                if (role.hasSupport(XML.SHIB_NS)) {
-                    ;
-                }
-            }
-        }
+        // TODO: finish profile extension using metadata/trust interfaces
         
         return bpr;
     }
index 928d422..86178a9 100644 (file)
@@ -32,11 +32,12 @@ import java.util.Iterator;
 import javax.servlet.http.HttpServlet;
 
 import org.apache.log4j.Logger;
+import org.opensaml.artifact.Artifact;
 import org.w3c.dom.Element;
 
 import edu.internet2.middleware.shibboleth.metadata.Metadata;
 import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
+import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
 
 /**
  * @author Walter Hoehn (wassa@columbia.edu)
@@ -65,17 +66,28 @@ public class TargetFederationComponent extends HttpServlet implements Metadata {
                return fedMetadata.size();
        }
 
-       public Provider lookup(String providerId) {
+       public EntityDescriptor lookup(String providerId) {
 
                Iterator iterator = fedMetadata.iterator();
                while (iterator.hasNext()) {
-                       Provider provider = ((Metadata) iterator.next()).lookup(providerId);
+                       EntityDescriptor provider = ((Metadata) iterator.next()).lookup(providerId);
                        if (provider != null) {
                                return provider;
                        }
                }
                return null;
        }
+
+    public EntityDescriptor lookup(Artifact artifact) {
+        Iterator iterator = fedMetadata.iterator();
+        while (iterator.hasNext()) {
+            EntityDescriptor provider = ((Metadata) iterator.next()).lookup(artifact);
+            if (provider != null) {
+                return provider;
+            }
+        }
+        return null;
+    }
 }
 
 class FederationProviderFactory {
index 18c4881..037f28d 100755 (executable)
@@ -58,23 +58,23 @@ package edu.internet2.middleware.shibboleth.common;
  */
 public class XML
 {
+    /**  SAMLv2 Metadata XML namespace */
+    public final static String SAML2META_NS = "urn:oasis:names:tc:SAML:2.0:metadata";
+
+    /**  SAMLv2 Assertion XML namespace */
+    public final static String SAML2ASSERT_NS = "urn:oasis:names:tc:SAML:2.0:assertion";
+    
     /**  Shibboleth XML namespace */
     public final static String SHIB_NS = "urn:mace:shibboleth:1.0";
     
-    /**  Shibboleth XML schema identifier */
-    public final static String SHIB_SCHEMA_ID = "shibboleth.xsd";
-    
     /**  Shibboleth Metadata XML namespace */
     public final static String SHIBMETA_NS = "urn:mace:shibboleth:1.0:metadata";
     
-    /**  Shibboleth XML schema identifier */
-    public final static String SHIBMETA_SCHEMA_ID = "shibboleth-metadata-1.0.xsd";
-
     /**  Shibboleth trust metadata XML namespace */
     public final static String TRUST_NS = "urn:mace:shibboleth:trust:1.0";
-    
-    /**  Shibboleth trust metadata XML schema identifier */
-    public final static String TRUST_SCHEMA_ID = "shibboleth-trust-1.0.xsd";
+
+    /**  XML Encryption namespace */
+    public final static String XMLENC_NS = "http://www.w3.org/2001/04/xmlenc#";
     
     public final static String MAIN_SHEMA_ID = "shibboleth-targetconfig-1.0.xsd";
     public final static String ORIGIN_SHEMA_ID = "shibboleth-idpconfig-1.0.xsd";
index 5a9f7cc..97163c9 100644 (file)
@@ -66,6 +66,7 @@ import org.opensaml.SAMLAuthenticationStatement;
 import org.opensaml.SAMLAuthorityBinding;
 import org.opensaml.SAMLBinding;
 import org.opensaml.SAMLBindingFactory;
+import org.opensaml.SAMLBrowserProfile;
 import org.opensaml.SAMLCondition;
 import org.opensaml.SAMLException;
 import org.opensaml.SAMLNameIdentifier;
@@ -101,12 +102,7 @@ import edu.internet2.middleware.shibboleth.common.ServiceProviderMapperException
 import edu.internet2.middleware.shibboleth.common.ShibBrowserProfile;
 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
 import edu.internet2.middleware.shibboleth.common.TargetFederationComponent;
-import edu.internet2.middleware.shibboleth.metadata.AttributeConsumerRole;
-import edu.internet2.middleware.shibboleth.metadata.Endpoint;
-import edu.internet2.middleware.shibboleth.metadata.KeyDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
-import edu.internet2.middleware.shibboleth.metadata.SPProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.*;
 
 /**
  * Primary entry point for requests to the SAML IdP. Listens on multiple endpoints, routes requests to the appropriate
@@ -321,7 +317,7 @@ public class IdPResponder extends TargetFederationComponent {
                        }
 
                        // Grab the metadata for the provider
-                       Provider provider = lookup(relyingParty.getProviderId());
+                       EntityDescriptor provider = lookup(relyingParty.getProviderId());
 
                        // Use profile-specific method for determining the acceptance URL
                        String acceptanceURL = activeHandler.getAcceptanceURL(request, relyingParty, provider);
@@ -751,7 +747,7 @@ public class IdPResponder extends TargetFederationComponent {
                                SAMLAssertion assertion = mapping.getAssertion();
 
                                // See if we have metadata for this provider
-                               Provider provider = lookup(mapping.getServiceProviderId());
+                               EntityDescriptor provider = lookup(mapping.getServiceProviderId());
                                if (provider == null) {
                                        log.info("No metadata found for provider: (" + mapping.getServiceProviderId() + ").");
                                        throw new SAMLException(SAMLException.REQUESTER, "Invalid service provider.");
@@ -858,7 +854,7 @@ public class IdPResponder extends TargetFederationComponent {
                        } else {
 
                                // See if we have metadata for this provider
-                               Provider provider = lookup(relyingParty.getProviderId());
+                               EntityDescriptor provider = lookup(relyingParty.getProviderId());
                                if (provider == null) {
                                        log.info("No metadata found for provider: (" + relyingParty.getProviderId() + ").");
                                        log.info("Treating remote provider as unauthenticated.");
@@ -881,22 +877,18 @@ public class IdPResponder extends TargetFederationComponent {
                }
        }
 
-       private static void addSignatures(SAMLResponse response, RelyingParty relyingParty, Provider provider,
+       private static void addSignatures(SAMLResponse response, RelyingParty relyingParty, EntityDescriptor provider,
                        boolean signResponse) throws SAMLException {
 
                if (provider != null) {
                        boolean signAssertions = false;
 
-                       ProviderRole[] roles = provider.getRoles();
-                       if (roles.length == 0) {
+                       SPSSODescriptor sp = provider.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
+                       if (sp == null) {
                                log.info("Inappropriate metadata for provider: " + provider.getId() + ".  Expected SPSSODescriptor.");
                        }
-                       for (int i = 0; roles.length > i; i++) {
-                               if (roles[i] instanceof SPProviderRole) {
-                                       if (((SPProviderRole) roles[i]).wantAssertionsSigned()) {
-                                               signAssertions = true;
-                                       }
-                               }
+                       if (sp.getWantAssertionsSigned()) {
+                               signAssertions = true;
                        }
 
                        if (signAssertions && relyingParty.getIdentityProvider().getSigningCredential() != null
@@ -942,26 +934,25 @@ public class IdPResponder extends TargetFederationComponent {
                }
        }
 
-       private static boolean useArtifactProfile(Provider provider, String acceptanceURL) {
+       private static boolean useArtifactProfile(EntityDescriptor provider, String acceptanceURL) {
 
                // Default to POST if we have no metadata
                if (provider == null) { return false; }
 
                // Default to POST if we have incomplete metadata
-               ProviderRole[] roles = provider.getRoles();
-               if (roles.length == 0) { return false; }
-
-               for (int i = 0; roles.length > i; i++) {
-                       if (roles[i] instanceof SPProviderRole) {
-                               Endpoint[] endpoints = ((SPProviderRole) roles[i]).getAssertionConsumerServiceURLs();
-
-                               for (int j = 0; endpoints.length > j; j++) {
-                                       if (acceptanceURL.equals(endpoints[j].getLocation())
-                                                       && "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01".equals(endpoints[j].getBinding())) { return true; }
-                               }
-                       }
+        SPSSODescriptor sp = provider.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
+               if (sp == null) { return false; }
+
+        // TODO: This will actually favor artifact, since a given location could support
+        // both profiles. If that's not what we want, needs adjustment...
+               Iterator endpoints = sp.getAssertionConsumerServiceManager().getEndpoints();
+               while (endpoints.hasNext()) {
+            Endpoint ep = (Endpoint)endpoints.next();
+                       if (acceptanceURL.equals(ep.getLocation())
+                                       && SAMLBrowserProfile.PROFILE_ARTIFACT_URI.equals(ep.getBinding())) { return true; }
                }
-               // Default to POST if we have incomplete metadata
+
+        // Default to POST if we have incomplete metadata
                return false;
        }
 
@@ -973,22 +964,18 @@ public class IdPResponder extends TargetFederationComponent {
                                "Unable to obtain client address."); }
        }
 
-       private static boolean isValidAssertionConsumerURL(Provider provider, String shireURL)
+       private static boolean isValidAssertionConsumerURL(EntityDescriptor provider, String shireURL)
                        throws InvalidClientDataException {
 
-               ProviderRole[] roles = provider.getRoles();
-               if (roles.length == 0) {
+        SPSSODescriptor sp = provider.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
+               if (sp == null) {
                        log.info("Inappropriate metadata for provider.");
                        return false;
                }
 
-               for (int i = 0; roles.length > i; i++) {
-                       if (roles[i] instanceof SPProviderRole) {
-                               Endpoint[] endpoints = ((SPProviderRole) roles[i]).getAssertionConsumerServiceURLs();
-                               for (int j = 0; endpoints.length > j; j++) {
-                                       if (shireURL.equals(endpoints[j].getLocation())) { return true; }
-                               }
-                       }
+               Iterator endpoints = sp.getAssertionConsumerServiceManager().getEndpoints();
+               while (endpoints.hasNext()) {
+                       if (shireURL.equals(((Endpoint)endpoints.next()).getLocation())) { return true; }
                }
                log.info("Supplied consumer URL not found in metadata.");
                return false;
@@ -1001,74 +988,68 @@ public class IdPResponder extends TargetFederationComponent {
                return null;
        }
 
-       private static boolean isValidCredential(Provider provider, X509Certificate certificate) {
+       private static boolean isValidCredential(EntityDescriptor provider, X509Certificate certificate) {
 
-               ProviderRole[] roles = provider.getRoles();
-               if (roles.length == 0) {
+               SPSSODescriptor sp = provider.getSPSSODescriptor(org.opensaml.XML.SAML11_PROTOCOL_ENUM);
+               if (sp == null) {
                        log.info("Inappropriate metadata for provider.");
                        return false;
                }
                // TODO figure out what to do about this role business here
-               for (int i = 0; roles.length > i; i++) {
-                       if (roles[i] instanceof AttributeConsumerRole) {
-                               KeyDescriptor[] descriptors = roles[i].getKeyDescriptors();
-                               for (int j = 0; descriptors.length > j; j++) {
-                                       KeyInfo[] keyInfo = descriptors[j].getKeyInfo();
-                                       for (int k = 0; keyInfo.length > k; k++) {
-                                               for (int l = 0; keyInfo[k].lengthKeyName() > l; l++) {
-                                                       try {
-
-                                                               // First, try to match DN against metadata
-                                                               try {
-                                                                       if (certificate.getSubjectX500Principal().getName(X500Principal.RFC2253).equals(
-                                                                                       new X500Principal(keyInfo[k].itemKeyName(l).getKeyName())
-                                                                                                       .getName(X500Principal.RFC2253))) {
-                                                                               log.debug("Matched against DN.");
-                                                                               return true;
-                                                                       }
-                                                               } catch (IllegalArgumentException iae) {
-                                                                       // squelch this runtime exception, since
-                                                                       // this might be a valid case
-                                                               }
+               Iterator descriptors = sp.getKeyDescriptors();
+               while (descriptors.hasNext()) {
+                       KeyInfo keyInfo = ((KeyDescriptor)descriptors.next()).getKeyInfo();
+                       for (int l = 0; keyInfo.lengthKeyName() > l; l++) {
+                               try {
 
-                                                               // If that doesn't work, we try matching against
-                                                               // some Subject Alt Names
-                                                               try {
-                                                                       Collection altNames = certificate.getSubjectAlternativeNames();
-                                                                       if (altNames != null) {
-                                                                               for (Iterator nameIterator = altNames.iterator(); nameIterator.hasNext();) {
-                                                                                       List altName = (List) nameIterator.next();
-                                                                                       if (altName.get(0).equals(new Integer(2))
-                                                                                                       || altName.get(0).equals(new Integer(6))) { // 2 is
-                                                                                               // DNS,
-                                                                                               // 6 is
-                                                                                               // URI
-                                                                                               if (altName.get(1).equals(keyInfo[k].itemKeyName(l).getKeyName())) {
-                                                                                                       log.debug("Matched against SubjectAltName.");
-                                                                                                       return true;
-                                                                                               }
-                                                                                       }
-                                                                               }
-                                                                       }
-                                                               } catch (CertificateParsingException e1) {
-                                                                       log
-                                                                                       .error("Encountered an problem trying to extract Subject Alternate Name from supplied certificate: "
-                                                                                                       + e1);
-                                                               }
+                                       // First, try to match DN against metadata
+                                       try {
+                                               if (certificate.getSubjectX500Principal().getName(X500Principal.RFC2253).equals(
+                                                               new X500Principal(keyInfo.itemKeyName(l).getKeyName())
+                                                                               .getName(X500Principal.RFC2253))) {
+                                                       log.debug("Matched against DN.");
+                                                       return true;
+                                               }
+                                       } catch (IllegalArgumentException iae) {
+                                               // squelch this runtime exception, since
+                                               // this might be a valid case
+                                       }
 
-                                                               // If that doesn't work, try to match using
-                                                               // SSL-style hostname matching
-                                                               if (ShibBrowserProfile.getHostNameFromDN(certificate.getSubjectX500Principal()).equals(
-                                                                               keyInfo[k].itemKeyName(l).getKeyName())) {
-                                                                       log.debug("Matched against hostname.");
-                                                                       return true;
+                                       // If that doesn't work, we try matching against
+                                       // some Subject Alt Names
+                                       try {
+                                               Collection altNames = certificate.getSubjectAlternativeNames();
+                                               if (altNames != null) {
+                                                       for (Iterator nameIterator = altNames.iterator(); nameIterator.hasNext();) {
+                                                               List altName = (List) nameIterator.next();
+                                                               if (altName.get(0).equals(new Integer(2))
+                                                                               || altName.get(0).equals(new Integer(6))) { // 2 is
+                                                                       // DNS,
+                                                                       // 6 is
+                                                                       // URI
+                                                                       if (altName.get(1).equals(keyInfo.itemKeyName(l).getKeyName())) {
+                                                                               log.debug("Matched against SubjectAltName.");
+                                                                               return true;
+                                                                       }
                                                                }
-
-                                                       } catch (XMLSecurityException e) {
-                                                               log.error("Encountered an error reading federation metadata: " + e);
                                                        }
                                                }
+                                       } catch (CertificateParsingException e1) {
+                                               log
+                                                               .error("Encountered an problem trying to extract Subject Alternate Name from supplied certificate: "
+                                                                               + e1);
                                        }
+
+                                       // If that doesn't work, try to match using
+                                       // SSL-style hostname matching
+                                       if (ShibBrowserProfile.getHostNameFromDN(certificate.getSubjectX500Principal()).equals(
+                                                       keyInfo.itemKeyName(l).getKeyName())) {
+                                               log.debug("Matched against hostname.");
+                                               return true;
+                                       }
+
+                               } catch (XMLSecurityException e) {
+                                       log.error("Encountered an error reading federation metadata: " + e);
                                }
                        }
                }
@@ -1159,13 +1140,13 @@ public class IdPResponder extends TargetFederationComponent {
 
                abstract boolean preProcessHook(HttpServletRequest request, HttpServletResponse response) throws IOException;
 
-               abstract SAMLAssertion[] processHook(HttpServletRequest request, RelyingParty relyingParty, Provider provider,
+               abstract SAMLAssertion[] processHook(HttpServletRequest request, RelyingParty relyingParty, EntityDescriptor provider,
                                SAMLNameIdentifier nameId, String authenticationMethod, Date authTime) throws SAMLException,
                                IOException;
 
-               abstract String getSAMLTargetParameter(HttpServletRequest request, RelyingParty relyingParty, Provider provider);
+               abstract String getSAMLTargetParameter(HttpServletRequest request, RelyingParty relyingParty, EntityDescriptor provider);
 
-               abstract String getAcceptanceURL(HttpServletRequest request, RelyingParty relyingParty, Provider provider)
+               abstract String getAcceptanceURL(HttpServletRequest request, RelyingParty relyingParty, EntityDescriptor provider)
                                throws InvalidClientDataException;
        }
        class ShibbolethProfileHandler extends SSOProfileHandler {
@@ -1224,7 +1205,7 @@ public class IdPResponder extends TargetFederationComponent {
                 *      edu.internet2.middleware.shibboleth.hs.HSRelyingParty, org.opensaml.SAMLNameIdentifier, java.lang.String,
                 *      long)
                 */
-               SAMLAssertion[] processHook(HttpServletRequest request, RelyingParty relyingParty, Provider provider,
+               SAMLAssertion[] processHook(HttpServletRequest request, RelyingParty relyingParty, EntityDescriptor provider,
                                SAMLNameIdentifier nameId, String authenticationMethod, Date authTime) throws SAMLException, IOException {
                        Document doc = org.opensaml.XML.parserPool.newDocument();
 
@@ -1258,7 +1239,7 @@ public class IdPResponder extends TargetFederationComponent {
                        ArrayList bindings = new ArrayList();
                        if (relyingParty.isLegacyProvider()) {
 
-                               SAMLAuthorityBinding binding = new SAMLAuthorityBinding(SAMLBinding.SAML_SOAP_HTTPS, relyingParty
+                               SAMLAuthorityBinding binding = new SAMLAuthorityBinding(SAMLBinding.SOAP, relyingParty
                                                .getAAUrl().toString(), new QName(org.opensaml.XML.SAMLP_NS, "AttributeQuery"));
                                bindings.add(binding);
                        }
@@ -1292,7 +1273,7 @@ public class IdPResponder extends TargetFederationComponent {
                 * @see edu.internet2.middleware.shibboleth.hs.AuthNProfileHandler#getSAMLTargetParameter(javax.servlet.http.HttpServletRequest,
                 *      edu.internet2.middleware.shibboleth.hs.HSRelyingParty)
                 */
-               String getSAMLTargetParameter(HttpServletRequest request, RelyingParty relyingParty, Provider provider) {
+               String getSAMLTargetParameter(HttpServletRequest request, RelyingParty relyingParty, EntityDescriptor provider) {
                        return request.getParameter("target");
                }
 
@@ -1302,7 +1283,7 @@ public class IdPResponder extends TargetFederationComponent {
                 * @see edu.internet2.middleware.shibboleth.hs.AuthNProfileHandler#getAcceptanceURL(javax.servlet.http.HttpServletRequest,
                 *      edu.internet2.middleware.shibboleth.hs.HSRelyingParty)
                 */
-               String getAcceptanceURL(HttpServletRequest request, RelyingParty relyingParty, Provider provider)
+               String getAcceptanceURL(HttpServletRequest request, RelyingParty relyingParty, EntityDescriptor provider)
                                throws InvalidClientDataException {
                        return request.getParameter("shire");
                }
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/AffiliationDescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/AffiliationDescriptor.java
new file mode 100644 (file)
index 0000000..b425683
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+import org.w3c.dom.Element;
+
+/**
+ * <p>Corresponds to SAML Metadata Schema "AffiliationDescriptorType".
+ *
+ *  @author Scott Cantor
+ */
+public interface AffiliationDescriptor {
+
+       public EntityDescriptor getEntityDescriptor(); // parent EntityDescriptor
+    
+    public String getOwnerID();
+
+    public boolean isValid();
+    
+    public Iterator /* <String> */ getMembers();
+
+    public boolean isMember(String id);
+    
+    public Iterator /* <KeyDescriptor> */ getKeyDescriptors(); // direct or indirect key references 
+    
+       public Element getElement(); // punch through to XML content if permitted
+}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/AttributeAuthorityDescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/AttributeAuthorityDescriptor.java
new file mode 100644 (file)
index 0000000..1e72876
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ * Corresponds to SAML Metadata Schema "AttributeAuthorityDescriptorType".
+ * 
+ * @author Scott Cantor
+ */
+public interface AttributeAuthorityDescriptor extends SSODescriptor {
+
+    public EndpointManager getAttributeServiceManager();
+    
+    public EndpointManager getAssertionIDRequestServiceManager(); 
+
+    public Iterator /* <String> */ getNameIDFormats();
+    
+    public Iterator /* <String> */ getAttributeProfiles();
+    
+    public Iterator /* <SAMLAttribute> */ getAttributes();
+}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/AttributeAuthorityRole.java b/src/edu/internet2/middleware/shibboleth/metadata/AttributeAuthorityRole.java
deleted file mode 100644 (file)
index a9c1ea4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * AttributeAuthorityRole.java
-  */
-package edu.internet2.middleware.shibboleth.metadata;
-
-import org.opensaml.SAMLAttributeDesignator;
-
-/**
- * @author Howard Gilbert
- */
-public interface AttributeAuthorityRole extends ProviderRole {
-       
-       Endpoint[] getAttributeServices();
-       SAMLAttributeDesignator[] getAttributeDesignators();
-
-}
 
 package edu.internet2.middleware.shibboleth.metadata;
 
+import java.util.Iterator;
+
+import org.opensaml.SAMLAttribute;
+
 /**
- * <p>Corresponds loosely to SAML Metadata Schema "EntityDescriptorType".
- * </p><p>
- * Entities are campuses or departments with either an origin or target
- * infrastructure (or both). Each implemented component (HS, AA, SHAR) 
- * has a Role definition with URLs and PKI to locate and authenticate
- * the provider of that role. Although the Metadata may define all 
- * roles, target code tends to build objects describing origins, and 
- * origins are only interested in targets.
+ * <p>Corresponds to SAML Metadata Schema "AttributeConsumingServiceType".
  * 
- * @author Walter Hoehn (wassa@columbia.edu)
+ * @author Scott Cantor
  */
-public interface Provider {
-
-       public String getId();  // Unique ID used as global key of Provider
-
-       public String[] getGroups(); // Groups in which this Provider is nested
+public interface AttributeConsumingService {
 
-       public ContactPerson[] getContacts(); // People
+    public String getName();
+    public String getName(String lang);
+    
+    public String getDescription();
+    public String getDescription(String lang);
 
-       public ProviderRole[] getRoles(); // HS, AA, SHAR, ... definitions
+    public class RequestedAttribute {
+        public SAMLAttribute attribute;
+        public boolean required;
+    }
 
+    public Iterator /* <RequestedAttribute> */ getRequestedAttributes();
 }
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/AuthnAuthorityDescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/AuthnAuthorityDescriptor.java
new file mode 100644 (file)
index 0000000..a170d74
--- /dev/null
@@ -0,0 +1,16 @@
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ * @author Scott Cantor
+ *
+= */
+public interface AuthnAuthorityDescriptor extends RoleDescriptor {
+
+    public EndpointManager getAuthnQueryServiceManager();
+    
+    public EndpointManager getAssertionIDRequestServiceManager();
+    
+    public Iterator /* <String> */ getNameIDFormats();
+}
index 207faf9..c75a9ae 100644 (file)
 
 package edu.internet2.middleware.shibboleth.metadata;
 
+import java.util.Iterator;
+
+import org.w3c.dom.Element;
+
 /**
  * Ported from Scott Cantor's C++ interfaces
  * 
@@ -41,9 +45,15 @@ public interface ContactPerson {
 
        public int getType();
 
-       public String getName();
+    public String getCompany();
+    
+       public String getGivenName();
+    
+    public String getSurName();
 
-       public String[] getEmails();
+       public Iterator /* <String> */ getEmailAddresses();
 
-       public String[] getTelephones();
+    public Iterator /* <String> */ getTelephoneNumbers();
+    
+    public Element getElement();
 }
index 30675fb..02e9872 100644 (file)
 
 package edu.internet2.middleware.shibboleth.metadata;
 
+import org.w3c.dom.Element;
+
 /**
- * <p>Corresponds loosely to SAML Metadata Schema "EndpointType".
+ * <p>Corresponds to SAML Metadata Schema "EndpointType".
  * </p><p>
  * "The complex type EndpointType describes a SAML protocol binding endpoint
  * at which a SAML entity can be sent protocol messages." That is, it is 
@@ -44,5 +46,6 @@ public interface Endpoint {
        public String getLocation(); // URI(URL) of the message destination
 
        public String getResponseLocation(); // optional second URI(URL) destination
-
+    
+    public Element getElement(); // punch through to XML content if permitted
 }
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/EndpointManager.java b/src/edu/internet2/middleware/shibboleth/metadata/EndpointManager.java
new file mode 100644 (file)
index 0000000..f7d36e8
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ *  Manages access to endpoints using common operations.
+ * 
+ * @author Scott Cantor
+ */
+public interface EndpointManager {
+
+    public Iterator /* <Endpoint> */ getEndpoints();
+
+    public Endpoint getDefaultEndpoint();
+    
+    public Endpoint getEndpointByIndex(int index);
+    
+    public Endpoint getEndpointByBinding(String binding);
+}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/EntitiesDescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/EntitiesDescriptor.java
new file mode 100644 (file)
index 0000000..8abb45a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+import org.w3c.dom.Element;
+
+/**
+ * <p>Corresponds to SAML Metadata Schema "EntitiesDescriptorType".</p>
+ * <p>Groups multiple entities into a named set for policy/configuration
+ * 
+ * @author Scott Cantor
+ */
+public interface EntitiesDescriptor {
+
+       public String getName();  // name of group
+    
+    public boolean isValid();   // Is this group "active"?
+
+    public EntitiesDescriptor getEntitiesDescriptor(); // parent group, if any
+    
+    public Iterator /* <EntitiesDescriptor> */ getEntitiesDescriptors(); // child groups, if any
+    
+    public Iterator /* <EntityDescriptor> */ getEntityDescriptors(); // child entities, if any
+    
+    public Element getElement();    // punch through to raw XML, if enabled
+}
index 3a6e0b8..b8e5b34 100644 (file)
@@ -1,48 +1,80 @@
 /*
- * EntityDescriptor.java
- * 
- * Simplify the transition to SAML 2 by allowing the obsolete
- * "Provider" interface to be called by its new name "EntityDescriptor".
- * Can be used to add or rename fields while writing code that 
- * implements the new interface while continuing to support the old.
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
+
 package edu.internet2.middleware.shibboleth.metadata;
 
+import java.util.Iterator;
+import java.util.Map;
+
+import org.w3c.dom.Element;
+
 /**
- * @author Howard Gilbert
+ * <p>Corresponds to SAML Metadata Schema "EntityDescriptorType".
+ * </p><p>
+ * Entities are campuses or departments with either an origin or target
+ * infrastructure (or both). Each implemented component (HS, AA, SHAR) 
+ * has a Role definition with URLs and PKI to locate and authenticate
+ * the provider of that role. Although the Metadata may define all 
+ * roles, target code tends to build objects describing origins, and 
+ * origins are only interested in targets.
+ * 
+ * @author Walter Hoehn (wassa@columbia.edu)
  */
-public abstract class EntityDescriptor implements Provider {
+public interface EntityDescriptor {
+
+       public String getId();  // Unique ID used as global key of Provider
     
+    public boolean isValid();   // Is this entity descriptor "active"?
+
+    public Iterator /* <RoleDescriptor> */ getRoleDescriptors(); // Role definitions
+
     /**
-     * Scan the array of Roles, return instance of a particular type
-     * @param type  Sub-Class of ProviderRole
-     * @return      instance of the type
+     *  Finds a role descriptor of a particular type that supports the
+     *  specified protocol.
+     * 
+     * @param type  The type of role to locate
+     * @param protocol  The protocol constant that must be supported
+     * @return  The matching role decsriptor, if any
      */
-    public ProviderRole getRoleByType(Class type) {
-        
-        ProviderRole[] roles = this.getRoles();
-        for (int i=0;i<roles.length;i++) {
-            ProviderRole role = roles[i];
-            if (type.isInstance(role))
-                return role;
-        }
-         return null;
-    }
+    public RoleDescriptor getRoleByType(Class type, String protocol);
     
-    public 
-       AttributeAuthorityRole 
-    getAttributeAuthorityRole(){
-        AttributeAuthorityRole aa = (AttributeAuthorityRole) getRoleByType(AttributeAuthorityRole.class);
-        return aa;
-    }
-       
-    public 
-       IDPProviderRole 
-    getHandleServer() {
-        IDPProviderRole hs = (IDPProviderRole) getRoleByType(IDPProviderRole.class);
-        return hs;
-    }
-
+    public IDPSSODescriptor getIDPSSODescriptor(String protocol);
+    public SPSSODescriptor getSPSSODescriptor(String protocol);
+    public AuthnAuthorityDescriptor getAuthnAuthorityDescriptor(String protocol);
+    public AttributeAuthorityDescriptor getAttributeAuthorityDescriptor(String protocol);
+    public PDPDescriptor getPDPDescriptor(String protocol);
+    public AffiliationDescriptor getAffiliationDescriptor();
     
-
+    public Organization getOrganization();  // associated organization
+    
+    public Iterator /* <ContactPerson> */ getContactPersons();    // support contacts
+    
+    public Map /* <String,String> */ getAdditionalMetadataLocations(); // XML Namespace - location pairs
+    
+    public EntitiesDescriptor getEntitiesDescriptor(); // parent group, if any
+    
+    public Element getElement();    // punch through to raw XML, if enabled
 }
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/EntityLocator.java b/src/edu/internet2/middleware/shibboleth/metadata/EntityLocator.java
deleted file mode 100644 (file)
index 3c5ed11..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * EntityLocator.java
-  */
-package edu.internet2.middleware.shibboleth.metadata;
-
-/**
- * @author Howard Gilbert
- */
-public interface EntityLocator extends Metadata {
-       
-       EntityDescriptor getEntityDescriptor(String id);
-
-}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/IDPProviderRole.java b/src/edu/internet2/middleware/shibboleth/metadata/IDPProviderRole.java
deleted file mode 100644 (file)
index 06823f2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * IDPProviderRole.java
- */
-package edu.internet2.middleware.shibboleth.metadata;
-
-/**
- * ID Service (HS)
- * 
- * @author Howard Gilbert
- */
-public interface IDPProviderRole extends ProviderRole {
-       
-}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/IDPSSODescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/IDPSSODescriptor.java
new file mode 100644 (file)
index 0000000..eb2d5c1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ * Corresponds to SAML Metadata Schema "IDPSSODescriptorType".
+ * 
+ * @author Scott Cantor
+ */
+public interface IDPSSODescriptor extends SSODescriptor {
+
+    public boolean getWantAuthnRequestsSigned();
+    
+    public EndpointManager getSingleSignOnServiceManager();
+    
+    public EndpointManager getNameIDMappingServiceManager();
+    
+    public EndpointManager getAssertionIDRequestServiceManager(); 
+
+    public Iterator /* <String> */ getAttributeProfiles();
+    
+    public Iterator /* <SAMLAttribute> */ getAttributes();
+}
 package edu.internet2.middleware.shibboleth.metadata;
 
 /**
- * Ported from Scott Cantor's C++ interfaces
+ * <p>Corresponds to SAML Metadata Schema "IndexedEndpointType".
  * 
- * @author Walter Hoehn (wassa@columbia.edu)
+ * @author Scott Cantor
  */
-public interface AttributeConsumerRole extends ProviderRole {
-       //Stub interface
+public interface IndexedEndpoint extends Endpoint {
+    
+    public int getIndex();
 }
index f58fa31..1234d11 100644 (file)
 
 package edu.internet2.middleware.shibboleth.metadata;
 
+import java.util.Iterator;
+
 import org.apache.xml.security.keys.KeyInfo;
 
 /**
- * <p>Corresponds loosely to SAML Metadata Schema "KeyDescriptorType".
+ * <p>Corresponds to SAML Metadata Schema "KeyDescriptorType".
  * </p><p>
  * Provides information about the cryptographic keys that an EntityDescriptor/Provider
  * uses to sign data. However, this is nested inside a RoleDescriptor 
@@ -39,12 +41,13 @@ import org.apache.xml.security.keys.KeyInfo;
  */
 public interface KeyDescriptor {
 
-       public static int       ENCRYPTION      = 0;
-       public static int       SIGNING         = 1;
+    public final static int UNSPECIFIED = -1;   
+       public final static int ENCRYPTION      = 0;
+       public final static int SIGNING         = 1;
 
        public int getUse();
 
-       public String[] getEncryptionMethod();
-
-       public KeyInfo[] getKeyInfo();
+       public KeyInfo getKeyInfo();
+    
+    public Iterator /* <org.apache.xml.security.encryption.EncryptionMethod.EncryptionMethod> */ getEncryptionMethods();
 }
index 146cc0a..9e026bf 100644 (file)
@@ -26,6 +26,8 @@
 
 package edu.internet2.middleware.shibboleth.metadata;
 
+import org.opensaml.artifact.Artifact;
+
 /**
  * Ported from Scott Cantor's C++ interfaces
  * 
@@ -33,5 +35,19 @@ package edu.internet2.middleware.shibboleth.metadata;
  */
 public interface Metadata {
 
-       Provider lookup(final String providerId);
+       /**
+     *  Find an entity descriptor by its unique identifier.
+     * 
+        * @param id   The unique identifier of the site of interest
+        * @return  The corresponding entity
+        */
+       EntityDescriptor lookup(String id);
+    
+    /**
+     *  Find an entity descriptor that issued a SAML artifact.
+     * 
+     * @param artifact  The artifact whose source site is of interest
+     * @return  The issuing entity
+     */
+    EntityDescriptor lookup(Artifact artifact);
 }
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/Organization.java b/src/edu/internet2/middleware/shibboleth/metadata/Organization.java
new file mode 100644 (file)
index 0000000..610d781
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Created on Feb 28, 2005
+ *
+ */
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.net.URL;
+
+/**
+ * @author Scott Cantor
+ */
+public interface Organization {
+
+    public String getName();
+    public String getName(String lang);
+    
+    public String getDisplayName();
+    public String getDisplayName(String lang);
+
+    public URL getURL();
+    public URL getURL(String lang);
+}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/PDPDescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/PDPDescriptor.java
new file mode 100644 (file)
index 0000000..8a3e8e8
--- /dev/null
@@ -0,0 +1,16 @@
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ * @author Scott Cantor
+ *
+= */
+public interface PDPDescriptor extends RoleDescriptor {
+
+    public EndpointManager getAuthzServiceManager();
+    
+    public EndpointManager getAssertionIDRequestServiceManager();
+    
+    public Iterator /* <String> */ getNameIDFormats();
+}
 package edu.internet2.middleware.shibboleth.metadata;
 
 import java.net.URL;
+import java.util.Iterator;
+
+import org.w3c.dom.Element;
 
 /**
- * <p>Corresponds loosely to SAML Metadata Schema "RoleDescriptorType".
+ * <p>Corresponds to SAML Metadata Schema "RoleDescriptorType".
  * </p><p>
  * A child of the EntityDescriptor element (the Provider object).
  * Example Roles are IDP (Identity Provider), Authentication Authority (HS),
- * Attribute Authority (AA), Attribute Requestor (SHAR), ...
- * 
- * The only role supported in the Origin is 
- * AuthenticationAssertionConsumerService (formerly know as SHIRE)
- * [not formally part of the SAML 2 Metadata standard].
- * For this there is a special extension of SPProviderRole.
+ * Attribute Authority (AA), SP
  * 
  * @author Walter Hoehn (wassa@columbia.edu)
  */
-public interface ProviderRole {
-
-       public Provider getProvider(); // find parent EntityDescriptor/Provider
+public interface RoleDescriptor {
 
-       public String[] getProtocolSupport();
+       public EntityDescriptor getEntityDescriptor(); // parent EntityDescriptor
 
-       public boolean hasSupport(final String version);
+       public Iterator /* <String> */ getProtocolSupportEnumeration();
 
-       public ContactPerson[] getContacts();
+       public boolean hasSupport(final String version);   // does role support protocol?
 
-       public KeyDescriptor[] getKeyDescriptors();
+    public boolean isValid();   // is role valid?
 
-       public Endpoint[] getDefaultEndpoints();
+    public URL getErrorURL();
+    
+    public Iterator /* <KeyDescriptor> */ getKeyDescriptors(); // direct or indirect key references 
+    
+    public Organization getOrganization(); // associated organization
 
-       public URL getErrorURL();
+       public Iterator /* <ContactPerson> */ getContactPersons();
 
+       public Element getElement(); // punch through to XML content if permitted
 }
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/SAML2Metadata.java b/src/edu/internet2/middleware/shibboleth/metadata/SAML2Metadata.java
deleted file mode 100644 (file)
index acafae6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * SAML2Metadata.java
- * 
- * Shibboleth constants used in SAML 2.0 Metadata files
- */
-package edu.internet2.middleware.shibboleth.metadata;
-
-
-public class SAML2Metadata {
-    public static final String xmlns = "urn:oasis:names:tc:SAML:2.0:metadata";
-    public static final String schema = "sstc-saml-schema-metadata-2.0.xsd";
-    public static final String assertionns = "urn:oasis:names:tc:SAML:2.0:assertion";
-    public static final String saml1protocol = "urn:oasis:names:tc:SAML:1.0:protocol";
-    public static final String shib1protocol = "urn:mace:shibboleth:1.0";
-    public static final String shib1Binding ="urn:mace:shibboleth:1.0";
-    public static final String SAML1Binding ="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding";
-    public static final String POST1Binding ="urn:oasis:names:tc:SAML:1.0:profiles:browser-post";
-    public static final String handleNameIDFormat = "urn:mace:shibboleth:1.0:nameIdentifier";
-
-}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/SPProviderRole.java b/src/edu/internet2/middleware/shibboleth/metadata/SPProviderRole.java
deleted file mode 100644 (file)
index ab32a53..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
- * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
- * provided that the following conditions are met: Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution, if any, must include the following acknowledgment: "This product includes software
- * developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2 Project.
- * Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
- * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2, nor
- * the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
- * products derived from this software without specific prior written permission. For written permission, please contact
- * shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2, UCAID, or the
- * University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name, without prior
- * written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS PROVIDED BY THE
- * COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE
- * DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. IN NO
- * EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC.
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package edu.internet2.middleware.shibboleth.metadata;
-
-/**
- * Ported from Scott Cantor's C++ interfaces
- * 
- * @author Walter Hoehn (wassa@columbia.edu)
- */
-public interface SPProviderRole extends ProviderRole {
-
-       public boolean getAuthnRequestsSigned();
-
-       public boolean wantAssertionsSigned();
-
-       public Endpoint[] getAssertionConsumerServiceURLs();
-}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/SPSSODescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/SPSSODescriptor.java
new file mode 100644 (file)
index 0000000..381e612
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ * Corresponds to SAML Metadata Schema "SPSSODescriptorType".
+ * 
+ * @author Scott Cantor
+ */
+public interface SPSSODescriptor extends SSODescriptor {
+
+    public boolean getAuthnRequestsSigned();
+    
+    public boolean getWantAssertionsSigned();
+    
+    public EndpointManager getAssertionConsumerServiceManager();
+    
+    public Iterator /* <AttributeConsumingService> */ getAttributeConsumingServices();
+
+    public AttributeConsumingService getDefaultAttributeConsumingService();
+    
+    public AttributeConsumingService getAttributeConsumingServiceByID(String id);
+}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/SSODescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/SSODescriptor.java
new file mode 100644 (file)
index 0000000..361d9bb
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ * <p>Corresponds to SAML Metadata Schema "SSODescriptorType".
+ * </p><p>Base class with common behavior among SP and IdP roles.
+ * 
+ * @author Scott Cantor
+ */
+public interface SSODescriptor extends RoleDescriptor {
+
+    public EndpointManager getArtifactResolutionServiceManager();
+    
+    public EndpointManager getSingleLogoutServiceManager();
+    
+    public EndpointManager getManageNameIDServiceManager(); 
+
+    public Iterator /* <String> */ getNameIDFormats();
+}
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/ScopedRoleDescriptor.java b/src/edu/internet2/middleware/shibboleth/metadata/ScopedRoleDescriptor.java
new file mode 100644 (file)
index 0000000..8ca4ee4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata;
+
+import java.util.Iterator;
+
+/**
+ * Exposes metadata extension for Domain restrictions on scoped attributes 
+ * 
+ * @author Scott Cantor
+ */
+public interface ScopedRoleDescriptor extends RoleDescriptor {
+
+    public class Scope {
+        public String scope;
+        public boolean regexp;
+        public Scope(String s, boolean b) {scope=s; regexp=b;}
+    }
+
+    public Iterator /* <Scope> */ getScopes();
+}
index 81563e7..75580a8 100644 (file)
 
 package edu.internet2.middleware.shibboleth.metadata.provider;
 
-import java.net.URL;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Stack;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
 
 import org.apache.log4j.Logger;
-import org.apache.xml.security.Init;
-import org.apache.xml.security.keys.KeyInfo;
+import org.opensaml.SAMLException;
+import org.opensaml.XML;
+import org.opensaml.artifact.Artifact;
+import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import edu.internet2.middleware.shibboleth.common.XML;
-import edu.internet2.middleware.shibboleth.metadata.AttributeConsumerRole;
-import edu.internet2.middleware.shibboleth.metadata.ContactPerson;
-import edu.internet2.middleware.shibboleth.metadata.Endpoint;
-import edu.internet2.middleware.shibboleth.metadata.KeyDescriptor;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import edu.internet2.middleware.shibboleth.common.ResourceWatchdog;
+import edu.internet2.middleware.shibboleth.common.ResourceWatchdogExecutionException;
+import edu.internet2.middleware.shibboleth.common.ShibResource;
+import edu.internet2.middleware.shibboleth.common.ShibResource.ResourceNotAvailableException;
+import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
 import edu.internet2.middleware.shibboleth.metadata.Metadata;
 import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
-import edu.internet2.middleware.shibboleth.metadata.SPProviderRole;
+import edu.internet2.middleware.shibboleth.xml.Parser;
 
 /**
  * @author Walter Hoehn (wassa@columbia.edu)
  */
-public class XMLMetadata implements Metadata {
+public class XMLMetadata extends ResourceWatchdog implements Metadata {
 
-       private static Logger           log                     = Logger.getLogger(XMLMetadata.class.getName());
-       public static final String      namespace       = "urn:mace:shibboleth:1.0";
-       private Map                                     providers       = new HashMap();
+       private static Logger   log     = Logger.getLogger(XMLMetadataLoadWrapper.class.getName());
+       private Metadata                currentMeta;
 
-       public XMLMetadata(Element root) throws MetadataException {
-               try {
-                       new ShibGroup(root, new Stack(), providers);
-               } catch (XMLMetadataException e) {
-                       log.error("Encountered a problem loading federation metadata: " + e);
-                       throw new MetadataException("Unable to load federation metadata.");
-               }
-       }
-
-       public Provider lookup(String providerId) {
-               if (providers.containsKey(providerId)) {
-                       return (Provider) providers.get(providerId);
-               }
-               return null;
+       public XMLMetadata(Element configuration) throws MetadataException, ResourceNotAvailableException {
+               this(configuration.getAttribute("uri"));
        }
 
-       private class ShibGroup {
-
-               private String  id;
-
-               ShibGroup(Element root, Stack parents, Map providers) throws XMLMetadataException {
-                       if (!root.getNodeName().equals("SiteGroup")) {
-                               throw new XMLMetadataException("Excpected \"SiteGroup\", found \"" + root.getNodeName() + "\".");
-                       }
-
-                       id = root.getAttribute("Name");
-                       if (id == null || id.equals("")) {
-                               throw new XMLMetadataException("A name must be specified for the site group.");
-                       }
-
-                       parents.push(id);
-                       NodeList nodes = root.getChildNodes();
-                       for (int i = 0; nodes.getLength() > i; i++) {
-                               if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
-
-                                       if (nodes.item(i).getNodeName().equals("SiteGroup")) {
-                                               new ShibGroup((Element) nodes.item(i), parents, providers);
-
-                                       } else if (nodes.item(i).getNodeName().equals("DestinationSite")) {
-
-                                               Provider provider = new ShibTargetXMLProvider((Element) nodes.item(i), (String[]) parents
-                                                               .toArray(new String[0]));
-                                               providers.put(provider.getId(), provider);
+       public XMLMetadata(String sitesFileLocation) throws MetadataException, ResourceNotAvailableException {
+               super(new ShibResource(sitesFileLocation, XMLMetadata.class));
+               try {
+            InputSource src = new InputSource(resource.getInputStream());
+            src.setSystemId(resource.getURL().toString());
+                       Document doc = Parser.loadDom(src,true);
+                       currentMeta = new XMLMetadataProvider(doc.getDocumentElement());
+               } catch (IOException e) {
+                       log.error("Encountered a problem reading metadata source: " + e);
+                       throw new MetadataException("Unable to read metadata: " + e);
+               }
+        catch (SAXException e) {
+            log.error("Encountered a problem parsing metadata source: " + e);
+            throw new MetadataException("Unable to read metadata: + e");
+        }
+        catch (SAMLException e) {
+            log.error("Encountered a problem processing metadata source: " + e);
+            throw new MetadataException("Unable to read metadata: + e");
+        }
+
+               //Start checking for metadata updates
+               start();
 
-                                       } else if (nodes.item(i).getNodeName().equals("OriginSite")) {
-                                               log.debug("Ignoring OriginSite.");
-                                       }
-                               }
-                       }
-                       parents.pop();
-               }
        }
 
-       class ShibTargetXMLProvider implements Provider, ProviderRole, SPProviderRole, AttributeConsumerRole {
-
-               private String          id;
-               private HashSet         contacts;
-               private String[]        groups;
-               private HashSet         assertionConsumers      = new HashSet();
-               private HashSet         keyDescriptors          = new HashSet();
-
-               ShibTargetXMLProvider(Element element, String[] groups) throws XMLMetadataException {
-                       if (!element.getNodeName().equals("DestinationSite")) {
-                               log.error("This provider implementation can only marshall Shibboleth target metadata.");
-                               throw new XMLMetadataException("Unable to load provider.");
-                       }
-
-                       this.groups = groups;
-
-                       id = element.getAttribute("Name");
-                       if (id == null || id.equals("")) {
-                               log.error("No name set for provider.");
-                               throw new XMLMetadataException("Unable to load provider.");
-                       }
-
-                       NodeList contactNodes = element.getElementsByTagNameNS(namespace, "Contact");
-                       if (contactNodes.getLength() > 0) {
-                               contacts = new HashSet();
-                       }
-                       for (int i = 0; contactNodes.getLength() > i; i++) {
-                               try {
-                                       contacts.add(new XMLContactPerson((Element) contactNodes.item(i)));
-                               } catch (XMLMetadataException e) {
-                                       log.error("Error loading parsing contact person for provider (" + id + "): " + e.getMessage());
-                               }
-                       }
-
-                       NodeList consumerNodes = element.getElementsByTagNameNS(namespace, "AssertionConsumerServiceURL");
-                       for (int i = 0; consumerNodes.getLength() > i; i++) {
-                               String location = ((Element) consumerNodes.item(i)).getAttribute("Location");
-                               if (location == null || location.equals("")) {
-                                       log.error("Destination site (" + id + ") contained a malformed Assertion Consumer Service URL.");
-                                       continue;
-                               }
-                               assertionConsumers.add(new ShibEndpoint(location));
-                       }
-                       if (assertionConsumers.size() == 0) {
-                               log.error("No assertion consumer URLs specified for this provider.");
-                               throw new XMLMetadataException("Unable to load provider.");
-                       }
-
-                       NodeList requesterNodes = element.getElementsByTagNameNS(namespace, "AttributeRequester");
-                       for (int i = 0; requesterNodes.getLength() > i; i++) {
-                               String name = ((Element) requesterNodes.item(i)).getAttribute("Name");
-                               if (name == null || name.equals("")) {
-                                       log.error("Destination site (" + id + ") contained a malformed Attribute Requester name.");
-                                       continue;
-                               }
-
-                               DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
-                               try {
-                                       if (!Init.isInitialized()) {
-                                               org.apache.xml.security.Init.init();
-                                       }
-                                       KeyInfo keyInfo = new KeyInfo(docFactory.newDocumentBuilder().newDocument());
-                                       keyInfo.addKeyName(name);
-                                       keyDescriptors.add(new TargetKeyDescriptor(keyInfo));
-
-                               } catch (ParserConfigurationException e) {
-                                       log.error("Unable to create xml document needed for KeyInfo.");
-                               }
-                       }
-                       if (keyDescriptors.size() == 0) {
-                               log.error("No valid attribute requesters specified for this provider.");
-                               throw new XMLMetadataException("Unable to load provider.");
-                       }
-
-               }
-
-               public String getId() {
-                       return id;
-               }
-
-               public String[] getGroups() {
-                       return groups;
-               }
-
-               public ContactPerson[] getContacts() {
-                       if (contacts != null) {
-                               return (ContactPerson[]) contacts.toArray(new ContactPerson[0]);
-                       }
-                       return new ContactPerson[0];
-               }
-
-               public ProviderRole[] getRoles() {
-                       return new ProviderRole[]{this};
-               }
-
-               public Provider getProvider() {
-                       return this;
-               }
-
-               public String[] getProtocolSupport() {
-                       return new String[]{XML.SHIB_NS};
-               }
-
-               public boolean hasSupport(String version) {
-                       if (version.equals(XML.SHIB_NS)) {
-                               return true;
-                       } else {
-                               return false;
-                       }
-               }
-
-               public Endpoint[] getDefaultEndpoints() {
-                       return new Endpoint[0];
-               }
-
-               public URL getErrorURL() {
-                       return null;
-               }
-
-               public boolean getAuthnRequestsSigned() {
-                       return true;
-               }
-
-               public Endpoint[] getAssertionConsumerServiceURLs() {
-                       return (Endpoint[]) assertionConsumers.toArray(new Endpoint[0]);
-               }
-
-               public KeyDescriptor[] getKeyDescriptors() {
-                       return (KeyDescriptor[]) keyDescriptors.toArray(new KeyDescriptor[0]);
-               }
-               
-               public boolean wantAssertionsSigned() {
-                       return false;
-               }
-
-               class ShibEndpoint implements Endpoint {
-
-                       private String  binding;
-                       private String  location;
-
-                       ShibEndpoint(String location) {
-                               this.location = location;
-                       }
-
-                       public String getBinding() {
-                               return XML.SHIB_NS;
-                       }
-
-                       public String getVersion() {
-                               return null;
-                       }
-
-                       public String getLocation() {
-                               return location;
-                       }
-
-                       public String getResponseLocation() {
-                               return null;
-                       }
-               }
-
-               class TargetKeyDescriptor implements KeyDescriptor {
-
-                       private KeyInfo keyInfo;
-
-                       TargetKeyDescriptor(KeyInfo keyInfo) {
-                               this.keyInfo = keyInfo;
-                       }
-
-                       public int getUse() {
-                               return ENCRYPTION;
-                       }
-
-                       public String[] getEncryptionMethod() {
-                               return null;
-                       }
-
-                       public int getKeySize() {
-                               return 0;
-                       }
-
-                       public KeyInfo[] getKeyInfo() {
-                               return new KeyInfo[]{keyInfo};
-                       }
+       public EntityDescriptor lookup(String providerId) {
+               synchronized (currentMeta) {
+                       return currentMeta.lookup(providerId);
                }
        }
 
-       class XMLContactPerson implements ContactPerson {
-
-               private int             type;
-               private String  name;
-               private String  email;
-
-               public XMLContactPerson(Element element) throws XMLMetadataException {
-                       String rawType = element.getAttribute("Type");
-                       if (rawType.equalsIgnoreCase("TECHNICAL")) {
-                               type = ContactPerson.TECHNICAL;
-                       } else if (rawType.equalsIgnoreCase("SUPPORT")) {
-                               type = ContactPerson.SUPPORT;
-                       } else if (rawType.equalsIgnoreCase("ADMINISTRATIVE")) {
-                               type = ContactPerson.ADMINISTRATIVE;
-                       } else if (rawType.equalsIgnoreCase("BILLING")) {
-                               type = ContactPerson.BILLING;
-                       } else if (rawType.equalsIgnoreCase("OTHER")) {
-                               type = ContactPerson.OTHER;
-                       } else {
-                               throw new XMLMetadataException("Unknown contact type.");
-                       }
-                       name = element.getAttribute("Name");
-                       if (name == null || name.equals("")) {
-                               throw new XMLMetadataException("No contact name.");
-                       }
-                       email = element.getAttribute("Email");
-               }
-
-               public int getType() {
-                       return type;
-               }
+    public EntityDescriptor lookup(Artifact artifact) {
+        synchronized (currentMeta) {
+            return currentMeta.lookup(artifact);
+        }
+    }
+    
+       protected void doOnChange() throws ResourceWatchdogExecutionException {
+        Metadata newMeta = null;
+        Document newDoc = null;
 
-               public String getName() {
-                       return name;
-               }
-
-               public String[] getEmails() {
-                       if (email != null & !email.equals("")) {
-                               return new String[]{email};
+               try {
+                       log.info("Detected a change in the metadata. Reloading from (" + resource.getURL().toString() + ").");
+            newMeta = new XMLMetadataProvider(XML.parserPool.parse(resource.getInputStream()).getDocumentElement());
+        }
+        catch (IOException e) {
+                       log.error("Encountered an error retrieving updated federation metadata, continuing to use stale copy: " + e);
+                       return;
+               }
+        catch (SAXException e) {
+            log.error("Encountered an error retrieving updated federation metadata, continuing to use stale copy: " + e);
+            return;
+        }
+        catch (SAMLException e) {
+            log.error("Encountered an error retrieving updated federation metadata, continuing to use stale copy: " + e);
+            return;
+        }
+
+               if (newMeta != null) {
+                       synchronized (currentMeta) {
+                               currentMeta = newMeta;
                        }
-                       return new String[0];
-               }
-
-               public String[] getTelephones() {
-                       return new String[0];
-               }
-       }
-
-       class XMLMetadataException extends Exception {
-
-               XMLMetadataException(String message) {
-                       super(message);
                }
        }
 }
index 210a9a6..a3ee6a3 100644 (file)
 
 package edu.internet2.middleware.shibboleth.metadata.provider;
 
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-import org.xml.sax.InputSource;
-
-import edu.internet2.middleware.shibboleth.common.ResourceWatchdog;
-import edu.internet2.middleware.shibboleth.common.ResourceWatchdogExecutionException;
-import edu.internet2.middleware.shibboleth.common.ShibResource;
 import edu.internet2.middleware.shibboleth.common.ShibResource.ResourceNotAvailableException;
-import edu.internet2.middleware.shibboleth.metadata.Metadata;
 import edu.internet2.middleware.shibboleth.metadata.MetadataException;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
-import edu.internet2.middleware.shibboleth.xml.Parser;
 
 /**
  * @author Walter Hoehn (wassa@columbia.edu)
+ * 
+ * Class left in as a deprecated mechanism to install metadata in older config files.
  */
-public class XMLMetadataLoadWrapper extends ResourceWatchdog implements Metadata {
-
-       private static Logger   log     = Logger.getLogger(XMLMetadataLoadWrapper.class.getName());
-       private Metadata                currentMeta;
-
-       public XMLMetadataLoadWrapper(Element configuration) throws MetadataException, ResourceNotAvailableException {
-               this(configuration.getAttribute("uri"));
-       }
-
-       public XMLMetadataLoadWrapper(String sitesFileLocation) throws MetadataException, ResourceNotAvailableException {
-               super(new ShibResource(sitesFileLocation, XMLMetadataLoadWrapper.class));
-               try {
-                       Document doc = Parser.loadDom(new InputSource(resource.getInputStream()),true);
-                       currentMeta = new XMLMetadata(doc.getDocumentElement());
-               } catch (Exception e) {
-                       log.error("Encountered a problem reading federation metadata source: " + e);
-                       throw new MetadataException("Unable to read federation metadata.");
-               }
-
-               //Start checking for metadata updates
-               start();
-
-       }
-
-       public Provider lookup(String providerId) {
-               synchronized (currentMeta) {
-                       return currentMeta.lookup(providerId);
-               }
-       }
-
-       protected void doOnChange() throws ResourceWatchdogExecutionException {
-        Document newDoc = null;
-               //Log
-               try {
-                       log.info("Detected a change in the federation metadata.  Reloading from (" + resource.getURL().toString()
-                                       + ").");
-               } catch (IOException e) {
-                       log.error("Encountered an error retrieving updated federation metadata, continuing to use stale copy.");
-                       return;
-               }
-
-               //Load new, but keep the old in place
-               try {
-            newDoc = Parser.loadDom(new InputSource(resource.getInputStream()),true);
-        } catch (Exception e) {
-                       log.error("Encountered an error retrieving updated federation metadata, continuing to use stale copy.");
-                       return;
-               }
-
-               //If things went well, replace the live copy
-               Metadata newMeta = null;
-               try {
-                       newMeta = new XMLMetadata(newDoc.getDocumentElement());
-               } catch (MetadataException e1) {
-                       log.error("Encountered an error loading updated federation metadata, continuing to use stale copy.");
-                       return;
-               }
-
-               if (newMeta != null) {
-                       synchronized (currentMeta) {
-                               currentMeta = newMeta;
-                       }
-               }
-       }
-
+public class XMLMetadataLoadWrapper extends XMLMetadata {
+    public XMLMetadataLoadWrapper(String sitesFileLocation) throws MetadataException, ResourceNotAvailableException {
+        super(sitesFileLocation);
+    }
+    public XMLMetadataLoadWrapper(Element configuration) throws MetadataException, ResourceNotAvailableException {
+        super(configuration);
+    }
 }
diff --git a/src/edu/internet2/middleware/shibboleth/metadata/provider/XMLMetadataProvider.java b/src/edu/internet2/middleware/shibboleth/metadata/provider/XMLMetadataProvider.java
new file mode 100644 (file)
index 0000000..068c90f
--- /dev/null
@@ -0,0 +1,1310 @@
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met: Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution, if any, must include the following acknowledgment: "This product includes
+ * software developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu>Internet2
+ * Project. Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2,
+ * nor the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
+ * products derived from this software without specific prior written permission. For written permission, please
+ * contact shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name,
+ * without prior written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS
+ * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS
+ * WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED
+ * INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.metadata.provider;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.NoSuchAlgorithmException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.log4j.Logger;
+import org.apache.xml.security.encryption.EncryptionMethod;
+import org.apache.xml.security.exceptions.XMLSecurityException;
+import org.apache.xml.security.keys.KeyInfo;
+import org.opensaml.SAMLAttribute;
+import org.opensaml.SAMLBinding;
+import org.opensaml.SAMLBrowserProfile;
+import org.opensaml.SAMLException;
+import org.opensaml.XML;
+import org.opensaml.artifact.Artifact;
+import org.opensaml.artifact.SAMLArtifactType0001;
+import org.opensaml.artifact.SAMLArtifactType0002;
+import org.opensaml.artifact.Util;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import edu.internet2.middleware.shibboleth.common.Constants;
+import edu.internet2.middleware.shibboleth.metadata.*;
+
+/**
+ * @author Scott Cantor
+ */
+public class XMLMetadataProvider implements Metadata {
+
+       private static Logger log = Logger.getLogger(XMLMetadataProvider.class.getName());
+       private Map     /* <String,ArrayList<EntityDescriptor> > */ sites = new HashMap();
+    private Map /* <String,ArrayList<EntityDescriptor> > */ sources = new HashMap();
+    private XMLEntityDescriptor rootProvider = null;
+    private XMLEntitiesDescriptor rootGroup = null;
+
+       public XMLMetadataProvider(Element e) throws SAMLException {
+        if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"EntitiesDescriptor"))
+            rootGroup=new XMLEntitiesDescriptor(e,this, Long.MAX_VALUE, null);
+        else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"EntityDescriptor"))
+            rootProvider=new XMLEntityDescriptor(e,this, Long.MAX_VALUE, null);
+        else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"SiteGroup"))
+            rootGroup=new XMLEntitiesDescriptor(e,this, Long.MAX_VALUE, null);
+        else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"OriginSite"))
+            rootProvider=new XMLEntityDescriptor(e,this, Long.MAX_VALUE, null);
+        else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"DestinationSite"))
+            rootProvider=new XMLEntityDescriptor(e,this, Long.MAX_VALUE, null);
+        else {
+            log.error("Construction requires a valid SAML metadata file");
+            throw new MetadataException("Construction requires a valid SAML metadata file");
+        }
+       }
+
+       public EntityDescriptor lookup(String id) {
+               ArrayList list = (ArrayList)sites.get(id);
+               if (list != null) {
+                   long now = System.currentTimeMillis();
+            for (int i=0; i<list.size(); i++) {
+                if (now < ((XMLEntityDescriptor)list.get(i)).getValidUntil())
+                    return (EntityDescriptor)list.get(i);
+            }
+        }
+               return null;
+       }
+
+    public EntityDescriptor lookup(Artifact artifact) {
+        ArrayList list = null;
+        
+        if (artifact instanceof SAMLArtifactType0001) {
+            list = (ArrayList)sources.get(((SAMLArtifactType0001)artifact).getSourceId());
+        }
+        else if (artifact instanceof SAMLArtifactType0002) {
+            list = (ArrayList)sources.get(((SAMLArtifactType0002)artifact).getSourceLocation().toString());
+        }
+        else {
+            log.error("unsupported artifact type (" + artifact.getTypeCode().toString() + ")");
+        }
+
+        if (list != null) {
+            long now = System.currentTimeMillis();
+            for (int i=0; i<list.size(); i++) {
+                if (now < ((XMLEntityDescriptor)list.get(i)).getValidUntil())
+                    return (EntityDescriptor)list.get(i);
+            }
+        }
+        return null;
+    }
+
+    class XMLEndpoint implements Endpoint {
+        private Element root = null;
+        private String binding = null;
+        private String location = null;
+        private String resploc = null;
+
+        XMLEndpoint(Element e) {
+            root = e;
+            binding = XML.assign(e.getAttributeNS(null,"Binding"));
+            location = XML.assign(e.getAttributeNS(null,"Location"));
+            resploc = XML.assign(e.getAttributeNS(null,"ResponseLocation"));
+        }
+        
+        XMLEndpoint(String binding, String location) {
+            this.binding = binding;
+            this.location = location;
+        }
+
+        public String getBinding() {
+            return binding;
+        }
+
+        public String getLocation() {
+            return location;
+        }
+
+        public String getResponseLocation() {
+            return resploc;
+        }
+        
+        public Element getElement() {
+            return root;
+        }
+    }
+
+    class XMLIndexedEndpoint extends XMLEndpoint implements IndexedEndpoint {
+        private int index = 0;
+        
+        XMLIndexedEndpoint(Element e) {
+            super(e);
+            index = Integer.parseInt(e.getAttributeNS(null,"index"));
+        }
+
+        public int getIndex() {
+            return index;
+        }
+    }
+    
+    class XMLEndpointManager implements EndpointManager {
+        private ArrayList endpoints = new ArrayList();
+        Endpoint soft = null;   // Soft default (not explicit)
+        Endpoint hard = null;   // Hard default (explicit)
+
+        public Iterator getEndpoints() {
+            return endpoints.iterator();
+        }
+        
+        public Endpoint getDefaultEndpoint() {
+            if (hard != null) return hard;
+            if (soft != null) return soft;
+            if (!endpoints.isEmpty()) return (Endpoint)endpoints.get(0);
+            return null;
+        }
+        
+        public Endpoint getEndpointByIndex(int index) {
+            for (int i=0; i < endpoints.size(); i++) {
+                if (endpoints.get(i) instanceof IndexedEndpoint && index==((IndexedEndpoint)endpoints.get(i)).getIndex())
+                    return (Endpoint)endpoints.get(i);
+            }
+            return null;
+        }
+        
+        public Endpoint getEndpointByBinding(String binding) {
+            for (int i=0; i < endpoints.size(); i++) {
+                if (binding.equals(((Endpoint)endpoints.get(i)).getBinding()))
+                    return (Endpoint)endpoints.get(i);
+            }
+            return null;
+        }
+        
+        protected void add(Endpoint e) {
+            endpoints.add(e);
+            if (hard == null && e.getElement() != null) {
+                String v=XML.assign(e.getElement().getAttributeNS(null,"isDefault"));
+                if (v != null && (v.equals("1") || v.equals("true")))  // explicit default
+                    hard=e;
+                else if (v == null && soft == null)            // implicit default
+                    soft=e;
+            }
+            else if (hard == null && soft == null) {
+                // No default yet, so this one qualifies as an implicit.
+                soft=e;
+            }
+        }
+    }
+    
+    class XMLKeyDescriptor implements KeyDescriptor {
+
+        private int use = KeyDescriptor.UNSPECIFIED;
+        private KeyInfo keyInfo = null;
+        private ArrayList /* <XMLEncryptionMethod> */ methods = new ArrayList();
+
+        XMLKeyDescriptor(Element e) {
+            if (XML.safeCompare(e.getAttributeNS(null,"use"),"encryption"))
+                use = KeyDescriptor.ENCRYPTION;
+            else if (XML.safeCompare(e.getAttributeNS(null,"use"),"signing"))
+                use = KeyDescriptor.SIGNING;
+            
+            e = XML.getFirstChildElement(e);
+            try {
+                keyInfo = new KeyInfo(e, null);
+            }
+            catch (XMLSecurityException e1) {
+                log.error("unable to process ds:KeyInfo element: " + e1.getMessage());
+            }
+            
+            e = XML.getNextSiblingElement(e);
+            while (e != null && XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"EncryptionMethod")) {
+                methods.add(new XMLEncryptionMethod(e));
+            }
+        }
+
+        public int getUse() {
+            return use;
+        }
+
+        public Iterator getEncryptionMethods() {
+            return methods.iterator();
+        }
+
+        public KeyInfo getKeyInfo() {
+            return keyInfo;
+        }
+    }
+
+    class XMLEncryptionMethod implements EncryptionMethod {
+
+        String alg = null;
+        String params = null;
+        int size = 0;
+        
+        public XMLEncryptionMethod(Element e) {
+            alg = XML.assign(e.getAttributeNS(null, "Algorithm"));
+            e = XML.getFirstChildElement(e);
+            while (e != null) {
+                if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.XMLENC_NS,"KeySize")) {
+                    if (e.hasChildNodes())
+                        size = Integer.parseInt(e.getFirstChild().getNodeValue());
+                }
+                else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.XMLENC_NS,"OAEParams")) {
+                    if (e.hasChildNodes())
+                        params = XML.assign(e.getFirstChild().getNodeValue());
+                }
+                e = XML.getNextSiblingElement(e);
+            }
+        }
+        
+        public String getAlgorithm() {
+            return alg;
+        }
+
+        public int getKeySize() {
+            return size;
+        }
+
+        public byte[] getOAEPparams() {
+            return params.getBytes();
+        }
+
+        public Iterator getEncryptionMethodInformation() {
+            return null;
+        }
+
+        public void setKeySize(int arg0) {
+            throw new UnsupportedOperationException("EncryptionMethod implementation is read-only.");
+        }
+
+        public void setOAEPparams(byte[] arg0) {
+            throw new UnsupportedOperationException("EncryptionMethod implementation is read-only.");
+        }
+
+        public void addEncryptionMethodInformation(Element arg0) {
+            throw new UnsupportedOperationException("EncryptionMethod implementation is read-only.");
+        }
+
+        public void removeEncryptionMethodInformation(Element arg0) {
+            throw new UnsupportedOperationException("EncryptionMethod implementation is read-only.");
+        }
+    }
+
+    class XMLOrganization implements Organization {
+        private Element root = null;
+        private HashMap /* <String,String> */ names = new HashMap();
+        private HashMap /* <String,String> */ displays = new HashMap();
+        private HashMap /* <String,URL> */ urls = new HashMap();
+
+        public XMLOrganization(Element e) throws MetadataException {
+            root = e;
+            e=XML.getFirstChildElement(e);
+            while (e != null) {
+                if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"OrganizationName")) {
+                    if (e.hasChildNodes()) {
+                        names.put(e.getAttributeNS(XML.XML_NS,"lang"),XML.assign(e.getFirstChild().getNodeValue()));
+                    }
+                }
+                else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"OrganizationDisplayName")) {
+                    if (e.hasChildNodes()) {
+                        displays.put(e.getAttributeNS(XML.XML_NS,"lang"),XML.assign(e.getFirstChild().getNodeValue()));
+                    }
+                }
+                else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"OrganizationURL")) {
+                    if (e.hasChildNodes()) {
+                        URL u;
+                        try {
+                            u = new URL(e.getFirstChild().getNodeValue());
+                        }
+                        catch (MalformedURLException e1) {
+                            throw new MetadataException("OrganizationURL was invalid: " + e1);
+                        }
+                        urls.put(e.getAttributeNS(XML.XML_NS,"lang"),u);
+                    }
+                }
+                e=XML.getNextSiblingElement(e);
+            }
+        }
+        
+        public String getName() {
+            return getName("en");
+        }
+
+        public String getName(String lang) {
+            return (String)names.get(lang);
+        }
+
+        public String getDisplayName() {
+            return getDisplayName("en");
+        }
+
+        public String getDisplayName(String lang) {
+            return (String)displays.get(lang);
+        }
+
+        public URL getURL() {
+            return getURL("en");
+        }
+
+        public URL getURL(String lang) {
+            return (URL)urls.get(lang);
+        }
+        
+    }
+    
+       class XMLContactPerson implements ContactPerson {
+           private Element root = null;
+               private int             type;
+        private String  company = null;
+               private String  givenName = null;
+        private String  surName = null;
+               private ArrayList /* <String> */ emails = new ArrayList();
+        private ArrayList /* <String> */ telephones = new ArrayList();
+
+               public XMLContactPerson(Element e) throws MetadataException {
+            root = e;
+            String rawType = null;
+            
+            // Old metadata or new?
+            if (XML.isElementNamed(root, edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"Contact")) {
+                rawType = root.getAttributeNS(null,"Type");
+                surName = XML.assign(root.getAttributeNS(null,"Name"));
+                if (XML.isEmpty(surName)) {
+                    throw new MetadataException("Contact is missing Name attribute.");
+                }
+                if (root.hasAttributeNS(null,"Email"))
+                    emails.add(e.getAttributeNS(null,"Email"));
+            }
+            else {
+                rawType = root.getAttributeNS(null,"contactType");
+                Node n=null;
+                e=XML.getFirstChildElement(root);
+                while (e != null) {
+                    if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"Company")) {
+                        if (e.hasChildNodes())
+                            company=XML.assign(e.getFirstChild().getNodeValue());
+                    }
+                    else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"GivenName")) {
+                        if (e.hasChildNodes())
+                            givenName=XML.assign(e.getFirstChild().getNodeValue());
+                    }
+                    else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"SurName")) {
+                        if (e.hasChildNodes())
+                            surName=XML.assign(e.getFirstChild().getNodeValue());
+                    }
+                    else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"EmailAddress")) {
+                        if (e.hasChildNodes())
+                            emails.add(XML.assign(e.getFirstChild().getNodeValue()));
+                    }
+                    else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"TelephoneNumber")) {
+                        if (e.hasChildNodes())
+                            telephones.add(XML.assign(e.getFirstChild().getNodeValue()));
+                    }
+                    e=XML.getNextSiblingElement(e);
+                }
+            }
+                       
+                       if (rawType.equalsIgnoreCase("TECHNICAL")) {
+                               type = ContactPerson.TECHNICAL;
+                       } else if (rawType.equalsIgnoreCase("SUPPORT")) {
+                               type = ContactPerson.SUPPORT;
+                       } else if (rawType.equalsIgnoreCase("ADMINISTRATIVE")) {
+                               type = ContactPerson.ADMINISTRATIVE;
+                       } else if (rawType.equalsIgnoreCase("BILLING")) {
+                               type = ContactPerson.BILLING;
+                       } else if (rawType.equalsIgnoreCase("OTHER")) {
+                               type = ContactPerson.OTHER;
+                       } else {
+                               throw new MetadataException("Contact has unknown contact type.");
+                       }
+               }
+
+               public int getType() {
+                       return type;
+               }
+
+               public String getGivenName() {
+                       return givenName;
+               }
+
+        public String getSurName() {
+            return surName;
+        }
+        
+        public String getCompany() {
+            return company;
+        }
+
+        public Iterator getEmailAddresses() {
+                       return emails.iterator();
+               }
+
+               public Iterator getTelephoneNumbers() {
+                       return telephones.iterator();
+               }
+        
+        public Element getElement() {
+            return root;
+        }
+       }
+    
+    class Role implements RoleDescriptor {
+        private Element root = null;
+        private XMLEntityDescriptor provider = null;
+        private URL errorURL = null;
+        private Organization org = null;
+        private ArrayList /* <ContactPerson> */ contacts = new ArrayList();
+        private long validUntil = Long.MAX_VALUE;
+        protected ArrayList /* <String> */ protocolEnum = new ArrayList();
+        protected ArrayList /* <KeyDescriptor> */ keys = new ArrayList();
+
+        public Role(XMLEntityDescriptor provider, long validUntil, Element e) throws MetadataException {
+            root = e;
+            this.validUntil = validUntil;
+            this.provider = provider;
+            
+            // Check the root element namespace. If SAML2, assume it's the std schema.
+            if (e != null && edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS.equals(e.getNamespaceURI())) {
+               
+                if (e.hasAttributeNS(null,"validUntil")) {
+                    SimpleDateFormat formatter = null;
+                    String dateTime = XML.assign(e.getAttributeNS(null,"validUntil"));
+                    int dot = dateTime.indexOf('.');
+                    if (dot > 0)
+                        formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+                    else
+                        formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+                    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+                    try {
+                        validUntil=Math.min(validUntil,formatter.parse(dateTime).getTime());
+                    }
+                    catch (ParseException e1) {
+                        log.warn("Role descriptor contains invalid expiration time");
+                    }
+                }
+                
+                if (e.hasAttributeNS(null,"errorURL")) {
+                    try {
+                        errorURL=new URL(e.getAttributeNS(null,"errorURL"));
+                    }
+                    catch (MalformedURLException e1) {
+                        log.error("Role descriptor contains malformed errorURL");
+                    }
+                }
+                
+                // Chop the protocol list into pieces...assume any whitespace can appear in between.   
+                protocolEnum.addAll(Arrays.asList(e.getAttributeNS(null,"protocolSupportEnumeration").split("\\s")));
+                
+                e = XML.getFirstChildElement(root,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"KeyDescriptor");
+                while (e != null) {
+                    keys.add(new XMLKeyDescriptor(e));
+                    e = XML.getNextSiblingElement(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"KeyDescriptor");
+                }
+
+                e = XML.getFirstChildElement(root,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"Organization");
+                if (e != null)
+                    org=new XMLOrganization(e);
+
+                e = XML.getFirstChildElement(root,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"ContactPerson");
+                while (e != null) {
+                    contacts.add(new XMLContactPerson(e));
+                    e = XML.getNextSiblingElement(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"ContactPerson");
+                }
+            }
+        }
+        
+        public EntityDescriptor getEntityDescriptor() {
+            return provider;
+        }
+
+        public Iterator getProtocolSupportEnumeration() {
+            return protocolEnum.iterator();
+        }
+
+        public boolean hasSupport(String version) {
+            return protocolEnum.contains(version);
+        }
+
+        public boolean isValid() {
+            return System.currentTimeMillis() < validUntil;
+        }
+
+        public URL getErrorURL() {
+            return (errorURL != null) ? errorURL : provider.getErrorURL();
+        }
+
+        public Iterator getKeyDescriptors() {
+            return keys.iterator();
+        }
+
+        public Organization getOrganization() {
+            return (org != null) ? org : provider.getOrganization();
+        }
+
+        public Iterator getContactPersons() {
+            return (contacts.isEmpty()) ? provider.getContactPersons() : contacts.iterator();
+        }
+
+        public Element getElement() {
+            return root;
+        }
+    }
+    
+    class SSORole extends Role implements SSODescriptor {
+        private XMLEndpointManager artifact = new XMLEndpointManager();
+        private XMLEndpointManager logout = new XMLEndpointManager();
+        private XMLEndpointManager nameid = new XMLEndpointManager();
+        private ArrayList /* <String> */ formats = new ArrayList();
+
+        public SSORole(XMLEntityDescriptor provider, long validUntil, Element e) throws MetadataException {
+            super(provider, validUntil, e);
+            
+            // Check the root element namespace. If SAML2, assume it's the std schema.
+            if (edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS.equals(e.getNamespaceURI())) {
+                int i;
+                NodeList nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"ArtifactResolutionService");
+                for (i=0; i<nlist.getLength(); i++)
+                    artifact.add(new XMLIndexedEndpoint((Element)nlist.item(i)));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"SingleLogoutService");
+                for (i=0; i<nlist.getLength(); i++)
+                    logout.add(new XMLEndpoint((Element)nlist.item(i)));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"ManageNameIDService");
+                for (i=0; i<nlist.getLength(); i++)
+                    nameid.add(new XMLEndpoint((Element)nlist.item(i)));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"NameIDFormat");
+                for (i=0; i<nlist.getLength(); i++) {
+                    if (nlist.item(i).hasChildNodes())
+                        formats.add(nlist.item(i).getNodeValue());
+                }
+            }
+            else {
+                // For old style, we just do SAML 1.1 compatibility with Shib handles.
+                protocolEnum.add(XML.SAML11_PROTOCOL_ENUM);
+                formats.add(Constants.SHIB_NAMEID_FORMAT_URI);
+            }
+        }
+
+        public EndpointManager getArtifactResolutionServiceManager() {
+            return artifact;
+        }
+
+        public EndpointManager getSingleLogoutServiceManager() {
+            return logout;
+        }
+
+        public EndpointManager getManageNameIDServiceManager() {
+            return nameid;
+        }
+
+        public Iterator getNameIDFormats() {
+            return formats.iterator();
+        }
+    }
+    
+    class IDPRole extends SSORole implements IDPSSODescriptor, ScopedRoleDescriptor {
+        private ArrayList /* <Scope> */ scopes = new ArrayList();
+        private XMLEndpointManager sso = new XMLEndpointManager();
+        private XMLEndpointManager mapping = new XMLEndpointManager();
+        private XMLEndpointManager idreq = new XMLEndpointManager();
+        private ArrayList /* <String> */ attrprofs = new ArrayList();
+        private ArrayList /* <SAMLAttribute> */ attrs = new ArrayList();
+        private boolean wantAuthnRequestsSigned = false;
+        private String sourceId = null;
+
+        public IDPRole(XMLEntityDescriptor provider, long validUntil, Element e) throws SAMLException {
+            super(provider, validUntil, e);
+            NodeList domains=null;
+            
+            // Check the root element namespace. If SAML2, assume it's the std schema.
+            if (edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS.equals(e.getNamespaceURI())) {
+                String flag=XML.assign(e.getAttributeNS(null,"WantAuthnRequestsSigned"));
+                wantAuthnRequestsSigned=(XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"));
+                
+                // Check for extensions.
+                Element ext=XML.getFirstChildElement(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"Extensions");
+                if (ext != null) {
+                    Element ext1=XML.getFirstChildElement(ext,XML.SAML_ARTIFACT_SOURCEID,"SourceID");
+                    if (ext1 != null && ext1.hasChildNodes())
+                        sourceId=ext1.getFirstChild().getNodeValue();
+                    // Save off any domain elements for later.
+                    domains = ext.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIBMETA_NS,"Domain");
+                }
+                
+                int i;
+                NodeList nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"SingleSignOnService");
+                for (i=0; i<nlist.getLength(); i++)
+                    sso.add(new XMLEndpoint((Element)(nlist.item(i))));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"NameIDMappingService");
+                for (i=0; i<nlist.getLength(); i++)
+                    mapping.add(new XMLEndpoint((Element)(nlist.item(i))));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AssertionIDRequestService");
+                for (i=0; i<nlist.getLength(); i++)
+                    idreq.add(new XMLEndpoint((Element)(nlist.item(i))));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AttributeProfile");
+                for (i=0; i<nlist.getLength(); i++) {
+                    if (nlist.item(i).hasChildNodes())
+                        attrprofs.add(nlist.item(i).getFirstChild().getNodeValue());
+                }
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"Attribute");
+                for (i=0; i<nlist.getLength(); i++) {
+                    // For now, we need to convert these to plain SAML 1.1 attributes.
+                    Element src=(Element)(nlist.item(i));
+                    Element copy=e.getOwnerDocument().createElementNS(XML.SAML_NS,"Attribute");
+                    copy.setAttributeNS(null,"AttributeName",src.getAttributeNS(null,"Name"));
+                    copy.setAttributeNS(null,"AttributeNamespace",src.getAttributeNS(null,"NameFormat"));
+                    src=XML.getFirstChildElement(src,edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"AttributeValue");
+                    while (src != null) {
+                        src=XML.getNextSiblingElement(src,edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"AttributeValue");
+                        Element val=e.getOwnerDocument().createElementNS(XML.SAML_NS,"AttributeValue");
+                        NamedNodeMap attrs = src.getAttributes();
+                        for (int j=0; j<attrs.getLength(); j++)
+                            val.setAttributeNodeNS((Attr)(e.getOwnerDocument().importNode(attrs.item(j),true)));
+                        while (src.hasChildNodes())
+                            val.appendChild(src.getFirstChild());
+                        copy.appendChild(val);
+                    }
+                    attrs.add(SAMLAttribute.getInstance(copy));
+                }
+            }
+            else {
+                attrprofs.add(Constants.SHIB_ATTRIBUTE_NAMESPACE_URI);
+                int i;
+                domains = e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"Domain");
+                NodeList nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"HandleService");
+                for (i=0; i<nlist.getLength(); i++) {
+                    // Manufacture an endpoint for the "Shib" binding.
+                    sso.add(
+                        new XMLEndpoint(Constants.SHIB_AUTHNREQUEST_PROFILE_URI,((Element)nlist.item(i)).getAttributeNS(null,"Location"))
+                        );
+
+                    // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
+                    Element kd=e.getOwnerDocument().createElementNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"KeyDescriptor");
+                    Element ki=e.getOwnerDocument().createElementNS(XML.XMLSIG_NS,"KeyInfo");
+                    Element kn=e.getOwnerDocument().createElementNS(XML.XMLSIG_NS,"KeyName");
+                    kn.appendChild(
+                        e.getOwnerDocument().createTextNode(((Element)nlist.item(i)).getAttributeNS(null,"Name"))
+                        );
+                    ki.appendChild(kn);
+                    kd.appendChild(ki);
+                    kd.setAttributeNS(null,"use","signing");
+                    keys.add(new XMLKeyDescriptor(kd));
+                }
+            }
+            
+            if (domains != null) {
+                for (int i=0; i < domains.getLength(); i++) {
+                    String dom=(domains.item(i).hasChildNodes()) ? domains.item(i).getFirstChild().getNodeValue() : null;
+                    if (dom != null) {
+                        String regexp=XML.assign(((Element)domains.item(i)).getAttributeNS(null,"regexp"));
+                        scopes.add(
+                            new Scope(dom,(XML.safeCompare(regexp,"true") || XML.safeCompare(regexp,"1")))
+                            );
+                    }
+                }
+            }
+        }
+
+        public Iterator getScopes() {
+            return scopes.iterator();
+        }
+
+        public boolean getWantAuthnRequestsSigned() {
+            return wantAuthnRequestsSigned;
+        }
+
+        public EndpointManager getSingleSignOnServiceManager() {
+            return sso;
+        }
+
+        public EndpointManager getNameIDMappingServiceManager() {
+            return mapping;
+        }
+
+        public EndpointManager getAssertionIDRequestServiceManager() {
+            return idreq;
+        }
+
+        public Iterator getAttributeProfiles() {
+            return attrprofs.iterator();
+        }
+
+        public Iterator getAttributes() {
+            return attrs.iterator();
+        }
+    }
+
+    class AARole extends SSORole implements AttributeAuthorityDescriptor, ScopedRoleDescriptor {
+        private ArrayList /* <Scope> */ scopes = new ArrayList();
+        private XMLEndpointManager query = new XMLEndpointManager();
+        private XMLEndpointManager idreq = new XMLEndpointManager();
+        private ArrayList /* <String> */ attrprofs = new ArrayList();
+        private ArrayList /* <String> */ formats = new ArrayList();
+        private ArrayList /* <SAMLAttribute> */ attrs = new ArrayList();
+
+        public AARole(XMLEntityDescriptor provider, long validUntil, Element e) throws SAMLException {
+            super(provider, validUntil, e);
+            NodeList domains=null;
+            
+            // Check the root element namespace. If SAML2, assume it's the std schema.
+            if (edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS.equals(e.getNamespaceURI())) {
+                
+                // Check for extensions.
+                Element ext=XML.getFirstChildElement(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"Extensions");
+                if (ext != null) {
+                    // Save off any domain elements for later.
+                    domains = ext.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIBMETA_NS,"Domain");
+                }
+                
+                int i;
+                NodeList nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AttributeService");
+                for (i=0; i<nlist.getLength(); i++)
+                    query.add(new XMLEndpoint((Element)(nlist.item(i))));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AssertionIDRequestService");
+                for (i=0; i<nlist.getLength(); i++)
+                    idreq.add(new XMLEndpoint((Element)(nlist.item(i))));
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AttributeProfile");
+                for (i=0; i<nlist.getLength(); i++) {
+                    if (nlist.item(i).hasChildNodes())
+                        attrprofs.add(nlist.item(i).getFirstChild().getNodeValue());
+                }
+
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"Attribute");
+                for (i=0; i<nlist.getLength(); i++) {
+                    // For now, we need to convert these to plain SAML 1.1 attributes.
+                    Element src=(Element)(nlist.item(i));
+                    Element copy=e.getOwnerDocument().createElementNS(XML.SAML_NS,"Attribute");
+                    copy.setAttributeNS(null,"AttributeName",src.getAttributeNS(null,"Name"));
+                    copy.setAttributeNS(null,"AttributeNamespace",src.getAttributeNS(null,"NameFormat"));
+                    src=XML.getFirstChildElement(src,edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"AttributeValue");
+                    while (src != null) {
+                        src=XML.getNextSiblingElement(src,edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"AttributeValue");
+                        Element val=e.getOwnerDocument().createElementNS(XML.SAML_NS,"AttributeValue");
+                        NamedNodeMap attrs = src.getAttributes();
+                        for (int j=0; j<attrs.getLength(); j++)
+                            val.setAttributeNodeNS((Attr)(e.getOwnerDocument().importNode(attrs.item(j),true)));
+                        while (src.hasChildNodes())
+                            val.appendChild(src.getFirstChild());
+                        copy.appendChild(val);
+                    }
+                    attrs.add(SAMLAttribute.getInstance(copy));
+                }
+            }
+            else {
+                // For old style, we just do SAML 1.1 compatibility with Shib handles.
+                protocolEnum.add(XML.SAML11_PROTOCOL_ENUM);
+                formats.add(Constants.SHIB_NAMEID_FORMAT_URI);
+                attrprofs.add(Constants.SHIB_ATTRIBUTE_NAMESPACE_URI);
+                int i;
+                NodeList nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AttributeAuthority");
+                for (i=0; i<nlist.getLength(); i++) {
+                    // Manufacture an endpoint for the SOAP binding.
+                    query.add(
+                        new XMLEndpoint(
+                            SAMLBinding.SOAP,
+                            ((Element)nlist.item(i)).getAttributeNS(null,"Location")
+                            )
+                        );
+
+                    // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
+                    Element kd=e.getOwnerDocument().createElementNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"KeyDescriptor");
+                    Element ki=e.getOwnerDocument().createElementNS(XML.XMLSIG_NS,"KeyInfo");
+                    Element kn=e.getOwnerDocument().createElementNS(XML.XMLSIG_NS,"KeyName");
+                    kn.appendChild(
+                        e.getOwnerDocument().createTextNode(((Element)nlist.item(i)).getAttributeNS(null,"Name"))
+                        );
+                    ki.appendChild(kn);
+                    kd.appendChild(ki);
+                    kd.setAttributeNS(null,"use","signing");
+                    keys.add(new XMLKeyDescriptor(kd));
+                }
+            }
+
+            if (domains != null) {
+                for (int i=0; i < domains.getLength(); i++) {
+                    String dom=(domains.item(i).hasChildNodes()) ? domains.item(i).getFirstChild().getNodeValue() : null;
+                    if (dom != null) {
+                        String regexp=XML.assign(((Element)domains.item(i)).getAttributeNS(null,"regexp"));
+                        scopes.add(
+                            new Scope(dom,(XML.safeCompare(regexp,"true") || XML.safeCompare(regexp,"1")))
+                            );
+                    }
+                }
+            }
+        }
+
+        public Iterator getScopes() {
+            return scopes.iterator();
+        }
+
+        public EndpointManager getAttributeServiceManager() {
+            return query;
+        }
+
+        public EndpointManager getAssertionIDRequestServiceManager() {
+            return idreq;
+        }
+
+        public Iterator getAttributeProfiles() {
+            return attrprofs.iterator();
+        }
+
+        public Iterator getAttributes() {
+            return attrs.iterator();
+        }
+    }
+    
+    class SPRole extends SSORole implements SPSSODescriptor {
+        private boolean authnRequestsSigned = false;
+        private boolean wantAssertionsSigned = false;
+        private XMLEndpointManager asc = new XMLEndpointManager();
+        
+        public SPRole(XMLEntityDescriptor provider, long validUntil, Element e) throws MetadataException {
+            super(provider, validUntil, e);
+            // TODO Auto-generated constructor stub
+
+            // Check the root element namespace. If SAML2, assume it's the std schema.
+            if (edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS.equals(e.getNamespaceURI())) {
+                String flag=XML.assign(e.getAttributeNS(null,"AuthnRequestsSigned"));
+                authnRequestsSigned=(XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"));
+                flag=XML.assign(e.getAttributeNS(null,"WantAssertionsSigned"));
+                wantAssertionsSigned=(XML.safeCompare(flag,"1") || XML.safeCompare(flag,"true"));
+                
+                int i;
+                NodeList nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AssertionConsumerService");
+                for (i=0; i<nlist.getLength(); i++)
+                    asc.add(new XMLIndexedEndpoint((Element)(nlist.item(i))));
+
+                /*
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"Attribute");
+                for (i=0; i<nlist.getLength(); i++) {
+                    // For now, we need to convert these to plain SAML 1.1 attributes.
+                    Element src=(Element)(nlist.item(i));
+                    Element copy=e.getOwnerDocument().createElementNS(XML.SAML_NS,"Attribute");
+                    copy.setAttributeNS(null,"AttributeName",src.getAttributeNS(null,"Name"));
+                    copy.setAttributeNS(null,"AttributeNamespace",src.getAttributeNS(null,"NameFormat"));
+                    src=XML.getFirstChildElement(src,edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"AttributeValue");
+                    while (src != null) {
+                        src=XML.getNextSiblingElement(src,edu.internet2.middleware.shibboleth.common.XML.SAML2ASSERT_NS,"AttributeValue");
+                        Element val=e.getOwnerDocument().createElementNS(XML.SAML_NS,"AttributeValue");
+                        NamedNodeMap attrs = src.getAttributes();
+                        for (int j=0; j<attrs.getLength(); j++)
+                            val.setAttributeNodeNS((Attr)(e.getOwnerDocument().importNode(attrs.item(j),true)));
+                        while (src.hasChildNodes())
+                            val.appendChild(src.getFirstChild());
+                        copy.appendChild(val);
+                    }
+                    attrs.add(SAMLAttribute.getInstance(copy));
+                }
+                */
+            }
+            else {
+                int i;
+                NodeList nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AssertionConsumerServiceURL");
+                for (i=0; i<nlist.getLength(); i++) {
+                    // Manufacture an endpoint for the POST profile.
+                    asc.add(
+                        new XMLEndpoint(SAMLBrowserProfile.PROFILE_POST_URI,((Element)nlist.item(i)).getAttributeNS(null,"Location"))
+                        );
+                }
+                
+                nlist=e.getElementsByTagNameNS(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AttributeRequester");
+                for (i=0; i<nlist.getLength(); i++) {
+                    // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
+                    Element kd=e.getOwnerDocument().createElementNS(edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"KeyDescriptor");
+                    Element ki=e.getOwnerDocument().createElementNS(XML.XMLSIG_NS,"KeyInfo");
+                    Element kn=e.getOwnerDocument().createElementNS(XML.XMLSIG_NS,"KeyName");
+                    kn.appendChild(
+                        e.getOwnerDocument().createTextNode(((Element)nlist.item(i)).getAttributeNS(null,"Name"))
+                        );
+                    ki.appendChild(kn);
+                    kd.appendChild(ki);
+                    kd.setAttributeNS(null,"use","signing");
+                    keys.add(new XMLKeyDescriptor(kd));
+                }
+            }
+        }
+
+        public boolean getAuthnRequestsSigned() {
+            return authnRequestsSigned;
+        }
+
+        public boolean getWantAssertionsSigned() {
+            return wantAssertionsSigned;
+        }
+
+        public EndpointManager getAssertionConsumerServiceManager() {
+            return asc;
+        }
+
+        public Iterator getAttributeConsumingServices() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        public AttributeConsumingService getDefaultAttributeConsumingService() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        public AttributeConsumingService getAttributeConsumingServiceByID(String id) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+    }
+    
+    class XMLEntityDescriptor implements EntityDescriptor {
+        private Element root = null;
+        private EntitiesDescriptor parent = null;
+        private String id = null;
+        private URL errorURL = null;
+        private Organization org = null;
+        private ArrayList /* <ContactPerson> */ contacts = new ArrayList();
+        private ArrayList /* <RoleDescriptor> */ roles = new ArrayList();
+        private AffiliationDescriptor affiliation = null;
+        private HashMap /* <String,String> */ locs = new HashMap();
+        private long validUntil = 0;
+        
+        public XMLEntityDescriptor(Element e, XMLMetadataProvider wrapper, long validUntil, EntitiesDescriptor parent) throws SAMLException {
+            root = e;
+            this.parent = parent;
+            this.validUntil = validUntil;
+
+            // Check the root element namespace. If SAML2, assume it's the std schema.
+            if (edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS.equals(e.getNamespaceURI())) {
+                id=e.getAttributeNS(null,"entityID");
+
+                if (e.hasAttributeNS(null,"validUntil")) {
+                    SimpleDateFormat formatter = null;
+                    String dateTime = XML.assign(e.getAttributeNS(null,"validUntil"));
+                    int dot = dateTime.indexOf('.');
+                    if (dot > 0)
+                        formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+                    else
+                        formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+                    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+                    try {
+                        validUntil=Math.min(validUntil,formatter.parse(dateTime).getTime());
+                    }
+                    catch (ParseException e1) {
+                        log.warn("Entity descriptor contains invalid expiration time");
+                    }
+                }
+
+                Element child=XML.getFirstChildElement(e);
+                while (child != null) {
+                    // Process the various kinds of children that we care about...
+                    if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"ContactPerson")) {
+                        contacts.add(new XMLContactPerson(child));
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"Organization")) {
+                        org=new XMLOrganization(child);
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AdditionalMetadataLocation")) {
+                        Node loc=child.getFirstChild();
+                        if (loc != null)
+                            locs.put(child.getAttributeNS(null,"namespace"),loc.getNodeValue());
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"IDPSSODescriptor")) {
+                        roles.add(new IDPRole(this,validUntil,child));
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"AttributeAuthorityDescriptor")) {
+                        roles.add(new AARole(this,validUntil,child));
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"SPSSODescriptor")) {
+                        roles.add(new SPRole(this,validUntil,child));
+                    }
+                    child = XML.getNextSiblingElement(child);
+                }
+            }
+            else {
+                id=e.getAttributeNS(null,"Name");
+                if (e.hasAttributeNS(null,"ErrorURL")) {
+                    try {
+                        errorURL=new URL(e.getAttributeNS(null,"ErrorURL"));
+                    }
+                    catch (MalformedURLException e1) {
+                        log.error("Site descriptor contains invalid ErrorURL");
+                    }
+                }
+                
+                boolean idp=false,aa=false,sp=false;    // only want to build a role once
+                Element child=XML.getFirstChildElement(e);
+                while (child != null) {
+                    // Process the various kinds of OriginSite children that we care about...
+                    if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"Contact")) {
+                        contacts.add(new XMLContactPerson(child));
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"HandleService") && !idp) {
+                        // Create the IDP role if needed.
+                        roles.add(new IDPRole(this, validUntil, e));
+                        idp=true;
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AttributeAuthority") && !aa) {
+                        // Create the AA role if needed.
+                        roles.add(new AARole(this, validUntil, e));
+                        aa=true;
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AssertionConsumerServiceURL") && !sp) {
+                        // Create the SP role if needed.
+                        roles.add(new SPRole(this, validUntil, e));
+                        sp=true;
+                    }
+                    else if (XML.isElementNamed(child,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"AttributeRequester") && !sp) {
+                        // Create the SP role if needed.
+                        roles.add(new SPRole(this, validUntil, e));
+                        sp=true;
+                    }
+                    child = XML.getNextSiblingElement(child);
+                }
+            }
+
+            // Each map entry is a list of the descriptors with this ID.
+            ArrayList list;
+            if (wrapper.sites.containsKey(id)) {
+                list = (ArrayList)wrapper.sites.get(id);
+            }
+            else {
+                list = new ArrayList();
+                wrapper.sites.put(id,list);
+            }
+            list.add(this);
+            
+            // Look for an IdP role, and register the artifact source ID and endpoints.
+            IDPRole idp=null;
+            for (int i=0; i<roles.size(); i++) {
+                if (roles.get(i) instanceof IDPRole) {
+                    idp = (IDPRole)roles.get(i);
+                    if (idp.sourceId != null) {
+                        if (wrapper.sources.containsKey(idp.sourceId)) {
+                            list = (ArrayList)wrapper.sources.get(idp.sourceId);
+                        }
+                        else {
+                            list = new ArrayList();
+                            wrapper.sources.put(idp.sourceId,list);
+                        }
+                        list.add(this);
+                    }
+                    else {
+                        String sourceId;
+                        try {
+                            sourceId = new String(Hex.encodeHex(Util.generateSourceId(id)));
+                        }
+                        catch (NoSuchAlgorithmException e1) {
+                            log.error("caught exception while encoding sourceId: " + e1.getMessage());
+                            continue;
+                        }
+                        if (wrapper.sources.containsKey(sourceId)) {
+                            list = (ArrayList)wrapper.sources.get(sourceId);
+                        }
+                        else {
+                            list = new ArrayList();
+                            wrapper.sources.put(sourceId,list);
+                        }
+                        list.add(this);
+                    }
+                    Iterator locs=idp.getArtifactResolutionServiceManager().getEndpoints();
+                    while (locs.hasNext()) {
+                        String loc=((Endpoint)locs.next()).getLocation();
+                        if (wrapper.sources.containsKey(loc)) {
+                            list = (ArrayList)wrapper.sources.get(loc);
+                        }
+                        else {
+                            list = new ArrayList();
+                            wrapper.sources.put(loc,list);
+                        }
+                        list.add(this);
+                    }
+                }
+            }
+        }
+        
+        public String getId() {
+            return id;
+        }
+
+        public boolean isValid() {
+            return System.currentTimeMillis() < validUntil;
+        }
+
+        public Iterator getRoleDescriptors() {
+            return roles.iterator();
+        }
+
+        public RoleDescriptor getRoleByType(Class type, String protocol) {
+            for (int i=0; i<roles.size(); i++) {
+                RoleDescriptor role = (RoleDescriptor)roles.get(i);
+                if (type.isInstance(role) && role.hasSupport(protocol))
+                    return role;
+            }
+            return null;
+        }
+
+        public IDPSSODescriptor getIDPSSODescriptor(String protocol) {
+            return (IDPSSODescriptor)getRoleByType(IDPSSODescriptor.class, protocol);
+        }
+
+        public SPSSODescriptor getSPSSODescriptor(String protocol) {
+            return (SPSSODescriptor)getRoleByType(SPSSODescriptor.class, protocol);
+        }
+
+        public AuthnAuthorityDescriptor getAuthnAuthorityDescriptor(String protocol) {
+            return (AuthnAuthorityDescriptor)getRoleByType(AuthnAuthorityDescriptor.class, protocol);
+        }
+
+        public AttributeAuthorityDescriptor getAttributeAuthorityDescriptor(String protocol) {
+            return (AttributeAuthorityDescriptor)getRoleByType(AttributeAuthorityDescriptor.class, protocol);
+        }
+
+        public PDPDescriptor getPDPDescriptor(String protocol) {
+            return (PDPDescriptor)getRoleByType(PDPDescriptor.class, protocol);
+        }
+
+        public AffiliationDescriptor getAffiliationDescriptor() {
+            return affiliation;
+        }
+
+        public Organization getOrganization() {
+            return org;
+        }
+
+        public Iterator getContactPersons() {
+            return contacts.iterator();
+        }
+
+        public Map getAdditionalMetadataLocations() {
+            return Collections.unmodifiableMap(locs);
+        }
+
+        public EntitiesDescriptor getEntitiesDescriptor() {
+            return parent;
+        }
+
+        public Element getElement() {
+            return root;
+        }
+        
+        public long getValidUntil() {
+            return validUntil;
+        }
+        
+        public URL getErrorURL() {
+            return errorURL;
+        }
+    }
+    
+    class XMLEntitiesDescriptor implements EntitiesDescriptor {
+        private Element root = null;
+        private EntitiesDescriptor parent = null;
+        private String name = null;
+        private ArrayList /* <EntitiesDescriptor> */ groups = new ArrayList();
+        private ArrayList /* <EntityDescriptor> */ providers = new ArrayList();
+        private long validUntil = Long.MAX_VALUE;
+        
+        public XMLEntitiesDescriptor(Element e, XMLMetadataProvider wrapper, long validUntil, EntitiesDescriptor parent) throws SAMLException {
+            root = e;
+            this.parent = parent;
+            this.validUntil = validUntil;
+            name = XML.assign(e.getAttributeNS(null, "Name"));
+
+            // Check the root element namespace. If SAML2, assume it's the std schema.
+            if (edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS.equals(e.getNamespaceURI())) {
+
+                if (e.hasAttributeNS(null,"validUntil")) {
+                    SimpleDateFormat formatter = null;
+                    String dateTime = XML.assign(e.getAttributeNS(null,"validUntil"));
+                    int dot = dateTime.indexOf('.');
+                    if (dot > 0)
+                        formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+                    else
+                        formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+                    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+                    try {
+                        validUntil=Math.min(validUntil,formatter.parse(dateTime).getTime());
+                    }
+                    catch (ParseException e1) {
+                        log.warn("Entities descriptor contains invalid expiration time");
+                    }
+                }
+
+                e = XML.getFirstChildElement(e);
+                while (e != null) {
+                    if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"EntitiesDescriptor"))
+                        groups.add(new XMLEntitiesDescriptor(e, wrapper, this.validUntil, this));
+                    else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SAML2META_NS,"EntityDescriptor"))
+                        providers.add(new XMLEntityDescriptor(e, wrapper, this.validUntil, this));
+                    e = XML.getNextSiblingElement(e);
+                }
+            }
+            else {
+                e = XML.getFirstChildElement(e);
+                while (e != null) {
+                    if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"SiteGroup"))
+                        groups.add(new XMLEntitiesDescriptor(e, wrapper, this.validUntil, this));
+                    else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"OriginSite"))
+                        providers.add(new XMLEntityDescriptor(e, wrapper, this.validUntil, this));
+                    else if (XML.isElementNamed(e,edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,"DestinationSite"))
+                        providers.add(new XMLEntityDescriptor(e, wrapper, this.validUntil, this));
+                    e = XML.getNextSiblingElement(e);
+                }
+            }
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public boolean isValid() {
+            return System.currentTimeMillis() < validUntil;
+        }
+
+        public EntitiesDescriptor getEntitiesDescriptor() {
+            return parent;
+        }
+
+        public Iterator getEntitiesDescriptors() {
+            return groups.iterator();
+        }
+
+        public Iterator getEntityDescriptors() {
+            return providers.iterator();
+        }
+
+        public Element getElement() {
+            return root;
+        }
+    }
+}
index 992c860..ffaac04 100644 (file)
@@ -62,10 +62,11 @@ import org.opensaml.SAMLException;
 import org.opensaml.SAMLRequest;
 import org.opensaml.SAMLResponse;
 import org.opensaml.SAMLSubject;
+import org.opensaml.XML;
 
 import x0.maceShibbolethTargetConfig1.ApplicationDocument.Application;
 
-import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityRole;
+import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityDescriptor;
 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
 import edu.internet2.middleware.shibboleth.metadata.MetadataException;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
@@ -103,7 +104,7 @@ public class AttributeRequestor {
                ApplicationInfo appinfo = config.getApplication(session.getApplicationId());
                
                // The Entity name was fed by by ShibPOSTProfile.accept(). Look it up now.
-               EntityDescriptor entity = appinfo.getEntityDescriptor(session.getEntityId());
+               EntityDescriptor entity = appinfo.lookup(session.getEntityId());
                if (entity==null) {
                        log.error("Entity(Site) deleted from Metadata since authentication POST received: "+session.getEntityId());
                        return false;
@@ -115,8 +116,8 @@ public class AttributeRequestor {
                
                SAMLRequest request = null;
                
-               AttributeAuthorityRole aa = 
-                   entity.getAttributeAuthorityRole(); // throws MetadataException
+               AttributeAuthorityDescriptor aa = 
+                   entity.getAttributeAuthorityDescriptor(XML.SAML11_PROTOCOL_ENUM); // throws MetadataException
                if (aa==null) {
                    log.error("No Attribute Authority in Metadata for ID="+entity.getId());
                    return false;
index 7d25c70..036a0be 100644 (file)
@@ -35,8 +35,8 @@ import java.util.Iterator;
 
 import org.opensaml.SAMLObject;
 
-import edu.internet2.middleware.shibboleth.metadata.EntityLocator;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.Metadata;
+import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
 
 /**
  * @author Howard Gilbert
@@ -54,9 +54,9 @@ public interface ITrust {
         */
        boolean validate(
                Iterator revocations,
-               ProviderRole role,
+               RoleDescriptor role,
                SAMLObject token,
-               EntityLocator locator
+               Metadata locator
        );
        
        /*
@@ -64,7 +64,7 @@ public interface ITrust {
         */
        boolean attach (
                Iterator revocations,
-               ProviderRole role
+               RoleDescriptor role
        );
 
 }
diff --git a/src/edu/internet2/middleware/shibboleth/serviceprovider/SAML2MetadataImpl.java b/src/edu/internet2/middleware/shibboleth/serviceprovider/SAML2MetadataImpl.java
deleted file mode 100644 (file)
index 46dae04..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * SAML2MetadataImpl.java
- * 
- * Process SAML 2 Metadata and present an EntityDescriptor
- * interface.
- * 
- * --------------------
- * 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.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-
-import org.apache.log4j.Logger;
-import org.apache.xml.security.exceptions.XMLSecurityException;
-import org.apache.xml.security.keys.KeyInfo;
-import org.apache.xmlbeans.XmlException;
-import org.opensaml.SAMLAttributeDesignator;
-import org.w3.x2001.x04.xmlenc.EncryptionMethodType;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import x0Metadata.oasisNamesTcSAML2.AttributeAuthorityDescriptorType;
-import x0Metadata.oasisNamesTcSAML2.ContactType;
-import x0Metadata.oasisNamesTcSAML2.EndpointType;
-import x0Metadata.oasisNamesTcSAML2.EntitiesDescriptorDocument;
-import x0Metadata.oasisNamesTcSAML2.EntitiesDescriptorType;
-import x0Metadata.oasisNamesTcSAML2.EntityDescriptorType;
-import x0Metadata.oasisNamesTcSAML2.IDPSSODescriptorType;
-import x0Metadata.oasisNamesTcSAML2.KeyDescriptorType;
-import x0Metadata.oasisNamesTcSAML2.RoleDescriptorType;
-import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityRole;
-import edu.internet2.middleware.shibboleth.metadata.ContactPerson;
-import edu.internet2.middleware.shibboleth.metadata.Endpoint;
-import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.EntityLocator;
-import edu.internet2.middleware.shibboleth.metadata.IDPProviderRole;
-import edu.internet2.middleware.shibboleth.metadata.KeyDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
-
-
-/**
- * Shibboleth 1.2 XML Metadata support
- */
-class SAML2MetadataImpl 
-       implements 
-               EntityLocator /* renamed "Metadata" interface */, 
-               PluggableConfigurationComponent
-       {
-    
-    private static Logger log = Logger.getLogger(SAML2MetadataImpl.class);
-    
-       Map entityDescriptors = new HashMap();
-       
-
-       public void initialize(Node dom) 
-               throws XmlException {
-           EntitiesDescriptorDocument bean=null;
-        bean = EntitiesDescriptorDocument.Factory.parse(dom);
-        Stack parentgroups = new Stack();
-               processGroup(bean.getEntitiesDescriptor(),parentgroups);
-       }
-       
-       public String getSchemaPathname() {
-           return "/schemas/sstc-saml-schema-metadata-2.0.xsd";
-       }
-       
-       /**
-        * Drill down (recursively) through groups to wrap each
-        * OriginSite in a ProviderImp and index by Name.
-        * 
-        * @param group SiteGroup
-        */
-       private void processGroup(
-               EntitiesDescriptorType group, 
-               Stack /*<EntitiesDescriptorType>*/ parentgroups) {
-               parentgroups.push(group);
-               EntitiesDescriptorType[] parents = 
-                   new EntitiesDescriptorType[parentgroups.size()];
-               Iterator/*<EntitiesDescriptorType>*/ iterator = parentgroups.iterator();
-               for (int i=0;i<parentgroups.size();i++) {
-                   parents[i]=(EntitiesDescriptorType)iterator.next();
-               }
-               EntityDescriptorType[] sites = group.getEntityDescriptorArray();
-               for (int i=0;i<sites.length;i++) {
-                       entityDescriptors.put(
-                               sites[i].getEntityID(),
-                               new XMLEntityDescriptorImpl(sites[i],parents));
-               }
-               EntitiesDescriptorType[] subgroups = group.getEntitiesDescriptorArray();
-               for (int i=0;i<subgroups.length;i++) {
-                       processGroup(subgroups[i],parentgroups);
-               }
-               parentgroups.pop();
-       }
-
-       /**
-        * implement ...metadata.Metadata.lookup
-        * @param entityId ID of remote site
-        * @return EntityDescriptor cast as Provider to fulfill interface
-        */
-       public Provider lookup(String entityId) {
-               return (EntityDescriptor) entityDescriptors.get(entityId);
-       }
-       
-       /**
-        * SAML 2 rename of lookup
-        * @param entityId ID of remote site
-        * @return EntityDescriptor of site
-        */
-       public EntityDescriptor getEntityDescriptor(String entityId) {
-               return (EntityDescriptor) entityDescriptors.get(entityId);
-       }
-
-    /**
-     * implements ...metadata.Provider for XML data
-     * 
-     * <p>An object of this class is constructed for every 
-     * EntityDescriptor (site) in SAML 2 Metadata.
-     */
-    static private class XMLEntityDescriptorImpl extends EntityDescriptor {
-       
-       private EntityDescriptorType site;  // The XMLBean object
-       
-       private EntitiesDescriptorType[] groups; // ancestor elements
-       
-       private ProviderRole[] roles = null; // child roles             
-       
-       XMLEntityDescriptorImpl(
-               EntityDescriptorType site, 
-               EntitiesDescriptorType[] groups) {
-               this.site=site;
-               this.groups=groups;
-               
-               ArrayList/*<ProviderRoles>*/ roleArray = 
-                   new ArrayList/*<ProviderRoles>*/();
-               
-               /*
-                * The rolesArray combines objects constructed from 
-                * different types of roles. However, the implementing
-                * objects must be constructed from the specific subtypes
-                */
-               
-               AttributeAuthorityDescriptorType[] attributeAuthorityArray = 
-                   site.getAttributeAuthorityDescriptorArray();
-               for (int i=0;i<attributeAuthorityArray.length;i++) {
-                       AttributeAuthorityRole aarole = 
-                               new AttributeAuthorityRoleImpl(this,attributeAuthorityArray[i]);
-                       roleArray.add(aarole);
-               }
-               
-               IDPSSODescriptorType[] handleServiceArray = site.getIDPSSODescriptorArray();
-               for (int i=0;i<attributeAuthorityArray.length;i++) {
-                       IDPProviderRole idprole =
-                               new IDPProviderRoleImpl(this,handleServiceArray[i]);
-                       roleArray.add(idprole);
-               }
-               
-               // Put code to process more specific roles here as they are
-               // needed by Shibboleth
-               
-               roles = new ProviderRole[roleArray.size()];
-               Iterator iterator = roleArray.iterator();
-               for (int i=0;i<roles.length;i++) {
-                   roles[i]= (ProviderRole) iterator.next();
-               }
-       }
-       
-       public String getId() {
-               return site.getEntityID();
-       }
-       
-       public String[] getGroups() {
-               String [] groupnames = new String[groups.length];
-               for (int i=0;i<groups.length;i++) {
-                       groupnames[i]=(groups[i]).getName();
-               }
-               return groupnames;
-       }
-    
-       public ContactPerson[] getContacts() {
-           // Create the interface objects on demand
-               ContactType[] contacts = site.getContactPersonArray();
-               XMLContactPersonImpl[] retarray = new XMLContactPersonImpl[contacts.length];
-               for (int i=0;i<contacts.length;i++) {
-                       retarray[i]=new XMLContactPersonImpl(contacts[i]);
-               }
-               return retarray;
-       }
-    
-       public ProviderRole[] getRoles() {
-               return roles;
-       }
-    }
-
-    /**
-     * implements ...metadata.ContactPerson for XML data
-     */
-    static private class XMLContactPersonImpl implements ContactPerson {
-       
-        ContactType contact; // Wrapped XMLBean object
-       
-       XMLContactPersonImpl(ContactType contact) {
-               this.contact=contact;
-       }
-    
-       /*
-        * Dependency: the order of values in the XSD enumeration
-        * must match the order of values defined in the interface.
-        * [If someone objects, we can go back and get the string
-        * matching elseif logic.]
-        */
-       public int getType() {
-               return contact.getContactType().intValue();
-       }
-    
-       public String getName() {
-               return contact.getGivenName()+" "+contact.getSurName();
-       }
-    
-       public String[] getEmails() {
-               return contact.getEmailAddressArray();
-       }
-    
-       public String[] getTelephones() {
-               return contact.getTelephoneNumberArray();
-       }
-       
-    }
-
-    /**
-     * implements ...metadata.ProviderRole
-     * 
-     * <p>Represents a RoleDescriptor or (more commonly) one of its
-     * explicitly defined subtypes IDPSSO, SPSSO, AuthnAuthority, 
-     * PDP, AA, or AttributeConsumer).</p>
-     * 
-     * <p>We would make this class abstract, except that in theory
-     * somewhere down the line we may want to support the RoleDescriptor
-     * SAML 2 Metadata tag that allows new roles to be defined beyond
-     * the roles explicitly mentioned in the standard. Should that 
-     * occur, then the constructor for this class should become
-     * public. Now it is protected so you can only instantiate
-     * subclasses, but cannot create an object of this class directly.</p>
-     */
-    static private class XMLProviderRoleImpl 
-       implements ProviderRole {
-       
-        RoleDescriptorType roleDescriptorType = null;
-        
-       EntityDescriptor entity; // parent Entity
-       
-       private String name;
-       
-       Endpoint[] endpoints = null;
-       
-       String[] protocolUris = null;
-       
-       KeyDescriptor[] keyDescriptors= null;
-
-       protected XMLProviderRoleImpl(
-               EntityDescriptor entity,
-               RoleDescriptorType role) {
-               this.entity=entity;
-               this.roleDescriptorType = role;
-
-           List protocolSupportEnumeration = 
-               roleDescriptorType.getProtocolSupportEnumeration();
-           protocolUris = new String[protocolSupportEnumeration.size()];
-           Iterator iterator = protocolSupportEnumeration.iterator();
-           for (int i=0;i<protocolUris.length;i++) {
-               protocolUris[i]=(String) iterator.next();
-           }
-           
-           KeyDescriptorType[] keyDescriptorArray = 
-               roleDescriptorType.getKeyDescriptorArray();
-           
-               keyDescriptors = new KeyDescriptor[keyDescriptorArray.length];
-               for (int i=0;i<keyDescriptorArray.length;i++) {
-                   keyDescriptors[i]= new KeyDescriptorImpl(keyDescriptorArray[i]); 
-               }
-               
-               
-               // The Endpoints types are specific to the subtypes
-               // So the Endpoint array must be filled in by the
-               // constructor of subclasses.
-       }
-    
-       public Provider getProvider() {
-               return entity;
-       }
-    
-       public String[] getProtocolSupport() {
-               return protocolUris;
-       }
-    
-       public boolean hasSupport(String version) {
-           return roleDescriptorType.getProtocolSupportEnumeration().contains(version);
-       }
-    
-       public ContactPerson[] getContacts() {
-           // Maybe we should return the contacts for the role???
-               return entity.getContacts();
-       }
-    
-       public KeyDescriptor[] getKeyDescriptors() {
-               return keyDescriptors;
-       }
-    
-       public Endpoint[] getDefaultEndpoints() {
-               return endpoints;
-       }
-    
-       public URL getErrorURL() {
-               try {
-                return new URL(roleDescriptorType.getErrorURL());
-            } catch (MalformedURLException e) {
-                return null;
-           }
-       }
-    
-    }
-
-    /**
-     * implements ...metadata.Endpoint for XML data
-     * 
-     * <p>Delegate calls to the XMLBean EndpointType</p>
-     */
-    static private class XMLEndpointImpl implements Endpoint {
-        
-       EndpointType endpoint;
-       
-       XMLEndpointImpl(EndpointType xmlbean) {
-           this.endpoint=xmlbean;
-       }
-    
-       public String getBinding() {
-               return endpoint.getBinding();
-       }
-    
-       public String getLocation() {
-               return endpoint.getLocation();
-       }
-    
-       public String getResponseLocation() {
-               return endpoint.getResponseLocation();
-       }
-       
-    }
-
-    /**
-     * A subtype of generic roles for AttributeAuthority entries.
-     */
-    private static class AttributeAuthorityRoleImpl
-       extends XMLProviderRoleImpl
-       implements AttributeAuthorityRole {
-    
-        // Yes, this is redundant with the parent class reference 
-        // to the same object as a generic RoleDescriptorType, but
-        // having a more specific field saves casting that field
-        // all the time in this code.
-        AttributeAuthorityDescriptorType aabean;
-    
-        public AttributeAuthorityRoleImpl(
-                XMLEntityDescriptorImpl impl, 
-                AttributeAuthorityDescriptorType aaDescriptor) {
-            
-            super(impl,aaDescriptor);
-            aabean=aaDescriptor;
-            
-            EndpointType[] attributeServiceArray = 
-                aaDescriptor.getAttributeServiceArray();
-            endpoints = new Endpoint[attributeServiceArray.length];
-            for (int i=0;i<attributeServiceArray.length;i++) {
-                endpoints[i]=new XMLEndpointImpl(attributeServiceArray[i]);
-            }
-        }
-
-        public Endpoint[] getAttributeServices() {
-               return endpoints;
-       }
-    
-       public SAMLAttributeDesignator[] getAttributeDesignators() {
-               return null;
-       }
-    }
-
-    /**
-     * A subtype of generic roles for Handle Server entries.
-     */
-    private static class IDPProviderRoleImpl
-       extends XMLProviderRoleImpl
-       implements IDPProviderRole {
-    
-        IDPSSODescriptorType hsRole;
-        
-        public IDPProviderRoleImpl(XMLEntityDescriptorImpl impl, 
-                IDPSSODescriptorType type) {
-            super(impl,type);
-            hsRole = type;
-            
-            EndpointType[] singleSignOnServiceArray = 
-                type.getSingleSignOnServiceArray();
-            endpoints = new Endpoint[singleSignOnServiceArray.length];
-            for (int i=0;i<singleSignOnServiceArray.length;i++) {
-                endpoints[i]=new XMLEndpointImpl(singleSignOnServiceArray[i]);
-            }
-        }
-    }
-    
-    private static class KeyDescriptorImpl 
-       implements KeyDescriptor {
-        
-        KeyDescriptorType keyDescriptor = null;
-        
-        public KeyDescriptorImpl(KeyDescriptorType keyDescriptor) {
-            super();
-            this.keyDescriptor = keyDescriptor;
-        }
-        
-        public String[] getEncryptionMethod() {
-            EncryptionMethodType[] encryptionMethodArray = 
-                keyDescriptor.getEncryptionMethodArray();
-            String[] methods = new String[encryptionMethodArray.length];
-            for (int i=0;i<encryptionMethodArray.length;i++) {
-                   EncryptionMethodType encryptionMethod = encryptionMethodArray[i];
-                   methods[i] =encryptionMethod.getAlgorithm();
-            }
-            return methods;
-        }
-        public KeyInfo[] getKeyInfo() {
-            Node fragment = keyDescriptor.getKeyInfo().newDomNode();
-            Element node = (Element) fragment.getFirstChild();
-            KeyInfo info = null;
-            try {
-                info = new KeyInfo(node,"");
-            } catch (XMLSecurityException e) {
-                return null;
-            }
-            return new KeyInfo[] {info};
-        }
-        
-        public int getUse() {
-            String value = keyDescriptor.getUse().toString();
-            if (value.equals("encryption"))
-                return KeyDescriptor.ENCRYPTION;
-            else
-                return KeyDescriptor.SIGNING;
-        }
-}
-}
\ No newline at end of file
index c934cef..9150267 100644 (file)
 
 package edu.internet2.middleware.shibboleth.serviceprovider;
 
-import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
@@ -148,12 +147,11 @@ 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.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;
@@ -172,10 +170,8 @@ 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.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;
 
 /**
@@ -208,16 +204,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 = 
@@ -274,9 +269,9 @@ public class ServiceProviderConfig {
         */
        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 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";
@@ -584,7 +579,7 @@ public class ServiceProviderConfig {
                Class implclass,
                Class interfaceClass,
                String builtinName,
-               String schemaname,
+               //String schemaname,
                Map /*<String,PluggableConfigurationComponent>*/uriMap
                ) {
         
@@ -633,10 +628,11 @@ public class ServiceProviderConfig {
                    return "";
                }
                
+            /*
             String tempname = impl.getSchemaPathname();
             if (tempname!=null)
                 schemaname=tempname;
-            
+            */
                try {
                        Document extdoc = Parser.loadDom(uri,true);
                        if (extdoc==null)
@@ -663,9 +659,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;
@@ -713,7 +709,7 @@ public class ServiceProviderConfig {
                            XMLAAPImpl.class,
                            AAP.class,
                            XMLAAPPROVIDERTYPE,
-                           AAPSCHEMA,
+                           //AAPSCHEMA,
                            attributePolicies);
                    if (uri==null)
                        anyError=true;
@@ -770,7 +766,7 @@ public class ServiceProviderConfig {
                            XMLTrustImpl.class,
                            ITrust.class,
                            XMLTRUSTPROVIDERTYPE,
-                           TRUSTSCHEMA,
+                           //TRUSTSCHEMA,
                            certificateValidators);
                    if (uri==null)
                        anyError=true;
@@ -879,7 +875,7 @@ public class ServiceProviderConfig {
         * query their value directly.
         */
        public class ApplicationInfo 
-               implements EntityLocator, ITrust {
+               implements Metadata, ITrust {
                
                private Application applicationConfig;
         public Application getApplicationConfig() {
@@ -947,28 +943,30 @@ 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
                 * 
@@ -1087,9 +1085,9 @@ public class ServiceProviderConfig {
                public boolean 
                validate(
                                Iterator revocations,  // Currently unused 
-                               ProviderRole role,
+                               RoleDescriptor role,
                                SAMLObject token, 
-                               EntityLocator dummy    // "this" is an EntityLocator 
+                               Metadata dummy    // "this" is an EntityLocator 
                                        ) {
                        
                        // TODO If revocations are supported, "this" will provide them
@@ -1110,7 +1108,7 @@ public class ServiceProviderConfig {
                 * @param token Signed SAMLObject
                 * @return
                 */
-               public boolean validate(ProviderRole role, SAMLObject token) {
+               public boolean validate(RoleDescriptor role, SAMLObject token) {
                        return validate(null,role,token,null);
                }
 
@@ -1123,11 +1121,10 @@ 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;
                }
-               
        }
        
 
index 83d2948..01c8430 100644 (file)
@@ -35,7 +35,7 @@ import org.opensaml.SAMLRequest;
 import org.opensaml.SAMLResponse;
 import org.opensaml.TrustException;
 
-import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityRole;
+import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityDescriptor;
 import edu.internet2.middleware.shibboleth.metadata.Endpoint;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig.ApplicationInfo;
 
@@ -64,7 +64,6 @@ public class ShibBinding {
        private static ServiceProviderContext context = ServiceProviderContext.getInstance();
        
        private String applicationId = null;
-       private SAMLBinding sbinding = null;
        
        /**
         * While the C++ constructor takes iterators over the Trust and 
@@ -78,7 +77,6 @@ public class ShibBinding {
        ShibBinding(
                        String applicationId) throws NoSuchProviderException {
                this.applicationId=applicationId;
-        sbinding = SAMLBindingFactory.getInstance(SAMLBinding.SOAP);
        }
 
        /**
@@ -100,7 +98,7 @@ public class ShibBinding {
                        SAMLResponse 
        send (
                        SAMLRequest req,
-                       AttributeAuthorityRole role,
+                       AttributeAuthorityDescriptor role,
                        String[] audiences,
                        SAMLAuthorityBinding[] bindings) 
        throws SAMLException {
@@ -110,64 +108,57 @@ public class ShibBinding {
                ServiceProviderConfig config = context.getServiceProviderConfig();
                ApplicationInfo appinfo = config.getApplication(applicationId);
                
+        SAMLBinding sbinding = null;
                SAMLResponse resp = null;
                String prevBinding = null;
        
                /*
-                * I seriously considered commenting this block out. It makes
-                * no particular sense for the caller to know about or provide
-                * SAMLAuthorityBinding objects. In any rational world, 
-                * a caller inside Shibboleth is going to represent the 
-                * AA from the Metadata. 
+                * Try any inline bindings provided by 1.0/1.1 origins. 
                 */
                if (bindings!=null) {
                        for (int ibinding=0;ibinding<bindings.length;ibinding++) {
                                try {
                                        SAMLAuthorityBinding binding = bindings[ibinding];
-                                       String bindingString = binding.getBinding();
-                                       if (!bindingString.equals(prevBinding)) {
-                                               prevBinding = bindingString;
-                                               resp=sbinding.send(binding.getLocation(),req);
-                                       }
+                                       if (!binding.getBinding().equals(prevBinding)) {
+                                               prevBinding = binding.getBinding();
+                        sbinding = SAMLBindingFactory.getInstance(binding.getBinding());
+                    }
+                                       resp=sbinding.send(binding.getLocation(),req);
                                        validateResponseSignatures(role, appinfo, resp);
                                        return resp;
-                               } catch (SAMLException e) {
-                                       continue;
-                               }
+                } catch (TrustException e) {
+                    log.error("Unable to validate signatures on attribute response: " + e);
+                    continue;
+                } catch (SAMLException e) {
+                    log.error("Unable to query attributes: " + e);
+                    continue;
+                }
                        }
                }
                
                /*
-                * In concept, a Role can have a collection of Endpoints.
-                * The theory is that SAML 2.0 Metadata might have different
-                * entries for different protocols (or different versions of
-                * the same protocol).
-                * The current Shibboleth configuration file doesn't allow this.
-                * Later on, when support for SAML 2.0 metadata is added, it is
-                * just as likely that the Endpoint array would be filtered by
-                * the configuration construction/parse process to leave only
-                * relevant entries.
-                * So for now, the C++ code to run the array and filter entries
-                * is replaced by logic that "knows" there is exactly one 
-                * Endpoint per Role (built into the XMLProviderRoleImpl).
+                * Try each metadata endpoint...
                 */
-               Endpoint[] ends = role.getAttributeServices();
-               Endpoint endpoint = ends[0];
-               
-               log.debug("AA is at "+endpoint.getLocation());
-               
-               try {
-                       resp=sbinding.send(endpoint.getLocation(),req);
-                       log.debug("AA returned Attribute Assertion");
-                       validateResponseSignatures(role, appinfo, resp);
-                       return resp;
-               } catch (TrustException e) {
-                       log.error("Unable to validate signatures on attribute request",e);
-                       throw e;
-               } catch (SAMLException e) {
-                       log.error("Unable to query attributes.",e);
-                       throw e;
-               }
+               Iterator ends = role.getAttributeServiceManager().getEndpoints();
+        while (ends.hasNext()) {
+            Endpoint endpoint = (Endpoint)ends.next();
+            try {
+                if (!endpoint.getBinding().equals(prevBinding)) {
+                    prevBinding = endpoint.getBinding();
+                    sbinding = SAMLBindingFactory.getInstance(endpoint.getBinding());
+                }
+                resp=sbinding.send(endpoint.getLocation(),req);
+                validateResponseSignatures(role, appinfo, resp);
+                return resp;
+            } catch (TrustException e) {
+                log.error("Unable to validate signatures on attribute response: " + e);
+                continue;
+            } catch (SAMLException e) {
+                log.error("Unable to query attributes: " + e);
+                continue;
+            }
+        }
+        return null;
        }
 
        /**
@@ -180,7 +171,7 @@ public class ShibBinding {
         */
        private void 
        validateResponseSignatures(
-                       AttributeAuthorityRole role, 
+                       AttributeAuthorityDescriptor role, 
                        ApplicationInfo appinfo, 
                        SAMLResponse resp) 
        throws TrustException {
index 4843b2a..89cd868 100644 (file)
   */
 package edu.internet2.middleware.shibboleth.serviceprovider;
 
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Stack;
-
 import org.apache.log4j.Logger;
 import org.apache.xmlbeans.XmlException;
-import org.opensaml.SAMLAttributeDesignator;
+import org.opensaml.SAMLException;
+import org.opensaml.artifact.Artifact;
+import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
-import x0.maceShibboleth1.AuthorityType;
-import x0.maceShibboleth1.ContactType;
-import x0.maceShibboleth1.OriginSiteType;
-import x0.maceShibboleth1.SiteGroupDocument;
-import x0.maceShibboleth1.SiteGroupType;
-import edu.internet2.middleware.shibboleth.common.XML;
-import edu.internet2.middleware.shibboleth.metadata.AttributeAuthorityRole;
-import edu.internet2.middleware.shibboleth.metadata.ContactPerson;
-import edu.internet2.middleware.shibboleth.metadata.Endpoint;
+import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.EntityLocator;
-import edu.internet2.middleware.shibboleth.metadata.IDPProviderRole;
-import edu.internet2.middleware.shibboleth.metadata.KeyDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.Provider;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.Metadata;
+import edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadataProvider;
 
 
 /**
  * Shibboleth 1.2 XML Metadata support
+ * 
+ * TODO: This needs to be ripped out, but for now, I'll try and
+ * just wrap the real metadata plugin with this thing.
  */
 class XMLMetadataImpl 
        implements 
-               EntityLocator /* renamed "Metadata" interface */, 
+               Metadata,
                PluggableConfigurationComponent
        {
     
     private static Logger log = Logger.getLogger(XMLMetadataImpl.class);
     
-       Map entityDescriptors = new HashMap();
+       XMLMetadataProvider realObject = null;
        
 
        public void initialize(Node dom) 
-               throws XmlException {
-           SiteGroupDocument bean = SiteGroupDocument.Factory.parse(dom);
-               Stack parentgroups = new Stack();
-               processGroup(bean.getSiteGroup(),parentgroups);
-       }
-       
-       /**
-        * Drill down (recursively) through groups to wrap each
-        * OriginSite in a ProviderImp and index by Name.
-        * 
-        * @param group SiteGroup
-        */
-       private void processGroup(SiteGroupType group, Stack parentgroups) {
-               parentgroups.push(group.getName());
-               Object[] parents = parentgroups.toArray();
-               OriginSiteType[] sites = group.getOriginSiteArray();
-               for (int i=0;i<sites.length;i++) {
-                       entityDescriptors.put(
-                               sites[i].getName(),
-                               new XMLEntityDescriptorImpl(sites[i],parents));
-               }
-               SiteGroupType[] subgroups = group.getSiteGroupArray();
-               for (int i=0;i<subgroups.length;i++) {
-                       processGroup(subgroups[i],parentgroups);
-               }
-               parentgroups.pop();
-       }
-
-       /**
-        * implement ...metadata.Metadata.lookup
-        * @param entityId ID of remote site
-        * @return EntityDescriptor cast as Provider to fulfill interface
-        */
-       public Provider lookup(String entityId) {
-               return (EntityDescriptor) entityDescriptors.get(entityId);
+               throws XmlException, ShibbolethConfigurationException {
+           try {
+            // Assuming this just gets a DOM tree containing the metadata,
+            // hopefully this will "just work".
+            realObject = new edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadataProvider((Element)dom);
+        }
+        catch (SAMLException e) {
+            throw new ShibbolethConfigurationException("Exception initializing metadata: " + e);
+        }
        }
        
-       /**
-        * SAML 2 rename of lookup
-        * @param entityId ID of remote site
-        * @return EntityDescriptor of site
-        */
-       public EntityDescriptor getEntityDescriptor(String entityId) {
-               return (EntityDescriptor) entityDescriptors.get(entityId);
-       }
-
-    /**
-     * implements ...metadata.Provider for XML data
-     * 
-     * <p>An object of this class is constructed for every 
-     * OriginSite in the current Shibboleth configuration, and
-     * for every EntityDescriptor in SAML 2 Metadata. It has 
-     * a Role for the HS (IDP) and AA. Of course, it can also
-     * be used in Origin code to describe Targets.
-     */
-    static private class XMLEntityDescriptorImpl extends EntityDescriptor {
-       
-       OriginSiteType site;  // The real XMLBean object
-       Object[] groups; // Actually array of SiteGroupTypes
-       ProviderRole[] roles = null;            
-       
-       XMLEntityDescriptorImpl(OriginSiteType site, Object [] groups) {
-               this.site=site;
-               this.groups=groups;
-               
-               ArrayList/*<ProviderRoles>*/ roleArray = new ArrayList();
-               
-               /*
-                * Note: The schema allows for more than one AA or IDP.
-                * This makes sense in SAML 2.0 where different versions of
-                * the protocol can be supported by different URL endpoints.
-                * It is not clear how it would really be used here. This
-                * code goes through the motions of constructing more than
-                * one AA or IDP Role object, but in practice the subsequent
-                * code will only use the first such object it encounters.
-                */
-               
-               AuthorityType[] attributeAuthorityArray = site.getAttributeAuthorityArray();
-               if (attributeAuthorityArray.length>0) {
-                       AttributeAuthorityRole aarole = 
-                               new AttributeAuthorityRoleImpl(this,attributeAuthorityArray[0]);
-                       roleArray.add(aarole);
-               }
-               AuthorityType[] handleServiceArray = site.getHandleServiceArray();
-               if (handleServiceArray.length>0) {
-                       IDPProviderRole idprole =
-                               new IDPProviderRoleImpl(this,handleServiceArray[0]);
-                       roleArray.add(idprole);
-               }
-               roles = new ProviderRole[roleArray.size()];
-               Iterator iterator = roleArray.iterator();
-               for (int i=0;i<roles.length;i++) {
-                   roles[i]= (ProviderRole) iterator.next();
-               }
-       }
-       
-       public String getId() {
-               return site.getName();
-       }
-       
-       public String[] getGroups() {
-               String [] groupnames = new String[groups.length];
-               for (int i=0;i<groups.length;i++) {
-                       groupnames[i]=((OriginSiteType)groups[i]).getName();
-               }
-               return groupnames;
-       }
-    
-       public ContactPerson[] getContacts() {
-               ContactType[] contacts = site.getContactArray();
-               XMLContactPersonImpl[] retarray = new XMLContactPersonImpl[contacts.length];
-               for (int i=0;i<contacts.length;i++) {
-                       retarray[i]=new XMLContactPersonImpl(contacts[i]);
-               }
-               return retarray;
-       }
-    
-       public ProviderRole[] getRoles() {
-               return roles;
-       }
-    }
-
-    /**
-     * implements ...metadata.ContactPerson for XML data
-     */
-    static private class XMLContactPersonImpl implements ContactPerson {
-       
-       ContactType contact; // Wrapped XMLBean object
-       
-       XMLContactPersonImpl(ContactType contact) {
-               this.contact=contact;
-       }
-    
-       /*
-        * Dependency: the order of values in the XSD enumeration
-        * must match the order of values defined in the interface.
-        * [If someone objects, we can go back and get the string
-        * matching elseif logic.]
-        */
-       public int getType() {
-               return contact.getType().intValue();
-       }
-    
-       public String getName() {
-               return contact.getName();
-       }
-    
-       public String[] getEmails() {
-               return new String[] {contact.getEmail()};
-       }
-    
-       public String[] getTelephones() {
-               return null;
-       }
-       
-    }
-
-    /**
-     * implements ...metadata.ProviderRole and Endpoint for XML data
-     * 
-     * Note: In the Origin code, the ProviderRole is
-     * implemented directly by the Provider object 
-     * (because from the Origin the Provider has only
-     * one Role). This is not a generally good idea
-     * and it will not work if we move to SAML 2.0 
-     * Metadata. So might as well clean it up now.
-     */
-    static private class XMLProviderRoleImpl 
-       implements ProviderRole, Endpoint {
-       
-       EntityDescriptor entity;
-       private String name;
-       private String location;
-       
-       XMLProviderRoleImpl(EntityDescriptor entity, AuthorityType a) {
-               this.entity=entity;
-               this.name = a.getName();
-               this.location = a.getLocation();
-       }
-    
-       public Provider getProvider() {
-               return entity;
-       }
-    
-       public String[] getProtocolSupport() {
-               return new String[]{XML.SHIB_NS};
-       }
-    
-       public boolean hasSupport(String version) {
-               if (version.equals(XML.SHIB_NS)) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-    
-       public ContactPerson[] getContacts() {
-               return entity.getContacts();
-       }
-    
-       public KeyDescriptor[] getKeyDescriptors() {
-               return null;
-       }
-    
-       public Endpoint[] getDefaultEndpoints() {
-               return new Endpoint[] {this};
-       }
-    
-       public URL getErrorURL() {
-               return null;
-       }
-    
-       public String getBinding() {
-               return XML.SHIB_NS;
-       }
-    
-       public String getVersion() {
-               return null;
-       }
-    
-       public String getLocation() {
-               return location;
-       }
-    
-       public String getResponseLocation() {
-               return null;
-       }
-    }
-
-    /**
-     * implements ...metadata.Endpoint for XML data
-     * 
-     * <p>For now, the Endpoint just wraps a URL.</p>
-     */
-    static private class XMLEndpointImpl implements Endpoint {
-       
-       private String location;
-       
-       XMLEndpointImpl(String location) {
-               this.location=location;
-       }
-    
-       public String getBinding() {
-               return XML.SHIB_NS;
-       }
-    
-       public String getVersion() {
-               return null;
-       }
-    
-       public String getLocation() {
-               return location;
-       }
-    
-       public String getResponseLocation() {
-               return null;
-       }
-       
-    }
-
-    /**
-     * A subtype of generic roles for AttributeAuthority entries.
-     */
-    private static class AttributeAuthorityRoleImpl
-       extends XMLProviderRoleImpl
-       implements AttributeAuthorityRole {
-    
-       public AttributeAuthorityRoleImpl(EntityDescriptor entity, AuthorityType a) {
-               super(entity, a);
-       }
-    
-       public Endpoint[] getAttributeServices() {
-               return new Endpoint[] {this};
-       }
-    
-       public SAMLAttributeDesignator[] getAttributeDesignators() {
-               return null;
-       }
+    public String getSchemaPathname() {
+        return null;
     }
 
-    /**
-     * A subtype of generic roles for Handle Server entries.
-     */
-    private static class IDPProviderRoleImpl
-       extends XMLProviderRoleImpl
-       implements IDPProviderRole {
-    
-        public IDPProviderRoleImpl(EntityDescriptor entity, AuthorityType a) {
-            super(entity, a);
-        }
+    public EntityDescriptor lookup(String id) {
+        return realObject.lookup(id);
     }
 
-    /**
-     * @return
-     */
-    public String getSchemaPathname() {
-        return null;
+    public EntityDescriptor lookup(Artifact artifact) {
+        return realObject.lookup(artifact);
     }
 }
\ No newline at end of file
index 21b42f5..111d7c0 100644 (file)
@@ -116,8 +116,8 @@ import x0.maceShibbolethTrust1.TrustDocument.Trust;
 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
 import edu.internet2.middleware.shibboleth.common.XML;
 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
-import edu.internet2.middleware.shibboleth.metadata.EntityLocator;
-import edu.internet2.middleware.shibboleth.metadata.ProviderRole;
+import edu.internet2.middleware.shibboleth.metadata.Metadata;
+import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
 
 
 /**
@@ -414,16 +414,16 @@ public class XMLTrustImpl
         */
        public boolean validate(
                        Iterator revocations, 
-                       ProviderRole role,
+                       RoleDescriptor role,
                        SAMLObject token, 
-                       EntityLocator locator
+                       Metadata locator
                                ) {
                
                EntityDescriptor entityDescriptor = null;
                
                // Did the caller designate the remote Entity
                if (role!=null)
-                       entityDescriptor = (EntityDescriptor) role.getProvider();
+                       entityDescriptor = (EntityDescriptor) role.getEntityDescriptor();
                
                // If not, then search through the SAMLObject for the remote Entity Id
                if (entityDescriptor==null) {
@@ -442,7 +442,7 @@ public class XMLTrustImpl
                                SAMLQuery query = request.getQuery();
                                if (query!=null && query instanceof SAMLAttributeQuery) {
                                        String name = ((SAMLAttributeQuery) query).getResource();
-                                       entityDescriptor=locator.getEntityDescriptor(name);
+                                       entityDescriptor=locator.lookup(name);
                                }
                        }
                }
@@ -470,23 +470,23 @@ public class XMLTrustImpl
         * @param assertion  SAMLAssertion to be verified
         * @return           First ntityDescriptor mapped from assertion data fields. 
         */
-       private EntityDescriptor getEntityFromAssertion(EntityLocator locator, SAMLAssertion assertion) {
+       private EntityDescriptor getEntityFromAssertion(Metadata locator, SAMLAssertion assertion) {
                EntityDescriptor entityDescriptor = null;
-               entityDescriptor=locator.getEntityDescriptor(assertion.getIssuer());
+               entityDescriptor=locator.lookup(assertion.getIssuer());
                if (entityDescriptor!=null) 
                        return entityDescriptor;
                Iterator statements = assertion.getStatements();
                while (entityDescriptor==null && statements.hasNext()) {
                        SAMLSubjectStatement statement = (SAMLSubjectStatement) statements.next();
                        String qname = statement.getSubject().getName().getNameQualifier();
-                       entityDescriptor=locator.getEntityDescriptor(qname);
+                       entityDescriptor=locator.lookup(qname);
                }
                return entityDescriptor;
        }
 
        public boolean attach(
                        Iterator revocations, 
-                       ProviderRole role
+                       RoleDescriptor role
                                ) {
                return false;
        }
index 5cd2a46..8d550fe 100644 (file)
@@ -28,14 +28,16 @@ package edu.internet2.middleware.shibboleth.metadata;
 
 import java.io.File;
 import java.util.Arrays;
+import java.util.Iterator;
 
 import junit.framework.TestCase;
 
 import org.apache.log4j.BasicConfigurator;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
+import org.opensaml.XML;
 
-import edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadataLoadWrapper;
+import edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadata;
 
 /**
  * Validation suite for the <code>Metadata</code> interface.
@@ -67,39 +69,80 @@ public class MetadataTests extends TestCase {
        public void testBasicShibbolethXML() {
 
                try {
-                       Metadata metadata = new XMLMetadataLoadWrapper(new File("data/sites1.xml").toURL().toString());
+                       Metadata metadata = new XMLMetadata(new File("data/sites1.xml").toURL().toString());
 
                        assertNotNull("Unable to find test provider", metadata.lookup("bahsite"));
                        assertNotNull("Unable to find test provider", metadata.lookup("rootsite"));
 
+            /* TODO: rework to walk tree
                        assertTrue("Group list is incorrect or out of order.", Arrays.equals(new String[]{"urn:mace:inqueue",
                                        "foofed", "bahfed"}, metadata.lookup("bahsite").getGroups()));
-
+                                       */
+            
                        //This should probably be made more robust at some point
-                       assertTrue("Incorrect provider role.", metadata.lookup("bahsite").getRoles()[0] instanceof SPProviderRole);
-                       assertTrue("Incorrect provider role.",
-                                       metadata.lookup("bahsite").getRoles()[0] instanceof AttributeConsumerRole);
+                       assertNotNull("Incorrect provider role.", metadata.lookup("bahsite").getSPSSODescriptor(XML.SAML11_PROTOCOL_ENUM));
 
-                       assertEquals("Incorrect parsing of assertion consumer URL.", ((SPProviderRole) metadata.lookup("bahsite")
-                                       .getRoles()[0]).getAssertionConsumerServiceURLs()[0].getLocation(), "http://foo.com/SHIRE");
+                       assertEquals("Incorrect parsing of assertion consumer URL.",
+                    ((Endpoint)metadata.lookup("bahsite").getSPSSODescriptor(XML.SAML11_PROTOCOL_ENUM).getAssertionConsumerServiceManager().getEndpoints().next()).getLocation(),
+                    "http://foo.com/SHIRE"
+                    );
 
-                       assertTrue("Incorrect attribute requester parsing.", metadata.lookup("rootsite").getRoles()[0]
-                                       .getKeyDescriptors().length == 2);
+            Iterator keys = metadata.lookup("rootsite").getSPSSODescriptor(XML.SAML11_PROTOCOL_ENUM).getKeyDescriptors();
+            KeyDescriptor key1 = (KeyDescriptor)keys.next();
+            KeyDescriptor key2 = (KeyDescriptor)keys.next();
+                       assertTrue("Incorrect attribute requester key parsing.", key1 != null && key2 != null);
 
                        String[] control = new String[]{
                                        "C=US, ST=Tennessee, L=Memphis, O=The University of Memphis, OU=Information Systems, CN=test2.memphis.edu",
                                        "C=US, ST=Tennessee, L=Memphis, O=The University of Memphis, OU=Information Systems, CN=test1.memphis.edu"};
-                       String[] meta = new String[]{
-                                       metadata.lookup("rootsite").getRoles()[0].getKeyDescriptors()[0].getKeyInfo()[0].itemKeyName(0)
-                                                       .getKeyName(),
-                                       metadata.lookup("rootsite").getRoles()[0].getKeyDescriptors()[1].getKeyInfo()[0].itemKeyName(0)
-                                                       .getKeyName()};
+                       String[] meta = new String[] {
+                                       key1.getKeyInfo().itemKeyName(0).getKeyName(),
+                                       key2.getKeyInfo().itemKeyName(0).getKeyName()
+                    };
                        Arrays.sort(meta);
                        Arrays.sort(control);
                        assertTrue("Encountered unexpected key names", Arrays.equals(control, meta));
                } catch (Exception e) {
                        fail("Failed to correctly load metadata: " + e);
                }
-
        }
+
+    public void testBasicSAMLXML() {
+
+        try {
+            Metadata metadata = new XMLMetadata(new File("src/conf/IQ-sites.xml").toURL().toString());
+
+            EntityDescriptor entity = metadata.lookup("urn:mace:inqueue:example.edu");
+            
+            assertNotNull("Unable to find test provider", entity);
+            assertEquals("Descriptor group is wrong.", entity.getEntitiesDescriptor().getName(),"urn:mace:inqueue");
+            
+            IDPSSODescriptor idp = entity.getIDPSSODescriptor(edu.internet2.middleware.shibboleth.common.XML.SHIB_NS);
+            AttributeAuthorityDescriptor aa = entity.getAttributeAuthorityDescriptor(XML.SAML11_PROTOCOL_ENUM);
+            SPSSODescriptor sp = entity.getSPSSODescriptor(XML.SAML11_PROTOCOL_ENUM);
+            
+            assertNotNull("Missing IdP provider role.", idp);
+            assertNotNull("Missing AA provider role.", aa);
+            assertNotNull("Missing SP provider role.", sp);
+
+            assertEquals("Incorrect assertion consumer service location.",
+                    ((Endpoint)sp.getAssertionConsumerServiceManager().getEndpoints().next()).getLocation(),
+                    "https://wayf.internet2.edu/Shibboleth.shire"
+                    );
+
+            Iterator keys = sp.getKeyDescriptors();
+            KeyDescriptor key = (KeyDescriptor)keys.next();
+            assertNotNull("Incorrect attribute requester key parsing.", key);
+
+            String[] control = new String[]{"wayf.internet2.edu"};
+            String[] meta = new String[] {
+                    key.getKeyInfo().itemKeyName(0).getKeyName()
+                    };
+            Arrays.sort(meta);
+            Arrays.sort(control);
+            assertTrue("Encountered unexpected key names", Arrays.equals(control, meta));
+        } catch (Exception e) {
+            fail("Failed to correctly load metadata: " + e);
+        }
+    }
 }