summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose <jose@zeroc.com>2015-04-01 14:49:36 +0200
committerJose <jose@zeroc.com>2015-04-01 14:49:36 +0200
commiteb5749bee9ea0fc46211d365f1e21a6b460bc30d (patch)
treea5f44b79782cb2997e89dc6e3aafb0397f554afe
parentSSL fixes (bis) (diff)
downloadice-eb5749bee9ea0fc46211d365f1e21a6b460bc30d.tar.bz2
ice-eb5749bee9ea0fc46211d365f1e21a6b460bc30d.tar.xz
ice-eb5749bee9ea0fc46211d365f1e21a6b460bc30d.zip
ICE-6383 - Update crypt password usage
Added new script to create crypt passwords using passlib scripts/cryptpasswd.py Remove tests passwords files they are now generated using cryptpasswd script Update CryptPermissionsVerifierI to support PBKDF2 password schemes in Windows and OS X, and MD5/SHA256/SHA512 crypt in Linux, on other systems fallback to DES_crypt from openssl
-rw-r--r--.gitignore2
-rwxr-xr-xcpp/allTests.py1
-rw-r--r--cpp/config/Make.rules.Darwin4
-rw-r--r--cpp/config/Make.rules.Linux1
-rw-r--r--cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp296
-rw-r--r--cpp/src/Glacier2CryptPermissionsVerifier/Makefile2
-rw-r--r--cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak2
-rw-r--r--cpp/test/Glacier2/attack/passwords1
-rwxr-xr-xcpp/test/Glacier2/attack/run.py5
-rwxr-xr-xcpp/test/Glacier2/cryptpasswd/run.py114
-rw-r--r--cpp/test/Glacier2/router/passwords6
-rwxr-xr-xcpp/test/Glacier2/router/run.py6
-rw-r--r--cpp/test/Glacier2/sessionHelper/passwords1
-rwxr-xr-xcpp/test/Glacier2/sessionHelper/run.py5
-rw-r--r--cpp/test/Glacier2/staticFiltering/passwords1
-rwxr-xr-xcpp/test/Glacier2/staticFiltering/run.py5
-rw-r--r--csharp/test/Glacier2/router/passwords1
-rwxr-xr-xcsharp/test/Glacier2/router/run.py5
-rw-r--r--csharp/test/Glacier2/sessionHelper/passwords1
-rwxr-xr-xcsharp/test/Glacier2/sessionHelper/run.py5
-rw-r--r--java/test/src/main/java/test/Glacier2/router/passwords1
-rwxr-xr-xjava/test/src/main/java/test/Glacier2/router/run.py5
-rw-r--r--java/test/src/main/java/test/Glacier2/sessionHelper/passwords1
-rwxr-xr-xjava/test/src/main/java/test/Glacier2/sessionHelper/run.py5
-rw-r--r--js/test/Glacier2/router/passwords1
-rwxr-xr-xjs/test/Glacier2/router/run.py5
-rwxr-xr-xscripts/TestUtil.py21
-rw-r--r--scripts/cryptpasswd.py135
28 files changed, 614 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index 80a1760ed5c..82d36a18eb3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,3 +86,5 @@ cpp/src/Ice/EventLoggerMsg.res
# WinRT
cpp/SDKs
+
+passwords
diff --git a/cpp/allTests.py b/cpp/allTests.py
index 8b01519b97c..860fc464940 100755
--- a/cpp/allTests.py
+++ b/cpp/allTests.py
@@ -115,6 +115,7 @@ tests = [
("Glacier2/dynamicFiltering", ["service", "novc100", "nomingw"]),
("Glacier2/staticFiltering", ["service", "noipv6", "novc100", "nomingw", "nomx"]),
("Glacier2/sessionHelper", ["core", "novc100", "nomingw"]),
+ ("Glacier2/cryptpasswd", ["once", "nomingw", "novalgrind", "noappverifier"])
]
#
diff --git a/cpp/config/Make.rules.Darwin b/cpp/config/Make.rules.Darwin
index c801d50fa7f..d672de5c8c3 100644
--- a/cpp/config/Make.rules.Darwin
+++ b/cpp/config/Make.rules.Darwin
@@ -100,8 +100,8 @@ ICONV_LIB = -liconv
ICEUTIL_OS_LIBS =
ICE_OS_LIBS = -ldl
-
-SSL_OS_LIBS = -framework Security -framework CoreFoundation
+CRYPT_OS_LIBS = -framework Security -framework CoreFoundation
+SSL_OS_LIBS = $(CRYPT_OS_LIBS)
PLATFORM_HAS_READLINE := yes
diff --git a/cpp/config/Make.rules.Linux b/cpp/config/Make.rules.Linux
index 006434e9277..5668097a15f 100644
--- a/cpp/config/Make.rules.Linux
+++ b/cpp/config/Make.rules.Linux
@@ -203,6 +203,7 @@ endif
ICESSL_LIBS = $(OPENSSL_RPATH_LINK) -lIceSSL
LIBS = $(BZIP2_RPATH_LINK) -lIce $(BASELIBS)
+CRYPT_OS_LIBS = -lcrypt
ICEUTIL_OS_LIBS = -lrt $(OPENSSL_RPATH_LINK) -lcrypto
ICE_OS_LIBS = -ldl
diff --git a/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp b/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp
index 6c111b7c4a3..53bbb23f97f 100644
--- a/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp
+++ b/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp
@@ -13,8 +13,18 @@
#include <IceUtil/FileUtil.h>
#include <IceUtil/StringUtil.h>
-
-#ifndef __APPLE__
+#include <IceUtil/InputUtil.h>
+
+#if defined(__GLIBC__)
+# include <crypt.h>
+#elif defined(__APPLE__)
+# include <CoreFoundation/CoreFoundation.h>
+# include <Security/Security.h>
+# include <CommonCrypto/CommonCrypto.h>
+#elif defined(_WIN32)
+# include <Bcrypt.h>
+# include <Wincrypt.h>
+#else
# include <openssl/des.h>
#endif
@@ -92,6 +102,37 @@ CryptPermissionsVerifierI::CryptPermissionsVerifierI(const map<string, string>&
{
}
+namespace
+{
+
+#if defined(__APPLE__) || defined(_WIN32)
+
+const string padBytes0 = "";
+const string padBytes1 = "=";
+const string padBytes2 = "==";
+
+inline string
+paddingBytes(int lenght)
+{
+ switch(lenght % 4)
+ {
+ case 2:
+ {
+ return padBytes2;
+ }
+ case 3:
+ {
+ return padBytes1;
+ }
+ default:
+ {
+ return padBytes0;
+ }
+ }
+}
+#endif
+
+}
bool
CryptPermissionsVerifierI::checkPermissions(const string& userId, const string& password, string&, const Current&) const
{
@@ -103,6 +144,252 @@ CryptPermissionsVerifierI::checkPermissions(const string& userId, const string&
{
return false;
}
+#if defined(__GLIBC__)
+ size_t i = p->second.rfind('$');
+ if(i == string::npos)
+ {
+ return false;
+ }
+ string salt = p->second.substr(0, i + 1);
+ if(salt.empty())
+ {
+ return false;
+ }
+ struct crypt_data data;
+ data.initialized = 0;
+ return p->second == crypt_r(password.c_str(), salt.c_str(), &data);
+#elif defined(__APPLE__) || defined(_WIN32)
+ //
+ // Pbkdf2 string format:
+ //
+ // $pbkdf2-digest$rounds$salt$checksum
+ // $pbkdf2$rounds$salt$checksum (SHA1 digest)
+ //
+
+ size_t beg = 0;
+ size_t end = 0;
+
+
+ //
+ // Determine the digest algorithm
+ //
+# if defined(__APPLE__)
+ CCPseudoRandomAlgorithm algorithmId = 0;
+# else
+ LPCWSTR algorithmId = 0;
+# endif
+ int checksumLength = 0;
+
+ const string pbkdf2SHA1Token = "$pbkdf2$";
+
+ if(p->second.find(pbkdf2SHA1Token) == 0)
+ {
+# if defined(__APPLE__)
+ algorithmId = kCCPRFHmacAlgSHA1;
+# else
+ algorithmId = BCRYPT_SHA1_ALGORITHM;
+# endif
+ checksumLength = 20;
+ beg = pbkdf2SHA1Token.size();
+ }
+ else
+ {
+ //
+ // Pbkdf2 string format:
+ //
+ // $pbkdf2-digest$rounds$salt$checksum
+ //
+ const string pbkdf2Token = "$pbkdf2-";
+ if(p->second.find(pbkdf2Token) != 0)
+ {
+ return false; // PBKDF2 start token not found
+ }
+
+ beg = pbkdf2Token.size();
+ end = p->second.find('$', beg);
+ if(end == string::npos)
+ {
+ return false; // Digest algorithm end token not found
+ }
+
+ if(p->second.substr(beg, (end - beg)) == "sha256")
+ {
+# if defined(__APPLE__)
+ algorithmId = kCCPRFHmacAlgSHA256;
+# else
+ algorithmId = BCRYPT_SHA256_ALGORITHM;
+# endif
+ checksumLength = 32;
+ }
+ else if(p->second.substr(beg, (end - beg)) == "sha512")
+ {
+# if defined(__APPLE__)
+ algorithmId = kCCPRFHmacAlgSHA512;
+# else
+ algorithmId = BCRYPT_SHA512_ALGORITHM;
+# endif
+ checksumLength = 64;
+ }
+ else
+ {
+ return false; // Invalid digest algorithm
+ }
+ beg = end + 1;
+ }
+ //
+ // Determine the number of rounds
+ //
+ end = p->second.find('$', beg);
+ if(end == string::npos)
+ {
+ return false; // Rounds end token not found
+ }
+
+ IceUtil::Int64 rounds = 0;
+ if(!IceUtilInternal::stringToInt64(p->second.substr(beg, (end - beg)), rounds))
+ {
+ return false; // Invalid rounds value
+ }
+
+ //
+ // Determine salt and checksum
+ //
+ beg = end + 1;
+ end = p->second.find('$', beg);
+ if(end == string::npos)
+ {
+ return false; // Salt value end token not found
+ }
+
+ string salt = p->second.substr(beg, (end - beg));
+ string checksum = p->second.substr(end + 1);
+ if(checksum.empty())
+ {
+ return false;
+ }
+
+ //
+ // passlib encoding is identical to base64 except that it uses . instead of +,
+ // and omits trailing padding = and whitepsace.
+ //
+ std::replace(salt.begin(), salt.end(), '.', '+');
+ salt += paddingBytes(salt.size());
+
+ std::replace(checksum.begin(), checksum.end(), '.', '+');
+ checksum += paddingBytes(checksum.size());
+# if defined(__APPLE__)
+ CFErrorRef error = 0;
+ SecTransformRef decoder = SecDecodeTransformCreate(kSecBase64Encoding, &error);
+ if(error)
+ {
+ CFRelease(error);
+ return false;
+ }
+
+ CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+ reinterpret_cast<const uint8_t*>(salt.c_str()),
+ salt.size(), kCFAllocatorNull);
+
+ SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, data, &error);
+ if(error)
+ {
+ CFRelease(error);
+ CFRelease(decoder);
+ return false;
+ }
+
+ CFDataRef saltBuffer = static_cast<CFDataRef>(SecTransformExecute(decoder, &error));
+ CFRelease(decoder);
+
+ if(error)
+ {
+ CFRelease(error);
+ return false;
+ }
+
+ vector<uint8_t> checksumBuffer1(checksumLength);
+ OSStatus status = CCKeyDerivationPBKDF(kCCPBKDF2, password.c_str(), password.size(),
+ CFDataGetBytePtr(saltBuffer), CFDataGetLength(saltBuffer),
+ algorithmId, rounds, &checksumBuffer1[0], checksumLength);
+ CFRelease(saltBuffer);
+ if(status != errSecSuccess)
+ {
+ return false;
+ }
+
+ decoder = SecDecodeTransformCreate(kSecBase64Encoding, &error);
+ if(error)
+ {
+ CFRelease(error);
+ return false;
+ }
+ data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+ reinterpret_cast<const uint8_t*>(checksum.c_str()),
+ checksum.size(), kCFAllocatorNull);
+ SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, data, &error);
+ if(error)
+ {
+ CFRelease(error);
+ CFRelease(decoder);
+ return false;
+ }
+
+ data = static_cast<CFDataRef>(SecTransformExecute(decoder, &error));
+ CFRelease(decoder);
+ decoder = 0;
+
+ if(error)
+ {
+ CFRelease(error);
+ return false;
+ }
+
+ vector<uint8_t> checksumBuffer2(CFDataGetBytePtr(data), CFDataGetBytePtr(data) + CFDataGetLength(data));
+ CFRelease(data);
+
+ return checksumBuffer1 == checksumBuffer2;
+# else
+ DWORD saltLength = salt.size();
+ vector<BYTE> saltBuffer(saltLength);
+
+ if(!CryptStringToBinary(salt.c_str(), salt.size(), CRYPT_STRING_BASE64, &saltBuffer[0], &saltLength, 0, 0))
+ {
+ return false;
+ }
+ saltBuffer.resize(saltLength);
+
+ BCRYPT_ALG_HANDLE algorithmHandle = 0;
+ if(BCryptOpenAlgorithmProvider(&algorithmHandle, algorithmId, 0, BCRYPT_ALG_HANDLE_HMAC_FLAG) != 0)
+ {
+ return false;
+ }
+
+ vector<BYTE> checksumBuffer1(checksumLength);
+
+ vector<BYTE> passwordBuffer(password.begin(), password.end());
+
+ DWORD status = BCryptDeriveKeyPBKDF2(algorithmHandle, &passwordBuffer[0], passwordBuffer.size(),
+ &saltBuffer[0], saltLength, rounds,
+ &checksumBuffer1[0], checksumLength, 0);
+
+ BCryptCloseAlgorithmProvider(algorithmHandle, 0);
+
+ if(status != 0)
+ {
+ return false;
+ }
+
+ DWORD checksumBuffer2Length = checksumLength;
+ vector<BYTE> checksumBuffer2(checksumLength);
+
+ if(!CryptStringToBinary(checksum.c_str(), checksum.size(), CRYPT_STRING_BASE64, &checksumBuffer2[0],
+ &checksumBuffer2Length, 0, 0))
+ {
+ return false;
+ }
+ return checksumBuffer1 == checksumBuffer2;
+# endif
+#else
if(p->second.size() != 13) // Crypt passwords are 13 characters long.
{
@@ -111,16 +398,13 @@ CryptPermissionsVerifierI::checkPermissions(const string& userId, const string&
char buff[14];
string salt = p->second.substr(0, 2);
-#if defined(__APPLE__)
- return p->second == crypt(password.c_str(), salt.c_str());
-#else
# if OPENSSL_VERSION_NUMBER >= 0x0090700fL
DES_fcrypt(password.c_str(), salt.c_str(), buff);
# else
des_fcrypt(password.c_str(), salt.c_str(), buff);
# endif
-#endif
return p->second == buff;
+#endif
}
diff --git a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile
index 90829971149..f3c49c50313 100644
--- a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile
+++ b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile
@@ -24,7 +24,7 @@ include $(top_srcdir)/config/Make.rules
CPPFLAGS := -I.. $(CPPFLAGS)
-LINKWITH := $(BZIP2_RPATH_LINK) -lIce -lIceUtil -lGlacier2 $(ICEUTIL_OS_LIBS) $(CXXLIBS)
+LINKWITH := $(BZIP2_RPATH_LINK) -lIce -lIceUtil -lGlacier2 $(CRYPT_OS_LIBS) $(CXXLIBS)
$(libdir)/$(LIBFILENAME): $(OBJS)
@mkdir -p $(dir $@)
diff --git a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak
index 00ba7d8886b..3828a45771e 100644
--- a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak
+++ b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak
@@ -20,7 +20,7 @@ OBJS = .\CryptPermissionsVerifierI.obj
CPPFLAGS = -I.. $(CPPFLAGS) -DWIN32_LEAN_AND_MEAN
-LINKWITH = $(LIBS) libeay32.lib
+LINKWITH = $(LIBS) crypt32.lib bcrypt.lib
!if "$(GENERATE_PDB)" == "yes"
PDBFLAGS = /pdb:$(DLLNAME:.dll=.pdb)
diff --git a/cpp/test/Glacier2/attack/passwords b/cpp/test/Glacier2/attack/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/cpp/test/Glacier2/attack/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/cpp/test/Glacier2/attack/run.py b/cpp/test/Glacier2/attack/run.py
index cd3302f5371..36540456af9 100755
--- a/cpp/test/Glacier2/attack/run.py
+++ b/cpp/test/Glacier2/attack/run.py
@@ -26,6 +26,11 @@ router = TestUtil.getGlacier2Router()
if TestUtil.appverifier:
TestUtil.setAppVerifierSettings([router])
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
args = ' --Glacier2.RoutingTable.MaxSize=10' + \
' --Glacier2.Client.Endpoints="default -p 12347"' + \
' --Ice.Admin.Endpoints="tcp -h 127.0.0.1 -p 12348"' + \
diff --git a/cpp/test/Glacier2/cryptpasswd/run.py b/cpp/test/Glacier2/cryptpasswd/run.py
new file mode 100755
index 00000000000..fe441e07281
--- /dev/null
+++ b/cpp/test/Glacier2/cryptpasswd/run.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys, passlib.hash, subprocess
+
+path = [ ".", "..", "../..", "../../..", "../../../.." ]
+head = os.path.dirname(sys.argv[0])
+if len(head) > 0:
+ path = [os.path.join(head, p) for p in path]
+path = [os.path.abspath(p) for p in path if os.path.exists(os.path.join(p, "scripts", "TestUtil.py")) ]
+if len(path) == 0:
+ raise RuntimeError("can't find toplevel directory!")
+sys.path.append(os.path.join(path[0], "scripts"))
+import TestUtil
+
+cryptpasswd = os.path.join(path[0], "scripts", "cryptpasswd.py")
+
+def test(b):
+ if not b:
+ raise RuntimeError('test assertion failed')
+
+def cryptPasswords(password, args = ""):
+ p = subprocess.Popen("%s %s %s" % (sys.executable, cryptpasswd, args), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ stdin=subprocess.PIPE)
+ p.stdin.write(password.encode('UTF-8'))
+ p.stdin.write('\r\n'.encode('UTF-8'))
+ p.stdin.flush()
+ if(p.wait() != 0):
+ print("cryptpasswd.py failed:\n" + p.stdout.read().decode('UTF-8').strip())
+ sys.exit(1)
+ hash = p.stdout.readline().decode('UTF-8').strip()
+ return hash
+
+
+usePBKDF2 = sys.platform == "win32" or sys.platform == "darwin"
+useCryptExt = sys.platform.startswith("linux")
+
+if usePBKDF2:
+
+ sys.stdout.write("Testing PBKDF2 crypt passwords...")
+ sys.stdout.flush()
+
+ test(passlib.hash.pbkdf2_sha256.verify("abc123", cryptPasswords("abc123")))
+ test(not passlib.hash.pbkdf2_sha256.verify("abc123", cryptPasswords("abc")))
+
+ test(passlib.hash.pbkdf2_sha1.verify("abc123", cryptPasswords("abc123", "-d sha1")))
+ test(not passlib.hash.pbkdf2_sha1.verify("abc123", cryptPasswords("abc", "-d sha1")))
+
+ test(passlib.hash.pbkdf2_sha512.verify("abc123", cryptPasswords("abc123", "-d sha512")))
+ test(not passlib.hash.pbkdf2_sha512.verify("abc123", cryptPasswords("abc", "-d sha512")))
+
+ #
+ # Now use custom rounds, md5 digest doesn't support
+ #
+ hash = cryptPasswords("abc123", "-r 1000")
+ if hash.find("$pbkdf2-sha256$1000$") == -1:
+ test(False)
+ test(passlib.hash.pbkdf2_sha256.verify("abc123", hash))
+
+ hash = cryptPasswords("abc123", "-r 1000 -d sha1")
+ if hash.find("$pbkdf2$1000$") == -1:
+ test(False)
+ test(passlib.hash.pbkdf2_sha1.verify("abc123", hash))
+
+ hash = cryptPasswords("abc123", "-r 1000 -d sha512")
+ if hash.find("$pbkdf2-sha512$1000$") == -1:
+ test(False)
+ test(passlib.hash.pbkdf2_sha512.verify("abc123", hash))
+
+ print("ok")
+
+elif useCryptExt:
+
+ sys.stdout.write("Testing Linux crypt passwords...")
+ sys.stdout.flush()
+
+ test(passlib.hash.sha512_crypt.verify("abc123", cryptPasswords("abc123")))
+ test(not passlib.hash.sha512_crypt.verify("abc123", cryptPasswords("abc")))
+
+ test(passlib.hash.sha256_crypt.verify("abc123", cryptPasswords("abc123", "-d sha256")))
+ test(not passlib.hash.sha256_crypt.verify("abc123", cryptPasswords("abc", "-d sha256")))
+
+ test(passlib.hash.md5_crypt.verify("abc123", cryptPasswords("abc123", "-d md5")))
+ test(not passlib.hash.md5_crypt.verify("abc123", cryptPasswords("abc", "-d md5")))
+
+ #
+ # Now use custom rounds, md5 digest doesn't support
+ #
+ hash = cryptPasswords("abc123", "-r 5000")
+ if hash.find("rounds=") != -1:
+ test(False)
+ test(passlib.hash.sha512_crypt.verify("abc123", hash))
+ hash = cryptPasswords("abc123", "-d sha256 -r 5000")
+ if hash.find("rounds=") != -1:
+ test(False)
+ test(passlib.hash.sha256_crypt.verify("abc123", hash))
+
+ hash = cryptPasswords("abc123", "-r 10000")
+ if hash.find("$rounds=10000$") == -1:
+ test(False)
+ test(passlib.hash.sha512_crypt.verify("abc123", hash))
+ hash = cryptPasswords("abc123", "-d sha256 -r 10000")
+ if hash.find("$rounds=10000$") == -1:
+ test(False)
+ test(passlib.hash.sha256_crypt.verify("abc123", hash))
+
+ print("ok")
diff --git a/cpp/test/Glacier2/router/passwords b/cpp/test/Glacier2/router/passwords
deleted file mode 100644
index 01943218b12..00000000000
--- a/cpp/test/Glacier2/router/passwords
+++ /dev/null
@@ -1,6 +0,0 @@
-userid xxMqsnnDcK8tw
-userid-0 xxMqsnnDcK8tw
-userid-1 xxMqsnnDcK8tw
-userid-2 xxMqsnnDcK8tw
-userid-3 xxMqsnnDcK8tw
-userid-4 xxMqsnnDcK8tw
diff --git a/cpp/test/Glacier2/router/run.py b/cpp/test/Glacier2/router/run.py
index 050eee50d4c..60e5d448164 100755
--- a/cpp/test/Glacier2/router/run.py
+++ b/cpp/test/Glacier2/router/run.py
@@ -55,6 +55,12 @@ def startRouter(buffered):
name = os.path.join("Glacier2", "router")
#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"),
+ {"userid": "abc123", "userid-0": "abc123", "userid-1": "abc123",
+ "userid-2": "abc123", "userid-3": "abc123","userid-4": "abc123"})
+#
# We first run the test with unbuffered mode.
#
starterProc = startRouter(False)
diff --git a/cpp/test/Glacier2/sessionHelper/passwords b/cpp/test/Glacier2/sessionHelper/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/cpp/test/Glacier2/sessionHelper/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/cpp/test/Glacier2/sessionHelper/run.py b/cpp/test/Glacier2/sessionHelper/run.py
index 3ec7dec5363..14e74172df1 100755
--- a/cpp/test/Glacier2/sessionHelper/run.py
+++ b/cpp/test/Glacier2/sessionHelper/run.py
@@ -22,6 +22,11 @@ import TestUtil
router = os.path.join(TestUtil.getCppBinDir(), "glacier2router")
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
args = ' --Ice.Warn.Dispatch=0' + \
' --Ice.Warn.Connections=0' + \
' --Glacier2.SessionTimeout="30"' + \
diff --git a/cpp/test/Glacier2/staticFiltering/passwords b/cpp/test/Glacier2/staticFiltering/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/cpp/test/Glacier2/staticFiltering/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/cpp/test/Glacier2/staticFiltering/run.py b/cpp/test/Glacier2/staticFiltering/run.py
index e379442e327..de52ea47942 100755
--- a/cpp/test/Glacier2/staticFiltering/run.py
+++ b/cpp/test/Glacier2/staticFiltering/run.py
@@ -29,6 +29,11 @@ router = TestUtil.getGlacier2Router()
clientCmd = os.path.join(os.getcwd(), 'client')
serverCmd = os.path.join(os.getcwd(), 'server')
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
targets = []
if TestUtil.appverifier:
targets = [serverCmd, clientCmd, router]
diff --git a/csharp/test/Glacier2/router/passwords b/csharp/test/Glacier2/router/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/csharp/test/Glacier2/router/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/csharp/test/Glacier2/router/run.py b/csharp/test/Glacier2/router/run.py
index 4b88f3f882a..c32b3873c0c 100755
--- a/csharp/test/Glacier2/router/run.py
+++ b/csharp/test/Glacier2/router/run.py
@@ -22,6 +22,11 @@ import TestUtil
router = os.path.join(TestUtil.getCppBinDir(), "glacier2router")
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
args = ' --Ice.Warn.Dispatch=0' + \
' --Ice.Warn.Connections=0' + \
' --Glacier2.Filter.Category.Accept="c1 c2"' + \
diff --git a/csharp/test/Glacier2/sessionHelper/passwords b/csharp/test/Glacier2/sessionHelper/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/csharp/test/Glacier2/sessionHelper/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/csharp/test/Glacier2/sessionHelper/run.py b/csharp/test/Glacier2/sessionHelper/run.py
index 1565361b923..4bfc2a41224 100755
--- a/csharp/test/Glacier2/sessionHelper/run.py
+++ b/csharp/test/Glacier2/sessionHelper/run.py
@@ -20,6 +20,11 @@ if len(path) == 0:
sys.path.append(os.path.join(path[0], "scripts"))
import TestUtil
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
router = os.path.join(TestUtil.getCppBinDir(), "glacier2router")
args = ' --Ice.Warn.Dispatch=0' + \
diff --git a/java/test/src/main/java/test/Glacier2/router/passwords b/java/test/src/main/java/test/Glacier2/router/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/java/test/src/main/java/test/Glacier2/router/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/java/test/src/main/java/test/Glacier2/router/run.py b/java/test/src/main/java/test/Glacier2/router/run.py
index 780ceff6580..7baa3ac3c5c 100755
--- a/java/test/src/main/java/test/Glacier2/router/run.py
+++ b/java/test/src/main/java/test/Glacier2/router/run.py
@@ -23,6 +23,11 @@ import TestUtil
router = os.path.join(TestUtil.getCppBinDir(), "glacier2router")
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
args = ' --Ice.Warn.Dispatch=0' + \
' --Ice.Warn.Connections=0' + \
' --Glacier2.Filter.Category.Accept="c1 c2"' + \
diff --git a/java/test/src/main/java/test/Glacier2/sessionHelper/passwords b/java/test/src/main/java/test/Glacier2/sessionHelper/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/java/test/src/main/java/test/Glacier2/sessionHelper/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/java/test/src/main/java/test/Glacier2/sessionHelper/run.py b/java/test/src/main/java/test/Glacier2/sessionHelper/run.py
index 0144d973b85..4146018f313 100755
--- a/java/test/src/main/java/test/Glacier2/sessionHelper/run.py
+++ b/java/test/src/main/java/test/Glacier2/sessionHelper/run.py
@@ -23,6 +23,11 @@ import TestUtil
router = os.path.join(TestUtil.getCppBinDir(), "glacier2router")
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
args = ' --Ice.Warn.Dispatch=0' + \
' --Ice.Warn.Connections=0' + \
' --Glacier2.SessionTimeout="30"' + \
diff --git a/js/test/Glacier2/router/passwords b/js/test/Glacier2/router/passwords
deleted file mode 100644
index a1527dec2b9..00000000000
--- a/js/test/Glacier2/router/passwords
+++ /dev/null
@@ -1 +0,0 @@
-userid xxMqsnnDcK8tw \ No newline at end of file
diff --git a/js/test/Glacier2/router/run.py b/js/test/Glacier2/router/run.py
index b05757bb98b..e1ba5205563 100755
--- a/js/test/Glacier2/router/run.py
+++ b/js/test/Glacier2/router/run.py
@@ -22,6 +22,11 @@ import TestUtil
router = os.path.join(TestUtil.getCppBinDir(), "glacier2router")
+#
+# Generate the crypt passwords file
+#
+TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"})
+
args = ' --Ice.Warn.Dispatch=0' + \
' --Ice.Warn.Connections=0' + \
' --Glacier2.Filter.Category.Accept="c1 c2"' + \
diff --git a/scripts/TestUtil.py b/scripts/TestUtil.py
index 2a9f847016d..0ee9a0b73af 100755
--- a/scripts/TestUtil.py
+++ b/scripts/TestUtil.py
@@ -827,6 +827,27 @@ def getIceExe(name):
def getNodeCommand():
return nodeCmd
+#
+# Create a passwords file that contains the given users/passwords using cryptpasswd.py
+#
+def cryptPasswords(filePath, entries):
+ if os.path.exists(filePath):
+ os.remove(filePath)
+ passwords = open(filePath, "a")
+ for user, password in entries.items():
+ p = subprocess.Popen(
+ "%s %s" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "cryptpasswd.py"))),
+ shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
+ p.stdin.write(password.encode('UTF-8'))
+ p.stdin.write('\r\n'.encode('UTF-8'))
+ p.stdin.flush()
+ if(p.wait() != 0):
+ print("cryptpasswd.py failed:\n" + p.stdout.read().decode('UTF-8').strip())
+ passwords.close()
+ sys.exit(1)
+ passwords.write("%s %s\n" % (user, p.stdout.readline().decode('UTF-8').strip()))
+ passwords.close()
+
class InvalidSelectorString(Exception):
def __init__(self, value):
self.value = value
diff --git a/scripts/cryptpasswd.py b/scripts/cryptpasswd.py
new file mode 100644
index 00000000000..2277e23beef
--- /dev/null
+++ b/scripts/cryptpasswd.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import sys, getopt, passlib.hash, getpass
+
+usePBKDF2 = sys.platform == "win32" or sys.platform == "darwin"
+useCryptExt = sys.platform.startswith("linux")
+
+def usage():
+ print("cryptpasswd [options]")
+ print("")
+ print("OPTIONS")
+ print("")
+ if usePBKDF2:
+ print("")
+ print(" -d DIGEST_ALGORITHM, --digest=DIGEST_ALGORITHM")
+ print(" The digest algorithm to use with PBKDF2, valid values are (sha1, sha256, sha512).")
+ print("")
+ print(" -s SALT_SIZE, --salt=SALT_SIZE")
+ print(" Optional number of bytes to use when generating new salts.")
+ print("")
+ elif useCryptExt:
+ print(" -d DIGEST_ALGORITHM, --digest=DIGEST_ALGORITHM")
+ print(" The digest algorithm to use with crypt function, valid values are (md5, sha256, sha512).")
+ print("")
+ if usePBKDF2 or useCryptExt:
+ print(" -r ROUNDS, --rounds=ROUNDS")
+ print(" Optional number of rounds to use.")
+ print("")
+ print(" -h, --help" )
+ print(" Show this message.")
+ print("")
+
+def encrypt():
+
+ digestAlgorithms = ()
+ shortArgs = "h"
+ longArgs = ["help"]
+ if usePBKDF2:
+ shortArgs += "d:s:r:"
+ longArgs += ["digest=", "salt=", "rounds="]
+ digestAlgorithms = ("sha1", "sha256", "sha512")
+ elif useCryptExt:
+ shortArgs += "d:r:"
+ longArgs += ["digest=", "rounds="]
+ digestAlgorithms = ("md5", "sha256", "sha512")
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], shortArgs, longArgs)
+ except getopt.GetoptError as err:
+ print("")
+ print(str(err))
+ usage()
+ sys.exit(2)
+
+ digest = None
+ salt = None
+ rounds = None
+
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit(0)
+ elif o in ("-d", "--digest"):
+ if a in digestAlgorithms:
+ digest = a
+ else:
+ print("Unknown digest algorithm `" + a + "'")
+ sys.exit(2)
+ elif o in ("-s", "--salt"):
+ try:
+ salt = int(a)
+ if salt < 0 or salt > 1024:
+ print("Invalid salt value it must be an integer between 0 and 1024")
+ usage()
+ sys.exit(2)
+ except ValueError as err:
+ print("Invalid salt value it must be an integer between 0 and 1024")
+ usage()
+ sys.exit(2)
+ elif o in ("-r", "--rounds"):
+ try:
+ rounds = int(a)
+ if rounds < 1 or rounds > sys.maxsize:
+ print("Invalid rounds value it must be an integer between 1 and %s" % sys.maxsize)
+ usage()
+ sys.exit(2)
+ except ValueError as err:
+ print("Invalid rounds value it must be an integer between 1 and %s" % sys.maxsize)
+ usage()
+ sys.exit(2)
+
+ encryptfn = None
+ if usePBKDF2:
+ encryptfn = passlib.hash.pbkdf2_sha256.encrypt
+ if digest == "sha1":
+ encryptfn = passlib.hash.pbkdf2_sha1.encrypt
+ elif digest == "sha512":
+ encryptfn = passlib.hash.pbkdf2_sha512.encrypt
+ elif useCryptExt:
+ encryptfn = passlib.hash.sha512_crypt.encrypt
+ if digest == "md5":
+ if rounds:
+ print("Custom rounds not allowed with md5 digest")
+ usage()
+ sys.exit(2)
+ encryptfn = passlib.hash.md5_crypt.encrypt
+ elif digest == "sha256":
+ encryptfn = passlib.hash.sha256_crypt.encrypt
+ else:
+ encryptfn = passlib.hash.des_crypt.encrypt
+
+ args = []
+ if sys.stdout.isatty():
+ args.append(getpass.getpass("Password: "))
+ else:
+ args.append(sys.stdin.readline().strip())
+
+ opts = {}
+ if salt:
+ opts["salt_size"] = salt
+
+ if rounds:
+ opts["rounds"] = rounds
+
+ print(encryptfn(*args, **opts))
+
+encrypt()