Getting user name and password in ISAPI or CGI application (140964)



The information in this article applies to:

  • Microsoft Internet Information Server 4.0
  • Microsoft Internet Information Server 5.0

This article was previously published under Q140964

SUMMARY

This article explains how to retrieve values for the user name and password in an ISAPI or CGI application.

MORE INFORMATION

The user name and password values can be retrieved in the ISAPI/CGI, according to the following rules.

The user name can only be retrieved when either Basic Authentication scheme or Microsoft Windows NT Challenge/Response schemes are used. You can get the name by using the server variable, REMOTE_USER.
Note When you use Basic Authentication, you should use SSL to encrypt the traffic over the network, because it is very easy for other people to obtain credentials from a network trace. For more informationabout how to install SSL, click the following article numbers to view the articles in the Microsoft Knowledge Base:

228991 How to create and install an SSL certificate in Internet Information Server 4.0

299525 How to set up SSL by using IIS 5.0 and Certificate Server 2.0

298805 How to enable SSL for all customers who interact with your Web site in Internet Information Services


In ISAPI you can use GetServerVariable() API, and in CGI you can use getenv() C run-time function.

The following sample code can be used to get the server variable:
// This will fail with ERROR_INSUFFICIENT_BUFFER,
// since we supplied NULL buffer. As a result, dwLength will
// indicate the size of the buffer to allocate

if (!pECB -> GetServerVariable (pECB -> ConnID,
                           "REMOTE_USER",
                           NULL,
                           &dwLength) )
{
    // Handle error other then ERROR_INSUFFICIENT_BUFFER here.
}
lpszVar= (CHAR *) LocalAlloc (LPTR, dwLen);
if ( !pECB -> GetServerVariable (pECB -> ConnID,
                                 "REMOTE_USER",
                                 lpszVar,
                                 &dwLength))

{
    // Handle error here
}
				
The user password can only be retrieved when Basic authentication scheme is used. The password is not available with the Windows NT Challenge/Response scheme, because the password never gets transmitted on the network.

To retrieve the password with the Basic authentication scheme, you need to parse it out from the HTTP_AUTHORIZATION server variable, which sets from HTTP Authorization header. HTTP_AUTHORIZATION has the following value:
   Basic xxxxxxxxxxxxxxx
				
where Basic is an authentication scheme used, then it is followed by a space, and "xxxxxxxxxxxxxxx" is Base 64 string for "User-Name:User- Password" pair separated by the semicolon.

Notes:

  • The Base 64 routines are available from many public sources. Please see the following Microsoft Knowledge Base article for more information:

    191239 Sample Base 64 Encoding and Decoding

  • The user password can not be retrieved via REMOTE_PASS server variable.
  • In the IIS Filter application, the password (if available) can be retrieved in clear text from the HTTP_FILTER_AUTHENT structure during SF_NOTIFY_AUTHENTICATION event:
          typedef struct _HTTP_FILTER_AUTHENT
          {
              CHAR *    pszUser;
              DWORD    cbUserBuff;
              CHAR *    pszPassword;
              DWORD    cbPasswordBuff;
          } HTTP_FILTER_AUTHENT, *PHTTP_FILTER_AUTHENT;
    					
  • IIS 5.0 provides new notification SF_NOTIFY_AUTH_COMPLETE. With this notification, user name can be retrieved with Digest or Integrated (including NTLM) authentication schemes.
Currently the only documentation is in the httpfilt.h header file which ships with the latest Win2000 SDK. This notification will uses following structure:
#define SF_NOTIFY_AUTH_COMPLETE             0x04000000
typedef struct _HTTP_FILTER_AUTH_COMPLETE_INFO
{
    // 
    //  For SF_NOTIFY_AUTH_COMPLETE, retrieves the specified header value.
    //  Header names should include the trailing ':'.  The special values
    //  'method', 'url' and 'version' can be used to retrieve the individual
    //  portions of the request line
    // 

    BOOL (WINAPI * GetHeader) (
        struct _HTTP_FILTER_CONTEXT * pfc,
        LPSTR                         lpszName,
        LPVOID                        lpvBuffer,
        LPDWORD                       lpdwSize
        );

    // 
    //  Replaces this header value to the specified value.  To delete a header,
    //  specified a value of '\0'.
    // 

    BOOL (WINAPI * SetHeader) (
        struct _HTTP_FILTER_CONTEXT * pfc,
        LPSTR                         lpszName,
        LPSTR                         lpszValue
        );

    // 
    //  Adds the specified header and value
    // 

    BOOL (WINAPI * AddHeader) (
        struct _HTTP_FILTER_CONTEXT * pfc,
        LPSTR                         lpszName,
        LPSTR                         lpszValue
        );
        
    // 
    //  Get the authenticated user impersonation token
    // 
    
    BOOL (WINAPI * GetUserToken) (
        struct _HTTP_FILTER_CONTEXT * pfc,
        HANDLE *                      phToken
        );
    
    // 
    //  Status code to use when sending response
    // 
    
    DWORD HttpStatus;               
    
    // 
    //  Determines whether to reset auth if URL changed
    // 
    
    BOOL  fResetAuth;             
    
    // 
    //  Reserved
    // 
    
    DWORD dwReserved;            
    
} HTTP_FILTER_AUTH_COMPLETE_INFO, *PHTTP_FILTER_AUTH_COMPLETE_INFO;
				

The following code demonstrates how to use this notification:
      HTTP_FILTER_AUTH_COMPLETE_INFO *AuthComp; 
	if (NotificationType == SF_NOTIFY_AUTH_COMPLETE)
	{
		AuthComp = (HTTP_FILTER_AUTH_COMPLETE_INFO *) pvNotification;
		pfc->GetServerVariable (pfc, "AUTH_TYPE", szType, &dwSize);
		dwSum = dwSize;
		szType = new CHAR [dwSize];
		if (!pfc->GetServerVariable (pfc, "AUTH_TYPE", szType, &dwSize))
		{
			wsprintf (szTemp, "Can't get Auth_Type: %d\n", GetLastError());
			OutputDebugString (szMessage);
		}
		
		dwSize = 0;
		pfc->GetServerVariable (pfc,"AUTH_USER", szUser, &dwSize);		
		szUser = new CHAR [dwSize];

		if (!pfc->GetServerVariable (pfc,"AUTH_USER", szUser, &dwSize))
		{
			wsprintf (szTemp, "Can't get Auth_User: %d\n", GetLastError());
			OutputDebugString (szMessage);
		}
		
		szMessage = new CHAR [dwSum + 256];
		wsprintf (szMessage, "> Auth type: %s Auth user: %s\n", szType, szUser); 
		OutputDebugString (szMessage);
            ...
 	}
				
For additional information, please see the HTTP protocol spec, available on

Modification Type:MajorLast Reviewed:6/22/2006
Keywords:kbhowto kbnetwork KB140964