[pecl-authentication-krb5] master: Add GSSAPIContext::storeCredentials() (#15)
| From: | David Härdeman via GitHub | Date: | Tue, 09 Jun 2026 08:48:20 +0000 |
| Subject: | [pecl-authentication-krb5] master: Add GSSAPIContext::storeCredentials() (#15) | ||
| Groups: | php.pecl.cvs | ||
| Request: | Send a blank email to pecl-cvs+get-28570@lists.php.net to get a copy of this message | ||
Author: David Härdeman (Alphix)
Committer: GitHub (web-flow)
Pusher: mbechler
Date: 2026-06-09T10:48:18+02:00
Commit: https://github.com/php/pecl-authentication-krb5/commit/3089f06a05068000782b52c0710776799e1e76ae
Raw diff: https://github.com/php/pecl-authentication-krb5/commit/3089f06a05068000782b52c0710776799e1e76ae.diff
Add GSSAPIContext::storeCredentials() (#15)
Complements gss_acquire_cred_from(): stores the context's credentials into
a named ccache supplied as a "ccache" key/value element, following the same
gss_key_value_set_desc pattern used in negotiate_auth.c.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Changed paths:
A tests/008.phpt
M config.m4
M gssapi.c
Diff:
diff --git a/config.m4 b/config.m4
index 2c686df..b05bab3 100644
--- a/config.m4
+++ b/config.m4
@@ -91,6 +91,7 @@ if test "$PHP_KRB5" != "no" -o "$PHP_KRB5KADM" !=
"no"; then
AC_CHECK_FUNCS(krb5_free_string)
AC_CHECK_FUNCS(gss_acquire_cred_from)
AC_CHECK_FUNCS(gss_export_cred)
+ AC_CHECK_FUNCS(gss_store_cred_into)
AC_CHECK_FUNCS(krb5_chpw_message)
AC_CHECK_FUNCS(krb5_principal_get_realm)
AC_CHECK_FUNCS(krb5_get_init_creds_opt_set_expire_callback)
diff --git a/gssapi.c b/gssapi.c
index ebf2c68..2423491 100644
--- a/gssapi.c
+++ b/gssapi.c
@@ -98,6 +98,15 @@ ZEND_BEGIN_ARG_INFO_EX(krb5_GSSAPIContext_importCredentials, 0, 0, 1)
ZEND_END_ARG_INFO()
#endif
+#ifdef HAVE_GSS_STORE_CRED_INTO
+ZEND_BEGIN_ARG_INFO_EX(krb5_GSSAPIContext_storeCredentials, 0, 0, 1)
+ ZEND_ARG_INFO(0, ccache)
+ ZEND_ARG_INFO(0, usage)
+ ZEND_ARG_INFO(0, overwrite)
+ ZEND_ARG_INFO(0, default_cred)
+ZEND_END_ARG_INFO()
+#endif
+
PHP_METHOD(GSSAPIContext, registerAcceptorIdentity);
PHP_METHOD(GSSAPIContext, acquireCredentials);
PHP_METHOD(GSSAPIContext, inquireCredentials);
@@ -112,6 +121,9 @@ PHP_METHOD(GSSAPIContext, getTimeRemaining);
PHP_METHOD(GSSAPIContext, exportCredentials);
PHP_METHOD(GSSAPIContext, importCredentials);
#endif
+#ifdef HAVE_GSS_STORE_CRED_INTO
+PHP_METHOD(GSSAPIContext, storeCredentials);
+#endif
static zend_function_entry krb5_gssapi_context_functions[] = {
PHP_ME(GSSAPIContext, registerAcceptorIdentity, krb5_GSSAPIContext_registerAcceptorIdentity,
ZEND_ACC_PUBLIC)
@@ -127,6 +139,9 @@ static zend_function_entry krb5_gssapi_context_functions[] = {
#ifdef HAVE_GSS_EXPORT_CRED
PHP_ME(GSSAPIContext, exportCredentials, krb5_GSSAPIContext_none,
ZEND_ACC_PUBLIC)
PHP_ME(GSSAPIContext, importCredentials, krb5_GSSAPIContext_importCredentials,
ZEND_ACC_PUBLIC)
+#endif
+#ifdef HAVE_GSS_STORE_CRED_INTO
+ PHP_ME(GSSAPIContext, storeCredentials, krb5_GSSAPIContext_storeCredentials,
ZEND_ACC_PUBLIC)
#endif
PHP_FE_END
};
@@ -1010,3 +1025,47 @@ PHP_METHOD(GSSAPIContext, importCredentials)
RETURN_TRUE;
} /* }}} */
#endif
+
+#ifdef HAVE_GSS_STORE_CRED_INTO
+/* {{{ proto bool GSSAPIContext::storeCredentials( string $ccache [, int $usage = GSS_C_BOTH [,
bool $overwrite = true [, bool $default_cred = false ]]] )
+ Stores the current credentials into the named ccache using gss_store_cred_into() */
+PHP_METHOD(GSSAPIContext, storeCredentials)
+{
+ OM_uint32 status = 0;
+ OM_uint32 minor_status = 0;
+ krb5_gssapi_context_object *context = KRB5_THIS_GSSAPI_CONTEXT;
+ char *ccache_name = NULL;
+ strsize_t ccache_len = 0;
+ zend_long cred_usage = GSS_C_BOTH;
+ zend_bool overwrite = 1;
+ zend_bool default_cred = 0;
+ gss_key_value_element_desc ccache_element;
+ gss_key_value_set_desc cred_store;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbb",
+ &ccache_name, &ccache_len,
+ &cred_usage,
+ &overwrite,
+ &default_cred) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (context->creds == GSS_C_NO_CREDENTIAL) {
+ zend_throw_exception(NULL, "No credentials to store", 0 TSRMLS_CC);
+ return;
+ }
+
+ ccache_element.key = "ccache";
+ ccache_element.value = ccache_name;
+ cred_store.count = 1;
+ cred_store.elements = &ccache_element;
+
+ status = gss_store_cred_into(&minor_status, context->creds,
+ (gss_cred_usage_t)cred_usage, GSS_C_NO_OID,
+ (OM_uint32)overwrite, (OM_uint32)default_cred,
+ &cred_store, NULL, NULL);
+ ASSERT_GSS_SUCCESS(status, minor_status,);
+
+ RETURN_TRUE;
+} /* }}} */
+#endif
diff --git a/tests/008.phpt b/tests/008.phpt
new file mode 100644
index 0000000..8fc7425
--- /dev/null
+++ b/tests/008.phpt
@@ -0,0 +1,93 @@
+--TEST--
+Testing for credential store via storeCredentials()
+--SKIPIF--
+<?php
+if(!file_exists(dirname(__FILE__) . '/config.php')) { echo "skip config
missing"; return; }
+if(!include(dirname(__FILE__) . '/config.php')) return;
+if(!method_exists('GSSAPIContext', 'storeCredentials')) { echo "skip
gss_store_cred_into not available"; return; }
+if(!method_exists('GSSAPIContext', 'exportCredentials')) { echo "skip
gss_export_cred not available"; return; }
+?>
+--FILE--
+<?php
+include(dirname(__FILE__) . '/config.php');
+$client = new KRB5CCache();
+if($use_config) {
+ $client->setConfig(dirname(__FILE__) . '/krb5.ini');
+}
+
+$client->initPassword($client_principal, $client_password, array('forwardable' =>
true, 'proxiable' => true));
+
+$server = new KRB5CCache();
+if($use_config) {
+ $server->setConfig(dirname(__FILE__) . '/krb5.ini');
+}
+
+$server->initKeytab($server_principal, $server_keytab);
+
+$cgssapi = new GSSAPIContext();
+$sgssapi = new GSSAPIContext();
+
+$cgssapi->acquireCredentials($client);
+$sgssapi->acquireCredentials($server);
+
+$token = '';
+$token2 = '';
+$principal = '';
+$ret_flags = 0;
+$time_rec = 0;
+$deleg = new KRB5CCache();
+
+// Establish a context with delegation to obtain delegated credentials
+var_dump($cgssapi->initSecContext($server_principal, null, GSS_C_DELEG_FLAG, null, $token));
+var_dump($sgssapi->acceptSecContext($token, $token2, $principal, $ret_flags, $time_rec,
$deleg));
+var_dump(count($deleg->getEntries()));
+
+// Acquire credentials from the delegated ccache, then export and re-import them
+$dgssapi = new GSSAPIContext();
+$dgssapi->acquireCredentials($deleg, $principal, GSS_C_INITIATE);
+
+$exported = $dgssapi->exportCredentials();
+var_dump(is_string($exported) && strlen($exported) > 0);
+
+$igssapi = new GSSAPIContext();
+var_dump($igssapi->importCredentials($exported));
+
+// Store the imported credentials into a FILE ccache
+$tmpcc_path = tempnam(sys_get_temp_dir(), 'krb5cc_pecl_');
+unlink($tmpcc_path); // let gss_store_cred_into create the ccache fresh
+$tmpcc = 'FILE:' . $tmpcc_path;
+var_dump($igssapi->storeCredentials($tmpcc));
+
+// Verify the stored ccache contains credentials
+$storedcc = new KRB5CCache();
+$storedcc->open($tmpcc);
+var_dump(count($storedcc->getEntries()) > 0);
+
+// Use the stored credentials to authenticate to the server
+$s2gssapi = new GSSAPIContext();
+$s2gssapi->acquireCredentials($server);
+
+$ngssapi = new GSSAPIContext();
+$ngssapi->acquireCredentials($storedcc, $principal, GSS_C_INITIATE);
+
+$token = '';
+$token2 = '';
+$principal2 = '';
+
+var_dump($ngssapi->initSecContext($server_principal, null, null, null, $token));
+var_dump($s2gssapi->acceptSecContext($token, $token2, $principal2, $ret_flags, $time_rec,
$deleg));
+var_dump($principal2 === $principal);
+
+@unlink($tmpcc_path);
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+int(1)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)