7e807b92f5acd4e9e46233cbac81423f16dd1a5b
[shibboleth/sp.git] / shibsp / attribute / NameIDFromScopedAttributeDecoder.cpp
1 /*
2  *  Copyright 2001-2007 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * NameIDFromNameIDFromScopedAttributeDecoder.cpp
19  *
20  * Decodes SAML "scoped" attributes into NameIDAttributes.
21  */
22
23 #include "internal.h"
24 #include "attribute/AttributeDecoder.h"
25 #include "attribute/NameIDAttribute.h"
26
27 #include <saml/saml1/core/Assertions.h>
28 #include <saml/saml2/core/Assertions.h>
29
30 using namespace shibsp;
31 using namespace opensaml::saml1;
32 using namespace opensaml::saml2;
33 using namespace xmltooling;
34 using namespace std;
35
36 namespace shibsp {
37     static XMLCh format[] =                 UNICODE_LITERAL_6(f,o,r,m,a,t);
38     static XMLCh formatter[] =              UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
39     static const XMLCh Scope[] =            UNICODE_LITERAL_5(S,c,o,p,e);
40     static const XMLCh scopeDelimeter[] =   UNICODE_LITERAL_14(s,c,o,p,e,D,e,l,i,m,e,t,e,r);
41
42     class SHIBSP_DLLLOCAL NameIDFromScopedAttributeDecoder : virtual public AttributeDecoder
43     {
44     public:
45         NameIDFromScopedAttributeDecoder(const DOMElement* e) : AttributeDecoder(e), m_delimeter('@'),
46                 m_format(e ? e->getAttributeNS(NULL,format) : NULL), m_formatter(e ? e->getAttributeNS(NULL,formatter) : NULL) {
47             if (e && e->hasAttributeNS(NULL,scopeDelimeter)) {
48                 auto_ptr_char d(e->getAttributeNS(NULL,scopeDelimeter));
49                 m_delimeter = *(d.get());
50             }
51         }
52         ~NameIDFromScopedAttributeDecoder() {}
53
54         shibsp::Attribute* decode(
55             const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL
56             ) const;
57
58     private:
59         char m_delimeter;
60         auto_ptr_char m_format;
61         auto_ptr_char m_formatter;
62     };
63
64     AttributeDecoder* SHIBSP_DLLLOCAL NameIDFromScopedAttributeDecoderFactory(const DOMElement* const & e)
65     {
66         return new NameIDFromScopedAttributeDecoder(e);
67     }
68 };
69
70 shibsp::Attribute* NameIDFromScopedAttributeDecoder::decode(
71     const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty
72     ) const
73 {
74
75     char* val;
76     char* scope;
77     const XMLCh* xmlscope;
78     QName scopeqname(NULL,Scope);
79     auto_ptr<NameIDAttribute> nameid(
80         new NameIDAttribute(ids, (m_formatter.get() && *m_formatter.get()) ? m_formatter.get() : DEFAULT_NAMEID_FORMATTER)
81         );
82     nameid->setCaseSensitive(m_caseSensitive);
83     vector<NameIDAttribute::Value>& dest = nameid->getValues();
84     vector<XMLObject*>::const_iterator v,stop;
85
86     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.NameIDFromScoped");
87
88     if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) {
89         const opensaml::saml2::Attribute* saml2attr = dynamic_cast<const opensaml::saml2::Attribute*>(xmlObject);
90         if (saml2attr) {
91             const vector<XMLObject*>& values = saml2attr->getAttributeValues();
92             v = values.begin();
93             stop = values.end();
94             if (log.isDebugEnabled()) {
95                 auto_ptr_char n(saml2attr->getName());
96                 log.debug(
97                     "decoding NameIDAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",
98                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
99                     );
100             }
101         }
102         else {
103             const opensaml::saml1::Attribute* saml1attr = dynamic_cast<const opensaml::saml1::Attribute*>(xmlObject);
104             if (saml1attr) {
105                 const vector<XMLObject*>& values = saml1attr->getAttributeValues();
106                 v = values.begin();
107                 stop = values.end();
108                 if (log.isDebugEnabled()) {
109                     auto_ptr_char n(saml1attr->getAttributeName());
110                     log.debug(
111                         "decoding NameIDAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",
112                         ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()
113                         );
114                 }
115             }
116             else {
117                 log.warn("XMLObject type not recognized by NameIDFromScopedAttributeDecoder, no values returned");
118                 return NULL;
119             }
120         }
121
122         for (; v!=stop; ++v) {
123             if (!(*v)->hasChildren()) {
124                 val = toUTF8((*v)->getTextContent());
125                 if (val && *val) {
126                     dest.push_back(NameIDAttribute::Value());
127                     NameIDAttribute::Value& destval = dest.back();
128                     const AttributeExtensibleXMLObject* aexo=dynamic_cast<const AttributeExtensibleXMLObject*>(*v);
129                     xmlscope = aexo ? aexo->getAttribute(scopeqname) : NULL;
130                     if (!xmlscope || !*xmlscope) {
131                         // Terminate the value at the scope delimiter.
132                         if (scope = strchr(val, m_delimeter))
133                             *scope++ = 0;
134                     }
135                     destval.m_Name = val;
136                     if (m_format.get() && *m_format.get())
137                         destval.m_Format = m_format.get();
138                     if (assertingParty)
139                         destval.m_NameQualifier = assertingParty;
140                     if (relyingParty)
141                         destval.m_SPNameQualifier = relyingParty;
142                 }
143                 else {
144                     log.warn("skipping empty AttributeValue");
145                 }
146                 delete[] val;
147             }
148             else {
149                 log.warn("skipping complex AttributeValue");
150             }
151         }
152
153         return dest.empty() ? NULL : nameid.release();
154     }
155
156     log.warn("XMLObject type not recognized by NameIDFromScopedAttributeDecoder, no values returned");
157     return NULL;
158 }