https://issues.shibboleth.net/jira/browse/SSPCPP-365
[shibboleth/cpp-sp.git] / plugins / GSSAPIAttributeExtractor.cpp
index 42421fe..ec90a89 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * GSSAPIAttributeExtractor.cpp
  *
- * AttributeExtractor for a base64-encoded GSS-API context.
+ * AttributeExtractor for a base64-encoded GSS-API context or name.
  */
 
 #include "internal.h"
@@ -27,6 +27,7 @@
 #include <shibsp/exceptions.h>
 #include <shibsp/Application.h>
 #include <shibsp/SPConfig.h>
+#include <shibsp/attribute/BinaryAttribute.h>
 #include <shibsp/attribute/ScopedAttribute.h>
 #include <shibsp/attribute/SimpleAttribute.h>
 #include <shibsp/attribute/resolver/AttributeExtractor.h>
 #include <xercesc/util/Base64.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
 
-#include <gssapi/gssapi_ext.h>
+#ifdef SHIBSP_HAVE_GSSGNU
+# include <gss.h>
+#elif defined SHIBSP_HAVE_GSSMIT
+# include <gssapi/gssapi_ext.h>
+#else
+# include <gssapi.h>
+#endif
+
 
 using namespace shibsp;
 using namespace opensaml::saml2md;
@@ -71,9 +79,8 @@ namespace shibsp {
             m_document = doc;
         }
 
-        void extractAttributes(
-            gss_name_t initiatorName, gss_buffer_t namingAttribute, vector<Attribute*>& attributes
-            ) const;
+        void extractAttributes(gss_name_t initiatorName, vector<Attribute*>& attributes) const;
+        void extractAttributes(gss_name_t initiatorName, gss_buffer_t namingAttribute, vector<Attribute*>& attributes) const;
 
         void getAttributeIds(vector<string>& attributes) const {
             attributes.insert(attributes.end(), m_attributeIds.begin(), m_attributeIds.end());
@@ -81,9 +88,9 @@ namespace shibsp {
 
     private:
         struct Rule {
-            Rule() : authenticated(true), scopeDelimiter(0) {}
+            Rule() : authenticated(true), binary(false), scopeDelimiter(0) {}
             vector<string> ids;
-            bool authenticated;
+            bool authenticated,binary;
             char scopeDelimiter;
         };
 
@@ -136,6 +143,7 @@ namespace shibsp {
     static const XMLCh _aliases[] =             UNICODE_LITERAL_7(a,l,i,a,s,e,s);
     static const XMLCh Attributes[] =           UNICODE_LITERAL_10(A,t,t,r,i,b,u,t,e,s);
     static const XMLCh _authenticated[] =       UNICODE_LITERAL_13(a,u,t,h,e,n,t,i,c,a,t,e,d);
+    static const XMLCh _binary[] =              UNICODE_LITERAL_6(b,i,n,a,r,y);
     static const XMLCh GSSAPIAttribute[] =      UNICODE_LITERAL_15(G,S,S,A,P,I,A,t,t,r,i,b,u,t,e);
     static const XMLCh _id[] =                  UNICODE_LITERAL_2(i,d);
     static const XMLCh _name[] =                UNICODE_LITERAL_4(n,a,m,e);
@@ -213,6 +221,7 @@ GSSAPIExtractorImpl::GSSAPIExtractorImpl(const DOMElement* e, Category& log)
         }
 
         decl.authenticated = XMLHelper::getAttrBool(child, true, _authenticated);
+        decl.binary = XMLHelper::getAttrBool(child, false, _binary);
         string delim = XMLHelper::getAttrString(child, "", _scopeDelimiter);
         if (!delim.empty())
             decl.scopeDelimiter = delim[0];
@@ -221,6 +230,22 @@ GSSAPIExtractorImpl::GSSAPIExtractorImpl(const DOMElement* e, Category& log)
     }
 }
 
+void GSSAPIExtractorImpl::extractAttributes(gss_name_t initiatorName, vector<Attribute*>& attributes) const
+{
+    OM_uint32 minor;
+    gss_buffer_set_t attrnames = GSS_C_NO_BUFFER_SET;
+    OM_uint32 major = gss_inquire_name(&minor, initiatorName, nullptr, nullptr, &attrnames);
+    if (major == GSS_S_COMPLETE) {
+        for (size_t i = 0; i < attrnames->count; ++i) {
+            extractAttributes(initiatorName, &attrnames->elements[i], attributes);
+        }
+        gss_release_buffer_set(&minor, &attrnames);
+    }
+    else {
+        m_log.warn("unable to extract attributes, GSS name attribute inquiry failed (%u:%u)", major, minor);
+    }
+}
+
 void GSSAPIExtractorImpl::extractAttributes(
     gss_name_t initiatorName, gss_buffer_t namingAttribute, vector<Attribute*>& attributes
     ) const
@@ -248,8 +273,9 @@ void GSSAPIExtractorImpl::extractAttributes(
                 gss_release_buffer(&minor, &buf);
                 return;
             }
