Skip to content

Commit

Permalink
Add gss_a{dd,cquire}_cred_with_password functions from Solaris/IAKERB
Browse files Browse the repository at this point in the history
This closes #5.
  • Loading branch information
frozencemetery authored and DirectXMan12 committed Jan 26, 2015
1 parent b649060 commit 416d20c
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 0 deletions.
16 changes: 16 additions & 0 deletions docs/source/gssapi.raw.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,22 @@ raw Package
:undoc-members:
:show-inheritance:

:mod:`ext_password` Module
---------------------

.. automodule:: gssapi.raw.ext_password
:members:
:undoc-members:
:show-inheritance:

:mod:`ext_password_add` Module
---------------------

.. automodule:: gssapi.raw.ext_password_add
:members:
:undoc-members:
:show-inheritance:

:mod:`mech_krb5` Module
-----------------------

Expand Down
7 changes: 7 additions & 0 deletions gssapi/raw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,10 @@
import gssapi.raw.mech_krb5 # noqa
except ImportError:
pass

# optional password support
try:
from gssapi.raw.ext_password import * # noqa
from gssapi.raw.ext_password_add import * # noqa
except ImportError:
pass
97 changes: 97 additions & 0 deletions gssapi/raw/ext_password.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
GSSAPI="BASE" # This ensures that a full module is generated by Cythin

# Due to a bug in MIT Kerberos, add_cred_with_password was not properly
# exported for some time. In order to work around this,
# add_cred_with_password is in its own file. For more information, see:
# https://github.com/krb5/krb5/pull/244

from gssapi.raw.cython_types cimport *
from gssapi.raw.cython_converters cimport c_get_mech_oid_set
from gssapi.raw.cython_converters cimport c_create_oid_set
from gssapi.raw.cython_converters cimport c_py_ttl_to_c, c_c_ttl_to_py
from gssapi.raw.creds cimport Creds
from gssapi.raw.names cimport Name

from gssapi.raw.misc import GSSError
from gssapi.raw.named_tuples import AcquireCredResult

cdef extern from "gssapi/gssapi_ext.h":
OM_uint32 gss_acquire_cred_with_password(OM_uint32 *min_stat,
const gss_name_t desired_name,
const gss_buffer_t password,
OM_uint32 ttl,
const gss_OID_set desired_mechs,
gss_cred_usage_t cred_usage,
gss_cred_id_t *output_creds,
gss_OID_set *actual_mechs,
OM_uint32 *actual_ttl) nogil


def acquire_cred_with_password(Name name not None, password not None,
lifetime=None, mechs=None, usage="initiate"):
"""
Acquire credentials through provided password.
This function is originally from Solaris and is not documented by either
MIT or Heimdal.
Args:
name (Name): the name to acquire credentials for
password (bytes): the password used to acquire credentialss with
lifetime (int): the lifetime for the credentials (or None for
indefinite)
mechs ([MechType]): the desired mechanisms for which the credentials
should work (or None for the default set)
usage (str): usage type for credentials. Possible values:
'initiate' (default), 'accept', 'both' (failsafe).
Returns:
AcquireCredResult: the resulting credentials, the actual mechanisms
with which they may be used, and their actual lifetime (or None for
indefinite or not supported)
Raises:
GSSError
"""

cdef gss_buffer_desc password_buffer = gss_buffer_desc(len(password),
password)

cdef OM_uint32 input_ttl = c_py_ttl_to_c(lifetime)

cdef gss_OID_set desired_mechs
if mechs is not None:
desired_mechs = c_get_mech_oid_set(mechs)
else:
desired_mechs = GSS_C_NO_OID_SET

cdef gss_cred_usage_t c_usage
if usage == "initiate":
c_usage = GSS_C_INITIATE
elif usage == "accept":
c_usage = GSS_C_ACCEPT
else:
c_usage = GSS_C_BOTH

cdef gss_cred_id_t creds
cdef gss_OID_set actual_mechs
cdef OM_uint32 actual_ttl

cdef OM_uint32 maj_stat, min_stat

with nogil:
maj_stat = gss_acquire_cred_with_password(
&min_stat, name.raw_name, &password_buffer, input_ttl,
desired_mechs, c_usage, &creds, &actual_mechs, &actual_ttl)

cdef OM_uint32 tmp_min_stat
if mechs is not None:
gss_release_oid_set(&tmp_min_stat, &desired_mechs)

cdef Creds rc = Creds()
if maj_stat == GSS_S_COMPLETE:
rc.raw_creds = creds
return AcquireCredResult(rc, c_create_oid_set(actual_mechs),
c_c_ttl_to_py(actual_ttl))
else:
raise GSSError(maj_stat, min_stat)
105 changes: 105 additions & 0 deletions gssapi/raw/ext_password_add.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
GSSAPI="BASE" # This ensures that a full module is generated by Cythin

# Due to a bug in MIT Kerberos, add_cred_with_password was not properly
# exported for some time. In order to work around this,
# add_cred_with_password is in its own file. For more information, see:
# https://github.com/krb5/krb5/pull/244

from gssapi.raw.cython_types cimport *
from gssapi.raw.cython_converters cimport c_get_mech_oid_set
from gssapi.raw.cython_converters cimport c_create_oid_set
from gssapi.raw.cython_converters cimport c_py_ttl_to_c, c_c_ttl_to_py
from gssapi.raw.creds cimport Creds
from gssapi.raw.names cimport Name
from gssapi.raw.oids cimport OID

from gssapi.raw.misc import GSSError
from gssapi.raw.named_tuples import AddCredResult

