I am writing an ETW consumer to listen for ASP.NET events. I have the sample code below working nicely on a Windows 2008 server where it can see the ASP.NET provider. The problem that I am running into is that on my Win7 (64) PC, I do not see the ASP.NET provider so this code shows all the events as “unhandled”.
I have made sure the tracing feature is installed and the applicationhost.config file has the respective values in it.
When I do a logman –query providers, I do not see the
ASP.NET AFF081FE-0247-4275-9C4E-021F3DC1DA35 provider on the PC, but I see this on the Win2008 server that I am testing on.
How can I do one of the two items below:
Add this as a provider to my Win7 PC?
OR
Have the code able to handle this message and provide the manifest in my code. When I set “AFF081FE-0247-4275-9C4E-021F3DC1DA35” as a provider, I do get events but they are from unknown provider. So I am guessing the manifest content is missing.
My sample code is below
static void Test3()
{
var sessionName = "ASPNETMonitorSession";
using (var session = new TraceEventSession(sessionName, null))
{
Console.WriteLine("Starting Test1");
session.StopOnDispose = true;
Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
{
session.Dispose();
};
using (var source = new ETWTraceEventSource(sessionName, TraceEventSourceType.Session))
{
Action<TraceEvent> action = delegate(TraceEvent data)
{
Console.WriteLine("GOT EVENT: " + data.ToString());
};
var registeredParser = new RegisteredTraceEventParser(source);
registeredParser.All += action;
source.UnhandledEvents += delegate(TraceEvent data)
{
if ((int)data.ID != 0xFFFE)
Console.WriteLine("GOT UNHANDLED EVENT: " + data.Dump());
};
session.EnableProvider(new Guid("AFF081FE-0247-4275-9C4E-021F3DC1DA35"));
Console.WriteLine("Starting Listening for events");
source.Process();
}
}
Console.WriteLine("Done");
return;
}
The reason why ASP.NET tracing isn't available in your local machine is because it is not installed. If you look at the perfview help it gives you instructions as to how to enable it.
FYI perfview uses TracEevent to capture traces.
Here it is
ASP.NET Events
ASP.NET has a set of events that are sent when each
request is process. PerfView has a special view that you can open
when ASP.NET events are turned on. By default PerfView turns on
ASP.NET events, however, you must also have selected the 'Tracing'
option when ASP.NET was installed for these events to work. Thus if
you are not seeing ASP.NET events you are running an ASP.NET scenario
this is one likely reason why you are not getting data.
To turn on ASP.NET Tracing
The easiest way to turn on tracing is with the DISM tool that comes
with the operating system. Run the following command from an
elevated command prompt
DISM /online /Enable-Feature /FeatureName:IIS-HttpTracing
Note that this command will restart the web service (so that it takes effect),
which may cause complications if you ASP.NET service handles long
(many second) requests. This will either force DISM to delay (for a
reboot) or abort the outstanding requests. Thus you may wish to
schedule this with other server maintenance. Once this configuration
is done on a particular machine, it persists. You can also do
this configuration by hand using a GUI interface. You first need to
get to the dialog for configuring windows software. This differs
depending on whether you are on a Client or Server version of the
operating system.
On Client - Start -> Control Panel -> Programs -> Programs and
Features -> Turn Windows features on or off
-> Internet Information Services -> World Wide Web Services -> Health and Diagnostics -> Tracing On Server - Start -> Computer -> Right
Click -> Manage Roles -> Web Server (IIS) -> Roll Services Add Role
Services Health and Diagnostics -> Tracing
Hope this helps.
Related
I am working on an ERP asp.net mvc 5 web application deployed under iis7. And now I want to implement a new scanning service, which mainly uses powercli and power shell scripts, and scan our network for servers & vms and get their specifications and their statues.
So I am thinking of the following approach:-
1.Since the scanning should be access by only specific users and requires the hosting server to have powercli and other tools installed, so I want to create a new asp.net mvc 5 web application , and deploy it under iis7 instread of modifying my current ERP syste,. Where the new application will have the following action method which will do the scan as follow:-
public ActionResult ScanServer(string token)
{
// do the scan
//send n email with scanning result
}
2.Now inside my current ERP system I can manually initiating the scan by calling the above action method as follow:-
[HttpPost]
[CheckUserPermissions(Action = "", Model = "Admin")]
public ActionResult Scan()
{
try
{
string currentURL = System.Web.Configuration.WebConfigurationManager.AppSettings["scanningURL"];
using (WebClient wc = new WebClient())
{
string url = currentURL + "home/scanserver?token=*******" ;
var json = wc.DownloadString(url);
TempData["messagePartial"] = string.Format("Scan has been completed. Scan reported generated");
}
}
catch (WebException ex)
{
TempData["messageDangerPartial"] = string.Format("scanningservice can not be accessed");
}
catch (Exception e)
{
TempData["messageDangerPartial"] = string.Format("scan can not be completed");
}
Now I did a quick test where I manually started the scan from the ERP and the scanning service deployed under iis worked well.
But I have these questions:-
The scanning service might take 20-30 minutes to complete. So from an architecture point of view is my current approach considered valid ? I mean to initiate a scan by calling an action method from another application ?
Now can i inside the scanning service web application, to force it to call its action method on a timly basis (for example every 4 hours)?
Thanks
Your best option would be to write a windows service to install on the webserver alongside the web app. This windows service can use threads or a timer to execute a long running task (such as scanning your network) at a specified interval and send an email when finished.
You can talk to your service from the app using the database, a config file, or maybe even a registry entry.
If this will not work for you, you can look into some task scheduling apps such as Quartz.NET. If you do use a windows service, I recommend the excellent TopShelf which makes it easy to create and deploy. Here is a nice blog post I found by Scott Hanselman that may help.
Bellow is my code from asp.net service which is trying to run some external exe. It works fine from my Visual Studio on win 7, but fails on my server (server 2008).
Myapp.exe reports back eror that account under which is runned doesn't have sufficiet priviliges.
List<ProcInfo> allProcesses = new List<ProcInfo>();
ProcessStartInfo pInfo = new ProcessStartInfo();
pInfo.FileName = binPath + #"\myApp.exe";
pInfo.WindowStyle = ProcessWindowStyle.Hidden;
pInfo.CreateNoWindow = true;
pInfo.UseShellExecute = false;
pInfo.RedirectStandardOutput = true;
string exitMsg = "";
int exitCode = 1;
try
{
using (Process proc = Process.Start(pInfo))
{
exitMsg = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(1000);
exitCode = proc.ExitCode;
}
}
Resource pool on the server runs under account with sufficient priviliges and I also tried to use same account in code to start service with those same credentials and still nothing.
I have been told that account under which asp.net worker thread runs impose some additional limitations. So even if resource pool runs under appropriate account, you still won't have sufficient priviligies.
I also found something about using pInvoke and win32 api calls as the only way to run external code from asp.net service. But I don't have any win32 api knowlege nor did I found exples of this.
I would be very grateful for any tip/example how to run external exe under specified account from asp.net service.
If the account the worker process is runnning under lacks sufficient privelages then you have a few options.
You can either use impersonation in your code:
WindowsIdentity.Impersonate Method
Or configure IIS to run the application under a user account with the required privileges.
Here is an article which explains different methods of impersonation security:
Understanding ASP.NET Impersonation Security
If you do not feel confident implementing the user impersonation code yourself, here is a link to a codeproject article:
A small C# Class for impersonating a User
We have a web service running on the server. We want to use the service in local machine. Could some one kindly give all the steps to get the methods availble in the client.
We have created web methods in the server. And trying to access the same thing on the client. I can literally access those methods using the refernce variable of the server. but when I try to run it , it comes up with run time exception unable to connect to remote server.
I have added the web reference to my client class. What else I am missing. Do I need to do any kind of registration of service with client from command prompt.
I am assuming the client is unable to connect to server because the server is not running when I try to access the methods.
Any one with guidance will be helpful.
Thank you
Hari Gillala
I have added web refernce to this below client class using http://ipaddressofwerver/decisionclass/decisionclass.svc
The code:
try
{
DecisionClass ds = new DecisionClass();
string s = ds.Url;
Label1.Text = s;
string [] a = ds.GetList();
foreach (string i in a)
{
Response.Write(i);
}
}
catch (Exception Ex)
{
Response.Write(Ex.Message);
}
I am assuming the client is unable to connect to server because the server is not running when I try to access the methods.
If it's not running, it won't generate a WSDL either. However, it may have been running while you created the web reference, and then stopped.
Here are some things you can try to track down the problem:
Open the web service's URL, as specified in the web reference, in a regular web browser. This should bring up the web service's documentation page, and if you're running locally and haven't changed the web service's web.config, you can even call some simple methods using the provided test forms
See if you can access the web service with SoapUI or a similar tool.
Also, make sure you're running the web service in IIS, not in the Visual Studio development server - IIS will keep running when you close the project or even Visual Studio, but the development server might not.
I have a classic ASP page - written in JScript - that's using Scripting.FileSystemObject to save files to a network share - and it's not working. ("Permission denied")
The ASP page is running under IIS using Windows authentication, with impersonation enabled.
If I run the following block of code locally via CScript.exe:
var objNet = new ActiveXObject("WScript.Network");
WScript.Echo(objNet.ComputerName);
WScript.Echo(objNet.UserName);
WScript.Echo(objNet.UserDomain);
var fso = new ActiveXObject("Scripting.FileSystemObject");
var path = "\\\\myserver\\my_share\\some_path";
if (fso.FolderExists(path)) {
WScript.Echo("Yes");
} else {
WScript.Echo("No");
}
I get the (expected) output:
MY_COMPUTER
dylan.beattie
MYDOMAIN
Yes
If I run the same code as part of a .ASP page, substituting Response.Write for WScript.Echo I get this output:
MY_COMPUTER
dylan.beattie
MYDOMAIN
No
Now - my understanding is that the WScript.Network object will retrieve the current security credentials of the thread that's actually running the code. If this is correct - then why is the same user, on the same domain, getting different results from CScript.exe vs ASP? If my ASP code is running as dylan.beattie, then why can't I see the network share? And if it's not running as dylan.beattie, why does WScript.Network think it is?
Your problem is clear. In the current implementation you have only impersonation of users and no delegation. I don't want to repeat information already written by Stephen Martin. I only want to add at least three solutions. The classical way of delegation which Stephen Martin suggests is only one way. You can read some more ways here: http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation. I see three practical ways of you solving your problem:
Convert the impersonation token of the user to a token with delegation level of impersonation or to a new primary token. You can do this with respect of DuplicateToken or DuplicateTokenEx.
Use S4U2Self (see http://msdn.microsoft.com/en-us/magazine/cc188757.aspx and http://msdn.microsoft.com/en-us/library/ms998355.aspx) to receive a new token from the old one with respect of one simple .NET statement WindowsIdentity wi = new WindowsIdentity(identity);
You can access another server with respect of one fixed account. It can be a computer account on an account of the application pool of the IIS. It can be another fixed defined account which one will only use for access to the file system.
It is important to know which version of Windows Server you have on the server where IIS is running and which Domain Function Level you have in Active Directory for your Domain (you see this in "Active Directory Domain and Trusts" tool if you select your domain and choose "Raise Domain Functional Level"). It is also interesting to know under which account the application pool of the IIS runs.
The first and the third way will always work. The third way can be bad for your environment and for the current permission in the file system. The second one is very elegant. It allows control of which servers (file server) are accessed from IIS. This way has some restrictions and it needs some work to be done in Active Directory.
Because you use classic ASP, a small scriptable software component must be created to support your implementation.
Which way do you prefer?
UPDATED based on the question from comment: Because you use classic ASP you can not use a Win32 API directly, but you can write a small COM component in VB6 or in .NET which use APIs which you need. As an example you can use code from http://support.microsoft.com/kb/248187/en. But you should do some other things inside. So I explain now which Win32 API can help you to do everything what you need with tokens and impersonation.
First of all a small explanation about impersonation. Everything works very easy. There are always one primary token under which the process runs. To any thread another token (thread token) can be assigned. To do this one needs to have a token of a user hUserToken and call API ImpersonateLoggedOnUser(hUserToken);.
To go back to the original process token (for the current thread only) you can call RevertToSelf() function. The token of user will be received and already impersonated for you by IIS, because you so configured your Web Site. To go back to the original process token you should implement calling of the function RevertToSelf() in your custom COM component. Probably, if you need to do nothing more in the ASP page, it will be enough, but I recommend you be more careful and save current users token in a variable before operation with files. Then you make all operations with file system and at the end reassign users token back to the current thread. You can assign an impersonation token to a thread with respect of SetThreadToken(NULL,hUserToken);. To give (save) current thread token (user token in your case) you can use OpenThreadToken API. It must work.
UPDATED 2: Probably the usage of RevertToSelf() function at the end of one ASP page would be already OK for you. The corresponding C# code can be so:
Create a new Project in C# of the type "Class Library" with the name LoginAdmin. Paste the following code inside
using System;
using System.Runtime.InteropServices;
namespace LoginAdmin {
[InterfaceTypeAttribute (ComInterfaceType.InterfaceIsDual)]
public interface IUserImpersonate {
[DispId(1)]
bool RevertToSelf ();
}
internal static class NativeMethods {
[DllImport ("advapi32.dll", SetLastError = true)]
internal static extern bool RevertToSelf ();
}
[ClassInterface (ClassInterfaceType.AutoDual)]
public class UserImpersonate : IUserImpersonate {
public UserImpersonate () { }
public bool RevertToSelf () {
return NativeMethods.RevertToSelf();
}
}
}
Check in project properties in "Build" part "Register for COM interop". In "Signing" part of the project check Sign the assembly and in "Choose a strong name key file" choose <New...>, then type any filename and password (or check off "protect my key..."). At the end you should modify a line from AssemblyInfo.cs in Properties part of the project:
[assembly: ComVisible (true)]
After compiling this project you get two files, LoginAdmin.dll and LoginAdmin.tlb. The DLL is already registered on the current computer. To register if on the other computer use RegAsm.exe.
To test this COM DLL on a ASP page you can do following
<%# Language="javascript" %>
<html><body>
<% var objNet = Server.CreateObject("WScript.Network");
Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");
var objLoginAdmin = Server.CreateObject("LoginAdmin.UserImpersonate");
var isOK = objLoginAdmin.RevertToSelf();
if (isOK)
Response.Write("RevertToSelf return true<br/>");
else
Response.Write("RevertToSelf return false<br/>");
Response.Write("One more time after RevertToSelf()<br/>");
Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");
var fso = Server.CreateObject("Scripting.FileSystemObject");
var path = "\\\\mk01\\C\\Oleg";
if (fso.FolderExists(path)) {
Response.Write("Yes");
} else {
Response.Write("No");
}%>
</body></html>
If the account used to run the IIS application pool has access to the corresponding network share, the output will be look like following
Current user: Oleg
Current user's domain: WORKGROUP
RevertToSelf return true
One more time after RevertToSelf()
Current user: DefaultAppPool
Current user's domain: WORKGROUP
Yes
Under impersonation you can only access securable resources on the local computer you cannot access anything over the network.
On Windows when you are running as an impersonated user you are running under what is called a Network token. This token has the user's credentials for local computer access but has no credentials for remote access. So when you access the network share you are actually accessing it as the Anonymous user.
When you are running a process on your desktop (like CScript.exe) then you are running under an Interactive User token. This token has full credentials for both local and remote access, so you are able to access the network share.
In order to access remote resources while impersonating a Windows user you must use Delegation rather then Impersonation. This will involve some changes to your Active directory to allow delegation for the computer and/or the users in your domain. This can be a security risk so it should be reviewed carefully.
I have a bit of code in an internal ASP.net application that we use to start automatic services should they be stopped on the server that the web app is running on. The only problem is that it doesn't seem to start the service when its run on the server. It does so fine when its run on my desktop locally though so I'm guessing I have to give certain security settings to the the ASP.net user?
Here's my code:
protected void StartService(object sender, EventArgs e)
{
LinkButton serviceButton = (LinkButton)sender;
string name = serviceButton.ID;
ManagementPath path = new ManagementPath();
path.Server = System.Environment.MachineName;
path.NamespacePath = #"root\CIMV2";
path.RelativePath = "Win32_service.Name='" + name + "'";
ManagementObject service = new ManagementObject(path);
ManagementBaseObject temp = service.InvokeMethod("StartService", null, null);
Thread.Sleep(100);
GetStoppedServices();
}
Anyone have any ideas on how to get this to work?
Edit: For clarification the web app is run on the same server as the server that I want to start services on.
Edit 2: Had a brainwave and tried to use this code instead.. no dice.
ProcessInfo = new ProcessStartInfo("cmd.exe", "/C net start " + name);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
Process.Close();
Rather than using the System.Management objects for controlling services, look into the ServiceController class. All the methods for start/stop/pause are available and in a much more structured manner.
You may still encounter permission issues, though. The executing account for your web app will require permissions to control the target service you wish to affect.
Depending on your platform (which version of Win Serv), different accounts will execute for anonymous requests for your web application. Verify which accounts come into play (or if you have authenticated requests, you know your user) and determine their privileges against your Windows service.
Could be an access rights issue. When you run the application locally (through Visual Studio and the built-in Cassini web server) I think you're running it as yourself, so it makes sense that it would work.
When you run the application through IIS (on the server), its running as whatever user is specified in the application pool. (I think its "Network Service" by default). Check which user it is in IIS and try giving that user permission to start your service.
What version of IIS are you running? If its a Win 2K3 server, I'm guessing 6.0.
Information on configuring the application pool:
IIS 7.0
IIS 6.0
EDIT: You can use SubInACL.exe (a microsoft tool) to configure service permissions:
So let's say you have user "Johnny" and you want Johnny to be able to stop and start the World Wide Web Publishing service. Simply run the following subinacl.exe command:
subinacl /service W3SVC /GRANT=YOURDOMAIN\Johnny=TO
Obviously you will want to replace YOURDOMAIN with the name of your domain. The TO at the end are the identifiers that tell subinacl which actions you actually want grant to Johnny. T is used for "Start Service" and O is for "Stop Service".
For more information, check out Ingmar's blog post about it.
For Windows 7, Windows Server 2008, Windows Server 2008 R2, Windows Vista
Open IIS Manager.(From start->run-> type inetmgr and press enter)
In the Connections pane, expand the server node and click Application Pools.
On the Application Pools page, select the application pool for which you want to specify an identity, and then click Advanced Settings in the Actions pane.
For the Identity property, click the ... button to open the Application Pool Identity dialog box.
If you want to use a built-in account, select the Built-in account option and select an account from the list. Select Local System from the list
If you want to use a custom identity, select the Custom account option and click Set to open the Set Credentials dialog box. Then type the custom account name in the User name text box, type a password in the Password text box, retype the password in the Confirm password text box, and then click OK.
Click OK to dismiss the Application Pool Identity dialog box.
Right click on the application pull and then stop and again click on start