Skip to content

Commit 815c857

Browse files
authored
Merge pull request #75 from rbcarson/winkerberos
Replace kerberos-sspi with WinKerberos. Fixes #67.
2 parents fbe27c7 + bc57f3a commit 815c857

File tree

5 files changed

+28
-71
lines changed

5 files changed

+28
-71
lines changed

README.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ whom you last ran ``kinit`` or ``kswitch``, or an SSO credential if
121121
applicable). However, an explicit principal can be specified, which will
122122
cause Kerberos to look for a matching credential cache for the named user.
123123
This feature depends on OS support for collection-type credential caches,
124-
as well as working principal support in pykerberos (it is broken in many
124+
as well as working principal support in PyKerberos (it is broken in many
125125
builds). An explicit principal can be specified with the ``principal`` arg:
126126

127127
.. code-block:: python
@@ -131,10 +131,10 @@ builds). An explicit principal can be specified with the ``principal`` arg:
131131
>>> kerberos_auth = HTTPKerberosAuth(principal="user@REALM")
132132
>>> r = requests.get("http://example.org", auth=kerberos_auth)
133133
...
134-
135-
**Windows users:** Explicit Principal is currently not supported when using
136-
``kerberos-sspi``. Providing a value for ``principal`` in this scenario will raise
137-
``NotImplementedError``.
134+
135+
On Windows, WinKerberos is used instead of PyKerberos. WinKerberos allows the
136+
use of arbitrary principals instead of a credential cache. Passwords can be
137+
specified by following the form ``user@realm:password`` for ``principal``.
138138

139139
Logging
140140
-------

requests_kerberos/kerberos_.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
try:
22
import kerberos
3-
using_kerberos_sspi = False
43
except ImportError:
5-
import kerberos_sspi as kerberos
6-
using_kerberos_sspi = True
4+
import winkerberos as kerberos
75
import re
86
import logging
97