cdef extern from "gssapi/gssapi_ext.h":
OM_uint32 gss_add_cred_with_password(OM_uint32 *min_stat,
const gss_cred_id_t input_cred_handle,
const gss_name_t desired_name,
const gss_OID desired_mech,
const gss_buffer_t password,
gss_cred_usage_t cred_usage,
OM_uint32 initiator_ttl,
OM_uint32 acceptor_ttl,
gss_cred_id_t *output_creds,
gss_OID_set *actual_mechs,
OM_uint32 *actual_init_ttl,
OM_uint32 *actual_accept_ttl) nogil


def add_cred_with_password(Creds input_cred not None, Name name not None,
OID mech not None, password not None,
usage="initiate", init_lifetime=None,
accept_lifetime=None):

"""
Add a credential-element to a credential using provided password.
This function is originally from Solaris and is not documented by either
MIT or Heimdal.
Args:
input_cred (Creds): the credentials to add to
name (Name): the name to acquire credentials for
mech (MechType): the desired mechanism. Note that this is both
singular and required
password (bytes): the password used to acquire credentialss with
usage (str): the usage type for the credentials: may be
'initiate', 'accept', or 'both'
init_lifetime (int): the lifetime for the credentials to remain valid
when using them to initiate security contexts (or None for
indefinite)
accept_lifetime (int): the lifetime for the credentials to remain
valid when using them to accept security contexts (or None for
indefinite)
Returns:
AddCredResult: the actual mechanisms with which the credentials may be
used, the actual initiator TTL, and the actual acceptor TTL (the TTLs
may be None for indefinite or not supported)
Raises:
GSSError
"""

cdef gss_buffer_desc password_buffer = gss_buffer_desc(len(password),
password)

cdef gss_cred_usage_t c_usage
if usage == "initiate":
c_usage = GSS_C_INITIATE
elif usage == "accept":
c_usage = GSS_C_ACCEPT
else:
c_usage = GSS_C_BOTH

cdef OM_uint32 input_initiator_ttl = c_py_ttl_to_c(init_lifetime)
cdef OM_uint32 input_acceptor_ttl = c_py_ttl_to_c(accept_lifetime)

cdef gss_cred_id_t creds
cdef gss_OID_set actual_mechs
cdef OM_uint32 actual_initiator_ttl
cdef OM_uint32 actual_acceptor_ttl

cdef OM_uint32 maj_stat, min_stat

with nogil:
maj_stat = gss_add_cred_with_password(
&min_stat, input_cred.raw_creds, name.raw_name, &mech.raw_oid,
&password_buffer, c_usage, input_initiator_ttl,
input_acceptor_ttl, &creds, &actual_mechs, &actual_initiator_ttl,
&actual_acceptor_ttl)

cdef Creds rc
if maj_stat == GSS_S_COMPLETE:
rc = Creds()
rc.raw_creds = creds
return AddCredResult(rc, c_create_oid_set(actual_mechs),
c_c_ttl_to_py(actual_initiator_ttl),
c_c_ttl_to_py(actual_acceptor_ttl))
else:
raise GSSError(maj_stat, min_stat)
47 changes: 47 additions & 0 deletions gssapi/tests/test_raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ def tearDownClass(cls):


class TestBaseUtilities(_GSSAPIKerberosTestCase):
def setUp(self):
self.realm.kinit(SERVICE_PRINCIPAL.decode("UTF-8"), flags=['-k'])

def test_indicate_mechs(self):
mechs = gb.indicate_mechs()

Expand Down Expand Up @@ -449,6 +452,50 @@ def test_inquire_mechs_for_name(self):
res.shouldnt_be_none()
res.should_include(gb.MechType.kerberos)

@_extension_test('password', 'Password')
def test_acquire_cred_with_password(self):
password = self.realm.password('user')
self.realm.kinit(self.realm.user_princ, password=password)

name = gb.import_name(b'user', gb.NameType.kerberos_principal)

imp_resp = gb.acquire_cred_with_password(name,
password.encode('UTF-8'))
imp_resp.shouldnt_be_none()

imp_creds, actual_mechs, output_ttl = imp_resp

imp_creds.shouldnt_be_none()
imp_creds.should_be_a(gb.Creds)

actual_mechs.shouldnt_be_empty()
actual_mechs.should_include(gb.MechType.kerberos)

output_ttl.should_be_a(int)

@_extension_test('password_add', 'Password (add)')
def test_add_cred_with_password(self):
password = self.realm.password('user')
self.realm.kinit(self.realm.user_princ, password=password)

name = gb.import_name(b'user', gb.NameType.kerberos_principal)

input_creds = gb.Creds()
imp_resp = gb.add_cred_with_password(input_creds, name,
gb.MechType.kerberos,
password.encode('UTF-8'))
imp_resp.shouldnt_be_none()

new_creds, actual_mechs, output_init_ttl, output_accept_ttl = imp_resp

actual_mechs.shouldnt_be_empty()
actual_mechs.should_include(gb.MechType.kerberos)

output_init_ttl.should_be_a(int)
output_accept_ttl.should_be_a(int)

new_creds.should_be_a(gb.Creds)


class TestIntEnumFlagSet(unittest.TestCase):
def test_create_from_int(self):
Expand Down
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ def gssapi_modules(lst):
extension_file('cred_store', 'gss_store_cred_into'),
extension_file('rfc5588', 'gss_store_cred'),
extension_file('cred_imp_exp', 'gss_import_cred'),

# see ext_password{,_add}.pyx for more information on this split
extension_file('password', 'gss_acquire_cred_with_password'),
extension_file('password_add', 'gss_add_cred_with_password'),
]),
keywords=['gssapi', 'security'],
install_requires=[
Expand Down

0 comments on commit 416d20c

Please sign in to comment.