https://issues.shibboleth.net/jira/browse/SSPCPP-254
[shibboleth/cpp-sp.git] / shibsp / handler / impl / AbstractHandler.cpp
index a2e5439..07319d3 100644 (file)
@@ -67,15 +67,14 @@ using namespace xercesc;
 using namespace std;
 
 namespace shibsp {
+
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML1ConsumerFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ConsumerFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2ArtifactResolutionFactory;
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory ChainingLogoutInitiatorFactory;
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory LocalLogoutInitiatorFactory;
-    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutInitiatorFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2LogoutFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SAML2NameIDMgmtFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AssertionLookupFactory;
+    SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory DiscoveryFeedFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory MetadataGeneratorFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory StatusHandlerFactory;
     SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SessionHandlerFactory;
@@ -120,29 +119,32 @@ void SHIBSP_API shibsp::registerHandlers()
 {
     SPConfig& conf=SPConfig::getConfig();
 
+    conf.AssertionConsumerServiceManager.registerFactory(SAML1_ASSERTION_CONSUMER_SERVICE, SAML1ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_ARTIFACT, SAML1ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML1_PROFILE_BROWSER_POST, SAML1ConsumerFactory);
+    conf.AssertionConsumerServiceManager.registerFactory(SAML20_ASSERTION_CONSUMER_SERVICE, SAML2ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2ConsumerFactory);
     conf.AssertionConsumerServiceManager.registerFactory(SAML20_BINDING_PAOS, SAML2ConsumerFactory);
 
+    conf.ArtifactResolutionServiceManager.registerFactory(SAML20_ARTIFACT_RESOLUTION_SERVICE, SAML2ArtifactResolutionFactory);
     conf.ArtifactResolutionServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2ArtifactResolutionFactory);
 
     conf.HandlerManager.registerFactory(SAML20_BINDING_URI, AssertionLookupFactory);
+    conf.HandlerManager.registerFactory(DISCOVERY_FEED_HANDLER, DiscoveryFeedFactory);
     conf.HandlerManager.registerFactory(METADATA_GENERATOR_HANDLER, MetadataGeneratorFactory);
     conf.HandlerManager.registerFactory(STATUS_HANDLER, StatusHandlerFactory);
     conf.HandlerManager.registerFactory(SESSION_HANDLER, SessionHandlerFactory);
 
-    conf.LogoutInitiatorManager.registerFactory(CHAINING_LOGOUT_INITIATOR, ChainingLogoutInitiatorFactory);
-    conf.LogoutInitiatorManager.registerFactory(LOCAL_LOGOUT_INITIATOR, LocalLogoutInitiatorFactory);
-    conf.LogoutInitiatorManager.registerFactory(SAML2_LOGOUT_INITIATOR, SAML2LogoutInitiatorFactory);
+    conf.SingleLogoutServiceManager.registerFactory(SAML20_LOGOUT_HANDLER, SAML2LogoutFactory);
     conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2LogoutFactory);
     conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_REDIRECT, SAML2LogoutFactory);
     conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2LogoutFactory);
     conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_POST_SIMPLESIGN, SAML2LogoutFactory);
     conf.SingleLogoutServiceManager.registerFactory(SAML20_BINDING_HTTP_ARTIFACT, SAML2LogoutFactory);
 
+    conf.ManageNameIDServiceManager.registerFactory(SAML20_NAMEID_MGMT_SERVICE, SAML2NameIDMgmtFactory);
     conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_SOAP, SAML2NameIDMgmtFactory);
     conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_REDIRECT, SAML2NameIDMgmtFactory);
     conf.ManageNameIDServiceManager.registerFactory(SAML20_BINDING_HTTP_POST, SAML2NameIDMgmtFactory);
