I'm trying to implement SSO on some of our company's intranet sites using FreeIPA/Kerberos. But there is very little information on this topic.
I have three machines running on my test network:
Kinit, Unix login and Apache Kerberos Auth work. The Firefox browser on the client system can log into FreeIPA WebConfig without a password (using Kerberos Ticket). I now want to move this functionality to our intranet page. Until now, logins to these pages have been based on traditional LDAP logins. With a slight adjustment to the login script, users can now log in to the new FreeIPA server. However, he still needs a password, but thanks to the Kerberos ticket, the password is actually no longer required.
The question is, what does passwordless login look like?
Functional snippet of login script:
<?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); } } ?>
Now I have two thoughts:
Thank you very much in advance.
edit:
Both the Web server VM and the client VM are initialized via "ipa-client-install". In addition, the web server has registered the apache service (ipa service-add HTTP/ebook.exampletest.de).
The apache configuration also reflects this:
<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>As I already mentioned, user authentication seems to work like this (
client (own ticket)
> web service (own ticket) > ipa server
). Otherwise the apache server won't return my ldap/kerberos username. Or am I missing something important here? Is there any other way to enforce this authentication?
Output: <?php print_r($_SERVER) ?>
(Intercepted)
[GSS_MECH] => Negotiate/krb5 [GSS_NAME] => test@EXAMPLETEST.DE [REMOTE_USER] => test [AUTH_TYPE] => Negotiate [PHP_AUTH_USER] => test
Make sure your web server has a correct Kerberos ticket.
Typically, Kerberos authentication only transmits tickets that are valid only for that server, rather than a blanket of "all" tickets. When a client authenticates to your web app, all you get is a ticket for
HTTP/webapp.example.tld
, and you can't actually use it to access LDAP on behalf of the user.If you need to access LDAP on behalf of a user, you have the following options:
Network applications can have their own LDAP directory credentials. This is probably the easiest way. Web applications can use standard password binding or Kerberos (SASL) binding using their own tickets obtained from a keytab.
LDAP also supports "impersonation", where the web application will use its own credentials for authentication, but also specify an "Authorization ID" (authzid) to determine which account you will get permission.
For example, if you authenticate as "webapp" but specify the authzid "myuser" (and if the LDAP server allows it ), then you will get the permissions that "myuser" would normally have – instead of the “webapp” ones.
HTTP Negotiation (SPNEGO) authentication for web applications can enable "delegation". Delegation does transmit the master
krbtgt
ticket to the web server, which then places it in a temporary ticket cache and makes it available to your web application environment.However, there are some problems with delegation:
This will slow down every HTTP request because the client must request a new
krbtgt
ticket with the "forward" flag (unless the web server can use e.g. cookies to avoid the request negotiating the identity authentication) for further requests, e.g. mod_auth_gssapi with "session" mode).It requires the web application to be highly trusted because it will store wildcard tickets for every user who accesses it (including administrators) - even if the web application itself is trusted not to abuse them, they can still be Steal the server.
Most APIs that use Kerberos (including ldap_sasl_bind()) expect the
KRB5CCNAME
environment variable to point to the ticket cache. But environment variables are process-scoped, so they can be leaked on unrelated requests whenever PHP reuses the same process (or worse, if you use mod_php to run your web application inside the Apache process).In AD, this is specifically called "unconstrained delegation" since AD introduced additional variations.
Network applications can use S4U2Proxy aka "constrained delegation" to create tickets on behalf of users for certain limited sets of services (e.g. FreeIPA can restrict them to only access
ldap/foo.example.com
).This is a bit complicated (PHP doesn't have an API for this - you may need to generate a
kinit
with the correct flags), and still has the same potential issues as the KRB5CCNAME cross-request leak.For regular Kerberos authentication, the usage is as follows:
That’s all. The GSSAPI SASL mechanism expects the environment to already have a Kerberos ticket available (e.g. via $KRB5CCNAME or via gss-proxy), and it will authenticate using any ticket found there.
If you want to use impersonation (assuming it is set up in the LDAP server), you must specify the authz_id:
Most
ldap_*()
PHP functions are direct wrappers around the C libldap library, so its documentation can be used as a partial reference.It appears that your example already specifies the exact DN of the user, so additional filtering via
mail
does not seem to be required - just useobjectClass=*
specific when reading the mail DN. Also, when you want to read a specific DN, use ldap_read() for a "basic" search rather than a subtree search.No, that's not what happened. Your username (i.e. the client Kerberos principal) is stored in the client ticket, so the web server knows it immediately after decrypting the ticket without having to talk to IPA.