Mirror

Specifing authentication details & Impersonating a user for use on an Interface(Proxy) call (Client Side) (Views: 706)


Problem/Question/Abstract:

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.

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.

<< Back to main page