Skip to content

Commit ae99d0c

Browse files
cipherboyDirectXMan12
authored andcommitted
Implement support for GSSAPI extension RFC 5587
RFC 5587 provides extended mech inquiry calls to GSSAPI. This adds the ability to indicate mechs by their mech attrs, along with determining the attrs supported by a mech. These calls are provided as a part of the raw interface and are not exposed in the high-level interface due to not having objects for mechs or attrs. Signed-off-by: Alexander Scheel <[email protected]>
1 parent 0be0230 commit ae99d0c

File tree

6 files changed

+258
-0
lines changed

6 files changed

+258
-0
lines changed

README.txt

+2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ Extensions
136136

137137
In addition to RFC 2743/2744, Python-GSSAPI also has support for:
138138

139+
* RFC 5587 (Extended GSS Mechanism Inquiry APIs)
140+
139141
* RFC 5588 (GSS-API Extension for Storing Delegated Credentials)
140142

141143
* (Additional) Credential Store Extension

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 5587 support
73+
try:
74+
from gssapi.raw.ext_rfc5587 import * # noqa
75+
except ImportError:
76+
pass
77+
7278
# optional RFC 5588 support
7379
try:
7480
from gssapi.raw.ext_rfc5588 import * # noqa

gssapi/raw/ext_rfc5587.pyx

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
from gssapi.raw.cython_types cimport *
2+
from gssapi.raw.oids cimport OID
3+
from gssapi.raw.cython_converters cimport c_create_oid_set
4+
GSSAPI="BASE" # This ensures that a full module is generated by Cython
5+
6+
from gssapi.raw.cython_converters cimport c_get_mech_oid_set
7+
8+
from gssapi.raw.named_tuples import InquireAttrsResult, DisplayAttrResult
9+
from gssapi.raw.misc import GSSError
10+
11+
cdef extern from "python_gssapi_ext.h":
12+
OM_uint32 gss_indicate_mechs_by_attrs(
13+
OM_uint32 *minor_status,
14+
const gss_OID_set desired_mech_attrs,
15+
const gss_OID_set except_mech_attrs,
16+
const gss_OID_set critical_mech_attrs,
17+
gss_OID_set *mechs) nogil
18+
19+
OM_uint32 gss_inquire_attrs_for_mech(
20+
OM_uint32 *minor_status,
21+
const gss_OID mech,
22+
gss_OID_set *mech_attrs,
23+
gss_OID_set *known_mech_attrs) nogil
24+
25+
OM_uint32 gss_display_mech_attr(
26+
OM_uint32 *minor_status,
27+
const gss_OID mech_attr,
28+
gss_buffer_t name,
29+
gss_buffer_t short_desc,
30+
gss_buffer_t long_desc) nogil
31+
32+
33+
def indicate_mechs_by_attrs(desired_mech_attrs=None, except_mech_attrs=None,
34+
critical_mech_attrs=None):
35+
"""
36+
indicate_mechs_by_attrs(desired_mech_attrs=None, except_mech_attrs=None,
37+
critical_mech_attrs=None)
38+
Get a set of mechanisms that have the specified attributes.
39+
40+
Args:
41+
desired_mech_attrs ([OID]): Attributes that the output mechs MUST
42+
offer
43+
except_mech_attrs ([OID]): Attributes that the output mechs MUST NOT
44+
offer
45+
critical_mech_attrs ([OID]): Attributes that the output mechs MUST
46+
understand and offer
47+
48+
Returns:
49+
[MechType]: a set of mechs which satisfy the given criteria
50+
51+
Raises:
52+
GSSError
53+
"""
54+
cdef OM_uint32 maj_stat, min_stat
55+
cdef gss_OID_set desired_attrs = GSS_C_NO_OID_SET
56+
cdef gss_OID_set except_attrs = GSS_C_NO_OID_SET
57+
cdef gss_OID_set critical_attrs = GSS_C_NO_OID_SET
58+
cdef gss_OID_set mechs
59+
60+
if desired_mech_attrs is not None:
61+
desired_attrs = c_get_mech_oid_set(desired_mech_attrs)
62+
63+
if except_mech_attrs is not None:
64+
except_attrs = c_get_mech_oid_set(except_mech_attrs)
65+
66+
if critical_mech_attrs is not None:
67+
critical_attrs = c_get_mech_oid_set(critical_mech_attrs)
68+
69+
with nogil:
70+
maj_stat = gss_indicate_mechs_by_attrs(&min_stat, desired_attrs,
71+
except_attrs, critical_attrs,
72+
&mechs)
73+
74+
if maj_stat == GSS_S_COMPLETE:
75+
return c_create_oid_set(mechs)
76+
else:
77+
raise GSSError(maj_stat, min_stat)
78+
79+
80+
def inquire_attrs_for_mech(OID mech):
81+
"""
82+
inquire_attrs_for_mech(mech)
83+
Gets the set of attrs supported and known by a mechanism.
84+
85+
Args:
86+
mech (MechType): Mechanism to inquire about
87+
88+
Returns:
89+
InquireAttrsResult: the results of inquiry; a mech's attributes and
90+
known attributes
91+
92+
Raises:
93+
GSSError
94+
"""
95+
cdef OM_uint32 maj_stat, min_stat
96+
cdef gss_OID m = GSS_C_NO_OID
97+
cdef gss_OID_set mech_attrs = GSS_C_NO_OID_SET
98+
cdef gss_OID_set known_mech_attrs = GSS_C_NO_OID_SET
99+
100+
if mech is not None:
101+
m = &mech.raw_oid
102+
103+
with nogil:
104+
maj_stat = gss_inquire_attrs_for_mech(&min_stat, m, &mech_attrs,
105+
&known_mech_attrs)
106+
107+
if maj_stat == GSS_S_COMPLETE:
108+
return InquireAttrsResult(c_create_oid_set(mech_attrs),
109+
c_create_oid_set(known_mech_attrs))
110+
else:
111+
raise GSSError(maj_stat, min_stat)
112+
113+
114+
def display_mech_attr(OID attr):
115+
"""
116+
display_mech_attrs(attr)
117+
Returns information about attributes in human readable form.
118+
119+
Args:
120+
attr (OID): Mechanism attribute to retrive names and descriptions of
121+
122+
Returns:
123+
DisplayAttrResult: the results of displaying the attribute; mech name,
124+
short description, and long description.
125+
126+
Raises:
127+
GSSError
128+
"""
129+
cdef OM_uint32 maj_stat, min_stat
130+
cdef gss_OID a = GSS_C_NO_OID
131+
cdef gss_buffer_desc name
132+
cdef gss_buffer_desc short_desc
133+
cdef gss_buffer_desc long_desc
134+
135+
if attr is not None:
136+
a = &attr.raw_oid
137+
138+
with nogil:
139+
maj_stat = gss_display_mech_attr(&min_stat, a, &name, &short_desc,
140+
&long_desc)
141+
142+
if maj_stat == GSS_S_COMPLETE:
143+
out_name = name.value[:name.length]
144+
out_short = short_desc.value[:short_desc.length]
145+
out_long = long_desc.value[:long_desc.length]
146+
147+
gss_release_buffer(&min_stat, &name)
148+
gss_release_buffer(&min_stat, &short_desc)
149+
gss_release_buffer(&min_stat, &long_desc)
150+
151+
return DisplayAttrResult(out_name, out_short, out_long)
152+
else:
153+
raise GSSError(maj_stat, min_stat)

