Azman and impersonation

Jul 26, 2010 at 10:02 PM

Hi,

 

I am developing an application where all security / Authorization is base on Active directory logins and Azman.

 

For testing and developing purposes, we would like to support impersonation, so the tester/ developer can 'fake' to be some user, without having to enter login information of that account.

After the impersonation I would want to refresh the AZMan cache, to reflect the new Identity, but then i get :

System.ArgumentException was caught :

Message=Invalid token for impersonation - it cannot be duplicated,

when trying to open de connection to the azman storage.

 

Any hints how to fix this ? or any other ways to support this 'test user' behaviour in a way compatible with Azman, without enforcing a login screen ?

 

Thx in Advance

 

Stijn

Jul 27, 2010 at 8:49 AM

Could you please post your code ?

How you do the Impersonation ?

Andrea.

__________________________________
Andrea Ferendeles
NetSqlAzMan Project Coordinator
E-mail aferende@hotmail.com Web http://netsqlazman.codeplex.com

Jul 27, 2010 at 9:19 AM

Calling code :

                impContext = ImpersonateUser(login, domain,pwd);
                IUnityContainer _container = Application.Current.Properties["UnityContainer"as IUnityContainer;
                IAuthorizationHelper userAuthorizationHelper = _container.Resolve<IAuthorizationHelper>("AuthorizationHelper");
                object userAuthorizationCache = userAuthorizationHelper.GetUserAuthorizationCache();

Impersonation logic :

        public static WindowsImpersonationContext ImpersonateUser(string sUsername, string sDomain, string sPassword)
        {
            // initialize tokens
            IntPtr pExistingTokenHandle = new IntPtr(0);
            IntPtr pDuplicateTokenHandle = new IntPtr(0);
            pExistingTokenHandle = IntPtr.Zero;
            pDuplicateTokenHandle = IntPtr.Zero;

            // if domain name was blank, assume local machine
            if (string.IsNullOrEmpty(sDomain))
                sDomain = System.Environment.MachineName;

            try
            {
                string sResult = null;

                const int LOGON32_PROVIDER_DEFAULT = 0;

                // create token
                const int LOGON32_LOGON_INTERACTIVE = 2;
                //const int SecurityImpersonation = 2;

                // get handle to token
                bool bImpersonated = SafeNativeMethods.LogonUser(sUsername, sDomain, sPassword,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);

                // did impersonation fail?
                if (false == bImpersonated)
                {
                    int nErrorCode = Marshal.GetLastWin32Error();
                    sResult = "Logon gefaald met fout : " + nErrorCode + "\r\n";
                    throw new Afda.Common.ExceptionTypes.UserInterfaceException(sResult);
                }

                bool bRetVal = SafeNativeMethods.DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);

                // did DuplicateToken fail?
                if (false == bRetVal)
                {
                    int nErrorCode = Marshal.GetLastWin32Error();
                    SafeNativeMethods.CloseHandle(pExistingTokenHandle); // close existing handle
                    sResult += "Logon gefaald : DuplicateToken() gefaald met fout : " + nErrorCode + "\r\n";
                    throw new Afda.Common.ExceptionTypes.UserInterfaceException(sResult);
                }
                else
                {
                    // create new identity using new primary token
                    using (WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle))
                    {
                        WindowsImpersonationContext impersonatedUser = newId.Impersonate();
                        return impersonatedUser;
                    }

                }
            }
            catch
            {
                throw;
            }
            finally
            {
                // close handle(s)
                if (pExistingTokenHandle != IntPtr.Zero)
                    SafeNativeMethods.CloseHandle(pExistingTokenHandle);
                if (pDuplicateTokenHandle != IntPtr.Zero)
                    SafeNativeMethods.CloseHandle(pDuplicateTokenHandle);
            }
        }

GetUserAuthorizationCache code :

 

public object GetUserAuthorizationCache()
{
            IAzManUserPermissionCache userPermissionCache = null;
            userPermissionCache = new NetSqlAzMan.Cache.UserPermissionCache(this._storage, STORE_NAME, APPLICATION_NAME, this._windowsIdentity, falsetrue);
            
return userPermissionCache;
}
Jul 27, 2010 at 9:23 AM

