Fix issuer auto-extraction from token.
[shibboleth/cpp-sp-resolver.git] / src / shibresolver / resolver.cpp
index 83b6269..79c3537 100644 (file)
 
 #include "internal.h"
 
+#ifdef SHIBRESOLVER_HAVE_GSSAPI_NAMINGEXTS
+# ifdef SHIBRESOLVER_HAVE_GSSMIT
+#  include <gssapi/gssapi_ext.h>
+# endif
+#endif
+
 #include <shibsp/exceptions.h>
 #include <shibsp/Application.h>
 #include <shibsp/GSSRequest.h>
@@ -116,7 +122,9 @@ void ShibbolethResolver::setRequest(const SPRequest* request)
     if (request) {
         const GSSRequest* gss = dynamic_cast<const GSSRequest*>(request);
         if (gss) {
-            addToken(gss->getGSSContext());
+            // TODO: fix API to prevent destruction of contexts
+            gss_ctx_id_t ctx = gss->getGSSContext();
+            addToken(&ctx);
         }
     }
 #endif
@@ -143,19 +151,17 @@ void ShibbolethResolver::addToken(const XMLObject* token)
 }
 
 #ifdef SHIBRESOLVER_HAVE_GSSAPI
-void ShibbolethResolver::addToken(gss_ctx_id_t ctx)
+void ShibbolethResolver::addToken(gss_ctx_id_t* ctx)
 {
     if (m_gsswrapper) {
         delete m_gsswrapper;
         m_gsswrapper = NULL;
     }
 
-    if (ctx != GSS_C_NO_CONTEXT) {
+    if (ctx && *ctx != GSS_C_NO_CONTEXT) {
         OM_uint32 minor;
-        gss_buffer_desc contextbuf;
-        contextbuf.length = 0;
-        contextbuf.value = NULL;
-        OM_uint32 major = gss_export_sec_context(&minor, &ctx, &contextbuf);
+        gss_buffer_desc contextbuf = GSS_C_EMPTY_BUFFER;
+        OM_uint32 major = gss_export_sec_context(&minor, ctx, &contextbuf);
         if (major == GSS_S_COMPLETE) {
             xsecsize_t len=0;
             XMLByte* out=Base64::encode(reinterpret_cast<const XMLByte*>(contextbuf.value), contextbuf.length, &len);
@@ -168,19 +174,69 @@ void ShibbolethResolver::addToken(gss_ctx_id_t ctx)
 #else
                 XMLString::release((char**)&out);
 #endif
-                static const XMLCh _GSSAPI[] = UNICODE_LITERAL_6(G,S,S,A,P,I);
+                static const XMLCh _GSSAPI[] = UNICODE_LITERAL_13(G,S,S,A,P,I,C,o,n,t,e,x,t);
                 m_gsswrapper = new AnyElementImpl(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _GSSAPI);
                 m_gsswrapper->setTextContent(temp.get());
             }
             else {
                 Category::getInstance(SHIBRESOLVER_LOGCAT).error("error while base64-encoding GSS context");
             }
+            gss_release_buffer(&minor, &contextbuf);
         }
         else {
             Category::getInstance(SHIBRESOLVER_LOGCAT).error("error exporting GSS context");
         }
     }
 }
