I'm trying the change some configurations of the network adapters locally. I have to use a non-administrative user, but I just get the return value "91", which stands for "Access Denied", when I try to invoke methods. It was possible to set the rights for the "EnableStatic" method, but "SetDNSServerSearchOrder" doesn't work at all. It always returns "Access Denied". I cannot even disable the network adapter (in Win32_NetworkAdapter). Everything works great with an admin user. Since I had the same problem with "EnableStatic", I'm pretty sure, that there must be a way to get this working with the other methods. I set the security options in wmimgmt.msc for all namespaces, I set the limits in dcomcnfg, I granted permissions in the registry for tcpip, added the user in distributed com-users, performance groups, network configuration operators, but there is no way to get this working. I recognized, that there is no dns ip, when my tool was running. So something changes although the method is returning "Access Denied". Any ideas? Even Microsoft couldn't help me yet, since three weeks now. The tool is running without any problems, when I'm logged in as admin. Here is my C# Code: (and sorry for some mistakes in my written English ;) )
private static ManagementScope CreateScope(string strScope)
{
ManagementScope scope = new ManagementScope(strScope);
scope.Options.Impersonation = ImpersonationLevel.Impersonate;
scope.Options.Authentication = AuthenticationLevel.Packet;
return scope;
}
public static void SetIP(String strScope, String strQuery, string IPAddress, string SubnetMask, string Gateway, string DNSServer1, string DNSServer2)
{
ManagementScope scope = CreateScope(strScope);
SelectQuery query = new SelectQuery(strQuery);
Collection<object> objCol = new Collection<object>();
scope.Connect();
ManagementObjectCollection mobjCol = null;
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
mobjCol = searcher.Get();
}
foreach (ManagementObject objMO in mobjCol)
{
try
{
ManagementBaseObject objNewIP = null;
ManagementBaseObject objSetIP = null;
ManagementBaseObject objNewGate = null;
ManagementBaseObject objNewDNS = null;
objNewIP = objMO.GetMethodParameters("EnableStatic");
objNewGate = objMO.GetMethodParameters("SetGateways");
objNewDNS = objMO.GetMethodParameters("SetDNSServerSearchOrder");
//Set DefaultGateway
objNewGate["DefaultIPGateway"] = new string[] { Gateway };
objNewGate["GatewayCostMetric"] = new int[] { 1 };
//Set IPAddress and Subnet Mask
objNewIP["IPAddress"] = new string[] { IPAddress };
objNewIP["SubnetMask"] = new string[] { SubnetMask };
//Set DNS servers
objNewDNS["DNSServerSearchOrder"] = new string[] { DNSServer1, DNSServer2 };
//Invoke all changes
objSetIP = objMO.InvokeMethod("EnableStatic", objNewIP, null);
MessageBox.Show("EnableStatic: " + objSetIP["ReturnValue"].ToString());
objSetIP = objMO.InvokeMethod("SetGateways", objNewGate, null);
MessageBox.Show("SetGateways: " + objSetIP["ReturnValue"].ToString());
objSetIP = objMO.InvokeMethod("SetDNSServerSearchOrder", objNewDNS,null);
MessageBox.Show("SetDNSServerSearchOrder: " + objSetIP["ReturnValue"].ToString());
}
catch (ManagementException ex)
{
MessageBox.Show("Unable to Set IP : " + ex.Message);
}
}
}
non-administrative users need permissions to run WMI queries. You can set the relevant permissions using WMI Control [under ServerManager / Configuration or Computer Management / Services & Applications] ref: http://technet.microsoft.com/en-us/library/cc775497(v=ws.10).aspx
Try providing Execute Methods, Enable Account & Provider Write permissions to your non-admin user in the CIMV2 namespace.
Related
I have my web api that uploads and reads an excel file from the client app and then afterwards saves the data into the database, the application works perfect on locally server but the problem comes when the application is deployed to azure server it returns error 500 internal server error therefore i don't understand why this happens and and don't know how i can track to understand what might be the cause below are my code blocks.
My Interface Class
public interface UploadExcelInterface
{
Task UploadMultipleClients(Client obj);
}
My Service Implementation
public class UploadExcelService : UploadExcelInterface
{
private readonly DbContext _connect;
private readonly IHttpContextAccessor httpContextAccessor;
public UploadExcelService(DbContext _connect, IHttpContextAccessor httpContextAccessor)
{
this._connect = _connect;
this.httpContextAccessor = httpContextAccessor;
}
public async Task UploadMultipleClients(Client obj)
{
var file = httpContextAccessor.HttpContext.Request.Form.Files[0];
if (file != null && file.Length > 0)
{
var folderName = Path.Combine("Datas", "ClientUPloads");
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName);
var fileName = Guid.NewGuid() + ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var fullPath = Path.Combine(pathToSave, fileName);
var clientsList = new List<Client>();
using (var fileStream = new FileStream(fullPath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
FileInfo excelFile = new FileInfo(Path.Combine(pathToSave, fileName));
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (ExcelPackage package = new ExcelPackage(excelFile))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
var rowcount = worksheet.Dimension.Rows;
for (int row = 2; row <= rowcount; row++)
{
var Names = (worksheet.Cells[row,2].Value ?? string.Empty).ToString().Trim();
var Address = (worksheet.Cells[row,3].Value ?? string.Empty).ToString().Trim();
var Title = (worksheet.Cells[row,4].Value ?? string.Empty).ToString().Trim();
var Product = (worksheet.Cells[row,5].Value ?? string.Empty).ToString().Trim();
var Order = (worksheet.Cells[row,6].Value ?? string.Empty).ToString().Trim();
var Email = (worksheet.Cells[row,7].Value ?? string.Empty).ToString().Trim();
var Price = (worksheet.Cells[row,8].Value ?? string.Empty).ToString().Trim();
clientsList.Add(new Client
{
Names = Names,
Address = Address,
Title = Title,
Product = Product,
Order = Order,
Email = Email,
Price = Price,
}
}
//adding clients into the database
foreach (Client client in clientsList)
{
var exist = _connect.client.Any(x => x.Email == client.Email);
if (!exist)
{
await _connect.client.AddAsync(client);
}
}
await _connect.SaveChangesAsync();
}
}
}
My Controller Class
[HttpPost]
public async Task UploadMultipleClients([FromForm] Client obj)
{
await uploadExcelInterface.UploadMultipleClients(obj);
}
}
Please any help regarding this error that am getting from the server, and addition on that is it possible to get the data from the excel file without uploading it to server if yes how? because i tried adding the file to memory stream an reading it from memory but it appers not work, any suggestions thanks.
My answer may not help you solve the problem directly, but it can locate the error step by step. After we fix the error, we should be able to solve the problem in this thread.
Suggestions
Please make sure you have inclue EPPlus library in your deploy content.
Enabling ASP.NET Core stdout log (Windows Server)
Azure App Service - Configure Detailed Error Logging
Why
After tested, I am sure azure webapp can support EPPlus. For 500 error, as we don't have a more specific error message to refer to, we can't quickly locate the problem. Following the suggested method, you will surely see some useful information.
E.g:
The class library of EPPlus was not found.
Folders such as Datas are not created.
The database connection string, the test environment and the production environment may be different.
...
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...
I'm trying to authenticate against AD using application mode (ADAM), but keep getting unknown username or bad password. If I test the login in LDP.exe it logs in no problem, on simple bind. I've trawled through all similar posts with the same issue, but have not resolved it, any suggestions what I should be checking for?
private bool ValidateActiveDirectoryLogin(string Username, string Password)
{
bool Success = false;
System.DirectoryServices.DirectoryEntry Entry = new System.DirectoryServices.DirectoryEntry("LDAP://localhost:389/OU=Users,O=TestDirectory", Username, Password);
System.DirectoryServices.DirectorySearcher Searcher = new System.DirectoryServices.DirectorySearcher(Entry);
Searcher.SearchScope = System.DirectoryServices.SearchScope.Subtree;
try
{
System.DirectoryServices.SearchResult Results = Searcher.FindOne();
Success = (Results != null);
}
catch (Exception ex)
{
Success = false;
throw;
}
return Success;
}
Determine what context your application is hitting AD with. If your ASP.NET application pool identity is one that is low privileged, it won't have enough permissions to query active directory. If you don't want to create a custom user to run the app pool as with appropriate permissions - you could use the LogonUser API to make your ValidateActiveDirectoryLogin call under the security context of that account.
Finally, you should consider using System.DirectoryServices.AccountManagement if you are using .NET 3.5 or above.
You can use code like
bool validCreds = false;
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
validCreds = context.ValidateCredentials( username, password );
}
I get an error by a website, on which I use Windows Authentication.
Strange things:
Only occurs if user is not yet saved into database (new unknown user)
Appears only on live system, everything fine on local development environment
This is what I get in a logging mail:
Source : System.DirectoryServices
Message: The server is not operational.
Trace:
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
at Smarthouse.Labs.DataAccess.UserListManager.SaveUser(String windowsUserName)
This is how I implement DirectorySearch:
private void SaveUser(string windowsUserName)
{
string[] domainAndUser = windowsUserName.Split('\\');
string domain = domainAndUser[0];
string username = domainAndUser[1];
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain);
DirectorySearcher search = new DirectorySearcher(entry);
try
{
// Bind to the native AdsObject to force authentication.
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("sn");
search.PropertiesToLoad.Add("givenName");
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne();
if (result == null)
{
throw new Exception("No results found in Windows authentication.");
}
User userToSave = new User();
userToSave.FirstName = (String) result.Properties["givenName"][0];
userToSave.LastName = (String) result.Properties["sn"][0];
userToSave.Email = (String) result.Properties["mail"][0];
userToSave.Username = windowsUserName;
userToSave.Guid = Guid.NewGuid();
SaveUser(userToSave);
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message, ex);
}
finally
{
//Dispose service and search to prevent leek in memory
entry.Dispose();
search.Dispose();
}
}
If more code examples are needed just tell me.
Your problem is that you're using a "plain" domain name to bind - this won't work in LDAP. Actually, if you try to bind to LDAP://MyDomain, what you're really doing is trying to bind to the server called MyDomain.
You need a valid LDAP bind string - something like LDAP://dc=yourdomain,dc=local or something.
To find out what your default LDAP binding context is, use this code snippet:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://RootDSE");
if (deRoot != null)
{
string defaultNamingContext = deRoot.Properties["defaultNamingContext"].Value.ToString();
}
Once you have that string - use that as your bind string to your LDAP server.
And if you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context -- no domain name needed, uses default domain
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if(user != null)
{
// do something here....
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
You can use bind strings in the format LDAP://mydomain.com:389. I kept getting "Access is Denied" when trying to use the format LDAP://DC=mydomain,DC=com. Once I switched to the LDAP://mydomain.com:389 format, and bound using the AuthenticationTypes.ServerBind flag when constructing my DirectoryEntry, it worked great. This was in Azure App Service.
To add to marc_s's answer above, I needed to search multiple domains.
So for each Domain I did the following:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://" +"DomainName"+ "/RootDSE");
string defaultNamingContext = "LDAP://" + deRoot.Properties["defaultNamingContext"].Value.ToString();
DirectoryEntry mySearchRoot = new DirectoryEntry(defaultNamingContext);
DirectorySearcher myDirectorySearcher = new DirectorySearcher(mySearchRoot);
Similar Error Happened to me (though it happened all the time and not in specific cases like pointed out here) because of a wrong Active Directory connection string. i used the corp instead the prod one .
Use something that works for another app in your organization if exists.
I have an ASP.NET app which needs to save files to a network share (Samba).
The share requires a username and password to connect.
I have mapped a persistent drive to the share and provided the login credentials whilst logged in to the server as DOMAIN\WEBUSER.
I have changed the virtual directory which hosts my app to use the DOMAIN\WEBUSER account instead of the IWAM account.
However the user still cannot see the mapped drive.
What am I missing out?
Did you try mapping the drive in code? Here is a class for doing just that...
public static class NetworkDrives
{
public static bool MapDrive(string DriveLetter, string Path, string Username, string Password)
{
bool ReturnValue = false;
if(System.IO.Directory.Exists(DriveLetter + ":\\"))
{
DisconnectDrive(DriveLetter);
}
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": " + Path + " " + Password + " /user:" + Username;
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
public static bool DisconnectDrive(string DriveLetter)
{
bool ReturnValue = false;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": /DELETE";
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
}
It is best to use the UNC if you can as the mapped drives generally are linked to the interactive user and the virtual directory is probably connecting with a service or netwrok login type.
Another possible fix is described in this KB articleError occurs when you configure IIS to use a Samba network share as its root. Excerpted below.
Important These steps may increase
your security risk. These steps may
also make the computer or the network
more vulnerable to attack by malicious
users or by malicious software such as
viruses. We recommend the process that
this article describes to enable
programs to operate as they are
designed to or to implement specific
program capabilities. Before you make
these changes, we recommend that you
evaluate the risks that are associated
with implementing this process in your
particular environment. If you decide
to implement this process, take any
appropriate additional steps to help
protect the system. We recommend that
you use this process only if you
really require this process.
Warning This method involves a
security risk because the user who
created the mapping must remain logged
on to the local console. Therefore,
the only security is by locking the
computer. To work around this problem,
do the following:
Map a drive letter to \servername\iisroot using "root" and
"password."
In the Samba virtual directory, change the home directory from Share
on Another Computer to Local
Directory, and then specify the drive
letter that you mapped in step 1.
Restart the Web site, and then test it by browsing.
It's been a while (6 or 8 years) since I've done something like this, but as I recall, I also had to run the APP Pool as the domain user that had access to the network share in order for IIS to be able to serve up files from it.