Remove extra lf from decryption logging.
[shibboleth/sp.git] / shibsp / attribute / resolver / impl / XMLAttributeExtractor.cpp
index e0942e2..f5f1cf2 100644 (file)
@@ -78,6 +78,9 @@ namespace shibsp {
         void extractAttributes(
             const Application& application, const char* assertingParty, const saml2::Attribute& attr, vector<Attribute*>& attributes
             ) const;
+        void extractAttributes(
+            const Application& application, const char* assertingParty, const Extensions& ext, vector<Attribute*>& attributes
+            ) const;
 
         void getAttributeIds(vector<string>& attributes) const {
             attributes.insert(attributes.end(), m_attributeIds.begin(), m_attributeIds.end());
@@ -87,9 +90,9 @@ namespace shibsp {
         Category& m_log;
         DOMDocument* m_document;
 #ifdef HAVE_GOOD_STL
-        typedef map< pair<xstring,xstring>,pair<AttributeDecoder*,string> > attrmap_t;
+        typedef map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > > attrmap_t;
 #else
-        typedef map< pair<string,string>,pair<AttributeDecoder*,string> > attrmap_t;
+        typedef map< pair<string,string>,pair< AttributeDecoder*,vector<string> > > attrmap_t;
 #endif
         attrmap_t m_attrMap;
         vector<string> m_attributeIds;
@@ -133,15 +136,11 @@ namespace shibsp {
     static const XMLCh _AttributeDecoder[] =    UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
     static const XMLCh Attributes[] =           UNICODE_LITERAL_10(A,t,t,r,i,b,u,t,e,s);
     static const XMLCh _id[] =                  UNICODE_LITERAL_2(i,d);
+    static const XMLCh _aliases[] =             UNICODE_LITERAL_7(a,l,i,a,s,e,s);
     static const XMLCh _name[] =                UNICODE_LITERAL_4(n,a,m,e);
     static const XMLCh nameFormat[] =           UNICODE_LITERAL_10(n,a,m,e,F,o,r,m,a,t);
 };
 
-void SHIBSP_API shibsp::registerAttributeExtractors()
-{
-    SPConfig::getConfig().AttributeExtractorManager.registerFactory(XML_ATTRIBUTE_EXTRACTOR, XMLAttributeExtractorFactory);
-}
-
 XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) : m_log(log), m_document(NULL)
 {
 #ifdef _DEBUG
@@ -201,11 +200,11 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) : m_log(l
 
         // Fetch/create the map entry and see if it's a duplicate rule.
 #ifdef HAVE_GOOD_STL
-        pair<AttributeDecoder*,string>& decl = m_attrMap[make_pair(name,format)];
+        pair< AttributeDecoder*,vector<string> >& decl = m_attrMap[pair<xstring,xstring>(name,format)];
 #else
         auto_ptr_char n(name);
         auto_ptr_char f(format);
-        pair<AttributeDecoder*,string>& decl = m_attrMap[make_pair(n.get(),f.get())];
+        pair< AttributeDecoder*,vector<string> >& decl = m_attrMap[pair<string,string>(n.get(),f.get())];
 #endif
         if (decl.first) {
             m_log.warn("skipping duplicate Attribute mapping (same name and nameFormat)");
@@ -223,8 +222,32 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) : m_log(l
         }
         
         decl.first = decoder;
-        decl.second = id.get();
+        decl.second.push_back(id.get());
         m_attributeIds.push_back(id.get());
+
+        name = child->getAttributeNS(NULL, _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.second.push_back(start);
+                    m_attributeIds.push_back(start);
+                }
+                else {
+                    m_log.warn("skipping alias, REMOTE_USER is a reserved name");
+                }
+                start = pos ? pos+1 : NULL;
+            }
+        }
         
         child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);
     }
@@ -235,24 +258,30 @@ void XMLExtractorImpl::extractAttributes(
     ) const
 {
 #ifdef HAVE_GOOD_STL
-    map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #else
-    map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #endif
 
     const XMLCh* format = nameid.getFormat();
     if (!format || !*format)
         format = NameIdentifier::UNSPECIFIED;
 #ifdef HAVE_GOOD_STL
-    if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<xstring,xstring>(format,xstring()))) != m_attrMap.end()) {
 #else
     auto_ptr_char temp(format);
-    if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<string,string>(temp.get(),string()))) != m_attrMap.end()) {
 #endif
-        Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second);
+        Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, application.getString("entityID").second);
         if (a)
             attributes.push_back(a);
     }
+    else if (m_log.isDebugEnabled()) {
+#ifdef HAVE_GOOD_STL
+        auto_ptr_char temp(format);
+#endif
+        m_log.debug("skipping unmapped NameIdentifier with format (%s)", temp.get());
+    }
 }
 
 void XMLExtractorImpl::extractAttributes(
@@ -260,24 +289,30 @@ void XMLExtractorImpl::extractAttributes(
     ) const
 {
 #ifdef HAVE_GOOD_STL
-    map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #else
-    map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #endif
 
     const XMLCh* format = nameid.getFormat();
     if (!format || !*format)
         format = NameID::UNSPECIFIED;
 #ifdef HAVE_GOOD_STL
-    if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<xstring,xstring>(format,xstring()))) != m_attrMap.end()) {
 #else
     auto_ptr_char temp(format);
-    if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<string,string>(temp.get(),string()))) != m_attrMap.end()) {
 #endif
-        Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second);
+        Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, application.getString("entityID").second);
         if (a)
             attributes.push_back(a);
     }
