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