Skip to content

Commit

Permalink
Expose mechanisms in the high-level API
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
cipherboy committed Jul 27, 2017
1 parent b1cb22b commit afd68bf
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 0 deletions.
1 change: 1 addition & 0 deletions gssapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@
from gssapi.creds import Credentials # noqa
from gssapi.names import Name # noqa
from gssapi.sec_contexts import SecurityContext # noqa
from gssapi.mechs import Mechanism # noqa

from gssapi._utils import set_encoding # noqa
222 changes: 222 additions & 0 deletions gssapi/mechs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import six

from gssapi.raw import oids as roids
from gssapi._utils import import_gssapi_extension
from gssapi.raw import misc as rmisc
from gssapi import _utils

rfc5587 = import_gssapi_extension('rfc5587')
rfc5801 = import_gssapi_extension('rfc5801')


class Mechanism(roids.OID):
"""
A GSSAPI Mechanism
This class represents a mechanism and centralizes functions dealing with
mechanisms and can be used with any calls.
It inherits from the low-level GSSAPI :class:`~gssapi.raw.oids.OID` class,
and thus can be used with both low-level and high-level API calls.
"""
_sasl_name = None
_mech_attrs = None

def __new__(cls, cpy=None, elements=None):
return super(Mechanism, cls).__new__(cls, cpy, elements)

@property
def names(self):
"""
Get the set of name types supported by the mechanism.
"""
return rmisc.inquire_names_for_mech(self)

@property
def _query_saslname(self):
if rfc5801 is None:
raise NotImplementedError("Your GSSAPI implementation does not "
"have support for RFC 5801")
return rfc5801.inquire_saslname_for_mech(self)

@property
def _query_attrs(self):
if rfc5587 is None:
raise NotImplementedError("Your GSSAPI implementation does not "
"have support for RFC 5587")

return rfc5587.inquire_attrs_for_mech(self)

def __str__(self):
if issubclass(str, six.text_type):
# Python 3 -- we should return unicode
return self.__bytes__().decode(_utils._get_encoding())
else:
return self.__bytes__()

def __unicode__(self):
return self.__bytes__().decode(_utils._get_encoding())

def __bytes__(self):
"""
Get a name representing the mechanism; always safe to call
"""
base = self.dotted_form
if rfc5801 is not None:
base = self._query_saslname.mech_name

if issubclass(str, six.text_type):
base = bytes(base, _utils._get_encoding())
else:
base = bytes(base)

return base

def __repr__(self):
"""
Get a name representing the mechanism; always safe to call
"""
base = self.dotted_form
if rfc5801 is not None:
base = "%s %s" % (self._query_saslname.mech_name.decode('UTF-8'),
base)

return base

@property
def sasl_name(self):
"""
Get the SASL name for the mechanism; depends on RFC 5801
:requires-ext:`rfc5801`
"""
return self._query_saslname.sasl_mech_name.decode('UTF-8')

@property
def name(self):
"""
Get the name for the mechanism; depends on RFC 5801
:requires-ext:`rfc5801`
"""
self._query_saslname()
return self._query_saslname.mech_name.decode('UTF-8')

@property
def description(self):
"""
Get the description of the mechanism; depends on RFC 5801
:requires-ext:`rfc5801`
"""
self._query_saslname()
return self._query_saslname.mech_description.decode('UTF-8')

@property
def known_attrs(self):
"""
Get the known attributes of the mechanism; depends on RFC 5587
:requires-ext:`rfc5587`
"""
return self._query_attrs.known_mech_attrs

@property
def attrs(self):
"""
Get the attributes of the mechanism; depends on RFC 5587
:requires-ext:`rfc5587`
"""
return self._query_attrs.mech_attrs

@classmethod
def all_mechs(cls):
"""
all_mechs()
Get a list of all mechanisms supported by GSSAPI
"""
mechs = rmisc.indicate_mechs()
return [cls(mech) for mech in mechs]

@classmethod
def from_name(cls, name=None):
"""
from_name(name)
Get a set of mechanisms that may be able to process the name
Args:
name (Name): a name to inquire about
Returns:
[Mechanism]: a set of mechanisms which support this name
Raises:
GSSError
"""
mechs = rmisc.inquire_mechs_for_name(name)
return [cls(mech) for mech in mechs]

