NetworkCredential for mapped drive on IIS not working - .net-core

I have a .net core MVC controller that is downloading a file from a mapped drive on a server. It uses NetworkCredential to pass the username and password for the drive:
[HttpGet("[Action]")]
public IActionResult PdfContract(string fileName)
{
NetworkCredential theNetworkCredential = new NetworkCredential(_contractsUsername, _contractsPassword);
CredentialCache theNetCache = new CredentialCache();
theNetCache.Add(new Uri(_contractsPath), "Basic", theNetworkCredential);
try
{
var path = _contractsPath + #"\" + fileName;
if (System.IO.File.Exists(path))
{
return new PhysicalFileResult(path, "application/pdf");
}
else
{
return NotFound(path);
}
}
catch (Exception exception)
{
return NotFound(exception.ToString());
}
}
this works fine when I run it locally in visual studio but when I put the code on the server it is trying to connect to the drive using the credentials of the box rather than those I am passing. Is there a way to force it to use the credentials?

After a lot of messing around I found a way to do this. If anyone else has this problem then this solution worked for me
https://www.c-sharpcorner.com/blogs/how-to-access-network-drive-using-c-sharp

Related

HttpClient and WebClient requests / responses don't work for intranet with DefaultCredentials

Problem: I am unable to get content from an company internal webpage through using HttpClient or WebClient. I am able to get the content by accessing the URL directly, however.
Details: .NET Core 3.1 Razor Pages, IIS 10, Windows Authentication.
I have a website http://myintranet/Editor/Bib/4343 where a user can press a button to generate a static page. Behind the scenes, it attempts to read a stream from http://myintranet/Editor/NewBib/4343/true and create a static HTML page from it.
When clicking the button, the response is always IIS 10.0 Detailed Error - 401.1 - Unauthorized etc.
However when I access the webpage directly in the browser, it opens up just fine (note that if it is the first time accessing the website, I am prompted by the browser to enter my username and password. After that, the browser remembers these credentials).
Also note that when running it from localhost through Visual Studio, all works fine, the static page downloads properly too.
Here is my code:
Version 1:
public IActionResult OnPostGenerateStaticPage()
{
try
{
HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true, PreAuthenticate = true });
HttpResponseMessage response = client.GetAsync(Url.PageLink().Replace("Bib", "NewBib") + "/true").Result;
var indexPageContents = response.Content.ReadAsStreamAsync().Result;
var cd = new System.Net.Mime.ContentDisposition
{
FileName = BibNumber + ".htm",
Inline = false,
};
Response.Headers.Add("Content-Disposition", cd.ToString());
return File(indexPageContents, "text/html");
}
catch (IOException)
{
return RedirectToPage("./Bib");
}
}
Version 2:
public IActionResult OnPostGenerateStaticPage()
{
try
{
WebClient client = new WebClient { UseDefaultCredentials = true };
string desiredUrl = Url.PageLink().Replace("Bib", "NewBib") + "/true";
var indexPageContents = client.OpenRead("desiredUrl");
var cd = new System.Net.Mime.ContentDisposition
{
FileName = BibNumber + ".htm",
Inline = false,
};
Response.Headers.Add("Content-Disposition", cd.ToString());
return File(indexPageContents, "text/html");
}
catch (IOException)
{
return RedirectToPage("./Bib");
}
}
Another thing, I have asked the web server admin to check that NTLM is above Negotiate for the authentication providers for this website and it is. Also, Anonymous and Basic Authentication are disabled and Windows Authentication is enabled.
Not sure where to go from here...

Get windows logon user in asp.net web forms iis

I want to get the active directory login user in asp.net web forms.I used the below code snippet,but it won't work on either runtime or iis.
Request.ServerVariables["REMOTE_USER"].ToString();
Try using System.Web.HttpContext.Current.User.Identity; to get details of the authenticated user.
Use Directory Entry to get the user status.
string username = "";
string userpassword = "";
bool valid = false;
using (DirectoryEntry Direntry = new DirectoryEntry(path, username, userpassword))
{
using (DirectorySearcher Dsearch = new DirectorySearcher(Direntry))
{
Dsearch.Filter = "(cn=" + username + ")";
try
{
SearchResult adsSearchResult = Dsearch.FindOne();
if (adsSearchResult != null)
{
valid = true;
}
}
catch (Exception ex)
{
}
finally
{
Direntry.Close();
}
}
}
One additional change you may need to make is in the web.config file.
Change the authentication mode from Forms to Windows.
<authentication mode="Windows"/>
Documentation

Accessing client certificates smartcard with web application

