Restrict pre-2.4 use of new require rules
[shibboleth/cpp-sp.git] / plugins / GSSAPIAttributeExtractor.cpp
index eae93ba..8933d78 100644 (file)
@@ -1,17 +1,21 @@
-/*
- *  Copyright 2011 JANET(UK)
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * UCAID licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the
+ * License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
  */
 
 /**
@@ -27,6 +31,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 <xmltooling/util/XMLHelper.h>
 #include <xercesc/util/Base64.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
+#include <boost/algorithm/string.hpp>
+
+#ifdef SHIBSP_HAVE_GSSGNU
+# include <gss.h>
+#elif defined SHIBSP_HAVE_GSSMIT
+# include <gssapi/gssapi_ext.h>
+#else
+# include <gssapi.h>
+#endif
 
-#include <gssapi/gssapi_ext.h>
 
 using namespace shibsp;
 using namespace opensaml::saml2md;
 using namespace opensaml;
 using namespace xmltooling;
+using namespace xercesc;
+using namespace boost;
 using namespace std;
 
 namespace shibsp {
@@ -80,9 +95,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;
         };
 
@@ -96,12 +111,11 @@ namespace shibsp {
     {
     public:
         GSSAPIExtractor(const DOMElement* e)
-                : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".AttributeExtractor.GSSAPI")), m_impl(nullptr) {
+                : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".AttributeExtractor.GSSAPI")) {
             background_load();
         }
         ~GSSAPIExtractor() {
             shutdown();
-            delete m_impl;
         }
 
         void extractAttributes(
@@ -120,7 +134,7 @@ namespace shibsp {
         pair<bool,DOMElement*> background_load();
 
     private:
-        GSSAPIExtractorImpl* m_impl;
+        scoped_ptr<GSSAPIExtractorImpl> m_impl;
     };
 
 #if defined (_MSC_VER)
@@ -135,6 +149,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);
@@ -190,28 +205,19 @@ GSSAPIExtractorImpl::GSSAPIExtractorImpl(const DOMElement* e, Category& log)
         name = child->getAttributeNS(nullptr, _aliases);
         if (name && *name) {
             auto_ptr_char aliases(name);
-            char* pos;
-            char* start = const_cast<char*>(aliases.get());
-            while (start && *start) {
-                while (*start && isspace(*start))
-                    start++;
-                if (!*start)
-                    break;
-                pos = strchr(start,' ');
-                if (pos)
-                    *pos=0;
-                if (strcmp(start, "REMOTE_USER")) {
-                    decl.ids.push_back(start);
-                    m_attributeIds.push_back(start);
-                }
-                else {
-                    m_log.warn("skipping alias, REMOTE_USER is a reserved name");
-                }
-                start = pos ? pos+1 : nullptr;
+            string dup(aliases.get());
+            set<string> new_aliases;
+            split(new_aliases, dup, is_space(), algorithm::token_compress_on);
+            set<string>::iterator ru = new_aliases.find("REMOTE_USER");
+            if (ru != new_aliases.end()) {
+                m_log.warn("skipping alias, REMOTE_USER is a reserved name");
+                new_aliases.erase(ru);
             }
+            m_attributeIds.insert(m_attributeIds.end(), new_aliases.begin(), new_aliases.end());
         }
 
         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];
@@ -263,8 +269,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 {
@@ -275,7 +282,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) {
@@ -291,14 +298,22 @@ void GSSAPIExtractorImpl::extractAttributes(
                 m_log.warn("ignoring unscoped value");
             }
         }
-        if (!scoped->getValues().empty())
-            attributes.push_back(scoped.release());
+        if (!scoped->getValues().empty()) {
+            attributes.push_back(scoped.get());
+            scoped.release();
+        }
+    }
+    else if (rule->second.binary) {
+        auto_ptr<BinaryAttribute> binary(new BinaryAttribute(rule->second.ids));
+        binary->getValues() = values;
+        attributes.push_back(binary.get());
+        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());
+        attributes.push_back(simple.get());
+        simple.release();
     }
 }
 
@@ -313,9 +328,7 @@ void GSSAPIExtractor::extractAttributes(
     static const XMLCh _GSSAPIName[] = UNICODE_LITERAL_10(G,S,S,A,P,I,N,a,m,e);
 
     if (!XMLString::equals(xmlObject.getElementQName().getLocalPart(), _GSSAPIContext)
-#ifndef SHIBSP_HAVE_GSSAPI_COMPOSITE_NAME
            && !XMLString::equals(xmlObject.getElementQName().getLocalPart(), _GSSAPIName)
-#endif
         ) {
         m_log.debug("unable to extract attributes, unknown XML object type: %s", xmlObject.getElementQName().toString().c_str());
         return;
@@ -339,9 +352,12 @@ void GSSAPIExtractor::extractAttributes(
         gss_buffer_desc importbuf;
         importbuf.length = x;
         importbuf.value = decoded;
-#ifdef SHIBSP_HAVE_GSSAPI_COMPOSITE_NAME
         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);
@@ -352,15 +368,12 @@ void GSSAPIExtractor::extractAttributes(
             // We fall through here down to the GSS context check, which will exit us.
         }
         else {
-#endif
             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_HAVE_GSSAPI_COMPOSITE_NAME
         }
-#endif
 #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
         XMLString::release(&decoded);
 #else
@@ -396,7 +409,7 @@ pair<bool,DOMElement*> GSSAPIExtractor::background_load()
     // If we own it, wrap it.
     XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : nullptr);
 
-    GSSAPIExtractorImpl* impl = new GSSAPIExtractorImpl(raw.second, m_log);
+    scoped_ptr<GSSAPIExtractorImpl> impl(new GSSAPIExtractorImpl(raw.second, m_log));
 
     // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
     impl->setDocument(docjanitor.release());
@@ -405,8 +418,7 @@ pair<bool,DOMElement*> GSSAPIExtractor::background_load()
     if (m_lock)
         m_lock->wrlock();
     SharedLock locker(m_lock, false);
-    delete m_impl;
-    m_impl = impl;
+    m_impl.swap(impl);
 
     return make_pair(false,(DOMElement*)nullptr);
 }