Allow for default RequestMap, relax constraint on root applicationId.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Mon, 26 Jul 2010 21:08:35 +0000 (21:08 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Mon, 26 Jul 2010 21:08:35 +0000 (21:08 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/branches/REL_2@3276 cb58f699-b61c-0410-a6fe-9272a202ed29

12 files changed:
configs/example-shibboleth2.xml
configs/shibboleth2.xml
configs/win-shibboleth2.xml
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/AbstractSPRequest.cpp
shibsp/Application.cpp
shibsp/ServiceProvider.cpp
shibsp/ServiceProvider.h
shibsp/impl/XMLRequestMapper.cpp
shibsp/impl/XMLServiceProvider.cpp
shibsp/util/DOMPropertySet.cpp
shibsp/util/DOMPropertySet.h

index e826ad9..eb3df67 100644 (file)
@@ -58,7 +58,7 @@
 \r
     <!-- To customize behavior, map hostnames and path components to applicationId and other settings. -->\r
     <RequestMapper type="Native">\r
-        <RequestMap applicationId="default">\r
+        <RequestMap>\r
             <!--\r
             The example requires a session for documents in /secure on the containing host with http and\r
             https on the default ports. Note that the name and port in the <Host> elements MUST match\r
@@ -77,9 +77,9 @@
     <!--\r
     The ApplicationDefaults element is where most of Shibboleth's SAML bits are defined.\r
     Resource requests are mapped by the RequestMapper to an applicationId that\r
-    points into to this section.\r
+    points into to this section (or to the defaults here).\r
     -->\r
-    <ApplicationDefaults id="default" policyId="default"\r
+    <ApplicationDefaults policyId="default"\r
         entityID="https://sp.example.org/shibboleth"\r
         REMOTE_USER="eppn persistent-id targeted-id"\r
         signing="false" encryption="false">\r
index b363666..643fb3f 100644 (file)
@@ -11,7 +11,7 @@
 
     <!-- To customize behavior, map hostnames and path components to applicationId and other settings. -->
     <RequestMapper type="Native">
-        <RequestMap applicationId="default">
+        <RequestMap>
             <!--
             The example requires a session for documents in /secure on the containing host with http and
             https on the default ports. Note that the name and port in the <Host> elements MUST match
@@ -30,9 +30,9 @@
     <!--
     The ApplicationDefaults element is where most of Shibboleth's SAML bits are defined.
     Resource requests are mapped by the RequestMapper to an applicationId that
-    points into to this section.
+    points into to this section (or to the defaults here).
     -->
-    <ApplicationDefaults id="default" policyId="default"
+    <ApplicationDefaults policyId="default"
         entityID="https://sp.example.org/shibboleth"
         REMOTE_USER="eppn persistent-id targeted-id"
         signing="false" encryption="false">
index 89316ed..63ab25b 100644 (file)
@@ -31,7 +31,7 @@
 \r
     <!-- To customize behavior, map hostnames and path components to applicationId and other settings. -->\r
     <RequestMapper type="Native">\r
-        <RequestMap applicationId="default">\r
+        <RequestMap>\r
             <!--\r
             The example requires a session for documents in /secure on the containing host with http and\r
             https on the default ports. Note that the name and port in the <Host> elements MUST match\r
@@ -50,9 +50,9 @@
     <!--\r
     The ApplicationDefaults element is where most of Shibboleth's SAML bits are defined.\r
     Resource requests are mapped by the RequestMapper to an applicationId that\r
-    points into to this section.\r
+    points into to this section (or to the defaults here).\r
     -->\r
-    <ApplicationDefaults id="default" policyId="default"\r
+    <ApplicationDefaults policyId="default"\r
         entityID="https://sp.example.org/shibboleth"\r
         REMOTE_USER="eppn persistent-id targeted-id"\r
         signing="false" encryption="false">\r
index f12e353..10f4024 100644 (file)
   </complexType>
 
   <attributeGroup name="ContentSettings">
+    <attribute name="applicationId" type="conf:string"/>
     <attribute name="authType" type="conf:string"/>
     <attribute name="requireSession" type="boolean"/>
     <attribute name="requireSessionWith" type="conf:string"/>
         </choice>
         <element ref="ds:Signature" minOccurs="0"/>
       </sequence>
-      <attribute name="applicationId" type="conf:string" fixed="default"/>
       <attributeGroup ref="conf:ContentSettings"/>
     </complexType>
   </element>
     </attribute>
     <attribute name="name" type="conf:string" use="required"/>
     <attribute name="port" type="unsignedInt"/>
-    <attribute name="applicationId" type="conf:string"/>
     <attributeGroup ref="conf:ContentSettings"/>
   </complexType>
 
     </sequence>
     <attribute name="regex" type="conf:string" use="required"/>
     <attribute name="ignoreCase" type="boolean"/>
-    <attribute name="applicationId" type="conf:string"/>
     <attributeGroup ref="conf:ContentSettings"/>
   </complexType>
 
       </choice>
     </sequence>
     <attribute name="name" type="conf:string" use="required"/>
-    <attribute name="applicationId" type="conf:string"/>
     <attributeGroup ref="conf:ContentSettings"/>
   </complexType>
 
     </sequence>
     <attribute name="regex" type="conf:string" use="required"/>
     <attribute name="ignoreCase" type="boolean"/>
-    <attribute name="applicationId" type="conf:string"/>
     <attributeGroup ref="conf:ContentSettings"/>
   </complexType>
 
index 5fefc01..eb1ced4 100644 (file)
@@ -97,7 +97,7 @@ const Application& AbstractSPRequest::getApplication() const
         // Now find the application from the URL settings
         m_app=m_sp->getApplication(getRequestSettings().first->getString("applicationId").second);
         if (!m_app)
-            throw ConfigurationException("Unable to map request to ApplicationOverride settings, check configuration.");
+            throw ConfigurationException("Unable to map non-default applicationId to an ApplicationOverride, check configuration.");
     }
     return *m_app;
 }
