Glue SOAP client to SP config, expand policy settings.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 14 Feb 2007 05:30:12 +0000 (05:30 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 14 Feb 2007 05:30:12 +0000 (05:30 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2168 cb58f699-b61c-0410-a6fe-9272a202ed29

.cdtproject
configs/shibboleth.xml.in
schemas/shibboleth-spconfig-2.0.xsd
shibsp/Makefile.am
shibsp/ServiceProvider.h
shibsp/binding/SOAPClient.h [new file with mode: 0644]
shibsp/binding/impl/SOAPClient.cpp [new file with mode: 0644]
shibsp/impl/XMLServiceProvider.cpp
shibsp/shibsp.vcproj
util/samlquery.cpp

index c794717..79144f7 100644 (file)
@@ -8,12 +8,10 @@
         
     <item id="org.eclipse.cdt.core.pathentry">
 <pathentry kind="out" path=""/>
-<pathentry kind="src" path="apache"/>
-<pathentry kind="src" path="isapi_shib"/>
-<pathentry kind="src" path="nsapi_shib"/>
-<pathentry kind="src" path="odbc-store"/>
-<pathentry excluding="util/|impl/|security/|metadata/|remoting/|remoting/impl/|attribute/" kind="src" path="shibsp"/>
+<pathentry excluding="util/|impl/|security/|metadata/|remoting/|remoting/impl/|attribute/|binding/|binding/impl/" kind="src" path="shibsp"/>
 <pathentry kind="src" path="shibsp/attribute"/>
+<pathentry excluding="impl/" kind="src" path="shibsp/binding"/>
+<pathentry kind="src" path="shibsp/binding/impl"/>
 <pathentry kind="src" path="shibsp/impl"/>
 <pathentry kind="src" path="shibsp/metadata"/>
 <pathentry excluding="impl/" kind="src" path="shibsp/remoting"/>
 <pathentry kind="src" path="shibsp/security"/>
 <pathentry kind="src" path="shibsp/util"/>
 <pathentry kind="src" path="shibd"/>
+<pathentry kind="src" path="apache"/>
+<pathentry kind="src" path="isapi_shib"/>
+<pathentry kind="src" path="nsapi_shib"/>
+<pathentry kind="src" path="odbc-store"/>
 <pathentry kind="src" path="util"/>
 </item>
 </data>
index b41fda3..e24d5c3 100644 (file)
        Resource requests are mapped in the Local section into an applicationId that
        points into to this section.
        -->
-       <Applications id="default" providerId="https://sp.example.org/shibboleth"
+       <Applications id="default" policyId="default" providerId="https://sp.example.org/shibboleth"
                homeURL="https://sp.example.org/index.html">
 
                <!--
                impact on the security of the SP. Stealing cookies/sessions is much easier with this
                disabled.
                -->
-               <Sessions lifetime="7200" timeout="3600" checkAddress="false"
+               <Sessions lifetime="28800" timeout="3600" checkAddress="false"
                        handlerURL="/Shibboleth.sso" handlerSSL="false" idpHistory="true" idpHistoryDays="7">
                        
                        <!--
                </CredentialResolver>
        </Credentials>
 
-       <!-- Each policy defines a set of rules to use to secure SAML (and other) messages. -->
-       <SecurityPolicies default="full">
-               <!-- The predefined policy handles SAML 1 and 2 protocols and permits signing and TLS. -->
-               <Policy id="full">
+       <!-- Each policy defines a set of rules to use to secure SAML and SOAP messages. -->
+       <SecurityPolicies>
+               <!-- The predefined policy handles SAML 1 and 2 protocols and permits signing and client TLS. -->
+               <Policy id="default"
+                       validate="false"
+                       signedAssertions="false"
+                       requireConfidentiality="true"
+                       requireTransportAuth="true"
+                       connectTimeout="15" timeout="30"
+                       >
                        <Rule type="SAML1Message"/>
                        <Rule type="SAML2Message"/>
                        <Rule type="MessageFlow" checkReplay="true" expires="60"/>
index 87d9bc0..4054f2e 100644 (file)
@@ -50,8 +50,8 @@
                                <element ref="conf:Credentials" minOccurs="0"/>
                                <element ref="conf:SecurityPolicies"/>
                        </sequence>
-                       <attribute name="logger" type="anyURI" use="optional"/>
-                       <attribute name="clockSkew" type="unsignedInt" use="optional"/>
+                       <attribute name="logger" type="anyURI"/>
+                       <attribute name="clockSkew" type="unsignedInt"/>
                        <anyAttribute namespace="##other" processContents="lax"/>
                </complexType>\r
        </element>\r
@@ -70,7 +70,7 @@
                                                                        <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
                                                                </sequence>\r
                                                                <attribute name="path" type="anyURI" use="required"/>\r
-                                                               <attribute name="fatal" type="boolean" use="optional"/>\r
+                                                               <attribute name="fatal" type="boolean" default="true"/>\r
                                                        </restriction>\r
                                                </complexContent>\r
                                        </complexType>\r
@@ -91,7 +91,7 @@
                                                <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
                                        </sequence>\r
                                        <attribute name="id" type="conf:string" use="required"/>\r
-                                       <attribute name="cleanupInterval" type="unsignedInt" use="optional" default="900"/>\r
+                                       <attribute name="cleanupInterval" type="unsignedInt" default="900"/>\r
                                        <anyAttribute namespace="##any" processContents="lax"/>\r
                                </restriction>\r
                        </complexContent>\r
                                        <sequence>\r
                                                <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
                                        </sequence>\r
-                                       <attribute name="cacheTimeout" type="unsignedInt" use="optional" default="28800"/>\r
+                                       <attribute name="cacheTimeout" type="unsignedInt" default="28800"/>\r
                                        <anyAttribute namespace="##any" processContents="lax"/>\r
                                </restriction>\r
                        </complexContent>\r
                                                <complexType>
                                                        <attribute name="address" type="conf:string" use="required"/>
                                                        <attribute name="port" type="unsignedInt" use="required"/>
-                                                       <attribute name="acl" type="conf:listOfStrings" use="optional" default="127.0.0.1"/>
+                                                       <attribute name="acl" type="conf:listOfStrings" default="127.0.0.1"/>
                                                </complexType>
                                        </element>
                                        <element name="Listener" type="conf:PluggableType"/>
                                <element ref="conf:ReplayCache" minOccurs="0"/>
                                <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                        </sequence>
-                       <attribute name="logger" type="anyURI" use="optional"/>
+                       <attribute name="logger" type="anyURI"/>
                        <anyAttribute namespace="##other" processContents="lax"/>\r
                </complexType>\r
        </element>\r
                                </element>
                                <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                        </sequence>
-                       <attribute name="logger" type="anyURI" use="optional"/>
-                       <attribute name="localRelayState" type="boolean" use="optional" default="false"/>
+                       <attribute name="logger" type="anyURI"/>
+                       <attribute name="localRelayState" type="boolean" default="false"/>
                        <anyAttribute namespace="##other" processContents="lax"/>\r
                </complexType>\r
        </element>\r
                                                </sequence>\r
                                                <attribute name="id" type="unsignedInt" use="required"/>\r
                                                <attribute name="name" type="conf:string" use="required"/>\r
-                                               <attribute name="port" type="unsignedInt" use="optional"/>\r
-                                               <attribute name="sslport" type="unsignedInt" use="optional"/>\r
-                                               <attribute name="scheme" type="conf:string" use="optional"/>\r
+                                               <attribute name="port" type="unsignedInt"/>\r
+                                               <attribute name="sslport" type="unsignedInt"/>\r
+                                               <attribute name="scheme" type="conf:string"/>\r
                                        </complexType>\r
                                </element>\r
                                <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
                        </sequence>\r
-                       <attribute name="normalizeRequest" type="boolean" use="optional"/>\r
+                       <attribute name="normalizeRequest" type="boolean" default="true"/>\r
                        <anyAttribute namespace="##other" processContents="lax"/>\r
                </complexType>\r
        </element>\r
        </element>\r
        \r
        <attributeGroup name="ContentSettings">\r
-               <attribute name="authType" type="conf:string" use="optional"/>\r
-               <attribute name="requireSession" type="boolean" use="optional"/>\r
-               <attribute name="requireSessionWith" type="conf:string" use="optional"/>\r
-               <attribute name="exportAssertion" type="boolean" use="optional"/>\r
-               <attribute name="redirectToSSL" type="unsignedInt" use="optional"/>\r
+               <attribute name="authType" type="conf:string"/>\r
+               <attribute name="requireSession" type="boolean"/>\r
+               <attribute name="requireSessionWith" type="conf:string"/>\r
+               <attribute name="exportAssertion" type="boolean"/>\r
+               <attribute name="redirectToSSL" type="unsignedInt"/>\r
                <anyAttribute namespace="##other" processContents="lax"/>\r
        </attributeGroup>\r
        <element name="AccessControlProvider" type="conf:PluggableType"/>\r
                    </choice>\r
                        <element ref="conf:Path" minOccurs="0" maxOccurs="unbounded"/>\r
                </sequence>\r
-               <attribute name="scheme" use="optional">\r
+               <attribute name="scheme">\r
                            <simpleType>\r
                                <restriction base="conf:string">\r
                                    <enumeration value="http"/>\r
                            </simpleType>\r
                </attribute>\r
                <attribute name="name" type="conf:string" use="required"/>\r
-               <attribute name="port" type="unsignedInt" use="optional"/>\r
-               <attribute name="applicationId" type="conf:string" use="optional"/>\r
+               <attribute name="port" type="unsignedInt"/>\r
+               <attribute name="applicationId" type="conf:string"/>\r
                <attributeGroup ref="conf:ContentSettings"/>\r
        </complexType>\r
     </element>\r
                        <element ref="conf:Path" minOccurs="0" maxOccurs="unbounded"/>\r
                </sequence>\r
                <attribute name="name" type="conf:string" use="required"/>\r
-               <attribute name="applicationId" type="conf:string" use="optional"/>\r
+               <attribute name="applicationId" type="conf:string"/>\r
                <attributeGroup ref="conf:ContentSettings"/>\r
         </complexType>\r
     </element>\r
                        </sequence>\r
                        <attribute name="id" type="conf:string" fixed="default"/>\r
                        <attribute name="providerId" type="anyURI" use="required"/>\r
-                       <attribute name="homeURL" type="anyURI" use="optional"/>\r
+                       <attribute name="policyId" type="conf:string" use="required"/>\r
+                       <attribute name="homeURL" type="anyURI"/>\r
                <anyAttribute namespace="##other" processContents="lax"/>\r
                </complexType>\r
        </element>\r
                                <element name="TrustEngine" type="conf:PluggableType" minOccurs="0"/>\r
                        </sequence>\r
                        <attribute name="id" type="conf:string" use="required"/>\r
-                       <attribute name="providerId" type="anyURI" use="optional"/>\r
-                       <attribute name="homeURL" type="anyURI" use="optional"/>\r
+                       <attribute name="providerId" type="anyURI"/>\r
+                       <attribute name="policyId" type="conf:string"/>\r
+                       <attribute name="homeURL" type="anyURI"/>\r
                <anyAttribute namespace="##other" processContents="lax"/>\r
                </complexType>\r
        </element>\r
                                        </complexType>\r
                                </element>\r
                        </choice>\r
-                       <attribute name="handlerURL" type="anyURI" use="optional"/>\r
-                       <attribute name="handlerSSL" type="boolean" use="optional" default="true"/>\r
-                       <attribute name="cookieName" type="conf:string" use="optional"/>\r
-                       <attribute name="cookieProps" type="conf:string" use="optional"/>\r
-                       <attribute name="idpHistory" type="boolean" use="optional" default="true"/>\r
-                       <attribute name="idpHistoryDays" type="unsignedInt" use="optional"/>\r
-                       <attribute name="lifetime" type="unsignedInt" use="optional"/>\r
-                       <attribute name="timeout" type="unsignedInt" use="optional"/>\r
-                       <attribute name="checkAddress" type="boolean" use="optional"/>\r
-                       <attribute name="consistentAddress" type="boolean" use="optional" default="true"/>\r
-                       <attribute name="validate" type="boolean" use="optional"/>\r
+                       <attribute name="handlerURL" type="anyURI"/>\r
+                       <attribute name="handlerSSL" type="boolean" default="true"/>\r
+                       <attribute name="cookieName" type="conf:string"/>\r
+                       <attribute name="cookieProps" type="conf:string"/>\r
+                       <attribute name="idpHistory" type="boolean" default="true"/>\r
+                       <attribute name="idpHistoryDays" type="unsignedInt"/>\r
+                       <attribute name="lifetime" type="unsignedInt" default="28800"/>\r
+                       <attribute name="timeout" type="unsignedInt" default="3600"/>\r
+                       <attribute name="checkAddress" type="boolean" default="true"/>\r
+                       <attribute name="consistentAddress" type="boolean" default="true"/>\r
                        <anyAttribute namespace="##other" processContents="lax"/>\r
                </complexType>\r
        </element>\r
                        </sequence>\r
                        <attribute name="Location" type="anyURI" use="required"/>\r
                        <attribute name="Binding" type="anyURI" use="required"/>\r
-                       <attribute name="wayfURL" type="anyURI" use="optional"/>\r
-                       <attribute name="wayfBinding" type="anyURI" use="optional"/>\r
-                       <attribute name="checkCDC" type="anyURI" use="optional"/>\r
-                       <attribute name="isDefault" type="boolean" use="optional"/>\r
-                       <attribute name="id" type="conf:string" use="optional"/>\r
+                       <attribute name="wayfURL" type="anyURI"/>\r
+                       <attribute name="wayfBinding" type="anyURI"/>\r
+                       <attribute name="isDefault" type="boolean"/>\r
+                       <attribute name="id" type="conf:string"/>\r
                        <anyAttribute namespace="##any" processContents="lax"/>\r
                </complexType>\r
        </element>\r
                                <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
                        </sequence>\r
                        <attribute name="session" type="anyURI" use="required"/>\r
-                       <attribute name="metadata" type="anyURI" use="optional"/>\r
-                       <attribute name="rm" type="anyURI" use="optional"/>\r
-                       <attribute name="access" type="anyURI" use="optional"/>\r
-                       <attribute name="ssl" type="anyURI" use="optional"/>\r
-                       <attribute name="supportContact" type="conf:string" use="optional"/>\r
-                       <attribute name="logoLocation" type="anyURI" use="optional"/>\r
-                       <attribute name="styleSheet" type="anyURI" use="optional"/>\r
+                       <attribute name="metadata" type="anyURI"/>\r
+                       <attribute name="rm" type="anyURI"/>\r
+                       <attribute name="access" type="anyURI"/>\r
+                       <attribute name="ssl" type="anyURI"/>\r
+                       <attribute name="supportContact" type="conf:string"/>\r
+                       <attribute name="logoLocation" type="anyURI"/>\r
+                       <attribute name="styleSheet" type="anyURI"/>\r
                        <anyAttribute namespace="##any" processContents="lax"/>\r
                </complexType>\r
        </element>\r
 \r
        <attributeGroup name="CredentialUseGroup">\r
-               <attribute name="TLS" type="conf:string" use="optional"/>\r
-               <attribute name="Signing" type="conf:string" use="optional"/>\r
-               <attribute name="signRequest" type="boolean" use="optional" default="false"/>\r
-               <attribute name="signatureAlg" type="anyURI" use="optional"/>\r
-               <attribute name="signedAssertions" type="boolean" use="optional" default="false"/>\r
-               <attribute name="authType" use="optional">\r
+               <attribute name="TLS" type="conf:string"/>\r
+               <attribute name="Signing" type="conf:string"/>\r
+               <attribute name="signRequest" type="boolean" default="false"/>\r
+               <attribute name="signatureAlg" type="anyURI"/>\r
+               <attribute name="authType">\r
                        <simpleType>\r
                                <restriction base="conf:string">\r
                                        <enumeration value="basic"/>\r
                                </restriction>\r
                        </simpleType>\r
                </attribute>\r
-               <attribute name="authUsername" use="optional"/>\r
-               <attribute name="authPassword" use="optional"/>\r
+               <attribute name="authUsername"/>\r
+               <attribute name="authPassword"/>\r
        </attributeGroup>\r
 \r
        <element name="CredentialUse">\r
                                                        <element name="Rule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
                                                </sequence>
                                                <attribute name="id" type="conf:string" use="required"/>\r
+                                               <attribute name="validate" type="boolean" default="false"/>\r
+                                               <attribute name="signedAssertions" type="boolean" default="false"/>\r
+                                               <attribute name="requireConfidentiality" type="boolean" default="true"/>\r
+                                               <attribute name="requireTransportAuth" type="boolean" default="true"/>\r
+                                               <attribute name="connectTimeout" type="unsignedShort" default="15"/>\r
+                                               <attribute name="timeout" type="unsignedShort" default="30"/>\r
+                                               <anyAttribute namespace="##any" processContents="lax"/>\r
                                        </complexType>\r
                                </element>\r
                        </sequence>\r
-                       <attribute name="default" type="conf:string" use="required"/>\r
                </complexType>\r
        </element>\r
        \r
index 33b0e17..819e749 100644 (file)
@@ -9,6 +9,8 @@ libshibspincludedir = $(includedir)/shibsp
 
 attrincludedir = $(includedir)/shibsp/attribute
 
+bindincludedir = $(includedir)/shibsp/binding
+
 mdincludedir = $(includedir)/shibsp/metadata
 
 remincludedir = $(includedir)/shibsp/remoting
@@ -40,6 +42,9 @@ attrinclude_HEADERS = \
        attribute/ScopedAttribute.h \
        attribute/SimpleAttribute.h
 
+bindinclude_HEADERS = \
+       binding/SOAPClient.h
+       
 mdinclude_HEADERS = \
        metadata/MetadataExt.h
 
@@ -68,6 +73,7 @@ libshibsp_la_SOURCES = \
        SessionCache.cpp \
        SPConfig.cpp \
        attribute/Attribute.cpp \
+       binding/impl/SOAPClient.cpp \
        impl/RemotedSessionCache.cpp \
        impl/StorageServiceSessionCache.cpp \
        impl/XMLAccessControl.cpp \
index d4026fe..79cac91 100644 (file)
@@ -102,12 +102,20 @@ namespace shibsp {
         virtual xmlsignature::CredentialResolver* getCredentialResolver(const char* id) const=0;
 
         /**
+                * Returns the security policy settings for an identified policy.
+         *
+                * @param id    identifies the policy to return
+         * @return a PropertySet
+                */
+        virtual const PropertySet* getPolicySettings(const char* id) const=0;
+
+        /**
                 * Returns the security policy rules for an identified policy.
          *
-                * @param id    identifies the policy rules to return, or NULL for the default policy
+                * @param id    identifies the policy to return
          * @return an array of policy rules
                 */
-               virtual std::vector<const opensaml::SecurityPolicyRule*>& getPolicyRules(const char* id=NULL) const=0;
+        virtual const std::vector<const opensaml::SecurityPolicyRule*>& getPolicyRules(const char* id) const=0;
 
         /**
          * Returns a RequestMapper instance.
diff --git a/shibsp/binding/SOAPClient.h b/shibsp/binding/SOAPClient.h
new file mode 100644 (file)
index 0000000..f19af64
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/binding/SOAPClient.h
+ * 
+ * Specialized SOAPClient for SP environment.
+ */
+
+#ifndef __shibsp_soap11client_h__
+#define __shibsp_soap11client_h__
+
+#include <shibsp/Application.h>
+#include <saml/binding/SOAPClient.h>
+
+namespace shibsp {
+
+    /**
+     * Specialized SOAPClient for SP environment.
+     */
+    class SHIBSP_API SOAPClient : public opensaml::SOAPClient
+    {
+    public:
+        /**
+         * Creates a SOAP client instance for an Application to use.
+         * 
+         * @param application   reference to Application
+         * @param policy        reference to (empty) SecurityPolicy to apply
+         */
+        SOAPClient(const Application& application, opensaml::SecurityPolicy& policy);
+        
+        virtual ~SOAPClient() {
+            if (m_credResolver)
+                m_credResolver->unlock();
+        }
+
+        /**
+         * Override handles message signing for SAML payloads.
+         * 
+         * @param env       SOAP envelope to send
+         * @param peer      peer to send message to, expressed in TrustEngine terms
+         * @param endpoint  URL of endpoint to recieve message
+         */
+        void send(const soap11::Envelope& env, const xmltooling::KeyInfoSource& peer, const char* endpoint);
+
+        void reset();
+
+    protected:
+        /**
+         * Override prepares transport by applying policy settings from Application.
+         * 
+         * @param transport reference to transport layer
+         */
+        void prepareTransport(const xmltooling::SOAPTransport& transport);
+
+        /** Application supplied to client. */
+        const Application& m_app;
+
+        /** Properties associated with the Application's security policy. */
+        const PropertySet* m_settings;
+
+        /** CredentialUse properties, set after transport prep. */
+        const PropertySet* m_credUse;
+
+        /** Locked CredentialResolver for transport, set after transport prep. */
+        xmlsignature::CredentialResolver* m_credResolver;
+    };
+
+};
+
+#endif /* __shibsp_soap11client_h__ */
diff --git a/shibsp/binding/impl/SOAPClient.cpp b/shibsp/binding/impl/SOAPClient.cpp
new file mode 100644 (file)
index 0000000..7e9ec74
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * SOAPClient.cpp
+ * 
+ * Specialized SOAPClient for SP environment.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "ServiceProvider.h"
+#include "binding/SOAPClient.h"
+
+#include <log4cpp/Category.hh>
+#include <saml/saml2/metadata/Metadata.h>
+#include <xmltooling/soap/SOAP.h>
+#include <xmltooling/soap/HTTPSOAPTransport.h>
+#include <xmltooling/util/NDC.h>
+
+using namespace shibsp;
+using namespace opensaml::saml2md;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+SOAPClient::SOAPClient(const Application& application, opensaml::SecurityPolicy& policy)
+    : opensaml::SOAPClient(policy), m_app(application), m_settings(NULL), m_credUse(NULL), m_credResolver(NULL)
+{
+    SPConfig& conf = SPConfig::getConfig();
+    pair<bool,const char*> policyId = m_app.getString("policyId");
+    m_settings = conf.getServiceProvider()->getPolicySettings(policyId.second);
+    const vector<const opensaml::SecurityPolicyRule*>& rules = conf.getServiceProvider()->getPolicyRules(policyId.second);
+    for (vector<const opensaml::SecurityPolicyRule*>::const_iterator rule=rules.begin(); rule!=rules.end(); ++rule)
+        policy.addRule(*rule);
+    policy.setMetadataProvider(application.getMetadataProvider());
+    policy.setTrustEngine(application.getTrustEngine());
+}
+
+namespace {
+    class SHIBSP_DLLLOCAL _addcert : public binary_function<X509Data*,XSECCryptoX509*,void> {
+    public:
+        void operator()(X509Data* bag, XSECCryptoX509* cert) const {
+            safeBuffer& buf=cert->getDEREncodingSB();
+            X509Certificate* x=X509CertificateBuilder::buildX509Certificate();
+            x->setValue(buf.sbStrToXMLCh());
+            bag->getX509Certificates().push_back(x);
+        }
+    };
+};
+
+void SOAPClient::send(const soap11::Envelope& env, const KeyInfoSource& peer, const char* endpoint)
+{
+    if (!m_peer)
+        m_peer = dynamic_cast<const RoleDescriptor*>(&peer);
+    if (m_peer) {
+        const EntityDescriptor* entity = m_peer ? dynamic_cast<const EntityDescriptor*>(m_peer->getParent()) : NULL;
+        m_credUse = entity ? m_app.getCredentialUse(entity) : NULL;
+    }
+    
+    // Check for message signing requirements.   
+    if (m_credUse) {
+        pair<bool,bool> flag = m_credUse->getBool("signRequests");
+        if (flag.first && flag.second) {
+            CredentialResolver* cr=NULL;
+            pair<bool,const char*> cred = m_credUse->getString("Signing");
+            if (cred.first && (cr==SPConfig::getConfig().getServiceProvider()->getCredentialResolver(cred.second))) {
+                // Looks like we're supposed to sign, so check for message.
+                const vector<XMLObject*>& bodies=const_cast<const soap11::Body*>(env.getBody())->getUnknownXMLObjects();
+                if (!bodies.empty()) {
+                    opensaml::SignableObject* msg = dynamic_cast<opensaml::SignableObject*>(bodies.front());
+                    if (msg) {
+                        // Build a Signature.
+                        Signature* sig = SignatureBuilder::buildSignature();
+                        msg->setSignature(sig);
+                        pair<bool,const XMLCh*> alg = m_credUse->getXMLString("sigAlgorithm");
+                        if (alg.first)
+                            sig->setSignatureAlgorithm(alg.second);
+                        Locker locker(cr);
+                        sig->setSigningKey(cr->getKey());
+                    
+                        // Build KeyInfo.
+                        const vector<XSECCryptoX509*>& certs = cr->getCertificates();
+                        if (!certs.empty()) {
+                            KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo();
+                            sig->setKeyInfo(keyInfo);
+                            X509Data* x509Data=X509DataBuilder::buildX509Data();
+                            keyInfo->getX509Datas().push_back(x509Data);
+                            for_each(certs.begin(),certs.end(),bind1st(_addcert(),x509Data));
+                        }
+
+                        // Sign it. The marshalling step in the base class should be a no-op.
+                        vector<Signature*> sigs(1,sig);
+                        env.marshall((DOMDocument*)NULL,&sigs);
+                    }
+                }
+            }
+        }
+    }
+    
+    opensaml::SOAPClient::send(env, peer, endpoint);
+}
+
+void SOAPClient::prepareTransport(const SOAPTransport& transport)
+{
+#ifdef _DEBUG
+    xmltooling::NDC("prepareTransport");
+#endif
+    Category& log=Category::getInstance(SHIBSP_LOGCAT".SOAPClient");
+    log.debug("prepping SOAP transport for use by application (%s)", m_app.getId());
+
+    pair<bool,bool> flag = m_settings->getBool("requireConfidentiality");
+    if ((!flag.first || flag.second) && !transport.isConfidential())
+        throw opensaml::BindingException("Transport confidentiality required, but not available."); 
+
+    flag = m_settings->getBool("validate");
+    setValidating(flag.first && flag.second);
+    flag = m_settings->getBool("requireTransportAuth");
+    forceTransportAuthentication(!flag.first || flag.second);
+
+    opensaml::SOAPClient::prepareTransport(transport);
+
+    if (!m_credUse) {
+        const EntityDescriptor* entity = m_peer ? dynamic_cast<const EntityDescriptor*>(m_peer->getParent()) : NULL;
+        m_credUse = entity ? m_app.getCredentialUse(entity) : NULL;
+    }
+    if (m_credUse) {
+        pair<bool,const char*> authType=m_credUse->getString("authType");
+        if (authType.first) {
+            SOAPTransport::transport_auth_t type=SOAPTransport::transport_auth_none;
+            pair<bool,const char*> username=m_credUse->getString("authUsername");
+            pair<bool,const char*> password=m_credUse->getString("authPassword");
+            if (!username.first || !password.first)
+                log.error("transport authType (%s) specified but authUsername or authPassword was missing", authType.second);
+            else if (!strcmp(authType.second,"basic"))
+                type = SOAPTransport::transport_auth_basic;
+            else if (!strcmp(authType.second,"digest"))
+                type = SOAPTransport::transport_auth_digest;
+            else if (!strcmp(authType.second,"ntlm"))
+                type = SOAPTransport::transport_auth_ntlm;
+            else if (!strcmp(authType.second,"gss"))
+                type = SOAPTransport::transport_auth_gss;
+            else
+                log.error("unknown authType (%s) specified in CredentialUse element", authType.second);
+            if (type > SOAPTransport::transport_auth_none) {
+                if (transport.setAuth(type,username.second,password.second))
+                    log.debug("configured for transport authentication (method=%s, username=%s)", authType.second, username.second);
+                else
+                    log.error("failed to configure transport authentication (method=%s)", authType.second);
+            }
+        }
+        
+        authType = m_credUse->getString("TLS");
+        if (authType.first) {
+            m_credResolver = SPConfig::getConfig().getServiceProvider()->getCredentialResolver(authType.second);
+            if (m_credResolver) {
+                m_credResolver->lock();
+                if (!transport.setCredentialResolver(m_credResolver)) {
+                    m_credResolver->unlock();
+                    m_credResolver = NULL;
+                    log.error("failed to load CredentialResolver into SOAPTransport");
+                }
+            }
+            else {
+                log.error("unable to access CredentialResolver (%s)", authType.second);
+            }
+        }
+    } 
+
+    transport.setConnectTimeout(m_settings->getUnsignedInt("connectTimeout").second);
+    transport.setTimeout(m_settings->getUnsignedInt("timeout").second);
+
+    const HTTPSOAPTransport* http = dynamic_cast<const HTTPSOAPTransport*>(&transport);
+    if (http)
+        http->setRequestHeader("Shibboleth", PACKAGE_VERSION);
+}
+
+void SOAPClient::reset()
+{
+    m_credUse = NULL;
+    if (m_credResolver)
+        m_credResolver->unlock();
+    m_credResolver = NULL;
+    opensaml::SOAPClient::reset();
+}
\ No newline at end of file
index 600c3bd..426462b 100644 (file)
@@ -155,8 +155,7 @@ namespace {
         RequestMapper* m_requestMapper;\r
         map<string,Application*> m_appmap;\r
         map<string,CredentialResolver*> m_credResolverMap;\r
-        map< string,vector<const SecurityPolicyRule*> > m_policyMap;\r
-        string m_policyDefault;\r
+        map< string,pair< PropertySet*,vector<const SecurityPolicyRule*> > > m_policyMap;\r
         \r
         // Provides filter to exclude special config elements.\r
         short acceptNode(const DOMNode* node) const;\r
@@ -249,11 +248,17 @@ namespace {
             return NULL;\r
         }\r
 \r
-        vector<const SecurityPolicyRule*>& getPolicyRules(const char* id=NULL) const {\r
-            if (!id)\r
-                id = m_impl->m_policyDefault.c_str();\r
-            if (m_impl->m_policyMap.count(id))\r
-                return m_impl->m_policyMap[id];\r
+        const PropertySet* getPolicySettings(const char* id) const {\r
+            map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
+            if (i!=m_impl->m_policyMap.end())\r
+                return i->second.first;\r
+            throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
+        }\r
+\r
+        const vector<const SecurityPolicyRule*>& getPolicyRules(const char* id) const {\r
+            map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
+            if (i!=m_impl->m_policyMap.end())\r
+                return i->second.second;\r
             throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
         }\r
 \r
@@ -277,7 +282,6 @@ namespace {
     static const XMLCh Applications[] =         UNICODE_LITERAL_12(A,p,p,l,i,c,a,t,i,o,n,s);\r
     static const XMLCh Credentials[] =          UNICODE_LITERAL_11(C,r,e,d,e,n,t,i,a,l,s);\r
     static const XMLCh CredentialUse[] =        UNICODE_LITERAL_13(C,r,e,d,e,n,t,i,a,l,U,s,e);\r
-    static const XMLCh _default[] =             UNICODE_LITERAL_7(d,e,f,a,u,l,t);\r
     static const XMLCh fatal[] =                UNICODE_LITERAL_5(f,a,t,a,l);\r
     static const XMLCh _Handler[] =             UNICODE_LITERAL_7(H,a,n,d,l,e,r);\r
     static const XMLCh _id[] =                  UNICODE_LITERAL_2(i,d);\r
@@ -303,6 +307,16 @@ namespace {
     static const XMLCh _MetadataProvider[] =    UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);\r
     static const XMLCh _path[] =                UNICODE_LITERAL_4(p,a,t,h);\r
     static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);\r
+\r
+    class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter\r
+    {\r
+    public:\r
+        short acceptNode(const DOMNode* node) const {\r
+            if (XMLHelper::isNodeNamed(node,shibspconstants::SHIB2SPCONFIG_NS,Rule))\r
+                return FILTER_REJECT;\r
+            return FILTER_ACCEPT;\r
+        }\r
+    };\r
 };\r
 \r
 namespace shibsp {\r
@@ -940,17 +954,20 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
         // Load security policies.\r
         child = XMLHelper::getLastChildElement(e,SecurityPolicies);\r
         if (child) {\r
-            auto_ptr_char def(child->getAttributeNS(NULL,_default));\r
-            m_policyDefault = def.get();\r
+            PolicyNodeFilter filter;\r
             child = XMLHelper::getFirstChildElement(child,Policy);\r
             while (child) {\r
                 auto_ptr_char id(child->getAttributeNS(NULL,_id));\r
-                vector<const SecurityPolicyRule*>& rules = m_policyMap[id.get()];\r
+                pair< PropertySet*,vector<const SecurityPolicyRule*> >& rules = m_policyMap[id.get()];\r
+                rules.first = NULL;\r
+                auto_ptr<DOMPropertySet> settings(new DOMPropertySet());\r
+                settings->load(child, log, &filter);\r
+                rules.first = settings.release();\r
                 const DOMElement* rule = XMLHelper::getFirstChildElement(child,Rule);\r
                 while (rule) {\r
                     auto_ptr_char type(rule->getAttributeNS(NULL,_type));\r
                     try {\r
-                        rules.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));\r
+                        rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));\r
                     }\r
                     catch (exception& ex) {\r
                         log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());\r
@@ -959,8 +976,6 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
                 }\r
                 child = XMLHelper::getNextSiblingElement(child,Policy);\r
             }\r
-            if (!m_policyMap.count(m_policyDefault))\r
-                throw ConfigurationException("Default security policy ($1) not found in conf:SecurityPolicies element.", params(1,m_policyDefault.c_str()));\r
         }\r
 \r
         // Load the default application. This actually has a fixed ID of "default". ;-)\r
@@ -1000,8 +1015,10 @@ XMLConfigImpl::~XMLConfigImpl()
 {\r
     for_each(m_appmap.begin(),m_appmap.end(),cleanup_pair<string,Application>());\r
     for_each(m_credResolverMap.begin(),m_credResolverMap.end(),cleanup_pair<string,CredentialResolver>());\r
-    for (map< string,vector<const SecurityPolicyRule*> >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i)\r
-        for_each(i->second.begin(), i->second.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
+    for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i) {\r
+        delete i->second.first;\r
+        for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
+    }\r
     delete m_requestMapper;\r
     if (m_document)\r
         m_document->release();\r
index fdce281..d640797 100644 (file)
@@ -60,7 +60,7 @@
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib saml2D.lib xmltooling1D.lib wsock32.lib libeay32_0_9_8D.lib ssleay32_0_9_8D.lib"\r
+                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib xsec_1D.lib saml2D.lib xmltooling1D.lib wsock32.lib libeay32_0_9_8D.lib ssleay32_0_9_8D.lib"\r
                                OutputFile="$(OutDir)\$(ProjectName)1_0D.dll"\r
                                LinkIncremental="2"\r
                                AdditionalLibraryDirectories="&quot;..\..\cpp-opensaml1\saml\Debug&quot;;&quot;..\..\cpp-opensaml2\Debug&quot;;&quot;..\..\cpp-xmltooling\Debug&quot;"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib saml2.lib xmltooling1.lib wsock32.lib libeay32_0_9_8.lib ssleay32_0_9_8.lib"\r
+                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib xsec_1.lib saml2.lib xmltooling1.lib wsock32.lib libeay32_0_9_8.lib ssleay32_0_9_8.lib"\r
                                OutputFile="$(OutDir)\$(ProjectName)1_0.dll"\r
                                LinkIncremental="1"\r
                                AdditionalLibraryDirectories="&quot;..\..\cpp-opensaml1\saml\Release&quot;;&quot;..\..\cpp-opensaml2\Release&quot;;&quot;..\..\cpp-xmltooling\Release&quot;"\r
                                        >\r
                                </File>\r
                        </Filter>\r
+                       <Filter\r
+                               Name="binding"\r
+                               >\r
+                               <Filter\r
+                                       Name="impl"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\binding\impl\SOAPClient.cpp"\r
+                                               >\r
+                                       </File>\r
+                               </Filter>\r
+                       </Filter>\r
                </Filter>\r
                <Filter\r
                        Name="Header Files"\r
                                        >\r
                                </File>\r
                        </Filter>\r
+                       <Filter\r
+                               Name="binding"\r
+                               >\r
+                               <File\r
+                                       RelativePath=".\binding\SOAPClient.h"\r
+                                       >\r
+                               </File>\r
+                       </Filter>\r
                </Filter>\r
                <Filter\r
                        Name="Resource Files"\r
index 1d1bd74..d1af42c 100644 (file)
@@ -35,6 +35,7 @@
 #include <shibsp/exceptions.h>\r
 #include <shibsp/SPConfig.h>\r
 #include <shibsp/ServiceProvider.h>\r
+#include <shibsp/binding/SOAPClient.h>\r
 #include <shibsp/util/SPConstants.h>\r
 \r
 #include <saml/binding/SecurityPolicy.h>\r
@@ -127,7 +128,7 @@ int main(int argc,char* argv[])
     }\r
 \r
     ServiceProvider* sp=conf.getServiceProvider();\r
-    xmltooling::Locker locker(sp);\r
+    sp->lock();\r
 \r
     try {\r
         const Application* app=sp->getApplication(a_param);\r
@@ -157,12 +158,11 @@ int main(int argc,char* argv[])
         else\r
             throw MetadataException("No AttributeAuthority role found in metadata.");\r
 \r
-        QName role(samlconstants::SAML20P_NS, AttributeAuthorityDescriptor::LOCAL_NAME);\r
-        SecurityPolicy policy(sp->getPolicyRules(), m, &role, app->getTrustEngine());\r
+        SecurityPolicy policy;\r
+        shibsp::SOAPClient soaper(*app,policy);\r
 \r
         if (ver == v20) {\r
             auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);\r
-            SAML2SOAPClient soaper(policy,true);\r
             opensaml::saml2p::StatusResponseType* srt=NULL;\r
             const vector<AttributeService*>& endpoints=AA->getAttributeServices();\r
             for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !srt && ep!=endpoints.end(); ++ep) {\r
@@ -181,10 +181,9 @@ int main(int argc,char* argv[])
                     subject->setNameID(nameid);\r
                     query->setSubject(subject);\r
                     query->setIssuer(iss);\r
-                    auto_ptr<opensaml::saml2p::AttributeQuery> wrapper(query);\r
-                    soaper.sendSAML(query, *AA, loc.get());\r
-                    wrapper.release();  // freed by SOAP client\r
-                    srt = soaper.receiveSAML();\r
+                    SAML2SOAPClient client(soaper);\r
+                    client.sendSAML(query, *AA, loc.get());\r
+                    srt = client.receiveSAML();\r
                 }\r
                 catch (exception& ex) {\r
                     cerr << ex.what() << endl;\r
@@ -206,7 +205,6 @@ int main(int argc,char* argv[])
         }\r
         else {\r
             auto_ptr_XMLCh binding(samlconstants::SAML1_BINDING_SOAP);\r
-            SAML1SOAPClient soaper(policy,true);\r
             const opensaml::saml1p::Response* response=NULL;\r
             const vector<AttributeService*>& endpoints=AA->getAttributeServices();\r
             for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {\r
@@ -225,10 +223,9 @@ int main(int argc,char* argv[])
                     query->setSubject(subject);\r
                     query->setResource(issuer.get());\r
                     request->setMinorVersion(ver==v11 ? 1 : 0);\r
-                    auto_ptr<Request> wrapper(request);\r
-                    soaper.sendSAML(request, *AA, loc.get());\r
-                    wrapper.release();  // freed by SOAP client\r
-                    response = soaper.receiveSAML();\r
+                    SAML1SOAPClient client(soaper);\r
+                    client.sendSAML(request, *AA, loc.get());\r
+                    response = client.receiveSAML();\r
                 }\r
                 catch (exception& ex) {\r
                     cerr << ex.what() << endl;\r
@@ -252,6 +249,7 @@ int main(int argc,char* argv[])
         cerr << ex.what() << endl;\r
     }\r
 \r
+    sp->unlock();\r
     conf.term();\r
     return 0;\r
 }\r