Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9566a39

Browse files
Expose mechanisms in the high-level API
This creates a new class, Mechanism, for inquiring information about a mechanism. This includes support for RFCs 5587 and 5801. As Mechanism derives from OID, it is compatible with all places that accept a mech by OID. Signed-off-by: Alexander Scheel <ascheel@redhat.com>
1 parent 7ce3dac commit 9566a39

File tree

4 files changed

+261
-0
lines changed

4 files changed

+261
-0
lines changed

‎gssapi/__init__.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@
3333
from gssapi.creds import Credentials # noqa
3434
from gssapi.names import Name # noqa
3535
from gssapi.sec_contexts import SecurityContext # noqa
36+
from gssapi.mechs import Mechanism # noqa
3637

3738
from gssapi._utils import set_encoding # noqa

‎gssapi/mechs.py‎

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import six
2+
3+
from gssapi.raw import oids as roids
4+
from gssapi._utils import import_gssapi_extension
5+
from gssapi.raw import misc as rmisc
6+
from gssapi import _utils
7+
8+
rfc5587 = import_gssapi_extension('rfc5587')
9+
rfc5801 = import_gssapi_extension('rfc5801')
10+
11+
12+
class Mechanism(roids.OID):
13+
"""
14+
A GSSAPI Mechanism
15+
16+
This class represents a mechanism and centralizes functions dealing with
17+
mechanisms and can be used with any calls.
18+
19+
It inherits from the low-level GSSAPI :class:`~gssapi.raw.oids.OID` class,
20+
and thus can be used with both low-level and high-level API calls.
21+
"""
22+
def __new__(cls, cpy=None, elements=None):
23+
return super(Mechanism, cls).__new__(cls, cpy, elements)
24+
25+
@property
26+
def names(self):
27+
"""
28+
Get the set of name types supported by this mechanism.
29+
"""
30+
return rmisc.inquire_names_for_mech(self)
31+
32+
@property
33+
def _saslname(self):
34+
if rfc5801 is None:
35+
raise NotImplementedError("Your GSSAPI implementation does not "
36+
"have support for RFC 5801")
37+
return rfc5801.inquire_saslname_for_mech(self)
38+
39+
@property
40+
def _attrs(self):
41+
if rfc5587 is None:
42+
raise NotImplementedError("Your GSSAPI implementation does not "
43+
"have support for RFC 5587")
44+
45+
return rfc5587.inquire_attrs_for_mech(self)
46+
47+
def __str__(self):
48+
if issubclass(str, six.text_type):
49+
# Python 3 -- we should return unicode
50+
return self._bytes_desc().decode(_utils._get_encoding())
51+
else:
52+
return self._bytes_desc()
53+
54+
def __unicode__(self):
55+
return self._bytes_desc().decode(_utils._get_encoding())
56+
57+
def _bytes_desc(self):
58+
base = self.dotted_form
59+
if rfc5801 is not None:
60+
base = self._saslname.mech_name
61+
62+
if issubclass(str, six.text_type):
63+
base = bytes(base, _utils._get_encoding())
64+
else:
65+
base = bytes(base)
66+
67+
return base
68+
69+
def __repr__(self):
70+
"""
71+
Get a name representing the mechanism; always safe to call
72+
"""
73+
base = "<Mechanism (%s)>" % self.dotted_form
74+
if rfc5801 is not None:
75+
base = "<Mechanism %s (%s)>" % (
76+
self._saslname.mech_name.decode('UTF-8'),
77+
self.dotted_form
78+
)
79+
80+
return base
81+
82+
@property
83+
def sasl_name(self):
84+
"""
85+
Get the SASL name for the mechanism; depends on RFC 5801
86+
87+
:requires-ext:`rfc5801`
88+
"""
89+
return self._saslname.sasl_mech_name.decode('UTF-8')
90+
91+
@property
92+
def description(self):
93+
"""
94+
Get the description of the mechanism; depends on RFC 5801
95+
96+
:requires-ext:`rfc5801`
97+
"""
98+
return self._saslname.mech_description.decode('UTF-8')
99+
100+
@property
101+
def known_attrs(self):
102+
"""
103+
Get the known attributes of the mechanism; depends on RFC 5587
104+
105+
:requires-ext:`rfc5587`
106+
"""
107+
return self._attrs.known_mech_attrs
108+
109+
@property
110+
def attrs(self):
111+
"""
112+
Get the attributes of the mechanism; depends on RFC 5587
113+
114+
:requires-ext:`rfc5587`
115+
"""
116+
return self._attrs.mech_attrs
117+
118+
@classmethod
119+
def all_mechs(cls):
120+
"""
121+
all_mechs()
122+
Get a generator of all mechanisms supported by GSSAPI
123+
"""
124+
return (cls(mech) for mech in rmisc.indicate_mechs())
125+
126+
@classmethod
127+
def from_name(cls, name=None):
128+
"""
129+
from_name(name)
130+
Get a generator of mechanisms that may be able to process the name
131+
132+
Args:
133+
name (Name): a name to inquire about
134+
135+
Returns:
136+
[Mechanism]: a set of mechanisms which support this name
137+
138+
Raises:
139+
GSSError
140+
"""
141+
return (cls(mech) for mech in rmisc.inquire_mechs_for_name(name))
142+
143+
@classmethod
144+
def from_sasl_name(cls, name=None):
145+
"""
146+
from_sasl_name(name)
147+
Create a Mechanism from its SASL name
148+
149+
Args:
150+
name (str): SASL name of the desired mechanism
151+
152+
Returns:
153+
Mechanism: the desired mechanism
154+
155+
Raises:
156+
GSSError
157+
158+
:requires-ext:`rfc5801`
159+
"""
160+
if rfc5801 is None:
161+
raise NotImplementedError("Your GSSAPI implementation does not "
162+
"have support for RFC 5801")
163+
n = name
164+
if not isinstance(n, bytes):
165+
n = str(n).encode()
166+
167+
m = rfc5801.inquire_mech_for_saslname(n)
168+
169+
return cls(m)
170+
171+
@classmethod
172+
def from_attrs(cls, m_desired=None, m_except=None, m_critical=None):
173+
"""
174+
from_attrs
175+
Get a generator of mechanisms supporting the specified attributes. See
176+
RFC 5587's indicate_mechs_by_attrs for more information.
177+
178+
Args:
179+
m_desired ([OID]): Desired attributes
180+
m_except ([OID]): Except attributes
181+
m_critical ([OID]): Critical attributes
182+
183+
Returns:
184+
[Mechanism]: A set of mechanisms having the desired features.
185+
186+
Raises:
187+
GSSError
188+
189+
:requires-ext:`rfc5587`
190+
"""
191+
if isinstance(m_desired, roids.OID):
192+
m_desired = set([m_desired])
193+
if isinstance(m_except, roids.OID):
194+
m_except = set([m_except])
195+
if isinstance(m_critical, roids.OID):
196+
m_critical = set([m_critical])
197+
198+
if rfc5587 is None:
199+
raise NotImplementedError("Your GSSAPI implementation does not "
200+
"have support for RFC 5587")
201+
202+
mechs = rfc5587.indicate_mechs_by_attrs(m_desired,
203+
m_except,
204+
m_critical)
205+
return (cls(mech) for mech in mechs)