@@ -97,7 +95,6 @@ def __init__(
9795
self.principal = principal
9896
self.hostname_override = hostname_override
9997
self.sanitize_mutual_error_response = sanitize_mutual_error_response
100-
self._using_kerberos_sspi = using_kerberos_sspi
10198

10299
def generate_request_header(self, response, host, is_preemptive=False):
103100
"""
@@ -121,16 +118,9 @@ def generate_request_header(self, response, host, is_preemptive=False):
121118
# w/ name-based HTTP hosting)
122119
kerb_host = self.hostname_override if self.hostname_override is not None else host
123120
kerb_spn = "{0}@{1}".format(self.service, kerb_host)
124-
125-
kwargs = {}
126-
# kerberos-sspi: Never pass principal. Raise if user tries to specify one.
127-
if not self._using_kerberos_sspi:
128-
kwargs['principal'] = self.principal
129-
elif self.principal:
130-
raise NotImplementedError("Can't use 'principal' argument with kerberos-sspi.")
131121

132122
result, self.context[host] = kerberos.authGSSClientInit(kerb_spn,
133-
gssflags=gssflags, **kwargs)
123+
gssflags=gssflags, principal=self.principal)
134124

135125
if result < 1:
136126
raise EnvironmentError(result, kerb_stage)

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
requests>=1.1.0
2-
kerberos-sspi >= 0.2; sys.platform == 'win32'
2+
winkerberos >= 0.5.0; sys.platform == 'win32'
33
pykerberos >= 1.1.8, < 2.0.0; sys.platform != 'win32'

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def get_version():
5151
'requests>=1.1.0',
5252
],
5353
extras_require={
54-
':sys_platform=="win32"': ['kerberos-sspi>=0.2'],
54+
':sys_platform=="win32"': ['winkerberos>=0.5.0'],
5555
':sys_platform!="win32"': ['pykerberos>=1.1.8,<2.0.0'],
5656
},
5757
test_suite='test_requests_kerberos',

test_requests_kerberos.py

Lines changed: 19 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import kerberos
1313
kerberos_module_name='kerberos'
1414
except ImportError:
15-
import kerberos_sspi as kerberos # On Windows
16-
kerberos_module_name='kerberos_sspi'
15+
import winkerberos as kerberos # On Windows
16+
kerberos_module_name = 'winkerberos'
1717

1818
import requests_kerberos
1919
import unittest
@@ -54,12 +54,6 @@ def setUp(self):
5454
clientStep_error.reset_mock()
5555
clientStep_exception.reset_mock()
5656
clientResponse.reset_mock()
57-
58-
# When using kerberos-sspi, we never pass principal to authGSSClientInit().
59-
# This affects our repeated use of assert_called_with().
60-
self.clientInit_default_principal = {'principal': None}
61-
if kerberos_module_name == 'kerberos_sspi':
62-
self.clientInit_default_principal = {}
6357

6458
def tearDown(self):
6559
"""Teardown."""
@@ -126,7 +120,7 @@ def test_generate_request_header(self):
126120
gssflags=(
127121
kerberos.GSS_C_MUTUAL_FLAG |
128122
kerberos.GSS_C_SEQUENCE_FLAG),
129-
**self.clientInit_default_principal)
123+
principal=None)
130124
clientStep_continue.assert_called_with("CTX", "token")
131125
clientResponse.assert_called_with("CTX")
132126

@@ -148,7 +142,7 @@ def test_generate_request_header_init_error(self):
148142
gssflags=(
149143
kerberos.GSS_C_MUTUAL_FLAG |
150144
kerberos.GSS_C_SEQUENCE_FLAG),
151-
**self.clientInit_default_principal)
145+
principal=None)
152146
self.assertFalse(clientStep_continue.called)
153147
self.assertFalse(clientResponse.called)
154148

@@ -170,7 +164,7 @@ def test_generate_request_header_step_error(self):
170164
gssflags=(
171165
kerberos.GSS_C_MUTUAL_FLAG |
172166
kerberos.GSS_C_SEQUENCE_FLAG),
173-
**self.clientInit_default_principal)
167+
principal=None)
174168
clientStep_error.assert_called_with("CTX", "token")
175169
self.assertFalse(clientResponse.called)
176170

@@ -215,7 +209,7 @@ def test_authenticate_user(self):
215209
gssflags=(
216210
kerberos.GSS_C_MUTUAL_FLAG |
217211
kerberos.GSS_C_SEQUENCE_FLAG),
218-
**self.clientInit_default_principal)
212+
principal=None)
219213
clientStep_continue.assert_called_with("CTX", "token")
220214
clientResponse.assert_called_with("CTX")
221215

@@ -260,7 +254,7 @@ def test_handle_401(self):
260254
gssflags=(
261255
kerberos.GSS_C_MUTUAL_FLAG |
262256
kerberos.GSS_C_SEQUENCE_FLAG),
263-
**self.clientInit_default_principal)
257+
principal=None)
264258
clientStep_continue.assert_called_with("CTX", "token")
265259
clientResponse.assert_called_with("CTX")
266260

@@ -501,7 +495,7 @@ def test_handle_response_401(self):
501495
gssflags=(
502496
kerberos.GSS_C_MUTUAL_FLAG |
503497
kerberos.GSS_C_SEQUENCE_FLAG),
504-
**self.clientInit_default_principal)
498+
principal=None)
505499
clientStep_continue.assert_called_with("CTX", "token")
506500
clientResponse.assert_called_with("CTX")
507501

@@ -551,7 +545,7 @@ def connection_send(self, *args, **kwargs):
551545
gssflags=(
552546
kerberos.GSS_C_MUTUAL_FLAG |
553547
kerberos.GSS_C_SEQUENCE_FLAG),
554-
**self.clientInit_default_principal)
548+
principal=None)
555549
clientStep_continue.assert_called_with("CTX", "token")
556550
clientResponse.assert_called_with("CTX")
557551

@@ -571,7 +565,7 @@ def test_generate_request_header_custom_service(self):
571565
gssflags=(
572566
kerberos.GSS_C_MUTUAL_FLAG |
573567
kerberos.GSS_C_SEQUENCE_FLAG),
574-
**self.clientInit_default_principal)
568+
principal=None)
575569

576570
def test_delegation(self):
577571
with patch.multiple(kerberos_module_name,
@@ -615,7 +609,7 @@ def test_delegation(self):
615609
kerberos.GSS_C_MUTUAL_FLAG |
616610
kerberos.GSS_C_SEQUENCE_FLAG |
617611
kerberos.GSS_C_DELEG_FLAG),
618-
**self.clientInit_default_principal
612+
principal=None
619613
)
620614
clientStep_continue.assert_called_with("CTX", "token")
621615
clientResponse.assert_called_with("CTX")
@@ -630,18 +624,13 @@ def test_principal_override(self):
630624
response.headers = {'www-authenticate': 'negotiate token'}
631625
host = urlparse(response.url).hostname
632626
auth = requests_kerberos.HTTPKerberosAuth(principal="user@REALM")
633-
try:
634-
auth.generate_request_header(response, host)
635-
clientInit_complete.assert_called_with(
636-
"HTTP@www.example.org",
637-
gssflags=(
638-
kerberos.GSS_C_MUTUAL_FLAG |
639-
kerberos.GSS_C_SEQUENCE_FLAG),
640-
principal="user@REALM")
641-
except NotImplementedError:
642-
# principal is not supported with kerberos-sspi.
643-
if not auth._using_kerberos_sspi:
644-
raise
627+
auth.generate_request_header(response, host)
628+
clientInit_complete.assert_called_with(
629+
"HTTP@www.example.org",
630+
gssflags=(
631+
kerberos.GSS_C_MUTUAL_FLAG |
632+
kerberos.GSS_C_SEQUENCE_FLAG),
633+
principal="user@REALM")
645634

646635
def test_realm_override(self):
647636
with patch.multiple(kerberos_module_name,
@@ -659,29 +648,7 @@ def test_realm_override(self):
659648
gssflags=(
660649
kerberos.GSS_C_MUTUAL_FLAG |
661650
kerberos.GSS_C_SEQUENCE_FLAG),
662-
**self.clientInit_default_principal)
663-
664-
def test_kerberos_sspi_reject_principal(self):
665-
with patch.multiple(kerberos_module_name,
666-
authGSSClientInit=clientInit_complete,
667-
authGSSClientResponse=clientResponse,
668-
authGSSClientStep=clientStep_continue):
669-
response = requests.Response()
670-
response.url = "http://www.example.org/"
671-
host = urlparse(response.url).hostname
672-
673-
auth = requests_kerberos.HTTPKerberosAuth(principal="user@REALM")
674-
auth._using_kerberos_sspi = True
675-
self.assertRaises(NotImplementedError, auth.generate_request_header, response, host)
676-
677-
auth = requests_kerberos.HTTPKerberosAuth(principal=None)
678-
auth._using_kerberos_sspi = True
679-
auth.generate_request_header(response, host)
680-
clientInit_complete.assert_called_with(
681-
"HTTP@www.example.org",
682-
gssflags=(
683-
kerberos.GSS_C_MUTUAL_FLAG |
684-
kerberos.GSS_C_SEQUENCE_FLAG))
651+
principal=None)
685652

686653

687654
if __name__ == '__main__':

0 commit comments

Comments
 (0)