繁体   English   中英

无密码 LDAP 登录并在 PHP 中使用 Kerberos 票证获取用户信息

[英]passwordless LDAP login and get user information using Kerberos ticket in PHP

我正在尝试使用 FreeIPA/Kerberos 在我们公司的一些 Intranet 站点上实施 SSO。 但是关于这个主题的信息非常少。

我的测试网络中运行了三台机器:

  1. Centos 8 Stream 上的 FreeIPA v4.9.8 服务器
  2. Debian 11 上的 Web 服务器(Apache v2.4.53、PHP v7.4.28)
  3. 带有 Kinit 和 Firefox 的 Xubuntu 22.04 客户端

Kinit、Unix Login 和 Apache Kerberos Auth 工作。 客户端系统上的 Firefox 浏览器无需密码即可登录到 FreeIPA WebConfig(使用 Kerberos Ticket)。 我现在想将此功能转移到我们的内联网页面。 到目前为止,这些页面的登录都是基于传统的 LDAP 登录。 通过对登录脚本的细微调整,用户现在可以登录到新的 FreeIPA 服务器。 然而,他仍然需要他的密码,这实际上应该不再需要多亏了 Kerberos 票证。

问题是,无密码登录是什么样的?

登录脚本的功能片段:

<?php
$username = $_SERVER['PHP_AUTH_USER'];
$password = 'password';

$ldap_rdn  = 'uid='.$username.',cn=users,cn=accounts,dc=exampletest,dc=de';
$ldap_server = ldap_connect('ldap://ipa.exampletest.de:389');

ldap_set_option($ldap_server, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap_server, LDAP_OPT_REFERRALS, 0);

if ($ldap_server) {
  $ldap_bind = @ldap_bind($ldap_server, $ldap_rdn, $password);
  if ($ldap_bind) {
    $search = array("uid","givenname","sn","mail","uidnumber","gidnumber");
    $result = ldap_search($ldap_server, $ldap_rdn, "mail=$username*", $search);
    $info = ldap_get_entries($ldap_server, $result);

    print_r($info);
  }
}
?>