@classmethod
def from_sasl_name(cls, name=None):
"""
from_sasl_name(name)
Create a Mechanism from its SASL name
Args:
name (str): SASL name of the desired mechanism
Returns:
Mechanism: the desired mechanism
Raises:
GSSError
:requires-ext:`rfc5801`
"""
if rfc5801 is None:
raise NotImplementedError("Your GSSAPI implementation does not "
"have support for RFC 5801")
n = name
if type(n) is not bytes:
n = str(n).encode()

m = rfc5801.inquire_mech_for_saslname(n)

return cls(m)

@classmethod
def from_attrs(cls, m_desired=None, m_except=None, m_critical=None):
"""
from_attrs
Get the set of mechanisms supporting the specified attributes. See
RFC 5587's indicate_mechs_by_attrs for more information.
Args:
m_desired ([OID]): Desired attributes
m_except ([OID]): Except attributes
m_critical ([OID]): Critical attributes
Returns:
[Mechanism]: A set of mechanisms having the desired features.
Raises:
GSSError
:requires-ext:`rfc5587`
"""
if type(m_desired) == roids.OID:
m_desired = set([m_desired])
if type(m_except) == roids.OID:
m_except = set([m_except])
if type(m_critical) == roids.OID:
m_critical = set([m_critical])

if rfc5587 is None:
raise NotImplementedError("Your GSSAPI implementation does not "
"have support for RFC 5587")

mechs = rfc5587.indicate_mechs_by_attrs(m_desired,
m_except,
m_critical)
return [cls(mech) for mech in mechs]
3 changes: 3 additions & 0 deletions gssapi/raw/oids.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ cdef class OID:
self._free_on_dealloc = True
return 0

def _copy_oid(self, OID other):
self._copy_from(other.raw_oid)

cdef int _from_bytes(OID self, object base) except -1:
base_bytes = bytes(base)
cdef char* byte_str = base_bytes
Expand Down
52 changes: 52 additions & 0 deletions gssapi/tests/test_high_level.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from nose_parameterized import parameterized

from gssapi import creds as gsscreds
from gssapi import mechs as gssmechs
from gssapi import names as gssnames
from gssapi import sec_contexts as gssctx
from gssapi import raw as gb
Expand Down Expand Up @@ -369,6 +370,57 @@ def test_add_with_impersonate(self):
new_creds.should_be_a(gsscreds.Credentials)


class MechsTestCase(_GSSAPIKerberosTestCase):
def test_indicate_mechs(self):
mechs = gssmechs.Mechanism.all_mechs()
for mech in mechs:
s = str(mech)
s.shouldnt_be_empty()

@ktu.gssapi_extension_test('rfc5801', 'RFC 5801: SASL Names')
def test_sasl_properties(self):
mechs = gssmechs.Mechanism.all_mechs()
for mech in mechs:
s = str(mech)
s.shouldnt_be_empty()
s.should_be_a(str)
s[0].shouldnt_be('<')
s.should_be(mech.name)

mech.sasl_name.shouldnt_be_empty()
mech.sasl_name.should_be_a(six.text_type)

mech.description.shouldnt_be_empty()
mech.description.should_be_a(six.text_type)

cmp_mech = gssmechs.Mechanism.from_sasl_name(mech.sasl_name)
str(cmp_mech).should_be(str(mech))

@ktu.gssapi_extension_test('rfc5587', 'RFC 5587: Mech Inquiry')
def test_mech_inquiry(self):
mechs = gssmechs.Mechanism.all_mechs()
c = len(mechs)
for mech in mechs:
attrs = mech.attrs
known_attrs = mech.known_attrs

for attr in attrs:
i = gssmechs.Mechanism.from_attrs(m_desired=[attr])
e = gssmechs.Mechanism.from_attrs(m_except=[attr])

count = len(i) + len(e)
count.should_be(c)
i.should_include(mech)
e.shouldnt_include(mech)

for attr in known_attrs:
i = gssmechs.Mechanism.from_attrs(m_desired=[attr])
e = gssmechs.Mechanism.from_attrs(m_except=[attr])

count = len(i) + len(e)
count.should_be(c)


class NamesTestCase(_GSSAPIKerberosTestCase):
def test_create_from_other(self):
raw_name = gb.import_name(SERVICE_PRINCIPAL)
Expand Down

0 comments on commit afd68bf

Please sign in to comment.