Question : ISAPI Authentication Filter

Hi !

I am trying to code an ISAPI Filter, that does dynamic authentication based on the URL.
I code with Delphi, but C++ example/source will do just fine.

Here's what i do:
1. at GetFilterVersion i register with the following flags:
SF_NOTIFY_URL_MAP,SF_NOTIFY_AUTHENTICATION,SF_NOTIFY_SECURE_PORT,SF_NOTIFY_NONSECURE_PORT
2. at HttFilterProc i have something like this :
a. if Notification Type is SF_NOTIFY_URL_MAP, i cast the pvNotification pointer to a HTTP_FILTER_URL_MAP to obtain the URL and decide weather its a protected URL or not.
In case it is protected i do :
pFc.ServerSupportFunction(Pfc,SF_REQ_SEND_RESPONSE_HEADER,PChar('401 Authorization Required'),dword(Domain),0)
where Domain contains "WWW-Authenticate: Basic realm="Restricted Area" then return SF_STATUS_REQ_NEXT_NOTIFICATION.

b. if Notification Type is SF_NOTIFY_AUTHENTICATION i cast pvNotification to HTTP_FILTER_AUTHENT to obtain user/password supplied.
If invalid user/pass i return SF_STATUS_REQ_ERROR otherwise i return SF_STATUS_REQ_HANDLED_NOTIFICATION.

The following is the actual Delphi code (where GlobalURL, user and password variables are global) :
 case NotificationType of
        SF_NOTIFY_PREPROC_HEADERS:
                begin
                        PreprocHeaders := THTTP_FILTER_PREPROC_HEADERS(pvNotification^);
                        BufferSize := SizeOf(Buffer);
                        PreprocHeaders.GetHeader(pfc,'url',Buffer,BufferSize);
                        LogInfo('Notify Preprocess Headers URL: '+Buffer);
                end;
        SF_NOTIFY_URL_MAP:
                begin
                        LogInfo('************ Entering SF_NOTIFY_URL_MAP ************ ');
                        UrlMap := THTTP_FILTER_URL_MAP(pvNotification^);
                        GlobalURL := UrlMap.pszURL;
                        LogInfo('Notify URL Map: '+strpas(UrlMap.pszURL));
                        if strContains('/noie',GlobalURL) then
                        begin
                                LogInfo('*** Protected URL Detected !');
                                if (User <> 'someuser') and (pass <> 'somepassword') then
                                begin
                                        LogInfo('No user/pass supplied ... sending auth headers !');
                                        Domain := 'WWW-Authenticate: Basic realm="Restricted Area"';
                                        pFc.ServerSupportFunction(Pfc,SF_REQ_SEND_RESPONSE_HEADER,PChar('401 Authorization Required'),dword(Domain),0);
                                        SizeBuf:= 20;
                                        pfc.WriteClient(pfc,pchar('Password protected !'),SizeBuf,0);
                                        Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
                                end else
                                begin
                                        LogInfo('Correct user/pass');
                                        LogInfo('User: '+User);
                                        LogInfo('Pass: '+Pass);
                                        Result := SF_STATUS_REQ_HANDLED_NOTIFICATION;
                                end;
                        end
                        else
                        Result := SF_STATUS_REQ_NEXT_NOTIFICATION;

                        LogInfo('************ Exiting SF_NOTIFY_URL_MAP ************ ');
                end;
        SF_NOTIFY_AUTHENTICATION:
                begin
                        LogInfo('************ Entering SF_NOTIFY_AUTHENTICATION ************ ');
                        if User = 'someuser' then
                        begin
                                Result := SF_STATUS_REQ_HANDLED_NOTIFICATION;
                        end else
                        begin
                        AuthHeader := THTTP_FILTER_AUTHENT(pvNotification^);
                        LogInfo('Notify Authentication: '+GlobalURL);
                        User := AuthHeader.pszUser;
                        Pass := AuthHeader.pszPassword;
                        LogInfo('Notify Authentication User: '+User);
                        LogInfo('Notify Authentication Pass: '+Pass);
                        if user<>'someuser' then
                                begin
                                        LogInfo('Sending auth ...');
                                        Domain := 'WWW-Authenticate: Basic realm="Restricted Area"';
                                        pFc.ServerSupportFunction(Pfc,SF_REQ_SEND_RESPONSE_HEADER,PChar('401 Authorization Required'),dword(Domain),0);
                                        SizeBuf:= 20;
                                        pfc.WriteClient(pfc,pchar('Password protected !'),SizeBuf,0);
                                        Result := SF_STATUS_REQ_ERROR;
                                end else
                                begin
                                        User := AuthHeader.pszUser;
                                        Pass := AuthHeader.pszPassword;
                                        LogInfo('Correct user/pass found in SF_NOTIFY_AUTHENTICATION !');
                                        Result := SF_STATUS_REQ_HANDLED_NOTIFICATION;
                                end;
                        end;
                        LogInfo('************ Exiting SF_NOTIFY_AUTHENTICATION ************ ');
                end;
 end;

The thing is that even when the log says that correct user/pass are found, i still get the login window asking username and password.
Does anybody has any ideea what's wrong, or how can i do it right ?

Answer : ISAPI Authentication Filter

In C++ code:

// function that corresponds to your SF_NOTIFY_AUTHENTICATION switch case
DWORD CLoginFilter::OnAuthentication(CHttpFilterContext* pCtxt,
     PHTTP_FILTER_AUTHENT pAuthent)
{


...
// code that checks permitions and retrieves a valid NT username and password into m_strUsername and m_strPassword.
// this can be a database query or what ever...
// Example:
          Query = " select txt_nt_login, txt_nt_password from users where ";
          Query += " users.txt_login = '";
          Query += dbQuoteEscape(pAuthent->pszUser);
          Query += "' AND users.txt_password = '";
          QUery += dbQuoteEscape(pAuthent->pszPassword)+"'";    

...

        if (bAuthenticated)
        {
          strcpy(pAuthent->pszUser, LPCTSTR(m_strUsername));
          strcpy(pAuthent->pszPassword, LPCTSTR(m_strPassword));
         
          return SF_STATUS_REQ_HANDLED_NOTIFICATION;     }
        else
        {
                // clear the given login and password for security
          memset(pAuthent->pszUser, '\0', strlen(pAuthent->pszUser));
          memset(pAuthent->pszPassword, '\0', strlen(pAuthent->pszPassword));
               
          return SF_STATUS_REQ_NEXT_NOTIFICATION;
        }
Random Solutions  
 
programming4us programming4us