Maintaining State Across Requests / An SSO Extension

php.internals

Michael B Allen

20 years ago
Hello, I have a question that is maybe a little too advanced for the usual list so I'm hoping I can ask here. I want to write an extension for Kerberos 5 Single Sign On using GSSAPI. The problem is that GSSAPI is an iterative, multistep, statefull exchange. The request response flow might look like the following: C: GET /foo ----------> <---------- S: 401 Unauthorized WWW-Authenticate: Negotiate C: GET /foo ----------> Authorization: Negotiate <base64-token-1> <---------- S: 401 Unauthorized WWW-Authenticate: Negotiate <base64-token-2> C: GET /foo ----------> Authorization: Negotiate <base64-token-3> <---------- S: 200 <data> [Actually no state must be maintained for the initial request/response and for the Kerberos mechanism there's usually only two tokens which makes the whole exchange stateless. But for NTLMSSP there can be three tokens exchanged as depicted above and GSSAPI places no limit on the number of tokens exchanged for a given mechanism.] I'm sure you can imagine the headaches involved with trying to perform a stateful exchange over HTTP. In general the prevailing technique is to use a session cookie to maintain the state during the exchange. For example one might write this in PHP roughly like the following: function authenticate() { if (!isset($_SESSION["sso"])) { $_SESSION["sso"] = sso_new(); } $sso = $_SESSION["sso"]; $token = ""; $headers = apache_request_headers(); if (isset($headers["Authorization"])) { $token = $headers["Authorization"]; $token = sso_do_gssapi($sso, $token); switch (sso_status($sso)) { case SSO_SUCCESS: $_SESSION["auth"] = $sso; case SSO_FAILURE: unset($_SESSION["sso"]); return $sso; } $token = " " . $token; } header("WWW-Authenticate: Negotiate" . $token); header("HTTP/1.1 401 Unauthorized"); die("More processing required."); } I've read the tutorials and I have a working extension package but I need a better understanding of ZE internals with respect to maintaining state across requests. All of the examples register a dtor such that any variable returned is garbage collected after the request completes. For example, in the code above, if sso_new were to return a resource it is automatically unset from $_SESSION. I need it to persist. Ultimately I want to create one 'struct sso_context *' stored as a global (or one per MINIT is ok) from which I will derive 'struct sso *' objects in sso_new() that must persist for the life of the user's session. Can someone recommend a good technique for this? Thanks, Mike

Wez Furlong

20 years ago
Just curious, why aren't you writing this as an apache module? Is this of any use; it seems a bit dated, but could save you some effort: http://meta.cesnet.cz/cms/opencms/en/docs/software/devel/negotiate.html --Wez. On 12/21/05, Michael B Allen <mba2000@ioplex.com> wrote:

Michael B Allen

20 years ago
On Wed, 21 Dec 2005 01:58:41 -0500 Wez Furlong <kingwez@gmail.com> wrote:
> Just curious, why aren't you writing this as an apache module? > > Is this of any use; it seems a bit dated, but could save you some effort: > http://meta.cesnet.cz/cms/opencms/en/docs/software/devel/negotiate.html
Well for one, mod_auth_gss_krb5 only does authentication. My *real* product is Windows integration libraries for non-Windows environments (i.e. LAMP). So, for example, this SSO module is going to include Windows authorization functionality for integration with AD. Meaning the developer can restrict content based on group membership of groups defined in an AD domain: $auth = sso_authenticate(); if (!sso_is_member($auth, "Authenticated Users")) { header("Location: /login.php"); die("You are not authorized to access this content."); } ... if (sso_is_member($auth, "FOONET\\Engineers")) { echo "Engineers rule!"; } else if (sso_is_member($auth, "FOONET\\Consultants")) { echo "Consultants rule!"; } Also I think there's also alot of polish that can go into failing over to other authentication methods and redirecting to login pages and so on. You just can't do any of this well unless your at the language level. Mike

Jani Taskinen