gssapi/raw/named_tuples.py

+6
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,9 @@
6464
GetNameAttributeResult = namedtuple('GetNamedAttributeResult',
6565
['values', 'display_values',
6666
'authenticated', 'complete'])
67+
68+
InquireAttrsResult = namedtuple('InquireAttrsResult',
69+
['mech_attrs', 'known_mech_attrs'])
70+
71+
DisplayAttrResult = namedtuple('DisplayAttrResult', ['name', 'short_desc',
72+
'long_desc'])

gssapi/tests/test_raw.py

+90
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,96 @@ def test_add_cred_with_password(self):
644644

645645
new_creds.should_be_a(gb.Creds)
646646

647+
@ktu.gssapi_extension_test('rfc5587', 'RFC 5587')
648+
def test_rfc5587(self):
649+
mechs = gb.indicate_mechs_by_attrs(None, None, None)
650+
651+
mechs.should_be_a(set)
652+
mechs.shouldnt_be_empty()
653+
654+
# We need last_attr to be an attribute on last_mech.
655+
# Since mechs is of type set and thus not indexable, these
656+
# are used to track the last visited mech for testing
657+
# purposes, and saves a call to inquire_attrs_for_mech().
658+
last_attr = None
659+
last_mech = None
660+
661+
for mech in mechs:
662+
mech.shouldnt_be_none()
663+
mech.should_be_a(gb.OID)
664+
last_mech = mech
665+
666+
inquire_out = gb.inquire_attrs_for_mech(mech)
667+
mech_attrs = inquire_out.mech_attrs
668+
known_mech_attrs = inquire_out.known_mech_attrs
669+
670+
mech_attrs.should_be_a(set)
671+
mech_attrs.shouldnt_be_empty()
672+
673+
known_mech_attrs.should_be_a(set)
674+
known_mech_attrs.shouldnt_be_empty()
675+
676+
# Verify that we get data for every available
677+
# attribute. Testing the contents of a few known
678+
# attributes is done in test_display_mech_attr().
679+
for mech_attr in mech_attrs:
680+
mech_attr.shouldnt_be_none()
681+
mech_attr.should_be_a(gb.OID)
682+
683+
display_out = gb.display_mech_attr(mech_attr)
684+
display_out.name.shouldnt_be_none()
685+
display_out.short_desc.shouldnt_be_none()
686+
display_out.long_desc.shouldnt_be_none()
687+
display_out.name.should_be_a(bytes)
688+
display_out.short_desc.should_be_a(bytes)
689+
display_out.long_desc.should_be_a(bytes)
690+
691+
last_attr = mech_attr
692+
693+
for mech_attr in known_mech_attrs:
694+
mech_attr.shouldnt_be_none()
695+
mech_attr.should_be_a(gb.OID)
696+
697+
display_out = gb.display_mech_attr(mech_attr)
698+
display_out.name.shouldnt_be_none()
699+
display_out.short_desc.shouldnt_be_none()
700+
display_out.long_desc.shouldnt_be_none()
701+
display_out.name.should_be_a(bytes)
702+
display_out.short_desc.should_be_a(bytes)
703+
display_out.long_desc.should_be_a(bytes)
704+
705+
attrs = set([last_attr])
706+
707+
mechs = gb.indicate_mechs_by_attrs(attrs, None, None)
708+
mechs.shouldnt_be_empty()
709+
mechs.should_include(last_mech)
710+
711+
mechs = gb.indicate_mechs_by_attrs(None, attrs, None)
712+
mechs.shouldnt_include(last_mech)
713+
714+
mechs = gb.indicate_mechs_by_attrs(None, None, attrs)
715+
mechs.shouldnt_be_empty()
716+
mechs.should_include(last_mech)
717+
718+
@ktu.gssapi_extension_test('rfc5587', 'RFC 5587')
719+
def test_display_mech_attr(self):
720+
test_attrs = [
721+
# oid, name, short_desc, long_desc
722+
# Taken from krb5/src/tests/gssapi/t_saslname
723+
[gb.OID.from_int_seq("1.3.6.1.5.5.13.24"), b"GSS_C_MA_CBINDINGS",
724+
b"channel-bindings", b"Mechanism supports channel bindings."],
725+
[gb.OID.from_int_seq("1.3.6.1.5.5.13.1"),
726+
b"GSS_C_MA_MECH_CONCRETE", b"concrete-mech",
727+
b"Mechanism is neither a pseudo-mechanism nor a composite "
728+
b"mechanism."]
729+
]
730+
731+
for attr in test_attrs:
732+
display_out = gb.display_mech_attr(attr[0])
733+
display_out.name.should_be(attr[1])
734+
display_out.short_desc.should_be(attr[2])
735+
display_out.long_desc.should_be(attr[3])
736+
647737

648738
class TestIntEnumFlagSet(unittest.TestCase):
649739
def test_create_from_int(self):

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ def gssapi_modules(lst):
258258
main_file('chan_bindings'),
259259
extension_file('s4u', 'gss_acquire_cred_impersonate_name'),
260260
extension_file('cred_store', 'gss_store_cred_into'),
261+
extension_file('rfc5587', 'gss_indicate_mechs_by_attrs'),
261262
extension_file('rfc5588', 'gss_store_cred'),
262263
extension_file('cred_imp_exp', 'gss_import_cred'),
263264
extension_file('dce', 'gss_wrap_iov'),

0 commit comments

Comments
 (0)