Redesigned target around URL->application mapping
[shibboleth/sp.git] / shib / ScopedAttribute.cpp
index 68abf62..d9891f1 100644 (file)
@@ -65,90 +65,80 @@ using namespace saml;
 using namespace log4cpp;
 using namespace std;
 
+void ScopedAttribute::valueToDOM(unsigned int index, DOMElement* e) const
+{
+    SAMLAttribute::valueToDOM(index,e);
+    e->setAttributeNS(NULL,SHIB_L(Scope),m_scopes[index]);
+}
 
 ScopedAttribute::ScopedAttribute(const XMLCh* name, const XMLCh* ns, long lifetime,
                                  const saml::Iterator<const XMLCh*>& scopes,
                                  const saml::Iterator<const XMLCh*>& values)
-    : SimpleAttribute(name,ns,lifetime,values)
+    : SAMLAttribute(name,ns,NULL,lifetime,values)
 {
     if (scopes.size()!=values.size())
         throw MalformedException(SAMLException::RESPONDER,"ScopedAttribute() requires the number of scopes to equal the number of values");
 
     while (scopes.hasNext())
-        m_values.push_back(scopes.next());
+        m_scopes.push_back(XMLString::replicate(scopes.next()));
 }
 
-ScopedAttribute::ScopedAttribute(DOMElement* e) : SimpleAttribute(e) {}
-
-ScopedAttribute::~ScopedAttribute() {}
-
-bool ScopedAttribute::addValue(DOMElement* e)
+ScopedAttribute::ScopedAttribute(DOMElement* e) : SAMLAttribute(e)
 {
-    static XMLCh empty[] = {chNull};
-    if (SAMLAttribute::addValue(e))
+    // Default scope comes from subject.
+    DOMNodeList* nlist=
+        static_cast<DOMElement*>(e->getParentNode())->getElementsByTagNameNS(saml::XML::SAML_NS,L(NameIdentifier));
+    if (!nlist || nlist->getLength() != 1)
+        throw MalformedException(SAMLException::RESPONDER,"ScopedAttribute() can't find saml:NameIdentifier in enclosing statement");
+    m_originSite=static_cast<DOMElement*>(nlist->item(0))->getAttributeNS(NULL,L(NameQualifier));
+
+    e=saml::XML::getFirstChildElement(e,saml::XML::SAML_NS,L(AttributeValue));
+    while (e)
     {
-        DOMAttr* scope=e->getAttributeNodeNS(NULL,Scope);
-        m_scopes.push_back(scope ? scope->getNodeValue() : empty);
-        return true;
+        DOMAttr* scope=e->getAttributeNodeNS(NULL,SHIB_L(Scope));
+        m_scopes.push_back(scope ? scope->getNodeValue() : &chNull);
+        e=saml::XML::getNextSiblingElement(e,saml::XML::SAML_NS,L(AttributeValue));
     }
-    return false;
 }
 
-bool ScopedAttribute::accept(DOMElement* e) const
+ScopedAttribute::~ScopedAttribute()
 {
-    OriginSiteMapper mapper;
-    Iterator<pair<xstring,bool> > domains=mapper.getSecurityDomains(m_originSite.c_str());
-    const XMLCh* this_scope=NULL;
-    DOMAttr* scope=e->getAttributeNodeNS(NULL,Scope);
-    if (scope)
-        this_scope=scope->getNodeValue();
-    if (!this_scope || !*this_scope)
-        this_scope=m_originSite.c_str();
-
-    while (domains.hasNext())
+    if (m_bOwnStrings)
     {
-        const pair<xstring,bool>& p=domains.next();
-        if (p.second)
+        for (vector<const XMLCh*>::iterator i=m_scopes.begin(); i!=m_scopes.end(); i++)
         {
-            try
-            {
-                RegularExpression re(p.first.c_str());
-                if (re.matches(this_scope))
-                    return true;
-            }
-            catch (XMLException& ex)
-            {
-                auto_ptr<char> tmp(XMLString::transcode(ex.getMessage()));
-                NDC ndc("accept");
-                Category& log=Category::getInstance(SHIB_LOGCAT".ScopedAttribute");
-                log.errorStream() << "caught exception while parsing regular expression: " << tmp.get()
-                    << CategoryStream::ENDLINE;
-                return false;
-            }
+            XMLCh* p = const_cast<XMLCh*>(*i);
+            XMLString::release(&p);
         }
-        else if (p.first==this_scope)
-            return true;
     }
 
-    NDC ndc("accept");
-    Category& log=Category::getInstance(SHIB_LOGCAT".ScopedAttribute");
-    if (log.isWarnEnabled())
+    // We always own any scoped values we've built.
+    for (vector<const XMLCh*>::iterator i=m_scopedValues.begin(); i!=m_scopedValues.end(); i++)
     {
-        auto_ptr<char> tmp(XMLString::transcode(this_scope));
-        log.warn("rejecting value with scope of %s",tmp.get());
+        XMLCh* p = const_cast<XMLCh*>(*i);
+        XMLString::release(&p);
     }
-    return false;
 }
 