20 years ago
So you're duplicating the ldap extension? :) --Jani On Wed, 21 Dec 2005, Michael B Allen wrote:

Michael B Allen

20 years ago
On Wed, 21 Dec 2005 12:27:39 +0200 (EET) Jani Taskinen <sniper@iki.fi> wrote:
> > So you're duplicating the ldap extension? :)
Yeah, you might be able to do it that way. But considering the Kerberos ticket has the SIDs and LDAP would have to perform group expansion each time I think a DCE/RPC SID lookup would be a little faster. Actually it could be a lot faster if you do things like cache the SIDs since many people would have the same ones. Mike

Pierre Joye

20 years ago
On Wed, 21 Dec 2005 03:56:06 -0500 mba2000@ioplex.com (Michael B Allen) wrote:
> On Wed, 21 Dec 2005 01:58:41 -0500 > Wez Furlong <kingwez@gmail.com> wrote: > > > Just curious, why aren't you writing this as an apache module? > > > > Is this of any use; it seems a bit dated, but could save you some > > effort: > > http://meta.cesnet.cz/cms/opencms/en/docs/software/devel/negotiate.html > > Well for one, mod_auth_gss_krb5 only does authentication. My *real* > product is Windows integration libraries for non-Windows environments > (i.e. LAMP). So, for example, this SSO module is going to include > Windows authorization functionality for integration with AD. Meaning > the developer can restrict content based on group membership of > groups defined in an AD domain:
There is already some NTLM modules for apache. A php version will may be available in PEAR. NTLM is what you are trying to achieve, or a part of it. Single Sign On is another problem, and can be done with various auth mechanisms. Are you implementing SSO as well? :) --Pierre

Michael B Allen

20 years ago
On Wed, 21 Dec 2005 14:06:13 +0100 Pierre <pierre.dev@gmail.com> wrote:
> On Wed, 21 Dec 2005 03:56:06 -0500 > mba2000@ioplex.com (Michael B Allen) wrote: > > > On Wed, 21 Dec 2005 01:58:41 -0500 > > Wez Furlong <kingwez@gmail.com> wrote: > > > > > Just curious, why aren't you writing this as an apache module? > > > > > > Is this of any use; it seems a bit dated, but could save you some > > > effort: > > > http://meta.cesnet.cz/cms/opencms/en/docs/software/devel/negotiate.html > > > > Well for one, mod_auth_gss_krb5 only does authentication. My *real* > > product is Windows integration libraries for non-Windows environments > > (i.e. LAMP). So, for example, this SSO module is going to include > > Windows authorization functionality for integration with AD. Meaning > > the developer can restrict content based on group membership of > > groups defined in an AD domain: > > There is already some NTLM modules for apache. A php version will may > be available in PEAR. NTLM is what you are trying to achieve, or a part > of it. Single Sign On is another problem, and can be done with various > auth mechanisms. Are you implementing SSO as well? :)
Actually I don't think you're going to be satisfied with NTLM. Here's a few reasons: 1) W2K3 requires SMB signing by default and with NTLM you don't have the plain text equivalent password hash necessary to generate a valid MAC key. You have to setup credentials to perform the initial connect to the DC which is ugly because people don't want to put passwords into config files. 2) You cannot perform delegation with NTLM. That's one of the principal reasons why MS has moved to Kerberos. So if you want to use the negotiated credentials to then connect to other resources like file servers it will not work [1]. 3) Prevailing security policy these days is moving away from NTLM. At some point you're going to run into an admin that refuses to support it in which case you must also implement NTLMv2. 4) For NTLM or NTLMv2 you must implement NTLMSSP which is not supported by Heimdal or MIT Kerberos GSSAPI implementations (although I might fix this soon). Basically NTLM is depricated. NTLMv2 is still used when communicating with non-domain members but Kerberos is a much nicer system and honestly it's probably easier considering there are GSSAPI implementations that can do the heavy lifting for you now. Mike [1] Actually you can proxy NTLM but that means you must renegotiate with each resource you try to access.