How can I detect if another process is elevated? [duplicate] - c#

I have an application that needs to detect whether or not it is running with elevated privileges or not. I currently have code set up like this:
static bool IsAdministrator()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole (WindowsBuiltInRole.Administrator);
}
This works to detect if a user is an administrator or not, but doesn't work if running as an administrator without elevation. (For example in vshost.exe).
How can I determine whether or not elevation is [already in force or] possible?

Try this out:
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
public static class UacHelper
{
private const string uacRegistryKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
private const string uacRegistryValue = "EnableLUA";
private static uint STANDARD_RIGHTS_READ = 0x00020000;
private static uint TOKEN_QUERY = 0x0008;
private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);
public enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
MaxTokenInfoClass
}
public enum TOKEN_ELEVATION_TYPE
{
TokenElevationTypeDefault = 1,
TokenElevationTypeFull,
TokenElevationTypeLimited
}
public static bool IsUacEnabled
{
get
{
RegistryKey uacKey = Registry.LocalMachine.OpenSubKey(uacRegistryKey, false);
bool result = uacKey.GetValue(uacRegistryValue).Equals(1);
return result;
}
}
public static bool IsProcessElevated
{
get
{
if (IsUacEnabled)
{
IntPtr tokenHandle;
if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_READ, out tokenHandle))
{
throw new ApplicationException("Could not get process token. Win32 Error Code: " + Marshal.GetLastWin32Error());
}
TOKEN_ELEVATION_TYPE elevationResult = TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;
int elevationResultSize = Marshal.SizeOf((int)elevationResult);
uint returnedSize = 0;
IntPtr elevationTypePtr = Marshal.AllocHGlobal(elevationResultSize);
bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType, elevationTypePtr, (uint)elevationResultSize, out returnedSize);
if (success)
{
elevationResult = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(elevationTypePtr);
bool isProcessAdmin = elevationResult == TOKEN_ELEVATION_TYPE.TokenElevationTypeFull;
return isProcessAdmin;
}
else
{
throw new ApplicationException("Unable to determine the current elevation.");
}
}
else
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
bool result = principal.IsInRole(WindowsBuiltInRole.Administrator);
return result;
}
}
}
}

(new answer six years after the question was asked)
Disclaimer: This is just something that happened to work on my particular OS with my particular settings with my particular user:
using System.Security.Principal;
// ...
static bool IsElevated
{
get
{
return WindowsIdentity.GetCurrent().Owner
.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
}
}
So when I run this "Run as administrator", the property get accessor returns true. When running normally (even if my user "is" administrator, just not running this particular application "as administrator"), it returns false.
This seems much simpler than many other answers.
I have no idea if there are cases where this fails.
PS! This also seems OK:
static bool IsElevated
{
get
{
var id = WindowsIdentity.GetCurrent();
return id.Owner != id.User;
}
}

Here is a modified version of this answer to include things like the proper disposing of resources and handling of Domain Administrators.
public static class UacHelper
{
private const string uacRegistryKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
private const string uacRegistryValue = "EnableLUA";
private static uint STANDARD_RIGHTS_READ = 0x00020000;
private static uint TOKEN_QUERY = 0x0008;
private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);
public enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
MaxTokenInfoClass
}
public enum TOKEN_ELEVATION_TYPE
{
TokenElevationTypeDefault = 1,
TokenElevationTypeFull,
TokenElevationTypeLimited
}
public static bool IsUacEnabled
{
get
{
using (RegistryKey uacKey = Registry.LocalMachine.OpenSubKey(uacRegistryKey, false))
{
bool result = uacKey.GetValue(uacRegistryValue).Equals(1);
return result;
}
}
}
public static bool IsProcessElevated
{
get
{
if (IsUacEnabled)
{
IntPtr tokenHandle = IntPtr.Zero;
if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_READ, out tokenHandle))
{
throw new ApplicationException("Could not get process token. Win32 Error Code: " +
Marshal.GetLastWin32Error());
}
try
{
TOKEN_ELEVATION_TYPE elevationResult = TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;
int elevationResultSize = Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE));
uint returnedSize = 0;
IntPtr elevationTypePtr = Marshal.AllocHGlobal(elevationResultSize);
try
{
bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType,
elevationTypePtr, (uint) elevationResultSize,
out returnedSize);
if (success)
{
elevationResult = (TOKEN_ELEVATION_TYPE) Marshal.ReadInt32(elevationTypePtr);
bool isProcessAdmin = elevationResult == TOKEN_ELEVATION_TYPE.TokenElevationTypeFull;
return isProcessAdmin;
}
else
{
throw new ApplicationException("Unable to determine the current elevation.");
}
}
finally
{
if (elevationTypePtr != IntPtr.Zero)
Marshal.FreeHGlobal(elevationTypePtr);
}
}
finally
{
if (tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
}
}
else
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
bool result = principal.IsInRole(WindowsBuiltInRole.Administrator)
|| principal.IsInRole(0x200); //Domain Administrator
return result;
}
}
}
}

