Network Connected Printer not available in ASP.Net Application - asp.net

I have an ASP.Net 4.0 web application running on IIS 7.5, I can get the list of installed printers using System.Drawing.Printing.PrinterSettings.InstalledPrinters command and assign each report in the application to any printer listed above!
There might be some Network Connected Printers on the server all set with full privilege to the application's user account, everything works perfect until the application's user account logs off the windows, at this point System.Drawing.Printing.PrinterSettings.InstalledPrinters returns only local printers, no Network Connected Printers are listed!
I've tried to impersonate the ASP.Net process to the user with access to Network Printers in following ways, yet no success:
I configured the application pool Process Model to run as a
specific user identity.
I impersonated the Application's identity to specific user in
Web.Config:
<identity impersonate="true" userName="user" password="pass"/>
And finally implemented impersonation in code using advapi32.dll API
In all of the methods above, the WindowsIdentity returns the true username when printing:
System.Security.Principal.WindowsIdentity.GetCurrent().Name
But it looks like that impersonation is not the issue here, the moment the user logs off, all Network Connected Printers are gone!
Does anybody know how to resolve this? Is there any way to access Network Connected Printers even when the user is not logged in?

Network Connected Printers, Shared Folders and Map Drives are only accessible when user logs into the OS, they are barely a shortcut to some network resources, all disconnected and are inaccessible when the corresponding user logs off!
Using System.Printing.PrintServer and the GetPrintQueues method, you can get the collection of print queues that the print server hosts:
PrintServerUNCName is the UNC name of the corresponding server, as in \\MyServerName
var printers = new PrintServer("PrintServerUNCName").GetPrintQueues()
.Where(t =>
{
try { return t.IsShared && !t.IsNotAvailable; }
catch { return false; }
})
.Select(t => t.FullName)
.ToArray();

try following links that might help. You have to add printer on your server by name and access the printer using the name rather UNC.
Printing from ASP.NET to a network printer

Related

The remote server returned an error: (401) Unauthorized. Using CSOM in ASP.NET

I'm tried to pull some SharePoint 2013 list data I created which works fine when running locally on my machine and when run locally one the server. I'm user the same credentials when running both locally and locally on the server. The issue is when I publish and navigate to my ASP.NET app on the server I get the "The remote server returned an error: (401) Unauthorized." Error...
I've looked at a bunch of the posts on stackoverflow and some other articles on the web
This points out that the context seems to be using IUSR:
http://blogs.msdn.com/b/sridhara/archive/2014/02/06/sharepoint-2013-csom-call-from-web-part-fails-with-401-for-all-users.aspx
This one mentions to try setting the default network credentials:
https://sharepoint.stackexchange.com/questions/10364/http-401-unauthorized-using-the-managed-client-object-model
I've tried using the fixes mentioned in the article as well as trying to force the context to use DefaultNetworkCredentials but no luck. I would like for the app to use the credentials of the logged in user and not the machine...
Here is the code I'm using:
SP.ClientContext context = new SP.ClientContext("MySPDevInstance");
context.Credentials = CredentialCache.DefaultNetworkCredentials;
Entity entity = context.Web.GetEntity(collectionNamespace, collectionName);
LobSystem lobSystem = entity.GetLobSystem();
LobSystemInstanceCollection lobSystemInstanceCollection = lobSystem.GetLobSystemInstances();
context.Load(lobSystemInstanceCollection);
context.ExecuteQuery();
LobSystemInstance lobSystemInstance = lobSystemInstanceCollection[0];
FilterCollection filterCollection = entity.GetFilters(filter);
filterCollection.SetFilterValue("LimitFilter", 0, 1000);
EntityInstanceCollection items = entity.FindFiltered(filterCollection, filter, lobSystemInstance);
The server is running IIS 6.0
Any advice would be much appreciated!
Thank you
I presume your ASP.NET web site is using Windows Integrated (NTLM) authentication. A user authenticated this way cannot authenticate to a second location from the server side (the web server.) You are experiencing what is known as the "double-hop" (1) limitation of NTLM. You must use a dedicated account on the server side, or if you really do want to use the logged-in user's identity, you must use an authentication scheme that permits delegation, such as Kerberos.
If you really need the user's identity to access SharePoint data and you cannot change the authentication scheme, then the best way to do this is to use the JavaScript CSOM. This means the user is authenticating directly to the SharePoint server (a single hop, not double) and your ASP.NET site serves the page containing this script to the user.
(1) http://blogs.msdn.com/b/knowledgecast/archive/2007/01/31/the-double-hop-problem.aspx
Use Default Credentials worked for me:
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.UseDefaultCredentials = true;
Setup the crendentials by code:
SP.ClientContext context = new SP.ClientContext("MySPDevInstance");
context.Credentials = new NetworkCredential("username", "password");
You should put this at the configuration file to change it without publishing or recompiling the application.
Just to add one more setting that I encountered. If the account is restricted to access only certain servers than add the client machine to that account as well. For example if a web application is hosted on Server A and trying to connect to SharePoint 2010 on Server B with account ABC then make sure that account has access to Server A in Active Directory. Normally the AD account doesn't have restrictions to connect to machines but in my case the account was restricted to only certain machines. I added my web application hosted server to the account and it worked.

