Title: Specifing authentication details & Impersonating a user for use on an Interface(Proxy) call (Client Side)
Question: How to change authentication/authorization setting, and impersonate a user on an interface/proxy call.
Answer:
What we want to do
-----------------------
When it comes to COM and client security, and the authentication level details used on interface call, you can be sure than sooner or later you'll need to specify the authentication information at runtime, or on a specific call to an interface.
Usually you set up authentication/authorization/impersonation levels using the Dcomcnfg application provided. How ever, when you require these to be altered or wish to cloak or impersonate an alternate user on calls to a proxy so the server recongnises the alternate user as the callee rather than your natural login account, or the application user account ( i.e service user account).
Finding out how..
---------------------
Well to find out how to do this is really not very easy..
very differcult to find examples, people asking how to do it.. people responding where to maybe find out how...
msdn is definately the best resourse for information on low level security side of COM and authentication documentation on this subject, but finding full examples which work, or all the syntax/constants/data types that's required is always lacking when it comes to msdn library documentation.
So for all those who have been looking for this answer.
How it's done.
------------------
There are a few ways to setup this information, you can set it globally
to your process using the call CoInitializeSecurity(). But I am going to explain how to use the CoSetProxyBlanket() which can set this information on a specific interface (proxy) which is far more flexible.
CoSetProxyBlanket is a wrapper that simply uses the IClientSecurity interface provided by the proxy and calls the SetBlanket method of the interface.
I will give you a quick code example of this here and provide you with an attachment which contains all the contants, data types, and a the wrapper function to cater for all the options.
Enjoy.....
const
RPC_C_AUTHN_WINNT = 10;
RPC_C_AUTHZ_DEFAULT = $ffffffff;
RPC_C_AUTHN_LEVEL_CALL = 3;
RPC_C_IMP_LEVEL_IMPERSONATE = 3;
EOAC_NONE = $0;
type
(* The Auth Identity Structure *)
PCoAuthIdentity = ^TCoAuthIdentity;
_CoAuthIdentity = packed record
User : PChar;
UserLength : DWORD;
Domain : PChar;
DomainLength : DWORD;
Password : PChar;
PasswordLength : DWORD;
Flags : DWORD;
end;
TCoAuthIdentity = _CoAuthIdentity;
implementation
(* Procedure to demonstrate the use of the CoSetProxyBlanket call
and how to use it to impersonate another user when calling
an interface. *)
procedure SetUserImpersonateOnProxy(
Proxy: IUnknown; //-- Interface
const UserName, DomainName, Psword: String; //-- User Account
AuthenicationService: DWORD = RPC_C_AUTHN_WINNT;
AuthorizationService: DWORD = RPC_C_AUTHZ_DEFAULT;
AuthenicationLevel: DWORD = RPC_C_AUTHN_LEVEL_CALL;
ImpersonationLevel: DWORD = RPC_C_IMP_LEVEL_IMPERSONATE;
CapabiltiesFlag: DWORD = EOAC_NONE
);
var
AuthIdent: TCoAuthIdentity;
iResult: Integer;
begin
(* Populate an Auth Identity structure with the User Account Details *)
ZeroMemory(@AuthIdent, 0);
with AuthIdent do begin
User := pChar(UserName);
UserLength := length(UserName);
Domain := pChar(DomainName);
DomainLength := length(DomainName);
Password := pChar(Psword);
PasswordLength := length(Psword);
Flags := SEC_WINNT_AUTH_IDENTITY_ANSI;
end;
iResult := CoSetProxyBlanket(Proxy,
(* Authentication Service is the service which will be used
for authentication i.e WinNT NTLM KERBEROS etc.. this rarely
needs to be changed unless Delegation level of impersonation
is required and this is only possible with Windows 2000 and
Kerberos Authentication Service *)
AuthenicationService,
AuthorizationService,
0,
(* Authentication level should be CALL or PKT as this is the
level when authentication will take place.. On each CALL. *)
AuthenicationLevel,
(* Impersonation Level regards to the servers rights to
impersonate as the authenticated user. *)
ImpersonationLevel,
@AuthIdent,
CapabiltiesFlag);
case iResult of
S_OK: (* Success *) ;
E_INVALIDARG : Raise Exception.Create('Invalid Arguments.');
E_OUTOFMEMORY : Raise Exception.Create('Out of Memory');
else
Raise Exception.Create('Failed to blanket proxy')
end;
end;
-------------
var
Intf: IMyFooServer;
begin
Intf := CoMyFooServer.Create;
try
SetUserImpersonateOnProxy(Intf, 'AUser', 'DELPHIDOMAIN', 'FooBar');
(* Interface will authenticate the user AUser as the
Callee on each call to the Server. *)
Intf.CallMethodAsAUser(Blah);
finally
Intf := NIL;
end;
end;
--------------
You will find attached the unit shortly.
Regards to all, look forward to hearing any comments.