Rev 4310: Tighten multiple auth schemes handling. in file:///home/vila/src/bzr/bugs/366107-http-mutiple-auth-schemes/

Vincent Ladeuil v.ladeuil+lp at free.fr
Mon May 4 16:21:26 BST 2009


At file:///home/vila/src/bzr/bugs/366107-http-mutiple-auth-schemes/

------------------------------------------------------------
revno: 4310
revision-id: v.ladeuil+lp at free.fr-20090504152126-13juy7bmikof23xc
parent: v.ladeuil+lp at free.fr-20090504144821-39dvqkikmd3zqkdg
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 366107-http-mutiple-auth-schemes
timestamp: Mon 2009-05-04 17:21:26 +0200
message:
  Tighten multiple auth schemes handling.
  
  * bzrlib/transport/http/_urllib2_wrappers.py:
  (AbstractAuthHandler): Add a 'scheme' attribute to identify the
  handlers.
  (AbstractAuthHandler.auth_required): Once the most secured scheme
  is known to be proposed by the server, the other handlers should
  not be tried.
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS	2009-04-27 23:26:00 +0000
+++ b/NEWS	2009-05-04 15:21:26 +0000
@@ -58,6 +58,9 @@
 * Non-recursive ``bzr ls`` now works properly when a path is specified.
   (Jelmer Vernooij, #357863)
 
+* Correctly handle http servers proposing multiple authentication schemes.
+  (Vincent Ladeuil, #366107)
+
 Documentation
 *************
 

=== modified file 'bzrlib/transport/http/_urllib2_wrappers.py'
--- a/bzrlib/transport/http/_urllib2_wrappers.py	2009-05-04 14:48:21 +0000
+++ b/bzrlib/transport/http/_urllib2_wrappers.py	2009-05-04 15:21:26 +0000
@@ -978,6 +978,9 @@
       successful and the request authentication parameters have been updated.
     """
 
+    scheme = None
+    """The scheme as it appears in the server header (lower cased)"""
+
     _max_retry = 3
     """We don't want to retry authenticating endlessly"""
 
@@ -1044,7 +1047,8 @@
         auth = self.get_auth(request)
         auth['modified'] = False
         # FIXME: the auth handler should be selected at a single place instead
-        # of letting all handlers try to match all headers.
+        # of letting all handlers try to match all headers, but the current
+        # design doesn't allow a simple implementation.
         for server_header in server_headers:
             # Several schemes can be proposed by the server, try to match each
             # one in turn
@@ -1057,6 +1061,20 @@
                     # We already tried that, give up
                     return None
 
+                # Only the most secure scheme proposed by the server should be
+                # used, since the handlers use 'handler_order' to describe that
+                # property, the first handler tried takes precedence, the
+                # others should not attempt to authenticate if the best one
+                # failed.
+                best_scheme = auth.get('best_scheme', None)
+                if best_scheme is None:
+                    # At that point, if current handler should doesn't succeed
+                    # the credentials are wrong (or incomplete), but we know
+                    # that the associated scheme should be used.
+                    best_scheme = auth['best_scheme'] = self.scheme
+                if  best_scheme != self.scheme:
+                    continue
+
                 if self.requires_username and auth.get('user', None) is None:
                     # Without a known user, we can't authenticate
                     return None
@@ -1199,13 +1217,13 @@
     NTLM support may also be added.
     """
 
+    scheme = 'negotiate'
     handler_order = 480
-
     requires_username = False
 
     def auth_match(self, header, auth):
         scheme, raw_auth = self._parse_auth_header(header)
-        if scheme != 'negotiate':
+        if scheme != self.scheme:
             return False
         self.update_auth(auth, 'scheme', scheme)
         resp = self._auth_match_kerberos(auth)
@@ -1244,8 +1262,8 @@
 class BasicAuthHandler(AbstractAuthHandler):
     """A custom basic authentication handler."""
 
+    scheme = 'basic'
     handler_order = 500
-
     auth_regexp = re.compile('realm="([^"]*)"', re.I)
 
     def build_auth_header(self, auth, request):
@@ -1262,7 +1280,7 @@
 
     def auth_match(self, header, auth):
         scheme, raw_auth = self._parse_auth_header(header)
-        if scheme != 'basic':
+        if scheme != self.scheme:
             return False
 
         match, realm = self.extract_realm(raw_auth)
@@ -1304,6 +1322,7 @@
 class DigestAuthHandler(AbstractAuthHandler):
     """A custom digest authentication handler."""
 
+    scheme = 'digest'
     # Before basic as digest is a bit more secure and should be preferred
     handler_order = 490
 
@@ -1315,7 +1334,7 @@
 
     def auth_match(self, header, auth):
         scheme, raw_auth = self._parse_auth_header(header)
-        if scheme != 'digest':
+        if scheme != self.scheme:
             return False
 
         # Put the requested authentication info into a dict



More information about the bazaar-commits mailing list