Rev 2915: AuthenticationConfig can be queried for logins too (first step). in http://code.launchpad.net/%7Ev-ladeuil/bzr/auth.ring
Vincent Ladeuil
v.ladeuil+lp at free.fr
Mon Oct 22 16:18:44 BST 2007
At http://code.launchpad.net/%7Ev-ladeuil/bzr/auth.ring
------------------------------------------------------------
revno: 2915
revision-id: v.ladeuil+lp at free.fr-20071022151824-eol757lk393ofc38
parent: v.ladeuil+lp at free.fr-20071021104922-lc4hyrz0g06sj5u9
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: auth.ring
timestamp: Mon 2007-10-22 17:18:24 +0200
message:
AuthenticationConfig can be queried for logins too (first step).
* bzrlib/transport/ssh.py:
(_paramiko_auth): Try to get a user from AuthenticationConfig.
* bzrlib/smtp_connection.py:
(SMTPConnection._authenticate): Try to get a user from
AuthenticationConfig.
* bzrlib/transport/ftp.py:
(FtpTransport._create_connection): Try to get a user from
AuthenticationConfig. Credentials are now (user, password) instead
of just password.
* bzrlib/tests/test_ftp_transport.py:
(TestFTPServerUI._add_authorized_user): Cleanup by refactoring.
* bzrlib/config.py:
(AuthenticationConfig.get_user): New method to get logins.
modified:
bzrlib/config.py config.py-20051011043216-070c74f4e9e338e8
bzrlib/plugins/launchpad/lp_registration.py lp_registration.py-20060315190948-daa617eafe3a8d48
bzrlib/smtp_connection.py smtp_connection.py-20070618204456-nu6wag1ste4biuk2-1
bzrlib/tests/test_config.py testconfig.py-20051011041908-742d0c15d8d8c8eb
bzrlib/tests/test_ftp_transport.py test_aftp_transport.-20060823221619-98mwjzxtwtkt527k-1
bzrlib/tests/test_http.py testhttp.py-20051018020158-b2eef6e867c514d9
bzrlib/transport/ftp.py ftp.py-20051116161804-58dc9506548c2a53
bzrlib/transport/http/_urllib.py _urlgrabber.py-20060113083826-0bbf7d992fbf090c
bzrlib/transport/http/_urllib2_wrappers.py _urllib2_wrappers.py-20060913231729-ha9ugi48ktx481ao-1
bzrlib/transport/ssh.py ssh.py-20060824042150-0s9787kng6zv1nwq-1
doc/developers/authentication-ring.txt authring.txt-20070718200437-q5tdik0ne6lor86d-1
-------------- next part --------------
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py 2007-10-21 10:49:22 +0000
+++ b/bzrlib/config.py 2007-10-22 15:18:24 +0000
@@ -63,6 +63,7 @@
"""
import os
+import getpass
import sys
from bzrlib.lazy_import import lazy_import
@@ -1003,12 +1004,13 @@
:param path: the absolute path on the server (optional)
- :return: A dict with containing the matching credentials or None.
+ :return: A dict containing the matching credentials or None.
This includes:
- name: the section name of the credentials in the
authentication.conf file,
- user: can't de different from the provided user if any,
- - password: the decoded password,
+ - password: the decoded password, could be None if the credential
+ defines only the user
- verify_certificates: https specific, True if the server
certificate should be verified, False otherwise.
"""
@@ -1042,15 +1044,14 @@
and a_user != user):
# Never contradict the caller about the user to be used
continue
- user = a_user
- if user is None:
+ if a_user is None:
# Can't find a user
continue
a_password, a_encoding = map(auth_def.get,
['password', 'password_encoding'])
password = self.decode_password(a_password, a_encoding)
credentials = {'name': auth_def_name,
- 'user': user, 'password': password,
+ 'user': a_user, 'password': password,
'verify_certificates': a_verify_certificates,
}
if 'auth' in debug.debug_flags:
@@ -1059,6 +1060,29 @@
return credentials
+ def get_user(self, scheme, host, port=None,
+ realm=None, path=None, prompt=None):
+ """Get a user from authentication file.
+
+ :param scheme: protocol
+
+ :param host: the server address
+
+ :param port: the associated port (optional)
+
+ :param realm: the realm sent by the server (optional)
+
+ :param path: the absolute path on the server (optional)
+
+ :return: The found user.
+ """
+ credentials = self.get_credentials(scheme, host, port, user, path)
+ if credentials is not None:
+ user = credentials['user']
+ else:
+ user = None
+ return user
+
def get_password(self, scheme, host, user, port=None,
realm=None, path=None, prompt=None):
"""Get a password from authentication file or prompt the user for one.
@@ -1080,7 +1104,7 @@
credentials = self.get_credentials(scheme, host, port, user, path)
if credentials is not None:
password = credentials['password']
- else:
+ if password is None:
# Prompt user only if we could't find a password
if prompt is None:
prompt = ('%s' % scheme.upper()
=== modified file 'bzrlib/plugins/launchpad/lp_registration.py'
--- a/bzrlib/plugins/launchpad/lp_registration.py 2006-10-11 23:08:27 +0000
+++ b/bzrlib/plugins/launchpad/lp_registration.py 2007-10-22 15:18:24 +0000
@@ -92,6 +92,7 @@
def gather_user_credentials(self):
"""Get the password from the user."""
+ # FIXME: query AuthenticationConfig too
config = bzrlib.config.GlobalConfig()
self.registrant_email = config.user_email()
if self.registrant_password is None:
=== modified file 'bzrlib/smtp_connection.py'
--- a/bzrlib/smtp_connection.py 2007-10-20 16:49:14 +0000
+++ b/bzrlib/smtp_connection.py 2007-10-22 15:18:24 +0000
@@ -89,11 +89,13 @@
def _authenticate(self):
"""If necessary authenticate yourself to the server."""
+ auth = config.AuthenticationConfig()
if self._smtp_username is None:
- return
+ self._smtp_username = auth.get_user('smtp', self._smtp_server)
+ if self._smtp_username is None:
+ return
if self._smtp_password is None:
- auth = config.AuthenticationConfig()
self._smtp_password = auth.get_password(
'smtp', self._smtp_server, self._smtp_username)
=== modified file 'bzrlib/tests/test_config.py'
--- a/bzrlib/tests/test_config.py 2007-10-21 10:49:22 +0000
+++ b/bzrlib/tests/test_config.py 2007-10-22 15:18:24 +0000
@@ -1121,8 +1121,6 @@
class TestAuthenticationConfigFile(tests.TestCase):
"""Test the authentication.conf file matching"""
- # XXX: test definitions without users.
-
def _got_user_passwd(self, expected_user, expected_password,
config, *args, **kwargs):
credentials = config.get_credentials(*args, **kwargs)
@@ -1143,11 +1141,12 @@
def test_broken_config(self):
conf = config.AuthenticationConfig(_file=StringIO('[DEF'))
self.assertRaises(errors.ParseConfigError, conf._get_config)
+
conf = config.AuthenticationConfig(_file=StringIO(
"""[broken]
scheme=ftp
user=joe
-verify_certificates=askme
+verify_certificates=askme # Error: Not a boolean
"""))
self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
@@ -1345,5 +1344,11 @@
# FIXME: Once we have a way to declare authentication to all test servers, we
# can implement generic tests.
+# test_user_password_in_url
+# test_user_in_url_password_from_config
+# test_user_in_url_password_prompted
+# test_user_in_config
+# test_user_getpass.getuser
+# test_user_prompted ?
class TestAuthenticationRing(tests.TestCaseWithTransport):
pass
=== modified file 'bzrlib/tests/test_ftp_transport.py'
--- a/bzrlib/tests/test_ftp_transport.py 2007-10-21 10:49:22 +0000
+++ b/bzrlib/tests/test_ftp_transport.py 2007-10-22 15:18:24 +0000
@@ -82,6 +82,14 @@
class TestFTPServerUI(TestCaseWithFTPServer):
+ def _add_authorized_user(self, user, password):
+ server = self.get_server()
+ # FIXME: There should be a better way to declare authorized users and
+ # passwords to the server
+ authorizer = server._ftp_server.authorizer
+ authorizer.secured_user = user
+ authorizer.secured_password = password
+
def test_prompt_for_password(self):
t = self.get_transport()
# Ensure that the test framework set the password
@@ -93,12 +101,7 @@
ui.ui_factory = tests.TestUIFactory(stdin=password+'\n',
stdout=tests.StringIOWrapper())
# Ask the server to check the password
- server = self.get_server()
- # FIXME: There should be a better way to declare authorized users and
- # passwords to the server
- authorizer = server._ftp_server.authorizer
- authorizer.secured_user = t._user
- authorizer.secured_password = password
+ self._add_authorized_user(t._user, password)
# Issue a request to the server to connect
t.has('whatever/not/existing')
# stdin should be empty (the provided password have been consumed)
@@ -113,12 +116,7 @@
ui.ui_factory = tests.TestUIFactory(stdin='precious\n',
stdout=tests.StringIOWrapper())
# Ask the server to check the password
- server = self.get_server()
- # FIXME: There should be a better way to declare authorized users and
- # passwords to the server
- authorizer = server._ftp_server.authorizer
- authorizer.secured_user = t._user
- authorizer.secured_password = password
+ self._add_authorized_user(t._user, password)
# Create a config file with the right password
conf = config.AuthenticationConfig()
=== modified file 'bzrlib/tests/test_http.py'
--- a/bzrlib/tests/test_http.py 2007-10-20 16:49:14 +0000
+++ b/bzrlib/tests/test_http.py 2007-10-22 15:18:24 +0000
@@ -1304,6 +1304,8 @@
self.assertEqual('contents of a\n',t.get('a').read())
# stdin should have been left untouched
self.assertEqual(stdin_content, ui.ui_factory.stdin.readline())
+ # Only one 'Authentication Required' error should occur
+ self.assertEqual(1, self.server.auth_required_errors)
=== modified file 'bzrlib/transport/ftp.py'
--- a/bzrlib/transport/ftp.py 2007-10-20 16:49:14 +0000
+++ b/bzrlib/transport/ftp.py 2007-10-22 15:18:24 +0000
@@ -120,27 +120,33 @@
in base url at transport creation time.
"""
if credentials is None:
- password = self._password
+ user, password = self._user, self._password
else:
- password = credentials
+ user, password = credentials
+
+ auth = config.AuthenticationConfig()
+ if user is None:
+ user = auth.get_user('ftp', self._host, port=self._port)
+ if user is None:
+ # Default to local user
+ user = getpass.getuser()
mutter("Constructing FTP instance against %r" %
- ((self._host, self._port, self._user, '********',
+ ((self._host, self._port, user, '********',
self.is_active),))
try:
connection = ftplib.FTP()
connection.connect(host=self._host, port=self._port)
- if self._user and self._user != 'anonymous' and \
+ if user and user != 'anonymous' and \
password is None: # '' is a valid password
- auth = config.AuthenticationConfig()
- password = auth.get_password('ftp', self._host, self._user,
+ password = auth.get_password('ftp', self._host, user,
port=self._port)
- connection.login(user=self._user, passwd=password)
+ connection.login(user=user, passwd=password)
connection.set_pasv(not self.is_active)
except ftplib.error_perm, e:
raise errors.TransportError(msg="Error setting up connection:"
" %s" % str(e), orig_error=e)
- return connection, password
+ return connection, (user, password)
def _reconnect(self):
"""Create a new connection with the previously used credentials"""
=== modified file 'bzrlib/transport/http/_urllib.py'
--- a/bzrlib/transport/http/_urllib.py 2007-08-15 04:56:08 +0000
+++ b/bzrlib/transport/http/_urllib.py 2007-10-22 15:18:24 +0000
@@ -30,8 +30,6 @@
from bzrlib.transport.http._urllib2_wrappers import (
Opener,
Request,
- extract_authentication_uri,
- extract_credentials,
)
@@ -61,6 +59,8 @@
path = self._combine_paths(self._path, relative)
# urllib2 will be confused if it find authentication
# info (user, password) in the urls. So we handle them separatly.
+
+ # rhaaaa ! confused where ? confused when ? --vila 20070922
return self._unsplit_url(self._unqualified_scheme,
None, None, self._host, self._port, path)
=== modified file 'bzrlib/transport/http/_urllib2_wrappers.py'
--- a/bzrlib/transport/http/_urllib2_wrappers.py 2007-10-20 16:49:14 +0000
+++ b/bzrlib/transport/http/_urllib2_wrappers.py 2007-10-22 15:18:24 +0000
@@ -270,7 +270,7 @@
def extract_authentication_uri(url):
"""Extract the authentication uri from any url.
- In the context of bzr, we simplified the authentication uri
+ In the context of bzr, we simplify the authentication uri
to the host only. For the transport lifetime, we allow only
one user by realm on a given host. I.e. handling several
users for different paths for the same realm should be done
@@ -815,6 +815,8 @@
# grok user:password at host:port as well as
# http://user:password@host:port
+ # FIXME: query AuthenticationConfig too
+
# Extract credentials from the url and store them in the
# password manager so that the proxy AuthHandler can use
# them later.
=== modified file 'bzrlib/transport/ssh.py'
--- a/bzrlib/transport/ssh.py 2007-10-20 16:49:14 +0000
+++ b/bzrlib/transport/ssh.py 2007-10-22 15:18:24 +0000
@@ -461,7 +461,12 @@
# the username might be specified in ~/.ssh/config and we don't want to
# force it to something else
# Also, it would mess up the self.relpath() functionality
- username = username or getpass.getuser()
+ auth = config.AuthenticationConfig()
+ if username is None:
+ username = auth.get_user('ssh', host, port=port)
+ if username is None:
+ # Default to local user
+ username = getpass.getuser()
if _use_ssh_agent:
agent = paramiko.Agent()
@@ -487,7 +492,6 @@
pass
# give up and ask for a password
- auth = config.AuthenticationConfig()
password = auth.get_password('ssh', host, username, port=port)
try:
paramiko_transport.auth_password(username, password)
=== modified file 'doc/developers/authentication-ring.txt'
--- a/doc/developers/authentication-ring.txt 2007-10-18 10:33:11 +0000
+++ b/doc/developers/authentication-ring.txt 2007-10-22 15:18:24 +0000
@@ -162,13 +162,12 @@
Future versions of this specification may provide additional
encodings [#password_encoding]_.
-.. [#password_encoding] Additional password encoding methods may
- be defined that will rely on external means to store the
- password which, in these cases, will not appear anymore in the
- definition. It is assumed that additional password encodings
- will provide a storage outside of the file described here. An
- encoding named ``netrc`` for example will provide passwords by
- retrieving them in the ``.netrc`` file.
+.. [#password_encoding] Additional password encoding methods may be defined
+ that will rely on external means to store the password which, in these
+ cases, will not appear anymore in the definition. It is assumed that
+ additional password encodings will provide a storage outside of the file
+ described here. An encoding named ``netrc`` for example will provide
+ passwords by retrieving them in the ``.netrc`` file.
File format
-----------
@@ -245,9 +244,9 @@
bzr branch ftp://foo.net/bzr/branch
bzr pull ftp://bzr.foo.net/bzr/product/branch/trunk
- * all connections are done with the same ``user`` (the remote
- one for which the default bzr one is not appropriate) and the
- password is always prompted with some exceptions::
+ * all connections are done with the same ``user`` (the remote one for which
+ the default bzr one is not appropriate) and the password is always prompted
+ with some exceptions::
# Pet projects on hobby.net
[hobby]
@@ -265,6 +264,7 @@
verify_certificates=no # Still searching a free certificate provider
[DEFAULT]
+ # Our local user is barbaz, on all remote sites we're known as foobar
user=foobar
* an HTTP server and a proxy::
@@ -295,9 +295,11 @@
* source hosting provider declaring sub-domains for each project::
- [sfnet]
- scheme=ssh # we use sftp, but ssh is the scheme used for authentication
- host=.sf.net # The leading '.' ensures that 'sf.net' does not match
+ [sfnet domain]
+ # we use sftp, but ssh is the scheme used for authentication
+ scheme=ssh
+ # The leading '.' ensures that 'sf.net' alone doesn't match
+ host=.sf.net
user=georges
password=ben...son
@@ -322,8 +324,8 @@
Get a user from ``~/.bazaar/authentication.conf`` or prompt for one if none is
found. Continue as 2.
-Note: A user will be queried only if the server requires it for ``HTTP``, other
-protocols always require a user.
+Note: A user will be queried only if the server requires it for ``HTTP`` or
+``HTTPS``, other protocols always require a user.
In any case, if the server refuses the authentication, bzr reports to the user
and terminates.
More information about the bazaar-commits
mailing list