forked from bobcarroll/WebDAV-Kerberos
/
krb5dav.py
executable file
·132 lines (102 loc) · 4.48 KB
/
krb5dav.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python2.7
# WebDAV-Kerberos - Kerberised WebDAV client library
# Copyright (c) 2013 Bob Carroll (bob.carroll@alum.rit.edu)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import davlib
import kerberos
import Cookie
class Krb5Error(Exception):
def __init__(self, message):
self.message = message
def __str__(self):
return 'Kerberos authentication failed with error: %s' % (self.message, )
class Krb5DAV(davlib.DAV):
def __init__(self, *args, **kwargs):
self.__spn = 'http@%s' % (args[0], )
self.__upn = kwargs.pop('principal') if 'principal' in kwargs else ''
self.__spnego = False
self.__cookies = Cookie.SimpleCookie()
self.__persistauth = False
apply(davlib.DAV.__init__, (self, ) + args, kwargs)
def __probe_mechanisms(self):
if not self.__spnego:
response = davlib.DAV._request(self, 'OPTIONS', '/')
authstr = response.getheader('www-authenticate')
mechs = [s.strip() for s in authstr.split(',')]
self.__spnego = 'Negotiate' in mechs
self.close()
if not self.__spnego:
raise Krb5Error('Server does not support Kerberos authentication')
def __challenge(self, gssctx, blob):
try:
result = kerberos.authGSSClientStep(gssctx, blob)
except kerberos.GSSError as ex:
raise Krb5Error('%s (%s)' % (ex[0][0], ex[1][0]))
except kerberos.KrbError as ex:
raise Krb5Error(ex[0])
if result == kerberos.AUTH_GSS_COMPLETE:
return (True, '')
try:
response = kerberos.authGSSClientResponse(gssctx)
except kerberos.GSSError as ex:
raise Krb5Error('%s (%s)' % (ex[0][0], ex[1][0]))
except kerberos.KrbError as ex:
raise Krb5Error(ex[0])
return (False, response)
def __store_cookies(self, response):
cookiestr = response.getheader('set-cookie')
if not cookiestr is None:
self.__cookies.load(cookiestr)
def __request_authenticate(self, method, url, body, extra_hdrs):
self.__probe_mechanisms()
try:
result, gssctx = kerberos.authGSSClientInit(self.__spn, principal=self.__upn)
except kerberos.GSSError as ex:
raise Krb5Error('%s (%s)' % (ex[0][0], ex[1][0]))
response = None
blob = ''
while True:
try:
result, blob = self.__challenge(gssctx, blob)
except Krb5Error as ex:
kerberos.authGSSClientClean(gssctx)
raise ex
if result:
self.__upn = kerberos.authGSSClientUserName(gssctx)
break
self.close()
extra_hdrs['Authorization'] = 'Negotiate %s' % (blob, )
response = davlib.DAV._request(self, method, url, body, extra_hdrs)
self.__store_cookies(response)
authstr = response.getheader('www-authenticate')
(mech, blob) = authstr.split(' ')
persistauth = response.getheader('persistent-auth')
self.__persistauth = persistauth == 'true'
kerberos.authGSSClientClean(gssctx)
return response
def _request(self, method, url, body=None, extra_hdrs={}):
cookies = Cookie.SimpleCookie()
cookies.load(', '.join([self.__cookies[c].OutputString() for c in self.__cookies]))
if 'Cookie' in extra_hdrs:
cookies.load(extra_hdrs['Cookie'])
if len(cookies) > 0:
extra_hdrs['Cookie'] = ', '.join(['%s=%s' % (c, cookies[c].value) for c in cookies])
if self.__persistauth:
return davlib.DAV._request(self, method, url, body, extra_hdrs)
else:
return self.__request_authenticate(method, url, body, extra_hdrs)
def whoami(self):
return self.__upn