~bzr-pqm/bzr/bzr.dev

5247.1.4 by Vincent Ladeuil
Merge cleanup into first-try
1
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
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 2 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, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
16
17
"""Support for secure authentication using GSSAPI over FTP.
18
19
See RFC2228 for details.
20
"""
21
5270.1.3 by Jelmer Vernooij
Remove unused imports, lazily load kerberos python module.
22
import base64, ftplib
3331.2.11 by Jelmer Vernooij
Review comments from Martin.
23
3331.2.6 by Jelmer Vernooij
Fix formatting, check for completeness of kerberos functions.
24
from bzrlib import (
25
    errors,
26
    )
4695.5.8 by Martin Pool
Remove more trace.info uses
27
from bzrlib.trace import mutter
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
28
from bzrlib.transport.ftp import FtpTransport
29
30
try:
31
    import kerberos
32
except ImportError, e:
33
    mutter('failed to import kerberos lib: %s', e)
34
    raise errors.DependencyNotPresent('kerberos', e)
35
3331.2.6 by Jelmer Vernooij
Fix formatting, check for completeness of kerberos functions.
36
if getattr(kerberos, "authGSSClientWrap", None) is None:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
37
    raise errors.DependencyNotPresent('kerberos',
3649.3.3 by Jelmer Vernooij
Review feedback from John.
38
        "missing encryption function authGSSClientWrap")
3331.2.6 by Jelmer Vernooij
Fix formatting, check for completeness of kerberos functions.
39
3331.2.11 by Jelmer Vernooij
Review comments from Martin.
40
41
class GSSAPIFtp(ftplib.FTP):
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
42
    """Extended version of ftplib.FTP that can authenticate using GSSAPI."""
3331.2.11 by Jelmer Vernooij
Review comments from Martin.
43
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
44
    def mic_putcmd(self, line):
3763.2.1 by Jelmer Vernooij
Remove use of optional parameter in GSSAPI FTP support since it breaks newer versions of Python-Kerberos.
45
        rc = kerberos.authGSSClientWrap(self.vc, base64.b64encode(line))
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
46
        wrapped = kerberos.authGSSClientResponse(self.vc)
47
        ftplib.FTP.putcmd(self, "MIC " + wrapped)
48
3331.2.7 by Jelmer Vernooij
Fix handling of multilines.
49
    def mic_getline(self):
50
        resp = ftplib.FTP.getline(self)
3331.2.10 by Jelmer Vernooij
Review feedback from Vincent.
51
        if resp[:4] != '631 ':
52
            raise AssertionError
3331.2.7 by Jelmer Vernooij
Fix handling of multilines.
53
        rc = kerberos.authGSSClientUnwrap(self.vc, resp[4:].strip("\r\n"))
3331.2.6 by Jelmer Vernooij
Fix formatting, check for completeness of kerberos functions.
54
        response = base64.b64decode(kerberos.authGSSClientResponse(self.vc))
55
        return response
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
56
3331.2.7 by Jelmer Vernooij
Fix handling of multilines.
57
    def gssapi_login(self, user):
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
58
        # Try GSSAPI login first
3649.3.3 by Jelmer Vernooij
Review feedback from John.
59
60
        # Used FTP response codes:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
61
        # 235 [ADAT=base64data] - indicates that the security data exchange
3649.3.3 by Jelmer Vernooij
Review feedback from John.
62
        #     completed successfully.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
63
        # 334 [ADAT=base64data] - indicates that the requested security
64
        #     mechanism is ok, and includes security data to be used by the
3649.3.3 by Jelmer Vernooij
Review feedback from John.
65
        #     client to construct the next command.
66
        # 335 [ADAT=base64data] - indicates that the security data is
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
67
        #     acceptable, and more is required to complete the security
3649.3.3 by Jelmer Vernooij
Review feedback from John.
68
        #     data exchange.
69
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
70
        resp = self.sendcmd('AUTH GSSAPI')
