mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Add tests for get_password
This commit is contained in:
parent
d5fe537196
commit
7321da0f02
2 changed files with 130 additions and 39 deletions
|
|
@ -7,6 +7,7 @@
|
||||||
:license: MIT, see LICENSE for more details.
|
:license: MIT, see LICENSE for more details.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import pytest
|
||||||
import vdirsyncer.utils as utils
|
import vdirsyncer.utils as utils
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,3 +27,67 @@ def test_parse_options():
|
||||||
'bam': 123,
|
'bam': 123,
|
||||||
'asd': False
|
'asd': False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_password_from_netrc(monkeypatch):
|
||||||
|
username = 'foouser'
|
||||||
|
password = 'foopass'
|
||||||
|
resource = 'http://example.com/path/to/whatever/'
|
||||||
|
hostname = 'example.com'
|
||||||
|
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
def authenticators(self, hostname):
|
||||||
|
calls.append(hostname)
|
||||||
|
return username, 'bogus', password
|
||||||
|
|
||||||
|
import netrc
|
||||||
|
|
||||||
|
monkeypatch.setattr(netrc.netrc, 'authenticators', authenticators)
|
||||||
|
|
||||||
|
_password = utils.get_password(username, resource)
|
||||||
|
assert _password == password
|
||||||
|
assert calls == [hostname]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('resources_to_test', range(1, 8))
|
||||||
|
def test_get_password_from_system_keyring(monkeypatch, resources_to_test):
|
||||||
|
username = 'foouser'
|
||||||
|
password = 'foopass'
|
||||||
|
resource = 'http://example.com/path/to/whatever/'
|
||||||
|
hostname = 'example.com'
|
||||||
|
|
||||||
|
class KeyringMock(object):
|
||||||
|
def __init__(self):
|
||||||
|
p = utils.password_key_prefix
|
||||||
|
self.resources = [
|
||||||
|
p + 'http://example.com/path/to/whatever/',
|
||||||
|
p + 'http://example.com/path/to/whatever',
|
||||||
|
p + 'http://example.com/path/to/',
|
||||||
|
p + 'http://example.com/path/to',
|
||||||
|
p + 'http://example.com/path/',
|
||||||
|
p + 'http://example.com/path',
|
||||||
|
p + 'http://example.com/',
|
||||||
|
][:resources_to_test]
|
||||||
|
|
||||||
|
def get_password(self, resource, _username):
|
||||||
|
assert _username == username
|
||||||
|
assert resource == self.resources.pop(0)
|
||||||
|
if not self.resources:
|
||||||
|
return password
|
||||||
|
|
||||||
|
import sys
|
||||||
|
monkeypatch.setitem(sys.modules, 'keyring', KeyringMock())
|
||||||
|
|
||||||
|
import netrc
|
||||||
|
netrc_calls = []
|
||||||
|
|
||||||
|
def authenticators(self, h):
|
||||||
|
netrc_calls.append(h)
|
||||||
|
return None
|
||||||
|
|
||||||
|
monkeypatch.setattr(netrc.netrc, 'authenticators', authenticators)
|
||||||
|
|
||||||
|
_password = utils.get_password(username, resource)
|
||||||
|
assert _password == password
|
||||||
|
assert netrc_calls == [hostname]
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import vdirsyncer.log
|
import vdirsyncer.log
|
||||||
|
|
||||||
|
password_key_prefix = 'vdirsyncer:'
|
||||||
|
|
||||||
|
|
||||||
def expand_path(p):
|
def expand_path(p):
|
||||||
p = os.path.expanduser(p)
|
p = os.path.expanduser(p)
|
||||||
p = os.path.abspath(p)
|
p = os.path.abspath(p)
|
||||||
|
|
@ -65,54 +67,78 @@ def get_password(username, resource):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import getpass
|
import getpass
|
||||||
from netrc import netrc
|
|
||||||
try:
|
try:
|
||||||
from urlparse import urlsplit
|
from urlparse import urlsplit, urlunsplit
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from urllib.parse import urlsplit
|
from urllib.parse import urlsplit, urlunsplit
|
||||||
|
|
||||||
sync_logger = vdirsyncer.log.get('sync')
|
|
||||||
|
|
||||||
# XXX is it save to asume that a password is always the same for
|
|
||||||
# any given (hostname, username) combination?
|
|
||||||
hostname = urlsplit(resource).hostname
|
|
||||||
|
|
||||||
# netrc
|
|
||||||
try:
|
|
||||||
auths = netrc().authenticators(hostname)
|
|
||||||
# auths = (user, password)
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if auths is not None:
|
|
||||||
sync_logger.debug("Read password for user {0} on {1} in .netrc".format(
|
|
||||||
auths[0], hostname))
|
|
||||||
return auths[1]
|
|
||||||
|
|
||||||
# keyring
|
|
||||||
try:
|
try:
|
||||||
import keyring
|
import keyring
|
||||||
except ImportError:
|
except ImportError:
|
||||||
keyring, password = None, None
|
keyring = None
|
||||||
else:
|
|
||||||
password = keyring.get_password(
|
logger = vdirsyncer.log.get('sync')
|
||||||
'vdirsyncer:' + hostname, username)
|
hostname = urlsplit(resource).hostname
|
||||||
|
|
||||||
|
def _netrc():
|
||||||
|
'''.netrc'''
|
||||||
|
from netrc import netrc
|
||||||
|
try:
|
||||||
|
netrc_user, account, password = \
|
||||||
|
netrc().authenticators(hostname) or (None, None, None)
|
||||||
|
if netrc_user == username:
|
||||||
|
return password
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _keyring():
|
||||||
|
'''system keyring'''
|
||||||
|
if keyring is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
key = resource
|
||||||
|
password = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
password = keyring.get_password(password_key_prefix + key, username)
|
||||||
|
if password is not None:
|
||||||
|
return password
|
||||||
|
|
||||||
|
parsed = urlsplit(key)
|
||||||
|
path = parsed.path
|
||||||
|
if path.endswith('/'):
|
||||||
|
path = path.rstrip('/')
|
||||||
|
else:
|
||||||
|
path = path.rsplit('/', 1)[0] + '/'
|
||||||
|
|
||||||
|
new_key = urlunsplit((
|
||||||
|
parsed.scheme,
|
||||||
|
parsed.netloc,
|
||||||
|
path,
|
||||||
|
parsed.query,
|
||||||
|
parsed.fragment
|
||||||
|
))
|
||||||
|
if new_key == key:
|
||||||
|
return None
|
||||||
|
key = new_key
|
||||||
|
|
||||||
|
for func in (_netrc, _keyring):
|
||||||
|
password = func()
|
||||||
if password is not None:
|
if password is not None:
|
||||||
sync_logger.debug("Got password for user {0}@{1} from keyring".format(
|
logger.debug('Got password for {} from {}'
|
||||||
username, hostname))
|
.format(username, func.__doc__))
|
||||||
return password
|
return password
|
||||||
|
|
||||||
if password is None:
|
prompt = ('Server password for {} at the resource {}: '
|
||||||
prompt = 'Server password {0}@{1}: '.format(username, hostname)
|
.format(username, resource))
|
||||||
password = getpass.getpass(prompt=prompt)
|
password = getpass.getpass(prompt=prompt)
|
||||||
|
|
||||||
if keyring:
|
if keyring is not None:
|
||||||
answer = 'x'
|
answer = None
|
||||||
while answer.lower() not in ['', 'y', 'n']:
|
while answer not in ['', 'y', 'n']:
|
||||||
prompt = 'Save this password in the keyring? [y/N] '
|
prompt = 'Save this password in the keyring? [y/N] '
|
||||||
answer = raw_input(prompt)
|
answer = raw_input(prompt).lower()
|
||||||
if answer.lower() == 'y':
|
if answer == 'y':
|
||||||
keyring.set_password(
|
keyring.set_password(password_key_prefix + resource, username, password)
|
||||||
'vdirsyncer:' + hostname, username, password)
|
|
||||||
|
|
||||||
return password
|
return password
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue