Add a RP-based key name to credential lookup.
[shibboleth/sp.git] / shibsp / handler / impl / SAML2SessionInitiator.cpp
index ae09b9b..c904614 100644 (file)
 #include "handler/SessionInitiator.h"
 #include "util/SPConstants.h"
 
-#include <saml/SAMLConfig.h>
-#include <saml/binding/MessageEncoder.h>
-#include <saml/saml2/core/Protocols.h>
-#include <saml/saml2/metadata/EndpointManager.h>
-#include <saml/saml2/metadata/Metadata.h>
-#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
-
-using namespace shibsp;
+#ifndef SHIBSP_LITE
+# include <saml/SAMLConfig.h>
+# include <saml/binding/MessageEncoder.h>
+# include <saml/saml2/core/Protocols.h>
+# include <saml/saml2/metadata/EndpointManager.h>
+# include <saml/saml2/metadata/Metadata.h>
+# include <saml/saml2/metadata/MetadataCredentialCriteria.h>
 using namespace opensaml::saml2;
 using namespace opensaml::saml2p;
 using namespace opensaml::saml2md;
+#endif
+
+using namespace shibsp;
 using namespace opensaml;
 using namespace xmltooling;
 using namespace log4cpp;
@@ -58,11 +60,13 @@ namespace shibsp {
     public:
         SAML2SessionInitiator(const DOMElement* e, const char* appId);
         virtual ~SAML2SessionInitiator() {
+#ifndef SHIBSP_LITE
             if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
                 XMLString::release(&m_outgoing);
                 for_each(m_encoders.begin(), m_encoders.end(), cleanup_pair<const XMLCh*,MessageEncoder>());
                 delete m_requestTemplate;
             }
+#endif
         }
         
         void setParent(const PropertySet* parent);
@@ -85,10 +89,12 @@ namespace shibsp {
             ) const;
 
         string m_appId;
+#ifndef SHIBSP_LITE
         XMLCh* m_outgoing;
         vector<const XMLCh*> m_bindings;
         map<const XMLCh*,MessageEncoder*> m_encoders;
         AuthnRequest* m_requestTemplate;
+#endif
     };
 
 #if defined (_MSC_VER)
@@ -103,8 +109,11 @@ namespace shibsp {
 };
 
 SAML2SessionInitiator::SAML2SessionInitiator(const DOMElement* e, const char* appId)
-    : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionInitiator")), m_appId(appId), m_outgoing(NULL), m_requestTemplate(NULL)
+    : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionInitiator")), m_appId(appId)
 {
+#ifndef SHIBSP_LITE
+    m_outgoing=NULL;
+    m_requestTemplate=NULL;
     if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
         // Check for a template AuthnRequest to build from.
         DOMElement* child = XMLHelper::getFirstChildElement(e, samlconstants::SAML20P_NS, AuthnRequest::LOCAL_NAME);
@@ -146,6 +155,7 @@ SAML2SessionInitiator::SAML2SessionInitiator(const DOMElement* e, const char* ap
                 break;
         }
     }
+#endif
 
     // If Location isn't set, defer address registration until the setParent call.
     pair<bool,const char*> loc = getString("Location");
