Align with new SAML APIs.
authorcantor <cantor@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Sat, 25 Jan 2003 19:29:57 +0000 (19:29 +0000)
committercantor <cantor@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Sat, 25 Jan 2003 19:29:57 +0000 (19:29 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@419 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

17 files changed:
src/edu/internet2/middleware/eduPerson/ScopedAttribute.java
src/edu/internet2/middleware/shibboleth/aa/AASaml.java
src/edu/internet2/middleware/shibboleth/aa/AAServlet.java
src/edu/internet2/middleware/shibboleth/aaLocal/attributes/cmuAndrewId.java
src/edu/internet2/middleware/shibboleth/aaLocal/attributes/eduPersonAffiliation.java
src/edu/internet2/middleware/shibboleth/aaLocal/attributes/eduPersonEntitlement.java
src/edu/internet2/middleware/shibboleth/aaLocal/attributes/eduPersonPrincipalName.java
src/edu/internet2/middleware/shibboleth/common/ClubShibPOSTProfile.java
src/edu/internet2/middleware/shibboleth/common/Init.java
src/edu/internet2/middleware/shibboleth/common/OriginSiteMapper.java
src/edu/internet2/middleware/shibboleth/common/OriginSiteMapperException.java
src/edu/internet2/middleware/shibboleth/common/SAMLBindingFactory.java
src/edu/internet2/middleware/shibboleth/common/ShibPOSTProfile.java
src/edu/internet2/middleware/shibboleth/common/ShibPOSTProfileFactory.java
src/edu/internet2/middleware/shibboleth/common/SiteSigner.java
src/edu/internet2/middleware/shibboleth/common/UnsupportedProtocolException.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/hs/HandleServiceSAML.java

index 4032b42..1830d6d 100755 (executable)
 
 package edu.internet2.middleware.eduPerson;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.Vector;
+
 import org.opensaml.*;
 import org.w3c.dom.*;
 
@@ -60,37 +63,37 @@ import org.w3c.dom.*;
  * @author     Scott Cantor
  * @created    May 9, 2002
  */
-public class ScopedAttribute extends SAMLAttribute
+public class ScopedAttribute extends SAMLAttribute implements Cloneable
 {
     /**  Default attribute scope */
     protected String defaultScope = null;
 
     /**  Scopes of the attribute values */
-    protected Vector scopes = new Vector();
+    protected ArrayList scopes = new ArrayList();
 
     /**
      *  Constructor for the ScopedAttribute object
      *
      * @param  name               Name of attribute
      * @param  namespace          Namespace/qualifier of attribute
+     * @param  defaultScope       The default scope to apply for values
      * @param  type               The schema type of attribute value(s)
      * @param  lifetime           Effective lifetime of attribute's value(s) in
      *      seconds (0 means infinite)
-     * @param  values             An array of attribute values
-     * @param  defaultScope       The default scope to apply for values
      * @param  scopes             Scopes of the attribute values
+     * @param  values             A set of attribute values
      * @exception  SAMLException  Thrown if attribute cannot be built from the
      *      supplied information
      */
-    public ScopedAttribute(String name, String namespace, QName type, long lifetime, Object[] values,
-                           String defaultScope, String[] scopes)
+    public ScopedAttribute(String name, String namespace, String defaultScope, QName type, long lifetime,
+                           Collection scopes, Collection values)
         throws SAMLException
     {
         super(name, namespace, type, lifetime, values);
         this.defaultScope = defaultScope;
 
-        for (int i = 0; scopes != null && i < scopes.length; i++)
-            this.scopes.add(scopes[i]);
+        if (scopes != null)
+            this.scopes.addAll(scopes);
     }
 
     /**
@@ -109,34 +112,28 @@ public class ScopedAttribute extends SAMLAttribute
 
         // Default scope comes from subject.
         NodeList nlist = ((Element)e.getParentNode()).getElementsByTagNameNS(org.opensaml.XML.SAML_NS, "NameIdentifier");
-        if (nlist.getLength() != 1)
-            throw new InvalidAssertionException(SAMLException.RESPONDER, "ScopedAttribute() can't find saml:NameIdentifier in enclosing statement");
+        if (nlist ==null || nlist.getLength() != 1)
+            throw new MalformedException(SAMLException.RESPONDER, "ScopedAttribute() can't find saml:NameIdentifier in enclosing statement");
         defaultScope = ((Element)nlist.item(0)).getAttributeNS(null, "NameQualifier");
     }
 
     /**
-     *  Gets the values of the SAML Attribute, serialized as strings with the
-     *  effective scope appended
+     *  Adds a value to the state of the SAML Attribute<P>
+     *
+     *  This class supports a simple text node content model with a Scope
+     *  attribute
      *
-     * @return    The array of values
+     * @param  e  The AttributeValue element containing the value to add
+     * @return    true iff the value was understood
      */
-    public Object[] getValues()
+    public boolean addValue(Element e)
     {
-        if (values == null)
-            return null;
-
-        Object[] bufs = new Object[values.size()];
-        for (int i = 0; i < values.size(); i++)
+        if (super.addValue(e))
         {
-            if (values.get(i) != null)
-            {
-                if (scopes != null && i < scopes.size() && scopes.get(i) != null)
-                    bufs[i] = values.get(i).toString() + "@" + scopes.get(i);
-                else
-                    bufs[i] = values.get(i).toString() + "@" + defaultScope;
-            }
+            scopes.add(e.getAttributeNS(null,"Scope"));
+            return true;
         }
-        return bufs;
+        return false;
     }
 
     /**
@@ -153,22 +150,28 @@ public class ScopedAttribute extends SAMLAttribute
     }
 
     /**
-     *  Adds a value to the state of the SAML Attribute<P>
-     *
-     *  This class supports a simple text node content model with a Scope
-     *  attribute
+     *  Gets the values of the SAML Attribute, serialized as strings with the
+     *  effective scope appended
      *
-     * @param  e  The AttributeValue element containing the value to add
-     * @return    true iff the value was understood
+     * @return    The attribute's values
      */
-    public boolean addValue(Element e)
+    public Iterator getValues()
     {
-        if (super.addValue(e))
+        if (values == null)
+            return null;
+
+        ArrayList bufs = new ArrayList(values.size());
+        for (int i = 0; i < values.size(); i++)
         {
-            scopes.add(e.getAttributeNS(null,"Scope"));
-            return true;
+            if (values.get(i) != null)
+            {
+                if (i < scopes.size() && scopes.get(i) != null)
+                    bufs.set(i, values.get(i).toString() + "@" + scopes.get(i));
+                else
+                    bufs.set(i, values.get(i).toString() + "@" + defaultScope);
+            }
         }
-        return false;
+        return bufs.iterator();
     }
 
     /**
@@ -188,19 +191,38 @@ public class ScopedAttribute extends SAMLAttribute
     public Node toDOM(Document doc)
     {
         super.toDOM(doc);
-
-        NodeList nlist = ((Element)root).getElementsByTagNameNS(org.opensaml.XML.SAML_NS, "AttributeValue");
-        for (int i = 0; i < nlist.getLength(); i++)
+        
+        int i=0;
+        Node n=root.getFirstChild();
+        while (n!=null)
         {
-            ((Element)nlist.item(i)).removeAttributeNS(null, "Scope");
-            String scope=null;
-            if (i<scopes.size() && scopes.get(i)!=null)
-                scope=scopes.get(i).toString();
-            if (scope != null && scope.length()>0 && !scope.equals(defaultScope))
-                ((Element)nlist.item(i)).setAttributeNS(null, "Scope", scope);
+            if (n.getNodeType()==Node.ELEMENT_NODE)
+            {
+                ((Element)n).removeAttributeNS(null,"Scope");
+                if (scopes.get(i)!=null && !scopes.get(i).equals(defaultScope))
+                    ((Element)n).setAttributeNS(null,"Scope",(String)scopes.get(i));
+            }
+            n=n.getNextSibling();
         }
 
         return root;
     }
+
+    /**
+     *  Copies a SAML object such that no dependencies exist between the original
+     *  and the copy
+     * 
+     * @return      The new object
+     * @see java.lang.Object#clone()
+     */
+    public Object clone()
+        throws CloneNotSupportedException
+    {
+        ScopedAttribute dup=(ScopedAttribute)super.clone();
+
+        dup.scopes = (ArrayList)scopes.clone();
+
+        return dup;
+    }
 }
 
index dfda6ce..62da960 100755 (executable)
@@ -73,7 +73,6 @@ import org.apache.log4j.Logger;
 public class AASaml {
 
     String[] policies = { Constants.POLICY_CLUBSHIB };
-    String protocol = SAMLBinding.SAML_SOAP_HTTPS;
     String myName;
     StringBuffer sharName;
     String resource;
@@ -82,11 +81,11 @@ public class AASaml {
     SAMLBinding binding;
     private static Logger log = Logger.getLogger(AASaml.class.getName());        
 
-    public AASaml(String myName){
+    public AASaml(String myName) throws SAMLException {
        
        Init.init();
 
-       binding = SAMLBindingFactory.getInstance(protocol, policies);
+       binding = SAMLBindingFactory.getInstance(SAMLBinding.SAML_SOAP_HTTPS);
        this.myName = myName;
     }
 
@@ -129,24 +128,15 @@ public class AASaml {
            if(attrs == null || attrs.length == 0){
                sResp = new SAMLResponse(reqID,
                                         /* recipient URL*/ null,
-                                        /* sig */ null,
                                         /* no attrs -> no assersion*/ null,
-                                        exception);            
+                                        exception);
            }else{
                Date now = new Date();
                Date  then = null;
 
-               SAMLSubject rSubject = new SAMLSubject(sub.getName(),
-                                                      sub.getNameQualifier(),
-                                                      sub.getFormat(),
-                                                      sub.getConfirmationMethods(),
-                                                      sub.getConfirmationData());
-            
-               SAMLCondition[] conditions = new SAMLCondition[1];
-               conditions[0] = new SAMLAudienceRestrictionCondition(policies);
-
-               SAMLStatement[] statements = new SAMLStatement[1];
-               statements[0] = new SAMLAttributeStatement(rSubject, attrs);
+               SAMLSubject rSubject = (SAMLSubject)sub.clone();
+               SAMLCondition condition = new SAMLAudienceRestrictionCondition(Arrays.asList(policies));
+               SAMLStatement statement = new SAMLAttributeStatement(rSubject, Arrays.asList(attrs));
            
                long min = attrs[0].getLifetime();
                for(int i = 1; i < attrs.length; i++){
@@ -157,23 +147,23 @@ public class AASaml {
                if(min > 0)
                    then = new Date(now.getTime() + min);
 
-               SAMLAssertion sAssertion = new SAMLAssertion(myName,
+               SAMLAssertion sAssertion = new SAMLAssertion(
+                        myName,
                                             now,
                                             then,
-                                            conditions,
-                                            statements,
-                                            /* sig */ null);
-               SAMLAssertion[] assertions= new SAMLAssertion[1];
-               assertions[0] = sAssertion;
+                                            Collections.singleton(condition),
+                                            Collections.singleton(statement)
+                         );
 
                sResp = new SAMLResponse(reqID,
                                         /* recipient URL*/ null,
-                                        /* sig */ null,
-                                        assertions,
+                                        Collections.singleton(sAssertion),
                                         exception);
            }
        }catch (SAMLException se) {
            ourSE = se;
+    }catch (CloneNotSupportedException ex) {
+        ourSE = new SAMLException(SAMLException.RESPONDER,ex);
        }finally{
            binding.respond(resp,sResp,ourSE);      
        }
@@ -184,7 +174,6 @@ public class AASaml {
        try{
            SAMLResponse sResp = new SAMLResponse(reqID,
                                                  /* recipient URL*/ null,
-                                                 /* sig */ null,
                                                  /* an assersion*/ null,
                                                  exception);   
            binding.respond(resp, sResp, null);
index c1a9842..d120cb7 100755 (executable)
@@ -204,11 +204,11 @@ public class AAServlet extends HttpServlet {
            log.error("AA failed for "+userName+" because of: "+he);
            try{
                QName[] codes=new QName[2];
-               codes[0]=SAMLException.REQUESTER[0];
+               codes[0]=SAMLException.REQUESTER;
                codes[1]=new QName(
                                   edu.internet2.middleware.shibboleth.common.XML.SHIB_NS,
                                   "InvalidHandle");
-               saml.fail(resp, new SAMLException(codes, "AA got a HandleException: "+he));
+               saml.fail(resp, new SAMLException(Arrays.asList(codes), "AA got a HandleException: "+ he));
            }catch(Exception ee){
                throw new ServletException("AA failed to even make a SAML Failure message because "+ee+"  Original problem: "+he);
            }
index 66e8fe9..1e4a591 100644 (file)
@@ -1,5 +1,7 @@
 package edu.internet2.middleware.shibboleth.aaLocal.attributes;
 
+import java.util.Arrays;
+
 import edu.internet2.middleware.eduPerson.*;
 import edu.internet2.middleware.shibboleth.common.Constants; 
 import org.opensaml.*;
@@ -13,12 +15,11 @@ public class cmuAndrewId extends ScopedAttribute{
 
        super("urn:mace:eduPerson:1.0:eduPersonPrincipalName",
                   Constants.SHIB_ATTRIBUTE_NAMESPACE_URI, 
-                  new QName("urn:mace:eduPerson:1.0",
-                            "eduPersonPrincipalNameType"),
+           scopes[0],
+           null,
                   10*60,
-                  values,
-                  scopes[0],
-                  scopes);
+           Arrays.asList(scopes),
+                  Arrays.asList(values));
     }
 }
 
index 07c7b52..5441759 100644 (file)
@@ -9,6 +9,8 @@ package edu.internet2.middleware.shibboleth.aaLocal.attributes;
  * @created    June, 2002
  */
 
+import java.util.Arrays;
+
 import edu.internet2.middleware.eduPerson.*;
 import edu.internet2.middleware.shibboleth.common.Constants; 
 import edu.internet2.middleware.shibboleth.aa.ShibAttribute;
@@ -20,8 +22,6 @@ public class eduPersonAffiliation implements ShibAttribute{
     public SAMLAttribute toSamlAttribute(String defaultScope, Object[] values, String recipient)
        throws SAMLException{
 
-       String[] scopes = new String[values.length];
-
        for(int i=0; i<values.length; i++){
            String val = (String)values[i];
            if(val.equalsIgnoreCase("faculty") ||
@@ -38,12 +38,11 @@ public class eduPersonAffiliation implements ShibAttribute{
 
        return new ScopedAttribute("urn:mace:eduPerson:1.0:eduPersonAffiliation",
                   Constants.SHIB_ATTRIBUTE_NAMESPACE_URI, 
-                  new QName("urn:mace:eduPerson:1.0",
-                            "eduPersonAffiliationType"),
+           defaultScope,
+           null,
                   10*60,
-                  values,
-                  defaultScope,
-                  scopes);
+           null,
+                  Arrays.asList(values));
     }
 }
 
index 770318b..bb47613 100644 (file)
@@ -9,6 +9,8 @@ package edu.internet2.middleware.shibboleth.aaLocal.attributes;
  * @created    June, 2002
  */
 
+import java.util.Arrays;
+
 import edu.internet2.middleware.shibboleth.common.Constants; 
 import edu.internet2.middleware.shibboleth.aa.ShibAttribute;
 import org.opensaml.*;
@@ -23,7 +25,7 @@ public class eduPersonEntitlement implements ShibAttribute{
                                 Constants.SHIB_ATTRIBUTE_NAMESPACE_URI, 
                                 new QName(org.opensaml.XML.XSD_NS,"anyURI"),
                                 10*60,
-                                values);
+                                Arrays.asList(values));
 
     }
 }
index e8d07fa..e3d720b 100644 (file)
@@ -9,6 +9,8 @@ package edu.internet2.middleware.shibboleth.aaLocal.attributes;
  * @created    June, 2002
  */
 
+import java.util.Collections;
+
 import edu.internet2.middleware.eduPerson.*;
 import edu.internet2.middleware.shibboleth.common.Constants; 
 import edu.internet2.middleware.shibboleth.aa.ShibAttribute;
@@ -24,30 +26,29 @@ public class eduPersonPrincipalName implements ShibAttribute{
     public SAMLAttribute toSamlAttribute(String defaultScope, Object[] values, String recipient)
        throws SAMLException{
 
-       String scopes[] = new String[1];
-       String vals[] = new String[1];
+       String scope = null;
+       String val = null;
        String eppn = (String)values[0];
 
        int x = eppn.indexOf("@") ;
        log.debug("EPPN: "+eppn+"    @ at "+x);
        if(x > 0){
-           vals[0] = eppn.substring(0,x);
-           scopes[0] = eppn.substring(x+1);
+           val = eppn.substring(0,x);
+           scope = eppn.substring(x+1);
        }else{
-           vals[0] = eppn;
-           scopes[0] = defaultScope;
+           val = eppn;
+           scope = defaultScope;
        }
 
-       log.debug("Sending value="+vals[0]+"  scope="+scopes[0]);
+       log.debug("Sending value=" + val + ", scope=" + scope);
                
        return new ScopedAttribute("urn:mace:eduPerson:1.0:eduPersonPrincipalName",
                                 Constants.SHIB_ATTRIBUTE_NAMESPACE_URI, 
-                                new QName("urn:mace:eduPerson:1.0",
-                                          "eduPersonPrincipalNameType"),
+                 defaultScope,
+                                null,
                                 10*60,
-                                vals,
-                                defaultScope,
-                                scopes);
+                 Collections.singleton(scope),
+                                Collections.singleton(val));
 
     }
 
index 2b9afad..a41e9de 100755 (executable)
@@ -51,16 +51,12 @@ package edu.internet2.middleware.shibboleth.common;
 
 import java.security.Key;
 import java.security.KeyStore;
-import java.security.cert.X509Certificate;
 import java.security.interfaces.RSAPrivateKey;
+import java.util.Collection;
 import java.util.Date;
 
 import org.apache.xml.security.signature.XMLSignature;
-import org.opensaml.InvalidCryptoException;
-import org.opensaml.SAMLAuthorityBinding;
-import org.opensaml.SAMLException;
-import org.opensaml.SAMLResponse;
-import org.opensaml.SAMLSignedObject;
+import org.opensaml.*;
 
 /**
  *  ClubShib-specific POST browser profile implementation
@@ -73,45 +69,36 @@ public class ClubShibPOSTProfile extends ShibPOSTProfile
     /**
      *  SHIRE-side constructor for a ClubShibPOSTProfile object
      *
-     * @param  policies           Array of policy URIs that the implementation
+     * @param  policies           Set of policy URIs that the implementation
      *      must support
-     * @param  mapper             Interface between profile and trust base
      * @param  receiver           URL of SHIRE
      * @param  ttlSeconds         Length of time in seconds allowed to elapse
      *      from issuance of SAML response
      * @exception  SAMLException  Raised if a profile implementation cannot be
      *      constructed from the supplied information
      */
-    public ClubShibPOSTProfile(String[] policies, OriginSiteMapper mapper, String receiver, int ttlSeconds)
+    public ClubShibPOSTProfile(Collection policies, String receiver, int ttlSeconds)
         throws SAMLException
     {
-        super(policies, mapper, receiver, ttlSeconds);
-        int i;
-        for (i = 0; i < policies.length; i++)
-            if (policies[i].equals(Constants.POLICY_CLUBSHIB))
-                break;
-        if (i == policies.length)
+        super(policies, receiver, ttlSeconds);
+        if (!policies.contains(Constants.POLICY_CLUBSHIB))
             throw new SAMLException(SAMLException.REQUESTER, "ClubShibPOSTProfile() policy array must include Club Shib");
     }
 
     /**
      *  HS-side constructor for a ClubShibPOSTProfile object
      *
-     * @param  policies           Array of policy URIs that the implementation
+     * @param  policies           Set of policy URIs that the implementation
      *      must support
      * @param  issuer             "Official" name of issuing origin site
      * @exception  SAMLException  Raised if a profile implementation cannot be
      *      constructed from the supplied information
      */
-    public ClubShibPOSTProfile(String[] policies, String issuer)
+    public ClubShibPOSTProfile(Collection policies, String issuer)
         throws SAMLException
     {
         super(policies, issuer);
-        int i;
-        for (i = 0; i < policies.length; i++)
-            if (policies[i].equals(Constants.POLICY_CLUBSHIB))
-                break;
-        if (i == policies.length)
+        if (!policies.contains(Constants.POLICY_CLUBSHIB))
             throw new SAMLException(SAMLException.RESPONDER, "ClubShibPOSTProfile() policy array must include Club Shib");
     }
 
@@ -128,15 +115,15 @@ public class ClubShibPOSTProfile extends ShibPOSTProfile
      * @param  subjectIP          Client address of subject (optional)
      * @param  authMethod         URI of authentication method being asserted
      * @param  authInstant        Date and time of authentication being asserted
-     * @param  bindings           Array of SAML authorities the relying party
+     * @param  bindings           Set of SAML authorities the relying party
      *      may contact (optional)
      * @param  responseKey        A secret or private key to use in response
      *      signature or MAC
-     * @param  responseCert       A public key certificate to enclose with the
+     * @param  responseCert       One or more X.509 certificates to enclose with the
      *      response (optional)
      * @param  assertionKey       A secret or private key to use in assertion
      *      signature or MAC (optional)
-     * @param  assertionCert      A public key certificate to enclose with the
+     * @param  assertionCert      One or more X.509 certificates to enclose with the
      *      assertion (optional)
      * @return                    SAML response to send to accepting site
      * @exception  SAMLException  Base class of exceptions that may be thrown
@@ -148,9 +135,9 @@ public class ClubShibPOSTProfile extends ShibPOSTProfile
                                 String subjectIP,
                                 String authMethod,
                                 Date authInstant,
-                                SAMLAuthorityBinding[] bindings,
-                                Key responseKey, X509Certificate responseCert,
-                                Key assertionKey, X509Certificate assertionCert
+                                Collection bindings,
+                                Key responseKey, Collection responseCerts,
+                                Key assertionKey, Collection assertionCerts
                                 )
         throws SAMLException
     {
@@ -168,9 +155,9 @@ public class ClubShibPOSTProfile extends ShibPOSTProfile
             authInstant,
             bindings,
             responseKey,
-            responseCert,
+            responseCerts,
             assertionKey,
-            assertionCert);
+            assertionCerts);
     }
 
     /**
@@ -182,15 +169,16 @@ public class ClubShibPOSTProfile extends ShibPOSTProfile
      * @param  ks          A keystore containing trusted root certificates
      * @param  knownKey    An explicit key to use if a certificate cannot be
      *      found
-     * @return             The result of signature verification
+     * @param  simple      Verify according to simple SAML signature profile?
+     *
+     * @throws SAMLException    Thrown if the signature cannot be verified
      */
-    protected boolean verifySignature(SAMLSignedObject obj, String signerName, KeyStore ks, Key knownKey)
+    protected void verifySignature(SAMLSignedObject obj, String signerName, KeyStore ks, Key knownKey, boolean simple)
+        throws SAMLException
     {
-        if (!super.verifySignature(obj, signerName, ks, knownKey))
-            return false;
-        return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1.equals(
-            obj.getSignature().getSignedInfo().getSignatureMethodURI()
-            );
+        super.verifySignature(obj, signerName, ks, knownKey, simple);
+        if (!obj.getSignatureAlgorithm().equals(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1))
+            throw new TrustException(SAMLException.RESPONDER, "ClubShibPOSTProfile.verifySignature() requires the RSA-SHA1 signature algorithm");
     }
 }
 
index 56e3aa1..ebdefb6 100755 (executable)
@@ -60,6 +60,8 @@ import edu.internet2.middleware.shibboleth.common.XML.SchemaResolver;
 public class Init
 {
     private static boolean initialized = false;
+    
+    private static OriginSiteMapper mapper = null;
 
     /**  Initializes library */
     public static synchronized void init()
@@ -77,5 +79,25 @@ public class Init
     {
         Init.init();
     }
+    /**
+     *  Returns the mapper
+     * 
+     * @return OriginSiteMapper
+     */
+    public static synchronized OriginSiteMapper getMapper()
+    {
+        return mapper;
+    }
+
+    /**
+     *  Sets the mapper
+     * 
+     * @param mapper The mapper to set
+     */
+    public static synchronized void setMapper(OriginSiteMapper mapper)
+    {
+        Init.mapper = mapper;
+    }
+
 }
 
index 535fefb..b66b43b 100644 (file)
@@ -100,8 +100,6 @@ public interface OriginSiteMapper
      *  Gets a key store containing certificate entries that are trusted to sign
      *  Handle Service certificates that are encountered during processing<P>
      *
-     *
-     *
      * @return    A key store containing trusted certificate issuers
      */
     public abstract KeyStore getTrustedRoots();
index e0219e2..9e04e3a 100644 (file)
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  
- package edu.internet2.middleware.shibboleth.common;
+package edu.internet2.middleware.shibboleth.common;
+
+import java.util.Collection;
+
+import org.opensaml.QName;
+import org.opensaml.SAMLException;
 
 /**
- * Signals that an error occurred while creating or using an <code>OriginSiteMapper</code>
- * 
- * @author Walter Hoehn wassa&#064;columbia.edu
+ *  Indicates that an error occurred before or during the processing of a SAML
+ *  request/response exchange. <P>
  *
+ *
+ *
+ * @author     Scott Cantor
+ * @created    November 17, 2001
  */
-public class OriginSiteMapperException extends Exception {
-       
-       public OriginSiteMapperException(String message) {
-               super(message);
-       }
+public class OriginSiteMapperException extends SAMLException implements Cloneable
+{
+    /**
+     *  Creates a new OriginSiteMapperException
+     *
+     * @param  msg    The detail message
+     */
+    public OriginSiteMapperException(String msg)
+    {
+        super(msg);
+    }
+
+    /**
+     *  Creates a new OriginSiteMapperException
+     *
+     * @param  msg    The detail message
+     * @param  e      The exception to be wrapped in a OriginSiteMapperException
+     */
+    public OriginSiteMapperException(String msg, Exception e)
+    {
+        super(msg,e);
+    }
+
+    /**
+     *  Creates a new OriginSiteMapperException
+     *
+     * @param  codes  A collection of QNames
+     * @param  msg    The detail message
+     */
+    public OriginSiteMapperException(Collection codes, String msg)
+    {
+        super(codes,msg);
+    }
+
+    /**
+     *  Creates a new OriginSiteMapperException wrapping an existing exception <p>
+     *
+     *  The existing exception will be embedded in the new one, and its message
+     *  will become the default message for the OriginSiteMapperException.</p>
+     *
+     * @param  codes  A collection of QNames
+     * @param  e      The exception to be wrapped in a OriginSiteMapperException
+     */
+    public OriginSiteMapperException(Collection codes, Exception e)
+    {
+        super(codes,e);
+    }
+
+    /**
+     *  Creates a new OriginSiteMapperException from an existing exception. <p>
+     *
+     *  The existing exception will be embedded in the new one, but the new
+     *  exception will have its own message.</p>
+     *
+     * @param  codes  A collection of QNames
+     * @param  msg    The detail message
+     * @param  e      The exception to be wrapped in a OriginSiteMapperException
+     */
+    public OriginSiteMapperException(Collection codes, String msg, Exception e)
+    {
+        super(codes,msg,e);
+    }
+
+    /**
+     *  Creates a new OriginSiteMapperException
+     *
+     * @param  code   A status code
+     * @param  msg    The detail message
+     */
+    public OriginSiteMapperException(QName code, String msg)
+    {
+        super(code,msg);
+    }
+
+    /**
+     *  Creates a new OriginSiteMapperException wrapping an existing exception <p>
+     *
+     *  The existing exception will be embedded in the new one, and its message
+     *  will become the default message for the OriginSiteMapperException.</p>
+     *
+     * @param  code   A status code
+     * @param  e      The exception to be wrapped in a OriginSiteMapperException
+     */
+    public OriginSiteMapperException(QName code, Exception e)
+    {
+        super(code,e);
+    }
 
+    /**
+     *  Creates a new OriginSiteMapperException from an existing exception. <p>
+     *
+     *  The existing exception will be embedded in the new one, but the new
+     *  exception will have its own message.</p>
+     *
+     * @param  code   A status code
+     * @param  msg    The detail message
+     * @param  e      The exception to be wrapped in a OriginSiteMapperException
+     */
+    public OriginSiteMapperException(QName code, String msg, Exception e)
+    {
+        super(code,msg,e);
+    }
 }
 
index 6c634e4..cd3d9f2 100755 (executable)
 
 package edu.internet2.middleware.shibboleth.common;
 
-import org.opensaml.SAMLBinding;
-import org.opensaml.SAMLSOAPBinding;
+import java.util.Collection;
+
+import org.opensaml.*;
 
-import edu.internet2.middleware.shibboleth.common.*;
 
 /**
  *  Used by Shibboleth SHAR/AA to locate a SAML binding implementation
@@ -67,18 +67,15 @@ public class SAMLBindingFactory
      *  policies
      *
      * @param  protocol                          URI of SAML binding protocol
-     * @param  policies                          Array of policy URIs that the
-     *      implementation must support
      * @return                                   A compatible binding
-     *      implementation or null if one cannot be found
+     *      implementation
      */
-    public static SAMLBinding getInstance(String protocol, String[] policies)
+    public static SAMLBinding getInstance(String protocol)
+        throws SAMLException
     {
         // Current version only knows about SOAP binding and Club Shib...
         if (protocol == null || !protocol.equals(SAMLBinding.SAML_SOAP_HTTPS))
-            return null;
-        if (policies==null || policies.length!=1 || !policies[0].equals(Constants.POLICY_CLUBSHIB))
-            return null;
+            throw new UnsupportedProtocolException("SAMLBindingFactory.getInstance() unable to find binding implementation for specified protocol");            
         return new SAMLSOAPBinding();
     }
 }
index c0f7297..9e3adb8 100755 (executable)
  */
 
 package edu.internet2.middleware.shibboleth.common;
+
 import java.security.GeneralSecurityException;
 import java.security.Key;
 import java.security.KeyStore;
 import java.security.PrivateKey;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-
+import java.security.cert.*;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.Iterator;
+import java.util.Vector;
+
 import javax.crypto.SecretKey;
-import org.apache.xml.security.exceptions.XMLSecurityException;
-import org.apache.xml.security.keys.KeyInfo;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.NDC;
 import org.apache.xml.security.signature.XMLSignature;
 import org.opensaml.*;
-import org.w3c.dom.*;
-import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
 
 /**
  *  Basic Shibboleth POST browser profile implementation with basic support for
@@ -79,14 +82,11 @@ public class ShibPOSTProfile
     protected String algorithm = XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
 
     /**  Policy URIs to attach or check against */
-    protected String[] policies = null;
+    protected ArrayList policies = new ArrayList();
 
     /**  Official name of issuing site */
     protected String issuer = null;
 
-    /**  Abstract interface into trust base */
-    protected OriginSiteMapper mapper = null;
-
     /**  The URL of the receiving SHIRE */
     protected String receiver = null;
 
@@ -98,46 +98,41 @@ public class ShibPOSTProfile
     /**
      *  SHIRE-side constructor for a ShibPOSTProfile object
      *
-     * @param  policies           Array of policy URIs that the implementation
+     * @param  policies           Set of policy URIs that the implementation
      *      must support
-     * @param  mapper             Interface between profile and trust base
      * @param  receiver           URL of SHIRE
      * @param  ttlSeconds         Length of time in seconds allowed to elapse
      *      from issuance of SAML response
      * @exception  SAMLException  Raised if a profile implementation cannot be
      *      constructed from the supplied information
      */
-    public ShibPOSTProfile(String[] policies, OriginSiteMapper mapper, String receiver, int ttlSeconds)
+    public ShibPOSTProfile(Collection policies, String receiver, int ttlSeconds)
         throws SAMLException
     {
-        if (policies == null || policies.length == 0 || mapper == null ||
-            receiver == null || receiver.length() == 0 || ttlSeconds <= 0)
+        if (policies == null || policies.size() == 0 || receiver == null || receiver.length() == 0 || ttlSeconds <= 0)
             throw new SAMLException(SAMLException.REQUESTER, "ShibPOSTProfile() found a null or invalid argument");
 
-        this.mapper = mapper;
         this.receiver = receiver;
         this.ttlSeconds = ttlSeconds;
-        this.policies = new String[policies.length];
-        System.arraycopy(policies, 0, this.policies, 0, policies.length);
+        this.policies.addAll(policies);
     }
 
     /**
      *  HS-side constructor for a ShibPOSTProfile object
      *
-     * @param  policies           Array of policy URIs that the implementation
+     * @param  policies           Set of policy URIs that the implementation
      *      must support
      * @param  issuer             "Official" name of issuing origin site
      * @exception  SAMLException  Raised if a profile implementation cannot be
      *      constructed from the supplied information
      */
-    public ShibPOSTProfile(String[] policies, String issuer)
+    public ShibPOSTProfile(Collection policies, String issuer)
         throws SAMLException
     {
-        if (policies == null || policies.length == 0 || issuer == null || issuer.length() == 0)
+        if (policies == null || policies.size() == 0 || issuer == null || issuer.length() == 0)
             throw new SAMLException(SAMLException.REQUESTER, "ShibPOSTProfile() found a null or invalid argument");
         this.issuer = issuer;
-        this.policies = new String[policies.length];
-        System.arraycopy(policies, 0, this.policies, 0, policies.length);
+        this.policies.addAll(policies);
     }
 
     /**
@@ -147,8 +142,11 @@ public class ShibPOSTProfile
      *
      * @param  r          The response to the accepting site
      * @return            An SSO assertion
+     * 
+     * @throws SAMLException    Thrown if an SSO assertion can't be found
      */
     public SAMLAssertion getSSOAssertion(SAMLResponse r)
+        throws SAMLException
     {
         return SAMLPOSTProfile.getSSOAssertion(r,policies);
     }
@@ -159,10 +157,13 @@ public class ShibPOSTProfile
      *
      * @param  a  The SSO assertion sent to the accepting site
      * @return    A "bearer" authentication statement
+     *
+     * @throws SAMLException    Thrown if an SSO statement can't be found
      */
     public SAMLAuthenticationStatement getSSOStatement(SAMLAssertion a)
+        throws SAMLException
     {
-        return (a==null) ? null : SAMLPOSTProfile.getSSOStatement(a);
+        return SAMLPOSTProfile.getSSOStatement(a);
     }
 
     /**
@@ -174,8 +175,6 @@ public class ShibPOSTProfile
      *  origin site mapper, in accordance with general Shibboleth processing
      *  semantics. Club-specific processing must be performed in a subclass.<P>
      *
-     *
-     *
      * @param  buf                A Base-64 encoded buffer containing a SAML
      *      response
      * @return                    SAML response sent by origin site
@@ -194,40 +193,46 @@ public class ShibPOSTProfile
         // with its associated data. If we can't even find a SSO statement in the response
         // we just return the response to the caller, who will presumably notice this.
         SAMLAssertion assertion = getSSOAssertion(r);
-        if (assertion == null)
-            return r;
-
         SAMLAuthenticationStatement sso = getSSOStatement(assertion);
-        if (sso == null)
-            return r;
 
         // Examine the subject information.
         SAMLSubject subject = sso.getSubject();
         if (subject.getNameQualifier() == null)
-            throw new SAMLException(SAMLException.RESPONDER, "ShibPOSTProfile.accept() requires subject name qualifier");
+            throw new InvalidAssertionException(SAMLException.RESPONDER, "ShibPOSTProfile.accept() requires subject name qualifier");
 
         String originSite = subject.getNameQualifier();
         String handleService = assertion.getIssuer();
 
         // Is this a trusted HS?
+        OriginSiteMapper mapper=Init.getMapper();
         Iterator hsNames = mapper.getHandleServiceNames(originSite);
         boolean bFound = false;
-        while (!bFound && hsNames != null && hsNames.hasNext())
+        while (!bFound && hsNames.hasNext())
             if (hsNames.next().equals(handleService))
                 bFound = true;
         if (!bFound)
-            throw new SAMLException(SAMLException.RESPONDER, "ShibPOSTProfile.accept() detected an untrusted HS for the origin site");
+            throw new TrustException(SAMLException.RESPONDER, "ShibPOSTProfile.accept() detected an untrusted HS for the origin site");
 
         Key hsKey = mapper.getHandleServiceKey(handleService);
         KeyStore ks = mapper.getTrustedRoots();
 
         // Signature verification now takes place. We check the assertion and the response.
         // Assertion signing is optional, response signing is mandatory.
-        if (assertion.getSignature() != null && !verifySignature(assertion, handleService, ks, hsKey))
-            throw new SAMLException(SAMLException.RESPONDER, "ShibPOSTProfile.accept() detected an invalid assertion signature");
-        if (!verifySignature(r, handleService, ks, hsKey))
-            throw new SAMLException(SAMLException.RESPONDER, "ShibPOSTProfile.accept() detected an invalid response signature");
-
+        try
+        {
+            NDC.push("accept");
+            if (assertion.isSigned())
+            {
+                log.info("verifying assertion signature");
+                verifySignature(assertion, handleService, ks, hsKey, false);
+            }
+            log.info("verifying response signature");
+            verifySignature(r, handleService, ks, hsKey, true);
+        }
+        finally
+        {
+            NDC.pop();
+        }
         return r;
     }
 
@@ -235,23 +240,21 @@ public class ShibPOSTProfile
      *  Used by HS to generate a signed SAML response conforming to the POST
      *  profile<P>
      *
-     *
-     *
      * @param  recipient          URL of intended consumer
      * @param  name               Name of subject
      * @param  nameQualifier      Federates or qualifies subject name (optional)
      * @param  subjectIP          Client address of subject (optional)
      * @param  authMethod         URI of authentication method being asserted
      * @param  authInstant        Date and time of authentication being asserted
-     * @param  bindings           Array of SAML authorities the relying party
+     * @param  bindings           Set of SAML authorities the relying party
      *      may contact (optional)
      * @param  responseKey        A secret or private key to use in response
      *      signature or MAC
-     * @param  responseCert       A public key certificate to enclose with the
+     * @param  responseCert       One or more X.509 certificates to enclose with the
      *      response (optional)
      * @param  assertionKey       A secret or private key to use in assertion
      *      signature or MAC (optional)
-     * @param  assertionCert      A public key certificate to enclose with the
+     * @param  assertionCert      One or more X.509 certificates to enclose with the
      *      assertion (optional)
      * @return                    SAML response to send to accepting site
      * @exception  SAMLException  Base class of exceptions that may be thrown
@@ -263,9 +266,9 @@ public class ShibPOSTProfile
                                 String subjectIP,
                                 String authMethod,
                                 Date authInstant,
-                                SAMLAuthorityBinding[] bindings,
-                                Key responseKey, X509Certificate responseCert,
-                                Key assertionKey, X509Certificate assertionCert
+                                Collection bindings,
+                                Key responseKey, Collection responseCerts,
+                                Key assertionKey, Collection assertionCerts
                                 )
         throws SAMLException
     {
@@ -274,50 +277,26 @@ public class ShibPOSTProfile
         if (assertionKey != null && !(assertionKey instanceof PrivateKey) && !(assertionKey instanceof SecretKey))
             throw new InvalidCryptoException(SAMLException.RESPONDER, "ShibPOSTProfile.prepare() detected an invalid type of assertion key");
 
-        try
-        {
-            Document doc = org.opensaml.XML.parserPool.newDocument();
+        Document doc = org.opensaml.XML.parserPool.newDocument();
 
-            XMLSignature rsig = new XMLSignature(doc, null, algorithm);
-            XMLSignature asig = null;
-            if (assertionKey != null)
-                asig = new XMLSignature(doc, null, algorithm);
+        SAMLResponse r = SAMLPOSTProfile.prepare(
+            recipient,
+            issuer,
+            policies,
+            name,
+            nameQualifier,
+            null,
+            subjectIP,
+            authMethod,
+            authInstant,
+            bindings);
+        r.toDOM(doc);
 
-            SAMLResponse r = SAMLPOSTProfile.prepare(
-                recipient,
-                issuer,
-                policies,
-                name,
-                nameQualifier,
-                null,
-                subjectIP,
-                authMethod,
-                authInstant,
-                bindings,
-                rsig,
-                asig);
-            r.toDOM(doc);
-            if (asig != null)
-            {
-                if (assertionCert != null)
-                    asig.addKeyInfo(assertionCert);
-                if (assertionKey instanceof PrivateKey)
-                    asig.sign((PrivateKey)assertionKey);
-                else
-                    asig.sign((SecretKey)assertionKey);
-            }
-            if (responseCert != null)
-                rsig.addKeyInfo(responseCert);
-            if (responseKey instanceof PrivateKey)
-                rsig.sign((PrivateKey)responseKey);
-            else
-                rsig.sign((SecretKey)responseKey);
-            return r;
-        }
-        catch (XMLSecurityException e)
-        {
-            throw new InvalidCryptoException(SAMLException.RESPONDER, "ShibPOSTProfile.prepare() detected an XML security problem during signature creation", e);
-        }
+        if (assertionKey != null)
+            ((SAMLAssertion)r.getAssertions().next()).sign(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,assertionKey,assertionCerts,false);
+        r.sign(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,responseKey,responseCerts,true);
+        
+        return r;
     }
 
     /**
@@ -338,7 +317,7 @@ public class ShibPOSTProfile
 
     /**
      *  Default signature verification algorithm uses an embedded X509
-     *  certificate or an explicit key to verify the signature. The certificate
+     *  certificate(s) or an explicit key to verify the signature. The certificate
      *  is examined to insure the subject CN matches the signer, and that it is
      *  signed by a trusted CA
      *
@@ -347,70 +326,86 @@ public class ShibPOSTProfile
      * @param  ks          A keystore containing trusted root certificates
      * @param  knownKey    An explicit key to use if a certificate cannot be
      *      found
-     * @return             The result of signature verification
+     * @param  simple      Verify according to simple SAML signature profile?
+     * 
+     * @throws SAMLException    Thrown if the signature cannot be verified
      */
-    protected boolean verifySignature(SAMLSignedObject obj, String signerName, KeyStore ks, Key knownKey)
+    protected void verifySignature(SAMLSignedObject obj, String signerName, KeyStore ks, Key knownKey, boolean simple)
+        throws SAMLException
     {
         try
         {
-            XMLSignature sig = (obj != null) ? obj.getSignature() : null;
-            if (sig == null) {
-                log.warn("verifySignature() unable to find a signature");
-                return false;
+            NDC.push("verifySignature");
+            
+            if (!obj.isSigned())
+            {
+                log.error("unable to find a signature");
+                throw new TrustException(SAMLException.RESPONDER, "ShibPOSTProfile.verifySignature() given an unsigned object");
+            }
+            
+            if (knownKey != null)
+            {
+                log.info("verifying signature with known key value, ignoring signature KeyInfo");
+                obj.verify(knownKey,simple);
+                return;
             }
-            KeyInfo ki = sig.getKeyInfo();
-            if (ks != null && ki != null)
+            
+            log.info("verifying signature with embedded KeyInfo");
+            obj.verify(simple);
+            
+            // This is pretty painful, and this is leveraging the supposedly automatic support in JDK 1.4.
+            // First we have to extract the certificates from the object.
+            Iterator certs_from_obj = obj.getX509Certificates();
+            if (!certs_from_obj.hasNext())
             {
-                X509Certificate cert = ki.getX509Certificate();
-                if (cert != null)
-                {
-                    cert.checkValidity();
-                    if (!sig.checkSignatureValue(cert)) {
-                        log.warn("verifySignature() failed to verify signature using embedded certificate");
-                        return false;
-                    }
-                    if (signerName != null)
-                    {
-                        String dname = cert.getSubjectDN().getName();
-                        log.debug("verifySignature() found cert with DN: " + dname);
-                        String cname = "CN=" + signerName;
-                        if (!dname.equalsIgnoreCase(cname) && !dname.regionMatches(true, 0, cname + ',', 0, cname.length() + 1)) {
-                            log.warn("verifySignature() found a mismatch between the certificate DN and the expected signer: " + signerName);
-                            return false;
-                        }
-                    }
+                log.error("need certificates inside object to establish trust");
+                throw new TrustException(SAMLException.RESPONDER, "ShibPOSTProfile.verifySignature() can't find any certificates");
+            }
+            
+            // We assume the first one in the set is the end entity cert.
+            X509Certificate entity_cert = (X509Certificate)certs_from_obj.next();
 
-                    String iname = cert.getIssuerDN().getName();
-                    for (Enumeration aliases = ks.aliases(); aliases.hasMoreElements(); )
-                    {
-                        String alias = (String)aliases.nextElement();
-                        if (!ks.isCertificateEntry(alias))
-                            continue;
-                        Certificate cacert = ks.getCertificate(alias);
-                        if (!(cacert instanceof X509Certificate))
-                            continue;
-                        if (iname.equals(((X509Certificate)cacert).getSubjectDN().getName()))
-                        {
-                            cert.verify(cacert.getPublicKey());
-                            ((X509Certificate)cacert).checkValidity();
-                            return true;
-                        }
-                    }
-                    log.warn("verifySignature() unable to locate the cert issuer (" + iname + ") in the CA store");
-                    return false;
-                }
+            // Match the CN of the entity cert with the expected signer.
+            String dname = entity_cert.getSubjectDN().getName();
+            log.debug("found entity cert with DN: " + dname);
+            String cname = "CN=" + signerName;
+            if (!dname.equalsIgnoreCase(cname) && !dname.regionMatches(true, 0, cname + ',', 0, cname.length() + 1))
+            {
+                log.error("verifySignature() found a mismatch between the entity certificate's DN and the expected signer: " + signerName);
+                throw new TrustException(SAMLException.RESPONDER, "ShibPOSTProfile.verifySignature() found mismatch between entity certificate and expected signer");
             }
-            return (knownKey != null) ? sig.checkSignatureValue(knownKey) : false;
+            
+            // Prep a chain between the entity cert and the trusted roots.
+            X509CertSelector targetConstraints = new X509CertSelector();
+            targetConstraints.setCertificate(entity_cert);
+            PKIXBuilderParameters params = new PKIXBuilderParameters(ks, targetConstraints);
+            params.setMaxPathLength(-1);
+            
+            Vector certbag = new Vector();
+            certbag.add(entity_cert);
+            while (certs_from_obj.hasNext())
+                certbag.add(certs_from_obj.next());
+            CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(certbag);
+            CertStore store = CertStore.getInstance("Collection", ccsp);
+            params.addCertStore(store);
+            
+            // Attempt to build a path.
+            CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
+            PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult)cpb.build(params);
         }
-        catch (XMLSecurityException e)
+        catch (CertPathBuilderException e)
         {
-            e.printStackTrace();
-            return false;
+            log.error("caught a cert path builder exception: " + e.getMessage());
+            throw new TrustException(SAMLException.RESPONDER, "ShibPOSTProfile.verifySignature() unable to build a PKIX certificate path", e);
         }
         catch (GeneralSecurityException e)
         {
-            e.printStackTrace();
-            return false;
+            log.error("caught a general security exception: " + e.getMessage());
+            throw new TrustException(SAMLException.RESPONDER, "ShibPOSTProfile.verifySignature() unable to build a PKIX certificate path", e);
+        }
+        finally
+        {
+            NDC.pop();
         }
     }
 }