@@ -176,11 +178,18 @@ void Handler::log(SPRequest::SPLogLevel level, const string& msg) const
 
 void Handler::preserveRelayState(const Application& application, HTTPResponse& response, string& relayState) const
 {
+    // The empty string implies no state to deal with.
     if (relayState.empty())
         return;
 
-    // No setting means just pass it by value.
-    pair<bool,const char*> mech=getString("relayState");
+    // No setting means just pass state by value.
+    pair<bool,const char*> mech = getString("relayState");
+    if (!mech.first) {
+        // Check for setting on Sessions element.
+        const PropertySet* sessionprop = application.getPropertySet("Sessions");
+        if (sessionprop)
+            mech = sessionprop->getString("relayState");
+    }
     if (!mech.first || !mech.second || !*mech.second)
         return;
 
@@ -454,9 +463,19 @@ long AbstractHandler::sendMessage(
                 mcc.setUsage(Credential::SIGNING_CREDENTIAL);
                 if (keyName.first)
                     mcc.getKeyNames().insert(keyName.second);
-                if (sigalg.first)
+                if (sigalg.first) {
+                    // Using an explicit algorithm, so resolve a credential directly.
                     mcc.setXMLAlgorithm(sigalg.second);
-                cred = credResolver->resolve(&mcc);
+                    cred = credResolver->resolve(&mcc);
+                }
+                else {
+                    // Prefer credential based on peer's requirements.
+                    pair<const SigningMethod*,const Credential*> p = role->getSigningMethod(*credResolver, mcc);
+                    if (p.first)
+                        sigalg = make_pair(true, p.first->getAlgorithm());
+                    if (p.second)
+                        cred = p.second;
+                }
             }
             else {
                 CredentialCriteria cc;
@@ -469,6 +488,12 @@ long AbstractHandler::sendMessage(
             }
             if (cred) {
                 // Signed request.
+                pair<bool,const XMLCh*> digalg = relyingParty->getXMLString("digestAlg");
+                if (!digalg.first && role) {
+                    const DigestMethod* dm = role->getDigestMethod();
+                    if (dm)
+                        digalg = make_pair(true, dm->getAlgorithm());
+                }
                 return encoder.encode(
                     httpResponse,
                     msg,
@@ -478,7 +503,7 @@ long AbstractHandler::sendMessage(
                     &application,
                     cred,
                     sigalg.second,
-                    relyingParty->getXMLString("digestAlg").second
+                    (digalg.first ? digalg.second : nullptr)
                     );
             }
             else {
@@ -508,7 +533,7 @@ void AbstractHandler::preservePostData(
 
     // No specs mean no save.
     const PropertySet* props=application.getPropertySet("Sessions");
-    pair<bool,const char*> mech = props->getString("postData");
+    pair<bool,const char*> mech = props ? props->getString("postData") : pair<bool,const char*>(false,nullptr);
     if (!mech.first) {
         m_log.info("postData property not supplied, form data will not be preserved across SSO");
         return;
@@ -637,9 +662,9 @@ long AbstractHandler::sendPostResponse(
     HTTPResponse::sanitizeURL(url);
 
     const PropertySet* props=application.getPropertySet("Sessions");
-    pair<bool,const char*> postTemplate = props->getString("postTemplate");
+    pair<bool,const char*> postTemplate = props ? props->getString("postTemplate") : pair<bool,const char*>(true,nullptr);
     if (!postTemplate.first)
-        throw ConfigurationException("Missing postTemplate property, unable to recreate form post.");
+        postTemplate.second = "postTemplate.html";
 
     string fname(postTemplate.second);
     ifstream infile(XMLToolingConfig::getConfig().getPathResolver()->resolve(fname, PathResolver::XMLTOOLING_CFG_FILE).c_str());
@@ -659,7 +684,7 @@ long AbstractHandler::sendPostResponse(
     stringstream str;
     XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, respParam);
 
-    pair<bool,bool> postExpire = props->getBool("postExpire");
+    pair<bool,bool> postExpire = props ? props->getBool("postExpire") : make_pair(false,false);
 
     httpResponse.setContentType("text/html");
     if (!postExpire.first || postExpire.second) {
@@ -692,7 +717,7 @@ DDF AbstractHandler::getPostData(const Application& application, const HTTPReque
     string contentType = request.getContentType();
     if (contentType.compare("application/x-www-form-urlencoded") == 0) {
         const PropertySet* props=application.getPropertySet("Sessions");
-        pair<bool,unsigned int> plimit = props->getUnsignedInt("postLimit");
+        pair<bool,unsigned int> plimit = props ? props->getUnsignedInt("postLimit") : pair<bool,unsigned int>(false,0);
         if (!plimit.first)
             plimit.second = 1024 * 1024;
         if (plimit.second == 0 || request.getContentLength() <= plimit.second) {