Merge 0.4.
[jelmer/subvertpy.git] / auth.py
diff --git a/auth.py b/auth.py
index b5c9afe03f82253eba3443062e3161e632266372..b613676ca33b56f3a25b2e4e58e28263e7fc8429 100644 (file)
--- a/auth.py
+++ b/auth.py
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+"""Authentication token retrieval."""
+
 from bzrlib.config import AuthenticationConfig
 from bzrlib.ui import ui_factory
-from svn.core import (svn_auth_cred_username_t, 
-                      svn_auth_cred_simple_t,
-                      svn_auth_cred_ssl_client_cert_t,
-                      svn_auth_cred_ssl_client_cert_pw_t,
-                      svn_auth_cred_ssl_server_trust_t,
-                      svn_auth_get_username_prompt_provider,
-                      svn_auth_get_simple_prompt_provider,
-                      svn_auth_get_ssl_server_trust_prompt_provider,
-                      svn_auth_get_ssl_client_cert_pw_prompt_provider)
-
+from bzrlib.plugins.svn.ra import (get_username_prompt_provider, 
+                                   get_simple_prompt_provider,
+                                   get_ssl_server_trust_prompt_provider,
+                                   get_ssl_client_cert_pw_prompt_provider)
+                                   get_simple_provider, get_username_provider, 
+                                   get_ssl_client_cert_file_provider, 
+                                   get_ssl_client_cert_pw_file_provider,
+                                   get_ssl_server_trust_file_provider,
+                                   Auth
+                                   )
+from bzrlib.plugins.svn import ra
+import urlparse
+import urllib
+
+AUTH_PARAM_DEFAULT_USERNAME = 'svn:auth:username'
+AUTH_PARAM_DEFAULT_PASSWORD = 'svn:auth:password'
 
 class SubversionAuthenticationConfig(AuthenticationConfig):
     """Simple extended version of AuthenticationConfig that can provide 
     the information Subversion requires.
     """
-    def __init__(self, file=None, scheme="svn"):
+    def __init__(self, scheme, host, port, path, file=None):
         super(SubversionAuthenticationConfig, self).__init__(file)
         self.scheme = scheme
-
-    def get_svn_username(realm, may_save, pool=None):
+        self.host = host
+        self.port = port
+        self.path = path
+       
+    def get_svn_username(self, realm, may_save):
         """Look up a Subversion user name in the Bazaar authentication cache.
 
         :param realm: Authentication realm (optional)
         :param may_save: Whether or not the username should be saved.
-        :param pool: Allocation pool, is ignored.
         """
-        username_cred = svn_auth_cred_username_t()
-        username_cred.username = self.get_user(self.scheme, host=None, realm=realm)
-        username_cred.may_save = False
-        return username_cred
+        username = self.get_user(self.scheme, host=self.host, path=self.path, realm=realm)
+        return (username, False)
 
-    def get_svn_simple(realm, username, may_save, pool):
-        """Look up a Subversion user name+password combination in the Bazaar authentication cache.
+    def get_svn_simple(self, realm, username, may_save, pool):
+        """Look up a Subversion user name+password combination in the Bazaar 
+        authentication cache.
 
         :param realm: Authentication realm (optional)
         :param username: Username, if it is already known, or None.
         :param may_save: Whether or not the username should be saved.
         :param pool: Allocation pool, is ignored.
         """
-        simple_cred = svn_auth_cred_simple_t()
-        simple_cred.username = username or self.get_username(realm, may_save, pool)
-        simple_cred.password = self.get_password(self.scheme, host=None, 
-                                    user=simple_cred.username, realm=realm)
-        simple_cred.may_save = False
-        return simple_cred
-
-    def get_svn_ssl_server_trust(realm, failures, cert_info, may_save, pool):
+        username = self.get_user(self.scheme, 
+                host=self.host, path=self.path, realm=realm) or username
+        password = self.get_password(self.scheme, host=self.host, 
+            path=self.path, user=simple_cred.username, 
+            realm=realm, prompt="%s %s password" % (realm, simple_cred.username))
+        return (username, password, False)
+
+    def get_svn_ssl_server_trust(self, realm, failures, cert_info, may_save, 
+                                     pool):
         """Return a Subversion auth provider that verifies SSL server trust.
 
         :param realm: Realm name (optional)