Without using “Real Impersonation” you can use “Kerberos Protocol Transition” … that allows you to get the token of the impersonated user (and his Windows Identity) without knowing the password.

WindowsIdentity otherUser = new WindowsIdentity(“otheruser@domain.ext”);

Then use this otherIUser windowsIdentity to get all authorized items from NetSqlAzMan.

Regards,

Andrea.

__________________________________
Andrea Ferendeles
NetSqlAzMan Project Coordinator
E-mail aferende@hotmail.com Web http://netsqlazman.codeplex.com

Jul 27, 2010 at 11:57 AM

Andrea,

Thanx.

The Kerberos looks great, I tried it before, but then it failed ( becus i didnt get the domain ext right), this time it worked after the 5th possible domain ext combination.

It works perfect on my development machine ( windows 7 ), and since development is one of the target purposes of this option thats great.

it doesnt work on my other machine ( xp ), but thats not an issue, since XP isnt a target OS.

After getting the identity is still impersonate it

  WindowsIdentity wi = new WindowsIdentity(user@domain.com);
  impContext = wi.Impersonate();
What makes it fail when i try to run it on our citrix ( target client machine ) , the impersonation works, but the next call to the WCF service gives an exception and timeout : 
On the service side, there is BL for auditing ( would be nice that this code also knows about the impersonation),
and there will be Business Rules that will depend on de impersonated user, so it would be nice if it worked here as well, for testing / debugging puposes

System.IdentityModel.Tokens.SecurityTokenValidationException: The service does not allow you to log on anonymously.

at System.ServiceModel.Security.SecurityUtils.ValidateAnonymityConstraint(WindowsIdentity identity, Boolean allowUnauthenticatedCallers)

at System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeAcceptor.CreateClientSecurity(NegotiateStream negotiateStream, Boolean extractGroupsForWindowsAccounts)

at System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeAcceptor.OnAcceptUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity)

at System.ServiceModel.Channels.StreamSecurityUpgradeAcceptorBase.AcceptUpgrade(Stream stream)

at System.ServiceModel.Channels.InitialServerConnectionReader.UpgradeConnection(IConnection connection, StreamUpgradeAcceptor upgradeAcceptor, IDefaultCommunicationTimeouts defaultTimeouts)

at System.ServiceModel.Channels.ServerSessionPreambleConnectionReader.ServerFramingDuplexSessionChannel.OnOpen(TimeSpan timeout)

at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)

at System.ServiceModel.Channels.CommunicationObject.Open()

at System.ServiceModel.Dispatcher.ChannelHandler.OpenAndEnsurePump()

 

Jul 27, 2010 at 12:40 PM

Hi,

Kerberos Protocol Transition is supported only in Windows Server 2003/Vista or later.

Using KPT … you cannot impersonate a user because you don’t have the user password:

 
WindowsIdentity wi = new WindowsIdentity(user@domain.com);
impContext = wi.Impersonate(); //THIS WILL FAIL !

The question is… why you need impersonation ?

a. To take User SID and User Groups SID only

b. Or to do something else ?

KBT works for a. only (NetSqlAzMan does not need impersonation Context) !

Regards,

Andrea.

__________________________________
Andrea Ferendeles
NetSqlAzMan Project Coordinator
E-mail aferende@hotmail.com Web http://netsqlazman.codeplex.com

Jul 27, 2010 at 1:10 PM

Hi Andrea,

 

thank you very much for ur insights so far.

Up untill now our application was authentication with DB logons. When we as developers / helpdesk wanted to refabricate a bug specific to a User,

we would log in as that user.

Now we are reworking the application, and the users be authenticated with their windows accounts, so previous method of refabricating bugs wont be possible anymore.

We think that Impersonation will give us an answer for that, without KERBEROS : with some fixed test - account : hence my original  approach.

or with KERBEROS , giving us the complete behaviour we used to have  ( allowing us to impersonate anyone).

Like is said before, the 'impersonation' should happen on server, and on client side, in case there is 'role specific' behaviour written in Business Logic or Data Access Logic .

now, the

owsIdentity wi = new WindowsIdentity(user@domain.com);

impContext = wi.Impersonate(); 
does not appear to fail so long as the client and server are on the same machine, so i will use this approach for local debugging purposes,
Thx for the help