index 3b8dd94..115249a 100755 (executable)
@@ -49,7 +49,8 @@
 
 package edu.internet2.middleware.shibboleth.common;
 
-import java.security.Key;
+import java.util.Collection;
+
 import org.opensaml.SAMLException;
 import org.opensaml.SAMLPOSTProfile;
 
@@ -67,9 +68,8 @@ public class ShibPOSTProfileFactory
      *  Gets a compatible SHIRE-side profile implementation for the specified
      *  policies
      *
-     * @param  policies           Array of policy URIs that the implementation
+     * @param  policies           Set of policy URIs that the implementation
      *      must support
-     * @param  mapper             Interface between profile and trust base
      * @param  receiver           URL of SHIRE
      * @param  ttlSeconds         Length of time in seconds allowed to elapse
      *      from issuance of SAML response
@@ -78,25 +78,24 @@ public class ShibPOSTProfileFactory
      * @exception  SAMLException  Raised if a profile implementation cannot be
      *      constructed from the supplied information
      */
-    public static ShibPOSTProfile getInstance(String[] policies, OriginSiteMapper mapper,
-                                              String receiver, int ttlSeconds)
+    public static ShibPOSTProfile getInstance(Collection policies, String receiver, int ttlSeconds)
         throws SAMLException
     {
         // Current version only knows about Club Shib...
-        if (policies == null || policies.length != 1 || !policies[0].equals(Constants.POLICY_CLUBSHIB))
+        if (policies == null || !policies.contains(Constants.POLICY_CLUBSHIB))
             return null;
 
-        if (mapper == null || receiver == null || ttlSeconds <= 0)
+        if (receiver == null || ttlSeconds <= 0)
             return null;
 
-        return new ClubShibPOSTProfile(policies, mapper, receiver, ttlSeconds);
+        return new ClubShibPOSTProfile(policies, receiver, ttlSeconds);
     }
 
     /**
      *  Gets a compatible HS-side profile implementation for the specified
      *  policies
      *
-     * @param  policies           Array of policy URIs that the implementation
+     * @param  policies           Set of policy URIs that the implementation
      *      must support
      * @param  issuer             "Official" name of issuing origin site
      * @return                    A compatible profile implementation or null if
@@ -104,11 +103,11 @@ public class ShibPOSTProfileFactory
      * @exception  SAMLException  Raised if a profile implementation cannot be
      *      constructed from the supplied information
      */
