Re: HTRequest only holds a single auth scheme

Steinar Bang <[email protected]> Thu, 01 Jul 2004 12:21:20 +0200
Newsgroups gmane.comp.lib.libwww
Organization Probably a good idea
Message-ID <[email protected]>
>>>>> Steinar Bang <[email protected]>:

>>>>> Steinar Bang <[email protected]>:
>>>>> Steinar Bang <[email protected]>:
>>> The apache mod_auth_kerberos module by default has two
>>> WWW-Authenticate headers, one for "Negotiate", and one for "Basic".
>>> I believe this is the default behaviour for IIS as well.

>>> However the HTRequest structure only has room for a single
>>> authentication scheme, so the last WWW-Authentication header
>>> ("Basic" in this case) overwrites any previous values set.

>>> This means that my functions set with a call to HTAA_newModule(),
>>> are only called when I switch off password authentication.

>> Attached is my attempt at a patch for multiple auth schemes (diff
>> done against libwww CVS HEAD).  The idea is to iterate through the
>> list in the order the WWW-Authenticate headers occur in the HTTP
>> response, and if the implementation for a scheme returns HT_ERROR,
>> skip to the next one.

> The previous patch didn't build with MSVC7.1.  I had to declare
> local variables in a single block at the start of the functions.

In addition to the multiple auth schemes, I have changed the behaviour
for the authentication update filters: I set the context if present,
instead of just setting a null pointer.

This was neccessary to implement SPNEGO, because the response from the
server is needed to complete the authentication info.

The attached patch covers both changes, and is made against the
current CVS.
multiple_authschemes_v2.diff (text/x-patch, 9.8 KB)
Index: Library/src/HTAAUtil.c
===================================================================
RCS file: /sources/public/libwww/Library/src/HTAAUtil.c,v
retrieving revision 2.35
diff -c -d -r2.35 HTAAUtil.c
*** Library/src/HTAAUtil.c	22 Feb 1999 22:10:10 -0000	2.35
--- Library/src/HTAAUtil.c	1 Jul 2004 09:04:54 -0000
***************
*** 414,419 ****
--- 414,439 ----
      return HT_OK;
  }
  
+ /*
+ ** Single point of change structuring function.
+ ** Call the after function of the authentication module identified by
+ ** the scheme argument
+  */
+ PRIVATE int run_after_filter (HTRequest * request,
+ 			      HTResponse * response,
+ 			      const char * scheme,
+ 			      int status)
+ {
+     HTAAModule * module = NULL;
+     if ((module = HTAA_findModule(scheme)) != NULL) {
+ 	HTTRACE(AUTH_TRACE, "Auth Engine. Found AFTER filter %p\n" _ module->after);
+ 	HTRequest_deleteCredentialsAll(request);
+ 	HTRequest_addAARetry (request);
+ 	return (*module->after)(request, response, NULL, status);
+     }
+     return HT_ERROR;
+ }
+ 
  /*	HTAA_afterFilter
  **	-----------------
  **	Call the AFTER filter that knows how to handle this scheme.
***************
*** 422,443 ****
  PUBLIC int HTAA_afterFilter (HTRequest * request, HTResponse * response,
  			     void * param, int status)
  {
!     const char * scheme = HTResponse_scheme(response);
!     HTAAModule * module = NULL;
      HTTRACE(AUTH_TRACE, "Auth Engine. After filter status %d\n" _ status);
!     /*
!     **	If we don't have a scheme then the server has made an error. We
!     **  try to make up for it by creating our own "noop" realm and use basic.
!     */
!     if (!scheme) {
  	HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
  	scheme = "basic";
      }
      if ((module = HTAA_findModule(scheme)) != NULL) {
! 	HTTRACE(AUTH_TRACE, "Auth Engine. Found AFTER filter %p\n" _ module->after);
  	HTRequest_deleteCredentialsAll(request);
! 	HTRequest_addAARetry (request);
! 	return (*module->after)(request, response, NULL, status);
      }
      return HT_ERROR;
  }
