-/*
- * Copyright 2001-2007 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the
+ * License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
*/
/**
* AbstractSPRequest.cpp
- *
- * Abstract base for SPRequest implementations
+ *
+ * Abstract base for SPRequest implementations.
*/
#include "internal.h"
+#include "exceptions.h"
#include "AbstractSPRequest.h"
#include "Application.h"
+#include "GSSRequest.h"
#include "ServiceProvider.h"
#include "SessionCache.h"
+#include "util/CGIParser.h"
-#include <log4cpp/Category.hh>
+#include <boost/lexical_cast.hpp>
using namespace shibsp;
using namespace opensaml;
using namespace xmltooling;
-using namespace log4cpp;
using namespace std;
-AbstractSPRequest::AbstractSPRequest()
- : m_sp(NULL), m_mapper(NULL), m_app(NULL), m_sessionTried(false), m_session(NULL),
- m_log(&Category::getInstance(SHIBSP_LOGCAT".SPRequest")), m_parser(NULL)
+SPRequest::SPRequest()
+{
+}
+
+SPRequest::~SPRequest()
+{
+}
+
+string SPRequest::getSecureHeader(const char* name) const
+{
+ return getHeader(name);
+}
+
+void SPRequest::setAuthType(const char* authtype)
+{
+}
+
+#ifdef SHIBSP_HAVE_GSSAPI
+GSSRequest::GSSRequest()
+{
+}
+
+GSSRequest::~GSSRequest()
+{
+}
+
+gss_name_t GSSRequest::getGSSName() const
+{
+ return GSS_C_NO_NAME;
+}
+#endif
+
+AbstractSPRequest::AbstractSPRequest(const char* category)
+ : m_sp(SPConfig::getConfig().getServiceProvider()),
+ m_mapper(nullptr), m_app(nullptr), m_sessionTried(false), m_session(nullptr),
+ m_log(&Category::getInstance(category))
{
- m_sp=SPConfig::getConfig().getServiceProvider();
m_sp->lock();
}
m_mapper->unlock();
if (m_sp)
m_sp->unlock();
- delete m_parser;
}
-RequestMapper::Settings AbstractSPRequest::getRequestSettings() const
+const ServiceProvider& AbstractSPRequest::getServiceProvider() const
{
- if (m_mapper)
- return m_settings;
+ return *m_sp;
+}
- // Map request to application and content settings.
- m_mapper=m_sp->getRequestMapper();
- m_mapper->lock();
- return m_settings = m_mapper->getSettings(*this);
+RequestMapper::Settings AbstractSPRequest::getRequestSettings() const
+{
+ if (!m_mapper) {
+ // Map request to application and content settings.
+ m_mapper = m_sp->getRequestMapper();
+ m_mapper->lock();
+ m_settings = m_mapper->getSettings(*this);
+ if (reinterpret_cast<Category*>(m_log)->isDebugEnabled()) {
+ reinterpret_cast<Category*>(m_log)->debug(
+ "mapped %s to %s", getRequestURL(), m_settings.first->getString("applicationId").second
+ );
+ }
+ }
+ return m_settings;
}
const Application& AbstractSPRequest::getApplication() const
{
if (!m_app) {
// Now find the application from the URL settings
- m_app=m_sp->getApplication(getRequestSettings().first->getString("applicationId").second);
+ m_app = m_sp->getApplication(getRequestSettings().first->getString("applicationId").second);
if (!m_app)
- throw ConfigurationException("Unable to map request to application settings, check configuration.");
- }
+ throw ConfigurationException("Unable to map non-default applicationId to an ApplicationOverride, check configuration.");
+ }
return *m_app;
}
-Session* AbstractSPRequest::getSession(bool checkTimeout) const
+Session* AbstractSPRequest::getSession(bool checkTimeout, bool ignoreAddress, bool cache)
{
// Only attempt this once.
- if (m_sessionTried)
+ if (cache && m_sessionTried)
return m_session;
- m_sessionTried = true;
-
- // Get session ID from cookie.
- const Application& app = getApplication();
- pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
- const char* session_id = getCookie(shib_cookie.first.c_str());
- if (!session_id || !*session_id)
- return NULL;
+ else if (cache)
+ m_sessionTried = true;
// Need address checking and timeout settings.
- time_t timeout=0;
- bool consistent=true;
- const PropertySet* props=app.getPropertySet("Sessions");
- if (props) {
- if (checkTimeout) {
- pair<bool,unsigned int> p=props->getUnsignedInt("timeout");
- if (p.first)
- timeout = p.second;
+ time_t timeout = 3600;
+ if (checkTimeout || !ignoreAddress) {
+ const PropertySet* props = getApplication().getPropertySet("Sessions");
+ if (props) {
+ if (checkTimeout) {
+ pair<bool,unsigned int> p = props->getUnsignedInt("timeout");
+ if (p.first)
+ timeout = p.second;
+ }
+ pair<bool,bool> pcheck = props->getBool("consistentAddress");
+ if (pcheck.first)
+ ignoreAddress = !pcheck.second;
}
- pair<bool,bool> pcheck=props->getBool("consistentAddress");
- if (pcheck.first)
- consistent = pcheck.second;
}
- // The cache will either silently pass a session or NULL back, or throw an exception out.
- return m_session = getServiceProvider().getSessionCache()->find(
- session_id, app, consistent ? getRemoteAddr().c_str() : NULL, checkTimeout ? &timeout : NULL
+ // The cache will either silently pass a session or nullptr back, or throw an exception out.
+ Session* session = getServiceProvider().getSessionCache()->find(
+ getApplication(), *this, (ignoreAddress ? nullptr : getRemoteAddr().c_str()), (checkTimeout ? &timeout : nullptr)
);
+ if (cache)
+ m_session = session;
+ return session;
}
-const char* AbstractSPRequest::getRequestURL() const {
+static char _x2c(const char *what)
+{
+ register char digit;
+
+ digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
+ digit *= 16;
+ digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
+ return(digit);
+}
+
+void AbstractSPRequest::setRequestURI(const char* uri)
+{
+ // Fix for bug 574, secadv 20061002
+ // Unescape URI up to query string delimiter by looking for %XX escapes.
+ // Adapted from Apache's util.c, ap_unescape_url function.
+ if (uri) {
+ while (*uri) {
+ if (*uri == '?') {
+ m_uri += uri;
+ break;
+ }
+ else if (*uri != '%') {
+ m_uri += *uri;
+ }
+ else {
+ ++uri;
+ if (!isxdigit(*uri) || !isxdigit(*(uri+1)))
+ throw ConfigurationException("Bad request, contained unsupported encoded characters.");
+ m_uri += _x2c(uri);
+ ++uri;
+ }
+ ++uri;
+ }
+ }
+}
+
+const char* AbstractSPRequest::getRequestURI() const
+{
+ return m_uri.c_str();
+}
+
+const char* AbstractSPRequest::getRequestURL() const
+{
if (m_url.empty()) {
// Compute the full target URL
int port = getPort();
const char* scheme = getScheme();
m_url = string(scheme) + "://" + getHostname();
- if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {
- ostringstream portstr;
- portstr << port;
- m_url += ":" + portstr.str();
- }
- scheme = getRequestURI();
- if (scheme)
- m_url += scheme;
+ if (!isDefaultPort())
+ m_url += ":" + boost::lexical_cast<string>(port);
+ m_url += m_uri;
}
return m_url.c_str();
}
+string AbstractSPRequest::getRemoteAddr() const
+{
+ pair<bool,const char*> addr = getRequestSettings().first->getString("REMOTE_ADDR");
+ return addr.first ? getHeader(addr.second) : "";
+}
+
const char* AbstractSPRequest::getParameter(const char* name) const
{
- if (!m_parser)
- m_parser=new CGIParser(*this);
-
- pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
- return (bounds.first==bounds.second) ? NULL : bounds.first->second;
+ if (!m_parser.get())
+ m_parser.reset(new CGIParser(*this));
+
+ pair<CGIParser::walker,CGIParser::walker> bounds = m_parser->getParameters(name);
+ return (bounds.first==bounds.second) ? nullptr : bounds.first->second;
}
vector<const char*>::size_type AbstractSPRequest::getParameters(const char* name, vector<const char*>& values) const
{
- if (!m_parser)
- m_parser=new CGIParser(*this);
+ if (!m_parser.get())
+ m_parser.reset(new CGIParser(*this));
- pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
- while (bounds.first!=bounds.second) {
+ pair<CGIParser::walker,CGIParser::walker> bounds = m_parser->getParameters(name);
+ while (bounds.first != bounds.second) {
values.push_back(bounds.first->second);
++bounds.first;
}
return values.size();
}
-const char* AbstractSPRequest::getCookie(const char* name) const
-{
- if (m_cookieMap.empty()) {
- string cookies=getHeader("Cookie");
-
- string::size_type pos=0,cname,namelen,val,vallen;
- while (pos !=string::npos && pos < cookies.length()) {
- while (isspace(cookies[pos])) pos++;
- cname=pos;
- pos=cookies.find_first_of("=",pos);
- if (pos == string::npos)
- break;
- namelen=pos-cname;
- pos++;
- if (pos==cookies.length())
- break;
- val=pos;
- pos=cookies.find_first_of(";",pos);
- if (pos != string::npos) {
- vallen=pos-val;
- pos++;
- m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val,vallen)));
- }
- else
- m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val)));
- }
- }
- map<string,string>::const_iterator lookup=m_cookieMap.find(name);
- return (lookup==m_cookieMap.end()) ? NULL : lookup->second.c_str();
-}
-
const char* AbstractSPRequest::getHandlerURL(const char* resource) const
{
- if (!m_handlerURL.empty() && resource && !strcmp(getRequestURL(),resource))
+ if (!resource)
+ resource = getRequestURL();
+
+ if (!m_handlerURL.empty() && resource && !strcmp(getRequestURL(), resource))
return m_handlerURL.c_str();
-
+
+ // Check for relative URL.
+ string stackresource;
+ if (resource && *resource == '/') {
+ // Compute a URL to the root of the site and point resource at constructed string.
+ int port = getPort();
+ const char* scheme = getScheme();
+ stackresource = string(scheme) + "://" + getHostname();
+ if (!isDefaultPort())
+ stackresource += ":" + boost::lexical_cast<string>(port);
+ stackresource += resource;
+ resource = stackresource.c_str();
+ }
+
#ifdef HAVE_STRCASECMP
if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))
#else
#endif
throw ConfigurationException("Target resource was not an absolute URL.");
- bool ssl_only=false;
- const char* handler=NULL;
- const PropertySet* props=m_app->getPropertySet("Sessions");
+ bool ssl_only = true;
+ const char* handler = nullptr;
+ const PropertySet* props = getApplication().getPropertySet("Sessions");
if (props) {
- pair<bool,bool> p=props->getBool("handlerSSL");
+ pair<bool,bool> p = props->getBool("handlerSSL");
if (p.first)
- ssl_only=p.second;
- pair<bool,const char*> p2=props->getString("handlerURL");
+ ssl_only = p.second;
+ pair<bool,const char*> p2 = props->getString("handlerURL");
if (p2.first)
- handler=p2.second;
+ handler = p2.second;
+ }
+
+ if (!handler) {
+ handler = "/Shibboleth.sso";
}
-
- // Should never happen...
- if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
+ else if (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)) {
throw ConfigurationException(
- "Invalid handlerURL property ($1) in Application ($2)",
+ "Invalid handlerURL property ($1) in <Sessions> element for Application ($2)",
params(2, handler ? handler : "null", m_app->getId())
);
+ }
// The "handlerURL" property can be in one of three formats:
//
//
// note: if ssl_only is true, make sure the protocol is https
- const char* path = NULL;
+ const char* path = nullptr;
// Decide whether to use the handler or the resource for the "protocol"
const char* prot;
}
// break apart the "protocol" string into protocol, host, and "the rest"
- const char* colon=strchr(prot,':');
+ const char* colon = strchr(prot, ':');
colon += 3;
- const char* slash=strchr(colon,'/');
+ const char* slash = strchr(colon, '/');
if (!path)
path = slash;
void AbstractSPRequest::log(SPLogLevel level, const std::string& msg) const
{
reinterpret_cast<Category*>(m_log)->log(
- (level == SPDebug ? log4cpp::Priority::DEBUG :
- (level == SPInfo ? log4cpp::Priority::INFO :
- (level == SPWarn ? log4cpp::Priority::WARN :
- (level == SPError ? log4cpp::Priority::ERROR : log4cpp::Priority::CRIT)))),
+ (level == SPDebug ? Priority::DEBUG :
+ (level == SPInfo ? Priority::INFO :
+ (level == SPWarn ? Priority::WARN :
+ (level == SPError ? Priority::ERROR : Priority::CRIT)))),
msg
);
}
bool AbstractSPRequest::isPriorityEnabled(SPLogLevel level) const
{
return reinterpret_cast<Category*>(m_log)->isPriorityEnabled(
- (level == SPDebug ? log4cpp::Priority::DEBUG :
- (level == SPInfo ? log4cpp::Priority::INFO :
- (level == SPWarn ? log4cpp::Priority::WARN :
- (level == SPError ? log4cpp::Priority::ERROR : log4cpp::Priority::CRIT))))
+ (level == SPDebug ? Priority::DEBUG :
+ (level == SPInfo ? Priority::INFO :
+ (level == SPWarn ? Priority::WARN :
+ (level == SPError ? Priority::ERROR : Priority::CRIT))))
);
}