You are viewing limited content. For full access, please sign in.

Question

Question

Session.Login using Windows AD Credentials

SDK
asked on March 18, 2019

I need to run a console application that loops through all a server's repositories and then lock each repository's volumes. I have one Windows AD account as admin to all the repositories.

I'v managed to Impersonate and set the WindowsIdentity to this AD account, and server.GetRepositories() is calling successfully. However, when i try session.Login(repository), it's giving me Access Denied.

RepositoryRegistration repository = new RepositoryRegistration(serverName, repoName);
session.LogIn(repository);

I even tried setting the Thread's CurrentPrincipal Identity based on that of the WindowsIdentity, and it's still not working. What am i missing?

// Retrieve a GenericPrincipal that is based on the current user's WindowsIdentity.
GenericPrincipal genericPrincipal = GetGenericPrincipal();

// Retrieve the generic identity of the GenericPrincipal object.
GenericIdentity principalIdentity = (GenericIdentity)genericPrincipal.Identity;

Thread.CurrentPrincipal = genericPrincipal;



// Create a generic principal based on values from the current WindowsIdentity.
        private static GenericPrincipal GetGenericPrincipal()
        {
            // Use values from the current WindowsIdentity to construct
            // a set of GenericPrincipal roles.
            WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
            string[] roles = new string[10];
            if (windowsIdentity.IsAuthenticated)
            {
                // Add custom NetworkUser role.
                roles[0] = "NetworkUser";
            }

            if (windowsIdentity.IsGuest)
            {
                // Add custom GuestUser role.
                roles[1] = "GuestUser";
            }

            if (windowsIdentity.IsSystem)
            {
                // Add custom SystemUser role.
                roles[2] = "SystemUser";
            }

            // Construct a GenericIdentity object based on the current Windows
            // identity name and authentication type.
            string authenticationType = windowsIdentity.AuthenticationType;
            string userName = windowsIdentity.Name;
            GenericIdentity genericIdentity =
                new GenericIdentity(userName, authenticationType);

            // Construct a GenericPrincipal object based on the generic identity
            // and custom roles for the user.
            GenericPrincipal genericPrincipal =
                new GenericPrincipal(genericIdentity, roles);

            return genericPrincipal;
        }

 

0 0

Replies

replied on March 18, 2019

Since this can get complicated, I switched to using a NuGet package called SimpleImpersonation.

Now, all of my scripts just start with:

var credentials = new UserCredentials("domain", "user_name", "password");
Impersonation.RunAsUser(credentials, LogonType.Interactive, () =>
{
	var repo = new RepositoryRegistration("lf_server", "Repository_Name");
	session = new Session();
	session.LogIn(repo);
});

// Then you can proceed with the rest of your SDK work.

 

1 0
replied on March 18, 2019

Hi Devin, i used the SimpleImpersonation package and code as you suggested, but it's still not authenticating. Btw this class also utilizes the LogonUser function in the Windows API which i already tried successfully to call server.GetRepositories(). However it's failing on the session.Login() function. I don't get how it can work for one and not the other.

Anyway, the Exception Message is "Failed to Authenticate". If it's any help, the stack trace is as follows:

   at Laserfiche.HttpClient.HttpRequest.SendRequestWithCredentials(Boolean useKerberos, Boolean negotiateAuth)
   at Laserfiche.HttpClient.HttpRequest.SendRequest()
   at Laserfiche.RepositoryAccess.Session.SendLogInRequest(String idnRepName, HttpCredential credentials)
   at Laserfiche.RepositoryAccess.Session.LoginToServer(RepositoryRegistration repository, HttpCredential credentials)
   at Laserfiche.RepositoryAccess.Session.LogIn(RepositoryRegistration repository)
   at AUB.Laserfiche.Backups.RepoEngine.<>c__DisplayClass5_0.<StartRepoSession>b__0()

 

0 0
replied on March 19, 2019

I'm pretty sure GetRepositories() does not require authentication, which would be why you're seeing different behavior.

The repository information needs to be discoverable to some degree because, as an example, you need to see a list of repositories in the client before you can even choose which one to authenticate too.

0 0
replied on March 19, 2019

Probably... but i was getting access denied errors until i did the WindowsIdentity impersonation.

0 0
replied on March 18, 2019

Why are you constructing a GenericPrincipal if you already have a WindowsIdentity for the user you want to connect as?  Since you can construct a GenericPrincipal for an account without knowing its password, you can guess that it won't be usable to authenticate to a remote service.  If you run the console application as the desired user you don't have to mess with identities and principals.

More technically, if you do construct an identity you need to impersonate it so that calls to AcquireCredentialsHandle succeed.

0 0
replied on March 18, 2019

Hi Brian, thanks for your reply and yes, that line of thought about not supplying the password boggled me, yet i couldn't find a way to set the thread's CurrentPrincipal to the WindowsIdentity, plus i found that same code repeated many times in forums and other sites.

 

Regarding the AcquireCredentialsHandle, im not quite sure how to achieve that. Some sample code would me greatly appreciated. Thanks!

0 0
replied on March 18, 2019

Devin's answer gives one way of doing it, I'm not familiar with that library but I imagine it's similar to code discussed here, among other places.  That approach requires you to store and read credentials from somewhere, either compiled into the exe or from a configuration file.  If you can launch this program as the desired user (via services or whatever) then that is not a problem you have to solve yourself.

Identities are often for use inside a single application, where one part of the program determines what capabilities a user has and other parts make decisions based on that.  Those internal identities don't have an effect on how the program authenticates to an external program, that's what Windows impersonation is for.

0 0
replied on March 18, 2019

Hi Brian, the code in that thread is exactly the base code i used to impersonate the WindowsIdentity, and like i explained to Devin, it was successful in calling the server.GetRepositories() function... however it fails when calling session.Login(repo) for some reason. How do their authentication mechanisms differ... shouldn't they be the same?

0 0
replied on March 18, 2019

Btw, you can see in my code that i tried setting the Thread's CurrentPrincipal to one based on the WindowsIdentity using a GenericPrincipal. I'm suspecting there's a specific role that needs to be given to it... could that be the case?

0 0
replied on March 19, 2019

The most important step in the linked code is the Impersonate() call, which you don't have.  Thread.CurrentPrincipal is largely irrelevant for your situation.  It "Gets or sets the thread's current principal (for role-based security)", but won't have an impact on how you authenticate to a remote system.  The GenericPrincipal can't help here (since it has no authentication information associated with it), you want to use the WindowsIdentity directly like in the linked code.  Why are you building a principle with the same identity as the current Windows identity instead of using the latter directly?

One puzzling thing is that since the code doesn't change the identity of the thread or process, when you attempt to authenticate you should be using the original process identity.  Why doesn't that work?

0 0
replied on March 19, 2019

Hi Brian, regarding the Impersonate() call... i am calling it, it's just not included in the code i pasted in the initial post. I mentioned that i managed to impersonate and set the WindowsIdentity to the AD account, and that's how i did it, using the LogonUser function of Windows API. To be exact, i'm using this class (which internally calls the Impersonate() function):

https://www.daoudisamir.com/impersonate-users-in-c/

 

0 0
replied on March 21, 2019

LogonUser + Impersonate has always worked for me.  You're sure the account you are trying to impersonate has been given access to the repository?

0 0
replied on March 21, 2019

Imagine if that was it Brian... laugh

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.