--- 442,492 ----
  PUBLIC int HTAA_afterFilter (HTRequest * request, HTResponse * response,
  			     void * param, int status)
  {
!     const char* scheme = 0;
!     HTList * schemes = 0;
      HTTRACE(AUTH_TRACE, "Auth Engine. After filter status %d\n" _ status);
!     schemes = HTResponse_schemes(response);
!     if (schemes != 0) {
! 	while ((scheme = (char *) HTList_nextObject(schemes))) {
! 	    int retval = run_after_filter(request,response,scheme,status);
! 	    if (retval != HT_ERROR) {
! 		return retval;
! 	    }
! 	}
! 	return HT_ERROR;
!     } else {
! 	/*
! 	**	If we don't have a scheme then the server has made an
! 	**  error. We try to make up for it by creating our own "noop"
! 	**  realm and use basic.
! 	*/
  	HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
  	scheme = "basic";
+ 	return run_after_filter(request, response, scheme, status);
      }
+ }
+ /*
+ ** Single point of change structuring function.
+ ** Call the after function of the authentication module identified by
+ ** the scheme argument
+  */
+ PRIVATE int run_update_filter (HTRequest * request,
+ 			       HTResponse * response,
+ 			       const char * scheme,
+ 			       void* context,
+ 			       int status)
+ {
+     HTAAModule * module = NULL;
+ 
      if ((module = HTAA_findModule(scheme)) != NULL) {
! 	/* we don't call this module systematically, as it could hamper
! 	   the execution of Basic authentication requests for nothing */
!       if (module->update) {
! 	HTTRACE(AUTH_TRACE, "Auth Engine. Found Update filter %p\n" _ module->update);
  	HTRequest_deleteCredentialsAll(request);
! 	return (*module->update)(request, response, context, status);
!       }
!       return HT_OK;
      }
      return HT_ERROR;
  }
***************
*** 450,477 ****
  PUBLIC int HTAA_updateFilter (HTRequest * request, HTResponse * response,
  				 void * param, int status)
  {
!     const char * scheme = HTResponse_scheme(response);
!     HTAAModule * module = NULL;
      HTTRACE(AUTH_TRACE, "Auth Engine. Update filter status %d\n" _ status);
!     /*
!     **	If we don't have a scheme then the server has made an error. We
!     **  try to make up for it by creating our own "noop" realm and use basic.
!     */
!     if (!scheme) {
  	HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
  	scheme = "basic";
      }
-     if ((module = HTAA_findModule(scheme)) != NULL) {
- 	/* we don't call this module systematically, as it could hamper
- 	   the execution of Basic authentication requests for nothing */
-       if (module->update) {
- 	HTTRACE(AUTH_TRACE, "Auth Engine. Found Update filter %p\n" _ module->update);
- 	HTRequest_deleteCredentialsAll(request);
- 	return (*module->update)(request, response, NULL, status);
-       }
-       return HT_OK;
-     }
-     return HT_ERROR;
  }
  
  
--- 499,548 ----
  PUBLIC int HTAA_updateFilter (HTRequest * request, HTResponse * response,
  				 void * param, int status)
  {
!     const char * scheme = 0;
!     HTList * schemes = 0;
!     void* context = 0;
!     char* realm = 0;
!     char* url = 0;
!     HTAAElement* element = 0;
!     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
      HTTRACE(AUTH_TRACE, "Auth Engine. Update filter status %d\n" _ status);
!     schemes = HTResponse_schemes(response);
!     if (schemes != 0) {
! 	realm = HTResponse_realm(response);
! 	if (proxy) {
! 	    url = HTRequest_proxy(request);
! 	    element = HTAA_findElement(proxy, realm, url);
! 	} else {
! 	    HTAnchor* anchor = HTRequest_anchor(request);
! 	    char* url = HTAnchor_address(anchor);
! 	    element = HTAA_findElement(proxy, realm, url);
! 	    HT_FREE(url);
! 	}
! 	if (element != 0) {
! 	    context = element->context;
! 	}
! 	while ((scheme = (char *) HTList_nextObject(schemes))) {
! 	    int retval = run_update_filter(request,
! 					   response,
! 					   scheme,
! 					   context,
! 					   status);
! 	    if (retval != HT_ERROR) {
! 		return retval;
! 	    }
! 	}
! 	return HT_ERROR;
!     } else {
! 	/*
! 	**	If we don't have a scheme then the server has made an
! 	**  error. We try to make up for it by creating our own "noop"
! 	**  realm and use basic.
! 	*/
  	HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
  	scheme = "basic";
+ 	return run_update_filter(request, response, scheme, 0, status);
      }
  }
  
  
