Move settings from Policy to RelyingParty to allow per-RP values.
authorScott Cantor <cantor.2@osu.edu>
Thu, 3 Jan 2008 21:00:49 +0000 (21:00 +0000)
committerScott Cantor <cantor.2@osu.edu>
Thu, 3 Jan 2008 21:00:49 +0000 (21:00 +0000)
configs/shibboleth2.xml.in
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp
shibsp/binding/impl/SOAPClient.cpp
shibsp/handler/impl/MetadataGenerator.cpp
shibsp/handler/impl/SAML1Consumer.cpp
shibsp/handler/impl/SAML2Consumer.cpp

index bd35126..3bd41eb 100644 (file)
             styleSheet="/shibboleth-sp/main.css"/>
         
         <!-- Configure handling of outgoing messages and SOAP authentication. -->
-        <DefaultRelyingParty authType="TLS" artifactEndpointIndex="1" signing="false" encryption="false">
+        <DefaultRelyingParty authType="TLS"
+            artifactEndpointIndex="1"
+            signing="false"
+            encryption="false"
+            requireConfidentiality="true"
+            requireTransportAuth="true"
+            signedAssertions="false"
+            chunkedEncoding="false"
+            connectTimeout="15" timeout="30"
+            >
             <!-- Uncomment and modify to tweak settings for specific IdPs or groups. -->
             <!-- <RelyingParty Name="SpecialFederation" keyName="SpecialKey"/> -->
         </DefaultRelyingParty>
     <!-- Each policy defines a set of rules to use to secure messages. -->
     <SecurityPolicies>
         <!-- The predefined policy enforces replay/freshness and permits signing and client TLS. -->
-        <Policy id="default"
-            validate="false"
-            signedAssertions="false"
-            requireConfidentiality="true"
-            requireTransportAuth="true"
-            chunkedEncoding="false"
-            connectTimeout="15" timeout="30"
-            >
+        <Policy id="default" validate="false">
             <Rule type="MessageFlow" checkReplay="true" expires="60"/>
             <Rule type="ClientCertAuth" errorFatal="true"/>
             <Rule type="XMLSigning" errorFatal="true"/>
index 54bdd2b..652024e 100644 (file)
                <attribute name="encryptionAlg" type="anyURI"/>\r
                <attribute name="keyName" type="conf:string"/>\r
                <attribute name="artifactEndpointIndex" type="unsignedShort"/>\r
+        <attribute name="chunkedEncoding" type="boolean"/>\r
+        <attribute name="connectTimeout" type="unsignedShort"/>\r
+        <attribute name="timeout" type="unsignedShort"/>\r
+        <attribute name="requireConfidentiality" type="boolean"/>\r
+        <attribute name="requireTransportAuth" type="boolean"/>\r
+        <attribute name="signedAssertions" type="boolean"/>\r
        </attributeGroup>\r
        \r
        <element name="SecurityPolicies">\r
                                                </sequence>\r
                                                <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="chunkedEncoding" 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
index e6ccb70..46f46aa 100644 (file)
@@ -272,9 +272,6 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
     shibsp::SecurityPolicy policy(application);
     MetadataCredentialCriteria mcc(*AA);
     shibsp::SOAPClient soaper(policy);
-    const PropertySet* policySettings =
-        application.getServiceProvider().getPolicySettings(application.getString("policyId").second);
-    pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");
 
     auto_ptr_XMLCh binding(samlconstants::SAML1_BINDING_SOAP);
     saml1p::Response* response=NULL;
@@ -333,6 +330,7 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const
     auto_ptr<saml1p::Response> wrapper(response);
     saml1::Assertion* newtoken = assertions.front();
 
+    pair<bool,bool> signedAssertions = application.getRelyingParty(ctx.getEntityDescriptor())->getBool("signedAssertions");
     if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {
         m_log.error("assertion unsigned, rejecting it based on signedAssertions policy");
         return true;
@@ -405,10 +403,9 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const
     shibsp::SecurityPolicy policy(application);
     MetadataCredentialCriteria mcc(*AA);
     shibsp::SOAPClient soaper(policy);
-    const PropertySet* policySettings = application.getServiceProvider().getPolicySettings(application.getString("policyId").second);
-    pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");
 
     const PropertySet* relyingParty = application.getRelyingParty(ctx.getEntityDescriptor());
+    pair<bool,bool> signedAssertions = relyingParty->getBool("signedAssertions");
     pair<bool,const char*> encryption = relyingParty->getString("encryption");
 
     auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);
index ac4a438..63e7405 100644 (file)
@@ -109,13 +109,13 @@ void SOAPClient::prepareTransport(SOAPTransport& transport)
     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");
+    pair<bool,bool> flag = m_relyingParty->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");
+    flag = m_relyingParty->getBool("requireTransportAuth");
     forceTransportAuthentication(!flag.first || flag.second);
 
     opensaml::SOAPClient::prepareTransport(transport);
