Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for specifing an explicit GSSAPI mech #19

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,27 @@ applicable). However, an explicit credential can be in instead, if desired.
>>> r = requests.get("http://example.org", auth=gssapi_auth)
...

Explicit Mechanism
------------------

``HTTPSPNEGOAuth`` normally lets the underlying ``gssapi`` library decide which
negotiation mechanism to use. However, an explicit mechanism can be used instead
if desired. The ``mech`` parameter will be passed straight through to ``gssapi``
without interference. It is expected to be an instance of ``gssapi.mechs.Mechanism``.

.. code-block:: python

>>> import gssapi
>>> import requests
>>> from requests_gssapi import HTTPSPNEGOAuth
>>> try:
... spnego = gssapi,mechs.Mechanism.from_sasl_name("SPNEGO")
... except AttributeError:
... spnego = gssapi.OID.from_int_seq("1.3.6.1.5.5.2")
>>> gssapi_auth = HTTPSPNEGOAuth(mech=spnego)
>>> r = requests.get("http://example.org", auth=gssapi_auth)
...

Delegation
----------

Expand Down
8 changes: 6 additions & 2 deletions requests_gssapi/gssapi_.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,24 @@ class HTTPSPNEGOAuth(AuthBase):
`creds` is GSSAPI credentials (gssapi.Credentials) to use for negotiation.
Default is `None`.

`mech` is GSSAPI Mechanism (gssapi.Mechanism) to use for negotiation.
Default is `None`

`sanitize_mutual_error_response` controls whether we should clean up
server responses. See the `SanitizedResponse` class.

"""
def __init__(self, mutual_authentication=DISABLED, target_name="HTTP",
delegate=False, opportunistic_auth=False, creds=None,
sanitize_mutual_error_response=True):
mech=None, sanitize_mutual_error_response=True):
self.context = {}
self.pos = None
self.mutual_authentication = mutual_authentication
self.target_name = target_name
self.delegate = delegate
self.opportunistic_auth = opportunistic_auth
self.creds = creds
self.mech = mech
self.sanitize_mutual_error_response = sanitize_mutual_error_response

def generate_request_header(self, response, host, is_preemptive=False):
Expand Down Expand Up @@ -140,7 +144,7 @@ def generate_request_header(self, response, host, is_preemptive=False):
self.target_name, gssapi.NameType.hostbased_service)
self.context[host] = gssapi.SecurityContext(
usage="initiate", flags=gssflags, name=self.target_name,
creds=self.creds)
creds=self.creds, mech=self.mech)

gss_stage = "stepping context"
if is_preemptive:
Expand Down
45 changes: 32 additions & 13 deletions test_requests_gssapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def test_generate_request_header(self):
b64_negotiate_response)
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
creds=None, flags=gssflags, usage="initiate")
creds=None, mech=None, flags=gssflags, usage="initiate")
fake_resp.assert_called_with(b"token")

def test_generate_request_header_init_error(self):
Expand All @@ -121,7 +121,7 @@ def test_generate_request_header_init_error(self):
auth.generate_request_header, response, host)
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=None)
usage="initiate", flags=gssflags, creds=None, mech=None)

def test_generate_request_header_step_error(self):
with patch.multiple("gssapi.SecurityContext", __init__=fake_init,
Expand All @@ -135,7 +135,7 @@ def test_generate_request_header_step_error(self):
auth.generate_request_header, response, host)
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=None)
usage="initiate", flags=gssflags, creds=None, mech=None)
fail_resp.assert_called_with(b"token")

def test_authenticate_user(self):
Expand Down Expand Up @@ -172,7 +172,7 @@ def test_authenticate_user(self):
raw.release_conn.assert_called_with()
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
flags=gssflags, usage="initiate", creds=None)
flags=gssflags, usage="initiate", creds=None, mech=None)
fake_resp.assert_called_with(b"token")

def test_handle_401(self):
Expand Down Expand Up @@ -209,7 +209,7 @@ def test_handle_401(self):
raw.release_conn.assert_called_with()
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
creds=None, flags=gssflags, usage="initiate")
creds=None, mech=None, flags=gssflags, usage="initiate")
fake_resp.assert_called_with(b"token")

def test_authenticate_server(self):
Expand Down Expand Up @@ -448,7 +448,7 @@ def test_handle_response_401(self):
raw.release_conn.assert_called_with()
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=None)
usage="initiate", flags=gssflags, creds=None, mech=None)
fake_resp.assert_called_with(b"token")

def test_handle_response_401_rejected(self):
Expand Down Expand Up @@ -491,7 +491,7 @@ def connection_send(self, *args, **kwargs):
raw.release_conn.assert_called_with()
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=None)
usage="initiate", flags=gssflags, creds=None, mech=None)
fake_resp.assert_called_with(b"token")

def test_generate_request_header_custom_service(self):
Expand All @@ -505,7 +505,7 @@ def test_generate_request_header_custom_service(self):
auth.generate_request_header(response, host),
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=None)
usage="initiate", flags=gssflags, creds=None, mech=None)
fake_resp.assert_called_with(b"token")

def test_delegation(self):
Expand Down Expand Up @@ -543,7 +543,7 @@ def test_delegation(self):
raw.release_conn.assert_called_with()
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssdelegflags, creds=None)
usage="initiate", flags=gssdelegflags, creds=None, mech=None)
fake_resp.assert_called_with(b"token")

def test_principal_override(self):
Expand All @@ -561,7 +561,8 @@ def test_principal_override(self):
name=gssapi_name("user@REALM"))
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=b"fake creds")
usage="initiate", flags=gssflags,
creds=b"fake creds", mech=None)

def test_realm_override(self):
with patch.multiple("gssapi.SecurityContext", __init__=fake_init,
Expand All @@ -575,7 +576,7 @@ def test_realm_override(self):
auth.generate_request_header(response, host)
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=None)
usage="initiate", flags=gssflags, creds=None, mech=None)
fake_resp.assert_called_with(b"token")

def test_opportunistic_auth(self):
Expand Down Expand Up @@ -604,7 +605,25 @@ def test_explicit_creds(self):
auth.generate_request_header(response, host)
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=b"fake creds")
usage="initiate", flags=gssflags,
creds=b"fake creds", mech=None)
fake_resp.assert_called_with(b"token")

def test_explicit_mech(self):
with patch.multiple("gssapi.Credentials", __new__=fake_creds), \
patch.multiple("gssapi.SecurityContext", __init__=fake_init,
step=fake_resp):
response = requests.Response()
response.url = "http://www.example.org/"
response.headers = {'www-authenticate': b64_negotiate_token}
host = urlparse(response.url).hostname
fake_mech = b'fake mech'
auth = requests_gssapi.HTTPSPNEGOAuth(mech=fake_mech)
auth.generate_request_header(response, host)
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags,
creds=None, mech=b'fake mech')
fake_resp.assert_called_with(b"token")

def test_target_name(self):
Expand All @@ -619,7 +638,7 @@ def test_target_name(self):
auth.generate_request_header(response, host)
fake_init.assert_called_with(
name=gssapi_name("[email protected]"),
usage="initiate", flags=gssflags, creds=None)
usage="initiate", flags=gssflags, creds=None, mech=None)
fake_resp.assert_called_with(b"token")


Expand Down