The CodePlex project UAChelper has code that checks on elevation in UserAccountControl.cpp UserAccountControl::IsUserAdmin, that checks if UAC is enabled and then checks if process is elevated.
bool UserAccountControl::IsCurrentProcessElevated::get()
{
return GetProcessTokenElevationType() == TokenElevationTypeFull; //elevated
}
from the function:
int UserAccountControl::GetProcessTokenElevationType()
{
HANDLE hToken;
try
{
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
throw gcnew Win32Exception(GetLastError());
TOKEN_ELEVATION_TYPE elevationType;
DWORD dwSize;
if (!GetTokenInformation(hToken, TokenElevationType, &elevationType, sizeof(elevationType), &dwSize))
throw gcnew Win32Exception(GetLastError());
return elevationType;
}
finally
{
CloseHandle(hToken);
}
}

In .net Framwork 4.5 I found another method that works for me.
In relation to the following script that can be found here here (in German)
rem --- Admintest.bat ---
whoami /groups | find "S-1-5-32-544" > nul
if errorlevel 1 goto ende
echo Benutzer %username% ist lokaler Administrator.
:ende
In C# it looks like this:
private bool IsAdmin
{
get
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
if (identity != null)
{
WindowsPrincipal principal = new WindowsPrincipal(identity);
List<Claim> list = new List<Claim>(principal.UserClaims);
Claim c = list.Find(p => p.Value.Contains("S-1-5-32-544"));
if (c != null)
return true;
}
return false;
}
}
But in .net < 4.5 the WindowsPrincipal class does not contain the UserClaims property
and I found no way to get this information.

Using TokenElevationType would work, but if you PInvoke CheckTokenMembership() against the admin group SID, your code would also work when UAC is off and on 2000/XP/2003 and will also handle deny SID's.
There is also a IsUserAnAdmin() function that does the CheckTokenMembership check for you, but MSDN says it might not be there forever

This Answer has a few problems. First, it doesn't get any System processes that run as Admin (for example under NT-Authority/SYSTEM).
The code example below fixes all problems (detects, LocalAdmins, DomainAdmins, and LocalSystemAdmins)
If you just want the current Process, replace pHandle with Process.GetCurrentProcess().Handle
NOTE:
You must have certain privileges to run it. (Every AdminProcess has them but
needs to active them first, Services have them activated by default)
internal static bool IsProcessElevatedEx(this IntPtr pHandle) {
var token = IntPtr.Zero;
if (!OpenProcessToken(pHandle, MAXIMUM_ALLOWED, ref token))
throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");
WindowsIdentity identity = new WindowsIdentity(token);
WindowsPrincipal principal = new WindowsPrincipal(identity);
bool result = principal.IsInRole(WindowsBuiltInRole.Administrator)
|| principal.IsInRole(0x200); //Domain Administrator
CloseHandle(token);
return result;
}

I think there is one more issue. I checked solutions provided by you and have to say that in the installation of Windows 7 and logged on as an admin the check does not work. Windows never returns information that process runs in an elevated mode. So the sequence:
if (IsUacEnabled)
return IsProcessInElevatedMode();
return IsUserAdmin();
does not returns true when logged as an Administrator but the process has all privileges to perform system operations (e.g. stop system services).
The working sequence is:
if (IsUserAdmin())
return true;
if (IsUacEnabled)
return IsProcessInElevatedMode();
return false;
You should first check if the process is run in Administrator context.
Additional info:
IsUacEnabled() - checks if the UAC has been enabled in the system (Windows)
IsProcessInElevatedMode() - checks if the process is run in an elevated mode
IsUserAdmin() - checks if the current user has an Administrtor role
All of that methods has been described in previous posts.

Using UACHelper nuget package:
https://www.nuget.org/packages/UACHelper/
if (UACHelper.IsElevated)
// something
else
// something else
There are a lot of other properties that can be used to detect if the user is, in fact, an administrator, or if the process is running under UAC virtualization, or if the desktop owner is the process owner. (Run as from limited account)
Check the read me for more information.

I am using this code and it works well:
bool runningAsAdmin = WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
*Admin is part of the Build-In Administrators group.
"A user account for the system administrator. This account is the first account created during operating system installation. The account cannot be deleted or locked out. It is a member of the Administrators group and cannot be removed from that group." -- https://ss64.com/nt/syntax-security_groups.html

Related

How can I use impersonation to manipulate files/directories on a remote machine with UNC?