+
+#ifdef SHIBRESOLVER_HAVE_GSSAPI_NAMINGEXTS
+void ShibbolethResolver::addToken(gss_name_t name)
+{
+    if (m_gsswrapper) {
+        delete m_gsswrapper;
+        m_gsswrapper = NULL;
+    }
+
+    OM_uint32 minor;
+    gss_buffer_desc namebuf = GSS_C_EMPTY_BUFFER;
+    OM_uint32 major = gss_export_name_composite(&minor, name, &namebuf);
+    if (major == GSS_S_COMPLETE) {
+        addToken(&namebuf);
+        gss_release_buffer(&minor, &namebuf);
+    }
+    else {
+        Category::getInstance(SHIBRESOLVER_LOGCAT).error("error exporting GSS name");
+    }
+}
+#endif
+
+void ShibbolethResolver::addToken(const gss_buffer_t contextbuf)
+{
+    if (m_gsswrapper) {
+        delete m_gsswrapper;
+        m_gsswrapper = NULL;
+    }
+
+    xsecsize_t len=0;
+    XMLByte* out=Base64::encode(reinterpret_cast<const XMLByte*>(contextbuf->value), contextbuf->length, &len);
+    if (out) {
+        string s;
+        s.append(reinterpret_cast<char*>(out), len);
+        auto_ptr_XMLCh temp(s.c_str());
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+        XMLString::release(&out);
+#else
+        XMLString::release((char**)&out);
+#endif
+        static const XMLCh _GSSAPI[] = UNICODE_LITERAL_10(G,S,S,A,P,I,N,a,m,e);
+        m_gsswrapper = new AnyElementImpl(shibspconstants::SHIB2ATTRIBUTEMAP_NS, _GSSAPI);
+        m_gsswrapper->setTextContent(temp.get());
+    }
+    else {
+        Category::getInstance(SHIBRESOLVER_LOGCAT).error("error while base64-encoding GSS name");
+    }
+}
+
 #endif
 
 void ShibbolethResolver::addAttribute(Attribute* attr)
@@ -216,7 +272,7 @@ void ShibbolethResolver::resolve()
     if (!app)
         throw ConfigurationException("Unable to locate application for resolution.");
 
-#ifdef HAVE_GSSAPI
+#ifdef SHIBRESOLVER_HAVE_GSSAPI
     if (m_gsswrapper)
         m_tokens.push_back(m_gsswrapper);
 #endif
@@ -341,21 +397,45 @@ void RemotedResolver::resolve(
 {
 #ifndef SHIBSP_LITE
     Category& log = Category::getInstance(SHIBRESOLVER_LOGCAT);
+    string issuerstr(issuer ? issuer : "");
     pair<const EntityDescriptor*,const RoleDescriptor*> entity = make_pair((EntityDescriptor*)NULL, (RoleDescriptor*)NULL);
     MetadataProvider* m = app.getMetadataProvider(false);
     Locker locker(m);
     if (!m) {
         log.warn("no metadata providers are configured");
     }
-    else if (issuer && *issuer) {
-        // Lookup metadata for the issuer.
-        MetadataProviderCriteria mc(app, issuer, &IDPSSODescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
-        entity = m->getEntityDescriptor(mc);
-        if (!entity.first) {
-            log.warn("unable to locate metadata for provider (%s)", issuer);
+    else {
+        if (issuerstr.empty()) {
+            // Attempt to locate an issuer based on input token.
+            for (vector<const XMLObject*>::const_iterator t = tokens.begin(); t!=tokens.end(); ++t) {
+                const saml2::Assertion* assertion = dynamic_cast<const saml2::Assertion*>(*t);
+                if (assertion && assertion->getIssuer()) {
+                    auto_ptr_char iss(assertion->getIssuer()->getName());
+                    if (iss.get() && *iss.get()) {
+                        issuerstr = iss.get();
+                        break;
+                    }
+                }
+            }
+            if (!issuerstr.empty()) {
+                log.info("setting issuer based on input token (%s)", issuerstr.c_str());
+            }
         }
-        else if (!entity.second) {
-            log.warn("unable to locate SAML 2.0 identity provider role for provider (%s)", issuer);
+
+        if (!issuerstr.empty()) {
+            // Lookup metadata for the issuer.
+            MetadataProviderCriteria idpmc(app, issuerstr.c_str(), &IDPSSODescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
+            entity = m->getEntityDescriptor(idpmc);
+            if (!entity.first) {
+                log.warn("unable to locate metadata for provider (%s)", issuerstr.c_str());
+            }
+            else if (!entity.second) {
+                MetadataProviderCriteria aamc(app, issuerstr.c_str(), &AttributeAuthorityDescriptor::ELEMENT_QNAME, samlconstants::SAML20P_NS);
+                entity = m->getEntityDescriptor(aamc);
+                if (!entity.second) {
+                    log.warn("unable to locate SAML 2.0 IdP or AA role for provider (%s)", issuerstr.c_str());
+                }
+            }
         }
     }