现在我有两个想法:

  1. 我可以使用 ldap_sasl_bind() 而不是 ldap_bind() 但这个函数没有记录在 php.net ( https://www.php.net/manual/en/function.ldap-sasl-bind.php ) 上。 如果有人知道如何使用此功能,我将不胜感激。
  2. 如果我能以某种方式在没有密码的情况下运行 ldap_search() 来获取用户信息(全名、电子邮件等),我也会很高兴。

提前谢谢了。

编辑:

Web 服务器 VM 和客户端 VM 都通过“ipa-client-install”进行初始化。 另外,web服务器已经注册了apache服务(ipa service-add HTTP/ebook.exampletest.de)。

apache 配置也反映了这一点:

<Directory /var/www/ebook/>
        AuthType                GSSAPI
        AuthName                "eBook Login"
        GssapiCredStore         keytab:/etc/apache2/http.keytab
        GssapiAllowedMech       krb5
        GssapiBasicAuthMech     krb5
        GssapiImpersonate       On
        GssapiDelegCcacheDir    /run/apache2/clientcaches
        GssapiLocalName         On
        
        # for production set to on:
        GssapiSSLonly           Off
        GssapiNegotiateOnce     Off
        
        GssapiUseSessions       On
        Session                 On
        SessionCookieName       gssapi_session path=/private;httponly;secure;
        Require                 valid-user
    </Directory>

正如我已经提到的,用户身份验证似乎以这种方式工作( client (own ticket) > web service (own ticket) > ipa server )。 否则 apache 服务器不会返回我的 ldap/kerberos 用户名。 还是我在这里遗漏了一些重要的东西? 是否有另一种方法来强制执行这种身份验证?

<?php print_r($_SERVER) ?>的输出(截断)

[GSS_MECH] => Negotiate/krb5
[GSS_NAME] => test@EXAMPLETEST.DE
[REMOTE_USER] => test
[AUTH_TYPE] => Negotiate
[PHP_AUTH_USER] => test

然而,他仍然需要他的密码,这实际上应该不再需要多亏了 Kerberos 票证。

确保您的 Web 服务器具有正确的 Kerberos 票证。

通常 Kerberos 身份验证仅传输仅对该服务器有效的票证,而不是一揽子“一切”票证。 当客户端向您的 webapp 进行身份验证时,您得到的只是HTTP/webapp.example.tld的票证,您不能真正使用它代表用户访问 LDAP。

如果您需要代表用户访问 LDAP,则存在一些选项:

  • webapp 可以拥有自己的 LDAP 目录凭据。 这可能是最简单的方法。 webapp 可以使用标准密码绑定,也可以使用 Kerberos (SASL) 绑定从 keytab 获取的自己的票证。

    • LDAP 还支持“模拟”,其中 web 应用程序将使用自己的凭据进行身份验证,但指定一个“授权 ID”(authzid)来确定您将获得哪个帐户的权限。

      例如,如果您以 'webapp' 身份进行身份验证,但指定 authzid 'myuser'(并且如果 LDAP 服务器允许这样做),那么您将获得 'myuser' 通常拥有的权限 - 而不是 'webapp' 的权限。

  • webapp 的 HTTP 协商 (SPNEGO) 身份验证可以启用“委托”。 委托确实将主krbtgt票证传输到 Web 服务器,然后将其放入临时票证缓存中,并提供给您的 Web 应用程序环境。

    然而,委派有一些问题:

    1. 它使每个 HTTP 请求变慢,因为客户端必须使用“转发”标志请求新的krbtgt票证(除非 Web 服务器可以使用例如 cookie 来避免为进一步的请求请求协商身份验证,例如带有“会话”模式的 mod_auth_gssapi) .

    2. 它要求 webapp 是高度可信的,因为它将为每个访问它的用户(包括管理员)存储通配符票证——即使 webapp 本身被信任不会滥用它们,它们仍然可能从服务器中被盗。

    3. 大多数使用 Kerberos 的 API(包括 ldap_sasl_bind())都期望KRB5CCNAME环境变量指向票证缓存。 但是环境变量是进程范围的,所以只要 PHP 重用同一个进程(或者更糟糕的是,如果你使用 mod_php 在 Apache 进程中运行 webapp),它们就会在不相关的请求之间泄漏。

    在 AD 中,这被特别称为“无约束委派”,因为 AD 引入了其他变体。

  • webapp 可以使用 S4U2Proxy 又名“约束委派”来代表用户为一组有限的服务创建票证(例如,FreeIPA 可以将其限制为仅访问ldap/foo.example.com )。

    这有点复杂(PHP 没有用于此的 API——您可能需要使用正确的标志生成kinit ),并且仍然存在与 KRB5CCNAME 跨请求泄漏相同的潜在问题。

我可以使用 ldap_sasl_bind() 而不是 ldap_bind() 但这个函数没有记录在 php.net ( https://www.php.net/manual/en/function.ldap-sasl-bind.php ) 上。 如果有人知道如何使用此功能,我将不胜感激。

对于常规的 Kerberos 身份验证,用法如下所示:

ldap_sasl_bind($conn, null, null, "GSSAPI");

就这样。 GSSAPI SASL 机制期望环境已经有可用的 Kerberos 票证(例如,通过 $KRB5CCNAME 或通过 gss-proxy),并且它将使用它在那里找到的任何票证进行身份验证。

如果您想使用模拟(假设已在 LDAP 服务器中设置),则必须指定 authz_id:

ldap_sasl_bind($conn, null, null, "GSSAPI", null, null, $theuser);

大多数ldap_*() PHP 函数都是 C libldap 库的直接包装器,因此它的文档可能作为部分参考有用。

$result = ldap_search($ldap_server, $ldap_rdn, "mail=$username*", $search);

您的示例似乎已经指定了用户的确切 DN,因此似乎不需要通过mail进行额外过滤 - 只需在读取特定 DN 时使用objectClass=*即可。 此外,当您要读取特定 DN 时,请使用ldap_read()进行“基本”搜索而不是子树搜索。

正如我已经提到的,用户身份验证似乎以这种方式工作(客户端(自己的票证)> Web 服务(自己的票证)> ipa 服务器)。 否则 apache 服务器不会返回我的 ldap/kerberos 用户名。

不,这不是它的工作原理。 您的用户名(即客户端 Kerberos 主体)存储在客户端票证中,因此 Web 服务器在解密票证后立即知道它,而根本无需与 IPA 对话。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM