Skip to content

Commit 1dcb5b9

Browse files
committed
Implement support for GSSAPI extension RFC 4178
RFC 4178 provides two support API calls that enable the caller to manipulate the set of acceptable security mechanisms used in SPNEGO protocol; for the given credentials, the gss_get_neg_mechs call is used to indicate the current set of security mechanisms available for negotiation, and the gss_set_neg_mechs call is used to specify the set of security mechanisms avaiable for negotiation. Since gss_get_neg_mechs is not implemented by MIT krb5, we are only implementing the raw interface for the latter call. Note that although RFC 4178 did not specify that the mech_set argument cannot be an empty set, we are forcing it to be non empty in the low-level API here since passing an empty set will always trigger an error in MIT krb5 implementation.
1 parent b6efe72 commit 1dcb5b9

File tree

4 files changed

+122
-0
lines changed

4 files changed

+122
-0
lines changed

gssapi/raw/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
except ImportError:
7070
pass
7171

72+
# optional RFC 4178 support
73+
try:
74+
from gssapi.raw.ext_rfc4178 import * # noqa
75+
except ImportError:
76+
pass
77+
7278
# optional RFC 5587 support
7379
try:
7480
from gssapi.raw.ext_rfc5587 import * # noqa

gssapi/raw/ext_rfc4178.pyx

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
GSSAPI="BASE" # This ensures that a full module is generated by Cython
2+
3+
from gssapi.raw.cython_types cimport *
4+
from gssapi.raw.cython_converters cimport c_get_mech_oid_set
5+
from gssapi.raw.creds cimport Creds
6+
7+
from gssapi.raw.misc import GSSError
8+
9+
cdef extern from "python_gssapi_ext.h":
10+
OM_uint32 gss_set_neg_mechs(
11+
OM_uint32 *minor_status,
12+
gss_cred_id_t cred_handle,
13+
const gss_OID_set mech_set) nogil
14+
15+
16+
def set_neg_mechs(Creds cred_handle not None, mech_set not None):
17+
"""
18+
set_neg_mechs(cred_handle not None, mech_set not None)
19+
20+
Specify the set of security mechanisms that may be negotiated with
21+
the credential identified by cred_handle.
22+
If more than one mechanism is specified in mech_set, the order in
23+
which those mechanisms are specified implies a relative preference.
24+
25+
Args:
26+
cred_handle (Creds): credentials to set negotiable mechanisms for
27+
mech_set ([MechType]): negotiable mechanisms to be set
28+
Returns:
29+
None
30+
Raises:
31+
GSSError
32+
"""
33+
34+
cdef gss_OID_set negotiable_mechs = c_get_mech_oid_set(mech_set)
35+
36+
cdef OM_uint32 maj_stat, min_stat
37+
38+
with nogil:
39+
maj_stat = gss_set_neg_mechs(&min_stat, cred_handle.raw_creds,
40+
negotiable_mechs)
41+
42+
cdef OM_uint32 tmp_min_stat
43+
gss_release_oid_set(&tmp_min_stat, &negotiable_mechs)
44+
45+
if maj_stat == GSS_S_COMPLETE:
46+
return None
47+
else:
48+
raise GSSError(maj_stat, min_stat)

gssapi/tests/test_raw.py

+67
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,73 @@ def test_sasl_names(self):
772772
cmp_mech.shouldnt_be_none()
773773
cmp_mech.should_be(mech)
774774

775+
@ktu.gssapi_extension_test('rfc4178', 'Negotiation Mechanism')
776+
def test_set_neg_mechs(self):
777+
all_mechs = gb.indicate_mechs()
778+
spnego_mech = gb.OID.from_int_seq("1.3.6.1.5.5.2")
779+
krb5_mech = gb.OID.from_int_seq("1.2.840.113554.1.2.2")
780+
ntlm_mech = gb.OID.from_int_seq("1.3.6.1.4.1.311.2.2.10")
781+
782+
server_name = gb.import_name(TARGET_SERVICE_NAME,
783+
gb.NameType.hostbased_service)
784+
785+
username = gb.import_name(name=b"user",
786+
name_type=gb.NameType.user)
787+
krb5_client_creds = gb.acquire_cred(
788+
None, usage='initiate',
789+
mechs=[krb5_mech, spnego_mech]).creds
790+
try:
791+
ntlm_client_creds = gb.acquire_cred_with_password(
792+
name=username,
793+
password=b'password',
794+
mechs=[ntlm_mech, spnego_mech]).creds
795+
except gb.GSSError:
796+
self.skipTest('You do not have the GSSAPI gss-ntlmssp mech '
797+
'installed')
798+
799+
server_creds = gb.acquire_cred(server_name, usage='accept',
800+
mechs=all_mechs).creds
801+
802+
neg_resp = gb.set_neg_mechs(server_creds, [ntlm_mech])
803+
neg_resp.should_be_none()
804+
805+
client_ctx_resp = gb.init_sec_context(server_name,
806+
creds=ntlm_client_creds,
807+
mech=spnego_mech)
808+
client_token = client_ctx_resp.token
809+
810+
server_ctx_resp = gb.accept_sec_context(client_token,
811+
acceptor_creds=server_creds)
812+
server_ctx_resp.shouldnt_be_none()
813+
814+
client_ctx_resp = gb.init_sec_context(server_name,
815+
creds=krb5_client_creds,
816+
mech=spnego_mech)
817+
client_token = client_ctx_resp.token
818+
819+
gb.accept_sec_context.should_raise(gb.GSSError, client_token,
820+
acceptor_creds=server_creds)
821+
822+
neg_resp = gb.set_neg_mechs(server_creds, [krb5_mech])
823+
neg_resp.should_be_none()
824+
825+
client_ctx_resp = gb.init_sec_context(server_name,
826+
creds=krb5_client_creds,
827+
mech=spnego_mech)
828+
client_token = client_ctx_resp.token
829+
830+
server_ctx_resp = gb.accept_sec_context(client_token,
831+
acceptor_creds=server_creds)
832+
server_ctx_resp.shouldnt_be_none()
833+
834+
client_ctx_resp = gb.init_sec_context(server_name,
835+
creds=ntlm_client_creds,
836+
mech=spnego_mech)
837+
client_token = client_ctx_resp.token
838+
839+
gb.accept_sec_context.should_raise(gb.GSSError, client_token,
840+
acceptor_creds=server_creds)
841+
775842
@ktu.gssapi_extension_test('ggf', 'Global Grid Forum')
776843
@ktu.gssapi_extension_test('s4u', 'S4U')
777844
@ktu.krb_minversion_test('1.16',

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ def gssapi_modules(lst):
269269
main_file('chan_bindings'),
270270
extension_file('s4u', 'gss_acquire_cred_impersonate_name'),
271271
extension_file('cred_store', 'gss_store_cred_into'),
272+
extension_file('rfc4178', 'gss_set_neg_mechs'),
272273
extension_file('rfc5587', 'gss_indicate_mechs_by_attrs'),
273274
extension_file('rfc5588', 'gss_store_cred'),
274275
extension_file('rfc5801', 'gss_inquire_saslname_for_mech'),

0 commit comments

Comments
 (0)