summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMili Verma <mili.verma@isode.com>2015-06-25 12:13:14 (GMT)
committerKevin Smith <kevin.smith@isode.com>2015-06-29 17:02:01 (GMT)
commit394642c69bc232429621e209b787d3496967b37b (patch)
tree12fda8350b5694b4e6dc93899debc5a8c46e0adf
parentac45f360be049242a89ae80258e4ea8350f909ba (diff)
downloadswift-394642c69bc232429621e209b787d3496967b37b.zip
swift-394642c69bc232429621e209b787d3496967b37b.tar.bz2
Add WindowsServicePrincipalName class
Test-information: Tested on Windows using WIP GSSAPI code. Unit tests pass. Change-Id: If872863d6a8b5a164f8ebec4f88e9939b4e73c62
-rw-r--r--BuildTools/SCons/SConscript.boot2
-rw-r--r--Swiften/SASL/SConscript9
-rw-r--r--Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp161
-rw-r--r--Swiften/SASL/WindowsServicePrincipalName.cpp106
-rw-r--r--Swiften/SASL/WindowsServicePrincipalName.h71
5 files changed, 348 insertions, 1 deletions
diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot
index ff24eeb..2415fde 100644
--- a/BuildTools/SCons/SConscript.boot
+++ b/BuildTools/SCons/SConscript.boot
@@ -333,7 +333,7 @@ if env.get("coverage", 0) :
333 env.Append(LINKFLAGS = ["-fprofile-arcs", "-ftest-coverage"]) 333 env.Append(LINKFLAGS = ["-fprofile-arcs", "-ftest-coverage"])
334 334
335if env["PLATFORM"] == "win32" : 335if env["PLATFORM"] == "win32" :
336 env.Append(LIBS = ["user32", "crypt32", "dnsapi", "iphlpapi", "ws2_32", "wsock32", "Advapi32"]) 336 env.Append(LIBS = ["user32", "crypt32", "dnsapi", "iphlpapi", "ws2_32", "wsock32", "Advapi32", "ntdsapi"])
337 env.Append(CCFLAGS = ["/EHsc", "/nologo", "/Zm256"]) 337 env.Append(CCFLAGS = ["/EHsc", "/nologo", "/Zm256"])
338 env.Append(LINKFLAGS = ["/INCREMENTAL:no", "/NOLOGO"]) 338 env.Append(LINKFLAGS = ["/INCREMENTAL:no", "/NOLOGO"])
339 if int(env["MSVS_VERSION"].split(".")[0]) < 10 : 339 if int(env["MSVS_VERSION"].split(".")[0]) < 10 :
diff --git a/Swiften/SASL/SConscript b/Swiften/SASL/SConscript
index 6509547..faf6320 100644
--- a/Swiften/SASL/SConscript
+++ b/Swiften/SASL/SConscript
@@ -11,6 +11,11 @@ objects = myenv.SwiftenObject([
11 "DIGESTMD5Properties.cpp", 11 "DIGESTMD5Properties.cpp",
12 "DIGESTMD5ClientAuthenticator.cpp", 12 "DIGESTMD5ClientAuthenticator.cpp",
13 ]) 13 ])
14if myenv["PLATFORM"] == "win32" :
15 objects += myenv.SwiftenObject([
16 "WindowsServicePrincipalName.cpp",
17 ])
18
14swiften_env.Append(SWIFTEN_OBJECTS = [objects]) 19swiften_env.Append(SWIFTEN_OBJECTS = [objects])
15 20
16env.Append(UNITTEST_SOURCES = [ 21env.Append(UNITTEST_SOURCES = [
@@ -20,3 +25,7 @@ env.Append(UNITTEST_SOURCES = [
20 File("UnitTest/DIGESTMD5PropertiesTest.cpp"), 25 File("UnitTest/DIGESTMD5PropertiesTest.cpp"),
21 File("UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp"), 26 File("UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp"),
22 ]) 27 ])
28if myenv["PLATFORM"] == "win32" :
29 env.Append(UNITTEST_SOURCES = [
30 File("UnitTest/WindowsServicePrincipalNameTest.cpp"),
31 ])
diff --git a/Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp b/Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp
new file mode 100644
index 0000000..1b0e6f6
--- /dev/null
+++ b/Swiften/SASL/UnitTest/WindowsServicePrincipalNameTest.cpp
@@ -0,0 +1,161 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#include <cppunit/extensions/HelperMacros.h>
8
9#include <Swiften/SASL/WindowsServicePrincipalName.h>
10
11using namespace Swift;
12
13class WindowsServicePrincipalNameTest : public CppUnit::TestFixture {
14 CPPUNIT_TEST_SUITE(WindowsServicePrincipalNameTest);
15 CPPUNIT_TEST(testServiceClass);
16 CPPUNIT_TEST(testServiceName);
17 CPPUNIT_TEST(testInstanceName);
18 CPPUNIT_TEST(testInstancePort);
19 CPPUNIT_TEST(testReferrer);
20 CPPUNIT_TEST_SUITE_END();
21
22 public:
23 void testServiceClass() {
24 WindowsServicePrincipalName spn("mlink.adlon.isode.net");
25
26 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/mlink.adlon.isode.net"));
27
28 spn.setServiceClass("ldap");
29 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("ldap/mlink.adlon.isode.net"));
30
31 spn.setServiceClass("中文");
32 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("中文/mlink.adlon.isode.net"));
33
34 try {
35 spn.setServiceClass("");
36 spn.toString();
37 CPPUNIT_ASSERT(false);
38 } catch (std::runtime_error) {
39 /* expected */
40 }
41
42 try {
43 spn.setServiceClass("xm/pp"); /* Foward slash not allowed */
44 spn.toString();
45 CPPUNIT_ASSERT(false);
46 } catch (std::runtime_error) {
47 /* expected */
48 }
49 }
50
51 void testServiceName() {
52 try {
53 WindowsServicePrincipalName spn("");
54 spn.toString();
55 CPPUNIT_ASSERT(false);
56 } catch (std::runtime_error) {
57 /* expected */
58 }
59
60 try {
61 WindowsServicePrincipalName spn2("mlink/adlon.isode.net"); /* Foward slash not allowed */
62 spn2.toString();
63 CPPUNIT_ASSERT(false);
64 } catch (std::runtime_error) {
65 /* expected */
66 }
67
68 WindowsServicePrincipalName spn3("mlinkÄ.adlon.isode.net");
69 CPPUNIT_ASSERT_EQUAL(spn3.toString(), std::string("xmpp/mlinkÄ.adlon.isode.net"));
70 }
71
72 void testInstanceName() {
73 WindowsServicePrincipalName spn("adlon.isode.net");
74
75 spn.setInstanceName("mlink.adlon.isode.net");
76 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/mlink.adlon.isode.net/adlon.isode.net"));
77
78 spn.setInstanceName("127.0.0.1");
79 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/127.0.0.1/adlon.isode.net"));
80
81 spn.setInstanceName("");
82 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/adlon.isode.net"));
83
84 spn.setInstanceName("cañón.adlon.isode.net");
85 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/cañón.adlon.isode.net/adlon.isode.net"));
86
87 try {
88 spn.setInstanceName("mlink/adlon.isode.net"); /* Foward slash not allowed */
89 spn.toString();
90 CPPUNIT_ASSERT(false);
91 } catch (std::runtime_error) {
92 /* expected */
93 }
94 }
95
96 void testInstancePort() {
97 WindowsServicePrincipalName spn("adlon.isode.net");
98
99 spn.setInstanceName("mlink.adlon.isode.net");
100 spn.setInstancePort(6222);
101 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/mlink.adlon.isode.net:6222/adlon.isode.net"));
102
103 spn.setInstancePort(0);
104 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/mlink.adlon.isode.net/adlon.isode.net"));
105
106 WindowsServicePrincipalName spn2("mlink.adlon.isode.net");
107
108 spn2.setInstancePort(6222);
109 CPPUNIT_ASSERT_EQUAL(spn2.toString(), std::string("xmpp/mlink.adlon.isode.net:6222"));
110
111 spn2.setInstancePort(0);
112 CPPUNIT_ASSERT_EQUAL(spn2.toString(), std::string("xmpp/mlink.adlon.isode.net"));
113 }
114
115 void testReferrer() {
116 WindowsServicePrincipalName spn("127.0.0.1");
117
118 spn.setReferrer("referrer.net");
119 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/127.0.0.1/referrer.net"));
120
121 spn.setInstancePort(6222);
122 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/127.0.0.1:6222/referrer.net"));
123
124 spn.setReferrer("हिन्दी.net");
125 CPPUNIT_ASSERT_EQUAL(spn.toString(), std::string("xmpp/127.0.0.1:6222/हिन्दी.net"));
126
127 try {
128 spn.setReferrer("referrer/net"); /* Foward slash not allowed */
129 spn.toString();
130 CPPUNIT_ASSERT(false);
131 } catch (std::runtime_error) {
132 /* expected */
133 }
134
135 try {
136 spn.setReferrer(""); /* seems like you must have referrer with an IP */
137 spn.toString();
138 CPPUNIT_ASSERT(false);
139 } catch (std::runtime_error) {
140 /* expected */
141 }
142
143 WindowsServicePrincipalName spn2("mlink.adlon.isode.net");
144
145 spn2.setReferrer("referrer.net"); /* Referrer ignored if service name is not IP */
146 CPPUNIT_ASSERT_EQUAL(spn2.toString(), std::string("xmpp/mlink.adlon.isode.net"));
147
148 spn2.setReferrer("referrer/net"); /* Referrer ignored if service name is not IP */
149 CPPUNIT_ASSERT_EQUAL(spn2.toString(), std::string("xmpp/mlink.adlon.isode.net"));
150
151 WindowsServicePrincipalName spn3("adlon.isode.net");
152
153 spn3.setInstanceName("mlink.adlon.isode.net");
154 spn3.setInstancePort(6222);
155 spn3.setReferrer("referrer.net"); /* Referrer ignored if service name is not IP */
156 CPPUNIT_ASSERT_EQUAL(spn3.toString(), std::string("xmpp/mlink.adlon.isode.net:6222/adlon.isode.net"));
157
158 }
159};
160
161CPPUNIT_TEST_SUITE_REGISTRATION(WindowsServicePrincipalNameTest);
diff --git a/Swiften/SASL/WindowsServicePrincipalName.cpp b/Swiften/SASL/WindowsServicePrincipalName.cpp
new file mode 100644
index 0000000..187e9ac
--- /dev/null
+++ b/Swiften/SASL/WindowsServicePrincipalName.cpp
@@ -0,0 +1,106 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#include <Swiften/SASL/WindowsServicePrincipalName.h>
8
9#include <vector>
10
11#include <Ntdsapi.h>
12
13#include <Swiften/Base/ByteArray.h>
14#include <Swiften/Base/Log.h>
15#include <Swiften/Base/String.h>
16
17namespace Swift {
18
19WindowsServicePrincipalName::WindowsServicePrincipalName(const std::string& serviceName) : serviceClass_(L"xmpp"), instancePort_(0) {
20 serviceName_ = convertStringToWString(serviceName);
21}
22
23WindowsServicePrincipalName::~WindowsServicePrincipalName() {
24}
25
26void WindowsServicePrincipalName::setServiceClass(const std::string& serviceClass) {
27 serviceClass_ = convertStringToWString(serviceClass);
28}
29
30void WindowsServicePrincipalName::setInstanceName(const std::string& instanceName) {
31 instanceName_ = convertStringToWString(instanceName);
32}
33
34void WindowsServicePrincipalName::setReferrer(const std::string& referrer) {
35 referrer_ = convertStringToWString(referrer);
36}
37
38std::string WindowsServicePrincipalName::toString() {
39 DWORD length = 512;
40 DWORD status = ERROR_BUFFER_OVERFLOW;
41 bool firstCall = true;
42 std::string str;
43
44 while (status == ERROR_BUFFER_OVERFLOW) {
45 std::vector<wchar_t> value(length);
46
47 /* length after this call will contain the required length if current length is not enough - so the next call should succeed */
48 status = dsMakeSpn(&length, vecptr(value));
49 if (status == ERROR_SUCCESS) {
50 str = convertWStringToString(std::wstring(vecptr(value), length-1 /* trailing 0 character */));
51 break;
52 }
53
54 if ((firstCall == false) || (status != ERROR_BUFFER_OVERFLOW)) {
55 std::stringstream errorString;
56 boost::system::error_code errorCode(status, boost::system::system_category());
57
58 errorString << "Error creating Service Principal Name: status: 0x" << std::hex << status << ": " << errorCode.message();
59
60 /* Any other error will be a programming error */
61 throw std::runtime_error(errorString.str());
62 }
63
64 firstCall = false;
65 }
66
67 SWIFT_LOG(debug) << "SPN: " << str << std::endl;
68 return str;
69}
70
71DWORD WindowsServicePrincipalName::dsMakeSpn(DWORD* length, wchar_t* value) {
72 DWORD status;
73
74#ifdef UNICODE
75 SWIFT_LOG(debug) << "UNICODE is defined" << std::endl;
76#else
77 SWIFT_LOG(debug) << "UNICODE is not defined" << std::endl;
78#endif
79
80 SWIFT_LOG(debug) << "serviceClass_: " << convertWStringToString(serviceClass_.c_str()) << std::endl;
81 SWIFT_LOG(debug) << "serviceName_: " << convertWStringToString(serviceName_.c_str()) << std::endl;
82 SWIFT_LOG(debug) << "instanceName_: " << convertWStringToString(instanceName_.c_str()) << std::endl;
83 SWIFT_LOG(debug) << "referrer_: " << convertWStringToString(referrer_.c_str()) << std::endl;
84 SWIFT_LOG(debug) << "instancePort_: " << instancePort_ << std::endl;
85 SWIFT_LOG(debug) << "length: " << *length << std::endl;
86
87 /* Call the Unicode function because that is recommended:
88https://msdn.microsoft.com/en-us/library/windows/desktop/ff381407%28v=vs.85%29.aspx */
89 status = DsMakeSpnW(
90 serviceClass_.c_str(),
91 serviceName_.c_str(),
92 instanceName_.empty() ? NULL : instanceName_.c_str(),
93 instancePort_,
94 referrer_.empty() ? NULL : referrer_.c_str(),
95 length,
96 value);
97 if (status != ERROR_SUCCESS) {
98 boost::system::error_code errorCode(status, boost::system::system_category());
99
100 SWIFT_LOG(debug) << std::hex << "status: 0x" << status << ": " << errorCode.message() << std::endl;
101 }
102
103 return status;
104}
105
106}
diff --git a/Swiften/SASL/WindowsServicePrincipalName.h b/Swiften/SASL/WindowsServicePrincipalName.h
new file mode 100644
index 0000000..dc97c93
--- /dev/null
+++ b/Swiften/SASL/WindowsServicePrincipalName.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#pragma once
8
9#include <string>
10
11#include <Windows.h>
12
13#include <Swiften/Base/API.h>
14
15namespace Swift {
16 /*
17 * This represents the SPN used on Windows to identify a service
18 * instance.
19 */
20 class SWIFTEN_API WindowsServicePrincipalName {
21 public:
22 /*
23 * This assigns the provided service name,
24 * "xmpp" service class, no instance name or referrer,
25 * and default port. All of these (except the service
26 * name) can be set to other values using the provided
27 * methods.
28 * If the constructor is called with the service name
29 * "hostname.example.com" and the provided methods are
30 * not used to change the defaults, then toString()
31 * will return the SPN "xmpp/hostname.example.com".
32 */
33 WindowsServicePrincipalName(const std::string& serviceName);
34
35 ~WindowsServicePrincipalName();
36
37 void setServiceClass(const std::string& serviceClass);
38
39 void setInstanceName(const std::string& instanceName);
40
41 void setReferrer(const std::string& referrer);
42
43 /*
44 * This sets a non-default port for the service. Note
45 * that the default value is 0 which indicates the
46 * default port for the service. So if the XMPP service
47 * is using the default port of 5222 for client
48 * connections, then do not set the port to 5222 but let
49 * it remain 0 to indicate that the default port is
50 * used.
51 */
52 void setInstancePort(short int instancePort) { instancePort_ = instancePort; }
53
54 /*
55 * This follows the rules of SPN creation on Windows and
56 * returns the SPN string constructed from the set
57 * values.
58 */
59 std::string toString();
60
61 private:
62 DWORD dsMakeSpn(DWORD* length, wchar_t* value);
63
64 private:
65 std::wstring serviceClass_;
66 std::wstring serviceName_;
67 std::wstring instanceName_;
68 USHORT instancePort_;
69 std::wstring referrer_;
70 };
71}