Windows Impersonation Apache Module in Lazarus -


i in process of porting several windows desktop applications single web site.

the current setup includes several sql server backend databases, configured windows authentication (sspi) only, , every user/group/role has specific rights on specific objects. convenient, because application layer doesn't have implement access control.

i'd keep same way web server, apache on windows machine. every connection databases being made using apache's account. that's understandable , expected, in fact apache deliberately given access public data, able deliver public content.

but in case domain user logs in (the login process implemented) i'd apache process handles request impersonate user, , act them during whole request.

at first, tried php's fastcgi.impersonate trick, using iis web server. gave on that, because (1) had port apache anyway , (2) php-specific, , turned out should targeting web server whole...

so redirected search apache modules. months of research gave no fruits, other mod_auth_sspi , like, apparently isn't i'm looking (authentication , impersonation 2 different things).

finally decided make own module. of "101" examples find written in c, managed find 2-3 ones in lazarus/fpc, i've been using quite while now, never such task.

i know have build .dll project, know (more or less) units use , know functions logonuser() , impersonateloggedonuser() should in toolbox.

has done similar? can point me right direction?

an example appreciated, if it's simple proof of concept. question far asking final, definitive solution.

i came following:

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     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); themodule   begin   name := 'mod_winimpersonate.dll';   register_hooks := @registerhooks;   end; end. 

this no means final solution, it's start. logic following:

  • revert apache account. a must, in case using recycled apache thread impersonate else.

  • retrieve user's credentials cookie named 'winimpersonate', in form of username:password. needs more work (maybe encrypt credentials, or store them in safe(?) place on server or more secure)

  • impersonate user, of windows unit.

  • return declined, apache knows didn't handle request, , should continue asking modules right handler.

there many concerns addressed, in order achieve decent security level. among others, protection of credentials, , browser cache. said, it's start, proof of concept.

you'll notice there 2 utility functions missing above listing:

urldecode decodes url-encoded string:

// convert urlencoded string 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));   := 1;   len := 1;   while (i <= cardinal(length(sansi)))      begin     if (sansi[i] <> '%')        begin       if (sansi[i] = '+') 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 tries login user using credentials supplied, , upon success tries impersonate him:

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         )       begin       impersonateloggedonuser(creds);       result:=true;       end;       //wipe memory security     fillchar(username,sizeof(username),#0);     fillchar(password,sizeof(username),#0);     fillchar(domain,sizeof(username),#0);     end;  //try-finally   end; 

hope finds useful. comments more welcome.


Comments

Popular posts from this blog

java.util.scanner - How to read and add only numbers to array from a text file -

rewrite - Trouble with Wordpress multiple custom querystrings -

php - Accessing static methods using newly created $obj or using class Name -