Reducing header overuse, non-inlining selected methods (CPPOST-35).
[shibboleth/cpp-sp.git] / shibsp / attribute / KeyInfoAttributeDecoder.cpp
1 /*\r
2  *  Copyright 2009 Internet2\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /**\r
18  * KeyInfoAttributeDecoder.cpp\r
19  *\r
20  * Decodes KeyInfo information into a SimpleAttribute.\r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "attribute/AttributeDecoder.h"\r
25 #include "attribute/SimpleAttribute.h"\r
26 \r
27 #include <saml/saml1/core/Assertions.h>\r
28 #include <saml/saml2/core/Assertions.h>\r
29 #include <xmltooling/XMLToolingConfig.h>\r
30 #include <xmltooling/security/Credential.h>\r
31 #include <xmltooling/security/KeyInfoResolver.h>\r
32 #include <xmltooling/security/SecurityHelper.h>\r
33 #include <xmltooling/signature/KeyInfo.h>\r
34 \r
35 using namespace shibsp;\r
36 using namespace opensaml;\r
37 using namespace xmlsignature;\r
38 using namespace xmltooling;\r
39 using namespace std;\r
40 \r
41 namespace shibsp {\r
42     class SHIBSP_DLLLOCAL KeyInfoAttributeDecoder : virtual public AttributeDecoder\r
43     {\r
44     public:\r
45         KeyInfoAttributeDecoder(const DOMElement* e);\r
46         ~KeyInfoAttributeDecoder() {\r
47             delete m_keyInfoResolver;\r
48         }\r
49 \r
50         Attribute* decode(\r
51             const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
52             ) const;\r
53 \r
54     private:\r
55         void extract(const KeyInfo* k, vector<string>& dest) const {\r
56             auto_ptr<Credential> cred (getKeyInfoResolver()->resolve(k, Credential::RESOLVE_KEYS));\r
57             if (cred.get()) {\r
58                 dest.push_back(string());\r
59                 dest.back() = SecurityHelper::getDEREncoding(*cred.get(), m_hash);\r
60                 if (dest.back().empty())\r
61                     dest.pop_back();\r
62             }\r
63         }\r
64 \r
65         const KeyInfoResolver* getKeyInfoResolver() const {\r
66             return m_keyInfoResolver ? m_keyInfoResolver : XMLToolingConfig::getConfig().getKeyInfoResolver();\r
67         }\r
68 \r
69         bool m_hash;\r
70         KeyInfoResolver* m_keyInfoResolver;\r
71     };\r
72 \r
73     AttributeDecoder* SHIBSP_DLLLOCAL KeyInfoAttributeDecoderFactory(const DOMElement* const & e)\r
74     {\r
75         return new KeyInfoAttributeDecoder(e);\r
76     }\r
77 \r
78     static const XMLCh _KeyInfoResolver[] = UNICODE_LITERAL_15(K,e,y,I,n,f,o,R,e,s,o,l,v,e,r);\r
79     static const XMLCh _hash[] =            UNICODE_LITERAL_4(h,a,s,h);\r
80     static const XMLCh _type[] =            UNICODE_LITERAL_4(t,y,p,e);\r
81 };\r
82 \r
83 KeyInfoAttributeDecoder::KeyInfoAttributeDecoder(const DOMElement* e) : AttributeDecoder(e), m_hash(false), m_keyInfoResolver(NULL) {\r
84     const XMLCh* flag = e ? e->getAttributeNS(NULL, _hash) : NULL;\r
85     m_hash = (flag && (*flag == chLatin_t || *flag == chDigit_1));\r
86     e = e ? XMLHelper::getFirstChildElement(e,_KeyInfoResolver) : NULL;\r
87     if (e) {\r
88         auto_ptr_char t(e->getAttributeNS(NULL, _type));\r
89         if (t.get() && *t.get())\r
90             m_keyInfoResolver = XMLToolingConfig::getConfig().KeyInfoResolverManager.newPlugin(t.get(), e);\r
91         else\r
92             throw UnknownExtensionException("<KeyInfoResolver> element found with no type attribute");\r
93     }\r
94 }\r
95 \r
96 Attribute* KeyInfoAttributeDecoder::decode(\r
97     const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
98     ) const\r
99 {\r
100     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder.KeyInfo");\r
101 \r
102     if (!xmlObject || !XMLString::equals(saml1::Attribute::LOCAL_NAME, xmlObject->getElementQName().getLocalPart())) {\r
103         log.warn("XMLObject type not recognized by KeyInfoAttributeDecoder, no values returned");\r
104         return NULL;\r
105     }\r
106 \r
107     auto_ptr<SimpleAttribute> attr(new SimpleAttribute(ids));\r
108     vector<string>& dest = attr->getValues();\r
109     vector<XMLObject*>::const_iterator v,stop;\r
110 \r
111     const saml2::Attribute* saml2attr = dynamic_cast<const saml2::Attribute*>(xmlObject);\r
112     if (saml2attr) {\r
113         const vector<XMLObject*>& values = saml2attr->getAttributeValues();\r
114         v = values.begin();\r
115         stop = values.end();\r
116         if (log.isDebugEnabled()) {\r
117             auto_ptr_char n(saml2attr->getName());\r
118             log.debug(\r
119                 "decoding KeyInfo information (%s) from SAML 2 Attribute (%s) with %lu value(s)",\r
120                 ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
121                 );\r
122         }\r
123     }\r
124     else {\r
125         const saml1::Attribute* saml1attr = dynamic_cast<const saml1::Attribute*>(xmlObject);\r
126         if (saml1attr) {\r
127             const vector<XMLObject*>& values = saml1attr->getAttributeValues();\r
128             v = values.begin();\r
129             stop = values.end();\r
130             if (log.isDebugEnabled()) {\r
131                 auto_ptr_char n(saml1attr->getAttributeName());\r
132                 log.debug(\r
133                     "decoding KeyInfo information (%s) from SAML 1 Attribute (%s) with %lu value(s)",\r
134                     ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
135                     );\r
136             }\r
137         }\r
138         else {\r
139             log.warn("XMLObject type not recognized by KeyInfoAttributeDecoder, no values returned");\r
140             return NULL;\r
141         }\r
142     }\r
143 \r
144     for (; v!=stop; ++v) {\r
145         const KeyInfo* k = dynamic_cast<const KeyInfo*>(*v);\r
146         if (k)\r
147             extract(k, dest);\r
148         else if ((*v)->hasChildren()) {\r
149             const list<XMLObject*>& children = (*v)->getOrderedChildren();\r
150             for (list<XMLObject*>::const_iterator vv = children.begin(); vv!=children.end(); ++vv) {\r
151                 if (k=dynamic_cast<const KeyInfo*>(*vv))\r
152                     extract(k, dest);\r
153                 else\r
154                     log.warn("skipping AttributeValue without a recognizable KeyInfo");\r
155             }\r
156         }\r
157     }\r
158 \r
159     return dest.empty() ? NULL : _decode(attr.release());\r
160 }\r