[cpp-sp] branch main updated: Remove ExternalAuth handler.
Scott Cantor
cantor.2 at osu.edu
Fri Nov 1 18:32:24 UTC 2024
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository cpp-sp.
View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=f2677f75ed11ce663a104bbcc36c482cd8120860
The following commit(s) were added to refs/heads/main by this push:
new f2677f75 Remove ExternalAuth handler.
f2677f75 is described below
commit f2677f75ed11ce663a104bbcc36c482cd8120860
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Nov 1 14:32:20 2024 -0400
Remove ExternalAuth handler.
---
Projects/vc15/shibsp/shibsp.vcxproj | 1 -
shibsp/Makefile.am | 1 -
shibsp/handler/Handler.h | 3 -
shibsp/handler/impl/AbstractHandler.cpp | 2 -
shibsp/handler/impl/ExternalAuthHandler.cpp | 835 ----------------------------
5 files changed, 842 deletions(-)
diff --git a/Projects/vc15/shibsp/shibsp.vcxproj b/Projects/vc15/shibsp/shibsp.vcxproj
index cd05b177..70043de7 100644
--- a/Projects/vc15/shibsp/shibsp.vcxproj
+++ b/Projects/vc15/shibsp/shibsp.vcxproj
@@ -202,7 +202,6 @@
<ClCompile Include="..\..\..\shibsp\handler\impl\AdminLogoutInitiator.cpp" />
<ClCompile Include="..\..\..\shibsp\handler\impl\AttributeCheckerHandler.cpp" />
<ClCompile Include="..\..\..\shibsp\handler\impl\DiscoveryFeed.cpp" />
- <ClCompile Include="..\..\..\shibsp\handler\impl\ExternalAuthHandler.cpp" />
<ClCompile Include="..\..\..\shibsp\handler\impl\LogoutInitiator.cpp" />
<ClCompile Include="..\..\..\shibsp\handler\impl\SecuredHandler.cpp" />
<ClCompile Include="..\..\..\shibsp\impl\StoredSession.cpp" />
diff --git a/shibsp/Makefile.am b/shibsp/Makefile.am
index 9db3deb5..53b04eb8 100644
--- a/shibsp/Makefile.am
+++ b/shibsp/Makefile.am
@@ -90,7 +90,6 @@ libshibsp_la_SOURCES = \
handler/impl/ChainingSessionInitiator.cpp \
handler/impl/CookieSessionInitiator.cpp \
handler/impl/DiscoveryFeed.cpp \
- handler/impl/ExternalAuthHandler.cpp \
handler/impl/FormSessionInitiator.cpp \
handler/impl/LocalLogoutInitiator.cpp \
handler/impl/LogoutHandler.cpp \
diff --git a/shibsp/handler/Handler.h b/shibsp/handler/Handler.h
index 2e647fc2..49652a1d 100644
--- a/shibsp/handler/Handler.h
+++ b/shibsp/handler/Handler.h
@@ -155,9 +155,6 @@ namespace shibsp {
/** Handler for metadata generation. */
#define DISCOVERY_FEED_HANDLER "DiscoveryFeed"
- /** Handler for external authentication integration. */
- #define EXTERNAL_AUTH_HANDLER "ExternalAuth"
-
/** Handler for metadata generation. */
#define METADATA_GENERATOR_HANDLER "MetadataGenerator"
diff --git a/shibsp/handler/impl/AbstractHandler.cpp b/shibsp/handler/impl/AbstractHandler.cpp
index bc0f8d3b..8b0f9159 100644
--- a/shibsp/handler/impl/AbstractHandler.cpp
+++ b/shibsp/handler/impl/AbstractHandler.cpp
@@ -65,7 +65,6 @@ namespace shibsp {
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AssertionLookupFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory AttributeCheckerFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory DiscoveryFeedFactory;
- SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory ExternalAuthFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory MetadataGeneratorFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory StatusHandlerFactory;
SHIBSP_DLLLOCAL PluginManager< Handler,string,pair<const DOMElement*,const char*> >::Factory SessionHandlerFactory;
@@ -101,7 +100,6 @@ void SHIBSP_API shibsp::registerHandlers()
conf.HandlerManager.registerFactory(SAML20_BINDING_URI, AssertionLookupFactory);
conf.HandlerManager.registerFactory(ATTR_CHECKER_HANDLER, AttributeCheckerFactory);
conf.HandlerManager.registerFactory(DISCOVERY_FEED_HANDLER, DiscoveryFeedFactory);
- conf.HandlerManager.registerFactory(EXTERNAL_AUTH_HANDLER, ExternalAuthFactory);
conf.HandlerManager.registerFactory(METADATA_GENERATOR_HANDLER, MetadataGeneratorFactory);
conf.HandlerManager.registerFactory(STATUS_HANDLER, StatusHandlerFactory);
conf.HandlerManager.registerFactory(SESSION_HANDLER, SessionHandlerFactory);
diff --git a/shibsp/handler/impl/ExternalAuthHandler.cpp b/shibsp/handler/impl/ExternalAuthHandler.cpp
deleted file mode 100644
index 92760583..00000000
--- a/shibsp/handler/impl/ExternalAuthHandler.cpp
+++ /dev/null
@@ -1,835 +0,0 @@
-/**
- * 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
- *
- * 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.
- */
-
-/**
- * ExternalAuthHandler.cpp
- *
- * Handler for integrating with external authentication mechanisms.
- */
-
-#include "internal.h"
-#include "exceptions.h"
-#include "Application.h"
-#include "ServiceProvider.h"
-#include "SPRequest.h"
-#include "handler/RemotedHandler.h"
-#include "handler/SecuredHandler.h"
-
-#include <sstream>
-#include <boost/scoped_ptr.hpp>
-
-#ifndef SHIBSP_LITE
-# include "SessionCache.h"
-# include "attribute/SimpleAttribute.h"
-# include "attribute/filtering/AttributeFilter.h"
-# include "attribute/filtering/BasicFilteringContext.h"
-# include "attribute/resolver/AttributeExtractor.h"
-# include "attribute/resolver/AttributeResolver.h"
-# include "attribute/resolver/ResolutionContext.h"
-# include <boost/tokenizer.hpp>
-# include <boost/iterator/indirect_iterator.hpp>
-# include <saml/exceptions.h>
-# include <saml/saml2/core/Assertions.h>
-# include <saml/saml2/metadata/Metadata.h>
-# include <saml/saml2/metadata/MetadataProvider.h>
-# include <xmltooling/XMLToolingConfig.h>
-# include <xmltooling/util/ParserPool.h>
-# include <xmltooling/util/XMLHelper.h>
-# include <xercesc/framework/MemBufInputSource.hpp>
-# include <xercesc/framework/Wrapper4InputSource.hpp>
-using namespace opensaml::saml2md;
-using namespace opensaml;
-using saml2::NameID;
-using saml2::AuthnStatement;
-using saml2::AuthnContext;
-# ifndef min
-# define min(a,b) (((a) < (b)) ? (a) : (b))
-# endif
-#endif
-
-using namespace shibspconstants;
-using namespace shibsp;
-using namespace xmltooling;
-using namespace boost;
-using namespace std;
-
-namespace shibsp {
-
-#if defined (_MSC_VER)
- #pragma warning( push )
- #pragma warning( disable : 4250 )
-#endif
-
- class SHIBSP_API ExternalAuth : public SecuredHandler, public RemotedHandler
- {
- public:
- ExternalAuth(const DOMElement* e, const char* appId);
- virtual ~ExternalAuth() {}
-
- pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
- void receive(DDF& in, ostream& out);
-
- private:
- pair<bool,long> processMessage(
- const Application& application,
- HTTPRequest& httpRequest,
- HTTPResponse& httpResponse,
- DDF& reqDDF,
- const DDF* respDDF=nullptr
- ) const;
-#ifndef SHIBSP_LITE
- ResolutionContext* resolveAttributes(
- const Application& application,
- const GenericRequest* request,
- const saml2md::RoleDescriptor* issuer,
- const XMLCh* protocol,
- const saml2::NameID* nameid,
- const saml2::AuthnStatement* statement,
- const XMLCh* authncontext_class,
- const XMLCh* authncontext_decl,
- const vector<const Assertion*>* tokens=nullptr,
- const vector<Attribute*>* inputAttributes=nullptr
- ) const;
-#endif
- };
-
-#if defined (_MSC_VER)
- #pragma warning( pop )
-#endif
-
- Handler* SHIBSP_DLLLOCAL ExternalAuthFactory(const pair<const DOMElement*,const char*>& p, bool)
- {
- return new ExternalAuth(p.first, p.second);
- }
-
-};
-
-namespace {
- static ostream& json_safe(ostream& os, const char* buf)
- {
- os << '"';
- for (; *buf; ++buf) {
- switch (*buf) {
- case '\\':
- case '"':
- os << '\\';
- os << *buf;
- break;
- case '\b':
- os << "\\b";
- break;
- case '\t':
- os << "\\t";
- break;
- case '\n':
- os << "\\n";
- break;
- case '\f':
- os << "\\f";
- break;
- case '\r':
- os << "\\r";
- break;
- default:
- os << *buf;
- }
- }
- os << '"';
- return os;
- }
-};
-
-ExternalAuth::ExternalAuth(const DOMElement* e, const char* appId)
- : SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT ".Handler.ExternalAuth"), "acl", "127.0.0.1 ::1")
-{
- SPConfig::getConfig().deprecation().warn(EXTERNAL_AUTH_HANDLER" handler");
-
- pair<bool,const char*> prop = getString("Location");
- if (!prop.first)
- throw ConfigurationException("ExternalAuth handler requires Location property.");
- string address(appId);
- address += prop.second;
- setAddress(address.c_str());
-}
-
-pair<bool,long> ExternalAuth::run(SPRequest& request, bool isHandler) const
-{
- // Check ACL in base class.
- pair<bool,long> ret = SecuredHandler::run(request, isHandler);
- if (ret.first)
- return ret;
-
- try {
- if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
- // When out of process, we run natively and directly process the message, except that we
- // have to indirect the request anyway in order to override the client address. This is
- // the simplest way to get a delegated HTTPRequest object, and since this code path is
- // not really one we expect to use, it's good enough.
- vector<string> headers(1, "User-Agent");
- headers.push_back("Accept");
- headers.push_back("Accept-Language");
- headers.push_back("Cookie");
- DDF in = wrap(request, &headers);
- DDFJanitor jin(in);
- scoped_ptr<HTTPRequest> fakedreq(getRequest(request.getApplication(), in));
- return processMessage(request.getApplication(), *fakedreq, request, in);
- }
- else {
- // When not out of process, we remote all the message processing.
- vector<string> headers(1, "User-Agent");
- headers.push_back("Accept");
- headers.push_back("Accept-Language");
- headers.push_back("Cookie");
- DDF out,in = wrap(request, &headers);
- DDFJanitor jin(in), jout(out);
- out = send(request, in);
- return unwrap(request, out);
- }
- }
- catch (const std::exception& ex) {
- m_log.error("error while processing request: %s", ex.what());
- istringstream msg("External Authentication Failed");
- return make_pair(true, request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
- }
-}
-
-void ExternalAuth::receive(DDF& in, ostream& out)
-{
- // Find application.
- const char* aid = in["application_id"].string();
- const Application* app = aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
- if (!app) {
- // Something's horribly wrong.
- m_log.error("couldn't find application (%s) for external authentication", aid ? aid : "(missing)");
- throw ConfigurationException("Unable to locate application for external authentication, deleted?");
- }
-
- // Unpack the request.
- scoped_ptr<HTTPRequest> req(getRequest(*app, in));
-
- // Wrap a response shim.
- DDF ret(nullptr);
- DDFJanitor jout(ret);
- scoped_ptr<HTTPResponse> resp(getResponse(*app, ret));
-
- // Since we're remoted, the result should either be a throw, a false/0 return,
- // which we just return as an empty structure, or a response/redirect,
- // which we capture in the facade and send back.
- try {
- processMessage(*app, *req, *resp, in, &ret);
- }
- catch (const std::exception& ex) {
- m_log.error("raising exception: %s", ex.what());
- throw;
- }
- out << ret;
-}
-
-pair<bool,long> ExternalAuth::processMessage(
- const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse, DDF& reqDDF, const DDF* respDDF
- ) const
-{
-#ifndef SHIBSP_LITE
- string session_id;
- SessionCache* cache = application.getServiceProvider().getSessionCache();
- MetadataProvider* m = application.getMetadataProvider(false);
- Locker mocker(m);
-
- scoped_ptr<TransactionLog::Event> event;
- LoginEvent* login_event = nullptr;
- if (SPConfig::getConfig().isEnabled(SPConfig::Logging)) {
- event.reset(SPConfig::getConfig().EventManager.newPlugin(LOGIN_EVENT, nullptr, false));
- login_event = dynamic_cast<LoginEvent*>(event.get());
- if (login_event)
- login_event->m_app = &application;
- else
- m_log.warn("unable to audit event, log event object was of an incorrect type");
- }
-
- string ctype(httpRequest.getContentType());
- if (ctype == "text/xml" || ctype == "application/samlassertion+xml") {
- const char* body = httpRequest.getRequestBody();
- if (!body)
- throw FatalProfileException("Request body was empty.");
-
- // Parse and bind the document into an XMLObject.
- MemBufInputSource src(reinterpret_cast<const XMLByte*>(body), httpRequest.getContentLength(), "SAMLAssertion");
- Wrapper4InputSource dsrc(&src, false);
- DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(dsrc);
- XercesJanitor<DOMDocument> janitor(doc);
- scoped_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
- janitor.release();
-
- saml2::Assertion* token = dynamic_cast<saml2::Assertion*>(xmlObject.get());
- if (!token)
- throw FatalProfileException("Request body did not contain a SAML 2.0 assertion.");
- else if (token->getAuthnStatements().empty())
- throw FatalProfileException("Assertion in request did not contain an AuthnStatement.");
-
- // We're not implementing a full SAML profile here, only a minimal one that ignores most
- // security checking, conditions, etc. The caller is in full control here and we just consume
- // what we're given. The only thing we're honoring is the authentication information we find
- // and processing any attributes.
-
- const XMLCh* protocol = nullptr;
- pair<const EntityDescriptor*, const RoleDescriptor*> issuer = pair<const EntityDescriptor*, const RoleDescriptor*>(nullptr,nullptr);
- if (m && token->getIssuer() && token->getIssuer()->getName()) {
- MetadataProvider::Criteria mc;
- mc.entityID_unicode = token->getIssuer()->getName();
- mc.role = &IDPSSODescriptor::ELEMENT_QNAME;
- mc.protocol = samlconstants::SAML20P_NS;
- issuer = m->getEntityDescriptor(mc);
- if (!issuer.first) {
- auto_ptr_char iname(token->getIssuer()->getName());
- m_log.warn("no metadata found for issuer (%s)", iname.get());
- }
- else if (!issuer.second) {
- auto_ptr_char iname(token->getIssuer()->getName());
- m_log.warn("no IdP role found in metadata for issuer (%s)", iname.get());
- }
- protocol = mc.protocol;
- }
-
- const saml2::NameID* nameid = nullptr;
- if (token->getSubject())
- nameid = token->getSubject()->getNameID();
- const AuthnStatement* ssoStatement = token->getAuthnStatements().front();
-
- // authnskew allows rejection of SSO if AuthnInstant is too old.
- const PropertySet* sessionProps = application.getPropertySet("Sessions");
- pair<bool,unsigned int> authnskew = sessionProps ? sessionProps->getUnsignedInt("maxTimeSinceAuthn") : pair<bool,unsigned int>(false,0);
-
- time_t now(time(nullptr));
- if (ssoStatement->getAuthnInstant() &&
- ssoStatement->getAuthnInstantEpoch() - XMLToolingConfig::getConfig().clock_skew_secs > now) {
- throw FatalProfileException("The AuthnInstant was future-dated.");
- }
- else if (authnskew.first && authnskew.second && ssoStatement->getAuthnInstant() &&
- ssoStatement->getAuthnInstantEpoch() <= now && (now - ssoStatement->getAuthnInstantEpoch() > authnskew.second)) {
- throw FatalProfileException("The gap between now and the AuthnInstant exceeds the allowed limit.");
- }
- else if (authnskew.first && authnskew.second && ssoStatement->getAuthnInstant() == nullptr) {
- throw FatalProfileException("No AuthnInstant was supplied, violating local policy.");
- }
-
- // Session expiration for SAML 2.0 is jointly IdP- and SP-driven.
- time_t sessionExp = ssoStatement->getSessionNotOnOrAfter() ?
- (ssoStatement->getSessionNotOnOrAfterEpoch() + XMLToolingConfig::getConfig().clock_skew_secs) : 0;
- pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : pair<bool,unsigned int>(true,28800);
- if (!lifetime.first || lifetime.second == 0)
- lifetime.second = 28800;
- if (sessionExp == 0)
- sessionExp = now + lifetime.second; // IdP says nothing, calulate based on SP.
- else
- sessionExp = min(sessionExp, now + lifetime.second); // Use the lowest.
-
- const XMLCh* authncontext_class = nullptr;
- const XMLCh* authncontext_decl = nullptr;
- const AuthnContext* authnContext = ssoStatement->getAuthnContext();
- if (authnContext) {
- authncontext_class = authnContext->getAuthnContextClassRef() ? authnContext->getAuthnContextClassRef()->getReference() : nullptr;
- authncontext_decl = authnContext->getAuthnContextDeclRef() ? authnContext->getAuthnContextDeclRef()->getReference() : nullptr;
- }
-
- // Extract client address.
- reqDDF.addmember("client_addr").string((const char*)nullptr);
- if (ssoStatement->getSubjectLocality() && ssoStatement->getSubjectLocality()->getAddress()) {
- auto_ptr_char addr(ssoStatement->getSubjectLocality()->getAddress());
- if (addr.get())
- reqDDF.getmember("client_addr").string(addr.get());
- }
-
- // The context will handle deleting attributes and tokens.
- vector<const Assertion*> tokens(1, token);
- scoped_ptr<ResolutionContext> ctx(
- resolveAttributes(
- application,
- &httpRequest,
- issuer.second,
- protocol,
- nameid,
- ssoStatement,
- authncontext_class,
- authncontext_decl,
- &tokens
- )
- );
- tokens.clear(); // don't store the original token in the session, since it was contrived
-
- if (ctx) {
- // Copy over any new tokens, but leave them in the context for cleanup.
- tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
- }
-
- cache->insert(
- session_id,
- application,
- httpRequest,
- httpResponse,
- sessionExp,
- issuer.first,
- protocol,
- nameid,
- ssoStatement->getAuthnInstant() ? ssoStatement->getAuthnInstant()->getRawData() : nullptr,
- ssoStatement->getSessionIndex(),
- authncontext_class,
- authncontext_decl,
- &tokens,
- ctx ? &ctx->getResolvedAttributes() : nullptr
- );
-
- if (login_event) {
- login_event->m_binding = "ExternalAuth/XML";
- login_event->m_sessionID = session_id.c_str();
- login_event->m_peer = issuer.first;
- auto_ptr_char prot(protocol);
- login_event->m_protocol = prot.get();
- login_event->m_nameID = nameid;
- login_event->m_saml2AuthnStatement = ssoStatement;
- if (ctx)
- login_event->m_attributes = &ctx->getResolvedAttributes();
- try {
- application.getServiceProvider().getTransactionLog()->write(*login_event);
- }
- catch (std::exception& ex) {
- m_log.warn("exception auditing event: %s", ex.what());
- }
- }
- }
- else if (ctype == "application/x-www-form-urlencoded") {
- auto_ptr_XMLCh protocol(httpRequest.getParameter("protocol"));
- const char* param = httpRequest.getParameter("issuer");
- pair<const EntityDescriptor*, const RoleDescriptor*> issuer = pair<const EntityDescriptor*, const RoleDescriptor*>(nullptr,nullptr);
- if (m && param && *param) {
- MetadataProvider::Criteria mc;
- mc.entityID_ascii = param;
- mc.role = &IDPSSODescriptor::ELEMENT_QNAME;
- mc.protocol = protocol.get();
- issuer = m->getEntityDescriptor(mc);
- if (!issuer.first)
- m_log.warn("no metadata found for issuer (%s)", param);
- else if (!issuer.second)
- m_log.warn("no IdP role found in metadata for issuer (%s)", param);
- }
-
- scoped_ptr<saml2::NameID> nameid;
- param = httpRequest.getParameter("NameID");
- if (param && *param) {
- nameid.reset(saml2::NameIDBuilder::buildNameID());
- auto_arrayptr<XMLCh> n(fromUTF8(param));
- nameid->setName(n.get());
- param = httpRequest.getParameter("Format");
- if (param && param) {
- auto_ptr_XMLCh f(param);
- nameid->setFormat(f.get());
- }
- }
-
- scoped_ptr<XMLDateTime> authn_instant;
- param = httpRequest.getParameter("AuthnInstant");
- if (param && *param) {
- auto_ptr_XMLCh d(param);
- try {
- authn_instant.reset(new XMLDateTime(d.get()));
- authn_instant->parseDateTime();
- }
- catch (const XMLException& e) {
- auto_ptr_char temp(e.getMessage());
- throw XMLObjectException(temp.get() ? temp.get() : "XMLException parsing date/time value.");
- }
- }
-
- auto_ptr_XMLCh session_index(httpRequest.getParameter("SessionIndex"));
- auto_ptr_XMLCh authncontext_class(httpRequest.getParameter("AuthnContextClassRef"));
- auto_ptr_XMLCh authncontext_decl(httpRequest.getParameter("AuthnContextDeclRef"));
-
- time_t sessionExp = 0;
- param = httpRequest.getParameter("lifetime");
- if (param && param)
- sessionExp = atol(param);
- if (sessionExp) {
- sessionExp += time(nullptr);
- }
- else {
- const PropertySet* sessionProps = application.getPropertySet("Sessions");
- pair<bool,unsigned int> lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : pair<bool,unsigned int>(true,28800);
- if (!lifetime.first || lifetime.second == 0)
- lifetime.second = 28800;
- sessionExp = time(nullptr) + lifetime.second;
- }
-
- // Create simple attributes around whatever parameters are specified.
- vector<Attribute*> resolvedAttributes;
- param = httpRequest.getParameter("attributes");
- if (param && *param) {
- char_separator<char> sep(", ");
- string dup(param);
- tokenizer< char_separator<char> > tokens(dup, sep);
- try {
- for (tokenizer< char_separator<char> >::iterator t = tokens.begin(); t != tokens.end(); ++t) {
- vector<const char*> vals;
- if (httpRequest.getParameters(t->c_str(), vals)) {
- vector<string> ids(1, *t);
- auto_ptr<SimpleAttribute> attr(new SimpleAttribute(ids));
- vector<string>& dest = attr->getValues();
- for (vector<const char*>::const_iterator v = vals.begin(); v != vals.end(); ++v)
- dest.push_back(*v);
- resolvedAttributes.push_back(attr.get());
- attr.release();
- }
- }
- }
- catch (const std::exception&) {
- for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
- throw;
- }
- }
-
- // Get actual client address.
- reqDDF.addmember("client_addr").string(httpRequest.getParameter("address"));
-
- scoped_ptr<ResolutionContext> ctx(
- resolveAttributes(
- application,
- &httpRequest,
- issuer.second,
- protocol.get(),
- nameid.get(),
- nullptr,
- authncontext_class.get(),
- authncontext_decl.get(),
- nullptr,
- &resolvedAttributes
- )
- );
-
- vector<const Assertion*> tokens;
- if (ctx) {
- // Copy over any new tokens, but leave them in the context for cleanup.
- tokens.insert(tokens.end(), ctx->getResolvedAssertions().begin(), ctx->getResolvedAssertions().end());
- }
-
- cache->insert(
- session_id,
- application,
- httpRequest,
- httpResponse,
- sessionExp,
- issuer.first,
- protocol.get(),
- nameid.get(),
- authn_instant ? authn_instant->getRawData() : nullptr,
- session_index.get(),
- authncontext_class.get(),
- authncontext_decl.get(),
- &tokens,
- ctx ? &ctx->getResolvedAttributes() : nullptr
- );
-
- if (login_event) {
- login_event->m_binding = "ExternalAuth/POST";
- login_event->m_sessionID = session_id.c_str();
- login_event->m_peer = issuer.first;
- login_event->m_protocol = httpRequest.getParameter("protocol");
- login_event->m_nameID = nameid.get();
- if (ctx)
- login_event->m_attributes = &ctx->getResolvedAttributes();
- try {
- application.getServiceProvider().getTransactionLog()->write(*login_event);
- }
- catch (std::exception& ex) {
- m_log.warn("exception auditing event: %s", ex.what());
- }
- }
- }
- else {
- throw FatalProfileException("Submission was not in a recognized SAML assertion or form-encoded format.");
- }
-
- const char* param = httpRequest.getParameter("RelayState");
- string target(param ? param : "");
- try {
- recoverRelayState(application, httpRequest, httpResponse, target);
- }
- catch (const std::exception& ex) {
- m_log.error("error recovering relay state: %s", ex.what());
- target.erase();
- }
-
- stringstream os;
- string accept = httpRequest.getHeader("Accept");
- if (accept.find("application/json") != string::npos) {
- httpResponse.setContentType("application/json");
- os << "{ \"SessionID\": "; json_safe(os, session_id.c_str());
- bool firstCookie = true;
- if (respDDF) {
- DDF hdr;
- DDF hdrs = respDDF->getmember("headers");
- hdr = hdrs.first();
- while (hdr.isstring()) {
- if (!strcmp(hdr.name(), "Set-Cookie")) {
- if (firstCookie) {
- os << ", \"Cookies\": [ ";
- firstCookie = false;
- }
- else {
- os << ", ";
- }
- json_safe(os, hdr.string());
- }
- hdr = hdrs.next();
- }
- }
- os << " ]";
- if (!target.empty()) {
- os << ", \"RelayState\": ";
- json_safe(os, target.c_str());
- }
- os << " }";
- }
- else {
- httpResponse.setContentType("text/xml");
- static const XMLCh _ExternalAuth[] = UNICODE_LITERAL_12(E,x,t,e,r,n,a,l,A,u,t,h);
- static const XMLCh _SessionID[] = UNICODE_LITERAL_9(S,e,s,s,i,o,n,I,D);
- static const XMLCh _RelayState[] = UNICODE_LITERAL_10(R,e,l,a,y,S,t,a,t,e);
- static const XMLCh _Cookie[] = UNICODE_LITERAL_6(C,o,o,k,i,e);
- DOMDocument* retdoc = XMLToolingConfig::getConfig().getParser().newDocument();
- XercesJanitor<DOMDocument> retjanitor(retdoc);
- retdoc->appendChild(retdoc->createElement(_ExternalAuth));
- auto_ptr_XMLCh wideid(session_id.c_str());
- DOMElement* child = retdoc->createElement(_SessionID);
- child->appendChild(retdoc->createTextNode(wideid.get()));
- retdoc->getDocumentElement()->appendChild(child);
- if (respDDF) {
- DDF hdr;
- DDF hdrs = respDDF->getmember("headers");
- hdr = hdrs.first();
- while (hdr.isstring()) {
- if (!strcmp(hdr.name(), "Set-Cookie")) {
- child = retdoc->createElement(_Cookie);
- auto_ptr_XMLCh wideval(hdr.string());
- child->appendChild(retdoc->createTextNode(wideval.get()));
- retdoc->getDocumentElement()->appendChild(child);
- }
- hdr = hdrs.next();
- }
- }
- if (!target.empty()) {
- auto_ptr_XMLCh widetar(target.c_str());
- child = retdoc->createElement(_RelayState);
- child->appendChild(retdoc->createTextNode(widetar.get()));
- retdoc->getDocumentElement()->appendChild(child);
- }
- XMLHelper::serialize(retdoc->getDocumentElement(), os, true);
- }
- return make_pair(true, httpResponse.sendResponse(os));
-#else
- return make_pair(false, 0L);
-#endif
-}
-
-#ifndef SHIBSP_LITE
-
-namespace {
- class SHIBSP_DLLLOCAL DummyContext : public ResolutionContext
- {
- public:
- DummyContext(const vector<Attribute*>& attributes) : m_attributes(attributes) {
- }
-
- virtual ~DummyContext() {
- for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
- }
-
- vector<Attribute*>& getResolvedAttributes() {
- return m_attributes;
- }
- vector<Assertion*>& getResolvedAssertions() {
- return m_tokens;
- }
-
- private:
- vector<Attribute*> m_attributes;
- static vector<Assertion*> m_tokens; // never any tokens, so just share an empty vector
- };
-};
-
-vector<Assertion*> DummyContext::m_tokens;
-
-ResolutionContext* ExternalAuth::resolveAttributes(
- const Application& application,
- const GenericRequest* request,
- const RoleDescriptor* issuer,
- const XMLCh* protocol,
- const saml2::NameID* nameid,
- const saml2::AuthnStatement* statement,
- const XMLCh* authncontext_class,
- const XMLCh* authncontext_decl,
- const vector<const Assertion*>* tokens,
- const vector<Attribute*>* inputAttributes
- ) const
-{
- vector<Attribute*> resolvedAttributes;
- if (inputAttributes)
- resolvedAttributes = *inputAttributes;
-
- // First we do the extraction of any pushed information, including from metadata.
- AttributeExtractor* extractor = application.getAttributeExtractor();
- if (extractor) {
- Locker extlocker(extractor);
- if (issuer) {
- pair<bool,const char*> mprefix = application.getString("metadataAttributePrefix");
- if (mprefix.first) {
- m_log.debug("extracting metadata-derived attributes...");
- try {
- // We pass nullptr for "issuer" because the IdP isn't the one asserting metadata-based attributes.
- extractor->extractAttributes(application, request, nullptr, *issuer, resolvedAttributes);
- for (indirect_iterator<vector<Attribute*>::iterator> a = make_indirect_iterator(resolvedAttributes.begin());
- a != make_indirect_iterator(resolvedAttributes.end()); ++a) {
- vector<string>& ids = a->getAliases();
- for (vector<string>::iterator id = ids.begin(); id != ids.end(); ++id)
- *id = mprefix.second + *id;
- }
- }
- catch (const std::exception& ex) {
- m_log.error("caught exception extracting attributes: %s", ex.what());
- }
- }
- }
-
- m_log.debug("extracting pushed attributes...");
-
- if (nameid) {
- try {
- extractor->extractAttributes(application, request, issuer, *nameid, resolvedAttributes);
- }
- catch (const std::exception& ex) {
- m_log.error("caught exception extracting attributes: %s", ex.what());
- }
- }
-
- if (statement) {
- try {
- extractor->extractAttributes(application, request, issuer, *statement, resolvedAttributes);
- }
- catch (const std::exception& ex) {
- m_log.error("caught exception extracting attributes: %s", ex.what());
- }
- }
-
- if (tokens) {
- for (indirect_iterator<vector<const Assertion*>::const_iterator> t = make_indirect_iterator(tokens->begin());
- t != make_indirect_iterator(tokens->end()); ++t) {
- try {
- extractor->extractAttributes(application, request, issuer, *t, resolvedAttributes);
- }
- catch (const std::exception& ex) {
- m_log.error("caught exception extracting attributes: %s", ex.what());
- }
- }
- }
-
- AttributeFilter* filter = application.getAttributeFilter();
- if (filter && !resolvedAttributes.empty()) {
- BasicFilteringContext fc(application, resolvedAttributes, issuer, authncontext_class, authncontext_decl);
- Locker filtlocker(filter);
- try {
- filter->filterAttributes(fc, resolvedAttributes);
- }
- catch (const std::exception& ex) {
- m_log.error("caught exception filtering attributes: %s", ex.what());
- m_log.error("dumping extracted attributes due to filtering exception");
- for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
- resolvedAttributes.clear();
- }
- }
- }
- else {
- m_log.warn("no AttributeExtractor plugin installed, check log during startup");
- }
-
- try {
- AttributeResolver* resolver = application.getAttributeResolver();
- if (resolver) {
- m_log.debug("resolving attributes...");
-
- Locker locker(resolver);
- auto_ptr<ResolutionContext> ctx(
- resolver->createResolutionContext(
- application,
- request,
- issuer ? dynamic_cast<const EntityDescriptor*>(issuer->getParent()) : nullptr,
- protocol,
- nameid,
- authncontext_class,
- authncontext_decl,
- tokens,
- &resolvedAttributes
- )
- );
- resolver->resolveAttributes(*ctx);
- // Copy over any pushed attributes.
- while (!resolvedAttributes.empty()) {
- ctx->getResolvedAttributes().push_back(resolvedAttributes.back());
- resolvedAttributes.pop_back();
- }
- return ctx.release();
- }
- }
- catch (const std::exception& ex) {
- m_log.error("attribute resolution failed: %s", ex.what());
- }
-
- if (!resolvedAttributes.empty()) {
- try {
- return new DummyContext(resolvedAttributes);
- }
- catch (const bad_alloc&) {
- for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
- }
- }
- return nullptr;
-}
-
-LoginEvent* ExternalAuth::newLoginEvent(const Application& application, const HTTPRequest& request) const
-{
- if (!SPConfig::getConfig().isEnabled(SPConfig::Logging))
- return nullptr;
- try {
- auto_ptr<TransactionLog::Event> event(SPConfig::getConfig().EventManager.newPlugin(LOGIN_EVENT, nullptr, false));
- LoginEvent* login_event = dynamic_cast<LoginEvent*>(event.get());
- if (login_event) {
- login_event->m_request = &request;
- login_event->m_app = &application;
- login_event->m_binding = "ExternalAuth";
- event.release();
- return login_event;
- }
- else {
- m_log.warn("unable to audit event, log event object was of an incorrect type");
- }
- }
- catch (const std::exception& ex) {
- m_log.warn("exception auditing event: %s", ex.what());
- }
- return nullptr;
-}
-
-#endif
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list