Skip to content

Commit f49c359

Browse files
Add HTTPSPNEGOAuth (and retain HTTPKerberosAuth as a shim)
Signed-off-by: Robbie Harwood <rharwood@redhat.com> Resolves: #1
1 parent 66fb4a9 commit f49c359

File tree

5 files changed

+57
-54
lines changed

5 files changed

+57
-54
lines changed

README.rst

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ authentication. Basic GET usage:
99
.. code-block:: python
1010
1111
>>> import requests
12-
>>> from requests_gssapi import HTTPKerberosAuth
13-
>>> r = requests.get("http://example.org", auth=HTTPKerberosAuth())
12+
>>> from requests_gssapi import HTTPSPNEGOAuth
13+
>>> r = requests.get("http://example.org", auth=HTTPSPNEGOAuth())
1414
...
1515
1616
The entire ``requests.api`` should be supported.
@@ -27,7 +27,7 @@ Mutual Authentication
2727
REQUIRED
2828
^^^^^^^^
2929

30-
By default, ``HTTPKerberosAuth`` will require mutual authentication from the
30+
By default, ``HTTPSPNEGOAuth`` will require mutual authentication from the
3131
server, and if a server emits a non-error response which cannot be
3232
authenticated, a ``requests_gssapi.errors.MutualAuthenticationError`` will
3333
be raised. If a server emits an error which cannot be authenticated, it will
@@ -39,8 +39,8 @@ setting ``sanitize_mutual_error_response=False``:
3939
.. code-block:: python
4040
4141
>>> import requests
42-
>>> from requests_gssapi import HTTPKerberosAuth, REQUIRED
43-
>>> gssapi_auth = HTTPKerberosAuth(mutual_authentication=REQUIRED, sanitize_mutual_error_response=False)
42+
>>> from requests_gssapi import HTTPSPNEGOAuth, REQUIRED
43+
>>> gssapi_auth = HTTPSPNEGOAuth(mutual_authentication=REQUIRED, sanitize_mutual_error_response=False)
4444
>>> r = requests.get("https://windows.example.org/wsman", auth=gssapi_auth)
4545
...
4646
@@ -49,13 +49,13 @@ OPTIONAL
4949
^^^^^^^^
5050

5151
If you'd prefer to not require mutual authentication, you can set your
52-
preference when constructing your ``HTTPKerberosAuth`` object:
52+
preference when constructing your ``HTTPSPNEGOAuth`` object:
5353

5454
.. code-block:: python
5555
5656
>>> import requests
57-
>>> from requests_gssapi import HTTPKerberosAuth, OPTIONAL
58-
>>> gssapi_auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL)
57+
>>> from requests_gssapi import HTTPSPNEGOAuth, OPTIONAL
58+
>>> gssapi_auth = HTTPSPNEGOAuth(mutual_authentication=OPTIONAL)
5959
>>> r = requests.get("http://example.org", auth=gssapi_auth)
6060
...
6161
@@ -72,15 +72,15 @@ authentication, you can do that as well:
7272
.. code-block:: python
7373
7474
>>> import requests
75-
>>> from requests_gssapi import HTTPKerberosAuth, DISABLED
76-
>>> gssapi_auth = HTTPKerberosAuth(mutual_authentication=DISABLED)
75+
>>> from requests_gssapi import HTTPSPNEGOAuth, DISABLED
76+
>>> gssapi_auth = HTTPSPNEGOAuth(mutual_authentication=DISABLED)
7777
>>> r = requests.get("http://example.org", auth=gssapi_auth)
7878
...
7979
8080
Preemptive Authentication
8181
-------------------------
8282

