r46908 - Merge conch-checkers-py3-8225: Port twisted.conch.checkers to Python 3
hawkowl-TA+aISz0psMTMxyoc4vAAJOcrHinNvQL0E9HWUfgJXw@public.gmane.org
| Newsgroups | gmane.comp.python.twisted.commits |
|---|---|
| Message-ID | <[email protected]> |
Author: hawkowl
Date: Thu Mar 3 23:41:01 2016
New Revision: 46908
Added:
trunk/twisted/conch/topfiles/8225.feature
Modified:
trunk/twisted/conch/checkers.py
trunk/twisted/conch/error.py
trunk/twisted/conch/test/test_checkers.py
trunk/twisted/python/compat.py
trunk/twisted/python/dist3.py
Log:
Merge conch-checkers-py3-8225: Port twisted.conch.checkers to Python 3
Author: hawkowl
Reviewer: adiroiban
Fixes: #8225
Modified: trunk/twisted/conch/checkers.py
==============================================================================
--- trunk/twisted/conch/checkers.py (original)
+++ trunk/twisted/conch/checkers.py Thu Mar 3 23:41:01 2016
@@ -6,7 +6,12 @@
Provide L{ICredentialsChecker} implementations to be used in Conch protocols.
"""
-import base64, binascii, errno
+from __future__ import absolute_import, division
+
+import sys
+import binascii
+import errno
+
try:
import pwd
except ImportError:
@@ -15,26 +20,19 @@
import crypt
try:
- # Python 2.5 got spwd to interface with shadow passwords
import spwd
except ImportError:
spwd = None
- try:
- import shadow
- except ImportError:
- shadow = None
-else:
- shadow = None
from zope.interface import providedBy, implementer, Interface
-
from twisted.conch import error
from twisted.conch.ssh import keys
from twisted.cred.checkers import ICredentialsChecker
from twisted.cred.credentials import IUsernamePassword, ISSHPrivateKey
from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials
from twisted.internet import defer
+from twisted.python.compat import _keys, _PY3, _b64decodebytes
from twisted.python import failure, reflect, log
from twisted.python.deprecate import deprecatedModuleAttribute
from twisted.python.util import runAsEffectiveUser
@@ -44,6 +42,16 @@
def verifyCryptedPassword(crypted, pw):
+ """
+ Check that the password, when crypted, matches the stored crypted password.
+
+ @param crypted: The stored crypted password.
+ @type crypted: L{str}
+ @param pw: The password the user has given.
+ @type pw: L{str}
+
+ @rtype: L{bool}
+ """
return crypt.crypt(pw, crypted) == crypted
@@ -55,6 +63,7 @@
@param username: the username of the user to return the passwd database
information for.
+ @type username: L{str}
"""
if pwd is None:
return None
@@ -64,16 +73,15 @@
def _shadowGetByName(username):
"""
- Look up a user in the /etc/shadow database using the spwd or shadow
- modules. If neither module is available, return None.
+ Look up a user in the /etc/shadow database using the spwd module. If it is
+ not available, return C{None}.
@param username: the username of the user to return the shadow database
information for.
+ @type username: L{str}
"""
if spwd is not None:
f = spwd.getspnam
- elif shadow is not None:
- f = shadow.getspnam
else:
return None
return runAsEffectiveUser(0, 0, f, username)
@@ -87,8 +95,8 @@
databases of a compatible format.
@ivar _getByNameFunctions: a C{list} of functions which are called in order
- to valid a user. The default value is such that the /etc/passwd
- database will be tried first, followed by the /etc/shadow database.
+ to valid a user. The default value is such that the C{/etc/passwd}
+ database will be tried first, followed by the C{/etc/shadow} database.
"""
credentialInterfaces = IUsernamePassword,
@@ -99,9 +107,18 @@
def requestAvatarId(self, credentials):
+ # We get bytes, but the Py3 pwd module uses str. So attempt to decode
+ # it using the same method that CPython does for the file on disk.
+ if _PY3:
+ username = credentials.username.decode(sys.getfilesystemencoding())
+ password = credentials.password.decode(sys.getfilesystemencoding())
+ else:
+ username = credentials.username
+ password = credentials.password
+
for func in self._getByNameFunctions:
try:
- pwnam = func(credentials.username)
+ pwnam = func(username)
except KeyError:
return defer.fail(UnauthorizedLogin("invalid username"))
else:
@@ -109,7 +126,8 @@
crypted = pwnam[1]
if crypted == '':
continue
- if verifyCryptedPassword(crypted, credentials.password):
+
+ if verifyCryptedPassword(crypted, password):
return defer.succeed(credentials.username)
# fallback
return defer.fail(UnauthorizedLogin("unable to verify password"))
@@ -211,7 +229,7 @@
if len(l2) < 2:
continue
try:
- if base64.decodestring(l2[1]) == credentials.blob:
+ if _b64decodebytes(l2[1]) == credentials.blob:
return True
except binascii.Error:
continue
@@ -243,7 +261,7 @@
self.successfulCredentials = {}
def get_credentialInterfaces(self):
- return self.checkers.keys()
+ return _keys(self.checkers)
credentialInterfaces = property(get_credentialInterfaces)
@@ -354,7 +372,7 @@
"""
for line in fileobj:
line = line.strip()
- if line and not line.startswith('#'): # for comments
+ if line and not line.startswith(b'#'): # for comments
try:
yield parseKey(line)
except keys.BadKeyError as e:
@@ -553,7 +571,7 @@
was any error verifying the signature.
@return: The user's username, if authentication was successful
- @rtype: C{str}
+ @rtype: L{bytes}
"""
try:
if pubKey.verify(credentials.signature, credentials.sigData):
Modified: trunk/twisted/conch/error.py
==============================================================================
--- trunk/twisted/conch/error.py (original)
+++ trunk/twisted/conch/error.py Thu Mar 3 23:41:01 2016
@@ -7,8 +7,9 @@
Maintainer: Paul Swartz
"""
-from twisted.cred.error import UnauthorizedLogin
+from __future__ import absolute_import, division
+from twisted.cred.error import UnauthorizedLogin
class ConchError(Exception):
Modified: trunk/twisted/conch/test/test_checkers.py
==============================================================================
--- trunk/twisted/conch/test/test_checkers.py (original)
+++ trunk/twisted/conch/test/test_checkers.py Thu Mar 3 23:41:01 2016
@@ -5,6 +5,8 @@
Tests for L{twisted.conch.checkers}.
"""
+from __future__ import absolute_import, division
+
try:
import crypt
except ImportError:
@@ -12,13 +14,15 @@
else:
cryptSkip = None
-import os, base64
+import os
+
from collections import namedtuple
-from io import StringIO
+from io import BytesIO
from zope.interface.verify import verifyObject
from twisted.python import util
+from twisted.python.compat import _b64encodebytes
from twisted.python.failure import Failure
from twisted.python.reflect import requireModule
from twisted.trial.unittest import TestCase
@@ -30,6 +34,7 @@
from twisted.python.fakepwd import UserDatabase, ShadowDatabase
from twisted.test.test_process import MockOS
+
if requireModule('cryptography') and requireModule('pyasn1'):
dependencySkip = None
from twisted.conch.ssh import keys
@@ -140,32 +145,9 @@
def test_shadowGetByNameWithoutSpwd(self):
"""
- L{_shadowGetByName} uses the C{shadow} module to return a tuple of items
- from the UNIX /etc/shadow database if the C{spwd} module is not present
- and the C{shadow} module is.
- """
- userdb = ShadowDatabase()
- userdb.addUser('bob', 'passphrase', 1, 2, 3, 4, 5, 6, 7)
- self.patch(checkers, 'spwd', None)
- self.patch(checkers, 'shadow', userdb)
- self.patch(util, 'os', self.mockos)
-
- self.mockos.euid = 2345
- self.mockos.egid = 1234
-
- self.assertEqual(
- checkers._shadowGetByName('bob'), userdb.getspnam('bob'))
- self.assertEqual(self.mockos.seteuidCalls, [0, 2345])
- self.assertEqual(self.mockos.setegidCalls, [0, 1234])
-
-
- def test_shadowGetByNameWithoutEither(self):
- """
- L{_shadowGetByName} returns C{None} if neither C{spwd} nor C{shadow} is
- present.
+ L{_shadowGetByName} returns C{None} if C{spwd} is not present.
"""
self.patch(checkers, 'spwd', None)
- self.patch(checkers, 'shadow', None)
self.assertIs(checkers._shadowGetByName('bob'), None)
self.assertEqual(self.mockos.seteuidCalls, [])
@@ -181,9 +163,10 @@
def setUp(self):
self.checker = checkers.SSHPublicKeyDatabase()
- self.key1 = base64.encodestring("foobar")
- self.key2 = base64.encodestring("eggspam")
- self.content = "t1 %s foo\nt2 %s egg\n" % (self.key1, self.key2)
+ self.key1 = _b64encodebytes(b"foobar")
+ self.key2 = _b64encodebytes(b"eggspam")
+ self.content = (b"t1 " + self.key1 + b" foo\nt2 " + self.key2 +
+ b" egg\n")
self.mockos = MockOS()
self.mockos.path = FilePath(self.mktemp())
@@ -194,8 +177,8 @@
userdb = UserDatabase()
userdb.addUser(
- 'user', 'password', 1, 2, 'first last',
- self.mockos.path.path, '/bin/shell')
+ b'user', b'password', 1, 2, b'first last',
+ self.mockos.path.path, b'/bin/shell')
self.checker._userdb = userdb
@@ -218,12 +201,12 @@
def _testCheckKey(self, filename):
self.sshDir.child(filename).setContent(self.content)
- user = UsernamePassword("user", "password")
- user.blob = "foobar"
+ user = UsernamePassword(b"user", b"password")
+ user.blob = b"foobar"
self.assertTrue(self.checker.checkKey(user))
- user.blob = "eggspam"
+ user.blob = b"eggspam"
self.assertTrue(self.checker.checkKey(user))
- user.blob = "notallowed"
+ user.blob = b"notallowed"
self.assertFalse(self.checker.checkKey(user))
@@ -255,19 +238,19 @@
keyFile = self.sshDir.child("authorized_keys")
keyFile.setContent(self.content)
# Fake permission error by changing the mode
- keyFile.chmod(0000)
- self.addCleanup(keyFile.chmod, 0777)
+ keyFile.chmod(0o000)
+ self.addCleanup(keyFile.chmod, 0o777)
# And restore the right mode when seteuid is called
savedSeteuid = self.mockos.seteuid
def seteuid(euid):
- keyFile.chmod(0777)
+ keyFile.chmod(0o777)
return savedSeteuid(euid)
self.mockos.euid = 2345
self.mockos.egid = 1234
self.patch(self.mockos, "seteuid", seteuid)
self.patch(util, 'os', self.mockos)
- user = UsernamePassword("user", "password")
- user.blob = "foobar"
+ user = UsernamePassword(b"user", b"password")
+ user.blob = b"foobar"
self.assertTrue(self.checker.checkKey(user))
self.assertEqual(self.mockos.seteuidCalls, [0, 1, 0, 2345])
self.assertEqual(self.mockos.setegidCalls, [2, 1234])
@@ -282,11 +265,11 @@
return True
self.patch(self.checker, 'checkKey', _checkKey)
credentials = SSHPrivateKey(
- 'test', 'ssh-rsa', keydata.publicRSA_openssh, 'foo',
- keys.Key.fromString(keydata.privateRSA_openssh).sign('foo'))
+ b'test', b'ssh-rsa', keydata.publicRSA_openssh, b'foo',
+ keys.Key.fromString(keydata.privateRSA_openssh).sign(b'foo'))
d = self.checker.requestAvatarId(credentials)
def _verify(avatarId):
- self.assertEqual(avatarId, 'test')
+ self.assertEqual(avatarId, b'test')
return d.addCallback(_verify)
@@ -301,7 +284,7 @@
return True
self.patch(self.checker, 'checkKey', _checkKey)
credentials = SSHPrivateKey(
- 'test', 'ssh-rsa', keydata.publicRSA_openssh, None, None)
+ b'test', b'ssh-rsa', keydata.publicRSA_openssh, None, None)
d = self.checker.requestAvatarId(credentials)
return self.assertFailure(d, ValidPublicKey)
@@ -328,8 +311,8 @@
return True
self.patch(self.checker, 'checkKey', _checkKey)
credentials = SSHPrivateKey(
- 'test', 'ssh-rsa', keydata.publicRSA_openssh, 'foo',
- keys.Key.fromString(keydata.privateDSA_openssh).sign('foo'))
+ b'test', b'ssh-rsa', keydata.publicRSA_openssh, b'foo',
+ keys.Key.fromString(keydata.privateDSA_openssh).sign(b'foo'))
d = self.checker.requestAvatarId(credentials)
return self.assertFailure(d, UnauthorizedLogin)
@@ -342,7 +325,7 @@
def _checkKey(ignored):
return True
self.patch(self.checker, 'checkKey', _checkKey)
- credentials = SSHPrivateKey('test', None, 'blob', 'sigData', 'sig')
+ credentials = SSHPrivateKey(b'test', None, b'blob', b'sigData', b'sig')
d = self.checker.requestAvatarId(credentials)
def _verifyLoggedException(failure):
errors = self.flushLoggedErrors(keys.BadKeyError)
@@ -396,11 +379,11 @@
"""
checker = checkers.SSHProtocolChecker()
passwordDatabase = InMemoryUsernamePasswordDatabaseDontUse()
- passwordDatabase.addUser('test', 'test')
+ passwordDatabase.addUser(b'test', b'test')
checker.registerChecker(passwordDatabase)
- d = checker.requestAvatarId(UsernamePassword('test', 'test'))
+ d = checker.requestAvatarId(UsernamePassword(b'test', b'test'))
def _callback(avatarId):
- self.assertEqual(avatarId, 'test')
+ self.assertEqual(avatarId, b'test')
return d.addCallback(_callback)
@@ -416,9 +399,9 @@
self.patch(checker, 'areDone', _areDone)
passwordDatabase = InMemoryUsernamePasswordDatabaseDontUse()
- passwordDatabase.addUser('test', 'test')
+ passwordDatabase.addUser(b'test', b'test')
checker.registerChecker(passwordDatabase)
- d = checker.requestAvatarId(UsernamePassword('test', 'test'))
+ d = checker.requestAvatarId(UsernamePassword(b'test', b'test'))
return self.assertFailure(d, NotEnoughAuthentication)
@@ -428,7 +411,7 @@
L{SSHProtocolChecker} should raise L{UnhandledCredentials}.
"""
checker = checkers.SSHProtocolChecker()
- d = checker.requestAvatarId(UsernamePassword('test', 'test'))
+ d = checker.requestAvatarId(UsernamePassword(b'test', b'test'))
return self.assertFailure(d, UnhandledCredentials)
@@ -497,12 +480,12 @@
mockos.euid = 2345
mockos.egid = 1234
- cred = UsernamePassword("alice", "password")
- self.assertLoggedIn(checker.requestAvatarId(cred), 'alice')
+ cred = UsernamePassword(b"alice", b"password")
+ self.assertLoggedIn(checker.requestAvatarId(cred), b'alice')
self.assertEqual(mockos.seteuidCalls, [])
self.assertEqual(mockos.setegidCalls, [])
- cred.username = "bob"
- self.assertLoggedIn(checker.requestAvatarId(cred), 'bob')
+ cred.username = b"bob"
+ self.assertLoggedIn(checker.requestAvatarId(cred), b'bob')
self.assertEqual(mockos.seteuidCalls, [0, 2345])
self.assertEqual(mockos.setegidCalls, [0, 1234])
@@ -534,8 +517,8 @@
userdb.addUser('anybody', password, 1, 2, 'foo', '/bar', '/bin/sh')
checker = checkers.UNIXPasswordDatabase([userdb.getpwnam])
self.assertLoggedIn(
- checker.requestAvatarId(UsernamePassword('anybody', 'secret')),
- 'anybody')
+ checker.requestAvatarId(UsernamePassword(b'anybody', b'secret')),
+ b'anybody')
def test_verifyPassword(self):
@@ -550,8 +533,8 @@
return [username, username]
self.patch(checkers, 'verifyCryptedPassword', verifyCryptedPassword)
checker = checkers.UNIXPasswordDatabase([getpwnam])
- credential = UsernamePassword('username', 'username')
- self.assertLoggedIn(checker.requestAvatarId(credential), 'username')
+ credential = UsernamePassword(b'username', b'username')
+ self.assertLoggedIn(checker.requestAvatarId(credential), b'username')
def test_failOnKeyError(self):
@@ -562,7 +545,7 @@
def getpwnam(username):
raise KeyError(username)
checker = checkers.UNIXPasswordDatabase([getpwnam])
- credential = UsernamePassword('username', 'username')
+ credential = UsernamePassword(b'username', b'username')
self.assertUnauthorizedLogin(checker.requestAvatarId(credential))
@@ -577,7 +560,7 @@
return [username, username]
self.patch(checkers, 'verifyCryptedPassword', verifyCryptedPassword)
checker = checkers.UNIXPasswordDatabase([getpwnam])
- credential = UsernamePassword('username', 'username')
+ credential = UsernamePassword(b'username', b'username')
self.assertUnauthorizedLogin(checker.requestAvatarId(credential))
@@ -596,8 +579,8 @@
return [username, username]
self.patch(checkers, 'verifyCryptedPassword', verifyCryptedPassword)
checker = checkers.UNIXPasswordDatabase([getpwnam1, getpwnam2])
- credential = UsernamePassword('username', 'username')
- self.assertLoggedIn(checker.requestAvatarId(credential), 'username')
+ credential = UsernamePassword(b'username', b'username')
+ self.assertLoggedIn(checker.requestAvatarId(credential), b'username')
def test_failOnSpecial(self):
@@ -612,13 +595,13 @@
self.patch(checkers, 'pwd', pwd)
checker = checkers.UNIXPasswordDatabase([checkers._pwdGetByName])
- cred = UsernamePassword('alice', '')
+ cred = UsernamePassword(b'alice', b'')
self.assertUnauthorizedLogin(checker.requestAvatarId(cred))
- cred = UsernamePassword('bob', 'x')
+ cred = UsernamePassword(b'bob', b'x')
self.assertUnauthorizedLogin(checker.requestAvatarId(cred))
- cred = UsernamePassword('carol', '*')
+ cred = UsernamePassword(b'carol', b'*')
self.assertUnauthorizedLogin(checker.requestAvatarId(cred))
@@ -635,12 +618,12 @@
L{checkers.readAuthorizedKeyFile} does not attempt to turn comments
into keys
"""
- fileobj = StringIO(u'# this comment is ignored\n'
- u'this is not\n'
- u'# this is again\n'
- u'and this is not')
+ fileobj = BytesIO(b'# this comment is ignored\n'
+ b'this is not\n'
+ b'# this is again\n'
+ b'and this is not')
result = checkers.readAuthorizedKeyFile(fileobj, lambda x: x)
- self.assertEqual(['this is not', 'and this is not'], list(result))
+ self.assertEqual([b'this is not', b'and this is not'], list(result))
def test_ignoresLeadingWhitespaceAndEmptyLines(self):
@@ -648,12 +631,12 @@
L{checkers.readAuthorizedKeyFile} ignores leading whitespace in
lines, as well as empty lines
"""
- fileobj = StringIO(u"""
+ fileobj = BytesIO(b"""
# ignore
not ignored
""")
result = checkers.readAuthorizedKeyFile(fileobj, parseKey=lambda x: x)
- self.assertEqual(['not ignored'], list(result))
+ self.assertEqual([b'not ignored'], list(result))
def test_ignoresUnparsableKeys(self):
@@ -663,14 +646,14 @@
L{twisted.conch.ssh.keys.BadKeyError}), but rather just keeps going
"""
def failOnSome(line):
- if line.startswith('f'):
+ if line.startswith(b'f'):
raise keys.BadKeyError('failed to parse')
return line
- fileobj = StringIO(u'failed key\ngood key')
+ fileobj = BytesIO(b'failed key\ngood key')
result = checkers.readAuthorizedKeyFile(fileobj,
parseKey=failOnSome)
- self.assertEqual(['good key'], list(result))
+ self.assertEqual([b'good key'], list(result))
@@ -686,7 +669,7 @@
L{checkers.InMemorySSHKeyDB} implements
L{checkers.IAuthorizedKeysDB}
"""
- keydb = checkers.InMemorySSHKeyDB({'alice': ['key']})
+ keydb = checkers.InMemorySSHKeyDB({b'alice': [b'key']})
verifyObject(checkers.IAuthorizedKeysDB, keydb)
@@ -696,8 +679,8 @@
L{checkers.InMemorySSHKeyDB}, an empty iterator is returned
by L{checkers.InMemorySSHKeyDB.getAuthorizedKeys}
"""
- keydb = checkers.InMemorySSHKeyDB({'alice': ['keys']})
- self.assertEqual([], list(keydb.getAuthorizedKeys('bob')))
+ keydb = checkers.InMemorySSHKeyDB({b'alice': [b'keys']})
+ self.assertEqual([], list(keydb.getAuthorizedKeys(b'bob')))
def test_allKeysForAuthorizedUser(self):
@@ -706,8 +689,8 @@
L{checkers.InMemorySSHKeyDB}, an iterator with all the keys
is returned by L{checkers.InMemorySSHKeyDB.getAuthorizedKeys}
"""
- keydb = checkers.InMemorySSHKeyDB({'alice': ['a', 'b']})
- self.assertEqual(['a', 'b'], list(keydb.getAuthorizedKeys('alice')))
+ keydb = checkers.InMemorySSHKeyDB({b'alice': [b'a', b'b']})
+ self.assertEqual([b'a', b'b'], list(keydb.getAuthorizedKeys(b'alice')))
@@ -724,15 +707,15 @@
mockos.path.makedirs()
self.userdb = UserDatabase()
- self.userdb.addUser('alice', 'password', 1, 2, 'alice lastname',
- mockos.path.path, '/bin/shell')
+ self.userdb.addUser(b'alice', b'password', 1, 2, b'alice lastname',
+ mockos.path.path, b'/bin/shell')
self.sshDir = mockos.path.child('.ssh')
self.sshDir.makedirs()
authorizedKeys = self.sshDir.child('authorized_keys')
- authorizedKeys.setContent('key 1\nkey 2')
+ authorizedKeys.setContent(b'key 1\nkey 2')
- self.expectedKeys = ['key 1', 'key 2']
+ self.expectedKeys = [b'key 1', b'key 2']
def test_implementsInterface(self):
@@ -762,11 +745,11 @@
C{~/.ssh/authorized_keys} and C{~/.ssh/authorized_keys2} is returned
by L{checkers.UNIXAuthorizedKeysFiles.getAuthorizedKeys}.
"""
- self.sshDir.child('authorized_keys2').setContent('key 3')
+ self.sshDir.child('authorized_keys2').setContent(b'key 3')
keydb = checkers.UNIXAuthorizedKeysFiles(self.userdb,
parseKey=lambda x: x)
- self.assertEqual(self.expectedKeys + ['key 3'],
- list(keydb.getAuthorizedKeys('alice')))
+ self.assertEqual(self.expectedKeys + [b'key 3'],
+ list(keydb.getAuthorizedKeys(b'alice')))
def test_ignoresNonexistantFile(self):
@@ -778,7 +761,7 @@
keydb = checkers.UNIXAuthorizedKeysFiles(self.userdb,
parseKey=lambda x: x)
self.assertEqual(self.expectedKeys,
- list(keydb.getAuthorizedKeys('alice')))
+ list(keydb.getAuthorizedKeys(b'alice')))
def test_ignoresUnreadableFile(self):
@@ -791,7 +774,7 @@
keydb = checkers.UNIXAuthorizedKeysFiles(self.userdb,
parseKey=lambda x: x)
self.assertEqual(self.expectedKeys,
- list(keydb.getAuthorizedKeys('alice')))
+ list(keydb.getAuthorizedKeys(b'alice')))
@@ -816,8 +799,8 @@
def setUp(self):
self.credentials = SSHPrivateKey(
- 'alice', 'ssh-rsa', keydata.publicRSA_openssh, 'foo',
- keys.Key.fromString(keydata.privateRSA_openssh).sign('foo'))
+ b'alice', b'ssh-rsa', keydata.publicRSA_openssh, b'foo',
+ keys.Key.fromString(keydata.privateRSA_openssh).sign(b'foo'))
self.keydb = _KeyDB(lambda _: [
keys.Key.fromString(keydata.publicRSA_openssh)])
self.checker = checkers.SSHPublicKeyChecker(self.keydb)
@@ -838,7 +821,7 @@
Calling L{checkers.SSHPublicKeyChecker.requestAvatarId} with
credentials that have a bad key fails with L{keys.BadKeyError}.
"""
- self.credentials.blob = ''
+ self.credentials.blob = b''
self.failureResultOf(self.checker.requestAvatarId(self.credentials),
keys.BadKeyError)
@@ -862,7 +845,7 @@
L{UnauthorizedLogin}.
"""
self.credentials.signature = (
- keys.Key.fromString(keydata.privateDSA_openssh).sign('foo'))
+ keys.Key.fromString(keydata.privateDSA_openssh).sign(b'foo'))
self.failureResultOf(self.checker.requestAvatarId(self.credentials),
UnauthorizedLogin)
@@ -889,4 +872,4 @@
callbacks with the username.
"""
d = self.checker.requestAvatarId(self.credentials)
- self.assertEqual('alice', self.successResultOf(d))
+ self.assertEqual(b'alice', self.successResultOf(d))
Modified: trunk/twisted/python/compat.py
==============================================================================
--- trunk/twisted/python/compat.py (original)
+++ trunk/twisted/python/compat.py Thu Mar 3 23:41:01 2016
@@ -612,6 +612,18 @@
@rtype: L{list}
"""
+def _keys(d):
+ """
+ Return a list of the keys of C{d}.
+
+ @type d: L{dict}
+ @rtype: L{list}
+ """
+ if _PY3:
+ return list(d.keys())
+ else:
+ return d.keys()
+
def bytesEnviron():
@@ -665,6 +677,12 @@
"twisted.python.compat",
"OrderedDict")
+if _PY3:
+ from base64 import encodebytes as _b64encodebytes
+ from base64 import decodebytes as _b64decodebytes
+else:
+ from base64 import encodestring as _b64encodebytes
+ from base64 import decodestring as _b64decodebytes
__all__ = [
@@ -696,4 +714,7 @@
"urlquote",
"urlunquote",
"cookielib",
+ "_keys",
+ "_b64encodebytes",
+ "_b64decodebytes",
]
Modified: trunk/twisted/python/dist3.py
==============================================================================
--- trunk/twisted/python/dist3.py (original)
+++ trunk/twisted/python/dist3.py Thu Mar 3 23:41:01 2016
@@ -47,6 +47,8 @@
"twisted.application.strports",
"twisted.application.test",
"twisted.conch",
+ "twisted.conch.checkers",
+ "twisted.conch.error",
"twisted.conch.ssh",
"twisted.conch.ssh._cryptography_backports",
"twisted.conch.ssh.common",
@@ -161,6 +163,7 @@
"twisted.python.deprecate",
"twisted.python.dist3",
"twisted.python.failure",
+ "twisted.python.fakepwd",
"twisted.python.filepath",
"twisted.python.lockfile",
"twisted.python.log",
@@ -249,6 +252,7 @@
"twisted.application.test.test_internet",
"twisted.application.test.test_service",
"twisted.conch.test.test_keys",
+ "twisted.conch.test.test_checkers",
"twisted.cred.test.test_cramauth",
"twisted.cred.test.test_cred",
"twisted.cred.test.test_digestauth",
@@ -466,9 +470,6 @@
"twisted.names.root",
# Echo is ported for twisted.application tests:
"twisted.protocols.wire",
- # Required by twisted.test.test_twistd
- # https://twistedmatrix.com/trac/ticket/7958
- "twisted.python.fakepwd",
# Missing test coverage:
"twisted.protocols.loopback",
# Minimally used by setup3.py: