diff options
| -rw-r--r-- | Swiften/Client/ClientSession.cpp | 13 | ||||
| -rw-r--r-- | Swiften/Client/ClientSession.h | 3 | ||||
| -rw-r--r-- | Swiften/Elements/AuthSuccess.h | 5 | ||||
| -rw-r--r-- | Swiften/LinkLocal/IncomingLinkLocalSession.cpp | 1 | ||||
| -rw-r--r-- | Swiften/SASL/ClientAuthenticator.cpp | 11 | ||||
| -rw-r--r-- | Swiften/SASL/ClientAuthenticator.h | 43 | ||||
| -rw-r--r-- | Swiften/SASL/PLAINClientAuthenticator.cpp | 16 | ||||
| -rw-r--r-- | Swiften/SASL/PLAINClientAuthenticator.h | 13 | ||||
| -rw-r--r-- | Swiften/SASL/PLAINMessage.h | 2 | ||||
| -rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp | 12 | ||||
| -rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.h | 11 | ||||
| -rw-r--r-- | Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp | 35 | ||||
| -rw-r--r-- | Swiften/SConscript | 3 |
13 files changed, 149 insertions, 19 deletions
diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index a95c058..06a7617 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -10,24 +10,25 @@ #include "Swiften/Elements/AuthRequest.h" #include "Swiften/Elements/AuthSuccess.h" #include "Swiften/Elements/AuthFailure.h" #include "Swiften/Elements/StartSession.h" #include "Swiften/Elements/IQ.h" #include "Swiften/Elements/ResourceBind.h" -#include "Swiften/SASL/PLAINMessage.h" +#include "Swiften/SASL/PLAINClientAuthenticator.h" #include "Swiften/Session/SessionStream.h" namespace Swift { ClientSession::ClientSession( const JID& jid, boost::shared_ptr<SessionStream> stream) : localJID(jid), state(Initial), stream(stream), - needSessionStart(false) { + needSessionStart(false), + authenticator(NULL) { } void ClientSession::start() { stream->onStreamStartReceived.connect(boost::bind(&ClientSession::handleStreamStart, shared_from_this(), _1)); stream->onElementReceived.connect(boost::bind(&ClientSession::handleElement, shared_from_this(), _1)); stream->onError.connect(boost::bind(&ClientSession::handleStreamError, shared_from_this(), _1)); @@ -74,12 +75,13 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else { finishSession(Error::TLSClientCertificateError); } } else if (streamFeatures->hasAuthenticationMechanism("PLAIN")) { + authenticator = new PLAINClientAuthenticator(); state = WaitingForCredentials; onNeedCredentials(); } else { finishSession(Error::NoSupportedAuthMechanismsError); } @@ -109,16 +111,20 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } } } else if (dynamic_cast<AuthSuccess*>(element.get())) { checkState(Authenticating); state = WaitingForStreamStart; + delete authenticator; + authenticator = NULL; stream->resetXMPPParser(); sendStreamHeader(); } else if (dynamic_cast<AuthFailure*>(element.get())) { + delete authenticator; + authenticator = NULL; finishSession(Error::AuthenticationFailedError); } else if (dynamic_cast<TLSProceed*>(element.get())) { checkState(WaitingForEncrypt); state = Encrypting; stream->addTLSEncryption(); @@ -187,13 +193,14 @@ bool ClientSession::checkState(State state) { return true; } void ClientSession::sendCredentials(const String& password) { assert(WaitingForCredentials); state = Authenticating; - stream->writeElement(boost::shared_ptr<Element>(new AuthRequest("PLAIN", PLAINMessage(localJID.getNode(), password).getValue()))); + authenticator->setCredentials(localJID.getNode(), password); + stream->writeElement(boost::shared_ptr<AuthRequest>(new AuthRequest(authenticator->getName(), authenticator->getResponse()))); } void ClientSession::handleTLSEncrypted() { checkState(WaitingForEncrypt); state = WaitingForStreamStart; stream->resetXMPPParser(); diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index f980a9e..f3bc119 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -9,12 +9,14 @@ #include "Swiften/Session/BasicSessionStream.h" #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" #include "Swiften/Elements/Element.h" namespace Swift { + class ClientAuthenticator; + class ClientSession : public boost::enable_shared_from_this<ClientSession> { public: enum State { Initial, WaitingForStreamStart, Negotiating, @@ -87,8 +89,9 @@ namespace Swift { private: JID localJID; State state; boost::shared_ptr<SessionStream> stream; bool needSessionStart; + ClientAuthenticator* authenticator; }; } diff --git a/Swiften/Elements/AuthSuccess.h b/Swiften/Elements/AuthSuccess.h index f63d0a8..da4d798 100644 --- a/Swiften/Elements/AuthSuccess.h +++ b/Swiften/Elements/AuthSuccess.h @@ -1,13 +1,10 @@ -#ifndef SWIFTEN_AuthSuccess_H -#define SWIFTEN_AuthSuccess_H +#pragma once #include "Swiften/Elements/Element.h" namespace Swift { class AuthSuccess : public Element { public: AuthSuccess() {} }; } - -#endif diff --git a/Swiften/LinkLocal/IncomingLinkLocalSession.cpp b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp index 4c3a681..77910e6 100644 --- a/Swiften/LinkLocal/IncomingLinkLocalSession.cpp +++ b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp @@ -6,13 +6,12 @@ #include "Swiften/Network/Connection.h" #include "Swiften/StreamStack/StreamStack.h" #include "Swiften/StreamStack/ConnectionLayer.h" #include "Swiften/StreamStack/XMPPLayer.h" #include "Swiften/Elements/StreamFeatures.h" #include "Swiften/Elements/IQ.h" -#include "Swiften/SASL/PLAINMessage.h" namespace Swift { IncomingLinkLocalSession::IncomingLinkLocalSession( const JID& localJID, boost::shared_ptr<Connection> connection, diff --git a/Swiften/SASL/ClientAuthenticator.cpp b/Swiften/SASL/ClientAuthenticator.cpp new file mode 100644 index 0000000..5fc9e85 --- /dev/null +++ b/Swiften/SASL/ClientAuthenticator.cpp @@ -0,0 +1,11 @@ +#include "Swiften/SASL/ClientAuthenticator.h" + +namespace Swift { + +ClientAuthenticator::ClientAuthenticator(const String& name) : name(name) { +} + +ClientAuthenticator::~ClientAuthenticator() { +} + +} diff --git a/Swiften/SASL/ClientAuthenticator.h b/Swiften/SASL/ClientAuthenticator.h new file mode 100644 index 0000000..f42a51e --- /dev/null +++ b/Swiften/SASL/ClientAuthenticator.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" + +namespace Swift { + class ClientAuthenticator { + public: + ClientAuthenticator(const String& name); + virtual ~ClientAuthenticator(); + + const String& getName() const { + return name; + } + + void setCredentials(const String& authcid, const String& password, const String& authzid = String()) { + this->authcid = authcid; + this->password = password; + this->authzid = authzid; + } + + virtual ByteArray getResponse() const = 0; + virtual bool setChallenge(const ByteArray&) = 0; + + const String& getAuthenticationID() const { + return authcid; + } + + const String& getAuthorizationID() const { + return authzid; + } + + const String& getPassword() const { + return password; + } + + private: + String name; + String authcid; + String password; + String authzid; + }; +} diff --git a/Swiften/SASL/PLAINClientAuthenticator.cpp b/Swiften/SASL/PLAINClientAuthenticator.cpp new file mode 100644 index 0000000..8f88c3c --- /dev/null +++ b/Swiften/SASL/PLAINClientAuthenticator.cpp @@ -0,0 +1,16 @@ +#include "Swiften/SASL/PLAINClientAuthenticator.h" + +namespace Swift { + +PLAINClientAuthenticator::PLAINClientAuthenticator() : ClientAuthenticator("PLAIN") { +} + +ByteArray PLAINClientAuthenticator::getResponse() const { + return ByteArray(getAuthorizationID()) + '\0' + ByteArray(getAuthenticationID()) + '\0' + ByteArray(getPassword()); +} + +bool PLAINClientAuthenticator::setChallenge(const ByteArray&) { + return true; +} + +} diff --git a/Swiften/SASL/PLAINClientAuthenticator.h b/Swiften/SASL/PLAINClientAuthenticator.h new file mode 100644 index 0000000..854eb30 --- /dev/null +++ b/Swiften/SASL/PLAINClientAuthenticator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Swiften/SASL/ClientAuthenticator.h" + +namespace Swift { + class PLAINClientAuthenticator : public ClientAuthenticator { + public: + PLAINClientAuthenticator(); + + virtual ByteArray getResponse() const; + virtual bool setChallenge(const ByteArray&); + }; +} diff --git a/Swiften/SASL/PLAINMessage.h b/Swiften/SASL/PLAINMessage.h index 76de4f5..dd5e2ee 100644 --- a/Swiften/SASL/PLAINMessage.h +++ b/Swiften/SASL/PLAINMessage.h @@ -1,6 +1,8 @@ +// TODO: Get rid of this +// #pragma once #include "Swiften/Base/String.h" #include "Swiften/Base/ByteArray.h" namespace Swift { diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp index b2e85e9..3109f56 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp @@ -4,30 +4,30 @@ #include "Swiften/StringCodecs/SHA1.h" #include "Swiften/StringCodecs/HMACSHA1.h" namespace Swift { -SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const String& authcid, const String& password, const String& authzid, const ByteArray& nonce) : step(Initial), authcid(authcid), password(password), authzid(authzid), clientnonce(nonce) { +SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const ByteArray& nonce) : ClientAuthenticator("SCRAM-SHA1"), step(Initial), clientnonce(nonce) { } -ByteArray SCRAMSHA1ClientAuthenticator::getMessage() const { +ByteArray SCRAMSHA1ClientAuthenticator::getResponse() const { if (step == Initial) { return getInitialClientMessage(); } else { ByteArray mask = HMACSHA1::getResult(getClientVerifier(), initialServerMessage + getInitialClientMessage()); - ByteArray p = SHA1::getBinaryHash(password); + ByteArray p = SHA1::getBinaryHash(getPassword()); for (unsigned int i = 0; i < p.getSize(); ++i) { p[i] ^= mask[i]; } return p; } } -bool SCRAMSHA1ClientAuthenticator::setResponse(const ByteArray& response) { +bool SCRAMSHA1ClientAuthenticator::setChallenge(const ByteArray& response) { if (step == Initial) { initialServerMessage = response; step = Proof; return getSalt().getSize() > 0; } else { @@ -43,14 +43,14 @@ ByteArray SCRAMSHA1ClientAuthenticator::getSalt() const { else { return ByteArray(initialServerMessage.getData(), 8); } } ByteArray SCRAMSHA1ClientAuthenticator::getClientVerifier() const { - return HMACSHA1::getResult(SHA1::getBinaryHash(password), getSalt()); + return HMACSHA1::getResult(SHA1::getBinaryHash(getPassword()), getSalt()); } ByteArray SCRAMSHA1ClientAuthenticator::getInitialClientMessage() const { - return ByteArray(authzid) + '\0' + ByteArray(authcid) + '\0' + ByteArray(clientnonce); + return ByteArray(getAuthorizationID()) + '\0' + ByteArray(getAuthenticationID()) + '\0' + ByteArray(clientnonce); } } diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h index d129468..161afd1 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h @@ -1,18 +1,19 @@ #pragma once #include "Swiften/Base/String.h" #include "Swiften/Base/ByteArray.h" +#include "Swiften/SASL/ClientAuthenticator.h" namespace Swift { - class SCRAMSHA1ClientAuthenticator { + class SCRAMSHA1ClientAuthenticator : public ClientAuthenticator { public: - SCRAMSHA1ClientAuthenticator(const String& authcid, const String& password, const String& authzid, const ByteArray& nonce); - - ByteArray getMessage() const; - bool setResponse(const ByteArray&); + SCRAMSHA1ClientAuthenticator(const ByteArray& nonce); + + ByteArray getResponse() const; + bool setChallenge(const ByteArray&); private: ByteArray getInitialClientMessage() const; ByteArray getSalt() const; ByteArray getClientVerifier() const; diff --git a/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp new file mode 100644 index 0000000..b83e1f5 --- /dev/null +++ b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp @@ -0,0 +1,35 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/SASL/PLAINClientAuthenticator.h" + +using namespace Swift; + +class PLAINClientAuthenticatorTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(PLAINClientAuthenticatorTest); + CPPUNIT_TEST(testGetResponse_WithoutAuthzID); + CPPUNIT_TEST(testGetResponse_WithAuthzID); + CPPUNIT_TEST_SUITE_END(); + + public: + PLAINClientAuthenticatorTest() {} + + void testGetResponse_WithoutAuthzID() { + PLAINClientAuthenticator testling; + + testling.setCredentials("user", "pass"); + + CPPUNIT_ASSERT_EQUAL(testling.getResponse(), ByteArray("\0user\0pass", 10)); + } + + void testGetResponse_WithAuthzID() { + PLAINClientAuthenticator testling; + + testling.setCredentials("user", "pass", "authz"); + + CPPUNIT_ASSERT_EQUAL(testling.getResponse(), ByteArray("authz\0user\0pass", 15)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PLAINClientAuthenticatorTest); diff --git a/Swiften/SConscript b/Swiften/SConscript index be0af24..a5ef56d 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -39,12 +39,14 @@ sources = [ "Queries/Request.cpp", "Queries/Responders/DiscoInfoResponder.cpp", "Queries/Responders/SoftwareVersionResponder.cpp", "Roster/ContactRosterItem.cpp", "Roster/Roster.cpp", "Roster/XMPPRoster.cpp", + "SASL/ClientAuthenticator.cpp", + "SASL/PLAINClientAuthenticator.cpp", "SASL/PLAINMessage.cpp", "SASL/SCRAMSHA1ClientAuthenticator.cpp", "Serializer/AuthRequestSerializer.cpp", "Serializer/CompressRequestSerializer.cpp", "Serializer/ElementSerializer.cpp", "Serializer/MessageSerializer.cpp", @@ -156,12 +158,13 @@ env.Append(UNITTEST_SOURCES = [ File("Queries/UnitTest/IQRouterTest.cpp"), File("Queries/UnitTest/RequestTest.cpp"), File("Queries/UnitTest/ResponderTest.cpp"), File("Roster/UnitTest/OfflineRosterFilterTest.cpp"), File("Roster/UnitTest/RosterTest.cpp"), File("SASL/UnitTest/PLAINMessageTest.cpp"), + File("SASL/UnitTest/PLAINClientAuthenticatorTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp"), File("Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/DiscoInfoSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"), |
Swift