diff --git a/src/vmime/net/serviceInfos.cpp b/src/vmime/net/serviceInfos.cpp index 8de0529e..c5d0124a 100644 --- a/src/vmime/net/serviceInfos.cpp +++ b/src/vmime/net/serviceInfos.cpp @@ -50,6 +50,9 @@ const serviceInfos::property serviceInfos::property::AUTH_USERNAME const serviceInfos::property serviceInfos::property::AUTH_PASSWORD ("auth.password", serviceInfos::property::TYPE_STRING); +const serviceInfos::property serviceInfos::property::AUTH_ACCESS_TOKEN + ("auth.accesstoken", serviceInfos::property::TYPE_STRING); + #if VMIME_HAVE_TLS_SUPPORT const serviceInfos::property serviceInfos::property::CONNECTION_TLS diff --git a/src/vmime/net/serviceInfos.hpp b/src/vmime/net/serviceInfos.hpp index ec4ca7d6..5c3909b2 100644 --- a/src/vmime/net/serviceInfos.hpp +++ b/src/vmime/net/serviceInfos.hpp @@ -90,6 +90,10 @@ public: * password used to authenticate with the server. */ static const property AUTH_PASSWORD; + /** The common property 'auth.accesstoken' which is the + * access token used to authenticate with the server. */ + static const property AUTH_ACCESS_TOKEN; + #if VMIME_HAVE_TLS_SUPPORT /** The common property 'connection.tls': this is used to diff --git a/src/vmime/security/authenticator.hpp b/src/vmime/security/authenticator.hpp index bef07b4a..fc6bf5d5 100644 --- a/src/vmime/security/authenticator.hpp +++ b/src/vmime/security/authenticator.hpp @@ -81,6 +81,15 @@ public: */ virtual const string getPassword() const = 0; + /** Return the optional access token for authentication. This is + * used for example with XOAuth2 SASL authentication. + * + * @return access token + * @throw exceptions::no_auth_information if the information + * could not be provided + */ + virtual const string getAccessToken() const = 0; + /** Return the local host name of the machine. * * @return hostname diff --git a/src/vmime/security/defaultAuthenticator.cpp b/src/vmime/security/defaultAuthenticator.cpp index 790196d2..1c66b6c6 100644 --- a/src/vmime/security/defaultAuthenticator.cpp +++ b/src/vmime/security/defaultAuthenticator.cpp @@ -76,6 +76,20 @@ const string defaultAuthenticator::getPassword() const } +const string defaultAuthenticator::getAccessToken() const +{ + shared_ptr service = m_service.lock(); + + const string prefix = service->getInfos().getPropertyPrefix(); + const propertySet& props = service->getSession()->getProperties(); + + if (props.hasProperty(prefix + net::serviceInfos::property::AUTH_ACCESS_TOKEN.getName())) + return props[prefix + net::serviceInfos::property::AUTH_ACCESS_TOKEN.getName()]; + + throw exceptions::no_auth_information(); +} + + const string defaultAuthenticator::getHostname() const { return platform::getHandler()->getHostName(); diff --git a/src/vmime/security/defaultAuthenticator.hpp b/src/vmime/security/defaultAuthenticator.hpp index eead3d14..645d026e 100644 --- a/src/vmime/security/defaultAuthenticator.hpp +++ b/src/vmime/security/defaultAuthenticator.hpp @@ -53,6 +53,7 @@ public: const string getHostname() const; const string getAnonymousToken() const; const string getServiceName() const; + const string getAccessToken() const; void setService(shared_ptr serv); weak_ptr getService() const; diff --git a/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp b/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp new file mode 100644 index 00000000..01371dea --- /dev/null +++ b/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp @@ -0,0 +1,98 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT + + +#include "vmime/security/sasl/XOAuth2SASLAuthenticator.hpp" + +#include "vmime/security/sasl/SASLMechanism.hpp" +#include "vmime/security/sasl/SASLSession.hpp" +#include "vmime/security/sasl/SASLContext.hpp" + + +namespace vmime { +namespace security { +namespace sasl { + + +XOAuth2SASLAuthenticator::XOAuth2SASLAuthenticator(const Mode mode) + : m_mode(mode) +{ +} + + +XOAuth2SASLAuthenticator::~XOAuth2SASLAuthenticator() +{ +} + + +const std::vector > + XOAuth2SASLAuthenticator::getAcceptableMechanisms + (const std::vector >& available, + shared_ptr suggested) const +{ + if (m_mode == MODE_EXCLUSIVE) + { + std::vector > mechs; + + for (size_t i = available.size() ; i != 0 ; --i) + { + shared_ptr mech = available[i - 1]; + + if ("XOAUTH2" == mech->getName()) + { + // Only allow XOAuth2 + mechs.push_back(mech); + } + } + + return mechs; + } + else + { + for (size_t i = available.size() ; i != 0 ; --i) + { + shared_ptr mech = available[i - 1]; + + if ("XOAUTH2" == mech->getName()) + { + // Suggest using XOAuth2 + suggested = mech; + } + } + + return defaultSASLAuthenticator::getAcceptableMechanisms(available, suggested); + } +} + + +} // sasl +} // security +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT diff --git a/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp b/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp new file mode 100644 index 00000000..cbccf0f5 --- /dev/null +++ b/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp @@ -0,0 +1,78 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_SECURITY_SASL_XOAUTH2SASLAUTHENTICATOR_HPP_INCLUDED +#define VMIME_SECURITY_SASL_XOAUTH2SASLAUTHENTICATOR_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT + + +#include "vmime/security/sasl/defaultSASLAuthenticator.hpp" + + +namespace vmime { +namespace security { +namespace sasl { + + +/** An authenticator that is capable of providing information + * for XOAuth2 authentication mechanisms (username and access token). + * This authenticator force using the XOAUTH2 mechanism. + */ +class VMIME_EXPORT XOAuth2SASLAuthenticator : public defaultSASLAuthenticator +{ +public: + + enum Mode + { + MODE_SUGGEST, /**< Try XOAUTH2 before other mechanisms. */ + MODE_EXCLUSIVE /**< Use XOAUTH2 and nothing else. */ + }; + + + XOAuth2SASLAuthenticator(const Mode mode); + ~XOAuth2SASLAuthenticator(); + + const std::vector > getAcceptableMechanisms + (const std::vector >& available, + shared_ptr suggested) const; + +private: + + Mode m_mode; +}; + + +} // sasl +} // security +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT + +#endif // VMIME_SECURITY_SASL_XOAUTH2SASLAUTHENTICATOR_HPP_INCLUDED + diff --git a/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp b/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp new file mode 100644 index 00000000..a1150667 --- /dev/null +++ b/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp @@ -0,0 +1,142 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT + + +#include "vmime/security/sasl/XOAuth2SASLMechanism.hpp" + +#include "vmime/security/sasl/SASLContext.hpp" +#include "vmime/security/sasl/SASLSession.hpp" + +#include "vmime/exception.hpp" + +#include + + +namespace vmime { +namespace security { +namespace sasl { + + +XOAuth2SASLMechanism::XOAuth2SASLMechanism(shared_ptr ctx, const string& /* name */) + : m_context(ctx), m_complete(false) +{ +} + + +XOAuth2SASLMechanism::~XOAuth2SASLMechanism() +{ +} + + +const string XOAuth2SASLMechanism::getName() const +{ + return "XOAUTH2"; +} + + +bool XOAuth2SASLMechanism::step + (shared_ptr sess, + const byte_t* /* challenge */, const size_t /* challengeLen */, + byte_t** response, size_t* responseLen) +{ + // Build initial response + // + // The SASL XOAUTH2 initial client response has the following format: + // base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A") + + const std::string user(sess->getAuthenticator()->getUsername()); + const std::string accessToken(sess->getAuthenticator()->getAccessToken()); + + std::ostringstream initRespBytes; + initRespBytes.write("user=", 5); + initRespBytes.write(user.c_str(), user.length()); + initRespBytes.write("\x01", 1); + initRespBytes.write("auth=Bearer ", 12); + initRespBytes.write(accessToken.c_str(), accessToken.length()); + initRespBytes.write("\x01\x01", 2); + + const std::string initResp = initRespBytes.str(); + + // Set initial response + byte_t* res = new byte_t[initResp.length()]; + std::copy(initResp.c_str(), initResp.c_str() + initResp.length(), res); + + *response = res; + *responseLen = initResp.length(); + m_complete = true; + + return true; +} + + +bool XOAuth2SASLMechanism::isComplete() const +{ + return m_complete; +} + + +bool XOAuth2SASLMechanism::hasInitialResponse() const +{ + return true; +} + + +void XOAuth2SASLMechanism::encode + (shared_ptr /* sess */, + const byte_t* input, const size_t inputLen, + byte_t** output, size_t* outputLen) +{ + // No encoding performed, just copy input bytes + byte_t* res = new byte_t[inputLen]; + std::copy(input, input + inputLen, res); + + *outputLen = inputLen; + *output = res; +} + + +void XOAuth2SASLMechanism::decode + (shared_ptr /* sess */, + const byte_t* input, const size_t inputLen, + byte_t** output, size_t* outputLen) +{ + // No decoding performed, just copy input bytes + byte_t* res = new byte_t[inputLen]; + std::copy(input, input + inputLen, res); + + *outputLen = inputLen; + *output = res; +} + + +} // sasl +} // security +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT diff --git a/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp b/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp new file mode 100644 index 00000000..37dbdae5 --- /dev/null +++ b/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp @@ -0,0 +1,91 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_SECURITY_SASL_XOAUTH2SASLMECHANISM_HPP_INCLUDED +#define VMIME_SECURITY_SASL_XOAUTH2SASLMECHANISM_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT + + +#include "vmime/security/sasl/SASLMechanism.hpp" + + +namespace vmime { +namespace security { +namespace sasl { + + +class SASLContext; + + +/** SASL XOAUTH2 mechanism, used by GMail. + */ +class VMIME_EXPORT XOAuth2SASLMechanism : public SASLMechanism +{ +public: + + XOAuth2SASLMechanism(shared_ptr ctx, const string& name); + ~XOAuth2SASLMechanism(); + + + const string getName() const; + + bool step(shared_ptr sess, + const byte_t* challenge, const size_t challengeLen, + byte_t** response, size_t* responseLen); + + bool isComplete() const; + + bool hasInitialResponse() const; + + void encode(shared_ptr sess, + const byte_t* input, const size_t inputLen, + byte_t** output, size_t* outputLen); + + void decode(shared_ptr sess, + const byte_t* input, const size_t inputLen, + byte_t** output, size_t* outputLen); + +private: + + /** SASL context */ + shared_ptr m_context; + + /** Authentication process status. */ + bool m_complete; +}; + + +} // sasl +} // security +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT + +#endif // VMIME_SECURITY_SASL_XOAUTH2SASLMECHANISM_HPP_INCLUDED + diff --git a/src/vmime/security/sasl/defaultSASLAuthenticator.cpp b/src/vmime/security/sasl/defaultSASLAuthenticator.cpp index 7fe9b3eb..124f5c3f 100644 --- a/src/vmime/security/sasl/defaultSASLAuthenticator.cpp +++ b/src/vmime/security/sasl/defaultSASLAuthenticator.cpp @@ -89,6 +89,12 @@ const string defaultSASLAuthenticator::getPassword() const } +const string defaultSASLAuthenticator::getAccessToken() const +{ + return m_default.getAccessToken(); +} + + const string defaultSASLAuthenticator::getHostname() const { return m_default.getHostname(); diff --git a/src/vmime/security/sasl/defaultSASLAuthenticator.hpp b/src/vmime/security/sasl/defaultSASLAuthenticator.hpp index 6ea9af80..07baf975 100644 --- a/src/vmime/security/sasl/defaultSASLAuthenticator.hpp +++ b/src/vmime/security/sasl/defaultSASLAuthenticator.hpp @@ -59,6 +59,7 @@ public: const string getHostname() const; const string getAnonymousToken() const; const string getServiceName() const; + const string getAccessToken() const; void setService(shared_ptr serv); weak_ptr getService() const;