2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
22 * CaseFoldingAttributeResolver.cpp
24 * Attribute Resolver plugins for upcasing and downcasing.
30 #include <shibsp/exceptions.h>
31 #include <shibsp/SessionCache.h>
32 #include <shibsp/attribute/SimpleAttribute.h>
33 #include <shibsp/attribute/resolver/AttributeResolver.h>
34 #include <shibsp/attribute/resolver/ResolutionContext.h>
35 #include <xmltooling/XMLToolingConfig.h>
36 #include <xmltooling/util/XMLHelper.h>
37 #include <xercesc/util/XMLUniDefs.hpp>
39 using namespace shibsp;
40 using namespace xmltooling;
41 using namespace xercesc;
46 class SHIBSP_DLLLOCAL FoldingContext : public ResolutionContext
49 FoldingContext(const vector<Attribute*>* attributes) : m_inputAttributes(attributes) {
53 for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
56 const vector<Attribute*>* getInputAttributes() const {
57 return m_inputAttributes;
59 vector<Attribute*>& getResolvedAttributes() {
62 vector<opensaml::Assertion*>& getResolvedAssertions() {
67 const vector<Attribute*>* m_inputAttributes;
68 vector<Attribute*> m_attributes;
69 static vector<opensaml::Assertion*> m_assertions; // empty dummy
73 class SHIBSP_DLLLOCAL CaseFoldingAttributeResolver : public AttributeResolver
81 CaseFoldingAttributeResolver(const DOMElement* e, case_t direction);
82 virtual ~CaseFoldingAttributeResolver() {}
90 ResolutionContext* createResolutionContext(
91 const Application& application,
92 const opensaml::saml2md::EntityDescriptor* issuer,
93 const XMLCh* protocol,
94 const opensaml::saml2::NameID* nameid=nullptr,
95 const XMLCh* authncontext_class=nullptr,
96 const XMLCh* authncontext_decl=nullptr,
97 const vector<const opensaml::Assertion*>* tokens=nullptr,
98 const vector<Attribute*>* attributes=nullptr
100 // Make sure new method gets run.
101 return createResolutionContext(application, nullptr, issuer, protocol, nameid, authncontext_class, authncontext_decl, tokens, attributes);
104 ResolutionContext* createResolutionContext(
105 const Application& application,
106 const GenericRequest* request,
107 const opensaml::saml2md::EntityDescriptor* issuer,
108 const XMLCh* protocol,
109 const opensaml::saml2::NameID* nameid=nullptr,
110 const XMLCh* authncontext_class=nullptr,
111 const XMLCh* authncontext_decl=nullptr,
112 const vector<const opensaml::Assertion*>* tokens=nullptr,
113 const vector<Attribute*>* attributes=nullptr
115 return new FoldingContext(attributes);
118 ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {
119 return new FoldingContext(&session.getAttributes());
122 void resolveAttributes(ResolutionContext& ctx) const;
124 void getAttributeIds(vector<string>& attributes) const {
125 if (!m_dest.empty() && !m_dest.front().empty())
126 attributes.push_back(m_dest.front());
133 vector<string> m_dest;
136 static const XMLCh dest[] = UNICODE_LITERAL_4(d,e,s,t);
137 static const XMLCh source[] = UNICODE_LITERAL_6(s,o,u,r,c,e);
139 AttributeResolver* SHIBSP_DLLLOCAL UpperCaseAttributeResolverFactory(const DOMElement* const & e)
141 return new CaseFoldingAttributeResolver(e, CaseFoldingAttributeResolver::_up);
144 AttributeResolver* SHIBSP_DLLLOCAL LowerCaseAttributeResolverFactory(const DOMElement* const & e)
146 return new CaseFoldingAttributeResolver(e, CaseFoldingAttributeResolver::_down);
150 vector<opensaml::Assertion*> FoldingContext::m_assertions;
152 CaseFoldingAttributeResolver::CaseFoldingAttributeResolver(const DOMElement* e, case_t direction)
153 : m_log(Category::getInstance(SHIBSP_LOGCAT".AttributeResolver.CaseFolding")),
154 m_direction(direction),
155 m_source(XMLHelper::getAttrString(e, nullptr, source)),
156 m_dest(1, XMLHelper::getAttrString(e, nullptr, dest))
158 if (m_source.empty())
159 throw ConfigurationException("CaseFolding AttributeResolver requires source attribute.");
163 void CaseFoldingAttributeResolver::resolveAttributes(ResolutionContext& ctx) const
165 FoldingContext& fctx = dynamic_cast<FoldingContext&>(ctx);
166 if (!fctx.getInputAttributes())
169 auto_ptr<SimpleAttribute> destwrapper;
171 for (vector<Attribute*>::const_iterator a = fctx.getInputAttributes()->begin(); a != fctx.getInputAttributes()->end(); ++a) {
172 if (m_source != (*a)->getId() || (*a)->valueCount() == 0) {
176 SimpleAttribute* dest = nullptr;
177 if (m_dest.empty() || m_dest.front().empty()) {
178 // Can we transform in-place?
179 dest = dynamic_cast<SimpleAttribute*>(*a);
181 m_log.warn("can't %scase non-simple attribute (%s) 'in place'", (m_direction==_up ? "up" : "down"), m_source.c_str());
184 m_log.debug("applying in-place transform to source attribute (%s)", m_source.c_str());
186 else if (!destwrapper.get()) {
187 // Create a destination attribute.
188 destwrapper.reset(new SimpleAttribute(m_dest));
189 m_log.debug("applying transform from source attribute (%s) to dest attribute (%s)", m_source.c_str(), m_dest.front().c_str());
192 for (size_t i = 0; i < (*a)->valueCount(); ++i) {
194 XMLCh* srcval = fromUTF8((*a)->getSerializedValues()[i].c_str());
196 auto_arrayptr<XMLCh> valjanitor(srcval);
197 (m_direction == _up) ? XMLString::upperCase(srcval) : XMLString::lowerCase(srcval);
198 auto_arrayptr<char> narrow(toUTF8(srcval));
201 dest->getValues()[i] = narrow.get();
204 // Add to new object.
205 destwrapper->getValues().push_back(narrow.get());
209 catch (XMLException& ex) {
210 auto_ptr_char msg(ex.getMessage());
211 m_log.error("caught error performing conversion: %s", msg.get());
216 // Save off new object.
217 if (destwrapper.get()) {
218 ctx.getResolvedAttributes().push_back(destwrapper.get());
219 destwrapper.release();