-    public static ShibPOSTProfile getInstance(String[] policies, String issuer)
+    public static ShibPOSTProfile getInstance(Collection policies, String issuer)
         throws SAMLException
     {
         // Current version only knows about Club Shib...
-        if (policies == null || policies.length != 1 || !policies[0].equals(Constants.POLICY_CLUBSHIB))
+        if (policies == null || !policies.contains(Constants.POLICY_CLUBSHIB))
             return null;
 
         if (issuer == null || issuer.length() == 0)
index 3502b24..0b2353f 100644 (file)
@@ -149,6 +149,9 @@ public class SiteSigner
         if (keystore == null || keystore.length() == 0 ||
             key_alias == null || key_alias.length() == 0)
             printUsage();
+            
+        if (key_pass == null)
+            key_pass = ks_pass;
 
         KeyStore ks = KeyStore.getInstance("JKS");
         FileInputStream fis = new FileInputStream(keystore);
diff --git a/src/edu/internet2/middleware/shibboleth/common/UnsupportedProtocolException.java b/src/edu/internet2/middleware/shibboleth/common/UnsupportedProtocolException.java
new file mode 100644 (file)
index 0000000..34ad75a
--- /dev/null
@@ -0,0 +1,169 @@
+/* 
+ * The OpenSAML 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 OpenSAML 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 opensaml@opensaml.org
+ * 
+ * Products derived from this software may not be called OpenSAML, Internet2, 
+ * UCAID, or the University Corporation for Advanced Internet Development, nor 
+ * may OpenSAML 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.common;
+
+import java.util.Collection;
+
+import org.opensaml.QName;
+import org.opensaml.SAMLException;
+
+/**
+ *  Indicates that an error occurred before or during the processing of a SAML
+ *  request/response exchange. <P>
+ *
+ *
+ *
+ * @author     Scott Cantor
+ * @created    November 17, 2001
+ */
+public class UnsupportedProtocolException extends SAMLException implements Cloneable
+{
+    /**
+     *  Creates a new UnsupportedProtocolException
+     *
+     * @param  msg    The detail message
+     */
+    public UnsupportedProtocolException(String msg)
+    {
+        super(msg);
+    }
+
+    /**
+     *  Creates a new UnsupportedProtocolException
+     *
+     * @param  msg    The detail message
+     * @param  e      The exception to be wrapped in a UnsupportedProtocolException
+     */
+    public UnsupportedProtocolException(String msg, Exception e)
+    {
+        super(msg,e);
+    }
+
+    /**
+     *  Creates a new UnsupportedProtocolException
+     *
+     * @param  codes  A collection of QNames
+     * @param  msg    The detail message
+     */
+    public UnsupportedProtocolException(Collection codes, String msg)
+    {
+        super(codes,msg);
+    }
+
+    /**
+     *  Creates a new UnsupportedProtocolException wrapping an existing exception <p>
+     *
+     *  The existing exception will be embedded in the new one, and its message
+     *  will become the default message for the UnsupportedProtocolException.</p>
+     *
+     * @param  codes  A collection of QNames
+     * @param  e      The exception to be wrapped in a UnsupportedProtocolException
+     */
+    public UnsupportedProtocolException(Collection codes, Exception e)
+    {
+        super(codes,e);
+    }
+
+    /**
+     *  Creates a new UnsupportedProtocolException from an existing exception. <p>
+     *
+     *  The existing exception will be embedded in the new one, but the new
+     *  exception will have its own message.</p>
+     *
+     * @param  codes  A collection of QNames
+     * @param  msg    The detail message
+     * @param  e      The exception to be wrapped in a UnsupportedProtocolException
+     */
+    public UnsupportedProtocolException(Collection codes, String msg, Exception e)
+    {
+        super(codes,msg,e);
+    }
+
+    /**
+     *  Creates a new UnsupportedProtocolException
+     *
+     * @param  code   A status code
+     * @param  msg    The detail message
+     */
+    public UnsupportedProtocolException(QName code, String msg)
+    {
+        super(code,msg);
+    }
+
+    /**
+     *  Creates a new UnsupportedProtocolException wrapping an existing exception <p>
+     *
+     *  The existing exception will be embedded in the new one, and its message
+     *  will become the default message for the UnsupportedProtocolException.</p>
+     *
+     * @param  code   A status code
+     * @param  e      The exception to be wrapped in a UnsupportedProtocolException
+     */
+    public UnsupportedProtocolException(QName code, Exception e)
+    {
+        super(code,e);
+    }
+
+    /**
+     *  Creates a new UnsupportedProtocolException from an existing exception. <p>
+     *
+     *  The existing exception will be embedded in the new one, but the new
+     *  exception will have its own message.</p>
+     *
+     * @param  code   A status code
+     * @param  msg    The detail message
+     * @param  e      The exception to be wrapped in a UnsupportedProtocolException
+     */
+    public UnsupportedProtocolException(QName code, String msg, Exception e)
+    {
+        super(code,msg,e);
+    }
+}
+
index 53874f5..731064a 100755 (executable)
@@ -64,7 +64,7 @@ public class HandleServiceSAML {
     public String[] policies = { Constants.POLICY_CLUBSHIB };
     private ShibPOSTProfile spp;
     PrivateKey privateKey;
-    X509Certificate cert;
+    java.security.cert.Certificate[] certs;
 
     public HandleServiceSAML( String domain, String AAurl, String HSname,
                              String KSpass, String KSkeyalias,
@@ -78,9 +78,9 @@ public class HandleServiceSAML {
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load( is, KSpass.toCharArray());
        privateKey = (PrivateKey)ks.getKey(KSkeyalias, KSkeypass.toCharArray());
-       cert =(X509Certificate)ks.getCertificate(certalias);
+       certs = ks.getCertificateChain(certalias);
        
-       spp = ShibPOSTProfileFactory.getInstance( policies, HSname );
+       spp = ShibPOSTProfileFactory.getInstance( Arrays.asList(policies), HSname );
     }
     
     public byte[] prepare ( String handle, String shireURL, 
@@ -88,13 +88,13 @@ public class HandleServiceSAML {
        throws HandleException {
 
        try { 
-           SAMLAuthorityBinding[] bindings = new SAMLAuthorityBinding[1];
-           bindings[0] = new SAMLAuthorityBinding
-               ( SAMLBinding.SAML_SOAP_HTTPS, AAurl, 
-                 new QName(org.opensaml.XML.SAMLP_NS,"AttributeQuery") );
+           SAMLAuthorityBinding binding =
+            new SAMLAuthorityBinding(SAMLBinding.SAML_SOAP_HTTPS, AAurl, 
+                                             new QName(org.opensaml.XML.SAMLP_NS,"AttributeQuery")
+                                      );
            SAMLResponse r = spp.prepare 
            ( shireURL, handle, domain, clientAddress, authMethod, 
-             authInstant, bindings, privateKey, cert, null, null
+             authInstant, Collections.singleton(binding), privateKey, Arrays.asList(certs), null, null
              );
            byte[] buf = r.toBase64();