c - 将 GSS-SPNEGO 与 gss_krb5_import_cred 结合使用

标签 c ldap kerberos gssapi

我正在尝试实现为我的应用程序请求 TGT 的编程逻辑,因此在通过 GSSAPI 和 GSS 对 LDAP 服务器进行身份验证之前,无需从命令行调用 kinit SPNEGO机制。

我创建一个内存中 ccache,使用用户名和密码请求 TGT,然后使用 gss_krb5_import_cred 导入凭据。在开始身份验证之前,为 LDAP 结构设置 GSSAPI 上下文。

下面的示例代码在 GSSAPI 中运行良好,但是当我尝试将机制更改为 GSS-SPNEGO 时,出现本地 LDAP 错误 (-2),并显示以下消息:

SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (SPNEGO cannot find mechanisms to negotiate)

int create_krb5_cred(krb5_context ctx, char *realm, char *user,
    char *password, krb5_ccache *ccache, gss_cred_id_t *gsscred) {
    int rc = 0, minor_stat = 0;
    int len = 0;
    const char *cname = NULL;
    krb5_get_init_creds_opt *cred_opt;
    krb5_creds creds;
    krb5_principal princ = NULL;

    if (realm == NULL || user == NULL || password == NULL) return -1;

    rc = krb5_cc_new_unique(ctx, "MEMORY", NULL, ccache);
    if (rc != 0) goto clear;

    len = strlen(realm);
    rc = krb5_build_principal(ctx, &princ, len, realm, user, NULL);

    if (rc != 0) goto clear;

    rc = krb5_cc_initialize(ctx, *ccache, princ);
    if (rc != 0) goto clear;

    rc = krb5_get_init_creds_opt_alloc(ctx, &cred_opt);
    if (rc != 0) goto clear;

    rc = krb5_get_init_creds_password(ctx, &creds, princ, password, 0, NULL, 0, NULL, NULL);
    if (rc != 0) goto clear;

    rc= krb5_cc_store_cred(ctx, *ccache, &creds);
    if (rc != 0) goto clear;

    cname = krb5_cc_get_name(ctx, *ccache);
    if (cname == NULL) goto clear;

    rc = gss_krb5_ccache_name(&minor_stat, cname, NULL);
    if (rc != 0) goto clear;

    rc = gss_krb5_import_cred(&minor_stat, *ccache, princ, 0, gsscred);
 clear:
    if (princ != NULL) krb5_free_principal(ctx, princ);
    return rc;
}

int remove_krb5_cred(krb5_context ctx, krb5_ccache ccache, gss_cred_id_t *gsscred) {
    int rc = 0;

    rc = gss_release_cred(NULL, gsscred);
    if (rc != 0) return rc;

    rc = krb5_cc_destroy(ctx, ccache);
    krb5_free_context(ctx);

    return rc;
}

int main(void) {
    int rc = 0;
    krb5_context ctx;
    krb5_ccache ccache;
    gss_cred_id_t gsscred = NULL;

    rc = krb5_init_context(&ctx);
    create_krb5_cred(ctx, "EXAMPLE.ORG", "testuser", "secret", &ccache, &gsscred);
    LDAP *ld = NULL;
    const int version = LDAP_VERSION3;
    void *defaults = NULL;
    ldap_initialize(&ld, "ldap://example.org");
    ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
    /* Setting the credentials and handling the SASL binding with the `interact` function 
       (with setting the new GSS context) is not disclosed here...*/
    rc = ldap_sasl_interactive_bind_s(ld, NULL, "GSSAPI", NULL, NULL, 0, interact, defaults);
    printf("Connect 0x%x\n", rc);
    remove_krb5_cred(ctx, ccache, &gsscred);

    struct berval *authzid;
    rc = ldap_whoami_s(ld, &authzid, NULL, NULL);
    printf("RC %d %s\n\n", rc, authzid->bv_val);
}

This旧论坛帖子表明未为导入的凭据设置 SPNEGO oid,因此 LDAP 将在身份验证过程中忽略它。

我尝试使用 gss_acquire_cred 函数而不是 gss_krb5_import_cred,但我没有成功接收 TGT(甚至对于 GSSAPI 也是如此)。

任何有关如何使用 GSSAPI 和 GSS-SPNEGO 成功进行身份验证的想法都将受到欢迎。

更新:我已成功将 gss_acquire_cred 与 GSSAPI 和 GSS-SPNEGO 结合使用,但我必须使用基于文件的凭据缓存,而不是基于内存的凭据缓存。

最佳答案

要实现这一目标,需要采取几项行动:

  1. 获取常规 TGT。
  2. 确保 Cyrus SASL 针对 MIT Kerberos 正确编译。您可以使用 pluginviewer
  3. 进行检查
  4. 使 OpenLDAP 针对 Cyrus SASL 正确编译。
  5. 使用 ldapsearch 测试您的设置,以确保 Kerberos 实际工作。

如果一切顺利,请继续:

  • 使用公共(public)函数 gss_acquire_cred_with_password gssapi_ext.h .
  • 现在通过交互式绑定(bind)准备 LDAP 句柄,其他方法都不起作用。
  • 此句柄可以通过 Cyrus SASL 的身份验证,而 Cyrus SASL 需要采用该机制的格式。
  • 现在您需要使用指针和 sizeofgss_cred_t 传递给 berval 结构。
  • Cyrus SASL 将获取它并将其传递到 GSS 上下文。
  • 不幸的是,OpenLDAP 和 Cyrus SASL 的记录都很糟糕。我怎么知道它会起作用?我阅读了两者的源代码来理解和利用该用例。

    首先阅读头文件,您将得到结果。如果您遇到困难,请再次询问。

    关于c - 将 GSS-SPNEGO 与 gss_krb5_import_cred 结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35503916/

    相关文章:

    hadoop - 在 Kerberized 集群中读取 Spark 应用程序中的 HDFS 文件

    apache - 为什么不同域中的浏览器根本不响应 mod_auth_kerb 发送的 "WWW Authenticate : Negotiate" header ?

    c - 在 C 中使用空终止字符作为空指针

    c - 在哪里以及如何正确释放 malloc 指针?

    android - 如何在 Android Studio 中使用 Active Directory 或 LDAP 验证用户名和密码

    java - 如何在 Java 中针对此 LDAP 进行 LDAP 搜索/身份验证

    java - 如何使用 spring Security 根据邮件和 uid 从 LDAP 验证用户?

    java - 2 个 Java 线程能否作为两个不同的 Kerberos 用户(在同一进程中)进行身份验证?

    c - 字符常量中的多个字符

    c - 在 C 中如何使用大小写将枚举转换为字符串?