diff --git a/gssapi/raw/__init__.py b/gssapi/raw/__init__.py index 16a15ebf..054855d9 100644 --- a/gssapi/raw/__init__.py +++ b/gssapi/raw/__init__.py @@ -26,6 +26,11 @@ except ImportError: pass +try: + from gssapi.raw.ext_cred_imp_exp import * # noqa +except ImportError: + pass + # optional KRB5 mech support try: import gssapi.raw.mech_krb5 # noqa diff --git a/gssapi/raw/ext_cred_imp_exp.pyx b/gssapi/raw/ext_cred_imp_exp.pyx new file mode 100644 index 00000000..af92f47d --- /dev/null +++ b/gssapi/raw/ext_cred_imp_exp.pyx @@ -0,0 +1,86 @@ +GSSAPI="BASE" # This ensures that a full module is generated by Cython + +from gssapi.raw.cython_types cimport * +from gssapi.raw.cython_converters cimport c_create_oid_set +from gssapi.raw.cython_converters cimport c_get_mech_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 AcquireCredResult, AddCredResult + + +cdef extern from "gssapi/gssapi_ext.h": + OM_uint32 gss_export_cred(OM_uint32 *min_stat, gss_cred_id_t cred_handle, + gss_buffer_t token) nogil + + OM_uint32 gss_import_cred(OM_uint32 *min_stat, gss_buffer_t token, + gss_cred_id_t *cred_handle) nogil + + +def export_cred(Creds creds not None): + """Export GSSAPI credentials object + + This method exports a GSSSAPI credentials object into a token + which may be transmitted between different processes. + + Args: + creds (Creds): the credentials object to be exported + + Returns: + bytes: the exported token representing the given credentials object + + Raises: + GSSError + """ + + # GSS_C_EMPTY_BUFFER + cdef gss_buffer_desc exported_creds = gss_buffer_desc(0, NULL) + + cdef OM_uint32 maj_stat, min_stat + + with nogil: + maj_stat = gss_export_cred(&min_stat, creds.raw_creds, &exported_creds) + + if maj_stat == GSS_S_COMPLETE: + res = exported_creds.value[:exported_creds.length] + gss_release_buffer(&min_stat, &exported_creds) + return res + else: + raise GSSError(maj_stat, min_stat) + + +def import_cred(token not None): + """Import GSSAPI credentials from a token + + This method imports a credentials object from a token + previously exported by :func:`export_cred`. + + Args: + token (bytes): the token to import + + Returns: + Creds: the imported credentials object + + Raises: + GSSError + """ + + cdef gss_buffer_desc token_buffer = gss_buffer_desc(len(token), token) + + cdef gss_cred_id_t creds + + cdef OM_uint32 maj_stat, min_stat + + with nogil: + maj_stat = gss_import_cred(&min_stat, &token_buffer, &creds) + + cdef Creds res + if maj_stat == GSS_S_COMPLETE: + res = Creds() + res.raw_creds = creds + return res + else: + raise GSSError(maj_stat, min_stat) diff --git a/gssapi/tests/test_high_level.py b/gssapi/tests/test_high_level.py index 3bfffcce..5633444a 100644 --- a/gssapi/tests/test_high_level.py +++ b/gssapi/tests/test_high_level.py @@ -300,13 +300,13 @@ def test_store_into_add_from(self): retrieved_creds.shouldnt_be_none() retrieved_creds.should_be_a(gsscreds.Credentials) - @_extension_test('cred_imp_ext', 'credentials import-export') + @_extension_test('cred_imp_exp', 'credentials import-export') def test_export(self): creds = gsscreds.Credentials(name=self.name) token = creds.export() - token.should_be(bytes) + token.should_be_a(bytes) - @_extension_test('cred_imp_ext', 'credentials import-export') + @_extension_test('cred_imp_exp', 'credentials import-export') def test_import_by_init(self): creds = gsscreds.Credentials(name=self.name) token = creds.export() @@ -315,7 +315,7 @@ def test_import_by_init(self): imported_creds.lifetime.should_be(creds.lifetime) imported_creds.name.should_be(creds.name) - @_extension_test('cred_imp_ext', 'credentials import-export') + @_extension_test('cred_imp_exp', 'credentials import-export') def test_pickle_unpickle(self): creds = gsscreds.Credentials(name=self.name) pickled_creds = pickle.dumps(creds) diff --git a/gssapi/tests/test_raw.py b/gssapi/tests/test_raw.py index 3d0c4a52..a84ebaac 100644 --- a/gssapi/tests/test_raw.py +++ b/gssapi/tests/test_raw.py @@ -157,6 +157,17 @@ def test_acquire_creds(self): gb.release_name(name) gb.release_cred(creds) + @_extension_test('cred_imp_exp', 'credentials import-export') + def test_cred_import_export(self): + creds = gb.acquire_cred(None).creds + token = gb.export_cred(creds) + imported_creds = gb.import_cred(token) + + inquire_orig = gb.inquire_cred(creds, name=True) + inquire_imp = gb.inquire_cred(imported_creds, name=True) + + gb.compare_name(inquire_orig.name, inquire_imp.name).should_be_true() + def test_context_time(self): target_name = gb.import_name(TARGET_SERVICE_NAME, gb.NameType.hostbased_service) diff --git a/setup.py b/setup.py index 558dcb18..5a163200 100755 --- a/setup.py +++ b/setup.py @@ -190,6 +190,7 @@ def gssapi_modules(lst): extension_file('s4u', 'gss_acquire_cred_impersonate_name'), extension_file('cred_store', 'gss_store_cred_into'), extension_file('rfc5588', 'gss_store_cred'), + extension_file('cred_imp_exp', 'gss_import_cred'), ]), keywords=['gssapi', 'security'], install_requires=[