Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_with_password functions from Solaris/IAKERB #40

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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