@@ -169,14 +169,16 @@ void SOAPClient::prepareTransport(SOAPTransport& transport)
         }
     }
     
-    transport.setConnectTimeout(m_settings->getUnsignedInt("connectTimeout").second);
-    transport.setTimeout(m_settings->getUnsignedInt("timeout").second);
+    pair<bool,unsigned int> timeout = m_relyingParty->getUnsignedInt("connectTimeout"); 
+    transport.setConnectTimeout(timeout.first ? timeout.second : 10);
+    timeout = m_relyingParty->getUnsignedInt("timeout");
+    transport.setTimeout(timeout.first ? timeout.second : 20);
     m_app.getServiceProvider().setTransportOptions(m_app.getString("policyId").second, transport);
 
     HTTPSOAPTransport* http = dynamic_cast<HTTPSOAPTransport*>(&transport);
     if (http) {
-        flag = m_settings->getBool("chunkedEncoding");
-        http->useChunkedEncoding(!flag.first || flag.second);
+        flag = m_relyingParty->getBool("chunkedEncoding");
+        http->useChunkedEncoding(flag.first && flag.second);
         http->setRequestHeader("User-Agent", PACKAGE_NAME);
         http->setRequestHeader(PACKAGE_NAME, PACKAGE_VERSION);
     }
index ca5c926..3cdbc98 100644 (file)
@@ -223,8 +223,7 @@ pair<bool,long> MetadataGenerator::processMessage(const Application& application
     prop = application.getRelyingParty(NULL)->getString("signing");
     if (prop.first && (!strcmp(prop.second,"true") || !strcmp(prop.second,"front")))
         role->AuthnRequestsSigned(true);
-    pair<bool,bool> flagprop =
-        application.getServiceProvider().getPolicySettings(application.getString("policyId").second)->getBool("signedAssertions");
+    pair<bool,bool> flagprop = application.getRelyingParty(NULL)->getBool("signedAssertions");
     if (flagprop.first && flagprop.second)
         role->WantAssertionsSigned(true);
 
index 4bcc88c..7788b7e 100644 (file)
@@ -152,7 +152,8 @@ void SAML1Consumer::implementProtocol(
     BrowserSSOProfileValidator ssoValidator(application.getAudiences(), now);
 
     // With this flag on, we ignore any unsigned assertions.
-    pair<bool,bool> flag = settings->getBool("signedAssertions");
+    const EntityDescriptor* entity = policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL;
+    pair<bool,bool> flag = application.getRelyingParty(entity)->getBool("signedAssertions");
 
     // authnskew allows rejection of SSO if AuthnInstant is too old.
     const PropertySet* sessionProps = application.getPropertySet("Sessions");
@@ -273,7 +274,7 @@ void SAML1Consumer::implementProtocol(
         httpRequest,
         httpResponse,
         now + lifetime.second,
-        policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL,
+        entity,
         (!response->getMinorVersion().first || response->getMinorVersion().second==1) ?
             samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM,
         nameid.get(),
index d8fc3ec..cc2118c 100644 (file)
@@ -138,7 +138,12 @@ void SAML2Consumer::implementProtocol(
     BrowserSSOProfileValidator ssoValidator(application.getAudiences(), now, dest.substr(0,dest.find('?')).c_str());
 
     // With this flag on, we ignore any unsigned assertions.
-    pair<bool,bool> flag = settings->getBool("signedAssertions");
+    const EntityDescriptor* entity = NULL;
+    pair<bool,bool> flag = make_pair(false,false);
+    if (alreadySecured && policy.getIssuerMetadata()) {
+        entity = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
+        flag = application.getRelyingParty(entity)->getBool("signedAssertions");
+    }
 
     // authnskew allows rejection of SSO if AuthnInstant is too old.
     const PropertySet* sessionProps = application.getPropertySet("Sessions");
@@ -168,6 +173,14 @@ void SAML2Consumer::implementProtocol(
             if (!alreadySecured && !policy.isAuthenticated())
                 throw SecurityPolicyException("Unable to establish security of incoming assertion.");
 
+            // If we hadn't established Issuer yet, redo the signedAssertions check.
+            if (!entity && policy.getIssuerMetadata()) {
+                entity = dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent());
+                flag = application.getRelyingParty(entity)->getBool("signedAssertions");
+                if (!(*a)->getSignature() && flag.first && flag.second)
+                    throw SecurityPolicyException("The incoming assertion was unsigned, violating local security policy.");
+            }
+
             // Now do profile and core semantic validation to ensure we can use it for SSO.
             ssoValidator.validateAssertion(*(*a));
 
@@ -359,7 +372,7 @@ void SAML2Consumer::implementProtocol(
             httpRequest,
             httpResponse,
             sessionExp,
-            policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL,
+            entity,
             samlconstants::SAML20P_NS,
             ssoName,
             ssoStatement->getAuthnInstant() ? ssoStatement->getAuthnInstant()->getRawData() : NULL,