Refresh current user profile - c#

... I want to grant a user temporary administrator privileges via a c# tool. Therefore i add the user to the administrator user group (a background service running under a priviledged service account does this job). However the changes take effect only in new sessions (after Logout/Re-Login) which is inconvenient. Is there a way to refresh the current user profile?
I tried several ways:
via .net Process.Start with the LoadUserProfile property set to true.
The next try was via the LoadUserProfile Win32 Api function.
Another way was to impersonate the user with .net Impersonation
All these tries did not recognize the privilege changes. It seems to me that there is a cached user profile which contains the old privileges and is reloaded anytime.
The only way where a new profile was loaded is the runas command, however we do not want the user to play around with the command line, it should be possible to do this from .net
Would be great if there is another option? Maybe there is a tool which can do this?
Ok, I relog-in the user and then I use the new Token in combination with e.g. CreateProcessAsUser to run a new process using the new token. Is there a way to assign the current windows environment the new token and therefore all actions the user performs in windows use this new token? Otherwise I could use some other tools like lsrunas to open a process in a new context and avoid the winapi calls.
From our perspective we trust the user (it is his private notebook), he can install the software he wants (for a temporary time), but we document each installation with our tool. We are running a service with local admin account in background which manages the group assignment and system documentation.

When logging on to Windows a security token is created, where all group memberships (including nested memberships) are resolved. The token contains a list of SIDs (Security Identifiers) that the user belongs to. The first SID is the user's own ID and then any groups and roles (such as interactive log on, everyone etc) are included. This means that group membership doesn not have to be looked up against the user DB - possibly an Active Directory Server - each time an access control is done. Instead the ACL (Access Control List) of the object (e.g. a file) is checked against the token.
To refresh the group membership you need to have a new token created. Either you can log out and then log in again as you describe it, or you have to do another login with LogonUser for the same user. That function is not accessible for normal user however.
I think that it all boils down to finding another design. Adding and removing a user from the admin group dynamically looks strange from a security perspective. Is there any other way you can give the user access to the resources needed? Can you do the actual work from within a Windows Service that runs under the LocalSystem account?

Related

How to close user accounts from Admin API?