83-
``HTTPKerberosAuth`` can be forced to preemptively initiate the GSSAPI
83+
``HTTPSPNEGOAuth`` can be forced to preemptively initiate the GSSAPI
8484
exchange and present a token on the initial request (and all
8585
subsequent). By default, authentication only occurs after a
8686
``401 Unauthorized`` response containing a Negotiate challenge
@@ -92,8 +92,8 @@ behavior can be altered by setting ``force_preemptive=True``:
9292
.. code-block:: python
9393
9494
>>> import requests
95-
>>> from requests_gssapi import HTTPKerberosAuth, REQUIRED
96-
>>> gssapi_auth = HTTPKerberosAuth(mutual_authentication=REQUIRED, force_preemptive=True)
95+
>>> from requests_gssapi import HTTPSPNEGOAuth, REQUIRED
96+
>>> gssapi_auth = HTTPSPNEGOAuth(mutual_authentication=REQUIRED, force_preemptive=True)
9797
>>> r = requests.get("https://windows.example.org/wsman", auth=gssapi_auth)
9898
...
9999
@@ -108,15 +108,15 @@ setting the ``hostname_override`` arg:
108108
.. code-block:: python
109109
110110
>>> import requests
111-
>>> from requests_gssapi import HTTPKerberosAuth, REQUIRED
112-
>>> gssapi_auth = HTTPKerberosAuth(hostname_override="internalhost.local")
113-
>>> r = requests.get("https://externalhost.example.org/", auth=kerberos_auth)
111+
>>> from requests_gssapi import HTTPSPNEGOAuth, REQUIRED
112+
>>> gssapi_auth = HTTPSPNEGOAuth(hostname_override="internalhost.local")
113+
>>> r = requests.get("https://externalhost.example.org/", auth=gssapi_auth)
114114
...
115115
116116
Explicit Principal
117117
------------------
118118