+    else if (m_log.isDebugEnabled()) {
+#ifdef HAVE_GOOD_STL
+        auto_ptr_char temp(format);
+#endif
+        m_log.debug("skipping unmapped NameID with format (%s)", temp.get());
+    }
 }
 
 void XMLExtractorImpl::extractAttributes(
@@ -285,9 +320,9 @@ void XMLExtractorImpl::extractAttributes(
     ) const
 {
 #ifdef HAVE_GOOD_STL
-    map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #else
-    map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #endif
 
     const XMLCh* name = attr.getAttributeName();
@@ -297,16 +332,23 @@ void XMLExtractorImpl::extractAttributes(
     if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI))
         format = &chNull;
 #ifdef HAVE_GOOD_STL
-    if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<xstring,xstring>(name,format))) != m_attrMap.end()) {
 #else
     auto_ptr_char temp1(name);
     auto_ptr_char temp2(format);
-    if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<string,string>(temp1.get(),temp2.get()))) != m_attrMap.end()) {
 #endif
-        Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second);
+        Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, application.getString("entityID").second);
         if (a)
             attributes.push_back(a);
     }
+    else if (m_log.isInfoEnabled()) {
+#ifdef HAVE_GOOD_STL
+        auto_ptr_char temp1(name);
+        auto_ptr_char temp2(format);
+#endif
+        m_log.info("skipping unmapped SAML 1.x Attribute with Name: %s%s%s", temp1.get(), *temp2.get() ? ", Namespace:" : "", temp2.get());
+    }
 }
 
 void XMLExtractorImpl::extractAttributes(
@@ -314,9 +356,9 @@ void XMLExtractorImpl::extractAttributes(
     ) const
 {
 #ifdef HAVE_GOOD_STL
-    map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #else
-    map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+    map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
 #endif
 
     const XMLCh* name = attr.getName();
@@ -328,16 +370,35 @@ void XMLExtractorImpl::extractAttributes(
     else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE))
         format = &chNull;
 #ifdef HAVE_GOOD_STL
-    if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<xstring,xstring>(name,format))) != m_attrMap.end()) {
 #else
     auto_ptr_char temp1(name);
     auto_ptr_char temp2(format);
-    if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {
+    if ((rule=m_attrMap.find(pair<string,string>(temp1.get(),temp2.get()))) != m_attrMap.end()) {
 #endif
-        Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second);
+        Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, application.getString("entityID").second);
         if (a)
             attributes.push_back(a);
     }
+    else if (m_log.isInfoEnabled()) {
+#ifdef HAVE_GOOD_STL
+        auto_ptr_char temp1(name);
+        auto_ptr_char temp2(format);
+#endif
+        m_log.info("skipping unmapped SAML 2.0 Attribute with Name: %s%s%s", temp1.get(), *temp2.get() ? ", Format:" : "", temp2.get());
+    }
+}
+
+void XMLExtractorImpl::extractAttributes(
+    const Application& application, const char* assertingParty, const Extensions& ext, vector<Attribute*>& attributes
+    ) const
+{
+    const vector<XMLObject*> exts = ext.getUnknownXMLObjects();
+    for (vector<XMLObject*>::const_iterator i = exts.begin(); i!=exts.end(); ++i) {
+        const saml2::Attribute* attr = dynamic_cast<const saml2::Attribute*>(*i);
+        if (attr)
+            extractAttributes(application, assertingParty, *attr, attributes);
+    }
 }
 
 void XMLExtractor::extractAttributes(
@@ -380,6 +441,25 @@ void XMLExtractor::extractAttributes(
         throw AttributeExtractionException("Unable to extract attributes, unknown object type.");
     }
 
+    // Check for metadata.
+    if (XMLString::equals(xmlObject.getElementQName().getNamespaceURI(), samlconstants::SAML20MD_NS)) {
+        const EntityDescriptor* entity = dynamic_cast<const EntityDescriptor*>(&xmlObject);
+        if (!entity)
+            throw AttributeExtractionException("Unable to extract attributes, unknown metadata object type.");
+        auto_ptr_char assertingParty(issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID() : NULL);
+        const Extensions* ext = entity->getExtensions();
+        if (ext)
+            m_impl->extractAttributes(application, assertingParty.get(), *ext, attributes);
+        const EntitiesDescriptor* group = dynamic_cast<const EntitiesDescriptor*>(entity->getParent());
+        while (group) {
+            ext = group->getExtensions();
+            if (ext)
+                m_impl->extractAttributes(application, assertingParty.get(), *ext, attributes);
+            group = dynamic_cast<const EntitiesDescriptor*>(group->getParent());
+        }
+        return;
+    }
+
     // Check for attributes.
     if (XMLString::equals(xmlObject.getElementQName().getLocalPart(), saml1::Attribute::LOCAL_NAME)) {
         auto_ptr_char assertingParty(issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID() : NULL);
@@ -410,10 +490,14 @@ void XMLExtractor::extractAttributes(
                 if (issuer) {
                     MetadataCredentialCriteria mcc(*issuer);
                     auto_ptr<XMLObject> decrypted(encattr->decrypt(*cr, recipient, &mcc));
+                    if (m_log.isDebugEnabled())
+                        m_log.debugStream() << "decrypted Attribute: " << *(decrypted.get()) << logging::eol;
                     return extractAttributes(application, issuer, *(decrypted.get()), attributes);
                 }
                 else {
                     auto_ptr<XMLObject> decrypted(encattr->decrypt(*cr, recipient));
+                    if (m_log.isDebugEnabled())
+                        m_log.debugStream() << "decrypted Attribute: " << *(decrypted.get()) << logging::eol;
                     return extractAttributes(application, issuer, *(decrypted.get()), attributes);
                 }
             }