request->getMinorVersion()==1 ? saml::XML::SAML11_PROTOCOL_ENUM : saml::XML::SAML10_PROTOCOL_ENUM
);
if (idp) {
- ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse ? credUse->getString("TLS").second : NULL,idp);
+ ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse,idp);
const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
while (!response && eps.hasNext()) {
request->getMinorVersion()==1 ? saml::XML::SAML11_PROTOCOL_ENUM : saml::XML::SAML10_PROTOCOL_ENUM
);
if (idp) {
- ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse ? credUse->getString("TLS").second : NULL,idp);
+ ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse,idp);
const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
while (eps.hasNext()) {
ArtifactMapper.cpp \
MemoryListener.cpp \
RPCListener.cpp \
+ ShibHTTPHook.cpp \
shib-ccache.cpp \
shib-config.cpp \
shib-handlers.cpp \
--- /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.
+ */
+
+/* ShibHTTPHook.cpp - Shibboleth hook for SAML Binding with SSL callback
+
+ Scott Cantor
+ 2/13/05
+
+ $History:$
+*/
+
+#include "internal.h"
+
+#include <saml/version.h>
+#include <openssl/ssl.h>
+#include <openssl/x509_vfy.h>
+
+using namespace std;
+using namespace log4cpp;
+using namespace shibtarget;
+using namespace shibboleth;
+using namespace saml;
+
+/*
+ * 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
+
+ // Instead of using the supplied verifier, we let the plugins do whatever they want to do
+ // with the untrusted certificates we find in the object. We can save a bit of memory by
+ // just building a vector that points at them inside the supplied structure.
+ vector<void*> chain;
+ for (int i=0; i<sk_X509_num(x509_ctx->untrusted); i++)
+ chain.push_back(sk_X509_value(x509_ctx->untrusted,i));
+
+ Trust t(ctx->getHook()->getTrustProviders());
+ if (!t.validate(x509_ctx->cert,chain,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
+ saml::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 IPropertySet* credUse=ctx->getCredentialUse();
+ pair<bool,const char*> TLS=credUse ? credUse->getString("TLS") : pair<bool,const char*>(false,NULL);
+ if (TLS.first) {
+ Credentials c(ctx->getHook()->getCredentialProviders());
+ const ICredResolver* cr=c.lookup(TLS.second);
+ if (cr)
+ cr->attach(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
+ // The best we can do is assume authentication succeeds because when libcurl reuses
+ // SSL connections, no callback is made. Since we always authenticate SSL connections,
+ // the caller should check that the protocol is https.
+ ctx->setAuthenticated();
+ }
+ 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;
+
+ // The callCtx is our nested context class. Copy in the parent pointer.
+ reinterpret_cast<ShibHTTPHookCallContext*>(callCtx)->m_hook=this;
+
+ // Clear authn status.
+ reinterpret_cast<ShibHTTPHookCallContext*>(callCtx)->m_authenticated=false;
+
+ // 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 IPropertySet* 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);
+ }
+ return true;
+}
/*
- * The Shibboleth License, Version 1.
- * Copyright (c) 2002
- * University Corporation for Advanced Internet Development, Inc.
- * All rights reserved
+ * 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
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution, if any, must include
- * the following acknowledgment: "This product includes software developed by
- * the University Corporation for Advanced Internet Development
- * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
- * may appear in the software itself, if and wherever such third-party
- * acknowledgments normally appear.
- *
- * Neither the name of Shibboleth nor the names of its contributors, nor
- * Internet2, nor the University Corporation for Advanced Internet Development,
- * Inc., nor UCAID may be used to endorse or promote products derived from this
- * software without specific prior written permission. For written permission,
- * please contact shibboleth@shibboleth.org
- *
- * Products derived from this software may not be called Shibboleth, Internet2,
- * UCAID, or the University Corporation for Advanced Internet Development, nor
- * may Shibboleth appear in their name, without prior written permission of the
- * University Corporation for Advanced Internet Development.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
- * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
- * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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
// Call context object
Trust t(application->getTrustProviders());
- ShibHTTPHook::ShibHTTPHookCallContext ctx(credUse ? credUse->getString("TLS").second : NULL,AA);
+ ShibHTTPHook::ShibHTTPHookCallContext ctx(credUse,AA);
// Use metadata to locate endpoints.
Iterator<const IEndpoint*> endpoints=AA->getAttributeServiceManager()->getEndpoints();
virtual ~IApplication() {}
};
+ // 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 saml::Iterator<shibboleth::ITrust*>& trusts, const saml::Iterator<shibboleth::ICredentials*>& creds)
+ : m_trusts(trusts), m_creds(creds) {}
+ 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 IPropertySet* credUse, const shibboleth::IRoleDescriptor* role)
+ : m_credUse(credUse), m_role(role), m_hook(NULL), m_authenticated(false) {}
+ const ShibHTTPHook* getHook() {return m_hook;}
+ const IPropertySet* getCredentialUse() {return m_credUse;}
+ const shibboleth::IRoleDescriptor* getRoleDescriptor() {return m_role;}
+ bool isAuthenticated() const {return m_authenticated;}
+ void setAuthenticated() {m_authenticated=true;}
+
+ private:
+ const IPropertySet* m_credUse;
+ const shibboleth::IRoleDescriptor* m_role;
+ ShibHTTPHook* m_hook;
+ bool m_authenticated;
+ friend class ShibHTTPHook;
+ };
+
+ const saml::Iterator<shibboleth::ITrust*>& getTrustProviders() const {return m_trusts;}
+ const saml::Iterator<shibboleth::ICredentials*>& getCredentialProviders() const {return m_creds;}
+ private:
+ saml::Iterator<shibboleth::ITrust*> m_trusts;
+ saml::Iterator<shibboleth::ICredentials*> m_creds;
+ };
+
struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual saml::ILockable
{
virtual bool isValid(time_t lifetime, time_t timeout) const=0;
# 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 wsock32.lib saml_5.lib /nologo /dll /machine:I386 /out:"Release/shibtarget_5.dll" /libpath:"..\..\..\opensaml\c\saml\Release"
+# 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 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 "_DEBUG" /D "_AFXDLL" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /D "WANT_TCP_SHAR" /FR /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 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 wsock32.lib saml_5D.lib /nologo /dll /debug /machine:I386 /out:"Debug/shibtarget_5D.dll" /pdbtype:sept /libpath:"..\..\..\opensaml\c\saml\Debug"
+# 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
# 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