-            if (buf.length)
+            if (buf.length) {
                 values.push_back(string(reinterpret_cast<char*>(buf.value), buf.length));
+            }
             gss_release_buffer(&minor, &buf);
         }
         else {
@@ -260,7 +286,7 @@ void GSSAPIExtractorImpl::extractAttributes(
     if (values.empty())
         return;
 
-    if (rule->second.scopeDelimiter) {
+    if (rule->second.scopeDelimiter && !rule->second.binary) {
         auto_ptr<ScopedAttribute> scoped(new ScopedAttribute(rule->second.ids, rule->second.scopeDelimiter));
         vector< pair<string,string> >& dest = scoped->getValues();
         for (vector<string>::const_iterator v = values.begin(); v != values.end(); ++v) {
@@ -279,8 +305,12 @@ void GSSAPIExtractorImpl::extractAttributes(
         if (!scoped->getValues().empty())
             attributes.push_back(scoped.release());
     }
+    else if (rule->second.binary) {
+        auto_ptr<BinaryAttribute> binary(new BinaryAttribute(rule->second.ids));
+        binary->getValues() = values;
+        attributes.push_back(binary.release());
+    }
     else {
-        // If unscoped, just copy over the values.
         auto_ptr<SimpleAttribute> simple(new SimpleAttribute(rule->second.ids));
         simple->getValues() = values;
         attributes.push_back(simple.release());
@@ -295,7 +325,11 @@ void GSSAPIExtractor::extractAttributes(
         return;
 
     static const XMLCh _GSSAPIContext[] = UNICODE_LITERAL_13(G,S,S,A,P,I,C,o,n,t,e,x,t);
-    if (!XMLString::equals(xmlObject.getElementQName().getLocalPart(), _GSSAPIContext)) {
+    static const XMLCh _GSSAPIName[] = UNICODE_LITERAL_10(G,S,S,A,P,I,N,a,m,e);
+
+    if (!XMLString::equals(xmlObject.getElementQName().getLocalPart(), _GSSAPIContext)
+           && !XMLString::equals(xmlObject.getElementQName().getLocalPart(), _GSSAPIName)
+        ) {
         m_log.debug("unable to extract attributes, unknown XML object type: %s", xmlObject.getElementQName().toString().c_str());
         return;
     }
@@ -306,20 +340,39 @@ void GSSAPIExtractor::extractAttributes(
         return;
     }
 
-    gss_ctx_id_t gss = GSS_C_NO_CONTEXT;
-
     xsecsize_t x;
     OM_uint32 major,minor;
     auto_ptr_char encoded(encodedWide);
+
+    gss_name_t srcname;
+    gss_ctx_id_t gss = GSS_C_NO_CONTEXT;
+
     XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(encoded.get()), &x);
     if (decoded) {
         gss_buffer_desc importbuf;
         importbuf.length = x;
         importbuf.value = decoded;
-        major = gss_import_sec_context(&minor, &importbuf, &gss);
-        if (major != GSS_S_COMPLETE) {
-            m_log.warn("unable to extract attributes, GSS context import failed (%u:%u)", major, minor);
-            gss = GSS_C_NO_CONTEXT;
+        if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), _GSSAPIName)) {
+#ifdef HAVE_GSSAPI_COMPOSITE_NAME
+            major = gss_import_name(&minor, &importbuf, GSS_C_NT_EXPORT_NAME_COMPOSITE, &srcname);
+#else
+            major = gss_import_name(&minor, &importbuf, GSS_C_NT_EXPORT_NAME, &srcname);
+#endif
+            if (major == GSS_S_COMPLETE) {
+                m_impl->extractAttributes(srcname, attributes);
+                gss_release_name(&minor, &srcname);
+            }
+            else {
+                m_log.warn("unable to extract attributes, GSS name import failed (%u:%u)", major, minor);
+            }
+            // We fall through here down to the GSS context check, which will exit us.
+        }
+        else {
+            major = gss_import_sec_context(&minor, &importbuf, &gss);
+            if (major != GSS_S_COMPLETE) {
+                m_log.warn("unable to extract attributes, GSS context import failed (%u:%u)", major, minor);
+                gss = GSS_C_NO_CONTEXT;
+            }
         }
 #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
         XMLString::release(&decoded);
@@ -328,27 +381,17 @@ void GSSAPIExtractor::extractAttributes(
 #endif
     }
     else {
-        m_log.warn("unable to extract attributes, base64 decode of GSSAPI context failed");
+        m_log.warn("unable to extract attributes, base64 decode of GSSAPI context or name failed");
     }
 
     if (gss == GSS_C_NO_CONTEXT) {
         return;
     }
+
     // Extract the initiator name from the context.
-    gss_name_t srcname;
     major = gss_inquire_context(&minor, gss, &srcname, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
     if (major == GSS_S_COMPLETE) {
-        gss_buffer_set_t attrnames = GSS_C_NO_BUFFER_SET;
-        major = gss_inquire_name(&minor, srcname, nullptr, nullptr, &attrnames);
-        if (major == GSS_S_COMPLETE) {
-            for (size_t i = 0; i < attrnames->count; ++i) {
-                m_impl->extractAttributes(srcname, &attrnames->elements[i], attributes);
-            }
-            gss_release_buffer_set(&minor, &attrnames);
-        }
-        else {
-            m_log.warn("unable to extract attributes, GSS name attribute inquiry failed (%u:%u)", major, minor);
-        }
+        m_impl->extractAttributes(srcname, attributes);
         gss_release_name(&minor, &srcname);
     }
     else {