From c3fa606c7ac060c4929e7082e0e24531b093112f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Thu, 3 Jun 2010 20:11:02 +0200
Subject: Distinguish an empty SASL message from no SASL message.


diff --git a/Swiften/Elements/AuthChallenge.h b/Swiften/Elements/AuthChallenge.h
index 21486df..74d7dba 100644
--- a/Swiften/Elements/AuthChallenge.h
+++ b/Swiften/Elements/AuthChallenge.h
@@ -6,24 +6,29 @@
 
 #pragma once
 
+#include <boost/optional.hpp>
+
 #include "Swiften/Base/ByteArray.h"
 #include "Swiften/Elements/Element.h"
 
 namespace Swift {
 	class AuthChallenge : public Element {
 		public:
-			AuthChallenge(const ByteArray& value = "") : value(value) {
+			AuthChallenge() {
+			}
+
+			AuthChallenge(const ByteArray& value) : value(value) {
 			}
 
-			const ByteArray& getValue() const {
+			const boost::optional<ByteArray>& getValue() const {
 				return value;
 			}
 
 			void setValue(const ByteArray& value) {
-				this->value = value;
+				this->value = boost::optional<ByteArray>(value);
 			}
 
 		private:
-			ByteArray value;
+			boost::optional<ByteArray> value;
 	};
 }
diff --git a/Swiften/Elements/AuthRequest.h b/Swiften/Elements/AuthRequest.h
index 45ea743..a1aac31 100644
--- a/Swiften/Elements/AuthRequest.h
+++ b/Swiften/Elements/AuthRequest.h
@@ -4,8 +4,9 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#ifndef SWIFTEN_AuthRequest_H
-#define SWIFTEN_AuthRequest_H
+#pragma once
+
+#include <boost/optional.hpp>
 
 #include "Swiften/Base/ByteArray.h"
 #include "Swiften/Elements/Element.h"
@@ -13,16 +14,23 @@
 namespace Swift {
 	class AuthRequest : public Element {
 		public:
-			AuthRequest(const String& mechanism = "", const ByteArray& message = "") : 
+			AuthRequest(const String& mechanism = "") : mechanism_(mechanism) {
+			}
+
+			AuthRequest(const String& mechanism, const ByteArray& message) : 
 					mechanism_(mechanism), message_(message) {
 			}
 
-			const ByteArray& getMessage() const {
+			AuthRequest(const String& mechanism, const boost::optional<ByteArray>& message) : 
+					mechanism_(mechanism), message_(message) {
+			}
+
+			const boost::optional<ByteArray>& getMessage() const {
 				return message_;
 			}
 
 			void setMessage(const ByteArray& message) {
-				message_ = message;
+				message_ = boost::optional<ByteArray>(message);
 			}
 
 			const String& getMechanism() const {
@@ -35,8 +43,6 @@ namespace Swift {
 
 		private:
 			String mechanism_;
-			ByteArray message_;
+			boost::optional<ByteArray> message_;
 	};
 }
-
-#endif
diff --git a/Swiften/Elements/AuthResponse.h b/Swiften/Elements/AuthResponse.h
index baea83a..96d1b13 100644
--- a/Swiften/Elements/AuthResponse.h
+++ b/Swiften/Elements/AuthResponse.h
@@ -6,24 +6,32 @@
 
 #pragma once
 
+#include <boost/optional.hpp>
+
 #include "Swiften/Base/ByteArray.h"
 #include "Swiften/Elements/Element.h"
 
 namespace Swift {
 	class AuthResponse : public Element {
 		public:
-			AuthResponse(const ByteArray& value = "") : value(value) {
+			AuthResponse() {
+			}
+
+			AuthResponse(const ByteArray& value) : value(value) {
+			}
+
+			AuthResponse(const boost::optional<ByteArray>& value) : value(value) {
 			}
 
-			const ByteArray& getValue() const {
+			const boost::optional<ByteArray>& getValue() const {
 				return value;
 			}
 
 			void setValue(const ByteArray& value) {
-				this->value = value;
+				this->value = boost::optional<ByteArray>(value);
 			}
 
 		private:
-			ByteArray value;
+			boost::optional<ByteArray> value;
 	};
 }
diff --git a/Swiften/Elements/AuthSuccess.h b/Swiften/Elements/AuthSuccess.h
index 5c0faad..af5f9bb 100644
--- a/Swiften/Elements/AuthSuccess.h
+++ b/Swiften/Elements/AuthSuccess.h
@@ -6,6 +6,8 @@
 
 #pragma once
 
+#include <boost/optional.hpp>
+
 #include "Swiften/Elements/Element.h"
 #include "Swiften/Base/ByteArray.h"
 
@@ -14,15 +16,15 @@ namespace Swift {
 		public:
 			AuthSuccess() {}
 
-			const ByteArray& getValue() const {
+			const boost::optional<ByteArray>& getValue() const {
 				return value;
 			}
 
 			void setValue(const ByteArray& value) {
-				this->value = value;
+				this->value = boost::optional<ByteArray>(value);
 			}
 
 		private:
-			ByteArray value;
+			boost::optional<ByteArray> value;
 	};
 }
diff --git a/Swiften/SASL/ClientAuthenticator.h b/Swiften/SASL/ClientAuthenticator.h
index 7d81e8f..718ccdc 100644
--- a/Swiften/SASL/ClientAuthenticator.h
+++ b/Swiften/SASL/ClientAuthenticator.h
@@ -6,6 +6,8 @@
 
 #pragma once
 
+#include <boost/optional.hpp>
+
 #include "Swiften/Base/String.h"
 #include "Swiften/Base/ByteArray.h"
 
@@ -25,8 +27,8 @@ namespace Swift {
 				this->authzid = authzid;
 			}
 
-			virtual ByteArray getResponse() const = 0;
-			virtual bool setChallenge(const ByteArray&) = 0;
+			virtual boost::optional<ByteArray> getResponse() const = 0;
+			virtual bool setChallenge(const boost::optional<ByteArray>&) = 0;
 
 			const String& getAuthenticationID() const {
 				return authcid;
diff --git a/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp b/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp
index d22f295..050b73b 100644
--- a/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp
+++ b/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp
@@ -16,9 +16,9 @@ namespace Swift {
 DIGESTMD5ClientAuthenticator::DIGESTMD5ClientAuthenticator(const String& host, const String& nonce) : ClientAuthenticator("DIGEST-MD5"), step(Initial), host(host), cnonce(nonce) {
 }
 
-ByteArray DIGESTMD5ClientAuthenticator::getResponse() const {
+boost::optional<ByteArray> DIGESTMD5ClientAuthenticator::getResponse() const {
 	if (step == Initial) {
-		return ByteArray();
+		return boost::optional<ByteArray>();
 	}
 	else if (step == Response) {
 		String realm;
@@ -59,13 +59,16 @@ ByteArray DIGESTMD5ClientAuthenticator::getResponse() const {
 		return response.serialize();
 	}
 	else {
-		return ByteArray();
+		return boost::optional<ByteArray>();
 	}
 }
 
-bool DIGESTMD5ClientAuthenticator::setChallenge(const ByteArray& challengeData) {
+bool DIGESTMD5ClientAuthenticator::setChallenge(const boost::optional<ByteArray>& challengeData) {
 	if (step == Initial) {
-		challenge = DIGESTMD5Properties::parse(challengeData);
+		if (!challengeData) {
+			return false;
+		}
+		challenge = DIGESTMD5Properties::parse(*challengeData);
 
 		// Sanity checks
 		if (!challenge.getValue("nonce")) {
diff --git a/Swiften/SASL/DIGESTMD5ClientAuthenticator.h b/Swiften/SASL/DIGESTMD5ClientAuthenticator.h
index e360257..457bde9 100644
--- a/Swiften/SASL/DIGESTMD5ClientAuthenticator.h
+++ b/Swiften/SASL/DIGESTMD5ClientAuthenticator.h
@@ -18,8 +18,8 @@ namespace Swift {
 		public:
 			DIGESTMD5ClientAuthenticator(const String& host, const String& nonce);
 			
-			virtual ByteArray getResponse() const;
-			virtual bool setChallenge(const ByteArray&);
+			virtual boost::optional<ByteArray> getResponse() const;
+			virtual bool setChallenge(const boost::optional<ByteArray>&);
 
 		private:
 			enum Step {
diff --git a/Swiften/SASL/PLAINClientAuthenticator.cpp b/Swiften/SASL/PLAINClientAuthenticator.cpp
index 96d1163..2ea2425 100644
--- a/Swiften/SASL/PLAINClientAuthenticator.cpp
+++ b/Swiften/SASL/PLAINClientAuthenticator.cpp
@@ -11,11 +11,11 @@ namespace Swift {
 PLAINClientAuthenticator::PLAINClientAuthenticator() : ClientAuthenticator("PLAIN") {
 }
 
-ByteArray PLAINClientAuthenticator::getResponse() const {
+boost::optional<ByteArray> PLAINClientAuthenticator::getResponse() const {
 	return ByteArray(getAuthorizationID()) + '\0' + ByteArray(getAuthenticationID()) + '\0' + ByteArray(getPassword());
 }
 
-bool PLAINClientAuthenticator::setChallenge(const ByteArray&) {
+bool PLAINClientAuthenticator::setChallenge(const boost::optional<ByteArray>&) {
 	return true;
 }
 
diff --git a/Swiften/SASL/PLAINClientAuthenticator.h b/Swiften/SASL/PLAINClientAuthenticator.h
index 3fbad48..959244d 100644
--- a/Swiften/SASL/PLAINClientAuthenticator.h
+++ b/Swiften/SASL/PLAINClientAuthenticator.h
@@ -13,7 +13,7 @@ namespace Swift {
 		public:
 			PLAINClientAuthenticator();
 
-			virtual ByteArray getResponse() const;
-			virtual bool setChallenge(const ByteArray&);
+			virtual boost::optional<ByteArray> getResponse() const;
+			virtual bool setChallenge(const boost::optional<ByteArray>&);
 	};
 }
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
index 0dc61b6..5d0ee9a 100644
--- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
+++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
@@ -38,7 +38,7 @@ static String escape(const String& s) {
 SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const String& nonce) : ClientAuthenticator("SCRAM-SHA-1"), step(Initial), clientnonce(nonce) {
 }
 
-ByteArray SCRAMSHA1ClientAuthenticator::getResponse() const {
+boost::optional<ByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const {
 	if (step == Initial) {
 		return getGS2Header() + getInitialBareClientMessage();
 	}
@@ -54,13 +54,16 @@ ByteArray SCRAMSHA1ClientAuthenticator::getResponse() const {
 		return result;
 	}
 	else {
-		return ByteArray();
+		return boost::optional<ByteArray>();
 	}
 }
 
-bool SCRAMSHA1ClientAuthenticator::setChallenge(const ByteArray& challenge) {
+bool SCRAMSHA1ClientAuthenticator::setChallenge(const boost::optional<ByteArray>& challenge) {
 	if (step == Initial) {
-		initialServerMessage = challenge;
+		if (!challenge) {
+			return false;
+		}
+		initialServerMessage = *challenge;
 
 		std::map<char, String> keys = parseMap(String(initialServerMessage.getData(), initialServerMessage.getSize()));
 
@@ -102,7 +105,7 @@ bool SCRAMSHA1ClientAuthenticator::setChallenge(const ByteArray& challenge) {
 	else if (step == Proof) {
 		ByteArray result = ByteArray("v=") + ByteArray(Base64::encode(serverSignature));
 		step = Final;
-		return challenge == result;
+		return challenge && challenge == result;
 	}
 	else {
 		return true;
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
index 045c1b1..396cc93 100644
--- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
+++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
@@ -17,8 +17,8 @@ namespace Swift {
 		public:
 			SCRAMSHA1ClientAuthenticator(const String& nonce);
 			
-			virtual ByteArray getResponse() const;
-			virtual bool setChallenge(const ByteArray&);
+			virtual boost::optional<ByteArray> getResponse() const;
+			virtual bool setChallenge(const boost::optional<ByteArray>&);
 
 		private:
 			ByteArray getInitialBareClientMessage() const;
diff --git a/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp
index e16c202..8daea4f 100644
--- a/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp
+++ b/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp
@@ -25,9 +25,7 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture {
 		void testGetInitialResponse() {
 			DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh");
 
-			ByteArray response = testling.getResponse();
-
-			CPPUNIT_ASSERT(response.isEmpty());
+			CPPUNIT_ASSERT(!testling.getResponse());
 		}
 
 		void testGetResponse() {
@@ -39,7 +37,7 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture {
 				"nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\","
 				"qop=auth,charset=utf-8,algorithm=md5-sess"));
 
-			ByteArray response = testling.getResponse();
+			ByteArray response = *testling.getResponse();
 
 			CPPUNIT_ASSERT_EQUAL(String("charset=utf-8,cnonce=\"abcdefgh\",digest-uri=\"xmpp/xmpp.example.com\",nc=00000001,nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\",qop=auth,realm=\"example.com\",response=088891c800ecff1b842159ad6459104a,username=\"user\""), response.toString());
 		}
@@ -53,7 +51,7 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture {
 				"nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\","
 				"qop=auth,charset=utf-8,algorithm=md5-sess"));
 
-			ByteArray response = testling.getResponse();
+			ByteArray response = *testling.getResponse();
 
 			CPPUNIT_ASSERT_EQUAL(String("authzid=\"myauthzid\",charset=utf-8,cnonce=\"abcdefgh\",digest-uri=\"xmpp/xmpp.example.com\",nc=00000001,nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\",qop=auth,realm=\"example.com\",response=4293834432b6e7889a2dee7e8fe7dd06,username=\"user\""), response.toString());
 		}
diff --git a/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp
index 818e02e..7784898 100644
--- a/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp
+++ b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp
@@ -23,7 +23,7 @@ class PLAINClientAuthenticatorTest : public CppUnit::TestFixture {
 
 			testling.setCredentials("user", "pass");
 
-			CPPUNIT_ASSERT_EQUAL(testling.getResponse(), ByteArray("\0user\0pass", 10));
+			CPPUNIT_ASSERT_EQUAL(*testling.getResponse(), ByteArray("\0user\0pass", 10));
 		}
 
 		void testGetResponse_WithAuthzID() {
@@ -31,7 +31,7 @@ class PLAINClientAuthenticatorTest : public CppUnit::TestFixture {
 
 			testling.setCredentials("user", "pass", "authz");
 
-			CPPUNIT_ASSERT_EQUAL(testling.getResponse(), ByteArray("authz\0user\0pass", 15));
+			CPPUNIT_ASSERT_EQUAL(*testling.getResponse(), ByteArray("authz\0user\0pass", 15));
 		}
 };
 
diff --git a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
index 0fce39a..b65cdd3 100644
--- a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
+++ b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
@@ -39,36 +39,36 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
 			testling.setCredentials("user", "pass", "");
 
-			ByteArray response = testling.getResponse();
+			ByteArray response = *testling.getResponse();
 
-			CPPUNIT_ASSERT_EQUAL(String("n,,n=user,r=abcdefghABCDEFGH"), testling.getResponse().toString());
+			CPPUNIT_ASSERT_EQUAL(String("n,,n=user,r=abcdefghABCDEFGH"), response.toString());
 		}
 
 		void testGetInitialResponse_UsernameHasSpecialChars() {
 			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
 			testling.setCredentials(",us=,er=", "pass", "");
 
-			ByteArray response = testling.getResponse();
+			ByteArray response = *testling.getResponse();
 
-			CPPUNIT_ASSERT_EQUAL(String("n,,n==2Cus=3D=2Cer=3D,r=abcdefghABCDEFGH"), testling.getResponse().toString());
+			CPPUNIT_ASSERT_EQUAL(String("n,,n==2Cus=3D=2Cer=3D,r=abcdefghABCDEFGH"), response.toString());
 		}
 
 		void testGetInitialResponse_WithAuthorizationID() {
 			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
 			testling.setCredentials("user", "pass", "auth");
 
-			ByteArray response = testling.getResponse();
+			ByteArray response = *testling.getResponse();
 
-			CPPUNIT_ASSERT_EQUAL(String("n,a=auth,n=user,r=abcdefghABCDEFGH"), testling.getResponse().toString());
+			CPPUNIT_ASSERT_EQUAL(String("n,a=auth,n=user,r=abcdefghABCDEFGH"), response.toString());
 		}
 
 		void testGetInitialResponse_WithAuthorizationIDWithSpecialChars() {
 			SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH");
 			testling.setCredentials("user", "pass", "a=u,th");
 
-			ByteArray response = testling.getResponse();
+			ByteArray response = *testling.getResponse();
 
-			CPPUNIT_ASSERT_EQUAL(String("n,a=a=3Du=2Cth,n=user,r=abcdefghABCDEFGH"), testling.getResponse().toString());
+			CPPUNIT_ASSERT_EQUAL(String("n,a=a=3Du=2Cth,n=user,r=abcdefghABCDEFGH"), response.toString());
 		}
 
 		void testGetFinalResponse() {
@@ -76,9 +76,9 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 			testling.setCredentials("user", "pass", "");
 			testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
 
-			ByteArray response = testling.getResponse();
+			ByteArray response = *testling.getResponse();
 
-			CPPUNIT_ASSERT_EQUAL(String("c=biws,r=abcdefghABCDEFGH,p=CZbjGDpIteIJwQNBgO0P8pKkMGY="), testling.getResponse().toString());
+			CPPUNIT_ASSERT_EQUAL(String("c=biws,r=abcdefghABCDEFGH,p=CZbjGDpIteIJwQNBgO0P8pKkMGY="), response.toString());
 		}
 
 		void testSetFinalChallenge() {
@@ -169,9 +169,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
 			testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
 			testling.setChallenge(ByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo="));
 
-			ByteArray result = testling.getResponse();
-
-			CPPUNIT_ASSERT_EQUAL(ByteArray(), result);
+			CPPUNIT_ASSERT(!testling.getResponse());
 		}
 };
 
diff --git a/Swiften/SConscript b/Swiften/SConscript
index f8bcc8c..aea527a 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -211,6 +211,10 @@ if env["SCONS_STAGE"] == "build" :
 			File("Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp"),
 			File("Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp"),
 			File("Serializer/UnitTest/StreamFeaturesSerializerTest.cpp"),
+			File("Serializer/UnitTest/AuthSuccessSerializerTest.cpp"),
+			File("Serializer/UnitTest/AuthChallengeSerializerTest.cpp"),
+			File("Serializer/UnitTest/AuthRequestSerializerTest.cpp"),
+			File("Serializer/UnitTest/AuthResponseSerializerTest.cpp"),
 			File("Serializer/XML/UnitTest/XMLElementTest.cpp"),
 			File("Server/UnitTest/ServerStanzaRouterTest.cpp"),
 			File("StreamStack/UnitTest/StreamStackTest.cpp"),
diff --git a/Swiften/Serializer/AuthChallengeSerializer.cpp b/Swiften/Serializer/AuthChallengeSerializer.cpp
index 00b5058..883763f 100644
--- a/Swiften/Serializer/AuthChallengeSerializer.cpp
+++ b/Swiften/Serializer/AuthChallengeSerializer.cpp
@@ -15,8 +15,17 @@ AuthChallengeSerializer::AuthChallengeSerializer() {
 }
 
 String AuthChallengeSerializer::serialize(boost::shared_ptr<Element> element)  const {
-	boost::shared_ptr<AuthChallenge> authRequest(boost::dynamic_pointer_cast<AuthChallenge>(element));
-	String value = (authRequest->getValue().isEmpty() ? "=" : Base64::encode(authRequest->getValue()));
+	boost::shared_ptr<AuthChallenge> authChallenge(boost::dynamic_pointer_cast<AuthChallenge>(element));
+	String value;
+	boost::optional<ByteArray> message = authChallenge->getValue();
+	if (message) {
+		if ((*message).isEmpty()) {
+			value = "=";
+		}
+		else {
+			value = Base64::encode(*message);
+		}
+	}
 	return "<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</challenge>";
 }
 
diff --git a/Swiften/Serializer/AuthRequestSerializer.cpp b/Swiften/Serializer/AuthRequestSerializer.cpp
index 32d733a..45b6503 100644
--- a/Swiften/Serializer/AuthRequestSerializer.cpp
+++ b/Swiften/Serializer/AuthRequestSerializer.cpp
@@ -16,7 +16,16 @@ AuthRequestSerializer::AuthRequestSerializer() {
 
 String AuthRequestSerializer::serialize(boost::shared_ptr<Element> element)  const {
 	boost::shared_ptr<AuthRequest> authRequest(boost::dynamic_pointer_cast<AuthRequest>(element));
-	String value = (authRequest->getMessage().isEmpty() ? "=" : Base64::encode(authRequest->getMessage()));
+	String value;
+	boost::optional<ByteArray> message = authRequest->getMessage();
+	if (message) {
+		if ((*message).isEmpty()) {
+			value = "=";
+		}
+		else {
+			value = Base64::encode(*message);
+		}
+	}
 	return "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"" + authRequest->getMechanism() + "\">" + value + "</auth>";
 }
 
diff --git a/Swiften/Serializer/AuthResponseSerializer.cpp b/Swiften/Serializer/AuthResponseSerializer.cpp
index ffa3963..d2d5616 100644
--- a/Swiften/Serializer/AuthResponseSerializer.cpp
+++ b/Swiften/Serializer/AuthResponseSerializer.cpp
@@ -14,9 +14,18 @@ namespace Swift {
 AuthResponseSerializer::AuthResponseSerializer() {
 }
 
-String AuthResponseSerializer::serialize(boost::shared_ptr<Element> element)  const {
-	boost::shared_ptr<AuthResponse> authRequest(boost::dynamic_pointer_cast<AuthResponse>(element));
-	String value = (authRequest->getValue().isEmpty() ? "=" : Base64::encode(authRequest->getValue()));
+String AuthResponseSerializer::serialize(boost::shared_ptr<Element> element)	const {
+	boost::shared_ptr<AuthResponse> authResponse(boost::dynamic_pointer_cast<AuthResponse>(element));
+	String value;
+	boost::optional<ByteArray> message = authResponse->getValue();
+	if (message) {
+		if ((*message).isEmpty()) {
+			value = "=";
+		}
+		else {
+			value = Base64::encode(*message);
+		}
+	}
 	return "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</response>";
 }
 
diff --git a/Swiften/Serializer/AuthSuccessSerializer.cpp b/Swiften/Serializer/AuthSuccessSerializer.cpp
index f27b2cb..6e9103b 100644
--- a/Swiften/Serializer/AuthSuccessSerializer.cpp
+++ b/Swiften/Serializer/AuthSuccessSerializer.cpp
@@ -15,8 +15,17 @@ AuthSuccessSerializer::AuthSuccessSerializer() {
 }
 
 String AuthSuccessSerializer::serialize(boost::shared_ptr<Element> element)  const {
-	boost::shared_ptr<AuthSuccess> authRequest(boost::dynamic_pointer_cast<AuthSuccess>(element));
-	String value = (authRequest->getValue().isEmpty() ? "=" : Base64::encode(authRequest->getValue()));
+	boost::shared_ptr<AuthSuccess> authSuccess(boost::dynamic_pointer_cast<AuthSuccess>(element));
+	String value;
+	boost::optional<ByteArray> message = authSuccess->getValue();
+	if (message) {
+		if ((*message).isEmpty()) {
+			value = "=";
+		}
+		else {
+			value = Base64::encode(*message);
+		}
+	}
 	return "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</success>";
 }
 
diff --git a/Swiften/Serializer/UnitTest/AuthChallengeSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthChallengeSerializerTest.cpp
new file mode 100644
index 0000000..dc828e0
--- /dev/null
+++ b/Swiften/Serializer/UnitTest/AuthChallengeSerializerTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/Serializer/AuthChallengeSerializer.h"
+#include "Swiften/Elements/AuthChallenge.h"
+
+using namespace Swift;
+
+class AuthChallengeSerializerTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(AuthChallengeSerializerTest);
+		CPPUNIT_TEST(testSerialize);
+		CPPUNIT_TEST(testSerialize_NoMessage);
+		CPPUNIT_TEST(testSerialize_EmptyMessage);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		void testSerialize() {
+			AuthChallengeSerializer testling;
+			boost::shared_ptr<AuthChallenge> authChallenge(new AuthChallenge());
+			authChallenge->setValue("foo");
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+					"Zm9v"
+				"</challenge>"), testling.serialize(authChallenge));
+		}
+
+		void testSerialize_NoMessage() {
+			AuthChallengeSerializer testling;
+			boost::shared_ptr<AuthChallenge> authChallenge(new AuthChallenge());
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+				"</challenge>"), testling.serialize(authChallenge));
+		}
+
+		void testSerialize_EmptyMessage() {
+			AuthChallengeSerializer testling;
+			boost::shared_ptr<AuthChallenge> authChallenge(new AuthChallenge());
+			authChallenge->setValue(ByteArray());
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+					"="
+				"</challenge>"), testling.serialize(authChallenge));
+		}
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AuthChallengeSerializerTest);
diff --git a/Swiften/Serializer/UnitTest/AuthRequestSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthRequestSerializerTest.cpp
new file mode 100644
index 0000000..f63db90
--- /dev/null
+++ b/Swiften/Serializer/UnitTest/AuthRequestSerializerTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/Serializer/AuthRequestSerializer.h"
+#include "Swiften/Elements/AuthRequest.h"
+
+using namespace Swift;
+
+class AuthRequestSerializerTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(AuthRequestSerializerTest);
+		CPPUNIT_TEST(testSerialize);
+		CPPUNIT_TEST(testSerialize_NoMessage);
+		CPPUNIT_TEST(testSerialize_EmptyMessage);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		void testSerialize() {
+			AuthRequestSerializer testling;
+			boost::shared_ptr<AuthRequest> authRequest(new AuthRequest("PLAIN"));
+			authRequest->setMessage("foo");
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">"
+					"Zm9v"
+				"</auth>"), testling.serialize(authRequest));
+		}
+
+		void testSerialize_NoMessage() {
+			AuthRequestSerializer testling;
+			boost::shared_ptr<AuthRequest> authRequest(new AuthRequest("PLAIN"));
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">"
+				"</auth>"), testling.serialize(authRequest));
+		}
+
+		void testSerialize_EmptyMessage() {
+			AuthRequestSerializer testling;
+			boost::shared_ptr<AuthRequest> authRequest(new AuthRequest("PLAIN"));
+			authRequest->setMessage(ByteArray());
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">"
+					"="
+				"</auth>"), testling.serialize(authRequest));
+		}
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AuthRequestSerializerTest);
diff --git a/Swiften/Serializer/UnitTest/AuthResponseSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthResponseSerializerTest.cpp
new file mode 100644
index 0000000..fabe834
--- /dev/null
+++ b/Swiften/Serializer/UnitTest/AuthResponseSerializerTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/Serializer/AuthResponseSerializer.h"
+#include "Swiften/Elements/AuthResponse.h"
+
+using namespace Swift;
+
+class AuthResponseSerializerTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(AuthResponseSerializerTest);
+		CPPUNIT_TEST(testSerialize);
+		CPPUNIT_TEST(testSerialize_NoMessage);
+		CPPUNIT_TEST(testSerialize_EmptyMessage);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		void testSerialize() {
+			AuthResponseSerializer testling;
+			boost::shared_ptr<AuthResponse> authResponse(new AuthResponse());
+			authResponse->setValue("foo");
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+					"Zm9v"
+				"</response>"), testling.serialize(authResponse));
+		}
+
+		void testSerialize_NoMessage() {
+			AuthResponseSerializer testling;
+			boost::shared_ptr<AuthResponse> authResponse(new AuthResponse());
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+				"</response>"), testling.serialize(authResponse));
+		}
+
+		void testSerialize_EmptyMessage() {
+			AuthResponseSerializer testling;
+			boost::shared_ptr<AuthResponse> authResponse(new AuthResponse());
+			authResponse->setValue(ByteArray());
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+					"="
+				"</response>"), testling.serialize(authResponse));
+		}
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AuthResponseSerializerTest);
diff --git a/Swiften/Serializer/UnitTest/AuthSuccessSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthSuccessSerializerTest.cpp
new file mode 100644
index 0000000..a9b602f
--- /dev/null
+++ b/Swiften/Serializer/UnitTest/AuthSuccessSerializerTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/Serializer/AuthSuccessSerializer.h"
+#include "Swiften/Elements/AuthSuccess.h"
+
+using namespace Swift;
+
+class AuthSuccessSerializerTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(AuthSuccessSerializerTest);
+		CPPUNIT_TEST(testSerialize);
+		CPPUNIT_TEST(testSerialize_NoMessage);
+		CPPUNIT_TEST(testSerialize_EmptyMessage);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		void testSerialize() {
+			AuthSuccessSerializer testling;
+			boost::shared_ptr<AuthSuccess> authSuccess(new AuthSuccess());
+			authSuccess->setValue("foo");
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+					"Zm9v"
+				"</success>"), testling.serialize(authSuccess));
+		}
+
+		void testSerialize_NoMessage() {
+			AuthSuccessSerializer testling;
+			boost::shared_ptr<AuthSuccess> authSuccess(new AuthSuccess());
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+				"</success>"), testling.serialize(authSuccess));
+		}
+
+		void testSerialize_EmptyMessage() {
+			AuthSuccessSerializer testling;
+			boost::shared_ptr<AuthSuccess> authSuccess(new AuthSuccess());
+			authSuccess->setValue(ByteArray());
+
+			CPPUNIT_ASSERT_EQUAL(String(
+				"<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
+					"="
+				"</success>"), testling.serialize(authSuccess));
+		}
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AuthSuccessSerializerTest);
diff --git a/Swiften/Server/ServerFromClientSession.cpp b/Swiften/Server/ServerFromClientSession.cpp
index 424688f..882946d 100644
--- a/Swiften/Server/ServerFromClientSession.cpp
+++ b/Swiften/Server/ServerFromClientSession.cpp
@@ -48,7 +48,7 @@ void ServerFromClientSession::handleElement(boost::shared_ptr<Element> element)
 				finishSession(NoSupportedAuthMechanismsError);
 			}
 			else {
-				PLAINMessage plainMessage(authRequest->getMessage());
+				PLAINMessage plainMessage(authRequest->getMessage() ? *authRequest->getMessage() : "");
 				if (userRegistry_->isValidUserPassword(JID(plainMessage.getAuthenticationID(), getLocalJID().getDomain()), plainMessage.getPassword())) {
 					getXMPPLayer()->writeElement(boost::shared_ptr<AuthSuccess>(new AuthSuccess()));
 					user_ = plainMessage.getAuthenticationID();
-- 
cgit v0.10.2-6-g49f6