Skip to content

Commit de10b0f

Browse files
Add gss_a{dd,cquire}_cred_with_password functions from Solaris/IAKERB
This closes #5.
1 parent dec88d0 commit de10b0f

File tree

6 files changed

+276
-0
lines changed

6 files changed

+276
-0
lines changed

docs/source/gssapi.raw.rst

+16
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@ raw Package
5757
:undoc-members:
5858
:show-inheritance:
5959

60+
:mod:`ext_password` Module
61+
---------------------
62+
63+
.. automodule:: gssapi.raw.ext_password
64+
:members:
65+
:undoc-members:
66+
:show-inheritance:
67+
68+
:mod:`ext_password_add` Module
69+
---------------------
70+
71+
.. automodule:: gssapi.raw.ext_password_add
72+
:members:
73+
:undoc-members:
74+
:show-inheritance:
75+
6076
:mod:`mech_krb5` Module
6177
-----------------------
6278

gssapi/raw/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,10 @@
3636
import gssapi.raw.mech_krb5 # noqa
3737
except ImportError:
3838
pass
39+
40+
# optional password support
41+
try:
42+
from gssapi.raw.ext_password import * # noqa
43+
from gssapi.raw.ext_password_add import * # noqa
44+
except ImportError:
45+
pass

gssapi/raw/ext_password.pyx

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
GSSAPI="BASE" # This ensures that a full module is generated by Cythin
2+
3+
# Due to a bug in MIT Kerberos, add_cred_with_password was not properly
4+
# exported for some time. In order to work around this,
5+
# add_cred_with_password is in its own file. For more information, see:
6+
# https://github.com/krb5/krb5/pull/244
7+
8+
from gssapi.raw.cython_types cimport *
9+
from gssapi.raw.cython_converters cimport c_get_mech_oid_set
10+
from gssapi.raw.cython_converters cimport c_create_oid_set
11+
from gssapi.raw.cython_converters cimport c_py_ttl_to_c, c_c_ttl_to_py
12+
from gssapi.raw.creds cimport Creds
13+
from gssapi.raw.names cimport Name
14+
15+
from gssapi.raw.misc import GSSError
16+
from gssapi.raw.named_tuples import AcquireCredResult
17+
18+
cdef extern from "gssapi/gssapi_ext.h":
19+
OM_uint32 gss_acquire_cred_with_password(OM_uint32 *min_stat,
20+
const gss_name_t desired_name,
21+
const gss_buffer_t password,
22+
OM_uint32 ttl,
23+
const gss_OID_set desired_mechs,
24+
gss_cred_usage_t cred_usage,
25+
gss_cred_id_t *output_creds,
26+
gss_OID_set *actual_mechs,
27+
OM_uint32 *actual_ttl) nogil
28+
29+
30+
def acquire_cred_with_password(Name name not None, password not None,
31+
lifetime=None, mechs=None, usage="initiate"):
32+
"""
33+
Acquire credentials through provided password.
34+
35+
This function is originally from Solaris and is not documented by either
36+
MIT or Heimdal.
37+
38+
Args:
39+
name (Name): the name to acquire credentials for
40+
password (str): the password used to acquire credentialss with
41+
lifetime (int): the lifetime for the credentials (or None for
42+
indefinite)
43+
mechs ([MechType]): the desired mechanisms for which the credentials
44+
should work (or None for the default set)
45+
usage (str): usage type for credentials. Possible values:
46+
'initiate' (default), 'accept', 'both' (failsafe).
47+
48+
Returns:
49+
AcquireCredResult: the resulting credentials, the actual mechanisms
50+
with which they may be used, and their actual lifetime (or None for
51+
indefinite or not supported)
52+
53+
Raises:
54+
GSSError
55+
"""
56+
57+
cdef gss_buffer_desc password_buffer = gss_buffer_desc(len(password),
58+
password)
59+
60+
cdef OM_uint32 input_ttl = c_py_ttl_to_c(lifetime)
61+
62+
cdef gss_OID_set desired_mechs
63+
if mechs is not None:
64+
desired_mechs = c_get_mech_oid_set(mechs)
65+
else:
66+
desired_mechs = GSS_C_NO_OID_SET
67+
68+
cdef gss_cred_usage_t c_usage
69+
if usage == "initiate":
70+
c_usage = GSS_C_INITIATE
71+
elif usage == "accept":
72+
c_usage = GSS_C_ACCEPT
73+
else:
74+
c_usage = GSS_C_BOTH
75+
76+
cdef gss_cred_id_t creds
77+
cdef gss_OID_set actual_mechs
78+
cdef OM_uint32 actual_ttl
79+
80+
cdef OM_uint32 maj_stat, min_stat
81+
82+
with nogil:
83+
maj_stat = gss_acquire_cred_with_password(
84+
&min_stat, name.raw_name, &password_buffer, input_ttl,
85+
desired_mechs, c_usage, &creds, &actual_mechs, &actual_ttl)
86+
87+
cdef OM_uint32 tmp_min_stat
88+
if mechs is not None:
89+
gss_release_oid_set(&tmp_min_stat, &desired_mechs)
90+
91+
cdef Creds rc = Creds()
92+
if maj_stat == GSS_S_COMPLETE:
93+
rc.raw_creds = creds
94+
return AcquireCredResult(rc, c_create_oid_set(actual_mechs),
95+
c_c_ttl_to_py(actual_ttl))
96+
else:
97+
raise GSSError(maj_stat, min_stat)