I want to close users (which I'm now successfully importing through Admin API) without their consent when they leave our company and their domain email gets deactivated.
I found the following methods that are related to closing users:
https://developers.docusign.com/docs/admin-api/reference/usermanagement/esignusermanagement/closememberships/
This one says: "This method requires user authentication. It will fail with an application access token." So it's a no go for me because I have no way to get the user's auth form a server-side background application.
https://developers.docusign.com/docs/admin-api/reference/bulkoperations/userimport/closebulkuserimportrequest/
It says "Given a CSV list of users, close their accounts."
But the API method does not accept a CSV file as a request parameter! There is no way to pass any user data to it.
Maybe I could use eSignature API instead of Admin API - it has https://developers.docusign.com/docs/esign-rest-api/reference/users/users/delete/
But that one says "userId string
The ID of the user to access.
Note: Users can only access their own information. A user, even one with Admin rights, cannot access another user's settings."
So, I'm not sure if even an Organization admin with their JWT token can use this method to delete other users? Anyway, most likely, this method will require another JWT token for eSignature API, which in turn will require more infrastructure stuff (config variables, keeping token alive) and I really would want to avoid that and stick to the Admin API only, if possible.
I'm using .net DocuSign nuget package, and I see that CreateBulkImportCloseUsersRequestAsync also has only OrganizationId as the argument. But I don't want to close all the users in the organization, I want to close them by IDs or emails, whichever is accepted by DocuSign.
How do I close user accounts properly? No matter, if it's a bulk or single-user method, as we would want to close them immediately for every separate account.
You cannot close user memberships (note that the term "account" is incorrect here) you can only disable them. You can contact support, but even they cannot really completely eliminate a user membership like it never existed. There are reasons why it must stay in a dormant state.
To explain the difference between users and accounts, here is a diagram:

Process.Start impersonation with ServiceUser credentials / run code in the context of a ServiceUser (without login permissions to the machine)

We are having several departments with individual Service-Accounts on a Windows Domain (Active Directory) and want to use them to impersonate a console command to run it with Process.Start and set the username and password in the code. Process.Start requires a ProcessInfo class object, where a domain, username and password can be provided.
The commands need to be run under these Service-Account credentials to access related network-shares and manipule their structure and files with a cli-program.
The problem is, that all tries so far with running Process.Start within a webservice or api on a IIS server, we still got into the same problem: It seems to be required, that ProcessInfo can only use the other credentials, if the particular user is having login permissions on the running machine.
All the service users are not having rights to directly login to the machine, so the command cannot be run and an Exception is throwing.
Exception message:
Logon failure: the user has not been granted the requested logon type at this computer
Workaround:
To properly run these commands, we are thinking about creating multiple instances of the webservice/api and impersonate it via the IIS AppPool and assign the relevant service user. Each instance will then have a specific service run in which context IIS is serving the webservice/api.
Our goal is to accomplish the webservice/api in a single instance and change user credentials dynamically grabbed from database (username/password).
Is this possible in any way?
Like ServiceUsers can be assigned to windows service (machine/server), which are not needing login permissions.
I just want to ask, before we going the way of the workaround and creating several instances for this solution... Any helping comments or different ideas of solving this challenge are welcome. Thank you, folkz.
The missing logon type may well be "Log on as a batch job" - see if granting the service accounts this right helps.
The exact steps to achieve this might vary between different versions of Windows but will be something like this;
Start the "Local Security Policy" app (AKA secpol) Go to Security
Go to Settings | Local Policies | User Rights Assignment
Edit "Log on as a batch job" and add your service account
If this does not work then don't forget to undo the above - don't leave experimental security changes lying around!

C# Winform app with google Drive API. Way to automate login?

I'm creating a desktop application in C# that will act as a backup program. What I want to do is allow a user to create a schedule for when a backup should happen. I created a windows service that runs in the background that will run based on this schedule.
Right now, my program will copy files that the user has selected to another local user-selected folder. However, I want to extend this to allow users to backup their files to the cloud on a scheduled basis, specifically, their Google Drive account.
I'm not sure if this is possible, though, or how to go about it. I've got code working that will upload files to a Drive account, however, that requires the user to grant permission to my program each and every time it runs. My question is, how can I accomplish this to be done automatically? Is there a way to have a user enter his login credentials once and then allow the program to access their Drive account automatically thereafter, without them having to grant permission every time?
You need to store the access token for your user somewhere and use it to request a new short term access token when you do the backup. From the Google Drive API Docs:
Google Drive applications only receive a long-lived refresh token
during the very first exchange of an authorization code. This refresh
token is used to request new access tokens after a short-lived access
token expires, and it must be stored in the application's database to
be retrieved every time the user returns to the app.
See the documentation here for setting up OAuth in your application

Log into application with Windows Network Authentication

Not sure if there is another thread with the answer, but tried looking and nothing stood out.
Our company runs Windows Server 2008 R2 and as part of the normal login procedure you type your username and password. IT sets the domain when you get your PC so that is all good. So, when you open IE, the intranet sight detects that you are person XXX YYY and then logs you into the site automatically as the right person.
Now is there any way that I can do the same with an application written in C# or VB.NET. I.e., I would like the user to not have to log in as they have already done so during Windows log in, and then use the application as the indicidual user. This is for loggin purposes and specific rights for each group. (like admins or guests etc)
You can use Environment.UserName to get the username of the current user, but you will still need to store some permissions pertaining to this user somewhere.
You can make people a member of an Active Directory group and then grant them permissions based on which group they are a member of but this will require that you (or your application) has the ability to create AD groups and move people in and out of them. If you need some pointers to this then I can find some code.

How to reliably check the windows domain id of current user on a workstation

I am using C# and .Net Framework 4.
I am looking for a foolproof method to get the login id of the currently logged in windows user that is not susceptible to impersonation or hacking. I am looking for this in the form of: DOMAINNAME\USERNAME
e.g. SOMEDOMAIN\JohnDoe
Currently the best I have is:
var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
var currentLoginId = identity.Name;
Is this open to impersonation (outside of someone knowing both the username and password) and if so is there a better way of doing this?
There can be at least four different identities involved at this point:
The identity assigned to the thread
The identity assigned to the process
The account of the user who started the process
The account of the user who logged onto the PC
In your code you're getting (1). This is normally fine, and is usually the same as (2).
To retrieve (2), you could:
Call WindowsIdentity.GetCurrent to get the impersonated identity
Undo impersonation by calling the Win32 RevertToSelf function
Look at WindowsIdentity.GetCurrent to get the underlying process identity
Reset the thread identity by impersonating the identity from step (1)
(2) and (3) will be the same unless you've written unmanaged code that changes the process identity. As #Daniel points out, (3) and (4) could legitimately be different in the presence of the Windows "run as" command.
Edit: You can trust that the current WindowsIdentity is who it says it is, insofar as you can trust any given piece of data in your application.
You could spoof it by attaching a debugger to your process and faking the return value from this call, but if you're going to do that, you might as well fake the piece of code where you pass the user name to the database.
The 100% safe way to do this is to use integrated authentication/SSPI to connect to the database.
Only a partial answer:
I believe System.Security.Principal.WindowsIdentity.GetCurrent(); will return the windows user account associaed with the currently executing thread. If the thread or application was started under a different user account from the logged in user, you won't get what you're after using this.
If you can be sure that your aplication was not started using the "run-as" feature (or programatic equialent) and you're not doing anything internally with respect to the thread's identity, you can probably be sure this is the logged in user's account but I'm not 100% on this.
It may be possible to find the user account associated with the widows "session" within which the application is running by using ADSI (see System.DirectoryServices).

Categories