Ich versuche, SSO auf einigen Intranetseiten unseres Unternehmens mithilfe von FreeIPA/Kerberos zu implementieren. Es gibt jedoch nur sehr wenige Informationen zu diesem Thema.
In meinem Testnetzwerk laufen drei Maschinen:
Kinit, Unix-Login und Apache Kerberos Auth funktionieren. Der Firefox-Browser auf dem Client-System kann sich ohne Passwort bei FreeIPA WebConfig anmelden (mithilfe des Kerberos-Tickets). Ich möchte diese Funktionalität nun auf unsere Intranetseite verschieben. Bisher basierten die Anmeldungen auf diesen Seiten auf herkömmlichen LDAP-Anmeldungen. Mit einer leichten Anpassung des Anmeldeskripts können sich Benutzer jetzt beim neuen FreeIPA-Server anmelden. Allerdings benötigt er weiterhin ein Passwort, doch dank des Kerberos-Tickets ist das Passwort eigentlich nicht mehr erforderlich.
Die Frage ist, wie sieht eine passwortlose Anmeldung aus?
Funktioneller Ausschnitt des Anmeldeskripts:
<?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); } } ?>
Jetzt habe ich zwei Gedanken:
Vielen Dank im Voraus.
Herausgeber:
Sowohl die Webserver-VM als auch die Client-VM werden über „ipa-client-install“ initialisiert. Darüber hinaus hat der Webserver den Apache-Dienst registriert (ipa service-add HTTP/ebook.exampletest.de).
Die Apache-Konfiguration spiegelt dies auch wider:
<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>Wie ich bereits erwähnt habe, scheint die Benutzerauthentifizierung so zu funktionieren (
client(自己的票)
> web 服务(自己的票) > ipa server
). Andernfalls gibt der Apache-Server meinen LDAP/Kerberos-Benutzernamen nicht zurück. Oder übersehe ich hier etwas Wichtiges? Gibt es eine andere Möglichkeit, diese Authentifizierung durchzusetzen?
Ausgabe: <?php print_r($_SERVER) ?>
(abgefangen)
[GSS_MECH] => Negotiate/krb5 [GSS_NAME] => test@EXAMPLETEST.DE [REMOTE_USER] => test [AUTH_TYPE] => Negotiate [PHP_AUTH_USER] => test
确保您的 Web 服务器具有正确 Kerberos 票证。
通常,Kerberos 身份验证仅传输仅对该服务器有效的票证,而不是一揽子“所有”票证。当客户端对您的 web 应用进行身份验证时,您获得的只是
HTTP/webapp.example.tld
的票证,并且您无法真正使用它代表用户访问 LDAP。如果您需要代表用户访问 LDAP,则有以下几种选择:
网络应用程序可以拥有自己的 LDAP 目录凭据。这可能是最简单的方法。 Web 应用程序可以使用标准密码绑定,也可以使用从密钥表获取的自己的票证进行 Kerberos (SASL) 绑定。
LDAP 还支持“模拟”,即 Web 应用程序将使用自己的凭据进行身份验证,但还指定一个“授权 ID”(authzid) 来确定您将获得哪个帐户的权限。
例如,如果您以“webapp”身份进行身份验证,但指定了 authzid“myuser”(并且如果 LDAP 服务器允许),那么您将获得“myuser”通常所拥有的权限有 – 而不是“webapp”的那些。
Web 应用程序的 HTTP 协商 (SPNEGO) 身份验证可以启用“委托”。委派确实将主
krbtgt
票证传输到Web服务器,然后服务器会将其放入临时票证缓存中并可供您的Web应用程序环境使用。但是,委托有一些问题:
这会使每个 HTTP 请求变慢,因为客户端必须请求带有“转发”标志的新
krbtgt
票证(除非 Web 服务器可以使用例如 cookie 来避免请求协商身份验证)用于进一步的请求,例如带有“会话”模式的 mod_auth_gssapi)。它要求 Web 应用程序高度可信,因为它将为每个访问它的用户(包括管理员)存储通配符票证 - 即使 Web 应用程序本身被信任不会滥用它们,它们仍然可能被窃取服务器。
大多数使用 Kerberos 的 API(包括 ldap_sasl_bind())都期望
KRB5CCNAME
环境变量指向票证缓存。但环境变量是进程范围的,因此只要 PHP 重用同一进程,它们就可能会在不相关的请求中泄漏(或者更糟糕的是,如果您使用 mod_php 在 Apache 进程内运行 web 应用程序)。在 AD 中,这具体称为“无约束委派”,因为 AD 引入了其他变体。
网络应用程序可以使用 S4U2Proxy 又名“约束委派”来代表用户创建票证,以获取某些有限的服务集(例如,FreeIPA 可以将其限制为仅访问
ldap/foo.example.com
)。这有点复杂(PHP 没有这方面的 API - 您可能需要使用正确的标志生成
kinit
),并且仍然存在与 KRB5CCNAME 跨请求泄漏相同的潜在问题。对于常规 Kerberos 身份验证,用法如下所示:
仅此而已。 GSSAPI SASL 机制期望环境已经具有可用的 Kerberos 票证(例如通过 $KRB5CCNAME 或通过 gss-proxy),并且它将使用在那里找到的任何票证进行身份验证。
如果您想使用模拟(假设在 LDAP 服务器中设置),则必须指定 authz_id:
大多数
ldap_*()
PHP 函数都是 C libldap 库的直接包装器,因此其文档可作为部分参考。看来您的示例已经指定了用户的确切 DN,因此似乎不需要通过
mail
进行额外过滤 - 只需在读取邮件时使用objectClass=*
特定的DN。另外,当您想要读取特定 DN 时,请使用 ldap_read() 进行“基本”搜索而不是子树搜索。不,事情不是这样的。您的用户名(即客户端 Kerberos 主体)存储在客户端票证中,因此 Web 服务器在解密票证后立即知道它,而无需与 IPA 对话。