gssapi/raw/ext_password_add.pyx

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
GSSAPI="BASE" # This ensures that a full module is generated by Cythin
2+
3+
# Due to a bug in MIT Kerberos, add_cred_with_password was not properly
4+
# exported for some time. In order to work around this,
5+
# add_cred_with_password is in its own file. For more information, see:
6+
# https://github.com/krb5/krb5/pull/244
7+
8+
from gssapi.raw.cython_types cimport *
9+
from gssapi.raw.cython_converters cimport c_get_mech_oid_set
10+
from gssapi.raw.cython_converters cimport c_create_oid_set
11+
from gssapi.raw.cython_converters cimport c_py_ttl_to_c, c_c_ttl_to_py
12+
from gssapi.raw.creds cimport Creds
13+
from gssapi.raw.names cimport Name
14+
from gssapi.raw.oids cimport OID
15+
16+
from gssapi.raw.misc import GSSError
17+
from gssapi.raw.named_tuples import AddCredResult
18+
19+
cdef extern from "gssapi/gssapi_ext.h":
20+
OM_uint32 gss_add_cred_with_password(OM_uint32 *min_stat,
21+
const gss_cred_id_t input_cred_handle,
22+
const gss_name_t desired_name,
23+
const gss_OID desired_mech,
24+
const gss_buffer_t password,
25+
gss_cred_usage_t cred_usage,
26+
OM_uint32 initiator_ttl,
27+
OM_uint32 acceptor_ttl,
28+
gss_cred_id_t *output_creds,
29+
gss_OID_set *actual_mechs,
30+
OM_uint32 *actual_init_ttl,
31+
OM_uint32 *actual_accept_ttl) nogil
32+
33+
34+
def add_cred_with_password(Creds input_cred not None, Name name not None,
35+
OID mech not None, password not None,
36+
usage="initiate", init_lifetime=None,
37+
accept_lifetime=None):
38+
39+
"""
40+
Add a credential-element to a credential using provided password.
41+
42+
This function is originally from Solaris and is not documented by either
43+
MIT or Heimdal.
44+
45+
Args:
46+
input_cred (Creds): the credentials to add to
47+
name (Name): the name to acquire credentials for
48+
mech (MechType): the desired mechanism. Note that this is both
49+
singular and required
50+
password (str): the password used to acquire credentialss with
51+
usage (str): the usage type for the credentials: may be
52+
'initiate', 'accept', or 'both'
53+
init_lifetime (int): the lifetime for the credentials to remain valid
54+
when using them to initiate security contexts (or None for
55+
indefinite)
56+
accept_lifetime (int): the lifetime for the credentials to remain
57+
valid when using them to accept security contexts (or None for
58+
indefinite)
59+
60+
Returns:
61+
AddCredResult: the actual mechanisms with which the credentials may be
62+
used, the actual initiator TTL, and the actual acceptor TTL (the TTLs
63+
may be None for indefinite or not supported)
64+
65+
Raises:
66+
GSSError
67+
"""
68+
69+
cdef gss_buffer_desc password_buffer = gss_buffer_desc(len(password),
70+
password)
71+
72+
cdef gss_cred_usage_t c_usage
73+
if usage == "initiate":
74+
c_usage = GSS_C_INITIATE
75+
elif usage == "accept":
76+
c_usage = GSS_C_ACCEPT
77+
else:
78+
c_usage = GSS_C_BOTH
79+
80+
cdef OM_uint32 input_initiator_ttl = c_py_ttl_to_c(init_lifetime)
81+
cdef OM_uint32 input_acceptor_ttl = c_py_ttl_to_c(accept_lifetime)
82+
83+
cdef gss_cred_id_t creds
84+
cdef gss_OID_set actual_mechs
85+
cdef OM_uint32 actual_initiator_ttl
86+
cdef OM_uint32 actual_acceptor_ttl
87+
88+
cdef OM_uint32 maj_stat, min_stat
89+
90+
with nogil:
91+
maj_stat = gss_add_cred_with_password(
92+
&min_stat, input_cred.raw_creds, name.raw_name, &mech.raw_oid,
93+
&password_buffer, c_usage, input_initiator_ttl,
94+
input_acceptor_ttl, &creds, &actual_mechs, &actual_initiator_ttl,
95+
&actual_acceptor_ttl)
96+
97+
cdef Creds rc
98+
if maj_stat == GSS_S_COMPLETE:
99+
rc = Creds()
100+
rc.raw_creds = creds
101+
return AddCredResult(rc, c_create_oid_set(actual_mechs),
102+
c_c_ttl_to_py(actual_initiator_ttl),
103+
c_c_ttl_to_py(actual_acceptor_ttl))
104+
else:
105+
raise GSSError(maj_stat, min_stat)

gssapi/tests/test_raw.py

+47
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ def tearDownClass(cls):
5353

5454

5555
class TestBaseUtilities(_GSSAPIKerberosTestCase):
56+
def setUp(self):
57+
self.realm.kinit(SERVICE_PRINCIPAL.decode("UTF-8"), flags=['-k'])
58+
5659
def test_indicate_mechs(self):
5760
mechs = gb.indicate_mechs()
5861

@@ -449,6 +452,50 @@ def test_inquire_mechs_for_name(self):
449452
res.shouldnt_be_none()
450453
res.should_include(gb.MechType.kerberos)
451454

455+
@_extension_test('password', 'Password')
456+
def test_acquire_cred_with_password(self):
457+
password = self.realm.password('user')
458+
self.realm.kinit(self.realm.user_princ, password=password)
459+
460+
name = gb.import_name(b'user', gb.NameType.kerberos_principal)
461+
462+
imp_resp = gb.acquire_cred_with_password(name,
463+
password.encode('UTF-8'))
464+
imp_resp.shouldnt_be_none()
465+
466+
imp_creds, actual_mechs, output_ttl = imp_resp
467+
468+
imp_creds.shouldnt_be_none()
469+
imp_creds.should_be_a(gb.Creds)
470+
471+
actual_mechs.shouldnt_be_empty()
472+
actual_mechs.should_include(gb.MechType.kerberos)
473+
474+
output_ttl.should_be_a(int)
475+
476+
@_extension_test('password_add', 'Password (add)')
477+
def test_add_cred_with_password(self):
478+
password = self.realm.password('user')
479+
self.realm.kinit(self.realm.user_princ, password=password)
480+
481+
name = gb.import_name(b'user', gb.NameType.kerberos_principal)
482+
483+
input_creds = gb.Creds()
484+
imp_resp = gb.add_cred_with_password(input_creds, name,
485+
gb.MechType.kerberos,
486+
password.encode('UTF-8'))
487+
imp_resp.shouldnt_be_none()
488+
489+
new_creds, actual_mechs, output_init_ttl, output_accept_ttl = imp_resp
490+
491+
actual_mechs.shouldnt_be_empty()
492+
actual_mechs.should_include(gb.MechType.kerberos)
493+
494+
output_init_ttl.should_be_a(int)
495+
output_accept_ttl.should_be_a(int)
496+
497+
new_creds.should_be_a(gb.Creds)
498+
452499

453500
class TestIntEnumFlagSet(unittest.TestCase):
454501
def test_create_from_int(self):

setup.py

+4
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ def gssapi_modules(lst):
191191
extension_file('cred_store', 'gss_store_cred_into'),
192192
extension_file('rfc5588', 'gss_store_cred'),
193193
extension_file('cred_imp_exp', 'gss_import_cred'),
194+
195+
# see ext_password{,_add}.pyx for more information on this split
196+
extension_file('password', 'gss_acquire_cred_with_password'),
197+
extension_file('password_add', 'gss_add_cred_with_password'),
194198
]),
195199
keywords=['gssapi', 'security'],
196200
install_requires=[

0 commit comments

Comments
 (0)