2015-01-04 13:02:23 +00:00
|
|
|
from twisted.trial import unittest
|
|
|
|
from twisted.python import filepath
|
|
|
|
from twisted.cred import error, credentials
|
2015-01-04 14:44:56 +00:00
|
|
|
from twisted.conch import error as conch_error
|
2015-01-04 13:02:23 +00:00
|
|
|
from twisted.conch.ssh import keys
|
|
|
|
|
|
|
|
from allmydata.frontends import auth
|
|
|
|
|
|
|
|
DUMMY_KEY = keys.Key.fromString("""\
|
|
|
|
-----BEGIN RSA PRIVATE KEY-----
|
|
|
|
MIICXQIBAAKBgQDEP3DYiukOu+NrUlBZeLL9JoHkK5nSvINYfeOQWYVW9J5NG485
|
|
|
|
pZFVUQKzvvht34Ihj4ucrrvj7vOp+FFvzxI+zHKBpDxyJwV96dvWDAZMjxTxL7iV
|
|
|
|
8HcO7hqgtQ/Xk1Kjde5lH3EOEDs3IhFHA+sox9y6i4A5NUr2AJZSHiOEVwIDAQAB
|
|
|
|
AoGASrrNwefDr7SkeS2zIx7vKa8ML1LbFIBsk7n8ee9c8yvbTAl+lLkTiqV6ne/O
|
|
|
|
sig2aYk75MI1Eirf5o2ElUsI6u36i6AeKL2u/W7tLBVijmBB8dTiWZ5gMOARWt8w
|
|
|
|
daF2An2826YdcU+iNZ7Yi0q4xtlxHQn3JcNNWxicphLvt0ECQQDtajJ/bK+Nqd9j
|
|
|
|
/WGvqYcMzkkorQq/0+MQYhcIwDlpf2Xoi45tP4HeoBubeJmU5+jXpXmdP5epWpBv
|
|
|
|
k3ZCwV7pAkEA05xBP2HTdwRFTJov5I/w7uKOrn7mj7DCvSjQFCufyPOoCJJMeBSq
|
|
|
|
tfCQlHFtwlkyNfiSbhtgZ0Pp6ovL+1RBPwJBAOlFRBKxrpgpxcXQK5BWqMwrT/S4
|
|
|
|
eWxb+6mYR3ugq4h91Zq0rJ+pG6irdhS/XV/SsZRZEXIxDoom4u3OXQ9gQikCQErM
|
|
|
|
ywuaiuNhMRXY0uEaOHJYx1LLLLjSJKQ0zwiyOvMPnfAZtsojlAxoEtNGHSQ731HQ
|
|
|
|
ogIlzzfxe7ga3mni6IUCQQCwNK9zwARovcQ8nByqotGQzohpl+1b568+iw8GXP2u
|
|
|
|
dBSD8940XU3YW+oeq8e+p3yQ2GinHfeJ3BYQyNQLuMAJ
|
|
|
|
-----END RSA PRIVATE KEY-----
|
|
|
|
""")
|
|
|
|
|
|
|
|
DUMMY_ACCOUNTS = u"""\
|
|
|
|
alice password URI:DIR2:aaaaaaaaaaaaaaaaaaaaaaaaaa:1111111111111111111111111111111111111111111111111111
|
|
|
|
bob sekrit URI:DIR2:bbbbbbbbbbbbbbbbbbbbbbbbbb:2222222222222222222222222222222222222222222222222222
|
2015-01-04 14:44:56 +00:00
|
|
|
carol {key} URI:DIR2:cccccccccccccccccccccccccc:3333333333333333333333333333333333333333333333333333
|
|
|
|
""".format(key=DUMMY_KEY.public().toString("openssh")).encode("ascii")
|
2015-01-04 13:02:23 +00:00
|
|
|
|
|
|
|
class AccountFileCheckerKeyTests(unittest.TestCase):
|
|
|
|
"""
|
|
|
|
Tests for key handling done by allmydata.frontends.auth.AccountFileChecker.
|
|
|
|
"""
|
|
|
|
def setUp(self):
|
|
|
|
self.account_file = filepath.FilePath(self.mktemp())
|
|
|
|
self.account_file.setContent(DUMMY_ACCOUNTS)
|
|
|
|
self.checker = auth.AccountFileChecker(None, self.account_file.path)
|
|
|
|
|
|
|
|
def test_unknown_user(self):
|
|
|
|
"""
|
|
|
|
AccountFileChecker.requestAvatarId returns a Deferred that fires with
|
|
|
|
UnauthorizedLogin if called with an SSHPrivateKey object with a
|
|
|
|
username not present in the account file.
|
|
|
|
"""
|
|
|
|
key_credentials = credentials.SSHPrivateKey(
|
|
|
|
b"dennis", b"md5", None, None, None)
|
|
|
|
avatarId = self.checker.requestAvatarId(key_credentials)
|
|
|
|
return self.assertFailure(avatarId, error.UnauthorizedLogin)
|
2015-01-04 13:02:49 +00:00
|
|
|
|
2015-01-04 14:44:56 +00:00
|
|
|
def test_password_auth_user(self):
|
|
|
|
"""
|
|
|
|
AccountFileChecker.requestAvatarId returns a Deferred that fires with
|
|
|
|
UnauthorizedLogin if called with an SSHPrivateKey object for a username
|
|
|
|
only associated with a password in the account file.
|
|
|
|
"""
|
|
|
|
key_credentials = credentials.SSHPrivateKey(
|
|
|
|
b"alice", b"md5", None, None, None)
|
|
|
|
avatarId = self.checker.requestAvatarId(key_credentials)
|
|
|
|
return self.assertFailure(avatarId, error.UnauthorizedLogin)
|
|
|
|
|
2015-01-04 13:02:49 +00:00
|
|
|
def test_unrecognized_key(self):
|
|
|
|
"""
|
|
|
|
AccountFileChecker.requestAvatarId returns a Deferred that fires with
|
|
|
|
UnauthorizedLogin if called with an SSHPrivateKey object with a public
|
|
|
|
key other than the one indicated in the account file for the indicated
|
|
|
|
user.
|
|
|
|
"""
|
|
|
|
wrong_key_blob = b"""\
|
|
|
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQDJGMWlPXh2M3pYzTiamjcBIMqctt4VvLVW2QZgEFc86XhGjPXq5QAiRTKv9yVZJR9HW70CfBI7GHun8+v4Wb6aicWBoxgI3OB5NN+OUywdme2HSaif5yenFdQr0ME71Xs=
|
|
|
|
"""
|
|
|
|
key_credentials = credentials.SSHPrivateKey(
|
|
|
|
b"carol", b"md5", wrong_key_blob, None, None)
|
|
|
|
avatarId = self.checker.requestAvatarId(key_credentials)
|
|
|
|
return self.assertFailure(avatarId, error.UnauthorizedLogin)
|
2015-01-04 14:44:56 +00:00
|
|
|
|
|
|
|
def test_missing_signature(self):
|
|
|
|
"""
|
|
|
|
AccountFileChecker.requestAvatarId returns a Deferred that fires with
|
|
|
|
ValidPublicKey if called with an SSHPrivateKey object with an
|
|
|
|
authorized key for the indicated user but with no signature.
|
|
|
|
"""
|
|
|
|
right_key_blob = DUMMY_KEY.public().toString("openssh")
|
|
|
|
key_credentials = credentials.SSHPrivateKey(
|
|
|
|
b"carol", b"md5", right_key_blob, None, None)
|
|
|
|
avatarId = self.checker.requestAvatarId(key_credentials)
|
|
|
|
return self.assertFailure(avatarId, conch_error.ValidPublicKey)
|
|
|
|
|
|
|
|
def test_wrong_signature(self):
|
|
|
|
"""
|
|
|
|
AccountFileChecker.requestAvatarId returns a Deferred that fires with
|
|
|
|
UnauthorizedLogin if called with an SSHPrivateKey object with a public
|
|
|
|
key matching that on the user's line in the account file but with the
|
|
|
|
wrong signature.
|
|
|
|
"""
|
|
|
|
right_key_blob = DUMMY_KEY.public().toString("openssh")
|
|
|
|
key_credentials = credentials.SSHPrivateKey(
|
|
|
|
b"carol", b"md5", right_key_blob, b"signed data", b"wrong sig")
|
|
|
|
avatarId = self.checker.requestAvatarId(key_credentials)
|
|
|
|
return self.assertFailure(avatarId, error.UnauthorizedLogin)
|
|
|
|
|
|
|
|
def test_authenticated(self):
|
|
|
|
"""
|
2015-01-04 14:48:38 +00:00
|
|
|
If called with an SSHPrivateKey object with a username and public key
|
|
|
|
found in the account file and a signature that proves possession of the
|
|
|
|
corresponding private key, AccountFileChecker.requestAvatarId returns a
|
|
|
|
Deferred that fires with an FTPAvatarID giving the username and root
|
|
|
|
capability for that user.
|
2015-01-04 14:44:56 +00:00
|
|
|
"""
|
|
|
|
username = b"carol"
|
|
|
|
signed_data = b"signed data"
|
|
|
|
signature = DUMMY_KEY.sign(signed_data)
|
|
|
|
right_key_blob = DUMMY_KEY.public().toString("openssh")
|
|
|
|
key_credentials = credentials.SSHPrivateKey(
|
|
|
|
username, b"md5", right_key_blob, signed_data, signature)
|
|
|
|
avatarId = self.checker.requestAvatarId(key_credentials)
|
2015-01-04 14:48:38 +00:00
|
|
|
def authenticated(avatarId):
|
|
|
|
self.assertEqual(
|
|
|
|
(username,
|
|
|
|
b"URI:DIR2:cccccccccccccccccccccccccc:3333333333333333333333333333333333333333333333333333"),
|
|
|
|
(avatarId.username, avatarId.rootcap))
|
|
|
|
avatarId.addCallback(authenticated)
|
2015-01-04 14:44:56 +00:00
|
|
|
return avatarId
|