117c1a96a9df369eb168868b9ea6010ce327356f
[shibboleth/sp.git] / shibsp / attribute / resolver / impl / ChainingAttributeResolver.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  * ChainingAttributeResolver.cpp
19  * 
20  * Chains together multiple AttributeResolver plugins.
21  */
22
23 #include "internal.h"
24 #include "Application.h"
25 #include "ServiceProvider.h"
26 #include "attribute/Attribute.h"
27 #include "attribute/resolver/AttributeResolver.h"
28 #include "attribute/resolver/ResolutionContext.h"
29
30 #include <xercesc/util/XMLUniDefs.hpp>
31 #include <xmltooling/util/XMLHelper.h>
32
33 using namespace shibsp;
34 using namespace opensaml::saml2;
35 using namespace opensaml::saml2md;
36 using namespace xmltooling;
37 using namespace std;
38
39 namespace shibsp {
40
41     struct SHIBSP_DLLLOCAL ChainingContext : public ResolutionContext
42     {
43         ~ChainingContext() {
44             for_each(m_contexts.begin(), m_contexts.end(), xmltooling::cleanup<ResolutionContext>());
45             for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());
46             for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());
47         }
48
49         vector<shibsp::Attribute*>& getResolvedAttributes() {
50             return m_attributes;
51         }
52         vector<opensaml::Assertion*>& getResolvedAssertions() {
53             return m_assertions;
54         }
55
56         vector<ResolutionContext*> m_contexts;
57         vector<shibsp::Attribute*> m_attributes;
58         vector<opensaml::Assertion*> m_assertions;
59     };
60
61     class SHIBSP_DLLLOCAL ChainingAttributeResolver : public AttributeResolver
62     {
63     public:
64         ChainingAttributeResolver(const DOMElement* e);
65         virtual ~ChainingAttributeResolver() {
66             for_each(m_resolvers.begin(), m_resolvers.end(), xmltooling::cleanup<AttributeResolver>());
67         }
68         
69         Lockable* lock() {
70             for_each(m_resolvers.begin(), m_resolvers.end(), mem_fun(&AttributeResolver::lock));
71             return this;
72         }
73         void unlock() {
74             for_each(m_resolvers.begin(), m_resolvers.end(), mem_fun(&AttributeResolver::unlock));
75         }
76
77         ResolutionContext* createResolutionContext(
78             const Application& application,
79             const EntityDescriptor* issuer,
80             const XMLCh* protocol,
81             const NameID* nameid,
82             const XMLCh* authncontext_class=NULL,
83             const XMLCh* authncontext_decl=NULL,
84             const vector<const opensaml::Assertion*>* tokens=NULL,
85             const vector<shibsp::Attribute*>* attributes=NULL
86             ) const {
87             auto_ptr<ChainingContext> chain(new ChainingContext());
88             for (vector<AttributeResolver*>::const_iterator i=m_resolvers.begin(); i!=m_resolvers.end(); ++i)
89                 chain->m_contexts.push_back(
90                     (*i)->createResolutionContext(application, issuer, protocol, nameid, authncontext_class, authncontext_decl, tokens, attributes)
91                     );
92             return chain.release();
93         }
94
95         ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {
96             auto_ptr<ChainingContext> chain(new ChainingContext());
97             for (vector<AttributeResolver*>::const_iterator i=m_resolvers.begin(); i!=m_resolvers.end(); ++i)
98                 chain->m_contexts.push_back((*i)->createResolutionContext(application, session));
99             return chain.release();
100         }
101
102         void resolveAttributes(ResolutionContext& ctx) const;
103
104         void getAttributeIds(vector<string>& attributes) const {
105             for (vector<AttributeResolver*>::const_iterator i=m_resolvers.begin(); i!=m_resolvers.end(); ++i)
106                 (*i)->getAttributeIds(attributes);
107         }
108         
109     private:
110         vector<AttributeResolver*> m_resolvers;
111     };
112
113     static const XMLCh _AttributeResolver[] =   UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);
114     static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);
115
116     AttributeResolver* SHIBSP_DLLLOCAL ChainingAttributeResolverFactory(const DOMElement* & e)
117     {
118         return new ChainingAttributeResolver(e);
119     }
120 };
121
122 ChainingAttributeResolver::ChainingAttributeResolver(const DOMElement* e)
123 {
124     SPConfig& conf = SPConfig::getConfig();
125
126     // Load up the chain of handlers.
127     e = e ? XMLHelper::getFirstChildElement(e, _AttributeResolver) : NULL;
128     while (e) {
129         auto_ptr_char type(e->getAttributeNS(NULL,_type));
130         if (type.get() && *(type.get())) {
131             try {
132                 m_resolvers.push_back(conf.AttributeResolverManager.newPlugin(type.get(),e));
133             }
134             catch (exception& ex) {
135                 Category::getInstance(SHIBSP_LOGCAT".AttributeResolver").error(
136                     "caught exception processing embedded AttributeResolver element: %s", ex.what()
137                     );
138             }
139         }
140         e = XMLHelper::getNextSiblingElement(e, _AttributeResolver);
141     }
142 }
143
144 void ChainingAttributeResolver::resolveAttributes(ResolutionContext& ctx) const
145 {
146     ChainingContext& chain = dynamic_cast<ChainingContext&>(ctx);
147     vector<ResolutionContext*>::iterator ictx = chain.m_contexts.begin();
148     for (vector<AttributeResolver*>::const_iterator i=m_resolvers.begin(); i!=m_resolvers.end(); ++i, ++ictx) {
149         (*i)->resolveAttributes(*(*ictx));
150         chain.getResolvedAttributes().insert(chain.getResolvedAttributes().end(), (*ictx)->getResolvedAttributes().begin(), (*ictx)->getResolvedAttributes().end());
151         (*ictx)->getResolvedAttributes().clear();
152         chain.getResolvedAssertions().insert(chain.getResolvedAssertions().end(), (*ictx)->getResolvedAssertions().begin(), (*ictx)->getResolvedAssertions().end());
153         (*ictx)->getResolvedAssertions().clear();
154     }
155 }