Apache Module for Windows Impersonation in Lazares

I am currently porting several Windows desktop applications to a single website.

The current setup includes several basic SQL Server databases configured with Windows Authentication (SSPI) only, and each user / group / role has specific rights to certain objects. This is convenient because at the application level, access control is not necessary.

I would like to keep it the same as with the web server, Apache on a Windows machine. But every connection to the database is done using an Apache account. This is understandable and expected, because Apache intentionally gains access to public data in order to provide public content.

But if a domain user logs in (the login process has already been implemented), I would like the Apache process to process the request to impersonate this user and, thus, execute them throughout the request.

At first I tried using php fastcgi.impersonate using IIS as a web server. But in the end, I refused this, mainly because (1) we still had to port to Apache and (2) it was php-specific, and it turned out that we should focus on the web server as a whole ...

So, I redirected my search to Apache modules. Months of research yielded nothing but mod_auth_sspi and the like, which is obviously not what I am looking for (authentication and personification are two different things).

Finally, I decided to create my own module. Most of the examples of "101" that I could find are written in C, but I managed to find 2-3 in Lazarus / FPC , which I have been using for a long time, but never for such a task.

I know that I need to create a .dll project, I know (more or less) which units to use, and I know that functions such as LogonUser()and ImpersonateLoggedOnUser()should be in my toolbox.

Has anyone done something like this? Can someone point me in the right direction?

An example will be appreciated, even if it is a simple proof of concept. This question is far from asking for a final final decision.

+4
source share
1

:

library mod_winimpersonate;

{$mode objfpc}{$H+}

uses SysUtils, Windows, httpd, apr, Classes;

function DefaultHandler(r: Prequest_rec): Integer; cdecl;
  Var
    cookies:TStringList;
    logindata,username,password:String;
    p:Integer;
  begin
  RevertToSelf;
  cookies:=TStringList.Create;
  cookies.Delimiter:=';';
  cookies.DelimitedText:=apr_table_get(r^.headers_in,'COOKIE');
  logindata:=URLDecode(cookies.Values['WinImpersonate']);
  If Length(logindata)>0 then
    Begin
    p:=Pos(':',logindata);
    username:=LeftStr(logindata,p-1);
    password:=RightStr(logindata,Length(logindata)-p);
    ChangeLoggedInUser(username,password,'');
    End;
  Result:=DECLINED;
  end;

procedure RegisterHooks(p: Papr_pool_t); cdecl;
  begin
  ap_hook_handler(@DefaultHandler, nil, nil, APR_HOOK_REALLY_FIRST);
  end;

var
  TheModule: module;

exports TheModule name 'winimpersonate_module';

begin
FillChar(TheModule, sizeof(TheModule), 0);
STANDARD20_MODULE_STUFF(TheModule);
with TheModule do
  begin
  name := 'mod_winimpersonate.dll';
  register_hooks := @RegisterHooks;
  end;
end.

, . :

  • Apache. , Apache, .

  • cookie "WinImpersonate" username:password. (, (?) - )

  • windows.

  • DECLINED, Apache , , .

, , . , . , , , .

, :

URLDecode url:

// Convert URLEncoded string to utf8 string
function URLDecode(const s: String): String;
  var
    sAnsi: String;
    sUtf8: String;
    sWide: WideString;
    i, len: Cardinal;
    ESC: string[2];
    CharCode: integer;
    c: char;
  begin
  sAnsi := PChar(s);
  SetLength(sUtf8, Length(sAnsi));
  i := 1;
  len := 1;
  while (i <= Cardinal(Length(sAnsi))) do 
    begin
    if (sAnsi[i] <> '%') then 
      begin
      if (sAnsi[i] = '+') then c := ' '  else c := sAnsi[i];
      sUtf8[len] := c;
      Inc(len);
      end 
    else 
      begin
      Inc(i);
      ESC := Copy(sAnsi, i, 2);
      Inc(i, 1);
      try
        CharCode := StrToInt('$' + ESC);
        c := Char(CharCode);
        sUtf8[len] := c;
        Inc(len);
      except 
        end;
      end;
    Inc(i);
    end;
  Dec(len);
  SetLength(sUtf8, len);
  sWide := UTF8Decode(sUtf8);
  len := Length(sWide);
  Result := sWide;
  end;

ChangeLoggedInUser , , :

Function ChangeLoggedInUser(username, password, domain: string):Boolean;
  var
    creds: Cardinal;
  begin
  Result:=False;
  try
    if LogonUser(PChar(username)
        ,PChar(domain)
        ,PChar(password)
        ,LOGON32_LOGON_NETWORK_CLEARTEXT
        ,LOGON32_PROVIDER_DEFAULT
        ,creds
        ) then
      begin
      ImpersonateLoggedOnUser(creds);
      Result:=True;
      end;
  finally
    //wipe the memory for security
    FillChar(username,SizeOf(username),#0);
    FillChar(password,SizeOf(username),#0);
    FillChar(domain,SizeOf(username),#0);
    end;  //try-finally
  end;

, - . .

+3

All Articles