index b54e5d5..439cd73 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2009 Internet2
+ *  Copyright 2001-2010 Internet2
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -50,7 +50,8 @@ const ServiceProvider& Application::getServiceProvider() const
 
 const char* Application::getId() const
 {
-    return getString("id").second;
+    pair<bool,const char*> ret = getString("id");
+    return ret.first ? ret.second : "default";
 }
 
 pair<string,const char*> Application::getCookieNameProps(const char* prefix, time_t* lifetime) const
index 9c2487b..538fb2c 100644 (file)
@@ -63,7 +63,7 @@ namespace shibsp {
 
         // Strictly for error handling, detect a nullptr application and point at the default.
         if (!app)
-            app = request.getServiceProvider().getApplication("default");
+            app = request.getServiceProvider().getApplication(nullptr);
 
         const PropertySet* props=app->getPropertySet("Errors");
 
index 15658fe..3bb95ca 100644 (file)
@@ -155,7 +155,7 @@ namespace shibsp {
         /**
          * Returns an Application instance matching the specified ID.
          * 
-         * @param applicationId the ID of the application
+         * @param applicationId the ID of the application, or nullptr for the default
          * @return  pointer to the application, or nullptr
          */
         virtual const Application* getApplication(const char* applicationId) const=0;
index fbef292..593afe3 100644 (file)
@@ -35,6 +35,7 @@
 #include <xercesc/util/XMLUniDefs.hpp>
 #include <xercesc/util/regx/RegularExpression.hpp>
 
+using shibspconstants::SHIB2SPCONFIG_NS;
 using namespace shibsp;
 using namespace xmltooling;
 using namespace std;
@@ -469,10 +470,20 @@ XMLRequestMapperImpl::XMLRequestMapperImpl(const DOMElement* e, Category& log) :
 #ifdef _DEBUG
     xmltooling::NDC ndc("XMLRequestMapperImpl");
 #endif
+    static const XMLCh _default[] =    UNICODE_LITERAL_7(d,e,f,a,u,l,t);
+    static const XMLCh _id[] =         UNICODE_LITERAL_2(i,d);
+    static const XMLCh _RequestMap[] = UNICODE_LITERAL_10(R,e,q,u,e,s,t,M,a,p);
+
+    if (!XMLHelper::isNodeNamed(e, SHIB2SPCONFIG_NS, _RequestMap))
+        throw ConfigurationException("XML RequestMapper requires conf:RequestMap at root of configuration.");
 
     // Load the property set.
     load(e,nullptr,this);
 
+    // Inject "default" app ID if not explicit.
+    if (!getString("applicationId").first)
+        setProperty("applicationId", "default");
+
     // Load any AccessControl provider.
     loadACL(e,log);
 
index 5b73168..db279c2 100644 (file)
@@ -377,7 +377,7 @@ namespace {
         }
 
         const Application* getApplication(const char* applicationId) const {
-            map<string,Application*>::const_iterator i=m_impl->m_appmap.find(applicationId);
+            map<string,Application*>::const_iterator i=m_impl->m_appmap.find(applicationId ? applicationId : "default");
             return (i!=m_impl->m_appmap.end()) ? i->second : nullptr;
         }
 
@@ -427,6 +427,7 @@ namespace {
     #pragma warning( pop )
 #endif
 
+    static const XMLCh applicationId[] =        UNICODE_LITERAL_13(a,p,p,l,i,c,a,t,i,o,n,I,d);
     static const XMLCh ApplicationOverride[] =  UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,O,v,e,r,r,i,d,e);
     static const XMLCh ApplicationDefaults[] =  UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,D,e,f,a,u,l,t,s);
     static const XMLCh _ArtifactMap[] =         UNICODE_LITERAL_11(A,r,t,i,f,a,c,t,M,a,p);
@@ -439,6 +440,7 @@ namespace {
     static const XMLCh Binding[] =              UNICODE_LITERAL_7(B,i,n,d,i,n,g);
     static const XMLCh Channel[]=               UNICODE_LITERAL_7(C,h,a,n,n,e,l);
     static const XMLCh _CredentialResolver[] =  UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);
+    static const XMLCh _default[] =             UNICODE_LITERAL_7(d,e,f,a,u,l,t);
     static const XMLCh _Extensions[] =          UNICODE_LITERAL_10(E,x,t,e,n,s,i,o,n,s);
     static const XMLCh _fatal[] =               UNICODE_LITERAL_5(f,a,t,a,l);
     static const XMLCh _Handler[] =             UNICODE_LITERAL_7(H,a,n,d,l,e,r);
@@ -459,6 +461,7 @@ namespace {
     static const XMLCh RelyingParty[] =         UNICODE_LITERAL_12(R,e,l,y,i,n,g,P,a,r,t,y);
     static const XMLCh _ReplayCache[] =         UNICODE_LITERAL_11(R,e,p,l,a,y,C,a,c,h,e);
     static const XMLCh _RequestMapper[] =       UNICODE_LITERAL_13(R,e,q,u,e,s,t,M,a,p,p,e,r);
+    static const XMLCh RequestMap[] =           UNICODE_LITERAL_10(R,e,q,u,e,s,t,M,a,p);
     static const XMLCh SecurityPolicies[] =     UNICODE_LITERAL_16(S,e,c,u,r,i,t,y,P,o,l,i,c,i,e,s);
     static const XMLCh SecurityPolicyProvider[] = UNICODE_LITERAL_22(S,e,c,u,r,i,t,y,P,o,l,i,c,y,P,r,o,v,i,d,e,r);
     static const XMLCh _SessionCache[] =        UNICODE_LITERAL_12(S,e,s,s,i,o,n,C,a,c,h,e);
@@ -509,7 +512,7 @@ XMLApplication::XMLApplication(
         XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();
 #endif
 
-        // This used to be an actual hash, but now it's just a hex-encode to avoid xmlsec.
+        // This used to be an actual hash, but now it's just a hex-encode to avoid xmlsec dependency.
         static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
         string tohash=getId();
         tohash+=getString("entityID").second;
@@ -1503,8 +1506,12 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
                 }
             }
             if (!m_requestMapper) {
-                log.fatal("can't build RequestMapper, missing conf:RequestMapper element?");
-                throw ConfigurationException("Can't build RequestMapper, missing conf:RequestMapper element?");
+                log.info("no RequestMapper specified, using 'Native' plugin with empty/default map");
+                child = e->getOwnerDocument()->createElementNS(nullptr, _RequestMapper);
+                DOMElement* mapperDummy = e->getOwnerDocument()->createElementNS(shibspconstants::SHIB2SPCONFIG_NS, RequestMap);
+                mapperDummy->setAttributeNS(nullptr, applicationId, _default);
+                child->appendChild(mapperDummy);
+                m_requestMapper = conf.RequestMapperManager.newPlugin(NATIVE_REQUEST_MAPPER, child);
             }
         }
 