I need to download files from a server to a shared drive directory, creating the directory if it doesn't exist. There are a few things making this more complicated:
I do not have write access (nor does the account that will run the job in UAT/Prod) to the shared drive directory.
The Service account that does have write access does not have any privileges anywhere but the shared drive directory.
I attempt to impersonate, as so:
class Impersonation
{
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON_TYPE_NEW_CREDENTIALS = 9;
const int LOGON32_PROVIDER_WINNT50 = 3;
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
public static void Impersonate(string domain, string user, string password, Action act)
{
//if no user specified, don't impersonate
if (user.Trim() == "")
{
act();
return;
}
WindowsImpersonationContext impersonationContext = null;
IntPtr token = IntPtr.Zero;
try
{
//if no domain specified, default it to current machine
if (domain.Trim() == "")
{
domain = System.Environment.MachineName;
}
bool result = LogonUser(user, domain, password, LOGON_TYPE_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, ref token);
WindowsIdentity wi = new WindowsIdentity(token);
impersonationContext = WindowsIdentity.Impersonate(token);
act();
}
catch (Exception ex)
{
if (impersonationContext != null)
{
impersonationContext.Undo();
impersonationContext = null;
}
//if something went wrong, try it as the running user just in case
act();
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
impersonationContext = null;
}
if (token != IntPtr.Zero)
{
CloseHandle(token);
token = IntPtr.Zero;
}
}
}
}
And a piece of the the actual calling code is (in another class):
private static void CreateDirectoryIfNotExist(string directory, string domain, string username, string password)
{
Impersonation.Impersonate(domain, username, password, () => CreateIfNotExist(directory));
}
private static void CreateIfNotExist(string dir)
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
}
If I run it with the proper login info for the service account, I get an Exception on the Directory.CreateDirectory(string) call:
{System.IO.IOException: This user isn't allowed to sign in to this computer.}
I'm guessing this means the service account isn't allowed to log in to the executing machine, which I already knew. But really, there's no reason it needs to log in to the executing machine. Is there a way I can use impersonation to log on to a remote machine and execute the commands from there?
You cannot do it with impersonation if the account cannot log on. Impersonation requires the thread to run under the user credentials. That is why the LogonUser fails.
You can use the WNetAddConnection2 function that is used to establish a connection to a network resource.
Here is a sample for your CreateDirectoryIfNotExist function using this approach:
public static void CreateDirectoryIfNotExists(string directory, string sharePath, string username, string password)
{
NETRESOURCE nr = new NETRESOURCE();
nr.dwType = ResourceType.RESOURCETYPE_DISK;
nr.lpLocalName = null;
nr.lpRemoteName = sharePath;
nr.lpProvider = null;
int result = WNetAddConnection2(nr, password, username, 0);
string directoryFullPath = Path.Combine(sharePath, directory);
if (!Directory.Exists(directoryFullPath))
{
Directory.CreateDirectory(directoryFullPath);
}
}
To be able to do the system call you need also the following definitions from pinvoke.net.
[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public ResourceScope dwScope = 0;
public ResourceType dwType = 0;
public ResourceDisplayType dwDisplayType = 0;
public ResourceUsage dwUsage = 0;
[MarshalAs(UnmanagedType.LPStr)] public string lpLocalName = null;
[MarshalAs(UnmanagedType.LPStr)] public string lpRemoteName = null;
[MarshalAs(UnmanagedType.LPStr)] public string lpComment = null;
[MarshalAs(UnmanagedType.LPStr)] public string lpProvider;
};
public enum ResourceScope
{
RESOURCE_CONNECTED = 1,
RESOURCE_GLOBALNET,
RESOURCE_REMEMBERED,
RESOURCE_RECENT,
RESOURCE_CONTEXT
};
public enum ResourceType
{
RESOURCETYPE_ANY,
RESOURCETYPE_DISK,
RESOURCETYPE_PRINT,
RESOURCETYPE_RESERVED
};
public enum ResourceUsage
{
RESOURCEUSAGE_CONNECTABLE = 0x00000001,
RESOURCEUSAGE_CONTAINER = 0x00000002,
RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
RESOURCEUSAGE_SIBLING = 0x00000008,
RESOURCEUSAGE_ATTACHED = 0x00000010,
RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
};
public enum ResourceDisplayType
{
RESOURCEDISPLAYTYPE_GENERIC,
RESOURCEDISPLAYTYPE_DOMAIN,
RESOURCEDISPLAYTYPE_SERVER,
RESOURCEDISPLAYTYPE_SHARE,
RESOURCEDISPLAYTYPE_FILE,
RESOURCEDISPLAYTYPE_GROUP,
RESOURCEDISPLAYTYPE_NETWORK,
RESOURCEDISPLAYTYPE_ROOT,
RESOURCEDISPLAYTYPE_SHAREADMIN,
RESOURCEDISPLAYTYPE_DIRECTORY,
RESOURCEDISPLAYTYPE_TREE,
RESOURCEDISPLAYTYPE_NDSCONTAINER
};
public enum ResourceConnection
{
CONNECT_UPDATE_PROFILE = 1,
CONNECT_UPDATE_RECENT = 2,
CONNECT_TEMPORARY = 4,
CONNECT_INTERACTIVE = 8,
CONNECT_PROMPT = 0X10,
CONNECT_REDIRECT = 0X80,
CONNECT_CURRENT_MEDIA = 0X200,
CONNECT_COMMAND_LINE = 0X800,
CONNECT_CMD_SAVECRED = 0X1000,
CONNECT_CRED_RESET = 0X2000
};
[DllImport("mpr.dll", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
private static extern int WNetAddConnection2(NETRESOURCE lpNetResource,
[MarshalAs(UnmanagedType.LPStr)] string lpPassword,
[MarshalAs(UnmanagedType.LPStr)] string lpUserName, int dwFlags);
You can add this definitions to the same class as your function.
Here are also links to two older post which also use the same approach.
Accessing a Shared File (UNC) From a Remote, Non-Trusted Domain With Credentials
How do I access a file share programmatically
You can solve this problem like I solved it. Below are the steps:
Step 1: Open IIS. Then add a virtual directory in your web application.
Step 2: Then map your shared path with the virtual directory added in Step 1
Step 3: Now click on Connect as..
Step 4: Set the credential of your desired user by which you want to connect your shared path.
Step 5: Now the IIS configuration part is over and you need to start using src="Image/Image.png" in your html or start manipulating "SharedFolder/YourFile.ext".

Using Chromedriver with Developed Extension and Force Install Group Policy

I am working on a web application that has the following environment setup:
The website is designed to work in Chrome
The website depends on a Chrome Extension developed in-house and hosted on the Chrome Play Store
To make getting the extension easier, our systems team has setup the ExtensionInstallForcelist Group Policy (more information here http://dev.chromium.org/administrators/policy-list-3#ExtensionInstallForcelist). This makes it so Chrome can get the extension and update it as needed without manual user interaction
This is all setup on imaged devices (so separate devices, with separate browsers and group policies, that each get the extension on their own)
The problem I'm facing is when trying to use a Chromedriver instance with this group policy.
With the policy enabled, I am getting an error that says "Failed to load extension from: . (extension ID ) is blocked by the administrator." when running our tests.
This seems to happen because we add the extension to our Chromedriver through the Chrome Options (add Extension).
While I can manually turn off the Group Policy on our imaged devices to get around this, I was wondering if there is any setting I can add to the group policy to make it allow the installation of our extension in the Chromedriver?
I've tried a number of ways to get around this otherwise that didn't seem to work:
Command Line altering of the registry values set by the Group Policy - didn't work as, although altering the registry values worked, I still recevied the error on running tests
PowerShell altering of the group policy - won't work as it requires additional install of the Get Group Policy cmdlets
Using the GPMC C# libraries - the libraries seem very much out of date at this point (some only use .NET 2.0). I was able to setup some code to use the classes, but I receive a "reference missing" exception for creating a GPODomain object even though I have the reference in my solution
Thank you all in advance for any suggestions on getting making Chromedriver work with the force install group policy.
After a lot of looking at different answers around the web, I found this solution works.
Create a GroupPolicy class to handle interacting with it:
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Automation.Core
{
[ComImport, Guid("EA502722-A23D-11d1-A7D3-0000F87571E3")]
internal class GPClass
{
}
[ComImport, Guid("EA502723-A23D-11d1-A7D3-0000F87571E3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGroupPolicyObject
{
uint New([MarshalAs(UnmanagedType.LPWStr)] string domainName, [MarshalAs(UnmanagedType.LPWStr)] string displayName, uint flags);
uint OpenDSGPO([MarshalAs(UnmanagedType.LPWStr)] string path, uint flags);
uint OpenLocalMachineGPO(uint flags);
uint OpenRemoteMachineGPO([MarshalAs(UnmanagedType.LPWStr)] string computerName, uint flags);
uint Save([MarshalAs(UnmanagedType.Bool)] bool machine, [MarshalAs(UnmanagedType.Bool)] bool add, [MarshalAs(UnmanagedType.LPStruct)] Guid extension, [MarshalAs(UnmanagedType.LPStruct)] Guid app);
uint Delete();
uint GetName([MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxLength);
uint GetDisplayName([MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxLength);
uint SetDisplayName([MarshalAs(UnmanagedType.LPWStr)] string name);
uint GetPath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder path, int maxPath);
uint GetDSPath(uint section, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path, int maxPath);
uint GetFileSysPath(uint section, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path, int maxPath);
uint GetRegistryKey(uint section, out IntPtr key);
uint GetOptions(out uint options);
uint SetOptions(uint options, uint mask);
uint GetType(out IntPtr gpoType);
uint GetMachineName([MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxLength);
uint GetPropertySheetPages(out IntPtr pages);
}
public enum GroupPolicySection
{
Root = 0,
User = 1,
Machine = 2,
}
public abstract class GroupPolicyObject
{
protected const int MaxLength = 1024;
/// <summary>
/// The snap-in that processes .pol files
/// </summary>
private static readonly Guid RegistryExtension = new Guid(0x35378EAC, 0x683F, 0x11D2, 0xA8, 0x9A, 0x00, 0xC0, 0x4F, 0xBB, 0xCF, 0xA2);
/// <summary>
/// This application
/// </summary>
private static readonly Guid LocalGuid = new Guid(GetAssemblyAttribute<GuidAttribute>(Assembly.GetExecutingAssembly()).Value);
protected IGroupPolicyObject Instance = (IGroupPolicyObject) new GPClass();
static T GetAssemblyAttribute<T>(ICustomAttributeProvider assembly) where T : Attribute
{
object[] attributes = assembly.GetCustomAttributes(typeof(T), true);
if (attributes.Length == 0)
return null;
return (T)attributes[0];
}
public void Save()
{
var result = Instance.Save(true, true, RegistryExtension, LocalGuid);
if (result != 0)
{
throw new Exception("Error saving machine settings");
}
result = Instance.Save(false, true, RegistryExtension, LocalGuid);
if (result != 0)
{
throw new Exception("Error saving user settings");
}
}
public RegistryKey GetRootRegistryKey(GroupPolicySection section)
{
IntPtr key;
var result = Instance.GetRegistryKey((uint)section, out key);
if (result != 0)
{
throw new Exception(string.Format("Unable to get section '{0}'", Enum.GetName(typeof(GroupPolicySection), section)));
}
var handle = new SafeRegistryHandle(key, true);
return RegistryKey.FromHandle(handle, RegistryView.Default);
}
}
public class GroupPolicyObjectSettings
{
public readonly bool LoadRegistryInformation;
public readonly bool Readonly;
public GroupPolicyObjectSettings(bool loadRegistryInfo = true, bool readOnly = false)
{
LoadRegistryInformation = loadRegistryInfo;
Readonly = readOnly;
}
private const uint RegistryFlag = 0x00000001;
private const uint ReadonlyFlag = 0x00000002;
internal uint Flag
{
get
{
uint flag = 0x00000000;
if (LoadRegistryInformation)
{
flag |= RegistryFlag;
}
if (Readonly)
{
flag |= ReadonlyFlag;
}
return flag;
}
}
}
public class ComputerGroupPolicyObject : GroupPolicyObject
{
public readonly bool IsLocal;
public ComputerGroupPolicyObject(GroupPolicyObjectSettings options = null)
{
options = options ?? new GroupPolicyObjectSettings();
var result = Instance.OpenLocalMachineGPO(options.Flag);
if (result != 0)
{
throw new Exception("Unable to open local machine GPO");
}
IsLocal = true;
}
public static void SetPolicySetting(string registryInformation, string settingValue, RegistryValueKind registryValueKind)
{
string valueName;
GroupPolicySection section;
string key = Key(registryInformation, out valueName, out section);
// Thread must be STA
Exception exception = null;
var t = new Thread(() =>
{
try
{
var gpo = new ComputerGroupPolicyObject();
using (RegistryKey rootRegistryKey = gpo.GetRootRegistryKey(section))
{
// Data can't be null so we can use this value to indicate key must be delete
if (settingValue == null)
{
using (RegistryKey subKey = rootRegistryKey.OpenSubKey(key, true))
{
if (subKey != null)
{
subKey.DeleteValue(valueName);
}
}
}
else
{
using (RegistryKey subKey = rootRegistryKey.CreateSubKey(key))
{
subKey.SetValue(valueName, settingValue, registryValueKind);
}
}
}
gpo.Save();
}
catch (Exception ex)
{
exception = ex;
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
if (exception != null)
throw exception;
}
public static object GetPolicySetting(string registryInformation)
{
string valueName;
GroupPolicySection section;
string key = Key(registryInformation, out valueName, out section);
// Thread must be STA
object result = null;
var t = new Thread(() =>
{
var gpo = new ComputerGroupPolicyObject();
using (RegistryKey rootRegistryKey = gpo.GetRootRegistryKey(section))
{
// Data can't be null so we can use this value to indicate key must be delete
using (RegistryKey subKey = rootRegistryKey.OpenSubKey(key, true))
{
if (subKey == null)
{
result = null;
}
else
{
result = subKey.GetValue(valueName);
}
}
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
return result;
}
public static string Key(string registryInformation, out string value, out GroupPolicySection section)
{
// Parse parameter of format HKCU\Software\Policies\Microsoft\Windows\Personalization!NoChangingSoundScheme
string[] split = registryInformation.Split('!');
string key = split[0];
string hive = key.Substring(0, key.IndexOf('\\'));
key = key.Substring(key.IndexOf('\\') + 1);
value = split[1];
if (hive.Equals(#"HKLM", StringComparison.OrdinalIgnoreCase)
|| hive.Equals(#"HKEY_LOCAL_MACHINE", StringComparison.OrdinalIgnoreCase))
{
section = GroupPolicySection.Machine;
}
else
{
section = GroupPolicySection.User;
}
return key;
}
}
}
Then turn off the Force Install Chrome Extension Group Policy with a call like this:
[STAThread]
private static bool DisabledChromeExtensionGPO()
{
var PolicyExists = ComputerGroupPolicyObject.GetPolicySetting(#"HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist!1");
if (PolicyExists != null)
{
ComputerGroupPolicyObject.SetPolicySetting(#"HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist!1", "null", RegistryValueKind.String);
}
return true;
}
While the policy will still have its key in regedit listed, the value of the key will be set to null.
Setting the value to null allowed the Chrome Driver to load our local Chrome Extension file without issue at this point.

NetApi32 for UNC path is returning error code 1326

I have been trying to drop a file into a samba share folder within my application for the past few days.
Story so far
I took a copy of the UNCAccessWithCredentials class found here and referenced it in my repository. This class uses the NetApi32.dll
I wrote the following code to check whether a connection was present, and if there was not one, to create the connection.
bool available = UNCConnection.IsNetworkPathAvailable(WebConfigurationManager.AppSettings[#"ExportFilePath"]);
string uncpath = WebConfigurationManager.AppSettings[#"ExportFilePath"];
string user = WebConfigurationManager.AppSettings["ExportUser"];
string password = WebConfigurationManager.AppSettings["ExportPassword"];
string domain = #"";
string filePath = uncpath + #"\exportFile" + ".txt";
if (!available)
{
using (UNCAccessWithCredentials unc = new UNCAccessWithCredentials())
{
var x = unc.NetUseWithCredentials(uncpath, user, domain, password);
if (x)
{
CsvContext cc = new CsvContext();
cc.Write(
chargesForExport,
filePath,
outputFileDescription);
}
else
{
var error = unc.GetStatusCodeDefinition(unc.LastError);
throw new Exception(String.Format("The following error occured whilst writing to the creditors folder: {0}", error));
}
}
}
else
{
CsvContext cc = new CsvContext();
cc.Write(
chargesForExport,
filePath,
outputFileDescription);
}
The problem
When running this in debug via IIS Express, this works no problem.
I have run 'net use' from the cmd line and set a breakpoint on unc.NetUseWithCredentials
Before - No connection
During - Connection
After Using - No Connection
When I deploy to live, or host locally on full blown IIS I see error code '1326' which I believe means ERROR_LOGON_FAILURE. These credentials defiantly work because I can use them to browse to the folder, and I can use them to map a network drive to this folder and they are the same credentials I am using when it works in debug.
What I have tried
I have tried mapping a network share, closing any existing connections using netuse /delete, changing the identity in the IIS app pool to a custom account neither the administrator or my personal AD account made a difference. I have also ran caspol to set the policy to full trust but I still see error 1326.
I don't understand why this works perfectly when running off IIS Express, but the minute I host this on full blown IIS, I only see error 1326.
Can anyone see the problem here!?
UNCAccessWithCredentials Class
public class UNCAccessWithCredentials : IDisposable
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct USE_INFO_2
{
internal LPWSTR ui2_local;
internal LPWSTR ui2_remote;
internal LPWSTR ui2_password;
internal DWORD ui2_status;
internal DWORD ui2_asg_type;
internal DWORD ui2_refcount;
internal DWORD ui2_usecount;
internal LPWSTR ui2_username;
internal LPWSTR ui2_domainname;
}
[DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern NET_API_STATUS NetUseAdd(
LPWSTR UncServerName,
DWORD Level,
ref USE_INFO_2 Buf,
out DWORD ParmError);
[DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern NET_API_STATUS NetUseDel(
LPWSTR UncServerName,
LPWSTR UseName,
DWORD ForceCond);
private bool disposed = false;
private string sUNCPath;
private string sUser;
private string sPassword;
private string sDomain;
private int iLastError;
/// <summary>
/// A disposeable class that allows access to a UNC resource with credentials.
/// </summary>
public UNCAccessWithCredentials()
{
}
/// <summary>
/// The last system error code returned from NetUseAdd or NetUseDel. Success = 0
/// </summary>
public int LastError
{
get { return iLastError; }
}
public void Dispose()
{
if (!this.disposed)
{
NetUseDelete();
}
disposed = true;
GC.SuppressFinalize(this);
}
/// <summary>
/// Connects to a UNC path using the credentials supplied.
/// </summary>
/// <param name="UNCPath">Fully qualified domain name UNC path</param>
/// <param name="User">A user with sufficient rights to access the path.</param>
/// <param name="Domain">Domain of User.</param>
/// <param name="Password">Password of User</param>
/// <returns>True if mapping succeeds. Use LastError to get the system error code.</returns>
public bool NetUseWithCredentials(string UNCPath, string User, string Domain, string Password)
{
sUNCPath = UNCPath;
sUser = User;
sPassword = Password;
sDomain = Domain;
return NetUseWithCredentials();
}
private bool NetUseWithCredentials()
{
uint returncode;
try
{
USE_INFO_2 useinfo = new USE_INFO_2();
useinfo.ui2_remote = sUNCPath;
useinfo.ui2_username = sUser;
useinfo.ui2_domainname = sDomain;
useinfo.ui2_password = sPassword;
useinfo.ui2_asg_type = 0;
useinfo.ui2_usecount = 1;
uint paramErrorIndex;
returncode = NetUseAdd(null, 2, ref useinfo, out paramErrorIndex);
iLastError = (int)returncode;
return returncode == 0;
}
catch
{
iLastError = Marshal.GetLastWin32Error();
return false;
}
}
/// <summary>
/// Ends the connection to the remote resource
/// </summary>
/// <returns>True if it succeeds. Use LastError to get the system error code</returns>
public bool NetUseDelete()
{
uint returncode;
try
{
returncode = NetUseDel(null, sUNCPath, 2);
iLastError = (int)returncode;
return (returncode == 0);
}
catch
{
iLastError = Marshal.GetLastWin32Error();
return false;
}
}
~UNCAccessWithCredentials()
{
Dispose();
}
public string GetStatusCodeDefinition(int errorCode)
{
var test = (StatusCodeDefinitions)errorCode;
return test.ToString();
}
}

how to write tests that impersonates different users?

My Winforms app set permissions based on the group membership found in the current process.
I just made a unit test in MSTEST.
I'd like to run it as other users so I can verify the expected behavior.
Here's what I'm kind of shooting for:
[TestMethod]
public void SecuritySummaryTest1()
{
Impersonate(#"SomeDomain\AdminUser", password);
var target = new DirectAgentsSecurityManager();
string actual = target.SecuritySummary;
Assert.AreEqual(
#"Default=[no]AccountManagement=[no]MediaBuying=[no]AdSales=[no]Accounting=[no]Admin=[YES]", actual);
}
[TestMethod]
public void SecuritySummaryTest2()
{
Impersonate(#"SomeDomain\AccountantUser", password);
var target = new DirectAgentsSecurityManager();
string actual = target.SecuritySummary;
Assert.AreEqual(
#"Default=[no]AccountManagement=[YES]MediaBuying=[no]AdSales=[no]Accounting=[YES]Admin=[NO]", actual);
}
public class UserCredentials
{
private readonly string _domain;
private readonly string _password;
private readonly string _username;
public UserCredentials(string domain, string username, string password)
{
_domain = domain;
_username = username;
_password = password;
}
public string Domain { get { return _domain; } }
public string Username { get { return _username; } }
public string Password { get { return _password; } }
}
public class UserImpersonation : IDisposable
{
private readonly IntPtr _dupeTokenHandle = new IntPtr(0);
private readonly IntPtr _tokenHandle = new IntPtr(0);
private WindowsImpersonationContext _impersonatedUser;
public UserImpersonation(UserCredentials credentials)
{
const int logon32ProviderDefault = 0;
const int logon32LogonInteractive = 2;
const int securityImpersonation = 2;
_tokenHandle = IntPtr.Zero;
_dupeTokenHandle = IntPtr.Zero;
if (!Advapi32.LogonUser(credentials.Username, credentials.Domain, credentials.Password,
logon32LogonInteractive, logon32ProviderDefault, out _tokenHandle))
{
var win32ErrorNumber = Marshal.GetLastWin32Error();
// REVIEW: maybe ImpersonationException should inherit from win32exception
throw new ImpersonationException(win32ErrorNumber, new Win32Exception(win32ErrorNumber).Message,
credentials.Username, credentials.Domain);
}
if (!Advapi32.DuplicateToken(_tokenHandle, securityImpersonation, out _dupeTokenHandle))
{
var win32ErrorNumber = Marshal.GetLastWin32Error();
Kernel32.CloseHandle(_tokenHandle);
throw new ImpersonationException(win32ErrorNumber, "Unable to duplicate token!", credentials.Username,
credentials.Domain);
}
var newId = new WindowsIdentity(_dupeTokenHandle);
_impersonatedUser = newId.Impersonate();
}
public void Dispose()
{
if (_impersonatedUser != null)
{
_impersonatedUser.Undo();
_impersonatedUser = null;
if (_tokenHandle != IntPtr.Zero)
Kernel32.CloseHandle(_tokenHandle);
if (_dupeTokenHandle != IntPtr.Zero)
Kernel32.CloseHandle(_dupeTokenHandle);
}
}
}
internal static class Advapi32
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL,
out IntPtr DuplicateTokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
int dwLogonType, int dwLogonProvider, out IntPtr phToken);
}
internal static class Kernel32
{
[DllImport("kernel32.dll", SetLastError = true)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
}
I didn't include the implementation of ImpersonationException but it's not important. It doesn't do anything special.
You can also set the current principal directly if that's sufficient for your use case:
System.Threading.Thread.CurrentPrincipal
= new WindowsPrincipal(new WindowsIdentity("testuser#contoso.com"));
The principal is restored after each test method according to this connect page.
Note that this method won't work if used with web service clients that check the principal (for this use case, Jim Bolla's solution works just fine).
You should use Mock objects to simulate dependent objects in different states.
See moq for an example of a mocking framework:
You would need to abstract out the bit that provides the current user behind an interface. And pass in a mock of that interface to the class under test.
Use SimpleImpersonation.
Run Install-Package SimpleImpersonation to install the nuget package.
Then
var credentials = new UserCredentials(domain, username, password);
Impersonation.RunAsUser(credentials, LogonType.NewCredentials, () =>
{
// Body of the unit test case.
});
This is the most simple and elegant solution.
Another thing to add to Markus's solution, you may also need to set HttpContext.Current.User to the Thread.CurrentPrincipal you are creating/impersonating for certain calls to the RoleManager (eg: Roles.GetRolesForUser(Identity.Name) ) If you use the parameterless version of the method this is not needed but I have an authorization infrastructure in place that requires a username to be passed.
Calling that method signature with an impersonated Thread.CurrentPrincipal will fail with "Method is only supported if the user name parameter matches the user name in the current Windows Identity". As the message suggests, there is an internal check in the WindowsTokenRoleProvider code against "HttpContext.Current.Identity.Name". The method fails if they don't match.
Here's sample code for an ApiController demonstrating authorization of an Action. I use impersonation for unit and integration testing so I can QA under different AD Roles to ensure security is working before deployment.
using System.Web
List<string> WhoIsAuthorized = new List<string>() {"ADGroup", "AdUser", "etc"};
public class MyController : ApiController {
public MyController() {
#if TEST
var myPrincipal = new WindowsPrincipal(new WindowsIdentity("testuser#contoso.com"));
System.Threading.Thread.CurrentPrincipal = myPrincipal;
HttpContext.Current.User = myPrincipal;
#endif
}
public HttpResponseMessage MyAction() {
var userRoles = Roles.GetRolesForUser(User.Identity.Name);
bool isAuthorized = userRoles.Any(role => WhoIsAuthorized.Contains(role));
}
}
Hope this helps someone else :)

Programmatically Set Proxy Address, Port, Username, Password

Hi I need to set proxy address of IE programmatically
Earlier I used to use this RedTomahawk.TORActivator
but it doesnot gives an option to set those proxies which requires username and password.
How can we set those proxies which needs username and passwords
Please provide examples like
void Setproxy(string ip,string port,string uname,string pwd)
{
///Code here
}
You could P/Invoke the WinHttpSetDefaultProxyConfiguration function.
UPDATE:
Including example as requested:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WINHTTP_PROXY_INFO
{
public AccessType AccessType;
public string Proxy;
public string Bypass;
}
public enum AccessType
{
DefaultProxy = 0,
NamedProxy = 3,
NoProxy = 1
}
class Program
{
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool WinHttpSetDefaultProxyConfiguration(ref WINHTTP_PROXY_INFO config);
static void Main()
{
var config = new WINHTTP_PROXY_INFO();
config.AccessType = AccessType.NamedProxy;
config.Proxy = "http://proxy.yourcompany.com:8080";
config.Bypass = "intranet.com";
var result = WinHttpSetDefaultProxyConfiguration(ref config);
if (!result)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else
{
Console.WriteLine("Successfully modified proxy settings");
}
}
}

Categories

Resources