-Iterator<xstring> ScopedAttribute::getValues() const
+Iterator<const XMLCh*> ScopedAttribute::getValues() const
 {
+    static XMLCh at[]={chAt, chNull};
+
     if (m_scopedValues.empty())
     {
-        vector<xstring>::const_iterator j=m_scopes.begin();
-        for (vector<xstring>::const_iterator i=m_values.begin(); i!=m_values.end(); i++, j++)
-            m_scopedValues.push_back((*i) + chAt + (!j->empty() ? (*j) : m_originSite));
+        vector<const XMLCh*>::const_iterator j=m_scopes.begin();
+        for (vector<const XMLCh*>::const_iterator i=m_values.begin(); i!=m_values.end(); i++, j++)
+        {
+            const XMLCh* scope=((*j) ? (*j) : m_originSite);
+            XMLCh* temp=new XMLCh[XMLString::stringLen(*i) + XMLString::stringLen(scope) + 2];
+            temp[0]=chNull;
+            XMLString::catString(temp,*i);
+            XMLString::catString(temp,at);
+            XMLString::catString(temp,scope);
+            m_scopedValues.push_back(temp);
+        }
     }
-    return Iterator<xstring>(m_scopedValues);
+    return m_scopedValues;
 }
 
 Iterator<string> ScopedAttribute::getSingleByteValues() const
@@ -156,9 +146,9 @@ Iterator<string> ScopedAttribute::getSingleByteValues() const
     getValues();
     if (m_sbValues.empty())
     {
-        for (vector<xstring>::const_iterator i=m_scopedValues.begin(); i!=m_scopedValues.end(); i++)
+        for (vector<const XMLCh*>::const_iterator i=m_scopedValues.begin(); i!=m_scopedValues.end(); i++)
         {
-            auto_ptr<char> temp(XMLString::transcode(i->c_str()));
+            auto_ptr<char> temp(toUTF8(*i));
             if (temp.get())
                 m_sbValues.push_back(temp.get());
         }
@@ -166,32 +156,28 @@ Iterator<string> ScopedAttribute::getSingleByteValues() const
     return Iterator<string>(m_sbValues);
 }
 
-SAMLObject* ScopedAttribute::clone() const
+void ScopedAttribute::setValues(const Iterator<const XMLCh*>& values)
 {
-    ScopedAttribute* dest=new ScopedAttribute(m_name,m_namespace,m_lifetime);
-    dest->m_values.assign(m_values.begin(),m_values.end());
-    dest->m_scopes.assign(m_scopes.begin(),m_scopes.end());
-    return dest;
+    throw SAMLException("unsupported operation");
 }
 
-DOMNode* ScopedAttribute::toDOM(DOMDocument* doc,bool xmlns) const
+void ScopedAttribute::addValue(const XMLCh* value)
 {
-    SimpleAttribute::toDOM(doc,xmlns);
+    throw SAMLException("unsupported operation");
+}
 
-    int i=0;
-    DOMNode* n=m_root->getFirstChild();
-    while (n)
-    {
-        if (n->getNodeType()==DOMNode::ELEMENT_NODE)
-        {
-            static_cast<DOMElement*>(n)->setAttributeNS(NULL,Scope,
-                (!m_scopes[i].empty() ? m_scopes[i].c_str() : m_originSite.c_str()));
-            i++;
-        }
-        n=n->getNextSibling();
+void ScopedAttribute::removeValue(unsigned int index)
+{
+    SAMLAttribute::removeValue(index);
+    
+    if (m_bOwnStrings) {
+        XMLCh* p=const_cast<XMLCh*>(m_scopes[index]);
+        XMLString::release(&p);
     }
-
-    return m_root;
+    m_scopes.erase(m_scopes.begin()+index);
 }
 
-const XMLCh ScopedAttribute::Scope[] = { chLatin_S, chLatin_c, chLatin_o, chLatin_p, chLatin_e, chNull };
+SAMLObject* ScopedAttribute::clone() const
+{
+    return new ScopedAttribute(m_name,m_namespace,m_lifetime,m_scopes,m_values);
+}