EXTRA_DIST = \
schemas doc isapi_shib isapi_shib_gui \
Shibboleth.sln libtool.m4 acx_pthread.m4 acx_rpctest.m4 depcomp \
- config_win32.h shibtest/shibtest.vcproj \
- shibboleth.spec.in shibboleth.spec pkginfo.in pkginfo checkinstall
+ config_win32.h shibboleth.spec.in shibboleth.spec pkginfo.in pkginfo checkinstall
dist-hook:
rm -rf `find $(distdir)/schemas -name Makefile`
+++ /dev/null
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright (c) 1996 - 2004, Daniel Stenberg, <daniel@haxx.se>.
-
-All rights reserved.
-
-Permission to use, copy, modify, and distribute this software for any purpose
-with or without fee is hereby granted, provided that the above copyright
-notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
-NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
-OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization of the copyright holder.
README.txt \
OPENSSL.LICENSE \
LOG4CPP.LICENSE \
- CURL.LICENSE \
mysql-4.0.12.diff \
main.css \
logo.jpg
\ No newline at end of file
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/* ArtifactMapper.cpp - a ShibTarget-aware SAML artifact->binding mapper
-
- Scott Cantor
- 2/20/05
-
- $History:$
-*/
-
-#include "internal.h"
-#include <shibsp/SPConfig.h>
-#include <saml/binding/SAMLArtifact.h>
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace saml;
-using namespace opensaml::saml2md;
-using namespace xmltooling;
-using namespace log4cpp;
-using namespace std;
-using xmlsignature::CredentialResolver;
-
-SAMLResponse* STArtifactMapper::resolve(SAMLRequest* request)
-{
- Category& log=Category::getInstance("shibtarget.ArtifactMapper");
-
- // First do a search for the issuer.
- SAMLArtifact* artifact=request->getArtifacts().next();
- auto_ptr<opensaml::SAMLArtifact> os2art(opensaml::SAMLArtifact::parse(artifact->encode().c_str()));
-
- MetadataProvider* m=m_app->getMetadataProvider();
- const EntityDescriptor* entity=m->getEntityDescriptor(os2art.get());
- if (!entity) {
- log.error(
- "metadata lookup failed, unable to determine issuer of artifact (0x%s)",
- opensaml::SAMLArtifact::toHex(artifact->getBytes()).c_str()
- );
- throw MetadataException("Metadata lookup failed, unable to determine artifact issuer");
- }
-
- xmltooling::auto_ptr_char issuer(entity->getEntityID());
- log.info("lookup succeeded, artifact issued by (%s)", issuer.get());
-
- // Sign it?
- const PropertySet* credUse=m_app->getCredentialUse(entity);
- pair<bool,bool> signRequest=credUse ? credUse->getBool("signRequest") : make_pair(false,false);
- pair<bool,const char*> signatureAlg=credUse ? credUse->getString("signatureAlg") : pair<bool,const char*>(false,NULL);
- if (!signatureAlg.first)
- signatureAlg.second=URI_ID_RSA_SHA1;
- pair<bool,const char*> digestAlg=credUse ? credUse->getString("digestAlg") : pair<bool,const char*>(false,NULL);
- if (!digestAlg.first)
- digestAlg.second=URI_ID_SHA1;
- pair<bool,bool> signedResponse=credUse ? credUse->getBool("signedResponse") : make_pair(false,false);
- pair<bool,const char*> signingCred=credUse ? credUse->getString("Signing") : pair<bool,const char*>(false,NULL);
- if (signRequest.first && signRequest.second && signingCred.first) {
- if (request->getMinorVersion()==1) {
- CredentialResolver* cr=SPConfig::getConfig().getServiceProvider()->getCredentialResolver(signingCred.second);
- if (cr) {
- xmltooling::Locker locker(cr);
- request->sign(cr->getKey(),cr->getCertificates(),signatureAlg.second,digestAlg.second);
- }
- else
- log.error("unable to sign artifact request, specified credential (%s) was not found",signingCred.second);
- }
- else
- log.error("unable to sign SAML 1.0 artifact request, only SAML 1.1 defines signing adequately");
- }
-
- SAMLResponse* response = NULL;
- bool authenticated = false;
- static const XMLCh https[] = {chLatin_h, chLatin_t, chLatin_t, chLatin_p, chLatin_s, chColon, chNull};
-
- // Depends on type of artifact.
- const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
- if (type1) {
- // With type 01, any endpoint will do.
- const IDPSSODescriptor* idp=entity->getIDPSSODescriptor(
- request->getMinorVersion()==1 ? samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM
- );
- if (idp) {
- ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse,idp);
- const vector<ArtifactResolutionService*>& endpoints=idp->getArtifactResolutionServices();
- for (vector<ArtifactResolutionService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {
- const SAMLBinding* binding = m_app->getBinding((*ep)->getBinding());
- if (!binding) {
- xmltooling::auto_ptr_char prot((*ep)->getBinding());
- log.warn("skipping binding on unsupported protocol (%s)", prot.get());
- continue;
- }
- try {
- response = binding->send((*ep)->getLocation(),*request,&callCtx);
- if (log.isDebugEnabled())
- log.debugStream() << "SAML response from artifact request:\n" << *response << CategoryStream::ENDLINE;
-
- if (!response->getAssertions().hasNext()) {
- delete response;
- throw FatalProfileException("No SAML assertions returned in response to artifact profile request.");
- }
- authenticated = callCtx.isAuthenticated() && !XMLString::compareNString((*ep)->getLocation(),https,6);
- }
- catch (XMLToolingException& ex) {
- annotateException(&ex,idp); // rethrows it
- }
- catch (exception& ex) {
- opensaml::BindingException ex2(ex.what());
- annotateException(&ex2,idp); // rethrows it
- }
- }
- }
- }
- else {
- const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
- if (type2) {
- // With type 02, we have to find the matching location.
- const IDPSSODescriptor* idp=entity->getIDPSSODescriptor(
- request->getMinorVersion()==1 ? samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM
- );
- if (idp) {
- ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse,idp);
- const vector<ArtifactResolutionService*>& endpoints=idp->getArtifactResolutionServices();
- for (vector<ArtifactResolutionService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {
- xmltooling::auto_ptr_char loc((*ep)->getLocation());
- if (strcmp(loc.get(),type2->getSourceLocation()))
- continue;
- const SAMLBinding* binding = m_app->getBinding((*ep)->getBinding());
- if (!binding) {
- xmltooling::auto_ptr_char prot((*ep)->getBinding());
- log.warn("skipping binding on unsupported protocol (%s)", prot.get());
- continue;
- }
- try {
- response = binding->send((*ep)->getLocation(),*request,&callCtx);
- if (log.isDebugEnabled())
- log.debugStream() << "SAML response from artifact request:\n" << *response << CategoryStream::ENDLINE;
-
- if (!response->getAssertions().hasNext()) {
- delete response;
- throw FatalProfileException("No SAML assertions returned in response to artifact profile request.");
- }
- authenticated = callCtx.isAuthenticated() && !XMLString::compareNString((*ep)->getLocation(),https,6);
- }
- catch (XMLToolingException& ex) {
- annotateException(&ex,idp); // rethrows it
- }
- catch (exception& ex) {
- opensaml::BindingException ex2(ex.what());
- annotateException(&ex2,idp); // rethrows it
- }
- }
- }
- }
- else {
- log.error("unrecognized artifact type (0x%s)", SAMLArtifact::toHex(artifact->getTypeCode()).c_str());
- throw xmltooling::UnknownExtensionException(
- string("Received unrecognized artifact type (0x") + SAMLArtifact::toHex(artifact->getTypeCode()) + ")"
- );
- }
- }
-
- if (!response) {
- log.error("unable to locate acceptable binding/endpoint to resolve artifact");
- MetadataException ex("Unable to locate acceptable binding/endpoint to resolve artifact.");
- annotateException(&ex,entity); // throws it
- }
- else if (!response->isSigned()) {
- if (!authenticated || (signedResponse.first && signedResponse.second)) {
- log.error("unsigned response obtained, but it must be signed.");
- XMLSecurityException ex("Unable to obtain a signed response from artifact request.");
- annotateException(&ex,entity); // throws it
- }
- }
-
- return response;
-}
+++ /dev/null
-## $Id$
-
-AUTOMAKE_OPTIONS = foreign
-
-pkgsysconfdir = $(sysconfdir)/@PACKAGE@
-pkgxmldir = $(datadir)/xml/@PACKAGE@
-
-lib_LTLIBRARIES = libshib-target.la
-
-libshib_targetdir = $(includedir)/shib-target
-libshib_target_HEADERS = shib-target.h shib-paths.h
-noinst_HEADERS = internal.h
-
-libshib_target_la_SOURCES = \
- ArtifactMapper.cpp \
- ShibHTTPHook.cpp \
- shib-ccache.cpp \
- shib-config.cpp \
- shib-handlers.cpp \
- shib-ini.cpp
-
-# this is different from the project version
-# http://sources.redhat.com/autobook/autobook/autobook_91.html
-libshib_target_la_LDFLAGS = -version-info 7:0:0
-
-
-
-shib-paths.h: ${srcdir}/shib-paths.h.in Makefile ${top_builddir}/config.status
- rm -f $@.tmp
- sed < ${srcdir}/$@.in > $@.tmp \
- -e 's:@-PKGSYSCONFDIR-@:${pkgsysconfdir}:' \
- -e 's:@-PKGXMLDIR-@:${pkgxmldir}:'
- cmp -s $@ $@.tmp || mv $@.tmp $@
- rm -f $@.tmp
-
-install-exec-hook:
- for la in $(lib_LTLIBRARIES) ; do rm -f $(DESTDIR)$(libdir)/$$la ; done
-
-EXTRA_DIST = shibtarget.vcproj shib-paths.h.in resource.h shib-target.rc
-BUILT_SOURCES = shib-paths.h
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/* ShibHTTPHook.cpp - Shibboleth hook for SAML Binding with SSL callback
-
- Scott Cantor
- 2/13/05
-
- $History:$
-*/
-
-#include "internal.h"
-
-#include <shibsp/SPConfig.h>
-#include <xmltooling/security/OpenSSLTrustEngine.h>
-#include <xmltooling/signature/OpenSSLCredentialResolver.h>
-
-#include <saml/version.h>
-#include <openssl/ssl.h>
-#include <openssl/x509_vfy.h>
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace shibboleth;
-using namespace saml;
-using namespace xmltooling;
-using namespace log4cpp;
-using namespace std;
-using xmlsignature::OpenSSLCredentialResolver;
-
-/*
- * Our verifier callback is a front-end for invoking each trust plugin until
- * success, or we run out of plugins.
- */
-static int verify_callback(X509_STORE_CTX* x509_ctx, void* arg)
-{
- Category::getInstance("OpenSSL").debug("invoking default X509 verify callback");
-#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
- ShibHTTPHook::ShibHTTPHookCallContext* ctx = reinterpret_cast<ShibHTTPHook::ShibHTTPHookCallContext*>(arg);
-#else
- // Yes, this sucks. I'd use TLS, but there's no really obvious spot to put the thread key
- // and global variables suck too. We can't access the X509_STORE_CTX depth directly because
- // OpenSSL only copies it into the context if it's >=0, and the unsigned pointer may be
- // negative in the SSL structure's int member.
- SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(x509_ctx,SSL_get_ex_data_X509_STORE_CTX_idx()));
- ShibHTTPHook::ShibHTTPHookCallContext* ctx =
- reinterpret_cast<ShibHTTPHook::ShibHTTPHookCallContext*>(SSL_get_verify_depth(ssl));
-#endif
-
- const OpenSSLTrustEngine* t = dynamic_cast<const OpenSSLTrustEngine*>(ctx->getHook()->getTrustEngine());
- if (!t || !t->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->getRoleDescriptor()),false)) { // bypass name check (handled for us)
- x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION; // generic error, check log for plugin specifics
- return 0;
- }
-
- // Signal success. Hopefully it doesn't matter what's actually in the structure now.
- return 1;
-}
-
-/*
- * OpenSAML callback is invoked during SSL context setup, before the handshake.
- * We use it to attach credentials and our own certificate verifier callback above.
- */
-static bool ssl_ctx_callback(void* ssl_ctx, void* userptr)
-{
-#ifdef _DEBUG
- xmltooling::NDC("ssl_ctx_callback");
-#endif
- Category& log=Category::getInstance(SHIBT_LOGCAT".ShibHTTPHook");
-
- try {
- log.debug("OpenSAML invoked SSL context callback");
- ShibHTTPHook::ShibHTTPHookCallContext* ctx = reinterpret_cast<ShibHTTPHook::ShibHTTPHookCallContext*>(userptr);
- const PropertySet* credUse=ctx->getCredentialUse();
- pair<bool,const char*> TLS=credUse ? credUse->getString("TLS") : pair<bool,const char*>(false,NULL);
- if (TLS.first) {
- OpenSSLCredentialResolver* cr=dynamic_cast<OpenSSLCredentialResolver*>(SPConfig::getConfig().getServiceProvider()->getCredentialResolver(TLS.second));
- if (cr) {
- xmltooling::Locker locker(cr);
- cr->attach(reinterpret_cast<SSL_CTX*>(ssl_ctx));
- }
- else
- log.error("unable to attach credentials to request using (%s), leaving anonymous",TLS.second);
- }
- else
- log.warn("no TLS credentials supplied, leaving anonymous");
-
- SSL_CTX_set_verify(reinterpret_cast<SSL_CTX*>(ssl_ctx),SSL_VERIFY_PEER,NULL);
-#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
- // With 0.9.7, we can pass a callback argument directly.
- SSL_CTX_set_cert_verify_callback(reinterpret_cast<SSL_CTX*>(ssl_ctx),verify_callback,userptr);
-#else
- // With 0.9.6, there's no argument, so we're going to use a really embarrassing hack and
- // stuff the argument in the depth property where it will get copied to the context object
- // that's handed to the callback.
- SSL_CTX_set_cert_verify_callback(
- reinterpret_cast<SSL_CTX*>(ssl_ctx),
- reinterpret_cast<int (*)()>(verify_callback),
- NULL
- );
- SSL_CTX_set_verify_depth(reinterpret_cast<SSL_CTX*>(ssl_ctx),reinterpret_cast<int>(userptr));
-
-#endif
- }
- catch (SAMLException& e) {
- log.error(string("caught a SAML exception while attaching credentials to request: ") + e.what());
- return false;
- }
-#ifndef _DEBUG
- catch (...) {
- log.error("caught an unknown exception while attaching credentials to request");
- return false;
- }
-#endif
-
- return true;
-}
-
-bool ShibHTTPHook::outgoing(HTTPClient* conn, void* globalCtx, void* callCtx)
-{
- // Sanity check...
- if (globalCtx != this)
- return false;
-
- // Clear authn status.
- reinterpret_cast<ShibHTTPHookCallContext*>(callCtx)->m_authenticated=false;
-
- // The callCtx is our nested context class. Copy in the parent pointer.
- reinterpret_cast<ShibHTTPHookCallContext*>(callCtx)->m_hook=this;
-
- // The hook function is called before connecting to the HTTP server. This
- // gives us a chance to attach our own SSL callback, and set a version header.
- if (!conn->setSSLCallback(ssl_ctx_callback,callCtx))
- return false;
-
- if (!conn->setRequestHeader("Shibboleth", PACKAGE_VERSION))
- return false;
- if (!conn->setRequestHeader("Xerces-C", XERCES_FULLVERSIONDOT))
- return false;
- if (!conn->setRequestHeader("XML-Security-C", XSEC_VERSION))
- return false;
- if (!conn->setRequestHeader("OpenSAML-C", OPENSAML_FULLVERSIONDOT))
- return false;
-
- // Check for HTTP authentication...
- const PropertySet* credUse=reinterpret_cast<ShibHTTPHookCallContext*>(callCtx)->getCredentialUse();
- pair<bool,const char*> authType=credUse ? credUse->getString("authType") : pair<bool,const char*>(false,NULL);
- if (authType.first) {
-#ifdef _DEBUG
- saml::NDC("outgoing");
-#endif
- Category& log=Category::getInstance(SHIBT_LOGCAT".ShibHTTPHook");
- HTTPClient::auth_t type=HTTPClient::auth_none;
- pair<bool,const char*> username=credUse->getString("authUsername");
- pair<bool,const char*> password=credUse->getString("authPassword");
- if (!username.first || !password.first) {
- log.error("HTTP authType (%s) specified but authUsername or authPassword was missing", authType.second);
- return false;
- }
- else if (!strcmp(authType.second,"basic"))
- type = HTTPClient::auth_basic;
- else if (!strcmp(authType.second,"digest"))
- type = HTTPClient::auth_digest;
- else if (!strcmp(authType.second,"ntlm"))
- type = HTTPClient::auth_ntlm;
- else if (!strcmp(authType.second,"gss"))
- type = HTTPClient::auth_gss;
- else {
- log.error("Unknown authType (%s) specified in CredentialUse element", authType.second);
- return false;
- }
- log.debug("configured for HTTP authentication (method=%s, username=%s)", authType.second, username.second);
- return conn->setAuth(type,username.second,password.second);
- }
-
- // The best we can do is assume authentication succeeds because when libcurl reuses
- // SSL and HTTP connections, no callback is made. Since we always authenticate SSL connections,
- // the caller should check that the protocol is https.
- reinterpret_cast<ShibHTTPHookCallContext*>(callCtx)->setAuthenticated();
- return true;
-}
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/*
- * hresult.h - Code definitions
-= */
-
-#ifndef __shibtargethresult_h__
-#define __shibtargethresult_h__
-
-#include <saml/hresult.h>
-
-/* Codes from 0x9000 - 0x9FFF in FACILITY_ITF are reserved for the Shibboleth SP */
-
-#define SHIBSP_E_FIRST MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,SAML_E_LAST + 0x0001)
-#define SHIBSP_E_LAST MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,SAML_E_LAST + 0x1000)
-
-#define SHIBSP_S_FIRST MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_ITF,SAML_S_LAST + 0x0001)
-#define SHIBSP_S_LAST MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_ITF,SAML_S_LAST + 0x1000
-
-/* Specific code definitions */
-
-#define SHIBSP_E_UNSPECIFIED (SHIBSP_E_FIRST + 0L)
-
-#define SESSION_E_ADDRESSMISMATCH (SHIBSP_E_FIRST + 1L)
-#define SESSION_E_EXPIRED (SHIBSP_E_FIRST + 2L)
-
-#endif
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/* internal.h - internally visible declarations
-
- Scott Cantor
- 6/29/03
-
- $History:$
-*/
-
-#ifndef __shibtarget_internal_h__
-#define __shibtarget_internal_h__
-
-#ifdef WIN32
-# define _CRT_SECURE_NO_DEPRECATE 1
-# define _CRT_NONSTDC_NO_DEPRECATE 1
-#endif
-
-#ifdef WIN32
-# define SHIBTARGET_EXPORTS __declspec(dllexport)
-#endif
-
-// eventually we might be able to support autoconf via cygwin...
-#if defined (_MSC_VER) || defined(__BORLANDC__)
-# include "config_win32.h"
-#else
-# include "config.h"
-#endif
-
-#include <shibsp/util/SPConstants.h>
-
-#include "shib-target.h"
-#include "hresult.h"
-
-#include <log4cpp/Category.hh>
-#include <log4cpp/FixedContextCategory.hh>
-#include <shibsp/exceptions.h>
-#include <xmltooling/PluginManager.h>
-#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/Threads.h>
-
-
-#define SHIBT_L(s) shibtarget::XML::Literals::s
-#define SHIBT_L_QNAME(p,s) shibtarget::XML::Literals::p##_##s
-#define SHIBT_LOGCAT "shibtarget"
-#define SHIBTRAN_LOGCAT "Shibboleth-TRANSACTION"
-
-namespace shibtarget {
- // ST-aware class that maps SAML artifacts to appropriate binding information
- class STArtifactMapper : public virtual saml::SAMLBrowserProfile::ArtifactMapper
- {
- public:
- STArtifactMapper(const IApplication* application) : m_app(application) {}
- virtual ~STArtifactMapper() {}
- saml::SAMLResponse* resolve(saml::SAMLRequest* request);
-
- private:
- const IApplication* m_app;
- };
-
- class STConfig : public ShibTargetConfig
- {
- public:
- STConfig() : m_tranLog(NULL), m_tranLogLock(NULL) {}
- ~STConfig() {}
-
- bool init(const char* schemadir);
- bool load(const char* config);
- void shutdown();
-
- log4cpp::Category& getTransactionLog() { m_tranLogLock->lock(); return *m_tranLog; }
- void releaseTransactionLog() { m_tranLogLock->unlock();}
- private:
- log4cpp::FixedContextCategory* m_tranLog;
- xmltooling::Mutex* m_tranLogLock;
- };
-
- // TODO: move this over to shibsp lib.
- xmltooling::PluginManager<shibsp::ServiceProvider,const DOMElement*>::Factory XMLServiceProviderFactory;
-}
-
-#endif
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
-// Used by shib-target.rc
-//
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 101
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1000
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/*
- * shib-ccache.cpp -- in-memory session cache plugin
- *
- * $Id$
- */
-
-#include "internal.h"
-
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include <ctime>
-#include <algorithm>
-#include <sstream>
-#include <stdexcept>
-#include <shibsp/SPConfig.h>
-
-#ifdef HAVE_LIBDMALLOCXX
-#include <dmalloc.h>
-#endif
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace saml;
-using namespace opensaml::saml2md;
-using namespace xmltooling;
-using namespace log4cpp;
-using namespace std;
-using xmlsignature::CredentialResolver;
-
-static const XMLCh cleanupInterval[] =
-{ chLatin_c, chLatin_l, chLatin_e, chLatin_a, chLatin_n, chLatin_u, chLatin_p,
- chLatin_I, chLatin_n, chLatin_t, chLatin_e, chLatin_r, chLatin_v, chLatin_a, chLatin_l, chNull
-};
-static const XMLCh cacheTimeout[] =
-{ chLatin_c, chLatin_a, chLatin_c, chLatin_h, chLatin_e,
- chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull
-};
-static const XMLCh AAConnectTimeout[] =
-{ chLatin_A, chLatin_A, chLatin_C, chLatin_o, chLatin_n, chLatin_n, chLatin_e, chLatin_c, chLatin_t,
- chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull
-};
-static const XMLCh AATimeout[] =
-{ chLatin_A, chLatin_A, chLatin_T, chLatin_i, chLatin_m, chLatin_e, chLatin_o, chLatin_u, chLatin_t, chNull };
-
-static const XMLCh defaultLifetime[] =
-{ chLatin_d, chLatin_e, chLatin_f, chLatin_a, chLatin_u, chLatin_l, chLatin_t,
- chLatin_L, chLatin_i, chLatin_f, chLatin_e, chLatin_t, chLatin_i, chLatin_m, chLatin_e, chNull
-};
-static const XMLCh retryInterval[] =
-{ chLatin_r, chLatin_e, chLatin_t, chLatin_r, chLatin_y,
- chLatin_I, chLatin_n, chLatin_t, chLatin_e, chLatin_r, chLatin_v, chLatin_a, chLatin_l, chNull
-};
-static const XMLCh strictValidity[] =
-{ chLatin_s, chLatin_t, chLatin_r, chLatin_i, chLatin_c, chLatin_t,
- chLatin_V, chLatin_a, chLatin_l, chLatin_i, chLatin_d, chLatin_i, chLatin_t, chLatin_y, chNull
-};
-static const XMLCh propagateErrors[] =
-{ chLatin_p, chLatin_r, chLatin_o, chLatin_p, chLatin_a, chLatin_g, chLatin_a, chLatin_t, chLatin_e,
- chLatin_E, chLatin_r, chLatin_r, chLatin_o, chLatin_r, chLatin_s, chNull
-};
-static const XMLCh writeThrough[] =
-{ chLatin_w, chLatin_r, chLatin_i, chLatin_t, chLatin_e,
- chLatin_T, chLatin_h, chLatin_r, chLatin_o, chLatin_u, chLatin_g, chLatin_h, chNull
-};
-
-
-/*
- * Stubbed out, inproc version of an ISessionCacheEntry
- */
-class StubCacheEntry : public virtual ISessionCacheEntry
-{
-public:
- StubCacheEntry(Category* log) : m_log(log), m_pSubject(NULL), m_pUnfiltered(NULL), m_pFiltered(NULL) {}
- StubCacheEntry(DDF& obj, Category* log)
- : m_log(log), m_obj(obj), m_pSubject(NULL), m_pUnfiltered(NULL), m_pFiltered(NULL) {}
- ~StubCacheEntry() { m_obj.destroy(); delete m_pSubject; delete m_pUnfiltered; delete m_pFiltered; }
- void lock() {}
- void unlock() { delete this; }
- const char* getClientAddress() const { return m_obj["client_address"].string(); }
- const char* getProviderId() const { return m_obj["provider_id"].string(); }
- const char* getAuthnContext() const { return m_obj["authn_context"].string(); }
- pair<const char*,const SAMLSubject*> getSubject(bool xml=true, bool obj=false) const;
- pair<const char*,const SAMLResponse*> getTokens(bool xml=true, bool obj=false) const;
- pair<const char*,const SAMLResponse*> getFilteredTokens(bool xml=true, bool obj=false) const;
-
-protected:
- Category* m_log;
- mutable DDF m_obj;
- mutable SAMLSubject* m_pSubject;
- mutable SAMLResponse* m_pUnfiltered;
- mutable SAMLResponse* m_pFiltered;
-};
-
-pair<const char*,const SAMLSubject*> StubCacheEntry::getSubject(bool xml, bool obj) const
-{
- const char* raw=m_obj["subject"].string();
- pair<const char*,const SAMLSubject*> ret=pair<const char*,const SAMLSubject*>(NULL,NULL);
- if (xml)
- ret.first=raw;
- if (obj) {
- if (!m_pSubject) {
- istringstream in(raw);
- m_log->debugStream() << "decoding subject: " << (raw ? raw : "(none)") << CategoryStream::ENDLINE;
- m_pSubject=raw ? new SAMLSubject(in) : NULL;
- }
- ret.second=m_pSubject;
- }
- return ret;
-}
-
-pair<const char*,const SAMLResponse*> StubCacheEntry::getTokens(bool xml, bool obj) const
-{
- const char* unfiltered=m_obj["tokens.unfiltered"].string();
- pair<const char*,const SAMLResponse*> ret = pair<const char*,const SAMLResponse*>(NULL,NULL);
- if (xml)
- ret.first=unfiltered;
- if (obj) {
- if (!m_pUnfiltered) {
- if (unfiltered) {
- istringstream in(unfiltered);
- m_log->debugStream() << "decoding unfiltered tokens: " << unfiltered << CategoryStream::ENDLINE;
- m_pUnfiltered=new SAMLResponse(in,m_obj["minor_version"].integer());
- }
- }
- ret.second=m_pUnfiltered;
- }
- return ret;
-}
-
-pair<const char*,const SAMLResponse*> StubCacheEntry::getFilteredTokens(bool xml, bool obj) const
-{
- const char* filtered=m_obj["tokens.filtered"].string();
- if (!filtered)
- return getTokens(xml,obj);
- pair<const char*,const SAMLResponse*> ret = pair<const char*,const SAMLResponse*>(NULL,NULL);
- if (xml)
- ret.first=filtered;
- if (obj) {
- if (!m_pFiltered) {
- istringstream in(filtered);
- m_log->debugStream() << "decoding filtered tokens: " << filtered << CategoryStream::ENDLINE;
- m_pFiltered=new SAMLResponse(in,m_obj["minor_version"].integer());
- }
- ret.second=m_pFiltered;
- }
- return ret;
-}
-
-/*
- * Remoting front-half of session cache, drops out in single process deployments.
- * TODO: Add buffering of frequently-used entries.
- */
-class StubCache : public virtual ISessionCache
-{
-public:
- StubCache(const DOMElement* e);
-
- string insert(
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const SAMLSubject* subject,
- const char* authnContext,
- const SAMLResponse* tokens
- );
- ISessionCacheEntry* find(const char* key, const IApplication* application, const char* client_addr);
- void remove(const char* key, const IApplication* application, const char* client_addr);
-
- bool setBackingStore(ISessionCacheStore*) { return false; }
-
-private:
- Category* m_log;
-};
-
-StubCache::StubCache(const DOMElement* e) : m_log(&Category::getInstance(SHIBT_LOGCAT".SessionCache")) {}
-
-/*
- * The public methods are remoted using the message passing system.
- * In practice, insert is unlikely to be used remotely, but just in case...
- */
-
-string StubCache::insert(
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const SAMLSubject* subject,
- const char* authnContext,
- const SAMLResponse* tokens
- )
-{
- DDF in("SessionCache::insert"),out;
- DDFJanitor jin(in),jout(out);
- in.structure();
- in.addmember("application_id").string(application->getId());
- in.addmember("client_address").string(client_addr);
- xmltooling::auto_ptr_char provid(dynamic_cast<EntityDescriptor*>(role->getParent())->getEntityID());
- in.addmember("provider_id").string(provid.get());
- in.addmember("major_version").integer(1);
- in.addmember("minor_version").integer(tokens->getMinorVersion());
- in.addmember("authn_context").string(authnContext);
-
- ostringstream os;
- os << *subject;
- in.addmember("subject").string(os.str().c_str());
- os.str("");
- os << *tokens;
- in.addmember("tokens.unfiltered").string(os.str().c_str());
-
- out=SPConfig::getConfig().getServiceProvider()->getListenerService()->send(in);
- if (out["key"].isstring())
- return out["key"].string();
- throw opensaml::RetryableProfileException("A remoted cache insertion operation did not return a usable session key.");
-}
-
-ISessionCacheEntry* StubCache::find(const char* key, const IApplication* application, const char* client_addr)
-{
- DDF in("SessionCache::find"),out;
- DDFJanitor jin(in);
- in.structure();
- in.addmember("key").string(key);
- in.addmember("application_id").string(application->getId());
- in.addmember("client_address").string(client_addr);
-
- try {
- out=SPConfig::getConfig().getServiceProvider()->getListenerService()->send(in);
- if (!out.isstruct()) {
- out.destroy();
- return NULL;
- }
-
- // Wrap the results in a stub entry and return it to the caller.
- return new StubCacheEntry(out,m_log);
- }
- catch (...) {
- out.destroy();
- throw;
- }
-}
-
-void StubCache::remove(const char* key, const IApplication* application, const char* client_addr)
-{
- DDF in("SessionCache::remove");
- DDFJanitor jin(in);
- in.structure();
- in.addmember("key").string(key);
- in.addmember("application_id").string(application->getId());
- in.addmember("client_address").string(client_addr);
-
- SPConfig::getConfig().getServiceProvider()->getListenerService()->send(in);
-}
-
-/*
- * Long-lived cache entries that store the actual sessions and
- * wrap attribute query/refresh/filtering
- */
-class MemorySessionCache;
-class MemorySessionCacheEntry : public virtual ISessionCacheEntry, public virtual StubCacheEntry
-{
-public:
- MemorySessionCacheEntry(
- MemorySessionCache* cache,
- const char* key,
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const SAMLSubject* subject,
- const char* authnContext,
- const SAMLResponse* tokens
- );
- MemorySessionCacheEntry(
- MemorySessionCache* cache,
- const char* key,
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const char* subject,
- const char* authnContext,
- const char* tokens,
- int majorVersion,
- int minorVersion,
- time_t created,
- time_t accessed
- );
- ~MemorySessionCacheEntry();
-
- void lock() { m_lock->lock(); }
- void unlock() { m_lock->unlock(); }
-
- HRESULT isValid(const IApplication* application, const char* client_addr) const;
- void populate(const IApplication* application, const EntityDescriptor* source, bool initial=false) const;
- bool checkApplication(const IApplication* application) { return (m_obj["application_id"]==application->getId()); }
- time_t created() const { return m_sessionCreated; }
- time_t lastAccess() const { return m_lastAccess; }
- const DDF& getDDF() const { return m_obj; }
-
-private:
- bool hasAttributes(const SAMLResponse& r) const;
- time_t calculateExpiration(const SAMLResponse& r) const;
- pair<SAMLResponse*,SAMLResponse*> getNewResponse(const IApplication* application, const EntityDescriptor* source) const;
- SAMLResponse* filter(const SAMLResponse* r, const IApplication* application, const RoleDescriptor* role) const;
-
- time_t m_sessionCreated;
- mutable time_t m_responseExpiration, m_lastAccess, m_lastRetry;
-
- MemorySessionCache* m_cache;
- Mutex* m_lock;
-};
-
-/*
- * The actual in-memory session cache implementation.
- */
-class MemorySessionCache : public virtual ISessionCache, public virtual Remoted
-{
-public:
- MemorySessionCache(const DOMElement* e);
- virtual ~MemorySessionCache();
-
- DDF receive(const DDF& in);
-
- string insert(
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const SAMLSubject* subject,
- const char* authnContext,
- const SAMLResponse* tokens
- );
- ISessionCacheEntry* find(const char* key, const IApplication* application, const char* client_addr);
- void remove(const char* key, const IApplication* application, const char* client_addr);
-
- void cleanup();
-
- bool setBackingStore(ISessionCacheStore* store);
-
-private:
- const DOMElement* m_root; // Only valid during initialization
- RWLock* m_lock;
- map<string,MemorySessionCacheEntry*> m_hashtable;
-
- Category* m_log;
- Remoted* restoreInsert;
- Remoted* restoreFind;
- Remoted* restoreRemove;
- ISessionCacheStore* m_sink;
-
- void dormant(const char* key);
- static void* cleanup_fcn(void*);
- bool shutdown;
- CondWait* shutdown_wait;
- Thread* cleanup_thread;
-
- // extracted config settings
- unsigned int m_AATimeout,m_AAConnectTimeout;
- unsigned int m_defaultLifetime,m_retryInterval;
- bool m_strictValidity,m_propagateErrors,m_writeThrough;
- friend class MemorySessionCacheEntry;
-};
-
-MemorySessionCacheEntry::MemorySessionCacheEntry(
- MemorySessionCache* cache,
- const char* key,
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const SAMLSubject* subject,
- const char* authnContext,
- const SAMLResponse* tokens
- ) : StubCacheEntry(cache->m_log), m_cache(cache), m_responseExpiration(0), m_lastRetry(0)
-{
- m_sessionCreated = m_lastAccess = time(NULL);
-
- // Store session properties in DDF.
- m_obj=DDF(NULL).structure();
- m_obj.addmember("key").string(key);
- m_obj.addmember("client_address").string(client_addr);
- m_obj.addmember("application_id").string(application->getId());
- xmltooling::auto_ptr_char pid(dynamic_cast<EntityDescriptor*>(role->getParent())->getEntityID());
- m_obj.addmember("provider_id").string(pid.get());
- m_obj.addmember("major_version").integer(1);
- m_obj.addmember("minor_version").integer(tokens->getMinorVersion());
-
- // Save the subject as XML.
- ostringstream os;
- os << *subject;
- m_obj.addmember("subject").string(os.str().c_str());
-
- // Save the authn method.
- m_obj.addmember("authn_context").string(authnContext);
-
- // Serialize unfiltered assertions.
- os.str("");
- os << *tokens;
- m_obj.addmember("tokens.unfiltered").string(os.str().c_str());
-
- if (hasAttributes(*tokens)) {
- // Filter attributes in the response.
- auto_ptr<SAMLResponse> filtered(filter(tokens, application, role));
-
- // Calculate expiration.
- m_responseExpiration=calculateExpiration(*(filtered.get()));
-
- // Serialize filtered assertions (if changes were made).
- os.str("");
- os << *(filtered.get());
- string fstr=os.str();
- if (fstr.length() != m_obj["tokens.unfiltered"].strlen())
- m_obj.addmember("tokens.filtered").string(fstr.c_str());
-
- // Save actual objects only if we're running inprocess. The subject needs to be
- // owned by the entry, so we'll defer creation of a cloned copy.
- if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
- if (m_obj["tokens.filtered"].isstring())
- m_pFiltered=filtered.release();
- }
- }
-
- m_lock = Mutex::create();
-
- if (m_log->isDebugEnabled()) {
- m_log->debug("new cache entry created: SessionID (%s) IdP (%s) Address (%s)", key, pid.get(), client_addr);
- }
-
- // Transaction Logging
- xmltooling::auto_ptr_char hname(subject->getNameIdentifier()->getName());
- STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
- stc.getTransactionLog().infoStream() <<
- "New session (ID: " <<
- key <<
- ") with (applicationId: " <<
- application->getId() <<
- ") for principal from (IdP: " <<
- pid.get() <<
- ") at (ClientAddress: " <<
- client_addr <<
- ") with (NameIdentifier: " <<
- hname.get() <<
- ")";
- stc.releaseTransactionLog();
-}
-
-MemorySessionCacheEntry::MemorySessionCacheEntry(
- MemorySessionCache* cache,
- const char* key,
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const char* subject,
- const char* authnContext,
- const char* tokens,
- int majorVersion,
- int minorVersion,
- time_t created,
- time_t accessed
- ) : StubCacheEntry(cache->m_log), m_cache(cache), m_responseExpiration(0), m_lastRetry(0)
-{
- m_sessionCreated = created;
- m_lastAccess = accessed;
-
- // Reconstitute the tokens for filtering.
- istringstream is(tokens);
- auto_ptr<SAMLResponse> unfiltered(new SAMLResponse(is,minorVersion));
-
- // Store session properties in DDF.
- m_obj=DDF(NULL).structure();
- m_obj.addmember("key").string(key);
- m_obj.addmember("client_address").string(client_addr);
- m_obj.addmember("application_id").string(application->getId());
- xmltooling::auto_ptr_char pid(dynamic_cast<EntityDescriptor*>(role->getParent())->getEntityID());
- m_obj.addmember("provider_id").string(pid.get());
- m_obj.addmember("subject").string(subject);
- m_obj.addmember("authn_context").string(authnContext);
- m_obj.addmember("tokens.unfiltered").string(tokens);
- m_obj.addmember("major_version").integer(majorVersion);
- m_obj.addmember("minor_version").integer(minorVersion);
-
- if (hasAttributes(*(unfiltered.get()))) {
- auto_ptr<SAMLResponse> filtered(filter(unfiltered.get(), application, role));
-
- // Calculate expiration.
- m_responseExpiration=calculateExpiration(*(filtered.get()));
-
- // Serialize filtered assertions (if changes were made).
- ostringstream os;
- os << *(filtered.get());
- string fstr=os.str();
- if (fstr.length() != strlen(tokens))
- m_obj.addmember("tokens.filtered").string(fstr.c_str());
-
- // Save actual objects only if we're running inprocess.
- if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
- m_pUnfiltered=unfiltered.release();
- if (m_obj["tokens.filtered"].isstring())
- m_pFiltered=filtered.release();
- }
- }
-
- m_lock = Mutex::create();
-
- if (m_log->isDebugEnabled())
- m_log->debug("session loaded from secondary cache (ID: %s)", key);
-}
-
-
-MemorySessionCacheEntry::~MemorySessionCacheEntry()
-{
- delete m_lock;
-}
-
-HRESULT MemorySessionCacheEntry::isValid(const IApplication* app, const char* client_addr) const
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("isValid");
-#endif
-
- // Obtain validation rules from application settings.
- bool consistentIPAddress=true;
- int lifetime=0,timeout=0;
- const PropertySet* props=app->getPropertySet("Sessions");
- if (props) {
- pair<bool,unsigned int> p=props->getUnsignedInt("lifetime");
- if (p.first)
- lifetime = p.second;
- p=props->getUnsignedInt("timeout");
- if (p.first)
- timeout = p.second;
- pair<bool,bool> pcheck=props->getBool("consistentIPAddress");
- if (pcheck.first)
- consistentIPAddress = pcheck.second;
- }
-
- if (m_log->isDebugEnabled())
- m_log->debug("checking validity of session (ID: %s)", m_obj["key"].string());
-
- time_t now=time(NULL);
- if (lifetime > 0 && now > m_sessionCreated+lifetime) {
- if (m_log->isInfoEnabled())
- m_log->info("session expired (ID: %s)", m_obj["key"].string());
- return SESSION_E_EXPIRED;
- }
-
- if (timeout > 0 && now-m_lastAccess >= timeout) {
- // May need to query sink first to find out if another cluster member has been used.
- if (m_cache->m_sink && m_cache->m_writeThrough) {
- if (NOERROR!=m_cache->m_sink->onRead(m_obj["key"].string(),m_lastAccess))
- m_log->error("cache store failed to return last access timestamp");
- if (now-m_lastAccess >= timeout) {
- m_log->info("session timed out (ID: %s)", m_obj["key"].string());
- return SESSION_E_EXPIRED;
- }
- }
- else {
- m_log->info("session timed out (ID: %s)", m_obj["key"].string());
- return SESSION_E_EXPIRED;
- }
- }
-
- if (consistentIPAddress) {
- if (m_log->isDebugEnabled())
- m_log->debug("comparing client address %s against %s", client_addr, getClientAddress());
- if (strcmp(client_addr, getClientAddress())) {
- m_log->debug("client address mismatch");
- return SESSION_E_ADDRESSMISMATCH;
- }
- }
-
- m_lastAccess=now;
-
- if (m_cache->m_sink && m_cache->m_writeThrough && timeout > 0) {
- // Update sink with last access data, if possible.
- if (FAILED(m_cache->m_sink->onUpdate(m_obj["key"].string(),NULL,m_lastAccess)))
- m_log->error("cache store failed to update last access timestamp");
- }
-
- return NOERROR;
-}
-
-bool MemorySessionCacheEntry::hasAttributes(const SAMLResponse& r) const
-{
- Iterator<SAMLAssertion*> assertions=r.getAssertions();
- while (assertions.hasNext()) {
- Iterator<SAMLStatement*> statements=assertions.next()->getStatements();
- while (statements.hasNext()) {
- if (dynamic_cast<SAMLAttributeStatement*>(statements.next()))
- return true;
- }
- }
- return false;
-}
-
-time_t MemorySessionCacheEntry::calculateExpiration(const SAMLResponse& r) const
-{
- time_t expiration=0;
- Iterator<SAMLAssertion*> assertions = r.getAssertions();
- while (assertions.hasNext()) {
- SAMLAssertion* assertion = assertions.next();
-
- // Only examine this assertion if it contains an attribute statement.
- // We know at least one such statement exists, or this is a query response.
- Iterator<SAMLStatement*> statements = assertion->getStatements();
- while (statements.hasNext()) {
- if (dynamic_cast<SAMLAttributeStatement*>(statements.next())) {
- const SAMLDateTime* thistime = assertion->getNotOnOrAfter();
-
- // If there is no time, then just continue and ignore this assertion.
- if (thistime) {
- // If this is a tighter expiration, cache it.
- if (expiration == 0 || thistime->getEpoch() < expiration)
- expiration = thistime->getEpoch();
- }
-
- // No need to continue with this assertion.
- break;
- }
- }
- }
-
- // If we didn't find any assertions with times, then use the default.
- if (expiration == 0)
- expiration = time(NULL) + m_cache->m_defaultLifetime;
-
- return expiration;
-}
-
-void MemorySessionCacheEntry::populate(const IApplication* application, const EntityDescriptor* source, bool initial) const
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("populate");
-#endif
-
- // Do we have any attribute data cached?
- if (m_responseExpiration > 0) {
- // Can we use what we have?
- if (time(NULL) < m_responseExpiration)
- return;
-
- // Possibly check the sink in case another cluster member already refreshed it.
- if (m_cache->m_sink && m_cache->m_writeThrough) {
- string tokensFromSink;
- HRESULT hr=m_cache->m_sink->onRead(m_obj["key"].string(),tokensFromSink);
- if (FAILED(hr))
- m_log->error("cache store failed to return updated tokens");
- else if (hr==NOERROR && tokensFromSink!=m_obj["tokens.unfiltered"].string()) {
-
- // Bah...find role again.
- const RoleDescriptor* role=source->getAttributeAuthorityDescriptor(samlconstants::SAML11_PROTOCOL_ENUM);
- if (!role)
- role=source->getAttributeAuthorityDescriptor(samlconstants::SAML10_PROTOCOL_ENUM);
- if (!role)
- role=source->getIDPSSODescriptor(samlconstants::SAML11_PROTOCOL_ENUM);
- if (!role)
- role=source->getIDPSSODescriptor(samlconstants::SAML10_PROTOCOL_ENUM);
- if (!role) {
- throw MetadataException("Unable to locate attribute-issuing role in metadata.");
- }
-
- // The tokens in the sink were different.
- istringstream is(tokensFromSink);
- auto_ptr<SAMLResponse> respFromSink(new SAMLResponse(is,m_obj["minor_version"].integer()));
- auto_ptr<SAMLResponse> filteredFromSink(filter(respFromSink.get(),application,role));
- time_t expFromSink=calculateExpiration(*(filteredFromSink.get()));
-
- // Recheck to see if the new tokens are valid.
- if (expFromSink < time(NULL)) {
- m_log->info("loading replacement tokens into memory from cache store");
- m_obj["tokens"].destroy();
- delete m_pUnfiltered;
- delete m_pFiltered;
- m_pUnfiltered=m_pFiltered=NULL;
- m_obj.addmember("tokens.unfiltered").string(tokensFromSink.c_str());
-
- // Serialize filtered assertions (if changes were made).
- ostringstream os;
- os << *(filteredFromSink.get());
- string fstr=os.str();
- if (fstr.length() != m_obj.getmember("tokens.unfiltered").strlen())
- m_obj.addmember("tokens.filtered").string(fstr.c_str());
-
- // Save actual objects only if we're running inprocess.
- if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
- m_pUnfiltered=respFromSink.release();
- if (m_obj["tokens.filtered"].isstring())
- m_pFiltered=filteredFromSink.release();
- }
-
- m_responseExpiration=expFromSink;
- m_lastRetry=0;
- return;
- }
- }
- }
-
- // If we're being strict, dump what we have and reset timestamps.
- if (m_cache->m_strictValidity) {
- m_log->info("strictly enforcing attribute validity, dumping expired data");
- m_obj["tokens"].destroy();
- delete m_pUnfiltered;
- delete m_pFiltered;
- m_pUnfiltered=m_pFiltered=NULL;
- m_responseExpiration=0;
- m_lastRetry=0;
- if (m_cache->m_sink) {
- if (FAILED(m_cache->m_sink->onUpdate(m_obj["key"].string(),"")))
- m_log->error("cache store returned failure while clearing tokens from entry");
- }
- }
- }
-
- try {
- pair<SAMLResponse*,SAMLResponse*> new_responses=getNewResponse(application,source);
- auto_ptr<SAMLResponse> r1(new_responses.first),r2(new_responses.second);
- if (new_responses.first) {
- m_obj["tokens"].destroy();
- delete m_pUnfiltered;
- delete m_pFiltered;
- m_pUnfiltered=m_pFiltered=NULL;
- m_responseExpiration=0;
-
- // Serialize unfiltered assertions.
- ostringstream os;
- os << *new_responses.first;
- m_obj.addmember("tokens.unfiltered").string(os.str().c_str());
-
- // Serialize filtered assertions (if changes were made).
- os.str("");
- os << *new_responses.second;
- string fstr=os.str();
- if (fstr.length() != m_obj.getmember("tokens.unfiltered").strlen())
- m_obj.addmember("tokens.filtered").string(fstr.c_str());
-
- // Update expiration.
- m_responseExpiration=calculateExpiration(*new_responses.second);
-
- // Save actual objects only if we're running inprocess.
- if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
- m_pUnfiltered=r1.release();
- if (m_obj["tokens.filtered"].isstring())
- m_pFiltered=r2.release();
- }
-
- // Update backing store.
- if (!initial && m_cache->m_sink) {
- if (FAILED(m_cache->m_sink->onUpdate(m_obj["key"].string(),m_obj["tokens.unfiltered"].string())))
- m_log->error("cache store returned failure while updating tokens in entry");
- }
-
- m_lastRetry=0;
- m_log->debug("fetched and stored new response");
- STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
- stc.getTransactionLog().infoStream() << "Successful attribute query for session (ID: " << m_obj["key"].string() << ")";
- stc.releaseTransactionLog();
- }
- }
- catch (exception&) {
- if (m_cache->m_propagateErrors)
- throw;
- m_log->warn("suppressed exception caught while trying to fetch attributes");
- }
-#ifndef _DEBUG
- catch (...) {
- if (m_cache->m_propagateErrors)
- throw;
- m_log->warn("suppressed unknown exception caught while trying to fetch attributes");
- }
-#endif
-}
-
-pair<SAMLResponse*,SAMLResponse*> MemorySessionCacheEntry::getNewResponse(
- const IApplication* application, const EntityDescriptor* source
- ) const
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("getNewResponse");
-#endif
-
- // The retryInterval determines how often to poll an AA that might be down.
- time_t now=time(NULL);
- if ((now - m_lastRetry) < m_cache->m_retryInterval)
- return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
- if (m_lastRetry)
- m_log->debug("retry interval exceeded, trying for attributes again");
- m_lastRetry=now;
-
- m_log->info("trying to get new attributes for session (ID: %s)", m_obj["key"].string());
-
- // Transaction Logging
- STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
- stc.getTransactionLog().infoStream() <<
- "Making attribute query for session (ID: " <<
- m_obj["key"].string() <<
- ") on (applicationId: " <<
- m_obj["application_id"].string() <<
- ") for principal from (IdP: " <<
- m_obj["provider_id"].string() <<
- ")";
- stc.releaseTransactionLog();
-
-
- pair<bool,const XMLCh*> providerID=application->getXMLString("providerId");
- if (!providerID.first) {
- m_log->crit("unable to determine ProviderID for application, not set?");
- throw ConfigurationException("Unable to determine ProviderID for application, not set?");
- }
-
- // Try to locate an AA role.
- const AttributeAuthorityDescriptor* AA=source->getAttributeAuthorityDescriptor(
- m_obj["minor_version"].integer()==1 ? samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM
- );
- if (!AA) {
- m_log->warn("unable to locate metadata for identity provider's Attribute Authority");
- return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
- }
-
- // Get protocol signing policy.
- const PropertySet* credUse=application->getCredentialUse(source);
- pair<bool,bool> signRequest=credUse ? credUse->getBool("signRequest") : make_pair(false,false);
- pair<bool,const char*> signatureAlg=credUse ? credUse->getString("signatureAlg") : pair<bool,const char*>(false,NULL);
- if (!signatureAlg.first)
- signatureAlg.second=URI_ID_RSA_SHA1;
- pair<bool,const char*> digestAlg=credUse ? credUse->getString("digestAlg") : pair<bool,const char*>(false,NULL);
- if (!digestAlg.first)
- digestAlg.second=URI_ID_SHA1;
- pair<bool,bool> signedResponse=credUse ? credUse->getBool("signedResponse") : make_pair(false,false);
- pair<bool,const char*> signingCred=credUse ? credUse->getString("Signing") : pair<bool,const char*>(false,NULL);
-
- SAMLResponse* response = NULL;
- try {
- // Copy NameID from subject (may need to reconstitute it).
- SAMLNameIdentifier* nameid=NULL;
- if (m_pSubject)
- nameid=static_cast<SAMLNameIdentifier*>(m_pSubject->getNameIdentifier()->clone());
- else {
- istringstream instr(m_obj["subject"].string());
- auto_ptr<SAMLSubject> sub(new SAMLSubject(instr));
- nameid=static_cast<SAMLNameIdentifier*>(sub->getNameIdentifier()->clone());
- }
-
- // Build a SAML Request....
- SAMLAttributeQuery* q=new SAMLAttributeQuery(
- new SAMLSubject(nameid),
- providerID.second
- );
- auto_ptr<SAMLRequest> req(new SAMLRequest(q));
- req->setMinorVersion(m_obj["minor_version"].integer());
-
- // Sign it?
- if (signRequest.first && signRequest.second && signingCred.first) {
- if (req->getMinorVersion()==1) {
- CredentialResolver* cr=SPConfig::getConfig().getServiceProvider()->getCredentialResolver(signingCred.second);
- if (cr) {
- xmltooling::Locker locker(cr);
- req->sign(cr->getKey(),cr->getCertificates(),signatureAlg.second,digestAlg.second);
- }
- else
- m_log->error("unable to sign attribute query, specified credential (%s) was not found",signingCred.second);
- }
- else
- m_log->error("unable to sign SAML 1.0 attribute query, only SAML 1.1 defines signing adequately");
- }
-
- m_log->debug("trying to query an AA...");
-
- // Call context object
- ShibHTTPHook::ShibHTTPHookCallContext ctx(credUse,AA);
-
- // Use metadata to locate endpoints.
- const vector<AttributeService*>& endpoints=AA->getAttributeServices();
- for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {
- try {
- // Get a binding object for this protocol.
- const SAMLBinding* binding = application->getBinding((*ep)->getBinding());
- if (!binding) {
- xmltooling::auto_ptr_char prot((*ep)->getBinding());
- m_log->warn("skipping binding on unsupported protocol (%s)", prot.get());
- continue;
- }
- static const XMLCh https[] = {chLatin_h, chLatin_t, chLatin_t, chLatin_p, chLatin_s, chColon, chNull};
- auto_ptr<SAMLResponse> r(binding->send((*ep)->getLocation(), *(req.get()), &ctx));
- if (r->isSigned()) {
- // TODO: trust stuff will be changing anyway...
- //if (!t.validate(*r,AA))
- // throw TrustException("Unable to verify signed response message.");
- }
- else if (!ctx.isAuthenticated() || XMLString::compareNString((*ep)->getLocation(),https,6))
- throw XMLSecurityException("Response message was unauthenticated.");
- response = r.release();
- }
- catch (exception& e) {
- m_log->error("caught exception during SAML attribute query: %s", e.what());
- }
- }
-
- if (response) {
- if (signedResponse.first && signedResponse.second && !response->isSigned()) {
- delete response;
- m_log->error("unsigned response obtained, but we were told it must be signed.");
- throw XMLSecurityException("Unable to obtain a signed response message.");
- }
-
- // Iterate over the tokens and apply basic validation.
- time_t now=time(NULL);
- Iterator<SAMLAssertion*> assertions=response->getAssertions();
- for (unsigned int a=0; a<assertions.size();) {
- // Discard any assertions not issued by the right entity.
- if (XMLString::compareString(source->getEntityID(),assertions[a]->getIssuer())) {
- xmltooling::auto_ptr_char bad(assertions[a]->getIssuer());
- m_log->warn("discarding assertion not issued by (%s), instead by (%s)",m_obj["provider_id"].string(),bad.get());
- response->removeAssertion(a);
- continue;
- }
-
- // Validate the token.
- try {
- application->validateToken(assertions[a],now,AA,application->getTrustEngine());
- a++;
- }
- catch (exception&) {
- m_log->warn("assertion failed to validate, removing it from response");
- response->removeAssertion(a);
- }
- }
-
- // Run it through the filter.
- return make_pair(response,filter(response,application,AA));
- }
- }
- catch (exception& e) {
- m_log->error("caught exception during query to AA: %s", e.what());
- throw;
- }
-
- m_log->error("no response obtained");
- return pair<SAMLResponse*,SAMLResponse*>(NULL,NULL);
-}
-
-SAMLResponse* MemorySessionCacheEntry::filter(
- const SAMLResponse* r, const IApplication* application, const RoleDescriptor* role
- ) const
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("filter");
-#endif
-
- // Make a copy of the original and process that against the AAP.
- auto_ptr<SAMLResponse> copy(static_cast<SAMLResponse*>(r->clone()));
- copy->toDOM();
-
- Iterator<SAMLAssertion*> copies=copy->getAssertions();
- for (unsigned long j=0; j < copies.size();) {
- try {
- // Finally, filter the content.
- shibboleth::AAP::apply(application->getAAPProviders(),*(copies[j]),role);
- j++;
-
- }
- catch (exception&) {
- m_log->info("no statements remain after AAP, removing assertion");
- copy->removeAssertion(j);
- }
- }
-
- // Audit the results.
- STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
- Category& tran=stc.getTransactionLog();
- if (tran.isInfoEnabled()) {
- tran.infoStream() <<
- "Caching the following attributes after AAP applied for session (ID: " <<
- m_obj["key"].string() <<
- ") on (applicationId: " <<
- m_obj["application_id"].string() <<
- ") for principal from (IdP: " <<
- m_obj["provider_id"].string() <<
- ") {";
-
- Iterator<SAMLAssertion*> loggies=copy->getAssertions();
- while (loggies.hasNext()) {
- SAMLAssertion* logit=loggies.next();
- Iterator<SAMLStatement*> states=logit->getStatements();
- while (states.hasNext()) {
- SAMLAttributeStatement* state=dynamic_cast<SAMLAttributeStatement*>(states.next());
- Iterator<SAMLAttribute*> attrs=state ? state->getAttributes() : EMPTY(SAMLAttribute*);
- while (attrs.hasNext()) {
- SAMLAttribute* attr=attrs.next();
- xmltooling::auto_ptr_char attrname(attr->getName());
- tran.infoStream() << "\t" << attrname.get() << " (" << attr->getValues().size() << " values)";
- }
- }
- }
- tran.info("}");
- }
- stc.releaseTransactionLog();
-
- return copy.release();
-}
-
-MemorySessionCache::MemorySessionCache(const DOMElement* e)
- : m_root(e), m_AATimeout(30), m_AAConnectTimeout(15), m_defaultLifetime(1800), m_retryInterval(300),
- m_strictValidity(true), m_propagateErrors(false), m_writeThrough(false), m_lock(RWLock::create()),
- m_log(&Category::getInstance(SHIBT_LOGCAT".SessionCache")),
- restoreInsert(NULL), restoreFind(NULL), restoreRemove(NULL), m_sink(NULL)
-{
- if (m_root) {
- const XMLCh* tag=m_root->getAttributeNS(NULL,AATimeout);
- if (tag && *tag) {
- m_AATimeout = XMLString::parseInt(tag);
- if (!m_AATimeout)
- m_AATimeout=30;
- }
-
- tag=m_root->getAttributeNS(NULL,AAConnectTimeout);
- if (tag && *tag) {
- m_AAConnectTimeout = XMLString::parseInt(tag);
- if (!m_AAConnectTimeout)
- m_AAConnectTimeout=15;
- }
-
- tag=m_root->getAttributeNS(NULL,defaultLifetime);
- if (tag && *tag) {
- m_defaultLifetime = XMLString::parseInt(tag);
- if (!m_defaultLifetime)
- m_defaultLifetime=1800;
- }
-
- tag=m_root->getAttributeNS(NULL,retryInterval);
- if (tag && *tag) {
- m_retryInterval = XMLString::parseInt(tag);
- if (!m_retryInterval)
- m_retryInterval=300;
- }
-
- tag=m_root->getAttributeNS(NULL,strictValidity);
- if (tag && (*tag==chDigit_0 || *tag==chLatin_f))
- m_strictValidity=false;
-
- tag=m_root->getAttributeNS(NULL,propagateErrors);
- if (tag && (*tag==chDigit_1 || *tag==chLatin_t))
- m_propagateErrors=true;
-
- tag=m_root->getAttributeNS(NULL,writeThrough);
- if (tag && (*tag==chDigit_1 || *tag==chLatin_t))
- m_writeThrough=true;
- }
-
- SAMLConfig::getConfig().timeout = m_AATimeout;
- SAMLConfig::getConfig().conn_timeout = m_AAConnectTimeout;
-
- // Register for remoted messages.
- ListenerService* listener=SPConfig::getConfig().getServiceProvider()->getListenerService(false);
- if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
- restoreInsert=listener->regListener("SessionCache::insert",this);
- restoreFind=listener->regListener("SessionCache::find",this);
- restoreRemove=listener->regListener("SessionCache::remove",this);
- }
- else
- m_log->info("no listener interface available, cache remoting is disabled");
-
- shutdown_wait = CondWait::create();
- shutdown = false;
- cleanup_thread = Thread::create(&cleanup_fcn, (void*)this);
-}
-
-MemorySessionCache::~MemorySessionCache()
-{
- // Shut down the cleanup thread and let it know...
- shutdown = true;
- shutdown_wait->signal();
- cleanup_thread->join(NULL);
-
- // Unregister remoted messages.
- ListenerService* listener=SPConfig::getConfig().getServiceProvider()->getListenerService(false);
- if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
- listener->unregListener("SessionCache::insert",this,restoreInsert);
- listener->unregListener("SessionCache::find",this,restoreFind);
- listener->unregListener("SessionCache::remove",this,restoreRemove);
- }
-
- for_each(m_hashtable.begin(),m_hashtable.end(),xmltooling::cleanup_pair<string,MemorySessionCacheEntry>());
- delete m_lock;
- delete shutdown_wait;
-}
-
-bool MemorySessionCache::setBackingStore(ISessionCacheStore* store)
-{
- if (m_sink && store!=m_sink)
- return false;
- m_sink=store;
- return true;
-}
-
-/*
- * IPC message definitions:
- *
- * SessionCache::insert
- *
- * IN
- * application_id
- * client_address
- * provider_id
- * major_version
- * minor_version
- * authn_context
- * subject
- * tokens.unfiltered
- *
- * OUT
- * key
- *
- * SessionCache::find
- *
- * IN
- * key
- * application_id
- * client_address
- *
- * OUT
- * client_address
- * provider_id
- * major_version
- * minor_version
- * authn_context
- * subject
- * tokens.unfiltered
- * tokens.filtered
- *
- * SessionCache::remove
- *
- * IN
- * key
- * application_id
- * client_address
- */
-
-DDF MemorySessionCache::receive(const DDF& in)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("receive");
-#endif
-
- // Find application.
- xmltooling::Locker confLocker(SPConfig::getConfig().getServiceProvider());
- const char* aid=in["application_id"].string();
- const IApplication* app=aid ? dynamic_cast<const IApplication*>(SPConfig::getConfig().getServiceProvider()->getApplication(aid)) : NULL;
- if (!app) {
- // Something's horribly wrong.
- m_log->error("couldn't find application (%s) for session", aid ? aid : "(missing)");
- throw ConfigurationException("Unable to locate application for session, deleted?");
- }
-
- if (!strcmp(in.name(),"SessionCache::find")) {
- // Check required parameters.
- const char* key=in["key"].string();
- const char* client_address=in["client_address"].string();
- if (!key || !client_address)
- throw SAMLException("Required parameters missing in call to SessionCache::find");
-
- try {
- // Lookup the session and cast down to the internal type.
- MemorySessionCacheEntry* entry=dynamic_cast<MemorySessionCacheEntry*>(find(key,app,client_address));
- if (!entry)
- return DDF();
- DDF dup=entry->getDDF().copy();
- entry->unlock();
- return dup;
- }
- catch (exception&) {
- remove(key,app,client_address);
- throw;
- }
- }
- else if (!strcmp(in.name(),"SessionCache::remove")) {
- // Check required parameters.
- const char* key=in["key"].string();
- const char* client_address=in["client_address"].string();
- if (!key || !client_address)
- throw SAMLException("Required parameters missing in call to SessionCache::remove");
-
- remove(key,app,client_address);
- return DDF();
- }
- else if (!strcmp(in.name(),"SessionCache::insert")) {
- // Check required parameters.
- const char* client_address=in["client_address"].string();
- const char* provider_id=in["provider_id"].string();
- const char* authn_context=in["authn_context"].string();
- const char* subject=in["subject"].string();
- const char* tokens=in["tokens.unfiltered"].string();
- if (!client_address || !provider_id || !authn_context || !subject || !tokens)
- throw SAMLException("Required parameters missing in call to SessionCache::insert");
- int minor=in["minor_version"].integer();
-
- // Locate entity descriptor to use in filtering.
- MetadataProvider* m=app->getMetadataProvider();
- xmltooling::Locker locker(m);
- const EntityDescriptor* site=m->getEntityDescriptor(provider_id);
- if (!site) {
- m_log->error("unable to locate issuing identity provider's metadata");
- throw MetadataException("Unable to locate identity provider's metadata.");
- }
- const RoleDescriptor* role=site->getAttributeAuthorityDescriptor(samlconstants::SAML11_PROTOCOL_ENUM);
- if (!role)
- role=site->getAttributeAuthorityDescriptor(samlconstants::SAML10_PROTOCOL_ENUM);
- if (!role)
- role=site->getIDPSSODescriptor(samlconstants::SAML11_PROTOCOL_ENUM);
- if (!role)
- role=site->getIDPSSODescriptor(samlconstants::SAML10_PROTOCOL_ENUM);
- if (!role) {
- m_log->error("unable to locate attribute-issuing role in identity provider's metadata");
- throw MetadataException("Unable to locate attribute-issuing role in identity provider's metadata.");
- }
-
- // Deserialize XML for insert method.
- istringstream subis(subject);
- auto_ptr<SAMLSubject> pSubject(new SAMLSubject(subis));
- istringstream tokis(tokens);
- auto_ptr<SAMLResponse> pTokens(new SAMLResponse(tokis,minor));
-
- // Insert the data and return the cache key.
- string key=insert(app,role,client_address,pSubject.get(),authn_context,pTokens.get());
-
- DDF out(NULL);
- out.structure();
- out.addmember("key").string(key.c_str());
- return out;
- }
- throw ListenerException("Unsupported operation ($1)",xmltooling::params(1,in.name()));
-}
-
-string MemorySessionCache::insert(
- const IApplication* application,
- const RoleDescriptor* role,
- const char* client_addr,
- const SAMLSubject* subject,
- const char* authnContext,
- const SAMLResponse* tokens
- )
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("insert");
-#endif
-
- SAMLIdentifier id;
- xmltooling::auto_ptr_char key(id);
-
- if (m_log->isDebugEnabled())
- m_log->debug("creating new cache entry for application %s: \"%s\"", application->getId(), key.get());
-
- auto_ptr<MemorySessionCacheEntry> entry(
- new MemorySessionCacheEntry(
- this,
- key.get(),
- application,
- role,
- client_addr,
- subject,
- authnContext,
- tokens
- )
- );
- entry->populate(application,dynamic_cast<EntityDescriptor*>(role->getParent()),true);
-
- if (m_sink) {
- HRESULT hr=m_sink->onCreate(key.get(),application,entry.get(),1,tokens->getMinorVersion(),entry->created());
- if (FAILED(hr)) {
- m_log->error("cache store returned failure while storing new entry");
- throw IOException("Unable to record new session in cache store.");
- }
- }
-
- m_lock->wrlock();
- m_hashtable[key.get()]=entry.release();
- m_lock->unlock();
-
- return key.get();
-}
-
-ISessionCacheEntry* MemorySessionCache::find(const char* key, const IApplication* application, const char* client_addr)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("find");
-#endif
-
- m_log->debug("searching memory cache for key (%s)", key);
- m_lock->rdlock();
-
- map<string,MemorySessionCacheEntry*>::const_iterator i=m_hashtable.find(key);
- if (i==m_hashtable.end()) {
- m_lock->unlock();
- m_log->debug("no match found");
- if (!m_sink)
- return NULL; // no backing store to search
-
- m_log->debug("searching backing store");
- string appid,addr,pid,sub,ac,tokens;
- int major,minor;
- time_t created,accessed;
- HRESULT hr=m_sink->onRead(key,appid,addr,pid,sub,ac,tokens,major,minor,created,accessed);
- if (hr==S_FALSE)
- return NULL;
- else if (FAILED(hr)) {
- m_log->error("cache store returned failure during search");
- return NULL;
- }
- const IApplication* eapp=dynamic_cast<const IApplication*>(SPConfig::getConfig().getServiceProvider()->getApplication(appid.c_str()));
- if (!eapp) {
- // Something's horribly wrong.
- m_log->error("couldn't find application (%s) for session", appid.c_str());
- if (FAILED(m_sink->onDelete(key)))
- m_log->error("cache store returned failure during delete");
- return NULL;
- }
- if (m_log->isDebugEnabled())
- m_log->debug("loading cache entry (ID: %s) back into memory for application (%s)", key, appid.c_str());
-
- // Locate role to use in filtering.
- MetadataProvider* m=eapp->getMetadataProvider();
- xmltooling::Locker locker(m);
- const EntityDescriptor* site=m->getEntityDescriptor(pid.c_str());
- if (!site) {
- m_log->error("unable to locate issuing identity provider's metadata");
- if (FAILED(m_sink->onDelete(key)))
- m_log->error("cache store returned failure during delete");
- return NULL;
- }
- const RoleDescriptor* role=site->getAttributeAuthorityDescriptor(samlconstants::SAML11_PROTOCOL_ENUM);
- if (!role)
- role=site->getAttributeAuthorityDescriptor(samlconstants::SAML10_PROTOCOL_ENUM);
- if (!role)
- role=site->getIDPSSODescriptor(samlconstants::SAML11_PROTOCOL_ENUM);
- if (!role)
- role=site->getIDPSSODescriptor(samlconstants::SAML10_PROTOCOL_ENUM);
- if (!role) {
- m_log->error("unable to locate attribute-issuing role in identity provider's metadata");
- if (FAILED(m_sink->onDelete(key)))
- m_log->error("cache store returned failure during delete");
- return NULL;
- }
-
- MemorySessionCacheEntry* entry = new MemorySessionCacheEntry(
- this,
- key,
- eapp,
- role,
- addr.c_str(),
- sub.c_str(),
- ac.c_str(),
- tokens.c_str(),
- major,
- minor,
- created,
- accessed
- );
- m_lock->wrlock();
- m_hashtable[key]=entry;
- m_lock->unlock();
-
- // Downgrade to a read lock and repeat the initial search.
- m_lock->rdlock();
- i=m_hashtable.find(key);
- if (i==m_hashtable.end()) {
- m_lock->unlock();
- m_log->warn("cache entry was loaded from backing store, but disappeared after lock downgrade");
- return NULL;
- }
- }
- else
- m_log->debug("match found");
-
- // Check for application mismatch (could also do this with partitioned caches by application ID)
- if (!i->second->checkApplication(application)) {
- m_lock->unlock();
- m_log->crit("An application (%s) attempted to access another application's session!", application->getId());
- return NULL;
- }
-
- // Check for timeouts, expiration, address mismatch, etc (also updates last access)
- // Use the return code to assign specific error messages.
- try {
- HRESULT hr=i->second->isValid(application, client_addr);
- if (FAILED(hr)) {
- MetadataProvider* m=application->getMetadataProvider();
- xmltooling::Locker locker(m);
- switch (hr) {
- case SESSION_E_EXPIRED: {
- opensaml::RetryableProfileException ex("Your session has expired, and you must re-authenticate.");
- annotateException(&ex,m->getEntityDescriptor(i->second->getProviderId(),false)); // throws it
- }
-
- case SESSION_E_ADDRESSMISMATCH: {
- opensaml::RetryableProfileException ex(
- "Your IP address ($1) does not match the address recorded at the time the session was established.",
- xmltooling::params(1,client_addr)
- );
- annotateException(&ex,m->getEntityDescriptor(i->second->getProviderId(),false)); // throws it
- }
-
- default: {
- opensaml::RetryableProfileException ex("Your session is invalid.");
- annotateException(&ex,m->getEntityDescriptor(i->second->getProviderId(),false)); // throws it
- }
- }
- }
- }
- catch (...) {
- m_lock->unlock();
- throw;
- }
-
- // Lock the cache entry for the caller -- they have to unlock it.
- i->second->lock();
- m_lock->unlock();
-
- try {
- // Make sure the entry has valid tokens.
- MetadataProvider* m=application->getMetadataProvider();
- xmltooling::Locker locker(m);
- i->second->populate(application,m->getEntityDescriptor(i->second->getProviderId()));
- }
- catch (...) {
- i->second->unlock();
- throw;
- }
-
- return i->second;
-}
-
-void MemorySessionCache::remove(const char* key, const IApplication* application, const char* client_addr)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("remove");
-#endif
-
- m_log->debug("removing cache entry with key (%s)", key);
-
- // lock the cache for writing, which means we know nobody is sitting in find()
- m_lock->wrlock();
-
- // grab the entry from the database.
- map<string,MemorySessionCacheEntry*>::const_iterator i=m_hashtable.find(key);
- if (i==m_hashtable.end()) {
- m_lock->unlock();
- return;
- }
-
- // ok, remove the entry and lock it
- MemorySessionCacheEntry* entry=i->second;
- m_hashtable.erase(key);
- entry->lock();
-
- // unlock the cache
- m_lock->unlock();
-
- entry->unlock();
-
- // Notify sink. Smart ptr will make sure entry gets deleted.
- auto_ptr<ISessionCacheEntry> entrywrap(entry);
- if (m_sink) {
- if (FAILED(m_sink->onDelete(key)))
- m_log->error("cache store failed to delete entry");
- }
-
- // Transaction Logging
- STConfig& stc=static_cast<STConfig&>(ShibTargetConfig::getConfig());
- stc.getTransactionLog().infoStream() << "Destroyed session (ID: " << key << ")";
- stc.releaseTransactionLog();
-}
-
-void MemorySessionCache::dormant(const char* key)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("dormant");
-#endif
-
- m_log->debug("purging old cache entry with key (%s)", key);
-
- // lock the cache for writing, which means we know nobody is sitting in find()
- m_lock->wrlock();
-
- // grab the entry from the database.
- map<string,MemorySessionCacheEntry*>::const_iterator i=m_hashtable.find(key);
- if (i==m_hashtable.end()) {
- m_lock->unlock();
- return;
- }
-
- // ok, remove the entry and lock it
- MemorySessionCacheEntry* entry=i->second;
- m_hashtable.erase(key);
- entry->lock();
-
- // unlock the cache
- m_lock->unlock();
-
- // we can release the cache entry lock because we know we're not in the cache anymore
- entry->unlock();
-
- auto_ptr<ISessionCacheEntry> entrywrap(entry);
- if (m_sink && !m_writeThrough) {
- // Update sink with last access data. Wrapper will make sure entry gets deleted.
- if (FAILED(m_sink->onUpdate(key,NULL,entry->lastAccess())))
- m_log->error("cache store failed to update last access timestamp");
- }
-}
-
-void MemorySessionCache::cleanup()
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("cleanup()");
-#endif
-
- int rerun_timer = 0;
- int timeout_life = 0;
- Mutex* mutex = Mutex::create();
-
- // Load our configuration details...
- const XMLCh* tag=m_root->getAttributeNS(NULL,cleanupInterval);
- if (tag && *tag)
- rerun_timer = XMLString::parseInt(tag);
-
- tag=m_root->getAttributeNS(NULL,cacheTimeout);
- if (tag && *tag)
- timeout_life = XMLString::parseInt(tag);
-
- if (rerun_timer <= 0)
- rerun_timer = 300; // rerun every 5 minutes
-
- if (timeout_life <= 0)
- timeout_life = 28800; // timeout after 8 hours
-
- mutex->lock();
-
- m_log->info("cleanup thread started...Run every %d secs; timeout after %d secs", rerun_timer, timeout_life);
-
- while (!shutdown) {
- shutdown_wait->timedwait(mutex,rerun_timer);
- if (shutdown)
- break;
-
- // Ok, let's run through the cleanup process and clean out
- // really old sessions. This is a two-pass process. The
- // first pass is done holding a read-lock while we iterate over
- // the cache. The second pass doesn't need a lock because
- // the 'deletes' will lock the cache.
-
- // Pass 1: iterate over the map and find all entries that have not been
- // used in X hours
- vector<string> stale_keys;
- time_t stale = time(NULL) - timeout_life;
-
- m_lock->rdlock();
- for (map<string,MemorySessionCacheEntry*>::const_iterator i=m_hashtable.begin(); i!=m_hashtable.end(); i++)
- {
- // If the last access was BEFORE the stale timeout...
- i->second->lock();
- time_t last=i->second->lastAccess();
- i->second->unlock();
- if (last < stale)
- stale_keys.push_back(i->first);
- }
- m_lock->unlock();
-
- if (!stale_keys.empty()) {
- m_log->info("purging %d old sessions", stale_keys.size());
-
- // Pass 2: walk through the list of stale entries and remove them from the cache
- for (vector<string>::const_iterator j = stale_keys.begin(); j != stale_keys.end(); j++)
- dormant(j->c_str());
- }
- }
-
- m_log->info("cleanup thread finished.");
-
- mutex->unlock();
- delete mutex;
- Thread::exit(NULL);
-}
-
-void* MemorySessionCache::cleanup_fcn(void* cache_p)
-{
- MemorySessionCache* cache = reinterpret_cast<MemorySessionCache*>(cache_p);
-
-#ifndef WIN32
- // First, let's block all signals
- Thread::mask_all_signals();
-#endif
-
- // Now run the cleanup process.
- cache->cleanup();
- return NULL;
-}
-
-SessionCache* MemoryCacheFactory(const DOMElement* const & e)
-{
- // If this is a long-lived process, we return the "real" cache.
- if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess))
- return new MemorySessionCache(e);
- // Otherwise, we return a stubbed front-end that remotes calls to the real cache.
- return new StubCache(e);
-}
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/*
- * shib-config.cpp -- ShibTarget initialization and finalization routines
- *
- * Created By: Derek Atkins <derek@ihtfp.com>
- *
- * $Id$
- */
-
-#include "internal.h"
-#include <shibsp/SPConfig.h>
-#include <xmltooling/XMLToolingConfig.h>
-
-#include <log4cpp/OstreamAppender.hh>
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace shibboleth;
-using namespace saml;
-using namespace log4cpp;
-using namespace std;
-
-using xmltooling::XMLToolingConfig;
-using xmltooling::PluginManager;
-
-namespace {
- STConfig g_Config;
-}
-
-// Factories for built-in plugins we can manufacture. Actual definitions
-// will be with the actual object implementation.
-#ifndef WIN32
-PlugManager::Factory UnixListenerFactory;
-#endif
-PlugManager::Factory TCPListenerFactory;
-//PlugManager::Factory MemoryListenerFactory;
-
-PluginManager<Handler,const DOMElement*>::Factory ShibSessionInitiatorFactory;
-PluginManager<Handler,const DOMElement*>::Factory SAML1POSTFactory;
-PluginManager<Handler,const DOMElement*>::Factory SAML1ArtifactFactory;
-PluginManager<Handler,const DOMElement*>::Factory ShibLogoutFactory;
-
-ShibTargetConfig& ShibTargetConfig::getConfig()
-{
- return g_Config;
-}
-
-bool STConfig::init(const char* schemadir)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("init");
-#endif
- Category& log = Category::getInstance(SHIBT_LOGCAT".Config");
-
- if (!schemadir) {
- log.fatal("XML schema directory not supplied");
- return false;
- }
-
- // This will cause some extra console logging, but for now,
- // initialize the underlying libraries.
- SAMLConfig& samlConf=SAMLConfig::getConfig();
- if (schemadir)
- samlConf.schema_dir = schemadir;
- if (!samlConf.init()) {
- log.fatal("failed to initialize OpenSAML1 library");
- return false;
- }
-
- ShibConfig& shibConf=ShibConfig::getConfig();
- if (!shibConf.init()) {
- log.fatal("Failed to initialize Shib library");
- samlConf.term();
- return false;
- }
-
- SPConfig& conf=SPConfig::getConfig();
- if (!SPConfig::getConfig().init(NULL)) {
- log.fatal("Failed to initialize SP library");
- shibConf.term();
- samlConf.term();
- return false;
- }
-
- // Register built-in plugin types.
- conf.ServiceProviderManager.registerFactory(XML_SERVICE_PROVIDER, XMLServiceProviderFactory);
-
- conf.SessionInitiatorManager.registerFactory(shibspconstants::SHIB1_SESSIONINIT_PROFILE_URI,&ShibSessionInitiatorFactory);
- conf.AssertionConsumerServiceManager.registerFactory(samlconstants::SAML1_PROFILE_BROWSER_POST,&SAML1POSTFactory);
- conf.AssertionConsumerServiceManager.registerFactory(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT,&SAML1ArtifactFactory);
- conf.SingleLogoutServiceManager.registerFactory(shibspconstants::SHIB1_LOGOUT_PROFILE_URI,&ShibLogoutFactory);
-
- log.info("finished initializing");
- return true;
-}
-
-bool STConfig::load(const char* config)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("load");
-#endif
- Category& log = Category::getInstance(SHIBT_LOGCAT".Config");
-
- if (!config) {
- log.fatal("path to configuration file not supplied");
- shutdown();
- return false;
- }
-
- try {
- log.info("loading configuration file: %s", config);
- static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);
- DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(NULL);
- DOMDocument* dummydoc=impl->createDocument();
- xmltooling::XercesJanitor<DOMDocument> docjanitor(dummydoc);
- DOMElement* dummy = dummydoc->createElementNS(NULL,path);
-
- auto_ptr_XMLCh src(config);
- dummy->setAttributeNS(NULL,path,src.get());
-
- auto_ptr<ServiceProvider> sp(SPConfig::getConfig().ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER,dummy));
- sp->init();
-
- pair<bool,unsigned int> skew=sp->getUnsignedInt("clockSkew");
- SAMLConfig::getConfig().clock_skew_secs=skew.first ? skew.second : 180;
- SPConfig::getConfig().setServiceProvider(sp.release());
-
- m_tranLog=new FixedContextCategory(SHIBTRAN_LOGCAT);
- m_tranLog->info("opened transaction log");
- m_tranLogLock = xmltooling::Mutex::create();
- }
- catch (SAMLException& ex) {
- log.fatal("caught exception while loading/initializing configuration: %s",ex.what());
- shutdown();
- return false;
- }
-#ifndef _DEBUG
- catch (...) {
- log.fatal("caught exception while loading/initializing configuration");
- shutdown();
- return false;
- }
-#endif
-
- log.info("finished loading configuration");
- return true;
-}
-
-void STConfig::shutdown()
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("shutdown");
-#endif
- Category& log = Category::getInstance(SHIBT_LOGCAT".Config");
- log.info("shutting down the library");
- delete m_tranLogLock;
- m_tranLogLock = NULL;
- //delete m_tranLog; // This is crashing for some reason, but we're shutting down anyway.
- SPConfig::getConfig().term();
- ShibConfig::getConfig().term();
- SAMLConfig::getConfig().term();
- log.info("library shutdown complete");
-}
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/*
- * shib-handlers.cpp -- profile handlers that plug into SP
- *
- * Scott Cantor
- * 5/17/2005
- */
-
-#include "internal.h"
-
-#include <ctime>
-#include <saml/SAMLConfig.h>
-#include <saml/binding/URLEncoder.h>
-#include <saml/saml2/metadata/Metadata.h>
-#include <saml/saml2/metadata/EndpointManager.h>
-#include <saml/util/CommonDomainCookie.h>
-#include <shibsp/AbstractHandler.h>
-#include <shibsp/SPConfig.h>
-#include <shibsp/SPRequest.h>
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace shibboleth;
-using namespace saml;
-using namespace opensaml::saml2md;
-using namespace log4cpp;
-using namespace std;
-
-using opensaml::CommonDomainCookie;
-using opensaml::URLEncoder;
-
-#if defined (_MSC_VER)
- #pragma warning( push )
- #pragma warning( disable : 4250 )
-#endif
-
-namespace {
- class SessionInitiator : public AbstractHandler
- {
- public:
- SessionInitiator(const DOMElement* e) : AbstractHandler(e) {}
- ~SessionInitiator() {}
- pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
- pair<bool,long> ShibAuthnRequest(
- SPRequest& request,
- const Handler* shire,
- const char* dest,
- const char* target,
- const char* providerId
- ) const;
- };
-
- class SAML1Consumer : public AbstractHandler, public virtual Remoted
- {
- public:
- SAML1Consumer(const DOMElement* e);
- ~SAML1Consumer();
- pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
- void receive(DDF& in, ostream& out);
- private:
- string m_address;
- static int counter;
- };
-
- int SAML1Consumer::counter = 0;
-
- class ShibLogout : public AbstractHandler
- {
- public:
- ShibLogout(const DOMElement* e) : AbstractHandler(e) {}
- ~ShibLogout() {}
- pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
- };
-}
-
-#if defined (_MSC_VER)
- #pragma warning( pop )
-#endif
-
-Handler* ShibSessionInitiatorFactory(const DOMElement* const & e)
-{
- return new SessionInitiator(e);
-}
-
-Handler* SAML1POSTFactory(const DOMElement* const & e)
-{
- return new SAML1Consumer(e);
-}
-
-Handler* SAML1ArtifactFactory(const DOMElement* const & e)
-{
- return new SAML1Consumer(e);
-}
-
-Handler* ShibLogoutFactory(const DOMElement* const & e)
-{
- return new ShibLogout(e);
-}
-
-pair<bool,long> SessionInitiator::run(SPRequest& request, bool isHandler) const
-{
- string dupresource;
- const char* resource=NULL;
- const Handler* ACS=NULL;
- const IApplication& app=dynamic_cast<const IApplication&>(request.getApplication());
-
- if (isHandler) {
- /*
- * Binding is CGI query string with:
- * target the resource to direct back to later
- * acsIndex optional index of an ACS to use on the way back in
- * providerId optional direct invocation of a specific IdP
- */
- const char* option=request.getParameter("acsIndex");
- if (option)
- ACS=app.getAssertionConsumerServiceByIndex(atoi(option));
- option=request.getParameter("providerId");
-
- resource=request.getParameter("target");
- if (!resource || !*resource) {
- pair<bool,const char*> home=app.getString("homeURL");
- if (home.first)
- resource=home.second;
- else
- throw opensaml::FatalProfileException("Session initiator requires a target parameter or a homeURL application property.");
- }
- else if (!option) {
- dupresource=resource;
- resource=dupresource.c_str();
- }
-
- if (option) {
- // Here we actually use metadata to invoke the SSO service directly.
- // The only currently understood binding is the Shibboleth profile.
-
- MetadataProvider* m=app.getMetadataProvider();
- xmltooling::Locker locker(m);
- const EntityDescriptor* entity=m->getEntityDescriptor(option);
- if (!entity)
- throw MetadataException("Session initiator unable to locate metadata for provider ($1).", xmltooling::params(1,option));
- const IDPSSODescriptor* role=entity->getIDPSSODescriptor(shibspconstants::SHIB1_PROTOCOL_ENUM);
- if (!role)
- throw MetadataException(
- "Session initiator unable to locate a Shibboleth-aware identity provider role for provider ($1).",
- xmltooling::params(1,option)
- );
- const EndpointType* ep=EndpointManager<SingleSignOnService>(role->getSingleSignOnServices()).getByBinding(
- shibspconstants::SHIB1_AUTHNREQUEST_PROFILE_URI
- );
- if (!ep)
- throw MetadataException(
- "Session initiator unable to locate compatible SSO service for provider ($1).", xmltooling::params(1,option)
- );
- auto_ptr_char dest(ep->getLocation());
- return ShibAuthnRequest(
- request,ACS ? ACS : app.getDefaultAssertionConsumerService(),dest.get(),resource,app.getString("providerId").second
- );
- }
- }
- else {
- // We're running as a "virtual handler" from within the filter.
- // The target resource is the current one and everything else is defaulted.
- resource=request.getRequestURL();
- }
-
- if (!ACS) ACS=app.getDefaultAssertionConsumerService();
-
- // For now, we only support external session initiation via a wayfURL
- pair<bool,const char*> wayfURL=getString("wayfURL");
- if (!wayfURL.first)
- throw ConfigurationException("Session initiator is missing wayfURL property.");
-
- pair<bool,const XMLCh*> wayfBinding=getXMLString("wayfBinding");
- if (!wayfBinding.first || !XMLString::compareString(wayfBinding.second,shibspconstants::SHIB1_AUTHNREQUEST_PROFILE_URI))
- // Standard Shib 1.x
- return ShibAuthnRequest(request,ACS,wayfURL.second,resource,app.getString("providerId").second);
- else if (!strcmp(getString("wayfBinding").second,"urn:mace:shibboleth:1.0:profiles:EAuth")) {
- // TODO: Finalize E-Auth profile URI
- pair<bool,bool> localRelayState=request.getServiceProvider().getPropertySet("InProcess")->getBool("localRelayState");
- if (!localRelayState.first || !localRelayState.second)
- throw ConfigurationException("E-Authn requests cannot include relay state, so localRelayState must be enabled.");
-
- // Here we store the state in a cookie.
- pair<string,const char*> shib_cookie=app.getCookieNameProps("_shibstate_");
- string stateval = opensaml::SAMLConfig::getConfig().getURLEncoder()->encode(resource) + shib_cookie.second;
- request.setCookie(shib_cookie.first.c_str(),stateval.c_str());
- return make_pair(true, request.sendRedirect(wayfURL.second));
- }
-
- throw opensaml::BindingException("Unsupported WAYF binding ($1).", xmltooling::params(1,getString("wayfBinding").second));
-}
-
-// Handles Shib 1.x AuthnRequest profile.
-pair<bool,long> SessionInitiator::ShibAuthnRequest(
- SPRequest& request,
- const Handler* shire,
- const char* dest,
- const char* target,
- const char* providerId
- ) const
-{
- // Compute the ACS URL. We add the ACS location to the base handlerURL.
- // Legacy configs will not have the Location property specified, so no suffix will be added.
- string ACSloc=request.getHandlerURL(target);
- pair<bool,const char*> loc=shire ? shire->getString("Location") : pair<bool,const char*>(false,NULL);
- if (loc.first) ACSloc+=loc.second;
-
- URLEncoder* urlenc = opensaml::SAMLConfig::getConfig().getURLEncoder();
-
- char timebuf[16];
- sprintf(timebuf,"%u",time(NULL));
- string req=string(dest) + "?shire=" + urlenc->encode(ACSloc.c_str()) + "&time=" + timebuf;
-
- // How should the resource value be preserved?
- pair<bool,bool> localRelayState=request.getServiceProvider().getPropertySet("InProcess")->getBool("localRelayState");
- if (!localRelayState.first || !localRelayState.second) {
- // The old way, just send it along.
- req+="&target=" + urlenc->encode(target);
- }
- else {
- // Here we store the state in a cookie and send a fixed
- // value to the IdP so we can recognize it on the way back.
- pair<string,const char*> shib_cookie=request.getApplication().getCookieNameProps("_shibstate_");
- string stateval = urlenc->encode(target) + shib_cookie.second;
- request.setCookie(shib_cookie.first.c_str(),stateval.c_str());
- req+="&target=cookie";
- }
-
- // Only omitted for 1.1 style requests.
- if (providerId)
- req+="&providerId=" + urlenc->encode(providerId);
-
- return make_pair(true, request.sendRedirect(req.c_str()));
-}
-
-SAML1Consumer::SAML1Consumer(const DOMElement* e) : AbstractHandler(e)
-{
- m_address += ('A' + (counter++));
- m_address += "::SAML1Consumer::run";
-
- // Register for remoted messages.
- if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess))
- SPConfig::getConfig().getServiceProvider()->getListenerService()->regListener(m_address.c_str(),this);
-}
-
-SAML1Consumer::~SAML1Consumer()
-{
- ListenerService* listener=SPConfig::getConfig().getServiceProvider()->getListenerService(false);
- if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess))
- listener->unregListener(m_address.c_str(),this);
- counter--;
-}
-
-/*
- * IPC message definitions:
- *
- * [A-Z]::SAML1Consumer::run
- *
- * IN
- * application_id
- * client_address
- * recipient
- * SAMLResponse or SAMLart list
- *
- * OUT
- * key
- * provider_id
- */
-void SAML1Consumer::receive(DDF& in, ostream& sink)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("receive");
-#endif
- Category& log=Category::getInstance(SHIBT_LOGCAT".SAML1Consumer");
-
- // Find application.
- const char* aid=in["application_id"].string();
- const IApplication* app=aid ? dynamic_cast<const IApplication*>(SPConfig::getConfig().getServiceProvider()->getApplication(aid)) : NULL;
- if (!app) {
- // Something's horribly wrong.
- log.error("couldn't find application (%s) for new session", aid ? aid : "(missing)");
- throw SAMLException("Unable to locate application for new session, deleted?");
- }
-
- // Check required parameters.
- const char* client_address=in["client_address"].string();
- const char* recipient=in["recipient"].string();
- if (!client_address || !recipient)
- throw SAMLException("Required parameters missing in call to SAML1Consumer::run");
-
- log.debug("processing new assertion for %s", client_address);
- log.debug("recipient: %s", recipient);
- log.debug("application: %s", app->getId());
-
- // Access the application config.
- ServiceProvider* conf=SPConfig::getConfig().getServiceProvider();
- xmltooling::Locker confLocker(conf);
-
- auto_ptr_XMLCh wrecipient(recipient);
-
- pair<bool,bool> checkAddress=pair<bool,bool>(false,true);
- pair<bool,bool> checkReplay=pair<bool,bool>(false,true);
- const PropertySet* props=app->getPropertySet("Sessions");
- if (props) {
- checkAddress=props->getBool("checkAddress");
- if (!checkAddress.first)
- checkAddress.second=true;
- checkReplay=props->getBool("checkReplay");
- if (!checkReplay.first)
- checkReplay.second=true;
- }
-
- // Supports either version...
- pair<bool,unsigned int> version=getUnsignedInt("MinorVersion","urn:oasis:names:tc:SAML:1.0:protocol");
- if (!version.first)
- version.second=1;
-
- const EntityDescriptor* provider=NULL;
- const RoleDescriptor* role=NULL;
- MetadataProvider* m=app->getMetadataProvider();
- xmltooling::Locker locker(m);
- SAMLBrowserProfile::BrowserProfileResponse bpr;
-
- try {
- const char* samlResponse=in["SAMLResponse"].string();
- if (samlResponse) {
- // POST profile
- log.debug("executing Browser/POST profile...");
- bpr=app->getBrowserProfile()->receive(
- samlResponse,
- wrecipient.get(),
- NULL,
- version.second
- );
- }
- else {
- // Artifact profile
- vector<const char*> SAMLart;
- DDF arts=in["SAMLart"];
- DDF art=arts.first();
- while (art.isstring()) {
- SAMLart.push_back(art.string());
- art=arts.next();
- }
- auto_ptr<SAMLBrowserProfile::ArtifactMapper> artifactMapper(app->getArtifactMapper());
- log.debug("executing Browser/Artifact profile...");
- bpr=app->getBrowserProfile()->receive(
- SAMLart,
- wrecipient.get(),
- artifactMapper.get(),
- NULL,
- version.second
- );
-
- // Blow it away to clear any locks that might be held.
- delete artifactMapper.release();
- }
-
- // Try and map to metadata (again).
- // Once the metadata layer is in the SAML core, the repetition will be fixed.
- provider=m->getEntityDescriptor(bpr.assertion->getIssuer());
- if (!provider && bpr.authnStatement->getSubject()->getNameIdentifier() &&
- bpr.authnStatement->getSubject()->getNameIdentifier()->getNameQualifier())
- provider=m->getEntityDescriptor(bpr.authnStatement->getSubject()->getNameIdentifier()->getNameQualifier());
- if (provider) {
- role=provider->getIDPSSODescriptor(
- version.second==1 ? samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM
- );
- }
-
- // This isn't likely, since the profile must have found a role.
- if (!role) {
- MetadataException ex("Unable to locate role-specific metadata for identity provider.");
- annotateException(&ex,provider); // throws it
- }
-
- // Maybe verify the client address....
- if (checkAddress.second) {
- log.debug("verifying client address");
- // Verify the client address exists
- const XMLCh* wip = bpr.authnStatement->getSubjectIP();
- if (wip && *wip) {
- // Verify the client address matches authentication
- auto_ptr_char this_ip(wip);
- if (strcmp(client_address, this_ip.get())) {
- opensaml::FatalProfileException ex(
- "Your client's current address ($1) differs from the one used when you authenticated "
- "to your identity provider. To correct this problem, you may need to bypass a proxy server. "
- "Please contact your local support staff or help desk for assistance.",
- xmltooling::params(1,client_address)
- );
- annotateException(&ex,role); // throws it
- }
- }
- }
- }
- catch (exception&) {
- bpr.clear();
- throw;
- }
- catch (...) {
- log.error("caught unknown exception");
- bpr.clear();
-#ifdef _DEBUG
- throw;
-#else
- SAMLException e("An unexpected error occurred while creating your session.");
- shibboleth::annotateException(&e,role);
-#endif
- }
-
- // It passes all our tests -- create a new session.
- log.info("creating new session");
-
- // Insert into cache.
- auto_ptr_char authContext(bpr.authnStatement->getAuthMethod());
- string key=dynamic_cast<ISessionCache*>(conf->getSessionCache())->insert(
- app,
- role,
- client_address,
- bpr.authnStatement->getSubject(),
- authContext.get(),
- bpr.response
- );
- // objects owned by cache now
- log.debug("new session id: %s", key.c_str());
- auto_ptr_char oname(provider->getEntityID());
- DDF out=DDF(NULL).structure();
- out.addmember("key").string(key.c_str());
- out.addmember("provider_id").string(oname.get());
-
- sink << out;
-}
-
-pair<bool,long> SAML1Consumer::run(SPRequest& request, bool isHandler) const
-{
- DDF in,out;
- DDFJanitor jin(in),jout(out);
-
- pair<bool,const XMLCh*> binding=getXMLString("Binding");
- if (!binding.first || !XMLString::compareString(binding.second,SAMLBrowserProfile::BROWSER_POST)) {
-#ifdef HAVE_STRCASECMP
- if (strcasecmp(request.getMethod(), "POST")) {
-#else
- if (_stricmp(request.getMethod(), "POST")) {
-#endif
- request.log(SPRequest::SPInfo, "SAML 1.x Browser/POST handler ignoring non-POST request");
- return pair<bool,long>(false,NULL);
- }
-#ifdef HAVE_STRCASECMP
- if (strcasecmp(request.getContentType().c_str(),"application/x-www-form-urlencoded")) {
-#else
- if (_stricmp(request.getContentType().c_str(),"application/x-www-form-urlencoded")) {
-#endif
- request.log(SPRequest::SPInfo, "SAML 1.x Browser/POST handler ignoring submission with unknown content-type.");
- return pair<bool,long>(false,0);
- }
-
- const char* samlResponse = request.getParameter("SAMLResponse");
- if (!samlResponse) {
- request.log(SPRequest::SPInfo, "SAML 1.x Browser/POST handler ignoring request with no SAMLResponse parameter.");
- return pair<bool,long>(false,0);
- }
-
- in=DDF(m_address.c_str()).structure();
- in.addmember("SAMLResponse").string(samlResponse);
- }
- else if (!XMLString::compareString(binding.second,SAMLBrowserProfile::BROWSER_ARTIFACT)) {
-#ifdef HAVE_STRCASECMP
- if (strcasecmp(request.getMethod(), "GET")) {
-#else
- if (_stricmp(request.getMethod(), "GET")) {
-#endif
- request.log(SPRequest::SPInfo, "SAML 1.x Browser/Artifact handler ignoring non-GET request");
- return pair<bool,long>(false,0);
- }
-
- vector<const char*> arts;
- if (request.getParameters("SAMLart",arts)==0) {
- request.log(SPRequest::SPInfo, "SAML 1.x Browser/Artifact handler ignoring request with no SAMLart parameter.");
- return pair<bool,long>(false,0);
- }
-
- in=DDF(m_address.c_str()).structure();
- DDF artlist=in.addmember("SAMLart").list();
-
- for (vector<const char*>::const_iterator a=arts.begin(); a!=arts.end(); ++a)
- artlist.add(DDF(NULL).string(*a));
- }
-
- // Compute the endpoint location.
- string hURL=request.getHandlerURL(request.getRequestURL());
- pair<bool,const char*> loc=getString("Location");
- string recipient=loc.first ? hURL + loc.second : hURL;
- in.addmember("recipient").string(recipient.c_str());
-
- // Add remaining parameters.
- in.addmember("application_id").string(request.getApplication().getId());
- in.addmember("client_address").string(request.getRemoteAddr().c_str());
-
- out=request.getServiceProvider().getListenerService()->send(in);
- if (!out["key"].isstring())
- throw opensaml::FatalProfileException("Remote processing of SAML 1.x Browser profile did not return a usable session key.");
- string key=out["key"].string();
-
- request.log(SPRequest::SPDebug, string("profile processing succeeded, new session created (") + key + ")");
-
- const char* target=request.getParameter("TARGET");
- if (target && !strcmp(target,"default")) {
- pair<bool,const char*> homeURL=request.getApplication().getString("homeURL");
- target=homeURL.first ? homeURL.second : "/";
- }
- else if (!target || !strcmp(target,"cookie")) {
- // Pull the target value from the "relay state" cookie.
- pair<string,const char*> relay_cookie = request.getApplication().getCookieNameProps("_shibstate_");
- const char* relay_state = request.getCookie(relay_cookie.first.c_str());
- if (!relay_state || !*relay_state) {
- // No apparent relay state value to use, so fall back on the default.
- pair<bool,const char*> homeURL=request.getApplication().getString("homeURL");
- target=homeURL.first ? homeURL.second : "/";
- }
- else {
- char* rscopy=strdup(relay_state);
- opensaml::SAMLConfig::getConfig().getURLEncoder()->decode(rscopy);
- hURL=rscopy;
- free(rscopy);
- target=hURL.c_str();
- }
- request.setCookie(relay_cookie.first.c_str(),relay_cookie.second);
- }
-
- // We've got a good session, set the session cookie.
- pair<string,const char*> shib_cookie=request.getApplication().getCookieNameProps("_shibsession_");
- key += shib_cookie.second;
- request.setCookie(shib_cookie.first.c_str(), key.c_str());
-
- const char* providerId=out["provider_id"].string();
- if (providerId) {
- const PropertySet* sessionProps=request.getApplication().getPropertySet("Sessions");
- pair<bool,bool> idpHistory=sessionProps->getBool("idpHistory");
- if (!idpHistory.first || idpHistory.second) {
- // Set an IdP history cookie locally (essentially just a CDC).
- CommonDomainCookie cdc(request.getCookie(CommonDomainCookie::CDCName));
-
- // Either leave in memory or set an expiration.
- pair<bool,unsigned int> days=sessionProps->getUnsignedInt("idpHistoryDays");
- if (!days.first || days.second==0) {
- key = string(cdc.set(providerId)) + shib_cookie.second;
- request.setCookie(CommonDomainCookie::CDCName, key.c_str());
- }
- else {
- time_t now=time(NULL) + (days.second * 24 * 60 * 60);
-#ifdef HAVE_GMTIME_R
- struct tm res;
- struct tm* ptime=gmtime_r(&now,&res);
-#else
- struct tm* ptime=gmtime(&now);
-#endif
- char timebuf[64];
- strftime(timebuf,64,"%a, %d %b %Y %H:%M:%S GMT",ptime);
- key = string(cdc.set(providerId)) + shib_cookie.second + "; expires=" + timebuf;
- request.setCookie(CommonDomainCookie::CDCName, key.c_str());
- }
- }
- }
-
- // Now redirect to the target.
- return make_pair(true, request.sendRedirect(target));
-}
-
-pair<bool,long> ShibLogout::run(SPRequest& request, bool isHandler) const
-{
- // Recover the session key.
- pair<string,const char*> shib_cookie = request.getApplication().getCookieNameProps("_shibsession_");
- const char* session_id = request.getCookie(shib_cookie.first.c_str());
-
- // Logout is best effort.
- if (session_id && *session_id) {
- try {
- // TODO: port to new cache API
- //request.getServiceProvider().getSessionCache()->remove(session_id,request.getApplication(),request.getRemoteAddr().c_str());
- }
- catch (exception& e) {
- request.log(SPRequest::SPError, string("logout processing failed with exception: ") + e.what());
- }
-#ifndef _DEBUG
- catch (...) {
- request.log(SPRequest::SPError, "logout processing failed with unknown exception");
- }
-#endif
- // We send the cookie property alone, which acts as an empty value.
- request.setCookie(shib_cookie.first.c_str(),shib_cookie.second);
- }
-
- const char* ret=request.getParameter("return");
- if (!ret)
- ret=getString("ResponseLocation").second;
- if (!ret)
- ret=request.getApplication().getString("homeURL").second;
- if (!ret)
- ret="/";
- return make_pair(true, request.sendRedirect(ret));
-}
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/*
- * shib-ini.h -- config file handling, now XML-based
- *
- * $Id$
- */
-
-#include "internal.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <log4cpp/Category.hh>
-#include <log4cpp/PropertyConfigurator.hh>
-#include <shibsp/RequestMapper.h>
-#include <shibsp/SPConfig.h>
-#include <shibsp/TransactionLog.h>
-#include <shibsp/security/PKIXTrustEngine.h>
-#include <shibsp/util/DOMPropertySet.h>
-#include <saml/SAMLConfig.h>
-#include <saml/saml1/core/Assertions.h>
-#include <saml/saml2/metadata/ChainingMetadataProvider.h>
-#include <xmltooling/XMLToolingConfig.h>
-#include <xmltooling/security/ChainingTrustEngine.h>
-#include <xmltooling/util/ReloadableXMLFile.h>
-#include <xmltooling/util/ReplayCache.h>
-
-using namespace shibsp;
-using namespace shibtarget;
-using namespace shibboleth;
-using namespace saml;
-using namespace opensaml::saml1;
-using namespace opensaml::saml2md;
-using namespace xmltooling;
-using namespace log4cpp;
-using namespace std;
-using xmlsignature::CredentialResolver;
-
-namespace {
-
- vector<const Handler*> g_noHandlers;
-
- // Application configuration wrapper
- class XMLApplication : public virtual IApplication, public DOMPropertySet, public DOMNodeFilter
- {
- public:
- XMLApplication(const ServiceProvider*, const DOMElement* e, const XMLApplication* base=NULL);
- ~XMLApplication() { cleanup(); }
-
- // PropertySet
- pair<bool,bool> getBool(const char* name, const char* ns=NULL) const;
- pair<bool,const char*> getString(const char* name, const char* ns=NULL) const;
- pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const;
- pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const;
- pair<bool,int> getInt(const char* name, const char* ns=NULL) const;
- const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const;
-
- // IApplication
- const char* getId() const {return getString("id").second;}
- const char* getHash() const {return m_hash.c_str();}
- MetadataProvider* getMetadataProvider() const;
- TrustEngine* getTrustEngine() const;
- const vector<const XMLCh*>& getAudiences() const;
- const PropertySet* getCredentialUse(const EntityDescriptor* provider) const;
-
- const SAMLBrowserProfile* getBrowserProfile() const {return m_profile;}
- const SAMLBinding* getBinding(const XMLCh* binding) const
- {return XMLString::compareString(SAMLBinding::SOAP,binding) ? NULL : m_binding;}
- SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const {return new STArtifactMapper(this);}
- void validateToken(
- SAMLAssertion* token,
- time_t t=0,
- const RoleDescriptor* role=NULL,
- const TrustEngine* trust=NULL
- ) const;
- const Handler* getDefaultSessionInitiator() const;
- const Handler* getSessionInitiatorById(const char* id) const;
- const Handler* getDefaultAssertionConsumerService() const;
- const Handler* getAssertionConsumerServiceByIndex(unsigned short index) const;
- const vector<const Handler*>& getAssertionConsumerServicesByBinding(const XMLCh* binding) const;
- const Handler* getHandler(const char* path) const;
-
- // Provides filter to exclude special config elements.
- short acceptNode(const DOMNode* node) const;
-
- private:
- void cleanup();
- const ServiceProvider* m_sp; // this is ok because its locking scope includes us
- const XMLApplication* m_base;
- string m_hash;
- MetadataProvider* m_metadata;
- TrustEngine* m_trust;
- vector<const XMLCh*> m_audiences;
- ShibBrowserProfile* m_profile;
- SAMLBinding* m_binding;
- ShibHTTPHook* m_bindingHook;
-
- // manage handler objects
- vector<Handler*> m_handlers;
-
- // maps location (path info) to applicable handlers
- map<string,const Handler*> m_handlerMap;
-
- // maps unique indexes to consumer services
- map<unsigned int,const Handler*> m_acsIndexMap;
-
- // pointer to default consumer service
- const Handler* m_acsDefault;
-
- // maps binding strings to supporting consumer service(s)
-#ifdef HAVE_GOOD_STL
- typedef map<xmltooling::xstring,vector<const Handler*> > ACSBindingMap;
-#else
- typedef map<string,vector<const Handler*> > ACSBindingMap;
-#endif
- ACSBindingMap m_acsBindingMap;
-
- // maps unique ID strings to session initiators
- map<string,const Handler*> m_sessionInitMap;
-
- // pointer to default session initiator
- const Handler* m_sessionInitDefault;
-
- DOMPropertySet* m_credDefault;
-#ifdef HAVE_GOOD_STL
- map<xmltooling::xstring,PropertySet*> m_credMap;
-#else
- map<const XMLCh*,PropertySet*> m_credMap;
-#endif
- };
-
- // Top-level configuration implementation
- class XMLConfig;
- class XMLConfigImpl : public DOMPropertySet, public DOMNodeFilter
- {
- public:
- XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer);
- ~XMLConfigImpl();
-
- RequestMapper* m_requestMapper;
- map<string,Application*> m_appmap;
- map<string,CredentialResolver*> m_credResolverMap;
- vector<IAttributeFactory*> m_attrFactories;
-
- // Provides filter to exclude special config elements.
- short acceptNode(const DOMNode* node) const;
-
- void setDocument(DOMDocument* doc) {
- m_document = doc;
- }
-
- private:
- void doExtensions(const DOMElement* e, const char* label, Category& log);
-
- const XMLConfig* m_outer;
- DOMDocument* m_document;
- };
-
-#if defined (_MSC_VER)
- #pragma warning( push )
- #pragma warning( disable : 4250 )
-#endif
-
- class XMLConfig : public ServiceProvider, public ReloadableXMLFile
- {
- public:
- XMLConfig(const DOMElement* e)
- : ReloadableXMLFile(e), m_impl(NULL), m_listener(NULL), m_sessionCache(NULL) {
- }
-
- void init() {
- load();
- }
-
- ~XMLConfig() {
- delete m_impl;
- delete m_sessionCache;
- delete m_listener;
- delete m_tranLog;
- XMLToolingConfig::getConfig().setReplayCache(NULL);
- for_each(m_storage.begin(), m_storage.end(), xmltooling::cleanup_pair<string,StorageService>());
- }
-
- // PropertySet
- pair<bool,bool> getBool(const char* name, const char* ns=NULL) const {return m_impl->getBool(name,ns);}
- pair<bool,const char*> getString(const char* name, const char* ns=NULL) const {return m_impl->getString(name,ns);}
- pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const {return m_impl->getXMLString(name,ns);}
- pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const {return m_impl->getUnsignedInt(name,ns);}
- pair<bool,int> getInt(const char* name, const char* ns=NULL) const {return m_impl->getInt(name,ns);}
- const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const {return m_impl->getPropertySet(name,ns);}
- const DOMElement* getElement() const {return m_impl->getElement();}
-
- // ServiceProvider
- TransactionLog* getTransactionLog() const {
- if (m_tranLog)
- return m_tranLog;
- throw ConfigurationException("No TransactionLog available.");
- }
-
- StorageService* getStorageService(const char* id) const {
- if (id) {
- map<string,StorageService*>::const_iterator i=m_storage.find(id);
- if (i!=m_storage.end())
- return i->second;
- }
- return NULL;
- }
-
- ListenerService* getListenerService(bool required=true) const {
- if (required && !m_listener)
- throw ConfigurationException("No ListenerService available.");
- return m_listener;
- }
-
- SessionCache* getSessionCache(bool required=true) const {
- if (required && !m_sessionCache)
- throw ConfigurationException("No SessionCache available.");
- return m_sessionCache;
- }
-
- RequestMapper* getRequestMapper(bool required=true) const {
- if (required && !m_impl->m_requestMapper)
- throw ConfigurationException("No RequestMapper available.");
- return m_impl->m_requestMapper;
- }
-
- const Application* getApplication(const char* applicationId) const {
- map<string,Application*>::const_iterator i=m_impl->m_appmap.find(applicationId);
- return (i!=m_impl->m_appmap.end()) ? i->second : NULL;
- }
-
- CredentialResolver* getCredentialResolver(const char* id) const {
- if (id) {
- map<string,CredentialResolver*>::const_iterator i=m_impl->m_credResolverMap.find(id);
- if (i!=m_impl->m_credResolverMap.end())
- return i->second;
- }
- return NULL;
- }
-
- protected:
- pair<bool,DOMElement*> load();
-
- private:
- friend class XMLConfigImpl;
- XMLConfigImpl* m_impl;
- mutable ListenerService* m_listener;
- mutable SessionCache* m_sessionCache;
- mutable TransactionLog* m_tranLog;
- mutable map<string,StorageService*> m_storage;
- };
-
-#if defined (_MSC_VER)
- #pragma warning( pop )
-#endif
-
- static const XMLCh AAPProvider[] = UNICODE_LITERAL_11(A,A,P,P,r,o,v,i,d,e,r);
- static const XMLCh _Application[] = UNICODE_LITERAL_11(A,p,p,l,i,c,a,t,i,o,n);
- static const XMLCh Applications[] = UNICODE_LITERAL_12(A,p,p,l,i,c,a,t,i,o,n,s);
- static const XMLCh AttributeFactory[] = UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,F,a,c,t,o,r,y);
- static const XMLCh Credentials[] = UNICODE_LITERAL_11(C,r,e,d,e,n,t,i,a,l,s);
- static const XMLCh CredentialsProvider[] = UNICODE_LITERAL_19(C,r,e,d,e,n,t,i,a,l,s,P,r,o,v,i,d,e,r);
- static const XMLCh CredentialUse[] = UNICODE_LITERAL_13(C,r,e,d,e,n,t,i,a,l,U,s,e);
- static const XMLCh DiagnosticService[] = UNICODE_LITERAL_17(D,i,a,g,n,o,s,t,i,c,S,e,r,v,i,c,e);
- static const XMLCh fatal[] = UNICODE_LITERAL_5(f,a,t,a,l);
- static const XMLCh FileResolver[] = UNICODE_LITERAL_12(F,i,l,e,R,e,s,o,l,v,e,r);
- static const XMLCh Global[] = UNICODE_LITERAL_6(G,l,o,b,a,l);
- static const XMLCh Id[] = UNICODE_LITERAL_2(I,d);
- static const XMLCh Implementation[] = UNICODE_LITERAL_14(I,m,p,l,e,m,e,n,t,a,t,i,o,n);
- static const XMLCh InProcess[] = UNICODE_LITERAL_9(I,n,P,r,o,c,e,s,s);
- static const XMLCh Library[] = UNICODE_LITERAL_7(L,i,b,r,a,r,y);
- static const XMLCh Listener[] = UNICODE_LITERAL_8(L,i,s,t,e,n,e,r);
- static const XMLCh Local[] = UNICODE_LITERAL_5(L,o,c,a,l);
- static const XMLCh logger[] = UNICODE_LITERAL_6(l,o,g,g,e,r);
- static const XMLCh MemoryListener[] = UNICODE_LITERAL_14(M,e,m,o,r,y,L,i,s,t,e,n,e,r);
- static const XMLCh MemorySessionCache[] = UNICODE_LITERAL_18(M,e,m,o,r,y,S,e,s,s,i,o,n,C,a,c,h,e);
- static const XMLCh RelyingParty[] = UNICODE_LITERAL_12(R,e,l,y,i,n,g,P,a,r,t,y);
- static const XMLCh _ReplayCache[] = UNICODE_LITERAL_11(R,e,p,l,a,y,C,a,c,h,e);
- static const XMLCh RequestMapProvider[] = UNICODE_LITERAL_18(R,e,q,u,e,s,t,M,a,p,P,r,o,v,i,d,e,r);
- static const XMLCh _SessionCache[] = UNICODE_LITERAL_12(S,e,s,s,i,o,n,C,a,c,h,e);
- static const XMLCh SessionInitiator[] = UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);
- static const XMLCh _StorageService[] = UNICODE_LITERAL_14(S,t,o,r,a,g,e,S,e,r,v,i,c,e);
- static const XMLCh OutOfProcess[] = UNICODE_LITERAL_12(O,u,t,O,f,P,r,o,c,e,s,s);
- static const XMLCh TCPListener[] = UNICODE_LITERAL_11(T,C,P,L,i,s,t,e,n,e,r);
- static const XMLCh TrustProvider[] = UNICODE_LITERAL_13(T,r,u,s,t,P,r,o,v,i,d,e,r);
- static const XMLCh UnixListener[] = UNICODE_LITERAL_12(U,n,i,x,L,i,s,t,e,n,e,r);
- static const XMLCh _MetadataProvider[] = UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);
- static const XMLCh _path[] = UNICODE_LITERAL_4(p,a,t,h);
- static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
-
-}
-
-ServiceProvider* shibtarget::XMLServiceProviderFactory(const DOMElement* const & e)
-{
- return new XMLConfig(e);
-}
-
-XMLApplication::XMLApplication(
- const ServiceProvider* sp,
- const DOMElement* e,
- const XMLApplication* base
- ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_profile(NULL), m_binding(NULL), m_bindingHook(NULL),
- m_credDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("XMLApplication");
-#endif
- Category& log=Category::getInstance(SHIBT_LOGCAT".Application");
-
- try {
- // First load any property sets.
- map<string,string> root_remap;
- root_remap["shire"]="session";
- root_remap["shireURL"]="handlerURL";
- root_remap["shireSSL"]="handlerSSL";
- load(e,log,this,&root_remap);
-
- const PropertySet* propcheck=getPropertySet("Errors");
- if (propcheck && !propcheck->getString("session").first)
- throw ConfigurationException("<Errors> element requires 'session' (or deprecated 'shire') attribute");
- propcheck=getPropertySet("Sessions");
- if (propcheck && !propcheck->getString("handlerURL").first)
- throw ConfigurationException("<Sessions> element requires 'handlerURL' (or deprecated 'shireURL') attribute");
-
- SPConfig& conf=SPConfig::getConfig();
- XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();
- opensaml::SAMLConfig& samlConf=opensaml::SAMLConfig::getConfig();
- SAMLConfig& shibConf=SAMLConfig::getConfig();
-
- m_hash=getId();
- m_hash+=getString("providerId").second;
- m_hash=samlConf.hashSHA1(m_hash.c_str(), true);
-
- // Process handlers.
- Handler* handler=NULL;
- bool hardACS=false, hardSessionInit=false;
- const DOMElement* child = XMLHelper::getFirstChildElement(propcheck->getElement());
- while (child) {
- xmltooling::auto_ptr_char bindprop(child->getAttributeNS(NULL,EndpointType::BINDING_ATTRIB_NAME));
- if (!bindprop.get() || !*(bindprop.get())) {
- log.warn("md:AssertionConsumerService element has no Binding attribute, skipping it...");
- child = XMLHelper::getNextSiblingElement(child);
- continue;
- }
-
- try {
- // A handler is based on the Binding property in conjunction with the element name.
- // If it's an ACS or SI, also handle index/id mappings and defaulting.
- if (XMLHelper::isNodeNamed(child,samlconstants::SAML20MD_NS,AssertionConsumerService::LOCAL_NAME)) {
- handler=conf.AssertionConsumerServiceManager.newPlugin(bindprop.get(),child);
- // Map by binding (may be > 1 per binding, e.g. SAML 1.0 vs 1.1)
-#ifdef HAVE_GOOD_STL
- m_acsBindingMap[handler->getXMLString("Binding").second].push_back(handler);
-#else
- m_acsBindingMap[handler->getString("Binding").second].push_back(handler);
-#endif
- m_acsIndexMap[handler->getUnsignedInt("index").second]=handler;
-
- if (!hardACS) {
- pair<bool,bool> defprop=handler->getBool("isDefault");
- if (defprop.first) {
- if (defprop.second) {
- hardACS=true;
- m_acsDefault=handler;
- }
- }
- else if (!m_acsDefault)
- m_acsDefault=handler;
- }
- }
- else if (XMLString::equals(child->getLocalName(),SessionInitiator)) {
- handler=conf.SessionInitiatorManager.newPlugin(bindprop.get(),child);
- pair<bool,const char*> si_id=handler->getString("id");
- if (si_id.first && si_id.second)
- m_sessionInitMap[si_id.second]=handler;
- if (!hardSessionInit) {
- pair<bool,bool> defprop=handler->getBool("isDefault");
- if (defprop.first) {
- if (defprop.second) {
- hardSessionInit=true;
- m_sessionInitDefault=handler;
- }
- }
- else if (!m_sessionInitDefault)
- m_sessionInitDefault=handler;
- }
- }
- else if (XMLHelper::isNodeNamed(child,samlconstants::SAML20MD_NS,SingleLogoutService::LOCAL_NAME)) {
- handler=conf.SingleLogoutServiceManager.newPlugin(bindprop.get(),child);
- }
- else if (XMLHelper::isNodeNamed(child,samlconstants::SAML20MD_NS,ManageNameIDService::LOCAL_NAME)) {
- handler=conf.ManageNameIDServiceManager.newPlugin(bindprop.get(),child);
- }
- else {
- handler=conf.HandlerManager.newPlugin(bindprop.get(),child);
- }
- }
- catch (exception& ex) {
- log.error("caught exception processing md:AssertionConsumerService element: %s",ex.what());
- }
-
- // Save off the objects after giving the property set to the handler for its use.
- m_handlers.push_back(handler);
-
- // Insert into location map.
- pair<bool,const char*> location=handler->getString("Location");
- if (location.first && *location.second == '/')
- m_handlerMap[location.second]=handler;
- else if (location.first)
- m_handlerMap[string("/") + location.second]=handler;
-
- child = XMLHelper::getNextSiblingElement(child);
- }
-
- // If no handlers defined at the root, assume a legacy configuration.
- if (!m_base && m_handlers.empty()) {
- // A legacy config installs a SAML POST handler at the root handler location.
- // We use the Sessions element itself as the PropertySet.
- Handler* h1=conf.SessionInitiatorManager.newPlugin(
- shibspconstants::SHIB1_SESSIONINIT_PROFILE_URI,propcheck->getElement()
- );
- m_handlers.push_back(h1);
- m_sessionInitDefault=h1;
-
- Handler* h2=conf.AssertionConsumerServiceManager.newPlugin(
- samlconstants::SAML1_PROFILE_BROWSER_POST,propcheck->getElement()
- );
- m_handlers.push_back(h2);
- m_handlerMap[""] = h2;
- m_acsDefault=h2;
- }
-
- DOMNodeList* nlist=e->getElementsByTagNameNS(samlconstants::SAML1_NS,Audience::LOCAL_NAME);
- for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++)
- if (nlist->item(i)->getParentNode()->isSameNode(e) && nlist->item(i)->hasChildNodes())
- m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue());
-
- // Always include our own providerId as an audience.
- m_audiences.push_back(getXMLString("providerId").second);
-
- if (conf.isEnabled(SPConfig::AttributeResolver)) {
- child = XMLHelper::getFirstChildElement(e,AAPProvider);
- while (child) {
- // TODO: some kind of compatibility
- child = XMLHelper::getNextSiblingElement(child,AAPProvider);
- }
- }
-
- if (conf.isEnabled(SPConfig::Metadata)) {
- vector<MetadataProvider*> os2providers;
- child = XMLHelper::getFirstChildElement(e,_MetadataProvider);
- while (child) {
- xmltooling::auto_ptr_char type(child->getAttributeNS(NULL,_type));
- log.info("building metadata provider of type %s...",type.get());
- try {
- auto_ptr<MetadataProvider> mp(samlConf.MetadataProviderManager.newPlugin(type.get(),child));
- mp->init();
- os2providers.push_back(mp.release());
- }
- catch (exception& ex) {
- log.crit("error building/initializing metadata provider: %s", ex.what());
- }
-
- child = XMLHelper::getNextSiblingElement(child,_MetadataProvider);
- }
-
- if (os2providers.size()==1)
- m_metadata=os2providers.front();
- else if (os2providers.size()>1) {
- try {
- m_metadata = samlConf.MetadataProviderManager.newPlugin(CHAINING_METADATA_PROVIDER,NULL);
- ChainingMetadataProvider* chainMeta = dynamic_cast<ChainingMetadataProvider*>(m_metadata);
- while (!os2providers.empty()) {
- chainMeta->addMetadataProvider(os2providers.back());
- os2providers.pop_back();
- }
- }
- catch (exception& ex) {
- log.crit("error building chaining metadata provider wrapper: %s",ex.what());
- for_each(os2providers.begin(), os2providers.end(), xmltooling::cleanup<MetadataProvider>());
- }
- }
- }
-
- if (conf.isEnabled(SPConfig::Trust)) {
- ChainingTrustEngine* chainTrust = NULL;
- child = XMLHelper::getFirstChildElement(e,TrustProvider);
- while (child) {
- xmltooling::auto_ptr_char type(child->getAttributeNS(NULL,_type));
- log.info("building trust provider of type %s...",type.get());
- try {
- if (!m_trust) {
- // For compatibility with old engine types, we're assuming a Shib engine is likely,
- // which requires chaining, so we'll build that regardless.
- m_trust = xmlConf.TrustEngineManager.newPlugin(CHAINING_TRUSTENGINE,NULL);
- chainTrust = dynamic_cast<ChainingTrustEngine*>(m_trust);
- }
- if (!strcmp(type.get(),"edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust")) {
- chainTrust->addTrustEngine(xmlConf.TrustEngineManager.newPlugin(EXPLICIT_KEY_TRUSTENGINE,child));
- chainTrust->addTrustEngine(xmlConf.TrustEngineManager.newPlugin(SHIBBOLETH_PKIX_TRUSTENGINE,child));
- }
- else if (!strcmp(type.get(),"edu.internet2.middleware.shibboleth.common.provider.BasicTrust")) {
- chainTrust->addTrustEngine(xmlConf.TrustEngineManager.newPlugin(EXPLICIT_KEY_TRUSTENGINE,child));
- }
- else {
- chainTrust->addTrustEngine(xmlConf.TrustEngineManager.newPlugin(type.get(),child));
- }
- }
- catch (exception& ex) {
- log.crit("error building trust provider: %s",ex.what());
- }
-
- child = XMLHelper::getNextSiblingElement(child,TrustProvider);
- }
- }
-
- // Finally, load credential mappings.
- child = XMLHelper::getFirstChildElement(e,CredentialUse);
- if (child) {
- m_credDefault=new DOMPropertySet();
- m_credDefault->load(child,log,this);
- child = XMLHelper::getFirstChildElement(child,RelyingParty);
- while (child) {
- DOMPropertySet* rp=new DOMPropertySet();
- rp->load(child,log,this);
- m_credMap[child->getAttributeNS(NULL,opensaml::saml2::Attribute::NAME_ATTRIB_NAME)]=rp;
- child = XMLHelper::getNextSiblingElement(child,RelyingParty);
- }
- }
-
- if (conf.isEnabled(SPConfig::OutOfProcess)) {
- // Really finally, build local browser profile and binding objects.
- m_profile=new ShibBrowserProfile(this, getMetadataProvider(), getTrustEngine());
- m_bindingHook=new ShibHTTPHook(getTrustEngine());
- m_binding=SAMLBinding::getInstance(SAMLBinding::SOAP);
- SAMLSOAPHTTPBinding* bptr=dynamic_cast<SAMLSOAPHTTPBinding*>(m_binding);
- if (!bptr) {
- log.fatal("binding implementation was not SOAP over HTTP");
- throw UnknownExtensionException("binding implementation was not SOAP over HTTP");
- }
- bptr->addHook(m_bindingHook,m_bindingHook); // the hook is its own global context
- }
- }
- catch (exception&) {
- cleanup();
- throw;
- }
-#ifndef _DEBUG
- catch (...) {
- cleanup();
- throw;
- }
-#endif
-}
-
-void XMLApplication::cleanup()
-{
- delete m_bindingHook;
- delete m_binding;
- delete m_profile;
- for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());
-
- delete m_credDefault;
-#ifdef HAVE_GOOD_STL
- for_each(m_credMap.begin(),m_credMap.end(),xmltooling::cleanup_pair<xmltooling::xstring,PropertySet>());
-#else
- for_each(m_credMap.begin(),m_credMap.end(),xmltooling::cleanup_pair<const XMLCh*,PropertySet>());
-#endif
-
- delete m_trust;
- delete m_metadata;
-}
-
-short XMLApplication::acceptNode(const DOMNode* node) const
-{
- if (XMLHelper::isNodeNamed(node,samlconstants::SAML1_NS,AttributeDesignator::LOCAL_NAME))
- return FILTER_REJECT;
- else if (XMLHelper::isNodeNamed(node,samlconstants::SAML20_NS,opensaml::saml1::Attribute::LOCAL_NAME))
- return FILTER_REJECT;
- else if (XMLHelper::isNodeNamed(node,samlconstants::SAML1_NS,Audience::LOCAL_NAME))
- return FILTER_REJECT;
- const XMLCh* name=node->getLocalName();
- if (XMLString::equals(name,_Application) ||
- XMLString::equals(name,AssertionConsumerService::LOCAL_NAME) ||
- XMLString::equals(name,SingleLogoutService::LOCAL_NAME) ||
- XMLString::equals(name,DiagnosticService) ||
- XMLString::equals(name,SessionInitiator) ||
- XMLString::equals(name,AAPProvider) ||
- XMLString::equals(name,CredentialUse) ||
- XMLString::equals(name,RelyingParty) ||
- XMLString::equals(name,_MetadataProvider) ||
- XMLString::equals(name,TrustProvider))
- return FILTER_REJECT;
-
- return FILTER_ACCEPT;
-}
-
-pair<bool,bool> XMLApplication::getBool(const char* name, const char* ns) const
-{
- pair<bool,bool> ret=DOMPropertySet::getBool(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getBool(name,ns) : ret;
-}
-
-pair<bool,const char*> XMLApplication::getString(const char* name, const char* ns) const
-{
- pair<bool,const char*> ret=DOMPropertySet::getString(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getString(name,ns) : ret;
-}
-
-pair<bool,const XMLCh*> XMLApplication::getXMLString(const char* name, const char* ns) const
-{
- pair<bool,const XMLCh*> ret=DOMPropertySet::getXMLString(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getXMLString(name,ns) : ret;
-}
-
-pair<bool,unsigned int> XMLApplication::getUnsignedInt(const char* name, const char* ns) const
-{
- pair<bool,unsigned int> ret=DOMPropertySet::getUnsignedInt(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getUnsignedInt(name,ns) : ret;
-}
-
-pair<bool,int> XMLApplication::getInt(const char* name, const char* ns) const
-{
- pair<bool,int> ret=DOMPropertySet::getInt(name,ns);
- if (ret.first)
- return ret;
- return m_base ? m_base->getInt(name,ns) : ret;
-}
-
-const PropertySet* XMLApplication::getPropertySet(const char* name, const char* ns) const
-{
- const PropertySet* ret=DOMPropertySet::getPropertySet(name,ns);
- if (ret || !m_base)
- return ret;
- return m_base->getPropertySet(name,ns);
-}
-
-MetadataProvider* XMLApplication::getMetadataProvider() const
-{
- return (!m_metadata && m_base) ? m_base->getMetadataProvider() : m_metadata;
-}
-
-TrustEngine* XMLApplication::getTrustEngine() const
-{
- return (!m_trust && m_base) ? m_base->getTrustEngine() : m_trust;
-}
-
-const vector<const XMLCh*>& XMLApplication::getAudiences() const
-{
- return (m_audiences.empty() && m_base) ? m_base->getAudiences() : m_audiences;
-}
-
-const PropertySet* XMLApplication::getCredentialUse(const EntityDescriptor* provider) const
-{
- if (!m_credDefault && m_base)
- return m_base->getCredentialUse(provider);
-
-#ifdef HAVE_GOOD_STL
- map<xmltooling::xstring,PropertySet*>::const_iterator i=m_credMap.find(provider->getEntityID());
- if (i!=m_credMap.end())
- return i->second;
- const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());
- while (group) {
- if (group->getName()) {
- i=m_credMap.find(group->getName());
- if (i!=m_credMap.end())
- return i->second;
- }
- group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());
- }
-#else
- map<const XMLCh*,PropertySet*>::const_iterator i=m_credMap.begin();
- for (; i!=m_credMap.end(); i++) {
- if (XMLString::equals(i->first,provider->getId()))
- return i->second;
- const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());
- while (group) {
- if (XMLString::equals(i->first,group->getName()))
- return i->second;
- group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());
- }
- }
-#endif
- return m_credDefault;
-}
-
-void XMLApplication::validateToken(SAMLAssertion* token, time_t ts, const RoleDescriptor* role, const TrustEngine* trust) const
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("validateToken");
-#endif
- Category& log=Category::getInstance(SHIBT_LOGCAT".Application");
-
- // First we verify the time conditions, using the specified timestamp, if non-zero.
- SAMLConfig& config=SAMLConfig::getConfig();
- if (ts>0) {
- const SAMLDateTime* notBefore=token->getNotBefore();
- if (notBefore && ts+config.clock_skew_secs < notBefore->getEpoch())
- throw opensaml::FatalProfileException("Assertion is not yet valid.");
- const SAMLDateTime* notOnOrAfter=token->getNotOnOrAfter();
- if (notOnOrAfter && notOnOrAfter->getEpoch() <= ts-config.clock_skew_secs)
- throw opensaml::FatalProfileException("Assertion is no longer valid.");
- }
-
- // Now we process conditions. Only audience restrictions at the moment.
- Iterator<SAMLCondition*> conditions=token->getConditions();
- while (conditions.hasNext()) {
- SAMLCondition* cond=conditions.next();
- const SAMLAudienceRestrictionCondition* ac=dynamic_cast<const SAMLAudienceRestrictionCondition*>(cond);
- if (!ac) {
- ostringstream os;
- os << *cond;
- log.error("unrecognized Condition in assertion (%s)",os.str().c_str());
- throw xmltooling::UnknownExtensionException("Assertion contains an unrecognized condition.");
- }
- else if (!ac->eval(getAudiences())) {
- ostringstream os;
- os << *ac;
- log.error("unacceptable AudienceRestrictionCondition in assertion (%s)",os.str().c_str());
- throw opensaml::FatalProfileException("Assertion contains an unacceptable AudienceRestrictionCondition.");
- }
- }
-
- if (!role || !trust) {
- log.warn("no metadata provided, so no signature validation was performed");
- return;
- }
-
- const PropertySet* credUse=getCredentialUse(dynamic_cast<const EntityDescriptor*>(role->getParent()));
- pair<bool,bool> signedAssertions=credUse ? credUse->getBool("signedAssertions") : make_pair(false,false);
-
- if (token->isSigned()) {
-
- // This will all change, but for fun, we'll port the object from OS1->OS2 for validation.
- stringstream s;
- s << *token;
- DOMDocument* doc = XMLToolingConfig::getConfig().getValidatingParser().parse(s);
- XercesJanitor<DOMDocument> jdoc(doc);
- auto_ptr<Assertion> os2ass(AssertionBuilder::buildAssertion());
- os2ass->unmarshall(doc->getDocumentElement(),true);
- jdoc.release();
-
- if (!trust->validate(*(os2ass->getSignature()),*role))
- throw xmltooling::XMLSecurityException("Assertion signature did not validate.");
- }
- else if (signedAssertions.first && signedAssertions.second)
- throw xmltooling::XMLSecurityException("Assertion was unsigned, violating policy based on the issuer.");
-}
-
-const Handler* XMLApplication::getDefaultSessionInitiator() const
-{
- if (m_sessionInitDefault) return m_sessionInitDefault;
- return m_base ? m_base->getDefaultSessionInitiator() : NULL;
-}
-
-const Handler* XMLApplication::getSessionInitiatorById(const char* id) const
-{
- map<string,const Handler*>::const_iterator i=m_sessionInitMap.find(id);
- if (i!=m_sessionInitMap.end()) return i->second;
- return m_base ? m_base->getSessionInitiatorById(id) : NULL;
-}
-
-const Handler* XMLApplication::getDefaultAssertionConsumerService() const
-{
- if (m_acsDefault) return m_acsDefault;
- return m_base ? m_base->getDefaultAssertionConsumerService() : NULL;
-}
-
-const Handler* XMLApplication::getAssertionConsumerServiceByIndex(unsigned short index) const
-{
- map<unsigned int,const Handler*>::const_iterator i=m_acsIndexMap.find(index);
- if (i!=m_acsIndexMap.end()) return i->second;
- return m_base ? m_base->getAssertionConsumerServiceByIndex(index) : NULL;
-}
-
-const vector<const Handler*>& XMLApplication::getAssertionConsumerServicesByBinding(const XMLCh* binding) const
-{
-#ifdef HAVE_GOOD_STL
- ACSBindingMap::const_iterator i=m_acsBindingMap.find(binding);
-#else
- xmltooling::auto_ptr_char temp(binding);
- ACSBindingMap::const_iterator i=m_acsBindingMap.find(temp.get());
-#endif
- if (i!=m_acsBindingMap.end())
- return i->second;
- return m_base ? m_base->getAssertionConsumerServicesByBinding(binding) : g_noHandlers;
-}
-
-const Handler* XMLApplication::getHandler(const char* path) const
-{
- string wrap(path);
- map<string,const Handler*>::const_iterator i=m_handlerMap.find(wrap.substr(0,wrap.find('?')));
- if (i!=m_handlerMap.end())
- return i->second;
- return m_base ? m_base->getHandler(path) : NULL;
-}
-
-short XMLConfigImpl::acceptNode(const DOMNode* node) const
-{
- if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB1SPCONFIG_NS) &&
- !XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS))
- return FILTER_ACCEPT;
- const XMLCh* name=node->getLocalName();
- if (XMLString::equals(name,Applications) ||
- XMLString::equals(name,AttributeFactory) ||
- XMLString::equals(name,Credentials) ||
- XMLString::equals(name,CredentialsProvider) ||
- XMLString::equals(name,Extensions::LOCAL_NAME) ||
- XMLString::equals(name,Implementation) ||
- XMLString::equals(name,Listener) ||
- XMLString::equals(name,MemoryListener) ||
- XMLString::equals(name,MemorySessionCache) ||
- XMLString::equals(name,RequestMapProvider) ||
- XMLString::equals(name,_ReplayCache) ||
- XMLString::equals(name,_SessionCache) ||
- XMLString::equals(name,_StorageService) ||
- XMLString::equals(name,TCPListener) ||
- XMLString::equals(name,UnixListener))
- return FILTER_REJECT;
-
- return FILTER_ACCEPT;
-}
-
-void XMLConfigImpl::doExtensions(const DOMElement* e, const char* label, Category& log)
-{
- const DOMElement* exts=XMLHelper::getFirstChildElement(e,Extensions::LOCAL_NAME);
- if (exts) {
- exts=XMLHelper::getFirstChildElement(exts,Library);
- while (exts) {
- xmltooling::auto_ptr_char path(exts->getAttributeNS(NULL,_path));
- try {
- if (path.get()) {
- // TODO: replace with xmltooling extension load...
- SAMLConfig::getConfig().saml_register_extension(path.get(),(void*)exts);
- log.debug("loaded %s extension library (%s)", label, path.get());
- }
- }
- catch (exception& e) {
- const XMLCh* fatal=exts->getAttributeNS(NULL,fatal);
- if (fatal && (*fatal==chLatin_t || *fatal==chDigit_1)) {
- log.fatal("unable to load mandatory %s extension library %s: %s", label, path.get(), e.what());
- throw;
- }
- else {
- log.crit("unable to load optional %s extension library %s: %s", label, path.get(), e.what());
- }
- }
- exts=XMLHelper::getNextSiblingElement(exts,Library);
- }
- }
-}
-
-XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer) : m_outer(outer), m_requestMapper(NULL)
-{
-#ifdef _DEBUG
- xmltooling::NDC ndc("XMLConfigImpl");
-#endif
- Category& log=Category::getInstance(SHIBT_LOGCAT".Config");
-
- try {
- SPConfig& conf=SPConfig::getConfig();
- XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();
- const DOMElement* SHAR=XMLHelper::getFirstChildElement(e,OutOfProcess);
- if (!SHAR)
- SHAR=XMLHelper::getFirstChildElement(e,Global);
- const DOMElement* SHIRE=XMLHelper::getFirstChildElement(e,InProcess);
- if (!SHIRE)
- SHIRE=XMLHelper::getFirstChildElement(e,Local);
-
- // Initialize log4cpp manually in order to redirect log messages as soon as possible.
- if (conf.isEnabled(SPConfig::Logging)) {
- const XMLCh* logconf=NULL;
- if (conf.isEnabled(SPConfig::OutOfProcess))
- logconf=SHAR->getAttributeNS(NULL,logger);
- else if (conf.isEnabled(SPConfig::InProcess))
- logconf=SHIRE->getAttributeNS(NULL,logger);
- if (!logconf || !*logconf)
- logconf=e->getAttributeNS(NULL,logger);
- if (logconf && *logconf) {
- xmltooling::auto_ptr_char logpath(logconf);
- log.debug("loading new logging configuration from (%s), check log destination for status of configuration",logpath.get());
- XMLToolingConfig::getConfig().log_config(logpath.get());
- }
-
- if (first)
- m_outer->m_tranLog = new TransactionLog();
- }
-
- // First load any property sets.
- map<string,string> root_remap;
- root_remap["Global"]="OutOfProcess";
- root_remap["Local"]="InProcess";
- load(e,log,this,&root_remap);
-
- const DOMElement* child;
- string plugtype;
-
- // Much of the processing can only occur on the first instantiation.
- if (first) {
- // Set clock skew.
- pair<bool,unsigned int> skew=getUnsignedInt("clockSkew");
- if (skew.first)
- xmlConf.clock_skew_secs=skew.second;
-
- // Extensions
- doExtensions(e, "global", log);
- if (conf.isEnabled(SPConfig::OutOfProcess))
- doExtensions(SHAR, "out of process", log);
-
- if (conf.isEnabled(SPConfig::InProcess))
- doExtensions(SHIRE, "in process", log);
-
- // Instantiate the ListenerService and SessionCache objects.
- if (conf.isEnabled(SPConfig::Listener)) {
- child=XMLHelper::getFirstChildElement(SHAR,UnixListener);
- if (child)
- plugtype=UNIX_LISTENER_SERVICE;
- else {
- child=XMLHelper::getFirstChildElement(SHAR,TCPListener);
- if (child)
- plugtype=TCP_LISTENER_SERVICE;
- else {
- child=XMLHelper::getFirstChildElement(SHAR,MemoryListener);
- if (child)
- plugtype=MEMORY_LISTENER_SERVICE;
- else {
- child=XMLHelper::getFirstChildElement(SHAR,Listener);
- if (child) {
- xmltooling::auto_ptr_char type(child->getAttributeNS(NULL,_type));
- if (type.get())
- plugtype=type.get();
- }
- }
- }
- }
- if (child) {
- log.info("building ListenerService of type %s...", plugtype.c_str());
- m_outer->m_listener = conf.ListenerServiceManager.newPlugin(plugtype.c_str(),child);
- }
- else {
- log.fatal("can't build ListenerService, missing conf:Listener element?");
- throw ConfigurationException("Can't build ListenerService, missing conf:Listener element?");
- }
- }
-
- if (conf.isEnabled(SPConfig::Caching)) {
- // TODO: This code's a mess, due to a very bad config layout for the caches...
- // Needs rework with the new config file.
- const DOMElement* container=conf.isEnabled(SPConfig::OutOfProcess) ? SHAR : SHIRE;
-
- // First build any StorageServices.
- string inmemID;
- child=XMLHelper::getFirstChildElement(container,_StorageService);
- while (child) {
- xmltooling::auto_ptr_char id(child->getAttributeNS(NULL,Id));
- xmltooling::auto_ptr_char type(child->getAttributeNS(NULL,_type));
- if (id.get() && type.get()) {
- try {
- log.info("building StorageService (%s) of type %s...", id.get(), type.get());
- m_outer->m_storage[id.get()] = xmlConf.StorageServiceManager.newPlugin(type.get(),child);
- if (!strcmp(type.get(),MEMORY_STORAGE_SERVICE))
- inmemID = id.get();
- }
- catch (exception& ex) {
- log.crit("failed to instantiate StorageService (%s): %s", id.get(), ex.what());
- }
- }
- child=XMLHelper::getNextSiblingElement(container,_StorageService);
- }
-
- child=XMLHelper::getFirstChildElement(container,_SessionCache);
- if (child) {
- xmltooling::auto_ptr_char type(child->getAttributeNS(NULL,_type));
- log.info("building Session Cache of type %s...",type.get());
- m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(type.get(),child);
- }
- else if (conf.isEnabled(SPConfig::OutOfProcess)) {
- log.warn("custom SessionCache unspecified or no longer supported, building SessionCache of type %s...",STORAGESERVICE_SESSION_CACHE);
- if (inmemID.empty()) {
- inmemID = "memory";
- log.info("no StorageServices configured, providing in-memory version for legacy config");
- m_outer->m_storage[inmemID] = xmlConf.StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE,NULL);
- }
- child = container->getOwnerDocument()->createElementNS(NULL,_SessionCache);
- xmltooling::auto_ptr_XMLCh ssid(inmemID.c_str());
- const_cast<DOMElement*>(child)->setAttributeNS(NULL,_StorageService,ssid.get());
- m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(STORAGESERVICE_SESSION_CACHE,child);
- }
- else {
- log.warn("custom SessionCache unspecified or no longer supported, building SessionCache of type %s...",REMOTED_SESSION_CACHE);
- m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(REMOTED_SESSION_CACHE,NULL);
- }
-
- // Replay cache.
- StorageService* replaySS=NULL;
- child=XMLHelper::getFirstChildElement(container,_ReplayCache);
- if (child) {
- xmltooling::auto_ptr_char ssid(child->getAttributeNS(NULL,_StorageService));
- if (ssid.get() && *ssid.get()) {
- replaySS = m_outer->m_storage[ssid.get()];
- if (replaySS)
- log.info("building ReplayCache on top of StorageService (%s)...", ssid.get());
- else
- log.crit("unable to locate StorageService (%s) in configuration", ssid.get());
- }
- }
- if (!replaySS) {
- log.info("building ReplayCache using in-memory StorageService...");
- if (inmemID.empty()) {
- inmemID = "memory";
- log.info("no StorageServices configured, providing in-memory version for legacy config");
- m_outer->m_storage[inmemID] = xmlConf.StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE,NULL);
- }
- replaySS = m_outer->m_storage[inmemID];
- }
- xmlConf.setReplayCache(new ReplayCache(replaySS));
- }
- } // end of first-time-only stuff
-
- // Back to the fully dynamic stuff...next up is the RequestMapper.
- if (conf.isEnabled(SPConfig::RequestMapping)) {
- child=XMLHelper::getFirstChildElement(SHIRE,RequestMapProvider);
- if (child) {
- xmltooling::auto_ptr_char type(child->getAttributeNS(NULL,_type));
- log.info("building RequestMapper of type %s...",type.get());
- m_requestMapper=conf.RequestMapperManager.newPlugin(type.get(),child);
- }
- else {
- log.fatal("can't build RequestMapper, missing conf:RequestMapProvider element?");
- throw ConfigurationException("can't build RequestMapper, missing conf:RequestMapProvider element?");
- }
- }
-
- // Now we load the credentials map.
- if (conf.isEnabled(SPConfig::Credentials)) {
- // Old format was to wrap it in a CredentialsProvider plugin, we're inlining that...
- child = XMLHelper::getFirstChildElement(e,CredentialsProvider);
- child = XMLHelper::getFirstChildElement(child ? child : e,Credentials);
- if (child) {
- // Step down and process resolvers.
- child=XMLHelper::getFirstChildElement(child);
- while (child) {
- xmltooling::auto_ptr_char id(child->getAttributeNS(NULL,Id));
- if (!id.get() || !*(id.get())) {
- log.warn("skipping CredentialsResolver with no Id attribute");
- child = XMLHelper::getNextSiblingElement(child);
- continue;
- }
-
- if (XMLString::equals(child->getLocalName(),FileResolver))
- plugtype=FILESYSTEM_CREDENTIAL_RESOLVER;
- else {
- xmltooling::auto_ptr_char c(child->getAttributeNS(NULL,_type));
- plugtype=c.get();
- }
-
- if (!plugtype.empty()) {
- try {
- CredentialResolver* cr=
- XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(plugtype.c_str(),child);
- m_credResolverMap[id.get()] = cr;
- }
- catch (exception& ex) {
- log.crit("failed to instantiate CredentialResolver (%s): %s", id.get(), ex.what());
- }
- }
- else {
- log.error("unknown type of CredentialResolver with Id (%s)", id.get());
- }
-
- child = XMLHelper::getNextSiblingElement(child);
- }
- }
- }
-
- // Load the default application. This actually has a fixed ID of "default". ;-)
- child=XMLHelper::getFirstChildElement(e,Applications);
- if (!child) {
- log.fatal("can't build default Application object, missing conf:Applications element?");
- throw ConfigurationException("can't build default Application object, missing conf:Applications element?");
- }
- XMLApplication* defapp=new XMLApplication(m_outer,child);
- m_appmap[defapp->getId()]=defapp;
-
- // Load any overrides.
- child = XMLHelper::getFirstChildElement(child,_Application);
- while (child) {
- auto_ptr<XMLApplication> iapp(new XMLApplication(m_outer,child,defapp));
- if (m_appmap.find(iapp->getId())!=m_appmap.end())
- log.crit("found conf:Application element with duplicate Id attribute (%s), skipping it", iapp->getId());
- else
- m_appmap[iapp->getId()]=iapp.release();
-
- child = XMLHelper::getNextSiblingElement(child,_Application);
- }
- }
- catch (exception&) {
- this->~XMLConfigImpl();
- throw;
- }
-#ifndef _DEBUG
- catch (...) {
- this->~XMLConfigImpl();
- throw;
- }
-#endif
-}
-
-XMLConfigImpl::~XMLConfigImpl()
-{
- for_each(m_appmap.begin(),m_appmap.end(),xmltooling::cleanup_pair<string,Application>());
- ShibConfig::getConfig().clearAttributeMappings();
- for_each(m_attrFactories.begin(),m_attrFactories.end(),xmltooling::cleanup<IAttributeFactory>());
- for_each(m_credResolverMap.begin(),m_credResolverMap.end(),xmltooling::cleanup_pair<string,CredentialResolver>());
- delete m_requestMapper;
- if (m_document)
- m_document->release();
-}
-
-pair<bool,DOMElement*> XMLConfig::load()
-{
- // Load from source using base class.
- pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
-
- // If we own it, wrap it.
- XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);
-
- XMLConfigImpl* impl = new XMLConfigImpl(raw.second,(m_impl==NULL),this);
-
- // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
- impl->setDocument(docjanitor.release());
-
- delete m_impl;
- m_impl = impl;
-
- return make_pair(false,(DOMElement*)NULL);
-}
+++ /dev/null
-/*
- * Copyright 2001-2005 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
- *
- * 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.
- */
-
-/*
- * shib-paths.h.in -- source file for the (auto-generated) shib-paths.h
- * used to define the default paths for SHIB's Target
- *
- * Created by: Derek Atkins <derek@ihtfp.com>
- *
- * $Id$
- */
-
-#ifndef SHIB_PATHS_H
-#define SHIB_PATHS_H
-
-/*
- * SHIB_SCHEMAS defines the default location where the schemas will be installed.
- */
-#define SHIB_SCHEMAS "@-PKGXMLDIR-@"
-
-/*
- * SHIB_CONFIG defines the default location of the Shib Target Configuration File.
- */
-#define SHIB_CONFIG "@-PKGSYSCONFDIR-@/shibboleth.xml"
-
-#endif /* SHIB_PATHS_H */
+++ /dev/null
-/*
- * 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
- *
- * 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.
- */
-
-/*
- * shib-target.h -- top-level header file for the SHIB Common Target Library
- *
- * Created by: Derek Atkins <derek@ihtfp.com>
- *
- * $Id$
- */
-
-#ifndef SHIB_TARGET_H
-#define SHIB_TARGET_H
-
-// New headers
-#include <shibsp/Application.h>
-#include <shibsp/Handler.h>
-#include <shibsp/RequestMapper.h>
-#include <shibsp/ServiceProvider.h>
-#include <shibsp/SessionCache.h>
-#include <shibsp/remoting/ListenerService.h>
-
-// Old headers
-#include <saml/saml.h>
-#include <shib/shib.h>
-
-#ifdef WIN32
-# ifndef SHIBTARGET_EXPORTS
-# define SHIBTARGET_EXPORTS __declspec(dllimport)
-# endif
-# define SHIB_SCHEMAS "/opt/shibboleth-sp/share/xml/shibboleth"
-# define SHIB_CONFIG "/opt/shibboleth-sp/etc/shibboleth/shibboleth.xml"
-#else
-# include <shib-target/shib-paths.h>
-# define SHIBTARGET_EXPORTS
-#endif
-
-namespace shibtarget {
-
- // Abstract APIs for access to configuration information
-
- /**
- * Interface to Shibboleth Applications, which exposes most of the functionality
- * required to process web requests or security protocol messages for resources
- * associated with them.
- *
- * Applications are implementation-specific, but generally correspond to collections
- * of resources related to one another in logical ways, such as a virtual host or
- * a Java servlet context. Most complex configuration data is associated with an
- * Application. Implementations should always expose an application named "default"
- * as a last resort.
- */
- struct SHIBTARGET_EXPORTS IApplication : public virtual shibsp::Application,
- public virtual shibboleth::ShibBrowserProfile::ITokenValidator
- {
- // caller is borrowing object, must use within scope of config lock
- virtual const saml::SAMLBrowserProfile* getBrowserProfile() const=0;
- virtual const saml::SAMLBinding* getBinding(const XMLCh* binding) const=0;
-
- // caller is given ownership of object, must use and delete within scope of config lock
- virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
-
- // general token validation based on conditions, signatures, etc.
- virtual void validateToken(
- saml::SAMLAssertion* token,
- time_t t=0,
- const opensaml::saml2md::RoleDescriptor* role=NULL,
- const xmltooling::TrustEngine* trust=NULL
- ) const=0;
-
- virtual ~IApplication() {}
- };
-
- /**
- * OpenSAML binding hook
- *
- * Instead of wrapping the binding to deal with mutual authentication, we
- * just use the HTTP hook functionality offered by OpenSAML. The hook will
- * register "itself" as a globalCtx pointer with the SAML binding and the caller
- * will declare and pass the embedded struct as callCtx for use by the hook.
- */
- class ShibHTTPHook : virtual public saml::SAMLSOAPHTTPBinding::HTTPHook
- {
- public:
- ShibHTTPHook(const xmltooling::TrustEngine* trust) : m_trust(trust) {}
- virtual ~ShibHTTPHook() {}
-
- // Only hook we need here is for outgoing connection to server.
- virtual bool outgoing(saml::HTTPClient* conn, void* globalCtx=NULL, void* callCtx=NULL);
-
- // Client declares a context object and pass as callCtx to send() method.
- class ShibHTTPHookCallContext {
- public:
- ShibHTTPHookCallContext(const shibsp::PropertySet* credUse, const opensaml::saml2md::RoleDescriptor* role)
- : m_credUse(credUse), m_role(role), m_hook(NULL), m_authenticated(false) {}
- const ShibHTTPHook* getHook() {return m_hook;}
- const shibsp::PropertySet* getCredentialUse() {return m_credUse;}
- const opensaml::saml2md::RoleDescriptor* getRoleDescriptor() {return m_role;}
- bool isAuthenticated() const {return m_authenticated;}
- void setAuthenticated() {m_authenticated=true;}
-
- private:
- const shibsp::PropertySet* m_credUse;
- const opensaml::saml2md::RoleDescriptor* m_role;
- ShibHTTPHook* m_hook;
- bool m_authenticated;
- friend class ShibHTTPHook;
- };
-
- const xmltooling::TrustEngine* getTrustEngine() const {return m_trust;}
- private:
- const xmltooling::TrustEngine* m_trust;
- };
-
- /**
- * Interface to a cached user session.
- *
- * Cache entries provide implementations with access to the raw SAML information they
- * need to publish or provide access to the data for applications to use. All creation
- * or access to entries is through the ISessionCache interface, and callers must unlock
- * the entry when finished using it, rather than explicitly freeing them.
- */
- struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual saml::ILockable
- {
- virtual const char* getClientAddress() const=0;
- virtual const char* getProviderId() const=0;
- virtual std::pair<const char*,const saml::SAMLSubject*> getSubject(bool xml=true, bool obj=false) const=0;
- virtual const char* getAuthnContext() const=0;
- virtual std::pair<const char*,const saml::SAMLResponse*> getTokens(bool xml=true, bool obj=false) const=0;
- virtual std::pair<const char*,const saml::SAMLResponse*> getFilteredTokens(bool xml=true, bool obj=false) const=0;
- virtual ~ISessionCacheEntry() {}
- };
-
- /**
- * Interface to a sink for session cache events.
- *
- * All caches support registration of a backing store that can be informed
- * of significant events in the lifecycle of a cache entry.
- */
- struct SHIBTARGET_EXPORTS ISessionCacheStore
- {
- virtual HRESULT onCreate(
- const char* key,
- const IApplication* application,
- const ISessionCacheEntry* entry,
- int majorVersion,
- int minorVersion,
- time_t created
- )=0;
- virtual HRESULT onRead(
- const char* key,
- std::string& applicationId,
- std::string& clientAddress,
- std::string& providerId,
- std::string& subject,
- std::string& authnContext,
- std::string& tokens,
- int& majorVersion,
- int& minorVersion,
- time_t& created,
- time_t& accessed
- )=0;
- virtual HRESULT onRead(const char* key, time_t& accessed)=0;
- virtual HRESULT onRead(const char* key, std::string& tokens)=0;
- virtual HRESULT onUpdate(const char* key, const char* tokens=NULL, time_t lastAccess=0)=0;
- virtual HRESULT onDelete(const char* key)=0;
- virtual ~ISessionCacheStore() {}
- };
-
- /**
- * Interface to the session cache.
- *
- * The session cache abstracts a persistent (meaning across requests) cache of
- * instances of the ISessionCacheEntry interface. Creation of new entries and entry
- * lookup are confined to this interface to enable implementations to flexibly
- * remote and/or optimize calls by implementing custom versions of the
- * ISessionCacheEntry interface as required.
- */
- struct SHIBTARGET_EXPORTS ISessionCache : virtual public shibsp::SessionCache
- {
- virtual std::string insert(
- const IApplication* application,
- const opensaml::saml2md::RoleDescriptor* source,
- const char* client_addr,
- const saml::SAMLSubject* subject,
- const char* authnContext,
- const saml::SAMLResponse* tokens
- )=0;
- virtual ISessionCacheEntry* find(
- const char* key, const IApplication* application, const char* client_addr
- )=0;
- virtual void remove(
- const char* key, const IApplication* application, const char* client_addr
- )=0;
-
- virtual bool setBackingStore(ISessionCacheStore* store)=0;
- virtual ~ISessionCache() {}
- };
-
- #define MEMORY_SESSIONCACHE "edu.internet2.middleware.shibboleth.sp.provider.MemorySessionCacheProvider"
- #define MYSQL_SESSIONCACHE "edu.internet2.middleware.shibboleth.sp.provider.MySQLSessionCacheProvider"
- #define ODBC_SESSIONCACHE "edu.internet2.middleware.shibboleth.sp.provider.ODBCSessionCacheProvider"
-
- #define MYSQL_REPLAYCACHE "edu.internet2.middleware.shibboleth.sp.provider.MySQLReplayCacheProvider"
- #define ODBC_REPLAYCACHE "edu.internet2.middleware.shibboleth.sp.provider.ODBCReplayCacheProvider"
-
-
- class SHIBTARGET_EXPORTS ShibTargetConfig
- {
- public:
- ShibTargetConfig() {}
- virtual ~ShibTargetConfig() {}
-
- virtual bool init(const char* schemadir) = 0;
- virtual bool load(const char* config) = 0;
- virtual void shutdown() = 0;
-
- static ShibTargetConfig& getConfig();
- };
-
-}
-
-#endif /* SHIB_TARGET_H */
+++ /dev/null
-//Microsoft Developer Studio generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifndef _MAC
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 5,0,0,0
- PRODUCTVERSION 1,3,0,0
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x40004L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "Comments", "\0"
- VALUE "CompanyName", "Internet2\0"
- VALUE "FileDescription", "Shibboleth Target Library\0"
- VALUE "FileVersion", "5, 0, 0, 0\0"
-#ifdef _DEBUG
- VALUE "InternalName", "shibtarget_5D\0"
-#else
- VALUE "InternalName", "shibtarget_5\0"
-#endif
- VALUE "LegalCopyright", "Copyright © 2005 Internet2\0"
- VALUE "LegalTrademarks", "\0"
-#ifdef _DEBUG
- VALUE "OriginalFilename", "shibtarget_5D.dll\0"
-#else
- VALUE "OriginalFilename", "shibtarget_5.dll\0"
-#endif
- VALUE "PrivateBuild", "\0"
- VALUE "ProductName", "Shibboleth 1.3\0"
- VALUE "ProductVersion", "1, 3, 0, 0\0"
- VALUE "SpecialBuild", "\0"
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // !_MAC
-
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE DISCARDABLE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE DISCARDABLE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-# Microsoft Developer Studio Project File - Name="shibtarget" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=shibtarget - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "shibtarget.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "shibtarget.mak" CFG="shibtarget - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "shibtarget - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "shibtarget - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "shibtarget - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SHIBTARGET_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "." /I ".." /I "..\oncrpc" /I "..\..\..\opensaml\c" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /D "WANT_TCP_SHAR" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 log4cpp.lib xerces-c_2.lib saml_5.lib wsock32.lib libeay32.lib ssleay32.lib /nologo /dll /machine:I386 /out:"Release/shibtarget_5.dll" /libpath:"..\..\..\opensaml\c\saml\Release" /libpath:"\openssl-0.9.7e\out32dll"
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "shibtarget - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SHIBTARGET_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "." /I ".." /I "..\oncrpc" /I "..\..\..\opensaml\c" /D "_WINDOWS" /D "WANT_TCP_SHAR" /D "WIN32" /D "_DEBUG" /D "_MBCS" /FR /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 log4cppD.lib xerces-c_2D.lib saml_5D.lib wsock32.lib libeay32.lib ssleay32.lib /nologo /dll /debug /machine:I386 /out:"Debug/shibtarget_5D.dll" /pdbtype:sept /libpath:"..\..\..\opensaml\c\saml\Debug" /libpath:"\openssl-0.9.7e\out32dll.dbg"
-# SUBTRACT LINK32 /pdb:none
-
-!ENDIF
-
-# Begin Target
-
-# Name "shibtarget - Win32 Release"
-# Name "shibtarget - Win32 Debug"
-# Begin Source File
-
-SOURCE=.\ArtifactMapper.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\hresult.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\internal.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MemoryListener.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\resource.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\RPCListener.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-ccache.cpp"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-config.cpp"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-handlers.cpp"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-ini.cpp"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-mlp.cpp"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-sock.cpp"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-target.cpp"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-target.h"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shib-target.rc"
-# End Source File
-# Begin Source File
-
-SOURCE=.\ShibHTTPHook.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=".\shibrpc-clnt.c"
-# End Source File
-# Begin Source File
-
-SOURCE=".\shibrpc-xdr.c"
-# End Source File
-# Begin Source File
-
-SOURCE=.\shibrpc.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\XML.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\XMLRequestMapper.cpp
-# End Source File
-# End Target
-# End Project
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="8.00"
- Name="shibtarget"
- ProjectGUID="{84890110-2190-4AAE-9BDC-58F90DF71E4F}"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory=".\Debug"
- IntermediateDirectory=".\Debug"
- ConfigurationType="2"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug/shibtarget.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=".;..;"..\..\cpp-xmltooling";"..\..\cpp-opensaml1";"..\..\cpp-opensaml2""
- PreprocessorDefinitions="_WINDOWS;WANT_TCP_SHAR;WIN32;_DEBUG"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- RuntimeTypeInfo="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile=".\Debug/shibtarget.pch"
- AssemblerListingLocation=".\Debug/"
- ObjectFile=".\Debug/"
- ProgramDataBaseFileName=".\Debug/"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- Detect64BitPortabilityProblems="true"
- DebugInformationFormat="4"
- CompileAs="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="log4cppD.lib xerces-c_2D.lib saml_5D.lib saml2D.lib xmltooling1D.lib wsock32.lib libeay32_0_9_8D.lib ssleay32_0_9_8D.lib"
- OutputFile="Debug/shibtarget_5D.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- AdditionalLibraryDirectories=""..\..\cpp-opensaml1\saml\Debug";"..\..\cpp-opensaml2\Debug";"..\..\cpp-xmltooling\Debug""
- GenerateDebugInformation="true"
- ImportLibrary=".\Debug/shibtarget_5D.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\Release"
- IntermediateDirectory=".\Release"
- ConfigurationType="2"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/shibtarget.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- AdditionalIncludeDirectories=".;..;"..\..\cpp-opensaml1";"..\..\cpp-opensaml2";"..\..\cpp-xmltooling""
- PreprocessorDefinitions="NDEBUG;_WINDOWS;WIN32;WANT_TCP_SHAR"
- StringPooling="true"
- RuntimeLibrary="2"
- EnableFunctionLevelLinking="true"
- RuntimeTypeInfo="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile=".\Release/shibtarget.pch"
- AssemblerListingLocation=".\Release/"
- ObjectFile=".\Release/"
- ProgramDataBaseFileName=".\Release/"
- WarningLevel="3"
- SuppressStartupBanner="true"
- Detect64BitPortabilityProblems="true"
- CompileAs="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="log4cpp.lib xerces-c_2.lib saml_5.lib saml2.lib xmltooling1.lib wsock32.lib libeay32_0_9_8.lib ssleay32_0_9_8.lib"
- OutputFile="Release/shibtarget_5.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- AdditionalLibraryDirectories=""..\..\cpp-opensaml1\saml\Release";"..\..\cpp-opensaml2\Release";"..\..\cpp-xmltooling\Release""
- ProgramDatabaseFile=".\Release/shibtarget_5.pdb"
- ImportLibrary=".\Release/shibtarget_5.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <File
- RelativePath="ArtifactMapper.cpp"
- >
- </File>
- <File
- RelativePath="hresult.h"
- >
- </File>
- <File
- RelativePath="internal.h"
- >
- </File>
- <File
- RelativePath="resource.h"
- >
- </File>
- <File
- RelativePath="shib-config.cpp"
- >
- </File>
- <File
- RelativePath="shib-handlers.cpp"
- >
- </File>
- <File
- RelativePath="shib-ini.cpp"
- >
- </File>
- <File
- RelativePath="shib-target.h"
- >
- </File>
- <File
- RelativePath="shib-target.rc"
- >
- </File>
- <File
- RelativePath="ShibHTTPHook.cpp"
- >
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>