Index: Library/src/HTResMan.html
===================================================================
RCS file: /sources/public/libwww/Library/src/HTResMan.html,v
retrieving revision 2.7
diff -c -d -r2.7 HTResMan.html
*** Library/src/HTResMan.html	30 Oct 2000 10:04:23 -0000	2.7
--- Library/src/HTResMan.html	1 Jul 2004 09:04:54 -0000
***************
*** 73,79 ****
  by the authentication parsers and generators respectively.
  <PRE>
      char *		realm;				    /* Current realm */
!     char *		scheme;				   /* Current scheme */
  
      HTAssocList *	challenge;         /* Challenge received in response */
  </PRE>
--- 73,79 ----
  by the authentication parsers and generators respectively.
  <PRE>
      char *		realm;				    /* Current realm */
!     HTList *		schemes;			  /* Current schemes */
  
      HTAssocList *	challenge;         /* Challenge received in response */
  </PRE>
Index: Library/src/HTResponse.c
===================================================================
RCS file: /sources/public/libwww/Library/src/HTResponse.c,v
retrieving revision 2.12
diff -c -d -r2.12 HTResponse.c
*** Library/src/HTResponse.c	30 Oct 2000 10:04:23 -0000	2.12
--- Library/src/HTResponse.c	1 Jul 2004 09:04:54 -0000
***************
*** 43,54 ****
  
  PUBLIC BOOL HTResponse_delete (HTResponse * me)
  {
      if (me) {
  	HTTRACE(CORE_TRACE, "Response.... Delete %p\n" _ me);
  
  	/* Access Authentication */
  	HT_FREE(me->realm);
! 	HT_FREE(me->scheme);
  	if (me->challenge) HTAssocList_delete(me->challenge);
  
  	/* Connection headers */
--- 43,59 ----
  
  PUBLIC BOOL HTResponse_delete (HTResponse * me)
  {
+     char * scheme;
+     HTList * cursor = 0;
      if (me) {
  	HTTRACE(CORE_TRACE, "Response.... Delete %p\n" _ me);
  
  	/* Access Authentication */
  	HT_FREE(me->realm);
! 	cursor = me->schemes;
! 	while ((scheme = (char *) HTList_nextObject(cursor)))
! 	    HT_FREE(scheme);
! 	HTList_delete(me->schemes);
  	if (me->challenge) HTAssocList_delete(me->challenge);
  
  	/* Connection headers */
***************
*** 189,204 ****
  */
  PUBLIC BOOL HTResponse_setScheme (HTResponse * me, char * scheme)
  {
      if (me && scheme) {
! 	StrAllocCopy(me->scheme, scheme);
  	return YES;
      }
      return NO;
  }
  
! PUBLIC const char * HTResponse_scheme (HTResponse * me)
  {
!     return (me ? me->scheme : NULL);
  }
  
  /*
--- 194,214 ----
  */
  PUBLIC BOOL HTResponse_setScheme (HTResponse * me, char * scheme)
  {
+     char* responseScheme = 0;
      if (me && scheme) {
! 	if (me->schemes == 0) {
! 	    me->schemes = HTList_new();
! 	}
! 	StrAllocCopy(responseScheme, scheme);
! 	HTList_appendObject(me->schemes, responseScheme);
  	return YES;
      }
      return NO;
  }
  
! PUBLIC HTList * HTResponse_schemes (HTResponse * me)
  {
!     return me->schemes;
  }
  
  /*
Index: Library/src/HTResponse.html
===================================================================
RCS file: /sources/public/libwww/Library/src/HTResponse.html,v
retrieving revision 2.14
diff -c -d -r2.14 HTResponse.html
*** Library/src/HTResponse.html	19 Dec 2000 11:21:29 -0000	2.14
--- Library/src/HTResponse.html	1 Jul 2004 09:04:54 -0000
***************
*** 127,133 ****
  </H3>
  <PRE>
  extern BOOL HTResponse_setScheme (HTResponse * response, char * scheme);
! extern const char * HTResponse_scheme (HTResponse * response);
  </PRE>
  <H2>
    HTTP Connection Control Directives
--- 127,133 ----
  </H3>
  <PRE>
  extern BOOL HTResponse_setScheme (HTResponse * response, char * scheme);
! extern HTList * HTResponse_schemes (HTResponse * response);
  </PRE>
  <H2>
    HTTP Connection Control Directives