3649.3.5 by Jelmer Vernooij
use startswith.
71
        if resp.startswith('334 '):
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
72
            rc, self.vc = kerberos.authGSSClientInit("ftp@%s" % self.host)
3331.2.7 by Jelmer Vernooij
Fix handling of multilines.
73
            if kerberos.authGSSClientStep(self.vc, "") != 1:
3649.3.5 by Jelmer Vernooij
use startswith.
74
                while resp[:4] in ('334 ', '335 '):
3331.2.7 by Jelmer Vernooij
Fix handling of multilines.
75
                    authdata = kerberos.authGSSClientResponse(self.vc)
76
                    resp = self.sendcmd('ADAT ' + authdata)
77
                    if resp[:9] in ('235 ADAT=', '335 ADAT='):
78
                        rc = kerberos.authGSSClientStep(self.vc, resp[9:])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
79
                        if not ((resp.startswith('235 ') and rc == 1) or
3649.3.5 by Jelmer Vernooij
use startswith.
80
                                (resp.startswith('335 ') and rc == 0)):
3649.3.3 by Jelmer Vernooij
Review feedback from John.
81
                            raise ftplib.error_reply, resp
4695.5.8 by Martin Pool
Remove more trace.info uses
82
            trace.note("Authenticated as %s" % kerberos.authGSSClientUserName(
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
83
                    self.vc))
3331.2.7 by Jelmer Vernooij
Fix handling of multilines.
84
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
85
            # Monkey patch ftplib
86
            self.putcmd = self.mic_putcmd
3331.2.7 by Jelmer Vernooij
Fix handling of multilines.
87
            self.getline = self.mic_getline
88
            self.sendcmd('USER ' + user)
89
            return resp
3331.2.11 by Jelmer Vernooij
Review comments from Martin.
90
        mutter("Unable to use GSSAPI authentication: %s", resp)
91
92
93
class GSSAPIFtpTransport(FtpTransport):
3649.3.3 by Jelmer Vernooij
Review feedback from John.
94
    """FTP transport implementation that will try to use GSSAPI authentication.
95
96
    """
97
4725.3.3 by Vincent Ladeuil
Fix test failure at the root without cleaning up ftp APPE.
98
    connection_class = GSSAPIFtp
99
100
    def _login(self, connection, auth, user, password):
101
        """Login with GSSAPI Authentication.
102
103
        The password is used if GSSAPI Authentication is not available.
3331.2.11 by Jelmer Vernooij
Review comments from Martin.
104
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
105
        The username and password can both be None, in which case the
106
        credentials specified in the URL or provided by the
3331.2.11 by Jelmer Vernooij
Review comments from Martin.
107
        AuthenticationConfig() are used.
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
108
        """
109
        try:
4725.3.3 by Vincent Ladeuil
Fix test failure at the root without cleaning up ftp APPE.
110
            connection.gssapi_login(user=user)
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
111
        except ftplib.error_perm, e:
4725.3.3 by Vincent Ladeuil
Fix test failure at the root without cleaning up ftp APPE.
112
            super(GSSAPIFtpTransport, self)._login(connection, auth,
113
                                                   user, password)
3331.2.4 by Jelmer Vernooij
Move GSSAPI support to a separate file.
114
115
116
def get_test_permutations():
117
    """Return the permutations to be used in testing."""
4167.1.3 by Vincent Ladeuil
Fix GSSAPIFtpTransport tests when no FTP test server is available
118
    from bzrlib.tests import ftp_server
119
    if ftp_server.FTPServerFeature.available():
3508.1.23 by Vincent Ladeuil
Fix as per Martin's review.
120
        return [(GSSAPIFtpTransport, ftp_server.FTPTestServer)]
3331.2.8 by Jelmer Vernooij
Run regular FTP tests against SecureFTP transport.
121
    else:
3331.2.10 by Jelmer Vernooij
Review feedback from Vincent.
122
        return []