I am having problems trying to read a file that is stored on a network drive when hosting my website/request on a azure website.
The code works testing on a local machine and it also works on a Dedicated server that we have with another client and have full control of but it gets the following error when we try to read the file.
Access to the path '\xxx.xxx.xxx.xxx\abc\abc.xml' is denied.
I wanted to know if Azure was locked down to prevent this behaviour that I didn't know about. Maybe ports closed or something.
The code I am using
if (impersonate.impersonateValidUser("username", "domain.com", "password"))
{
message = "impersonate ok";
if (!System.IO.File.Exists(file))
{
message = "no file";
impersonate.undoImpersonation();
}
using (StreamReader reader = File.OpenText(file))
{
message = "";
XmlSerializer deserializer = new XmlSerializer(typeof(TextModeSchema));
schema = (TextModeSchema)deserializer.Deserialize(reader);
reader.Close();
}
}
which is using a basic Impersonate class that we use in alot of places
public class Impersonate : IDisposable
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_LOGON_NETWORK = 3;
public const int LOGON32_LOGON_BATCH = 4;
public const int LOGON32_LOGON_SERVICE = 5;
public const int LOGON32_LOGON_UNLOCK = 7;
public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
public const int LOGON32_PROVIDER_DEFAULT =0;
public const int LOGON32_PROVIDER_WINNT35 =1;
public const int LOGON32_PROVIDER_WINNT40 =2;
public const int LOGON32_PROVIDER_WINNT50 = 3;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public bool impersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
public void undoImpersonation()
{
impersonationContext.Undo();
}
public void Dispose()
{
impersonationContext.Undo();
GC.Collect();
}
}
If this is not allowed on azure, does anyone know of a way we can get around it without having to set up a full Virtual machine? I would like to keep with a azure website/webapp ideally.
Is this on a web role, worker role or a web application? I know that in case of a role, the remote host in your scenario has to be on the same private network than you role (It may also be true for a web app). Also, we had a similar scenario where we decided to use Azure Files which allows mounting shares on a role which you might want to try. http://blogs.msdn.com/b/windowsazurestorage/archive/2014/05/12/introducing-microsoft-azure-file-service.aspx
Related
I am currently doing some maintenance on a C# CodedUITest. It is testing the frontend on our software which is installed in validated mode (=> which means it can only be used by the "ProtectedUser" User and Administrators).
The problem is that we obviously want to perform some clicks on the interface but we are using our "TestAgent" User who doesn't have the rights to interact with the software's interface. Instead we want to Impersonate the "ProtectedUser" User when interacting with the interface.
At some point the following code is used:
using (new TestUtils.Tools.Impersonator(".", "ProtectedUser", "password"))
{
Microsoft.VisualStudio.TestTools.UITesting.Mouse.StartDragging(SoftwareBrowserSlider);
Microsoft.VisualStudio.TestTools.UITesting.Mouse.StopDragging(SoftwareBrowserTreeView, x, y);
}
My problem is that I can't seem to get the impersonation to work to do frontend interactions such as mouse clicks or drags. But the Impersonator class works just fine when copying or deleting files. Does anyone know if it is even possible to Impersonate another local user and then perform a click or a drag as the said user?
Here is my Impersonator class:
public class Impersonator : IDisposable
{
public bool isImpersonating { get; private set; }
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
#region DllImports
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
#endregion
public Impersonator(string domainName = ".",
string userName = "ProtectedUser",
string password = "password")
{
ImpersonateValidUser(domainName, userName, password);
}
public void Dispose()
{
UndoImpersonation();
}
private void ImpersonateValidUser(string domain, string userName, string password)
{
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if(!RevertToSelf())
{
ThrowLastWin32Exception();
}
if(LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) == 0)
{
ThrowLastWin32Exception();
}
if (DuplicateToken(token, 2, ref tokenDuplicate) == 0)
{
ThrowLastWin32Exception();
}
isImpersonating = ImpersonateLoggedOnUser(tokenDuplicate);
}
finally
{
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
}
}
private void ThrowLastWin32Exception()
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
private void UndoImpersonation()
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
}
I've created a window service application where it read files from other networks then save it to my database every 1 minute. I have been provided a username and password to access the file from the other network. Unfortunately, I don't know how to how to access the file with network username and. password Can you show me how. Thank you.
I know how to provide the path of the file from app.config
appSettings
add key="filepath" value="\111.111.1.11\dummyfolder\"
And access it to my code by this:
string path = ConfigurationManager.AppSettings["filepath"].ToString();
What can be easier?
class AuthHelper
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public static WindowsIdentity GetWindowsIdentityForUser(String userName, String password, String domain)
{
WindowsIdentity result = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0)
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
result = new WindowsIdentity(tokenDuplicate);
if (result != null) return result;
}
if (token != IntPtr.Zero) CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero) CloseHandle(tokenDuplicate);
return result;
}
}
And then just:
var identity = AuthHelper.GetWindowsIdentityForUser("other user", "password", "domain");
using (var context = identity.Impersonate())
{
//do whatever you want as "other user"
}
When I use WindowsIdentity Impersonation like this:
WindowsIdentity newId = null;
WindowsImpersonationContext impersonatedUser = null;
Console.WriteLine("Name of the identity BEFORE impersonation: "
+ WindowsIdentity.GetCurrent().Name + ".");
newId = new WindowsIdentity(_impersonationToken);
impersonatedUser = newId.Impersonate();
Console.WriteLine("Name of the identity AFTER impersonation: "
+ WindowsIdentity.GetCurrent().Name + ".");
(It's being used to copy files from my computer to a winCE machine.)
The Name Before and the Name after keep returning the same.
When I look # the newId Token after the impersonation it isn't the same as the one I use to Impersonate with.
The Token I impersonate with is DEFINITELY not the same user as the one I'm logged in with.
Does anyone have any suggestions on why it does not want to use my token?
(ow yeah, Yesterday It worked like a charm :s)
This is how I generate my token:
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
LogonUser(Username, IPMachine, Password,
LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT,
ref _token);
It give a successfull bool, so there is nothing wrong with my token i think
Here is another good example which you can try
How do you generate your _impersonationToken?
There's an excellent solution regarding impersonation over at CodeProject. Looking at that may give you some new ideas.
I get this working:
/// <summary>
/// Summary description for Impersonate
/// </summary>
public class Impersonate
{
#region "Class Members"
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext _impersonationContext;
#endregion
#region "Class Properties"
private string domainName { get; set; }
private string userName { get; set; }
private string userPassword { get; set; }
#endregion
public Impersonate(string domainName, string userName, string userPassword)
{
this.domainName = domainName;
this.userName = userName;
this.userPassword = userPassword;
}
#region "Impersonation Code"
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public bool ImpersonateValidUser()
{
var token = IntPtr.Zero;
var tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(this.userName, this.domainName, this.userPassword, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
_impersonationContext = tempWindowsIdentity.Impersonate();
if (_impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
public void UndoImpersonation()
{
_impersonationContext.Undo();
}
#endregion
}
You can call it:
var impessonate = new Impersonate(".", "User", "Psw");
if (impessonate.ImpersonateValidUser())
{
// do stuff
impessonate.UndoImpersonation();
}
We are developing a web application that uses forms authentication and the ActiveDirectoryMembershipProvider to authenticate users against the Active Directory. We soon found out that the provider does not allow a blank/empty password to be specified, even though this is perfectly legal in the Active Directory (provided a preventative password policy is not in place).
Courtesy of reflector:
private void CheckPassword(string password, int maxSize, string paramName)
{
if (password == null)
{
throw new ArgumentNullException(paramName);
}
if (password.Trim().Length < 1)
{
throw new ArgumentException(SR.GetString("Parameter_can_not_be_empty", new object[] { paramName }), paramName);
}
if ((maxSize > 0) && (password.Length > maxSize))
{
throw new ArgumentException(SR.GetString("Parameter_too_long", new object[] { paramName, maxSize.ToString(CultureInfo.InvariantCulture) }), paramName);
}
}
Short of writing our own custom Provider, is there any way to override this functionality using the magic of .NET?
I don't beleive you could change this behaviour without creating a derived class and overiding every method that calls the private CheckPassword method. I would not recomend this option however, i would recomend that you review your design and question whether it is approriate to allow blank passwords in your application. Whilst they are valid in AD it is unusual for this to be allowed in practice and it does impact other things in a windows network, e.g. i think the default settings for network file shares disallow any user with a blank password from connecting to the share.
You could perhaps look at using impersonation but i don't know if you will have the same issue. If it's to authorise a user, then you could use impersonation to try and "impersonate" the user on the machine. I don't know if it helps but I was doing something similar to this the other week. Have put the code below if any of this helps.. :)
using System;
using System.Runtime.InteropServices;
public partial class Test_Index : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{
IntPtr ptr = IntPtr.Zero;
if (LogonUser("USERNAME", "", "LEAVE-THIS-BLANK", LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, ref ptr))
{
using (System.Security.Principal.WindowsImpersonationContext context = new System.Security.Principal.WindowsIdentity(ptr).Impersonate())
{
try
{
// Do do something
}
catch (UnauthorizedAccessException ex)
{
// failed to do something
}
// un-impersonate user out
context.Undo();
}
}
else
{
Response.Write("login fail");
}
}
#region imports
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr existingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr duplicateTokenHandle);
#endregion
#region logon consts
// logon types
const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
// logon providers
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_PROVIDER_WINNT50 = 3;
const int LOGON32_PROVIDER_WINNT40 = 2;
const int LOGON32_PROVIDER_WINNT35 = 1;
#endregion }
I have a C# console application that needs to read a shared file on a machine in another domain.
When the application tries to access the file an exception occurs as the local user does not have permission to access the shared resource.
Currently I overcome this problem manually by open the shared folder from the run and put the username and password into the windows authentication dialog then run the application.
How can I do it programmatically?
a) p/invoke LogonUser with LOGON32_LOGON_NEW_CREDENTIALS and create a new WindowsIdentity with the new token, then use normal file access.
b) p/invoke WNetAddConnection3. Be advised that this makes your remote share accessible to every other process on your machine.
c) WMI via System.Management and CIM_DataFile; you won't even need p/invoke. System.Management lets you specify credentials for remote machine.
I used the point "a" as Anton suggested, I developed two versions for one class, the first one using the Win32 APIs, and the second uses the WindowsIdentity class.
Version 1:
class UserImpersonation : IDisposable
{
[DllImport("advapi32.dll")]
public static extern int LogonUser(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
WindowsImpersonationContext wic;
string _userName;
string _domain;
string _passWord;
public UserImpersonation(string userName, string domain, string passWord)
{
_userName = userName;
_domain = domain;
_passWord = passWord;
}
public bool ImpersonateValidUser()
{
WindowsIdentity wi;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUser(_userName, _domain, _passWord, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
wi = new WindowsIdentity(tokenDuplicate);
wic = wi.Impersonate();
if (wic != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
return false;
}
#region IDisposable Members
public void Dispose()
{
if (wic != null)
{
wic.Dispose();
}
RevertToSelf();
}
#endregion
}
Version2 (from MSDN with small changes):
class UserImpersonation2 : IDisposable
{
[DllImport("advapi32.dll")]
public static extern bool LogonUser(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
WindowsImpersonationContext wic;
IntPtr tokenHandle;
string _userName;
string _domain;
string _passWord;
public UserImpersonation2(string userName, string domain, string passWord)
{
_userName = userName;
_domain = domain;
_passWord = passWord;
}
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
public bool ImpersonateValidUser()
{
bool returnValue = LogonUser(_userName, _domain, _passWord,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
Console.WriteLine("LogonUser called.");
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine("LogonUser failed with error code : {0}", ret);
return false;
}
Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
Console.WriteLine("Value of Windows NT token: " + tokenHandle);
// Check the identity.
Console.WriteLine("Before impersonation: "
+ WindowsIdentity.GetCurrent().Name);
// Use the token handle returned by LogonUser.
WindowsIdentity newId = new WindowsIdentity(tokenHandle);
wic = newId.Impersonate();
// Check the identity.
Console.WriteLine("After impersonation: "
+ WindowsIdentity.GetCurrent().Name);
return true;
}
#region IDisposable Members
public void Dispose()
{
if(wic!=null)
{
wic.Undo();
}
if (tokenHandle != IntPtr.Zero)
{
CloseHandle(tokenHandle);
}
}
#endregion
}
How to use (both are the same):
const string file = #"\\machine\test\file.txt";
using (UserImpersonation user = new UserImpersonation("user", "domain", "password"))
{
if (user.ImpersonateValidUser())
{
StreamReader reader = new StreamReader(file);
Console.WriteLine(reader.ReadToEnd());
reader.Close();
}
}
From memory you'll need to use a Windows API call and login as a user on the other domain. See this link for an example.
Another idea could be to use the RunAs command line argument to read the file and save it into a file on your local domain/server.