Directory.CreateDirectory failed on Remote Server

I am working on a small project, in asp.net mvc3, that would copy the deployment files from a local drive to a share drive on a window server 2008 R2 server. I am connected using WMI, and the connection is successful. However, I tried to create a folder, and I receive the message "Logon failure: unknown user name or bad password." Here is a sample code:
bool isConnected = false;
options.Username = user.Name.Trim();
options.Password = user.password.Trim();
mScope = new ManagementScope("\\\\xxx.xxx.xxx.xxx\\root\\cimv2", options);
mScope.Connect();
if (mScope.IsConnected == true)
{
//I've gotten to this point. Then, the code below throw the exception
Directory.CreateDirectory(#"\\\\xxx.xxx.xxx.xxx\Tester\shareFile.txt");
isConnected = true;
}
I'd like to know what am I doing? Is that the right way of doing it?
it is the correct way however it will be the current user you are trying to access that gets passed to the remote computer to create the directory. The management scope at this point has nothing to do with Directory.CreateDirectory. These are 2 different "worlds". you do give the creds to ManagementScope but this has no affect on Directory.CreateDirectory. you could use impersonation to do what you are wanting to:
How do you do Impersonation in .NET?
it is unclear though if you are doing this in ASP.NET/MVC or a different platform. your tags indicate ASP.NET MVC but not your main question.
remember, if you are using ASP.NET/MVC, the credentials of the app pool are being used to perform such actions.

Active directory - exception has been thrown by the target of an invocation

I have a web application in a separate server than Active Directory and I want to change a user password. The code is the next:
string newPassword = Membership.GeneratePassword(int.Parse(WebConfigurationManager.AppSettings["passLenght"]),
int.Parse(WebConfigurationManager.AppSettings["passNonAlpha"]));
DirectoryEntry de = new DirectoryEntry(WebConfigurationManager.ConnectionStrings["ADConnString"].ConnectionString,
WebConfigurationManager.AppSettings["ADAdmin"], WebConfigurationManager.AppSettings["ADAdminPass"]);
DirectorySearcher deSearch = new DirectorySearcher(de);
deSearch.Filter = "(&(objectClass=user) (userPrincipalName=" + name + "))";
SearchResultCollection results = deSearch.FindAll();
if (results.Count == 1)
{
foreach (SearchResult OneSearchResult in results)
{
DirectoryEntry AlterUser = OneSearchResult.GetDirectoryEntry();
AlterUser.AuthenticationType = AuthenticationTypes.Secure;
AlterUser.Invoke("SetPassword", newPassword);
AlterUser.CommitChanges();
AlterUser.Close();
}
}
When I run this in my development environment (where Active Directory and the web application are on the same server) it is working. But when I try to run it in the production environment I am having the next error:
Exception has been thrown by the target of an invocation
What am I missing?
Thanks.
EDIT:
I could go deep in the exception error and I get this:
Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Permissions are the issue. The account under which your ASP.NET code is running doesn't have the permission to set the account password.
Either:
Run the AppPool under a user that has the required permissions, or
Use impersonation to elevate the permissions for the SetPassword call
The reason it is working in your dev environment/failing in production is likely due to a combination of:
You are running the app under the Visual Studio development web server that runs under your user account, which has the necessary permissions. Running it under "real" IIS will run it under a less privileged account.
In the live environment there's another machine hop from the web server to the AD server, and the credentials don't get passed along. The web server needs to have network credentials (either as part of the AppPool identity, or a call to LogonUser) in order to authenticate to AD.
The code looks correct. This could be happening because the password your sending though Active Directory does not meet the minimum requirements. Trying using a more complex password such as "M2k3ThisWork!"
If you want to change the password of AD then you use this
AlterUser.Invoke("ChangePassword", OldPassword, newPassword);

Access Denied errors accessing IIS WMI provider from ASP

I have a Windows 2003 server running IIS 6 and have some scripts that do automated setup and creation of websites. They are not working on a new server I cam commissioning (they already work happily on 3 other W2K3 servers). The problem appear to boil down to WMI security on the IIS provider. The ASP code below represents the problem (although it is not the original code that causes the problem - this is a simplified demonstration of the problem).
Set wmiProvider = GetObject("winmgmts:\\.\root\MicrosoftIISv2")
If wmiProvider is Nothing Then
Response.Write "Failed to get WMI provider MicrosoftIISv2<br>"
End If
Response.Write "Querying for IISWebService...<br>"
Set colItems = wmiProvider.ExecQuery("Select * From IISWebServer",,0)
Response.Write "Error: " & Hex(Err.Number) & " (" & Err.Description & ")<br>"
If I run this in my browser, I get an access denied error reported after the ExecQuery call. I have set WMI access for the IUSR_ user from the Root branch all the way down. In fact, I can query for IP address information using the CIMV2 provider quite happily. If I put the IUSR user in the machine admins group it all works, but I don't really want to do that.
This must be a DCOM/WMI security problem, but I can't work out what else there is. Can anyone shed any light?
After reading G. Stoynev's comment asking if any events were logged in the Windows Logs, I checked the event logs on the server to which I'm attempting to access IIS remotely via WMI, and lo and behold I found an event with the following text:
Access to the root\WebAdministration namespace was denied because the namespace is marked with RequiresEncryption but the script or application attempted to connect to this namespace with an authentication level below Pkt_Privacy. Change the authentication level to Pkt_Privacy and run the script or application again.
See the code in this answer to the related SO question c# - "Access is denied" Exception with WMI.
Here's some example C# code that I added that seemed to resolve this issue for me:
ConnectionOptions options = new ConnectionOptions();
options.Authentication = AuthenticationLevel.PacketPrivacy;
ManagementScope managementScope = new ManagementScope(#"\\remote-server\root\WebAdministration", options);
// ...
If this is something that you intend to run as a tool for yourself or your admin (as opposed to the unwashed anonymous masses), here is a way I have used in the past (YMMV):
Set up a new directory in your website (e.g. /SiteCreate) and place your WMI scripts there
Configure a Windows user that has appropriate rights (probably admin in this case but you should use whatever is pertinent to your app)
Turn off the anonymous access to the directory you created in step 1 and then set the security to allow access only to the user you created in step 2 (turn on the authentication for that directory)
Now, when you navigate to that directory in your browser, you should get a login prompt. When you enter the username/password you created in step 2 your script will have the appropriate rights to perform your WMI requests.
Not a DCOM issue, more so a WMI security and encryption issue. Try changing the GetObject moniker to include impersonation and pktPrivacy, eg:
Set wmiProvider = GetObject("winmgmts:{impersonationLevel=impersonate;authenticationLevel=pktPrivacy}!\root\MicrosoftIISv2")
Refer to the follow MS article for more info:
http://msdn.microsoft.com/en-us/library/aa393618(v=vs.85).aspx

How do I access database via virtual folder which points at a remote share

I'm having a problem getting access to a database which lives on a remote server.
I have a ASP.NET 2.0 webpage that is trying to connect to a database.
The database is accessed via a virtual folder (which I set up in IIS).
The virtual folder points at a remote share which contains the database.
The virtual folder (in the web apps root directory) is pointing at a share on a remote server via a UNC path:
\\databaseServerName\databaseFolder$\
The virtual folder has 'read' and 'browse' permissions set to 'true'.
I store the connection string in the 'appSettings' section of the web.config:
<add key="conStrVirtual" value="Provider=Microsoft.Jet.OleDb.4.0;Data Source=http://webAppServerName/virtualFolderName/databaseName.MDB;Jet OLEDB:Database Password=dumbPassword;"/>
The connection object is declard on my .aspx page:
Dim objConnVirtual As New OleDbConnection(ConfigurationManager.AppSettings("conStrVirtual"))
Here is the code that tries to use the connection object:
Public Sub Test()
If objConnVirtual.State <> ConnectionState.Open Then
objConnVirtual.Open()
End If
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM TableName", objConnVirtual)
objDR = cmd.ExecuteReader()
If objDR.Read() Then
response.write("Shazaam! Data shows up here")
End If
objDR.Close()
objConnVirtual.Close()
End Sub
When I run the above code I get the following error (on this line of the code 'objConnVirtual.Open()':
Exception Details: System.Data.OleDb.OleDbException: Not a valid file name.
I have checked the database name and it is correct (even copy/pasted it to make sure)
If I put the 'Data Source' section of the connection string into the address bar of my browser I can successfully see the contents of the share on the remote server.
Not sure if this is a problem with permissions or with the code.
I have googled the crap out of this but have not been able to find a solution.
Any help is much appreciated.
When accessing a remote Access MDB database, you have to specify a UNC path like \\remoteMachine\Share\test.mdb.
Make sure your application pool identity has the right permissions to connect to the remote share. By default on IIS 6 you are working with the Network Service account, which is by default not allowed to access a remote share.
The best way is to let the AppPool run with a dedicated service user.
What is the account being used on your server when your web app tries to read the db file? Whatever this user account is, it needs to have permissions to read that folder/file. In IIS6 you can configure the virtual folder to use any user account... on the Directory Security tab there's an Edit button under Authentication and access control.
It seems likely that your error message is just a generic error message, and the permissions problem is your real issue.
make sure the two servers have internal access to each other and also specify the ip & port of db server in your connection string .
Update
I should also mention that it works on my machine (but not once loaded up to the production box) if I declare the connection string in the 'appSettings' section of the web.config like this:
<add key="conStrVirtual" value="Provider=Microsoft.Jet.OleDb.4.0;Data Source=\\databaseServerName\databaseFolder$\databaseName.MDB;Jet OLEDB:Database Password=dumbPassword;"/>
This leads me to think that it could be an issue with needing to use domain credentials other than the local IUSER account.
UPDATE
First up, thank you to everyone who submitted answers.
However, we ended up not using the 'connect to remote database via virtual folder' method because the complexity of the permissions needed to get this to work was causing us more problems than it was worth. We put the UNC path back into the connection string, which may not be the best way to do this, but is working for us.

Resources