@@ -185,13 +195,16 @@ pair<bool,long> SAML2SessionInitiator::run(SPRequest& request, const char* entit
 
     if (isHandler) {
         option=request.getParameter("acsIndex");
-        if (option)
+        if (option) {
             ACS = app.getAssertionConsumerServiceByIndex(atoi(option));
+            if (!ACS)
+                throw ConfigurationException("AssertionConsumerService with index ($1) not found, check configuration.", params(1,option));
+        }
 
         option = request.getParameter("target");
         if (option)
             target = option;
-        if (!acsByIndex.first || !acsByIndex.second) {
+        if (acsByIndex.first && !acsByIndex.second) {
             // Since we're passing the ACS by value, we need to compute the return URL,
             // so we'll need the target resource for real.
             recoverRelayState(request.getApplication(), request, target, false);
@@ -233,7 +246,7 @@ pair<bool,long> SAML2SessionInitiator::run(SPRequest& request, const char* entit
 
     SPConfig& conf = SPConfig::getConfig();
     if (conf.isEnabled(SPConfig::OutOfProcess)) {
-        if (acsByIndex.first && acsByIndex.second) {
+        if (!acsByIndex.first || acsByIndex.second) {
             // Pass by Index. This also allows for defaulting it entirely and sending nothing.
             if (isHandler) {
                 // We may already have RelayState set if we looped back here,
@@ -294,7 +307,7 @@ pair<bool,long> SAML2SessionInitiator::run(SPRequest& request, const char* entit
         in.addmember("authnContextClassRef").string(acClass.second);
     if (acComp.first)
         in.addmember("authnContextComparison").string(acComp.second);
-    if (acsByIndex.first && acsByIndex.second) {
+    if (!acsByIndex.first || acsByIndex.second) {
         if (ACS)
             in.addmember("acsIndex").string(ACS->getString("index").second);
     }
@@ -381,13 +394,15 @@ pair<bool,long> SAML2SessionInitiator::doRequest(
     string& relayState
     ) const
 {
+#ifndef SHIBSP_LITE
     // Use metadata to locate the IdP's SSO service.
     MetadataProvider* m=app.getMetadataProvider();
     Locker locker(m);
     const EntityDescriptor* entity=m->getEntityDescriptor(entityID);
     if (!entity) {
         m_log.error("unable to locate metadata for provider (%s)", entityID);
-        return make_pair(false,0);
+        throw MetadataException("Unable to locate metadata for identity provider ($entityID)",
+            namedparams(1, "entityID", entityID));
     }
     const IDPSSODescriptor* role=entity->getIDPSSODescriptor(samlconstants::SAML20P_NS);
     if (!role) {
@@ -422,13 +437,13 @@ pair<bool,long> SAML2SessionInitiator::doRequest(
     }
 
     req->setDestination(ep->getLocation());
-    if (acsIndex)
+    if (acsIndex && *acsIndex)
         req->setAssertionConsumerServiceIndex(acsIndex);
     if (acsLocation) {
         auto_ptr_XMLCh wideloc(acsLocation);
         req->setAssertionConsumerServiceURL(wideloc.get());
     }
-    if (acsBinding)
+    if (acsBinding && *acsBinding)
         req->setProtocolBinding(acsBinding);
     if (isPassive)
         req->IsPassive(isPassive);
@@ -437,7 +452,7 @@ pair<bool,long> SAML2SessionInitiator::doRequest(
     if (!req->getIssuer()) {
         Issuer* issuer = IssuerBuilder::buildIssuer();
         req->setIssuer(issuer);
-        issuer->setName(app.getXMLString("providerId").second);
+        issuer->setName(app.getXMLString("entityID").second);
     }
     if (!req->getNameIDPolicy()) {
         NameIDPolicy* namepol = NameIDPolicyBuilder::buildNameIDPolicy();
@@ -476,6 +491,9 @@ pair<bool,long> SAML2SessionInitiator::doRequest(
             // Fill in criteria to use.
             MetadataCredentialCriteria mcc(*role);
             mcc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
+            pair<bool,const char*> keyName = relyingParty->getString("keyName");
+            if (keyName.first)
+                mcc.getKeyNames().insert(keyName.second);
             pair<bool,const XMLCh*> sigalg = relyingParty->getXMLString("signatureAlg");
             if (sigalg.first)
                 mcc.setXMLAlgorithm(sigalg.second);
@@ -505,4 +523,7 @@ pair<bool,long> SAML2SessionInitiator::doRequest(
     long ret = encoder->encode(httpResponse, req.get(), dest.get(), entityID, relayState.c_str());
     req.release();  // freed by encoder
     return make_pair(true,ret);
+#else
+    return make_pair(false,0);
+#endif
 }