Changeset fdd7ec6 in trunk
- Timestamp:
- 2021-10-26T13:13:11Z (4 years ago)
- Branches:
- master
- Children:
- f02f14a
- Parents:
- aa6360f (diff), 5b9997f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Jean-Paul Calderone <exarkun@…> (2021-10-26 13:13:11)
- git-committer:
- GitHub <noreply@…> (2021-10-26 13:13:11)
- Files:
-
- 1 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified docs/frontends/FTP-and-SFTP.rst ¶
raa6360f rfdd7ec6 48 48 might grant a particular user), and second to decide what directory cap 49 49 should be used as the root directory for a log-in by the authenticated user. 50 A username and password can be used; as of Tahoe-LAFS v1.11, RSA or DSA51 public key authentication is also supported.50 As of Tahoe-LAFS v1.17, 51 RSA/DSA public key authentication is the only supported mechanism. 52 52 53 53 Tahoe-LAFS provides two mechanisms to perform this user-to-cap mapping. … … 60 60 To use the first form, create a file (for example ``BASEDIR/private/accounts``) 61 61 in which each non-comment/non-blank line is a space-separated line of 62 (USERNAME, PASSWORD, ROOTCAP), like so::62 (USERNAME, KEY-TYPE, PUBLIC-KEY, ROOTCAP), like so:: 63 63 64 64 % cat BASEDIR/private/accounts 65 # This is a password line: username password cap66 alice password URI:DIR2:ioej8xmzrwilg772gzj4fhdg7a:wtiizszzz2rgmczv4wl6bqvbv33ag4kvbr6prz3u6w3geixa6m6a67 bob sekrit URI:DIR2:6bdmeitystckbl9yqlw7g56f4e:serp5ioqxnh34mlbmzwvkp3odehsyrr7eytt5f64we3k9hhcrcja68 69 65 # This is a public key line: username keytype pubkey cap 70 66 # (Tahoe-LAFS v1.11 or later) 71 67 carol ssh-rsa AAAA... URI:DIR2:ovjy4yhylqlfoqg2vcze36dhde:4d4f47qko2xm5g7osgo2yyidi5m4muyo2vjjy53q4vjju2u55mfa 72 68 73 For public key authentication, the keytype may be either "ssh-rsa" or "ssh-dsa". 74 To avoid ambiguity between passwords and public key types, a password cannot 75 start with "ssh-". 69 The key type may be either "ssh-rsa" or "ssh-dsa". 76 70 77 71 Now add an ``accounts.file`` directive to your ``tahoe.cfg`` file, as described in -
TabularUnified integration/conftest.py ¶
raa6360f rfdd7ec6 354 354 return nodes 355 355 356 @pytest.fixture(scope="session") 357 def alice_sftp_client_key_path(temp_dir): 358 # The client SSH key path is typically going to be somewhere else (~/.ssh, 359 # typically), but for convenience sake for testing we'll put it inside node. 360 return join(temp_dir, "alice", "private", "ssh_client_rsa_key") 356 361 357 362 @pytest.fixture(scope='session') 358 363 @log_call(action_type=u"integration:alice", include_args=[], include_result=False) 359 def alice(reactor, temp_dir, introducer_furl, flog_gatherer, storage_nodes, request): 364 def alice( 365 reactor, 366 temp_dir, 367 introducer_furl, 368 flog_gatherer, 369 storage_nodes, 370 alice_sftp_client_key_path, 371 request, 372 ): 360 373 process = pytest_twisted.blockon( 361 374 _create_node( … … 388 401 generate_ssh_key(host_ssh_key_path) 389 402 390 # 3. Add a SFTP access file with username/password and SSH key auth. 391 392 # The client SSH key path is typically going to be somewhere else (~/.ssh, 393 # typically), but for convenience sake for testing we'll put it inside node. 394 client_ssh_key_path = join(process.node_dir, "private", "ssh_client_rsa_key") 395 generate_ssh_key(client_ssh_key_path) 403 # 3. Add a SFTP access file with an SSH key for auth. 404 generate_ssh_key(alice_sftp_client_key_path) 396 405 # Pub key format is "ssh-rsa <thekey> <username>". We want the key. 397 ssh_public_key = open( client_ssh_key_path + ".pub").read().strip().split()[1]406 ssh_public_key = open(alice_sftp_client_key_path + ".pub").read().strip().split()[1] 398 407 with open(accounts_path, "w") as f: 399 408 f.write("""\ 400 alice password {rwcap} 401 402 alice2 ssh-rsa {ssh_public_key} {rwcap} 409 alice-key ssh-rsa {ssh_public_key} {rwcap} 403 410 """.format(rwcap=rwcap, ssh_public_key=ssh_public_key)) 404 411 -
TabularUnified integration/test_sftp.py ¶
raa6360f rfdd7ec6 20 20 from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401 21 21 22 import os.path 22 23 from posixpath import join 23 24 from stat import S_ISDIR … … 34 35 35 36 36 def connect_sftp(connect_args ={"username": "alice", "password": "password"}):37 def connect_sftp(connect_args): 37 38 """Create an SFTP client.""" 38 39 client = SSHClient() … … 61 62 def test_bad_account_password_ssh_key(alice, tmpdir): 62 63 """ 63 Can't login with unknown username, wrongpassword, or wrong SSH pub key.64 Can't login with unknown username, any password, or wrong SSH pub key. 64 65 """ 65 # Wrongpassword, wrong username:66 for u, p in [("alice ", "wrong"), ("someuser", "password")]:66 # Any password, wrong username: 67 for u, p in [("alice-key", "wrong"), ("someuser", "password")]: 67 68 with pytest.raises(AuthenticationException): 68 69 connect_sftp(connect_args={ … … 70 71 }) 71 72 72 another_key = join(str(tmpdir), "ssh_key")73 another_key = os.path.join(str(tmpdir), "ssh_key") 73 74 generate_ssh_key(another_key) 74 good_key = RSAKey(filename= join(alice.node_dir, "private", "ssh_client_rsa_key"))75 good_key = RSAKey(filename=os.path.join(alice.node_dir, "private", "ssh_client_rsa_key")) 75 76 bad_key = RSAKey(filename=another_key) 76 77 … … 78 79 with pytest.raises(AuthenticationException): 79 80 connect_sftp(connect_args={ 80 "username": "alice 2", "pkey": bad_key,81 "username": "alice-key", "pkey": bad_key, 81 82 }) 82 83 … … 87 88 }) 88 89 90 def sftp_client_key(node): 91 return RSAKey( 92 filename=os.path.join(node.node_dir, "private", "ssh_client_rsa_key"), 93 ) 94 95 def test_sftp_client_key_exists(alice, alice_sftp_client_key_path): 96 """ 97 Weakly validate the sftp client key fixture by asserting that *something* 98 exists at the supposed key path. 99 """ 100 assert os.path.exists(alice_sftp_client_key_path) 89 101 90 102 @run_in_thread 91 103 def test_ssh_key_auth(alice): 92 104 """It's possible to login authenticating with SSH public key.""" 93 key = RSAKey(filename=join(alice.node_dir, "private", "ssh_client_rsa_key"))105 key = sftp_client_key(alice) 94 106 sftp = connect_sftp(connect_args={ 95 "username": "alice 2", "pkey": key107 "username": "alice-key", "pkey": key 96 108 }) 97 109 assert sftp.listdir() == [] … … 101 113 def test_read_write_files(alice): 102 114 """It's possible to upload and download files.""" 103 sftp = connect_sftp() 115 sftp = connect_sftp(connect_args={ 116 "username": "alice-key", 117 "pkey": sftp_client_key(alice), 118 }) 104 119 with sftp.file("myfile", "wb") as f: 105 120 f.write(b"abc") … … 118 133 them. 119 134 """ 120 sftp = connect_sftp() 135 sftp = connect_sftp(connect_args={ 136 "username": "alice-key", 137 "pkey": sftp_client_key(alice), 138 }) 121 139 assert sftp.listdir() == [] 122 140 … … 149 167 def test_rename(alice): 150 168 """Directories and files can be renamed.""" 151 sftp = connect_sftp() 169 sftp = connect_sftp(connect_args={ 170 "username": "alice-key", 171 "pkey": sftp_client_key(alice), 172 }) 152 173 sftp.mkdir("dir") 153 174 -
TabularUnified src/allmydata/frontends/auth.py ¶
raa6360f rfdd7ec6 13 13 from zope.interface import implementer 14 14 from twisted.internet import defer 15 from twisted.cred import error,checkers, credentials15 from twisted.cred import checkers, credentials 16 16 from twisted.conch.ssh import keys 17 17 from twisted.conch.checkers import SSHPublicKeyChecker, InMemorySSHKeyDB … … 33 33 @implementer(checkers.ICredentialsChecker) 34 34 class AccountFileChecker(object): 35 credentialInterfaces = (credentials.IUsernamePassword, 36 credentials.IUsernameHashedPassword, 37 credentials.ISSHPrivateKey) 35 credentialInterfaces = (credentials.ISSHPrivateKey,) 36 38 37 def __init__(self, client, accountfile): 39 38 self.client = client 40 self.passwords = BytesKeyDict() 41 pubkeys = BytesKeyDict() 42 self.rootcaps = BytesKeyDict() 43 with open(abspath_expanduser_unicode(accountfile), "rb") as f: 44 for line in f: 45 line = line.strip() 46 if line.startswith(b"#") or not line: 47 continue 48 name, passwd, rest = line.split(None, 2) 49 if passwd.startswith(b"ssh-"): 50 bits = rest.split() 51 keystring = b" ".join([passwd] + bits[:-1]) 52 key = keys.Key.fromString(keystring) 53 rootcap = bits[-1] 54 pubkeys[name] = [key] 55 else: 56 self.passwords[name] = passwd 57 rootcap = rest 58 self.rootcaps[name] = rootcap 39 path = abspath_expanduser_unicode(accountfile) 40 with open_account_file(path) as f: 41 self.rootcaps, pubkeys = load_account_file(f) 59 42 self._pubkeychecker = SSHPublicKeyChecker(InMemorySSHKeyDB(pubkeys)) 60 43 61 44 def _avatarId(self, username): 62 45 return FTPAvatarID(username, self.rootcaps[username]) 63 64 def _cbPasswordMatch(self, matched, username):65 if matched:66 return self._avatarId(username)67 raise error.UnauthorizedLogin68 46 69 47 def requestAvatarId(self, creds): … … 72 50 d.addCallback(self._avatarId) 73 51 return d 74 elif credentials.IUsernameHashedPassword.providedBy(creds): 75 return self._checkPassword(creds) 76 elif credentials.IUsernamePassword.providedBy(creds): 77 return self._checkPassword(creds) 78 else: 79 raise NotImplementedError() 52 raise NotImplementedError() 80 53 81 def _checkPassword(self, creds): 82 """ 83 Determine whether the password in the given credentials matches the 84 password in the account file. 54 def open_account_file(path): 55 """ 56 Open and return the accounts file at the given path. 57 """ 58 return open(path, "rt", encoding="utf-8") 85 59 86 Returns a Deferred that fires with the username if the password matches 87 or with an UnauthorizedLogin failure otherwise. 88 """ 89 try: 90 correct = self.passwords[creds.username] 91 except KeyError: 92 return defer.fail(error.UnauthorizedLogin()) 60 def load_account_file(lines): 61 """ 62 Load credentials from an account file. 93 63 94 d = defer.maybeDeferred(creds.checkPassword, correct) 95 d.addCallback(self._cbPasswordMatch, creds.username) 96 return d 64 :param lines: An iterable of account lines to load. 65 66 :return: See ``create_account_maps``. 67 """ 68 return create_account_maps( 69 parse_accounts( 70 content_lines( 71 lines, 72 ), 73 ), 74 ) 75 76 def content_lines(lines): 77 """ 78 Drop empty and commented-out lines (``#``-prefixed) from an iterator of 79 lines. 80 81 :param lines: An iterator of lines to process. 82 83 :return: An iterator of lines including only those from ``lines`` that 84 include content intended to be loaded. 85 """ 86 for line in lines: 87 line = line.strip() 88 if line and not line.startswith("#"): 89 yield line 90 91 def parse_accounts(lines): 92 """ 93 Parse account lines into their components (name, key, rootcap). 94 """ 95 for line in lines: 96 name, passwd, rest = line.split(None, 2) 97 if not passwd.startswith("ssh-"): 98 raise ValueError( 99 "Password-based authentication is not supported; " 100 "configure key-based authentication instead." 101 ) 102 103 bits = rest.split() 104 keystring = " ".join([passwd] + bits[:-1]) 105 key = keys.Key.fromString(keystring) 106 rootcap = bits[-1] 107 yield (name, key, rootcap) 108 109 def create_account_maps(accounts): 110 """ 111 Build mappings from account names to keys and rootcaps. 112 113 :param accounts: An iterator if (name, key, rootcap) tuples. 114 115 :return: A tuple of two dicts. The first maps account names to rootcaps. 116 The second maps account names to public keys. 117 """ 118 rootcaps = BytesKeyDict() 119 pubkeys = BytesKeyDict() 120 for (name, key, rootcap) in accounts: 121 name_bytes = name.encode("utf-8") 122 rootcaps[name_bytes] = rootcap.encode("utf-8") 123 pubkeys[name_bytes] = [key] 124 return rootcaps, pubkeys -
TabularUnified src/allmydata/test/test_auth.py ¶
raa6360f rfdd7ec6 9 9 from future.utils import PY2 10 10 if PY2: 11 from future.builtins import str # noqa: F401 11 from future.builtins import str, open # noqa: F401 12 13 from hypothesis import ( 14 given, 15 ) 16 from hypothesis.strategies import ( 17 text, 18 characters, 19 lists, 20 ) 12 21 13 22 from twisted.trial import unittest … … 39 48 """) 40 49 41 DUMMY_ACCOUNTS = u"""\ 42 alice herpassword URI:DIR2:aaaaaaaaaaaaaaaaaaaaaaaaaa:1111111111111111111111111111111111111111111111111111 43 bob sekrit URI:DIR2:bbbbbbbbbbbbbbbbbbbbbbbbbb:2222222222222222222222222222222222222222222222222222 44 45 # dennis password URI:DIR2:aaaaaaaaaaaaaaaaaaaaaaaaaa:1111111111111111111111111111111111111111111111111111 50 DUMMY_KEY_DSA = keys.Key.fromString("""\ 51 -----BEGIN OPENSSH PRIVATE KEY----- 52 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH 53 NzAAAAgQDKMh/ELaiP21LYRBuPbUy7dUhv/XZwV7aS1LzxSP+KaJvtDOei8X76XEAfkqX+ 54 aGh9eup+BLkezrV6LlpO9uPzhY8ChlKpkvw5PZKv/2agSrVxZyG7yEzHNtSBQXE6qNMwIk 55 N/ycXLGCqyAhQSzRhLz9ETNaslRDLo7YyVWkiuAQAAABUA5nTatFKux5EqZS4EarMWFRBU 56 i1UAAACAFpkkK+JsPixSTPyn0DNMoGKA0Klqy8h61Ds6pws+4+aJQptUBshpwNw1ypo7MO 57 +goDZy3wwdWtURTPGMgesNdEfxp8L2/kqE4vpMK0myoczCqOiWMeNB/x1AStbSkBI8WmHW 58 2htgsC01xbaix/FrA3edK8WEyv+oIxlbV1FkrPkAAACANb0EpCc8uoR4/32rO2JLsbcLBw 59 H5wc2khe7AKkIa9kUknRIRvoCZUtXF5XuXXdRmnpVEm2KcsLdtZjip43asQcqgt0Kz3nuF 60 kAf7bI98G1waFUimcCSPsal4kCmW2HC11sg/BWOt5qczX/0/3xVxpo6juUeBq9ncnFTvPX 61 5fOlEAAAHoJkFqHiZBah4AAAAHc3NoLWRzcwAAAIEAyjIfxC2oj9tS2EQbj21Mu3VIb/12 62 cFe2ktS88Uj/imib7QznovF++lxAH5Kl/mhofXrqfgS5Hs61ei5aTvbj84WPAoZSqZL8OT 63 2Sr/9moEq1cWchu8hMxzbUgUFxOqjTMCJDf8nFyxgqsgIUEs0YS8/REzWrJUQy6O2MlVpI 64 rgEAAAAVAOZ02rRSrseRKmUuBGqzFhUQVItVAAAAgBaZJCvibD4sUkz8p9AzTKBigNCpas 65 vIetQ7OqcLPuPmiUKbVAbIacDcNcqaOzDvoKA2ct8MHVrVEUzxjIHrDXRH8afC9v5KhOL6 66 TCtJsqHMwqjoljHjQf8dQErW0pASPFph1tobYLAtNcW2osfxawN3nSvFhMr/qCMZW1dRZK 67 z5AAAAgDW9BKQnPLqEeP99qztiS7G3CwcB+cHNpIXuwCpCGvZFJJ0SEb6AmVLVxeV7l13U 68 Zp6VRJtinLC3bWY4qeN2rEHKoLdCs957hZAH+2yPfBtcGhVIpnAkj7GpeJAplthwtdbIPw 69 VjreanM1/9P98VcaaOo7lHgavZ3JxU7z1+XzpRAAAAFQC7360pZLbv7PFt4BPFJ8zAHxAe 70 QwAAAA5leGFya3VuQGJhcnlvbgECAwQ= 71 -----END OPENSSH PRIVATE KEY----- 72 """) 73 74 ACCOUNTS = u"""\ 75 # dennis {key} URI:DIR2:aaaaaaaaaaaaaaaaaaaaaaaaaa:1111111111111111111111111111111111111111111111111111 46 76 carol {key} URI:DIR2:cccccccccccccccccccccccccc:3333333333333333333333333333333333333333333333333333 47 77 """.format(key=str(DUMMY_KEY.public().toString("openssh"), "ascii")).encode("ascii") 48 78 79 # Python str.splitlines considers NEXT LINE, LINE SEPARATOR, and PARAGRAPH 80 # separator to be line separators, too. However, file.readlines() does not... 81 LINE_SEPARATORS = ( 82 '\x0a', # line feed 83 '\x0b', # vertical tab 84 '\x0c', # form feed 85 '\x0d', # carriage return 86 ) 87 88 class AccountFileParserTests(unittest.TestCase): 89 """ 90 Tests for ``load_account_file`` and its helper functions. 91 """ 92 @given(lists( 93 text(alphabet=characters( 94 blacklist_categories=( 95 # Surrogates are an encoding trick to help out UTF-16. 96 # They're not necessary to represent any non-surrogate code 97 # point in unicode. They're also not legal individually but 98 # only in pairs. 99 'Cs', 100 ), 101 # Exclude all our line separators too. 102 blacklist_characters=("\n", "\r"), 103 )), 104 )) 105 def test_ignore_comments(self, lines): 106 """ 107 ``auth.content_lines`` filters out lines beginning with `#` and empty 108 lines. 109 """ 110 expected = set() 111 112 # It's not clear that real files and StringIO behave sufficiently 113 # similarly to use the latter instead of the former here. In 114 # particular, they seem to have distinct and incompatible 115 # line-splitting rules. 116 bufpath = self.mktemp() 117 with open(bufpath, "wt", encoding="utf-8") as buf: 118 for line in lines: 119 stripped = line.strip() 120 is_content = stripped and not stripped.startswith("#") 121 if is_content: 122 expected.add(stripped) 123 buf.write(line + "\n") 124 125 with auth.open_account_file(bufpath) as buf: 126 actual = set(auth.content_lines(buf)) 127 128 self.assertEqual(expected, actual) 129 130 def test_parse_accounts(self): 131 """ 132 ``auth.parse_accounts`` accepts an iterator of account lines and returns 133 an iterator of structured account data. 134 """ 135 alice_key = DUMMY_KEY.public().toString("openssh").decode("utf-8") 136 alice_cap = "URI:DIR2:aaaa:1111" 137 138 bob_key = DUMMY_KEY_DSA.public().toString("openssh").decode("utf-8") 139 bob_cap = "URI:DIR2:aaaa:2222" 140 self.assertEqual( 141 list(auth.parse_accounts([ 142 "alice {} {}".format(alice_key, alice_cap), 143 "bob {} {}".format(bob_key, bob_cap), 144 ])), 145 [ 146 ("alice", DUMMY_KEY.public(), alice_cap), 147 ("bob", DUMMY_KEY_DSA.public(), bob_cap), 148 ], 149 ) 150 151 def test_parse_accounts_rejects_passwords(self): 152 """ 153 The iterator returned by ``auth.parse_accounts`` raises ``ValueError`` 154 when processing reaches a line that has what looks like a password 155 instead of an ssh key. 156 """ 157 with self.assertRaises(ValueError): 158 list(auth.parse_accounts(["alice apassword URI:DIR2:aaaa:1111"])) 159 160 def test_create_account_maps(self): 161 """ 162 ``auth.create_account_maps`` accepts an iterator of structured account 163 data and returns two mappings: one from account name to rootcap, the 164 other from account name to public keys. 165 """ 166 alice_cap = "URI:DIR2:aaaa:1111" 167 alice_key = DUMMY_KEY.public() 168 bob_cap = "URI:DIR2:aaaa:2222" 169 bob_key = DUMMY_KEY_DSA.public() 170 accounts = [ 171 ("alice", alice_key, alice_cap), 172 ("bob", bob_key, bob_cap), 173 ] 174 self.assertEqual( 175 auth.create_account_maps(accounts), 176 ({ 177 b"alice": alice_cap.encode("utf-8"), 178 b"bob": bob_cap.encode("utf-8"), 179 }, 180 { 181 b"alice": [alice_key], 182 b"bob": [bob_key], 183 }), 184 ) 185 186 def test_load_account_file(self): 187 """ 188 ``auth.load_account_file`` accepts an iterator of serialized account lines 189 and returns two mappings: one from account name to rootcap, the other 190 from account name to public keys. 191 """ 192 alice_key = DUMMY_KEY.public().toString("openssh").decode("utf-8") 193 alice_cap = "URI:DIR2:aaaa:1111" 194 195 bob_key = DUMMY_KEY_DSA.public().toString("openssh").decode("utf-8") 196 bob_cap = "URI:DIR2:aaaa:2222" 197 198 accounts = [ 199 "alice {} {}".format(alice_key, alice_cap), 200 "bob {} {}".format(bob_key, bob_cap), 201 "# carol {} {}".format(alice_key, alice_cap), 202 ] 203 204 self.assertEqual( 205 auth.load_account_file(accounts), 206 ({ 207 b"alice": alice_cap.encode("utf-8"), 208 b"bob": bob_cap.encode("utf-8"), 209 }, 210 { 211 b"alice": [DUMMY_KEY.public()], 212 b"bob": [DUMMY_KEY_DSA.public()], 213 }), 214 ) 215 216 49 217 class AccountFileCheckerKeyTests(unittest.TestCase): 50 218 """ … … 53 221 def setUp(self): 54 222 self.account_file = filepath.FilePath(self.mktemp()) 55 self.account_file.setContent( DUMMY_ACCOUNTS)223 self.account_file.setContent(ACCOUNTS) 56 224 abspath = abspath_expanduser_unicode(str(self.account_file.path)) 57 225 self.checker = auth.AccountFileChecker(None, abspath) 58 226 59 def test_unknown_user _ssh(self):227 def test_unknown_user(self): 60 228 """ 61 229 AccountFileChecker.requestAvatarId returns a Deferred that fires with … … 65 233 key_credentials = credentials.SSHPrivateKey( 66 234 b"dennis", b"md5", None, None, None) 67 avatarId = self.checker.requestAvatarId(key_credentials)68 return self.assertFailure(avatarId, error.UnauthorizedLogin)69 70 def test_unknown_user_password(self):71 """72 AccountFileChecker.requestAvatarId returns a Deferred that fires with73 UnauthorizedLogin if called with an SSHPrivateKey object with a74 username not present in the account file.75 76 We use a commented out user, so we're also checking that comments are77 skipped.78 """79 key_credentials = credentials.UsernamePassword(b"dennis", b"password")80 d = self.checker.requestAvatarId(key_credentials)81 return self.assertFailure(d, error.UnauthorizedLogin)82 83 def test_password_auth_user_with_ssh_key(self):84 """85 AccountFileChecker.requestAvatarId returns a Deferred that fires with86 UnauthorizedLogin if called with an SSHPrivateKey object for a username87 only associated with a password in the account file.88 """89 key_credentials = credentials.SSHPrivateKey(90 b"alice", b"md5", None, None, None)91 avatarId = self.checker.requestAvatarId(key_credentials)92 return self.assertFailure(avatarId, error.UnauthorizedLogin)93 94 def test_password_auth_user_with_correct_password(self):95 """96 AccountFileChecker.requestAvatarId returns a Deferred that fires with97 the user if the correct password is given.98 """99 key_credentials = credentials.UsernamePassword(b"alice", b"herpassword")100 d = self.checker.requestAvatarId(key_credentials)101 def authenticated(avatarId):102 self.assertEqual(103 (b"alice",104 b"URI:DIR2:aaaaaaaaaaaaaaaaaaaaaaaaaa:1111111111111111111111111111111111111111111111111111"),105 (avatarId.username, avatarId.rootcap))106 return d107 108 def test_password_auth_user_with_correct_hashed_password(self):109 """110 AccountFileChecker.requestAvatarId returns a Deferred that fires with111 the user if the correct password is given in hashed form.112 """113 key_credentials = credentials.UsernameHashedPassword(b"alice", b"herpassword")114 d = self.checker.requestAvatarId(key_credentials)115 def authenticated(avatarId):116 self.assertEqual(117 (b"alice",118 b"URI:DIR2:aaaaaaaaaaaaaaaaaaaaaaaaaa:1111111111111111111111111111111111111111111111111111"),119 (avatarId.username, avatarId.rootcap))120 return d121 122 def test_password_auth_user_with_wrong_password(self):123 """124 AccountFileChecker.requestAvatarId returns a Deferred that fires with125 UnauthorizedLogin if the wrong password is given.126 """127 key_credentials = credentials.UsernamePassword(b"alice", b"WRONG")128 235 avatarId = self.checker.requestAvatarId(key_credentials) 129 236 return self.assertFailure(avatarId, error.UnauthorizedLogin)
Note: See TracChangeset
for help on using the changeset viewer.