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 * AttributeCheckerHandler.cpp
24 * Handler for checking a session for required attributes.
28 #include "AccessControl.h"
29 #include "Application.h"
30 #include "exceptions.h"
31 #include "ServiceProvider.h"
32 #include "SessionCache.h"
33 #include "SPRequest.h"
34 #include "attribute/Attribute.h"
35 #include "handler/AbstractHandler.h"
36 #include "util/TemplateParameters.h"
40 #include <boost/bind.hpp>
41 #include <boost/scoped_ptr.hpp>
42 #include <boost/algorithm/string.hpp>
43 #include <xercesc/util/XMLUniDefs.hpp>
44 #include <xmltooling/XMLToolingConfig.h>
45 #include <xmltooling/util/PathResolver.h>
46 #include <xmltooling/util/XMLHelper.h>
48 using namespace shibsp;
49 using namespace xmltooling;
50 using namespace boost;
55 #if defined (_MSC_VER)
56 #pragma warning( push )
57 #pragma warning( disable : 4250 )
60 class SHIBSP_DLLLOCAL Blocker : public DOMNodeFilter
63 #ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
68 acceptNode(const DOMNode* node) const {
73 static SHIBSP_DLLLOCAL Blocker g_Blocker;
75 class SHIBSP_API AttributeCheckerHandler : public AbstractHandler
78 AttributeCheckerHandler(const DOMElement* e, const char* appId);
79 virtual ~AttributeCheckerHandler() {}
81 pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
84 void flushSession(SPRequest& request) const {
86 request.getApplication().getServiceProvider().getSessionCache()->remove(request.getApplication(), request, &request);
88 catch (std::exception&) {
94 vector<string> m_attributes;
95 scoped_ptr<AccessControl> m_acl;
98 #if defined (_MSC_VER)
99 #pragma warning( pop )
102 Handler* SHIBSP_DLLLOCAL AttributeCheckerFactory(const pair<const DOMElement*,const char*>& p)
104 return new AttributeCheckerHandler(p.first, p.second);
107 static const XMLCh attributes[] = UNICODE_LITERAL_10(a,t,t,r,i,b,u,t,e,s);
108 static const XMLCh _flushSession[] = UNICODE_LITERAL_12(f,l,u,s,h,S,e,s,s,i,o,n);
109 static const XMLCh _template[] = UNICODE_LITERAL_8(t,e,m,p,l,a,t,e);
112 AttributeCheckerHandler::AttributeCheckerHandler(const DOMElement* e, const char* appId)
113 : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".AttributeCheckerHandler"), &g_Blocker)
115 if (!SPConfig::getConfig().isEnabled(SPConfig::InProcess))
117 m_template = XMLHelper::getAttrString(e, nullptr, _template);
118 if (m_template.empty())
119 throw ConfigurationException("AttributeChecker missing required template setting.");
120 XMLToolingConfig::getConfig().getPathResolver()->resolve(m_template, PathResolver::XMLTOOLING_CFG_FILE);
122 m_flushSession = XMLHelper::getAttrBool(e, false, _flushSession);
124 string attrs(XMLHelper::getAttrString(e, nullptr, attributes));
125 if (!attrs.empty()) {
126 split(m_attributes, attrs, is_space(), algorithm::token_compress_on);
127 if (m_attributes.empty())
128 throw ConfigurationException("AttributeChecker unable to parse attributes setting.");
131 m_acl.reset(SPConfig::getConfig().AccessControlManager.newPlugin(XML_ACCESS_CONTROL, e));
135 pair<bool,long> AttributeCheckerHandler::run(SPRequest& request, bool isHandler) const
137 // If the checking passes, we route to the return URL, target URL, or homeURL in that order.
138 const char* returnURL = request.getParameter("return");
139 const char* target = request.getParameter("target");
143 request.getApplication().limitRedirect(request, returnURL);
145 returnURL = request.getApplication().getString("homeURL").second;
149 Session* session = nullptr;
151 session = request.getSession(true, false, false);
153 request.log(SPRequest::SPWarn, "AttributeChecker found session unavailable immediately after creation");
155 catch (std::exception& ex) {
156 request.log(SPRequest::SPWarn, string("AttributeChecker caught exception accessing session immediately after creation: ") + ex.what());
159 Locker sessionLocker(session, false);
161 bool checked = false;
163 if (!m_attributes.empty()) {
164 typedef multimap<string,const Attribute*> indexed_t;
165 static indexed_t::const_iterator (indexed_t::* fn)(const string&) const = &indexed_t::find;
166 const indexed_t& indexed = session->getIndexedAttributes();
167 // Look for an attribute in the list that is not in the session multimap.
168 // If that fails, the check succeeds.
170 find_if(m_attributes.begin(), m_attributes.end(),
171 boost::bind(fn, boost::cref(indexed), _1) == indexed.end()) == m_attributes.end()
175 checked = (m_acl && m_acl->authorized(request, session) == AccessControl::shib_acl_true);
180 string loc(returnURL);
181 request.absolutize(loc);
182 return make_pair(true, request.sendRedirect(loc.c_str()));
185 request.setContentType("text/html; charset=UTF-8");
186 request.setResponseHeader("Expires","Wed, 01 Jan 1997 12:00:00 GMT");
187 request.setResponseHeader("Cache-Control","private,no-store,no-cache,max-age=0");
189 ifstream infile(m_template.c_str());
191 TemplateParameters tp(nullptr, request.getApplication().getPropertySet("Errors"), session);
192 tp.m_request = &request;
194 XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp);
195 if (m_flushSession) {
196 sessionLocker.assign(); // unlock the session
197 flushSession(request);
199 return make_pair(true, request.sendError(str));
202 if (m_flushSession) {
203 sessionLocker.assign(); // unlock the session
204 flushSession(request);
206 m_log.error("could not process error template (%s)", m_template.c_str());
207 istringstream msg("Internal Server Error. Please contact the site administrator.");
208 return make_pair(true, request.sendResponse(msg));