119-
``HTTPKerberosAuth`` normally uses the default principal (ie, the user for
119+
``HTTPSPNEGOAuth`` normally uses the default principal (ie, the user for
120120
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 GSSAPI to look for a matching credential cache for the named user.
@@ -126,8 +126,8 @@ An explicit principal can be specified with the ``principal`` arg:
126126
.. code-block:: python
127127
128128
>>> import requests
129-
>>> from requests_gssapi import HTTPKerberosAuth, REQUIRED
130-
>>> gssapi_auth = HTTPKerberosAuth(principal="user@REALM")
129+
>>> from requests_gssapi import HTTPSPNEGOAuth, REQUIRED
130+
>>> gssapi_auth = HTTPSPNEGOAuth(principal="user@REALM")
131131
>>> r = requests.get("http://example.org", auth=gssapi_auth)
132132
...
133133
@@ -136,13 +136,13 @@ Delegation
136136

137137
``requests_gssapi`` supports credential delegation (``GSS_C_DELEG_FLAG``).
138138
To enable delegation of credentials to a server that requests delegation, pass
139-
``delegate=True`` to ``HTTPKerberosAuth``:
139+
``delegate=True`` to ``HTTPSPNEGOAuth``:
140140

141141
.. code-block:: python
142142
143143
>>> import requests
144-
>>> from requests_gssapi import HTTPKerberosAuth
145-
>>> r = requests.get("http://example.org", auth=HTTPKerberosAuth(delegate=True))
144+
>>> from requests_gssapi import HTTPSPNEGOAuth
145+
>>> r = requests.get("http://example.org", auth=HTTPSPNEGOAuth(delegate=True))
146146
...
147147
148148
Be careful to only allow delegation to servers you trust as they will be able

requests_gssapi/__init__.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,22 @@
77
authentication. Basic GET usage:
88
99
>>> import requests
10-
>>> from requests_gssapi import HTTPKerberosAuth
11-
>>> r = requests.get("http://example.org", auth=HTTPKerberosAuth())
10+
>>> from requests_gssapi import HTTPSPNEGOAuth
11+
>>> r = requests.get("http://example.org", auth=HTTPSPNEGOAuth())
1212
1313
The entire `requests.api` should be supported.
1414
"""
1515
import logging
1616

17-
from .gssapi_ import HTTPKerberosAuth, REQUIRED, OPTIONAL, DISABLED
17+
from .gssapi_ import HTTPSPNEGOAuth, REQUIRED, OPTIONAL, DISABLED
1818
from .exceptions import MutualAuthenticationError
1919
from .compat import NullHandler
2020

2121
logging.getLogger(__name__).addHandler(NullHandler())
2222

23-
__all__ = ('HTTPKerberosAuth', 'MutualAuthenticationError', 'REQUIRED',
24-
'OPTIONAL', 'DISABLED')
23+
""" Deprecated compatability shim """
24+
HTTPKerberosAuth = HTTPSPNEGOAuth
25+
26+
__all__ = ('HTTPKerberosAuth', 'HTTPSNPEGOAuth', 'MutualAuthenticationError',
27+
'REQUIRED', 'OPTIONAL', 'DISABLED')
2528
__version__ = '0.11.0'

requests_gssapi/gssapi_.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def _negotiate_value(response):
7878
return None
7979

8080

81-
class HTTPKerberosAuth(AuthBase):
81+
class HTTPSPNEGOAuth(AuthBase):
8282
"""Attaches HTTP GSSAPI Authentication to the given Request object."""
8383
def __init__(self, mutual_authentication=REQUIRED, service="HTTP",
8484
delegate=False, force_preemptive=False, principal=None,
@@ -292,7 +292,7 @@ def __call__(self, request):
292292
is_preemptive=True)
293293

294294
log.debug(
295-
"HTTPKerberosAuth: Preemptive Authorization header: {0}"
295+
"HTTPSPNEGOAuth: Preemptive Authorization header: {0}"
296296
.format(auth_header))
297297

298298
request.headers['Authorization'] = auth_header
@@ -301,7 +301,7 @@ def __call__(self, request):
301301
try:
302302
self.pos = request.body.tell()
303303
except AttributeError:
304-
# In the case of HTTPKerberosAuth being reused and the body
304+
# In the case of HTTPSPNEGOAuth being reused and the body
305305
# of the previous request was a file-like object, pos has
306306
# the file position of the previous body. Ensure it's set to
307307
# None.

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def get_version():
4242
long_description=long_desc,
4343
author='Ian Cordasco, Cory Benfield, Michael Komitee, Robbie Harwood',
4444
author_email='rharwood@redhat.com',
45-
url='https://github.com/frozencemetery/requests-gssapi',
45+
url='https://github.com/pythongssapi/requests-gssapi',
4646
packages=['requests_gssapi'],
4747
package_data={'': ['LICENSE', 'AUTHORS']},
4848
include_package_data=True,

test_requests_gssapi.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_negotate_value_extraction_none(self):
5959
def test_force_preemptive(self):
6060
with patch.multiple("gssapi.SecurityContext", __init__=fake_init,
6161
step=fake_resp):
62-
auth = requests_gssapi.HTTPKerberosAuth(force_preemptive=True)
62+
auth = requests_gssapi.HTTPSPNEGOAuth(force_preemptive=True)
6363

6464
request = requests.Request(url="http://www.example.org")
6565

@@ -72,7 +72,7 @@ def test_force_preemptive(self):
7272
def test_no_force_preemptive(self):
7373
with patch.multiple("gssapi.SecurityContext", __init__=fake_init,
7474
step=fake_resp):
75-
auth = requests_gssapi.HTTPKerberosAuth()
75+
auth = requests_gssapi.HTTPSPNEGOAuth()
7676

7777
request = requests.Request(url="http://www.example.org")
7878

@@ -87,7 +87,7 @@ def test_generate_request_header(self):
8787
response.url = "http://www.example.org/"
8888
response.headers = {'www-authenticate': 'negotiate token'}
8989
host = urlparse(response.url).hostname
90-
auth = requests_gssapi.HTTPKerberosAuth()
90+
auth = requests_gssapi.HTTPSPNEGOAuth()
9191
self.assertEqual(
9292
auth.generate_request_header(response, host),
9393
"Negotiate GSSRESPONSE")
@@ -103,7 +103,7 @@ def test_generate_request_header_init_error(self):
103103
response.url = "http://www.example.org/"
104104
response.headers = {'www-authenticate': 'negotiate token'}
105105
host = urlparse(response.url).hostname
106-
auth = requests_gssapi.HTTPKerberosAuth()
106+
auth = requests_gssapi.HTTPSPNEGOAuth()
107107
self.assertRaises(requests_gssapi.exceptions.KerberosExchangeError,
108108
auth.generate_request_header, response, host)
109109
fake_init.assert_called_with(
@@ -117,7 +117,7 @@ def test_generate_request_header_step_error(self):
117117
response.url = "http://www.example.org/"
118118
response.headers = {'www-authenticate': 'negotiate token'}
119119
host = urlparse(response.url).hostname
120-
auth = requests_gssapi.HTTPKerberosAuth()
120+
auth = requests_gssapi.HTTPSPNEGOAuth()
121121
self.assertRaises(requests_gssapi.exceptions.KerberosExchangeError,
122122
auth.generate_request_header, response, host)
123123
fake_init.assert_called_with(
@@ -148,7 +148,7 @@ def test_authenticate_user(self):
148148
response.connection = connection
149149
response._content = ""
150150
response.raw = raw
151-
auth = requests_gssapi.HTTPKerberosAuth()
151+
auth = requests_gssapi.HTTPSPNEGOAuth()
152152
r = auth.authenticate_user(response)
153153

154154
self.assertTrue(response in r.history)
@@ -185,7 +185,7 @@ def test_handle_401(self):
185185
response.connection = connection
186186
response._content = ""
187187
response.raw = raw
188-
auth = requests_gssapi.HTTPKerberosAuth()
188+
auth = requests_gssapi.HTTPSPNEGOAuth()
189189
r = auth.handle_401(response)
190190

191191
self.assertTrue(response in r.history)
@@ -209,7 +209,7 @@ def test_authenticate_server(self):
209209
'www-authenticate': 'negotiate servertoken',
210210
'authorization': 'Negotiate GSSRESPONSE'}
211211

212-
auth = requests_gssapi.HTTPKerberosAuth()
212+
auth = requests_gssapi.HTTPSPNEGOAuth()
213213
auth.context = {"www.example.org": gssapi.SecurityContext}
214214
result = auth.authenticate_server(response_ok)
215215

@@ -226,7 +226,7 @@ def test_handle_other(self):
226226
'www-authenticate': 'negotiate servertoken',
227227
'authorization': 'Negotiate GSSRESPONSE'}
228228

229-
auth = requests_gssapi.HTTPKerberosAuth()
229+
auth = requests_gssapi.HTTPSPNEGOAuth()
230230
auth.context = {"www.example.org": gssapi.SecurityContext}
231231

232232
r = auth.handle_other(response_ok)
@@ -244,7 +244,7 @@ def test_handle_response_200(self):
244244
'www-authenticate': 'negotiate servertoken',
245245
'authorization': 'Negotiate GSSRESPONSE'}
246246

247-
auth = requests_gssapi.HTTPKerberosAuth()
247+
auth = requests_gssapi.HTTPSPNEGOAuth()
248248
auth.context = {"www.example.org": gssapi.SecurityContext}
249249

250250
r = auth.handle_response(response_ok)
@@ -261,7 +261,7 @@ def test_handle_response_200_mutual_auth_required_failure(self):
261261
response_ok.status_code = 200
262262
response_ok.headers = {}
263263

264-
auth = requests_gssapi.HTTPKerberosAuth()
264+
auth = requests_gssapi.HTTPSPNEGOAuth()
265265
auth.context = {"www.example.org": "CTX"}
266266

267267
self.assertRaises(requests_gssapi.MutualAuthenticationError,
@@ -279,7 +279,7 @@ def test_handle_response_200_mutual_auth_required_failure_2(self):
279279
'www-authenticate': 'negotiate servertoken',
280280
'authorization': 'Negotiate GSSRESPONSE'}
281281

282-
auth = requests_gssapi.HTTPKerberosAuth()
282+
auth = requests_gssapi.HTTPSPNEGOAuth()
283283
auth.context = {"www.example.org": gssapi.SecurityContext}
284284

285285
self.assertRaises(requests_gssapi.MutualAuthenticationError,
@@ -297,7 +297,7 @@ def test_handle_response_200_mutual_auth_optional_hard_failure(self):
297297
'www-authenticate': 'negotiate servertoken',
298298
'authorization': 'Negotiate GSSRESPONSE'}
299299

300-
auth = requests_gssapi.HTTPKerberosAuth(
300+
auth = requests_gssapi.HTTPSPNEGOAuth(
301301
requests_gssapi.OPTIONAL)
302302
auth.context = {"www.example.org": gssapi.SecurityContext}
303303

@@ -313,7 +313,7 @@ def test_handle_response_200_mutual_auth_optional_soft_failure(self):
313313
response_ok.url = "http://www.example.org/"
314314
response_ok.status_code = 200
315315

316-
auth = requests_gssapi.HTTPKerberosAuth(
316+
auth = requests_gssapi.HTTPSPNEGOAuth(
317317
requests_gssapi.OPTIONAL)
318318
auth.context = {"www.example.org": gssapi.SecurityContext}
319319

@@ -337,7 +337,7 @@ def test_handle_response_500_mutual_auth_required_failure(self):
337337
response_500.raw = "RAW"
338338
response_500.cookies = "COOKIES"
339339

340-
auth = requests_gssapi.HTTPKerberosAuth()
340+
auth = requests_gssapi.HTTPSPNEGOAuth()
341341
auth.context = {"www.example.org": "CTX"}
342342

343343
r = auth.handle_response(response_500)
@@ -358,7 +358,7 @@ def test_handle_response_500_mutual_auth_required_failure(self):
358358
self.assertFalse(fail_resp.called)
359359

360360
# re-test with error response sanitizing disabled
361-
auth = requests_gssapi.HTTPKerberosAuth(
361+
auth = requests_gssapi.HTTPSPNEGOAuth(
362362
sanitize_mutual_error_response=False)
363363
auth.context = {"www.example.org": "CTX"}
364364

@@ -381,7 +381,7 @@ def test_handle_response_500_mutual_auth_optional_failure(self):
381381
response_500.raw = "RAW"
382382
response_500.cookies = "COOKIES"
383383

384-
auth = requests_gssapi.HTTPKerberosAuth(
384+
auth = requests_gssapi.HTTPSPNEGOAuth(
385385
requests_gssapi.OPTIONAL)
386386
auth.context = {"www.example.org": "CTX"}
387387

@@ -416,7 +416,7 @@ def test_handle_response_401(self):
416416
response._content = ""
417417
response.raw = raw
418418

419-
auth = requests_gssapi.HTTPKerberosAuth()
419+
auth = requests_gssapi.HTTPSPNEGOAuth()
420420
auth.handle_other = Mock(return_value=response_ok)
421421

422422
r = auth.handle_response(response)
@@ -462,7 +462,7 @@ def connection_send(self, *args, **kwargs):
462462
response._content = ""
463463
response.raw = raw
464464

465-
auth = requests_gssapi.HTTPKerberosAuth()
465+
auth = requests_gssapi.HTTPSPNEGOAuth()
466466

467467
r = auth.handle_response(response)
468468

@@ -483,7 +483,7 @@ def test_generate_request_header_custom_service(self):
483483
response.url = "http://www.example.org/"
484484
response.headers = {'www-authenticate': 'negotiate token'}
485485
host = urlparse(response.url).hostname
486-
auth = requests_gssapi.HTTPKerberosAuth(service="barfoo")
486+
auth = requests_gssapi.HTTPSPNEGOAuth(service="barfoo")
487487
auth.generate_request_header(response, host),
488488
fake_init.assert_called_with(
489489
name=gssapi.Name("barfoo@www.example.org"),
@@ -513,7 +513,7 @@ def test_delegation(self):
513513
response.connection = connection
514514
response._content = ""
515515
response.raw = raw
516-
auth = requests_gssapi.HTTPKerberosAuth(1, "HTTP", True)
516+
auth = requests_gssapi.HTTPSPNEGOAuth(1, "HTTP", True)
517517
r = auth.authenticate_user(response)
518518

519519
self.assertTrue(response in r.history)
@@ -535,7 +535,7 @@ def test_principal_override(self):
535535
response.url = "http://www.example.org/"
536536
response.headers = {'www-authenticate': 'negotiate token'}
537537
host = urlparse(response.url).hostname
538-
auth = requests_gssapi.HTTPKerberosAuth(principal="user@REALM")
538+
auth = requests_gssapi.HTTPSPNEGOAuth(principal="user@REALM")
539539
auth.generate_request_header(response, host)
540540
fake_creds.assert_called_with(gssapi.creds.Credentials,
541541
usage="initiate",
@@ -552,7 +552,7 @@ def test_realm_override(self):
552552
response.url = "http://www.example.org/"
553553
response.headers = {'www-authenticate': 'negotiate token'}
554554
host = urlparse(response.url).hostname
555-
auth = requests_gssapi.HTTPKerberosAuth(
555+
auth = requests_gssapi.HTTPSPNEGOAuth(
556556
hostname_override="otherhost.otherdomain.org")
557557
auth.generate_request_header(response, host)
558558
fake_init.assert_called_with(

0 commit comments

Comments
 (0)