@@ -1564,7 +1571,7 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o
         }
 #endif
 
-        // Load the default application. This actually has a fixed ID of "default". ;-)
+        // Load the default application.
         child = XMLHelper::getLastChildElement(e, ApplicationDefaults);
         if (!child) {
             log.fatal("can't build default Application object, missing conf:ApplicationDefaults element?");
index 12155fc..2c7f64b 100644 (file)
@@ -255,3 +255,21 @@ const PropertySet* DOMPropertySet::getPropertySet(const char* name, const char*
 
     return (i!=m_nested.end()) ? i->second : (m_parent ? m_parent->getPropertySet(name,ns) : nullptr);
 }
+
+bool DOMPropertySet::setProperty(const char* name, const char* val, const char* ns)
+{
+    string propname = ns ? (string("{") + ns + "}" + name) : name;
+
+    // Erase existing property.
+    if (m_map.count(propname) > 0) {
+        XMLString::release(&m_map[propname].first);
+        m_map.erase(propname);
+    }
+
+    char* dup = XMLString::replicate(val);
+    auto_ptr_XMLCh widedup(val);
+    m_injected.push_back(widedup.get());
+    m_map[propname] = make_pair(dup, m_injected.back().c_str());
+
+    return true;
+}
index 24e11fc..8d41e14 100644 (file)
@@ -65,11 +65,23 @@ namespace shibsp {
             const std::map<std::string,std::string>* remapper=nullptr
             );
 
+    protected:
+        /**
+         * Post-load injection of a property, for use by subclasses.
+         *
+         * @param name  property name
+         * @param val   property value
+         * @param ns    property namespace
+         * @return  true iff the property was successfully set
+         */
+        bool setProperty(const char* name, const char* val, const char* ns=nullptr);
+
     private:
         const PropertySet* m_parent;
         const xercesc::DOMElement* m_root;
         std::map<std::string,std::pair<char*,const XMLCh*> > m_map;
         std::map<std::string,DOMPropertySet*> m_nested;
+        std::vector<xmltooling::xstring> m_injected;
     };
 
 };