I need to fetch the certificate, and would like to fetch the client, and there is no server, I could do this form:
public static X509Certificate2 EscolherCertificado(string serial)
{
var store = new X509Store("MY", StoreLocation.CurrentUser);
var Key = new RSACryptoServiceProvider();
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = store.Certificates;
X509Certificate2Collection fcollection = collection.Find(X509FindType.FindBySerialNumber, serial, false);
if (fcollection.Count == 1)
{
return fcollection[0];
}
else { cod = "00000"; msgm = "not found"; return null; }
}
But when I publish on the server it does not work. Is there any way I can do this?
I can not get the client certificate, it returns error, because on the server there are no registered certificates.
EDIT
I have already been told that it is possible, I just do not know how to do it, the ways I tried does not work.
EDIT
Following this link, I did comply, but it does not work, it does not always find. What can I do to correct this problem?
public static X509Certificate2 EscolherCertificado(string serial)
{
X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
userCaStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindBySerialNumber, serial, true);
X509Certificate2 clientCertificate = null;
if (findResult.Count == 1)
{
clientCertificate = findResult[0];
}
else
{
throw new Exception("Unable to locate the correct client certificate.");
}
cod = "0000"; msgm = clientCertificate.ToString(); return clientCertificate;
}
catch
{
throw;
}
finally
{
userCaStore.Close();
}
As far as I know, you cannot reach the client Certificates Store.
To do that you have to code a propietary plugin for each browser platform and give the right access permissions to the client.
That's a very painful task.
I wish you good luck with it.
In my case we ended up developing an EXE which has full access to the client hardware and features of the platform.
Here's the code:
private void ElegirCert()
{
System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store("MY", System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
System.Security.Cryptography.X509Certificates.X509Certificate2Collection collection = (System.Security.Cryptography.X509Certificates.X509Certificate2Collection)store.Certificates;
System.Security.Cryptography.X509Certificates.X509Certificate2Collection fcollection = (System.Security.Cryptography.X509Certificates.X509Certificate2Collection)collection;//.Find(System.Security.Cryptography.X509Certificates.X509FindType.FindByTimeValid, DateTime.Now, false);
try
{
Cert = System.Security.Cryptography.X509Certificates.X509Certificate2UI.SelectFromCollection(fcollection, "Elegir", "Seleccione el certificado que desea utilizar", System.Security.Cryptography.X509Certificates.X509SelectionFlag.SingleSelection)[0];
}
catch (Exception e)
{
}
store.Close();
}
I still think that it is not possible to get the list of client certificates using the sole browser capabilities.
There is a way and it involves creating an extension which communicates with an Executable Native file that does the "hard work". That means, getting the full list of certificates and exposing it to the user.
I think that after that, the user chooses one, then the EXE asks for the cert store password (if it has one), then the exe digitally signs the hash and whatever...

Internal Server Error when I send my own certificate to Azure Cloud Service

I'm trying to access the Azure Elastic Scale Split/Merge tool from an ASP.NET application. I can open the page in my browser after I use the certificate that I uploaded on Azure. But when I try to connect to the page in ASP.NET I keep getting 500 Internal Server Error, even though I used the certificate in my request.
Is there something wrong with the code below? Have I been forgetting something?
var handler = new WebRequestHandler();
handler.ServerCertificateValidationCallback = delegate { return true; };
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(Cert); //Cert is the X509Certificate2 I use
using (var client = new HttpClient(handler))
{
try
{
var response = await client.GetAsync(Endpoint); //Endpoint = https://foobar.cloudapp.net/
if (response.IsSuccessStatusCode)
{
var a = response.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
Found where I went wrong. When creating the Certificate I was using the .cer file, but it works now with the .pfx file

ASP.NET Process Start PowerShell Script IIS 7.5

All works fine on my dev machine but if deployed to IIS the process doesn't get started. I am starting a powershell script by
private void RunScript()
{
Process process = null;
try
{
int timeout = 1800000;
var startInfo = new ProcessStartInfo
{
FileName = #"powershell.exe",
Arguments = string.Format("{0} {1}", "\path\toscript", "myParam"),
UseShellExecute = false,
CreateNoWindow = true
};
process = Process.Start(startInfo);
process.WaitForExit(timeout);
}
finally
{
if (!process.HasExited)
{
if (process.Responding)
process.CloseMainWindow();
else
process.Kill();
}
if (process != null)
{
process.Close();
process.Dispose();
}
}
}
Here's what's configured for the app pool this is running under.
Process Model
->Identity = domain user who is a Domain Admin.
->Load User Profile = True
Web App
Authentication is Windows
What else do I need to configure to so that I can run the Process?
As Start-Automating suggested I eventually ended up doing this:
using (Runspace runSpace = RunspaceFactory.CreateRunspace())
{
try
{
runSpace.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(runSpace);
scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
using (Pipeline pipeLine = runSpace.CreatePipeline())
{
var myCommand = new Command(scriptPath);
var myParam1 = new CommandParameter("-paramName", "someValue");
myCommand.Parameters.Add(myParam1);
pipeLine.Commands.Add(myCommand);
pipeLine.Commands.Add("Out-String");
Collection<PSObject> returnObjects = pipeLine.Invoke();
runSpace.Close();
return returnObjects;
}
}
finally
{
runSpace.Close();
}
}
On the IIS server I executed the following powershell command "Set-ExecutionPolicy RemoteSigned"
It's much better to embed the PowerShell APIs the call the .exe
Here's an old link that will get you a PowerShell runspace embedded in ASP.NET per user:
http://powershellpipeworks.com/
Check the permissions of the file system where powershell.exe lives.
Also, check the Security Log in the Event Viewer for authentication errors and access violations.

Resources