Some Details
I am working with VisualWebGUI, so this app is like ASP.NET, and it is deployed on IIS 7 (for testing)
For my 'Web Site', Anonymous Authentication is set to a specific user (DomainName\DomainUser). In my web.config, I have impersonation on. This is how I got my app to access the share in the first place.
The Problem
There is a point in the the app where we use the Thread class, something similar to:
Thread myThread = new Thread(new ThreadStart(objInstance.PublicMethod));
myThread.Start();
What I have noticed is that I can write to my logs (text file on the share), everywhere throughout my code, except in the thread that I kicked off. I added some debugging output and what I see for users is:
The thread that's kicked off: NT AUTHORITY\NETWORK SERVICE
Everywhere else in my code: DomainName\DomainUser (described in my IIS setup)
OK, for some reason the thread gets a different user (NETWORK SERVICE). Fine. But, my share (and the actual log file) was given 'Full Control' to the NETWORK SERVICE user (this share resides on a different server than the one that my app is running).
If NETWORK SERVICE has rights to this folder, why do I get access denied? Or is there a way to have the thread I kick off have the same user as the process?
You can also get the new thread to impersonate the user that issued the request. For example, if you are starting your request in the Page.Load event it might look like this.
public partial class MyPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Thread myThread = new Thread(new ParameterizedThreadStart(ThreadMethod));
myThread.Start(HttpContext.Current.User);
}
private void ThreadMethod(object state)
{
WindowsPrincipal principal = state as WindowsPrincipal;
WindowsImpersonationContext impersonationContext = null;
try
{
if (principal != null)
{
Thread.CurrentPrincipal = principal;
impersonationContext = WindowsIdentity.Impersonate(((WindowsIdentity)principal.Identity).Token);
}
// Do your user specific stuff here...
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
}
}
You will notice I passed the Principal from the ASP.NET thread through to the new thread, I obviously assume that you are using Windows Integrated Authentication so I did not do much in the way of error checking, this is just a quick sample.
Note: For VWG you would get the user from the VWG context and run the impersonation code in the appropriate function, this example is ASP.NET jsut because the environment is the same, just I do not know the VWG objects off the top of my head.
NT AUTHORITY\NETWORK SERVICE is a local computer account. To the remote server it looks like your IIS computer's Active Directory account (COMPUTERNAME$). You need to grant access to the log directory to the AD Computer Account of your IIS box.
HTH
Related
I am not able to detect this Logon event in Windows.
Here is my code:
namespace ConsoleApplication2
{
public class MyService: ServiceBase
{
public MyService()
{
CanPauseAndContinue = true;
CanHandleSessionChangeEvent = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
}
}
class Program
{
static void Main(string[] args)
{
MyService tpl = new MyService();
Thread t = new Thread(delegate()
{
while (true) { }
});
t.Start();
}
}
}
How do I test run this app and then remote desktop into my laptop? I can see the event generated in Windows EventViewer, but my OnSessionChange is never called (I added a breakpoint inside).
Is my code wrong or is the way I am testing wrong?
Normally multiple concurrent remote desktop sessions are not allowed on any of Windows desktop systems. So to use RDP to login as a different user then I assume that you have hacked this, or are using windows server (which rules out XP!).
Regardless, each user logged into the system will therefore have their own applications running and each set of applications are unique to that user. So App1 could be run independently by each user.
That means that your console application cannot detect the other user that is logged on.
To do this you must use a Windows Service. This runs in the background and can detect and work for multiple users and also detect login and logout. See this SO link
This is the purpose of inheriting MyService from ServiceBase. If you are not running the application as a service, then you are not running it correctly!
You need to first install your application as a service and then run it like a service.
You say that you don't think your application can run as a service. I'm not sure why, but if this is the case then you would have to instead look at creating some kind of script to run your application upon start-up/login.
This way, every time somebody logs in then your application would run. This might anyway be simpler for you.
I got the UnknownErrorException with error code 1346 for named pipe, the code as below
(notes: the client and server are in different machines)
server code:
public static void ReadFile()
{
string contents = File.ReadAllText(#"d:\123.txt"); <-- exception
}
public static void Main()
{
var pipe = new NamedPipeServerStream("testpipe", PipeDirection.InOut);
while (true)
{
pipe.WaitForConnection();
pipe.RunAsClient(ReadFile);
}
}
client code
NamedPipeClientStream pipeClient =
new NamedPipeClientStream("\\jachang-w1", "testpipe",
PipeDirection.InOut, PipeOptions.None,
TokenImpersonationLevel.Impersonation);
pipeClient.Connect();
I have search the info from google, and found the error is "ERROR_BAD_IMPERSONATION_LEVEL, Either a required impersonation level was not provided, or the provided impersonation level is invalid"
but I have set TokenImpersonationLevel.Impersonation in the client, so server should be able access it. could someone tell me what wrong it is? and how should I do?
Thanks
In order for the server process to impersonate the client with the token impersonation level Impersonate, its own process identity must have the security privilege SeImpersonatePrivilege, and this privilege must be enabled.
This is true even if the client and server account identities are the same domain account.
I guess that the domain account you are testing with does not have this privilege, or does not have it enabled. When you call RunAsClient, a thread token will be created, but this will not be granted the requested impersonation level because the process lacks the required privilege: the level will 'downgrade' to Identification. Then, when the call to ReadAllText is made, somewhere within the implementation of this method the Windows security APIs will be used to check the thread token against the file's access control list. The token will be found not to have the required impersonation level to succeed in reading the file, and the error you have seen will be raised.
To solve the problem you will have to find some way of ensuring that your server process runs with an identity which has the required privilege.
i' m developing webapp in ASP.NET 2.0 (C#). I've problem to resolve issue.
The application should show users on-line, and only for administrator should show the user name. I'm using Application[] object to store usermame and count, setting the value in Globall.asax file.
In the following code i'll show the section relative to counter:
protected void Application_Start(object sender, EventArgs e){
Application["OnlineCounter"] = 0;
}
protected void Session_Start(Object sender, EventArgs e){
// Code that runs when a new session is started
if (Application["OnlineCounter"] != null){
Application.Lock();
Application["OnlineCounter"] = ((int)Application["OnlineCounter"]) + 1;
Application.UnLock();
}
}
protected void Session_End(Object sender, EventArgs e){
// Code that runs when a new session is started
if (Application["OnlineCounter"] != null){
Application.Lock();
Application["OnlineCounter"] = ((int)Application["OnlineCounter"]) - 1;
Application.UnLock();
}
}
Using this code on my local machine i can count correctly the online user.
Instead, when i publish this code on server (Windows 2003 Server and IIS6) i found the following problem:
accessing from my machine with 3 different user (using different browser), i will see only 1 user in a single page (In each browser i see only 1 online user) !
There are some issue for this ? Any suggestion is appreciated.
Thanx
You can use a performance counter to get that number.
Here you have the list of performance counters for ASP.NET. Look for the description of "Sessions Active" under "ASP.NET Application Performance Counters".
Then you can use PerformanceCounter class to get the value of that performance counter for you application.
The problem is that this requires privileges:
To read performance counters in Windows Vista, Windows XP Professional x64 Edition, or Windows Server 2003, you must either be a member of the Performance Monitor Users group or have administrative privileges.
One way to do this would be to impersonate a part of your application to be run by a user with those privileges. It could be an .asmx web service, or the web forms itself which will show the required info. You can impersonate only that service using location and identity impersonate in web.config. Set up a user with the needed privileges and impersonate that user.
Is the server configured to use multiple worker processes per application pool?
ASP.NET State Management Recommendations: http://msdn.microsoft.com/en-us/library/z1hkazw7.aspx
Application scope: The scope of application state can also be a
disadvantage. Variables stored in application state are global only to
the particular process the application is running in, and each
application process can have different values. Therefore, you cannot
rely on application state to store unique values or update global
counters in Web-garden and Web-farm server configurations.
Configuring Web Gardens with IIS 6.0: https://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/659f2e2c-a58b-4770-833b-df96cabe569e.mspx?mfr=true
I have the following code snippet to test a plain-text username/password against the AD, which works fine if I hit F5 in visual studio and try it via the WCFTestClient, but once I deploy to IIS and try the same function, it will never return true for ValidCredentials; is there something security wise that needs to be set for the Identity that the Application Pool runs under?
I tried setting the App Pool identity to my own account (domain admin) just to test if this was the problem, but that didn't help either, so I'm a bit lost as to how to fix this.
The site (Custom API) has anonymous access set up.
try
{
// create a "principal context" - e.g. your domain (could be machine, too)
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, DomainName))
{
// validate the credentials
if (pc.ValidateCredentials(UserName, Password))
{
IsValid = true;
break;
}
}
}
catch (Exception)
{
LoggingControler.LogWarning(null, "Unreachable Domain: " + Domain);
}
I've gone over things again, and it's all due to Rights in Windows. Network Service somehow doesn't have enough rights to execute PrincipalContext.ValidateCredentials. If I change the Application Pool Identity to the identity of a Domain Administrator, the code works.
If someone can tell me how to set up a Limited User account with the proper rights to execute PrincipalContext.ValidateCredentials, I can finish this.
Ok, I've finally found my own answer via https://stackoverflow.com/questions/5140377/query-activedirectory-sometimes-not-working-asp-net-c and https://elgg.leeds.ac.uk/webteam/weblog/15385.html
As I've discovered, "Network Service" application pool identity holds the key to this problem...
Adding the read rights didn't work; so there's still something else wrong.
Did you enable Windows Authentication in IIS
I am calling the SQL Server Reporting Services Webservice from inside an asp.net application. I need to fire off all the subscriptions for a given report. But I don't want the user to have to wait around for it to all happen, so I want to have all the webservice calls inside a separate thread, and return to the user straight away.
I am using code that looks something like this:
public static void FireAllAsync(string ReportPath)
{
Hashtable paramValues = new Hashtable();
ThreadPool.QueueUserWorkItem(new WaitCallback(FireAll), ReportPath);
}
public static void FireAll(object ReportPath)
{
ReportingService rs = new ReportingService();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
Subscription[] SubList = rs.ListSubscriptions((string)ReportPath, null);
foreach (Subscription CurSub in SubList) {
rs.FireEvent(CurSub.EventType, CurSub.SubscriptionID);
}
}
Calling FireAll works fine, but trying to call FireAllAsync to use the Thread fails with a 401 error. I believe the problem with the credentials not getting passed through properly. ie this line of code here:
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
I do not have a good understanding of how the credentials cache works, so I can't figure out why it doesn't like being in a separate thread.
I have tried grabbing the credentials in the outer function, and passing them through as an argument, but the same error occurs.
Does anyone have any ideas what may be happening?
When your primary thread is executing, it has an impersonation context prepared for it. In an authenticated scenario, IIS has authenticated the user, and then set the thread token - not the process token - for that user.
Because the thread token is set for the user, that thread can then act on behalf of the user (on the local box; acting on behalf of the user on another box requires delegation to be set up if Integrated Windows Authentication (NTLM/Kerberos) is used).
But, if you spin off a worker thread without any identity information, that worker thread will be spawned without its own token, so it'll use the process token.
If you can do what you need to do on the initial thread, you don't have a delegation problem, just a lack of the user token on the worker thread.
Threadpool threads will run as the process identity (NetworkService by default, so the computer account of the hosting machine, unless your App Pool is set to run as SomeUser, in which case all worker threads will run as SomeUser) - and if that user has access to whatever it is the initial user wants, all is good.
If not, 401sville.
There are web references that can help work around this, with various possible answers:
Link
http://aspalliance.com/articleViewer.aspx?aId=650&pId=2