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