Fix typo, indentation.
[jelmer/subvertpy.git] / auth.py
1 # Copyright (C) 2005-2007 Jelmer Vernooij <jelmer@samba.org>
2  
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
7
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12
13 # You should have received a copy of the GNU General Public License
14 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 """Authentication token retrieval."""
17
18 from bzrlib.config import AuthenticationConfig
19 from bzrlib.ui import ui_factory
20 from bzrlib.plugins.svn.ra import (get_username_prompt_provider,
21                 get_simple_prompt_provider,
22                 get_ssl_server_trust_prompt_provider,
23                 get_ssl_client_cert_pw_prompt_provider,
24                 get_simple_provider, get_username_provider, 
25                 get_ssl_client_cert_file_provider, 
26                 get_ssl_client_cert_pw_file_provider,
27                 get_ssl_server_trust_file_provider,
28                 Auth
29                 )
30 from bzrlib.plugins.svn import ra
31 import urlparse
32 import urllib
33
34 AUTH_PARAM_DEFAULT_USERNAME = 'svn:auth:username'
35 AUTH_PARAM_DEFAULT_PASSWORD = 'svn:auth:password'
36
37 class SubversionAuthenticationConfig(AuthenticationConfig):
38     """Simple extended version of AuthenticationConfig that can provide 
39     the information Subversion requires.
40     """
41     def __init__(self, scheme, host, port, path, file=None):
42         super(SubversionAuthenticationConfig, self).__init__(file)
43         self.scheme = scheme
44         self.host = host
45         self.port = port
46         self.path = path
47        
48     def get_svn_username(self, realm, may_save):
49         """Look up a Subversion user name in the Bazaar authentication cache.
50
51         :param realm: Authentication realm (optional)
52         :param may_save: Whether or not the username should be saved.
53         """
54         username = self.get_user(self.scheme, host=self.host, path=self.path, realm=realm)
55         return (username, False)
56
57     def get_svn_simple(self, realm, username, may_save, pool):
58         """Look up a Subversion user name+password combination in the Bazaar 
59         authentication cache.
60
61         :param realm: Authentication realm (optional)
62         :param username: Username, if it is already known, or None.
63         :param may_save: Whether or not the username should be saved.
64         :param pool: Allocation pool, is ignored.
65         """
66         username = self.get_user(self.scheme, 
67                 host=self.host, path=self.path, realm=realm) or username
68         password = self.get_password(self.scheme, host=self.host, 
69             path=self.path, user=simple_cred.username, 
70             realm=realm, prompt="%s %s password" % (realm, simple_cred.username))
71         return (username, password, False)
72
73     def get_svn_ssl_server_trust(self, realm, failures, cert_info, may_save, 
74                                      pool):
75         """Return a Subversion auth provider that verifies SSL server trust.
76
77         :param realm: Realm name (optional)
78         :param failures: Failures to check for (bit field, SVN_AUTH_SSL_*)
79         :param cert_info: Certificate information
80         :param may_save: Whether this information may be stored.
81         """
82         credentials = self.get_credentials(self.scheme, host=self.host)
83         if (credentials is not None and 
84             credentials.has_key("verify_certificates") and 
85             credentials["verify_certificates"] == False):
86             accepted_failures = (
87                     AUTH_SSL_NOTYETVALID + 
88                     AUTH_SSL_EXPIRED +
89                     AUTH_SSL_CNMISMATCH +
90                     AUTH_SSL_UNKNOWNCA +
91                     AUTH_SSL_OTHER)
92         else:
93             accepted_failures = 0
94         return (accepted_failures, False)
95
96     def get_svn_username_prompt_provider(self, retries):
97         """Return a Subversion auth provider for retrieving the username, as 
98         accepted by svn_auth_open().
99         
100         :param retries: Number of allowed retries.
101         """
102         return get_username_prompt_provider(self.get_svn_username, 
103                                                      retries)
104
105     def get_svn_simple_prompt_provider(self, retries):
106         """Return a Subversion auth provider for retrieving a 
107         username+password combination, as accepted by svn_auth_open().
108         
109         :param retries: Number of allowed retries.
110         """
111         return get_simple_prompt_provider(self.get_svn_simple, retries)
112
113     def get_svn_ssl_server_trust_prompt_provider(self):
114         """Return a Subversion auth provider for checking 
115         whether a SSL server is trusted."""
116         return get_ssl_server_trust_prompt_provider(
117                     self.get_svn_ssl_server_trust)
118
119     def get_svn_auth_providers(self):
120         """Return a list of auth providers for this authentication file.
121         """
122         return [self.get_svn_username_prompt_provider(1),
123                 self.get_svn_simple_prompt_provider(1),
124                 self.get_svn_ssl_server_trust_prompt_provider()]
125
126 def get_ssl_client_cert_pw(realm, may_save, pool):
127     """Simple SSL client certificate password prompter.
128
129     :param realm: Realm, optional.
130     :param may_save: Whether the password can be cached.
131     """
132     password = ui_factory.get_password(
133             "Please enter password for client certificate[realm=%s]" % realm)
134     return (password, False)
135
136
137 def get_ssl_client_cert_pw_provider(tries):
138     return get_ssl_client_cert_pw_prompt_provider(
139                 get_ssl_client_cert_pw, tries)
140
141 def get_stock_svn_providers():
142     providers = [get_simple_provider(),
143             get_username_provider(),
144             get_ssl_client_cert_file_provider(),
145             get_ssl_client_cert_pw_file_provider(),
146             get_ssl_server_trust_file_provider(),
147             ]
148
149     if hasattr(ra, 'get_windows_simple_provider'):
150         providers.append(ra.get_windows_simple_provider())
151
152     if hasattr(ra, 'get_keychain_simple_provider'):
153         providers.append(ra.get_keychain_simple_provider())
154
155     if hasattr(ra, 'get_windows_ssl_server_trust_provider'):
156         providers.append(ra.get_windows_ssl_server_trust_provider())
157
158     return providers
159
160
161 def create_auth_baton(url):
162     """Create an authentication baton for the specified URL."""
163     assert isinstance(url, str)
164     (scheme, netloc, path, _, _) = urlparse.urlsplit(url)
165     (creds, host) = urllib.splituser(netloc)
166     (host, port) = urllib.splitport(host)
167
168     auth_config = SubversionAuthenticationConfig(scheme, host, port, path)
169
170     # Specify Subversion providers first, because they use file data
171     # rather than prompting the user.
172     providers = get_stock_svn_providers()
173
174     (major, minor, patch, tag) = ra.version()
175     if major == 1 and minor >= 5:
176         providers += auth_config.get_svn_auth_providers()
177         providers += [get_ssl_client_cert_pw_provider(1)]
178
179     auth_baton = Auth(providers)
180     if creds is not None:
181         (user, password) = urllib.splitpasswd(creds)
182         if user is not None:
183             auth_baton.set_parameter(AUTH_PARAM_DEFAULT_USERNAME, user)
184         if password is not None:
185             auth_baton.set_parameter(AUTH_PARAM_DEFAULT_PASSWORD, password)
186     return auth_baton