‎gssapi/raw/oids.pyx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ cdef class OID:
6161
self._free_on_dealloc = True
6262
return 0
6363

64+
def _copy_oid(self, OID other):
65+
self._copy_from(other.raw_oid)
66+
6467
cdef int _from_bytes(OID self, object base) except -1:
6568
base_bytes = bytes(base)
6669
cdef char* byte_str = base_bytes

‎gssapi/tests/test_high_level.py‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from nose_parameterized import parameterized
1010

1111
from gssapi import creds as gsscreds
12+
from gssapi import mechs as gssmechs
1213
from gssapi import names as gssnames
1314
from gssapi import sec_contexts as gssctx
1415
from gssapi import raw as gb
@@ -369,6 +370,57 @@ def test_add_with_impersonate(self):
369370
new_creds.should_be_a(gsscreds.Credentials)
370371

371372

373+
class MechsTestCase(_GSSAPIKerberosTestCase):
374+
def test_indicate_mechs(self):
375+
mechs = gssmechs.Mechanism.all_mechs()
376+
for mech in mechs:
377+
s = str(mech)
378+
s.shouldnt_be_empty()
379+
380+
@ktu.gssapi_extension_test('rfc5801', 'RFC 5801: SASL Names')
381+
def test_sasl_properties(self):
382+
mechs = gssmechs.Mechanism.all_mechs()
383+
for mech in mechs:
384+
s = str(mech)
385+
s.shouldnt_be_empty()
386+
s.should_be_a(str)
387+
s[0].shouldnt_be('<')
388+
s.should_be(mech.name)
389+
390+
mech.sasl_name.shouldnt_be_empty()
391+
mech.sasl_name.should_be_a(six.text_type)
392+
393+
mech.description.shouldnt_be_empty()
394+
mech.description.should_be_a(six.text_type)
395+
396+
cmp_mech = gssmechs.Mechanism.from_sasl_name(mech.sasl_name)
397+
str(cmp_mech).should_be(str(mech))
398+
399+
@ktu.gssapi_extension_test('rfc5587', 'RFC 5587: Mech Inquiry')
400+
def test_mech_inquiry(self):
401+
mechs = list(gssmechs.Mechanism.all_mechs())
402+
c = len(mechs)
403+
for mech in mechs:
404+
attrs = mech.attrs
405+
known_attrs = mech.known_attrs
406+
407+
for attr in attrs:
408+
i = list(gssmechs.Mechanism.from_attrs(m_desired=[attr]))
409+
e = list(gssmechs.Mechanism.from_attrs(m_except=[attr]))
410+
411+
count = len(i) + len(e)
412+
count.should_be(c)
413+
i.should_include(mech)
414+
e.shouldnt_include(mech)
415+
416+
for attr in known_attrs:
417+
i = list(gssmechs.Mechanism.from_attrs(m_desired=[attr]))
418+
e = list(gssmechs.Mechanism.from_attrs(m_except=[attr]))
419+
420+
count = len(i) + len(e)
421+
count.should_be(c)
422+
423+
372424
class NamesTestCase(_GSSAPIKerberosTestCase):
373425
def test_create_from_other(self):
374426
raw_name = gb.import_name(SERVICE_PRINCIPAL)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /