diff options
Diffstat (limited to 'qpid/cpp/src/qpid/client/windows')
-rw-r--r-- | qpid/cpp/src/qpid/client/windows/SaslFactory.cpp | 177 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/client/windows/SslConnector.cpp | 181 |
2 files changed, 358 insertions, 0 deletions
diff --git a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp new file mode 100644 index 0000000000..d1ae762f1b --- /dev/null +++ b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp @@ -0,0 +1,177 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/SaslFactory.h" + +#include "qpid/Exception.h" +#include "qpid/framing/reply_exceptions.h" +#include "qpid/sys/SecurityLayer.h" +#include "qpid/sys/SecuritySettings.h" +#include "qpid/log/Statement.h" + +#include "boost/tokenizer.hpp" + +namespace qpid { + +using qpid::sys::SecurityLayer; +using qpid::sys::SecuritySettings; +using qpid::framing::InternalErrorException; + +struct WindowsSaslSettings +{ + WindowsSaslSettings ( ) : + username ( std::string(0) ), + password ( std::string(0) ), + service ( std::string(0) ), + host ( std::string(0) ), + minSsf ( 0 ), + maxSsf ( 0 ) + { + } + + WindowsSaslSettings ( const std::string & user, const std::string & password, const std::string & service, const std::string & host, int minSsf, int maxSsf ) : + username(user), + password(password), + service(service), + host(host), + minSsf(minSsf), + maxSsf(maxSsf) + { + } + + std::string username, + password, + service, + host; + + int minSsf, + maxSsf; +}; + +class WindowsSasl : public Sasl +{ + public: + WindowsSasl( const std::string &, const std::string &, const std::string &, const std::string &, int, int ); + ~WindowsSasl(); + std::string start(const std::string& mechanisms, const SecuritySettings* externalSettings); + std::string step(const std::string& challenge); + std::string getMechanism(); + std::string getUserId(); + std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); + private: + WindowsSaslSettings settings; + std::string mechanism; +}; + +qpid::sys::Mutex SaslFactory::lock; +std::auto_ptr<SaslFactory> SaslFactory::instance; + +SaslFactory::SaslFactory() +{ +} + +SaslFactory::~SaslFactory() +{ +} + +SaslFactory& SaslFactory::getInstance() +{ + qpid::sys::Mutex::ScopedLock l(lock); + if (!instance.get()) { + instance = std::auto_ptr<SaslFactory>(new SaslFactory()); + } + return *instance; +} + +std::auto_ptr<Sasl> SaslFactory::create( const std::string & username, const std::string & password, const std::string & serviceName, const std::string & hostName, int minSsf, int maxSsf, bool ) +{ + std::auto_ptr<Sasl> sasl(new WindowsSasl( username, password, serviceName, hostName, minSsf, maxSsf )); + return sasl; +} + +namespace { + const std::string ANONYMOUS = "ANONYMOUS"; + const std::string PLAIN = "PLAIN"; +} + +WindowsSasl::WindowsSasl( const std::string & username, const std::string & password, const std::string & serviceName, const std::string & hostName, int minSsf, int maxSsf ) + : settings(username, password, serviceName, hostName, minSsf, maxSsf) +{ +} + +WindowsSasl::~WindowsSasl() +{ +} + +std::string WindowsSasl::start(const std::string& mechanisms, + const SecuritySettings* /*externalSettings*/) +{ + QPID_LOG(debug, "WindowsSasl::start(" << mechanisms << ")"); + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + bool havePlain = false; + bool haveAnon = false; + tokenizer mechs(mechanisms, sep); + for (tokenizer::iterator mech = mechs.begin(); + mech != mechs.end(); + ++mech) { + if (*mech == ANONYMOUS) + haveAnon = true; + else if (*mech == PLAIN) + havePlain = true; + } + if (!haveAnon && !havePlain) + throw InternalErrorException(QPID_MSG("Sasl error: no common mechanism")); + + std::string resp = ""; + if (havePlain) { + mechanism = PLAIN; + resp = ((char)0) + settings.username + ((char)0) + settings.password; + } + else { + mechanism = ANONYMOUS; + } + return resp; +} + +std::string WindowsSasl::step(const std::string& /*challenge*/) +{ + // Shouldn't get this for PLAIN... + throw InternalErrorException(QPID_MSG("Sasl step error")); +} + +std::string WindowsSasl::getMechanism() +{ + return mechanism; +} + +std::string WindowsSasl::getUserId() +{ + return std::string(); // TODO - when GSSAPI is supported, return userId for connection. +} + +std::auto_ptr<SecurityLayer> WindowsSasl::getSecurityLayer(uint16_t /*maxFrameSize*/) +{ + return std::auto_ptr<SecurityLayer>(0); +} + +} // namespace qpid diff --git a/qpid/cpp/src/qpid/client/windows/SslConnector.cpp b/qpid/cpp/src/qpid/client/windows/SslConnector.cpp new file mode 100644 index 0000000000..785c817928 --- /dev/null +++ b/qpid/cpp/src/qpid/client/windows/SslConnector.cpp @@ -0,0 +1,181 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/TCPConnector.h" + +#include "config.h" +#include "qpid/Msg.h" +#include "qpid/client/ConnectionImpl.h" +#include "qpid/client/ConnectionSettings.h" +#include "qpid/log/Statement.h" +#include "qpid/sys/Dispatcher.h" +#include "qpid/sys/Poller.h" +#include "qpid/sys/Time.h" +#include "qpid/sys/windows/check.h" +#include "qpid/sys/windows/SslAsynchIO.h" + +#include <iostream> +#include <boost/bind.hpp> +#include <boost/format.hpp> + +#include <memory.h> +// security.h needs to see this to distinguish from kernel use. +#define SECURITY_WIN32 +#include <security.h> +#include <Schnlsp.h> +#undef SECURITY_WIN32 +#include <winsock2.h> + +namespace qpid { +namespace client { +namespace windows { + +using namespace qpid::sys; +using boost::format; +using boost::str; + + +class SslConnector : public qpid::client::TCPConnector +{ + qpid::sys::windows::ClientSslAsynchIO *shim; + boost::shared_ptr<qpid::sys::Poller> poller; + std::string brokerHost; + SCHANNEL_CRED cred; + CredHandle credHandle; + TimeStamp credExpiry; + + virtual ~SslConnector(); + void negotiationDone(SECURITY_STATUS status); + + // A number of AsynchIO callbacks go right through to TCPConnector, but + // we can't boost::bind to a protected ancestor, so these methods redirect + // to those TCPConnector methods. + bool redirectReadbuff(qpid::sys::AsynchIO&, qpid::sys::AsynchIOBufferBase*); + void redirectWritebuff(qpid::sys::AsynchIO&); + void redirectEof(qpid::sys::AsynchIO&); + +public: + SslConnector(boost::shared_ptr<qpid::sys::Poller>, + framing::ProtocolVersion pVersion, + const ConnectionSettings&, + ConnectionImpl*); + virtual void connect(const std::string& host, const std::string& port); + virtual void connected(const Socket&); + unsigned int getSSF(); +}; + +// Static constructor which registers connector here +namespace { + Connector* create(boost::shared_ptr<qpid::sys::Poller> p, + framing::ProtocolVersion v, + const ConnectionSettings& s, + ConnectionImpl* c) { + return new SslConnector(p, v, s, c); + } + + struct StaticInit { + StaticInit() { + try { + Connector::registerFactory("ssl", &create); + } catch (const std::exception& e) { + QPID_LOG(error, "Failed to initialise SSL connector: " << e.what()); + } + }; + ~StaticInit() { } + } init; +} + +void SslConnector::negotiationDone(SECURITY_STATUS status) +{ + if (status == SEC_E_OK) + initAmqp(); + else + connectFailed(QPID_MSG(qpid::sys::strError(status))); +} + +bool SslConnector::redirectReadbuff(qpid::sys::AsynchIO& a, + qpid::sys::AsynchIOBufferBase* b) { + return readbuff(a, b); +} + +void SslConnector::redirectWritebuff(qpid::sys::AsynchIO& a) { + writebuff(a); +} + +void SslConnector::redirectEof(qpid::sys::AsynchIO& a) { + eof(a); +} + +SslConnector::SslConnector(boost::shared_ptr<qpid::sys::Poller> p, + framing::ProtocolVersion ver, + const ConnectionSettings& settings, + ConnectionImpl* cimpl) + : TCPConnector(p, ver, settings, cimpl), shim(0), poller(p) +{ + memset(&cred, 0, sizeof(cred)); + cred.dwVersion = SCHANNEL_CRED_VERSION; + SECURITY_STATUS status = ::AcquireCredentialsHandle(NULL, + UNISP_NAME, + SECPKG_CRED_OUTBOUND, + NULL, + &cred, + NULL, + NULL, + &credHandle, + &credExpiry); + if (status != SEC_E_OK) + throw QPID_WINDOWS_ERROR(status); + QPID_LOG(debug, "SslConnector created for " << ver.toString()); +} + +SslConnector::~SslConnector() +{ + ::FreeCredentialsHandle(&credHandle); +} + + // Will this get reach via virtual method via boost::bind???? + +void SslConnector::connect(const std::string& host, const std::string& port) { + brokerHost = host; + TCPConnector::connect(host, port); +} + +void SslConnector::connected(const Socket& s) { + shim = new qpid::sys::windows::ClientSslAsynchIO(brokerHost, + s, + credHandle, + boost::bind(&SslConnector::redirectReadbuff, this, _1, _2), + boost::bind(&SslConnector::redirectEof, this, _1), + boost::bind(&SslConnector::redirectEof, this, _1), + 0, // closed + 0, // nobuffs + boost::bind(&SslConnector::redirectWritebuff, this, _1), + boost::bind(&SslConnector::negotiationDone, this, _1)); + start(shim); + shim->start(poller); +} + +unsigned int SslConnector::getSSF() +{ + return shim->getSslKeySize(); +} + +}}} // namespace qpid::client::windows |