@@ -69,18 +79,19 @@ class SubversionAuthenticationConfig(AuthenticationConfig):
         :param cert_info: Certificate information
         :param may_save: Whether this information may be stored.
         """
-        ssl_server_trust = svn_auth_cred_ssl_server_trust_t()
-        credentials = self.get_credentials(self.scheme, host=None)
-        if credentials.has_key("verify_certificates") and credentials["verify_certificates"] == False:
-            ssl_server_trust.accepted_failures = (svn.core.SVN_AUTH_SSL_NOTYETVALID + 
-                                                  svn.core.SVN_AUTH_SSL_EXPIRED +
-                                                  svn.core.SVN_AUTH_SSL_CNMISMATCH +
-                                                  svn.core.SVN_AUTH_SSL_UNKNOWNCA +
-                                                  svn.core.SVN_AUTH_SSL_OTHER)
+        credentials = self.get_credentials(self.scheme, host=self.host)
+        if (credentials is not None and 
+            credentials.has_key("verify_certificates") and 
+            credentials["verify_certificates"] == False):
+            accepted_failures = (
+                    AUTH_SSL_NOTYETVALID + 
+                    AUTH_SSL_EXPIRED +
+                    AUTH_SSL_CNMISMATCH +
+                    AUTH_SSL_UNKNOWNCA +
+                    AUTH_SSL_OTHER)
         else:
-            ssl_server_trust.accepted_failures = 0
-        ssl_server_trust.may_save = False
-        return ssl_server_trust
+            accepted_failures = 0
+        return (accepted_failures, False)
 
     def get_svn_username_prompt_provider(self, retries):
         """Return a Subversion auth provider for retrieving the username, as 
@@ -88,7 +99,8 @@ class SubversionAuthenticationConfig(AuthenticationConfig):
         
         :param retries: Number of allowed retries.
         """
-        return svn_auth_get_username_prompt_provider(self.get_svn_username, retries)
+        return get_username_prompt_provider(self.get_svn_username, 
+                                                     retries)
 
     def get_svn_simple_prompt_provider(self, retries):
         """Return a Subversion auth provider for retrieving a 
@@ -96,12 +108,13 @@ class SubversionAuthenticationConfig(AuthenticationConfig):
         
         :param retries: Number of allowed retries.
         """
-        return svn_auth_get_simple_prompt_provider(self.get_svn_simple, retries)
+        return get_simple_prompt_provider(self.get_svn_simple, retries)
 
     def get_svn_ssl_server_trust_prompt_provider(self):
         """Return a Subversion auth provider for checking 
         whether a SSL server is trusted."""
-        return svn_auth_get_ssl_server_trust_prompt_provider(self.get_svn_ssl_server_trust)
+        return get_ssl_server_trust_prompt_provider(
+                    self.get_svn_ssl_server_trust)
 
     def get_svn_auth_providers(self):
         """Return a list of auth providers for this authentication file.
@@ -110,20 +123,64 @@ class SubversionAuthenticationConfig(AuthenticationConfig):
                 self.get_svn_simple_prompt_provider(1),
                 self.get_svn_ssl_server_trust_prompt_provider()]
 
-
 def get_ssl_client_cert_pw(realm, may_save, pool):
     """Simple SSL client certificate password prompter.
 
     :param realm: Realm, optional.
     :param may_save: Whether the password can be cached.
     """
-    ssl_cred_pw = svn_auth_cred_ssl_client_cert_pw_t()
-    ssl_cred_pw.password = \
-            ui_factory.get_password("Please enter password for client certificate[realm=%s]" % realm)
-    ssl_cred_pw.may_save = False
-    return ssl_cred_pw
+    password = ui_factory.get_password(
+            "Please enter password for client certificate[realm=%s]" % realm)
+    return (password, False)
 
 
 def get_ssl_client_cert_pw_provider(tries):
-    return svn_auth_get_ssl_client_cert_pw_prompt_provider(get_ssl_client_cert_pw, tries)
-
+    return get_ssl_client_cert_pw_prompt_provider(
+                get_ssl_client_cert_pw, tries)
+
+def get_stock_svn_providers():
+    providers = [get_simple_provider(),
+            get_username_provider(),
+            get_ssl_client_cert_file_provider(),
+            get_ssl_client_cert_pw_file_provider(),
+            get_ssl_server_trust_file_provider(),
+            ]
+
+    if hasattr(ra, 'get_windows_simple_provider'):
+        providers.append(ra.get_windows_simple_provider())
+
+    if hasattr(ra, 'get_keychain_simple_provider'):
+        providers.append(ra.get_keychain_simple_provider())
+
+    if hasattr(ra, 'get_windows_ssl_server_trust_provider'):
+        providers.append(ra.get_windows_ssl_server_trust_provider())
+
+    return providers
+
+
+def create_auth_baton(url):
+    """Create an authentication baton for the specified URL."""
+    assert isinstance(url, str)
+    (scheme, netloc, path, _, _) = urlparse.urlsplit(url)
+    (creds, host) = urllib.splituser(netloc)
+    (host, port) = urllib.splitport(host)
+
+    auth_config = SubversionAuthenticationConfig(scheme, host, port, path)
+
+    # Specify Subversion providers first, because they use file data
+    # rather than prompting the user.
+    providers = get_stock_svn_providers()
+
+    (major, minor, patch, tag) = ra.version()
+    if major == 1 and minor >= 5:
+        providers += auth_config.get_svn_auth_providers()
+        providers += [get_ssl_client_cert_pw_provider(1)]
+
+    auth_baton = Auth(providers)
+    if creds is not None:
+        (user, password) = urllib.splitpasswd(creds)
+        if user is not None:
+            auth_baton.set_parameter(AUTH_PARAM_DEFAULT_USERNAME, user)
+        if password is not None:
+            auth_baton.set_parameter(AUTH_PARAM_DEFAULT_PASSWORD, password)
+    return auth_baton