Not able to write image in shared folder in IIS - iis

I have developed an module to save image in windows shared location
my code works fine development machine in VS 2015 and IIS express.
But when i deploy the code in my IIS sever(IIS 8) and set my appppol.
When it checks the directory exists or no it fails and does not save the image.
in share path. I have tried accessing the shared path from server I am able to open it without issues
I have applied logs to check but it fails that directory does not exit
Sharepath ex:\atse-bs-13450.abc.xyz.com\Sharefolder\PhotoImages
My app pool is set to ApplicationPoolIdentity
public void WriteImage(string Location, string base64Image)
{
try
{
// Check if directory exist
if (Directory.Exists(Location))
{
//location value is set in appSettings;
//"\\atse-bs-13450.abc.xyz.com\Sharefolder\PhotoImages\"
string strImagePath = Location;
// Check file exist in location
if (!File.Exists(Location))
{
if (!string.IsNullOrEmpty(base64Image))
{
using (FileStream stream = new FileStream(strImagePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(Base64String2Blob(base64Image));
}
}
}
else
{
strBlobLogMessage = "image file could not be stored on shared location , Share path location : ";
PathNotFound(strBlobLogMessage);
}
}
else
{
strBlobLogMessage = "image file could not be stored on shared location as path does not exists , Share path location : ";
PathNotFound(strBlobLogMessage);
}
}
catch (Exception ex)
{
throw ex;
}
}

Two options
Create a user account and then assign that user account read and write access on shared location. Then you can set the Application Pool Identity to Custom account and then set it to newly created user account.
Since your app pool is using Application Pool Identity, there will be user account with name IIS AppPool\{Applicaiton Pool name} e.g. for DefaultAppPool the user account is IIS AppPool\DefaultAppPool so you can allow read/write access to shared directory to Applicaiton Pool user

Related

How to copy files from Azure File-Share (not blob) of different storage account using .net core

public void MoveFiles(AzureFileClient srcAzureClient, AzureFileClient destAzureClient, ShareClient srcShareClient, ShareClient destShareClient, string dirName)
{
if (!destAzureClient.ShareClient.GetDirectoryClient(dirName).Exists())
destAzureClient.ShareClient.GetDirectoryClient(dirName).Create();
var fileItems = GetChildNodes(srcShareClient, dirName);
if (fileItems.Count == 0)
return;
foreach (var item in fileItems)
{
if (item.ShareFileItem.IsDirectory)
{
MoveFiles(srcAzureClient, destAzureClient, srcShareClient, destShareClient, $"{dirName}/{item.ShareFileItem.Name}");
}
else
{
var srcFileClient = srcShareClient.GetDirectoryClient(Path.GetDirectoryName(item.FullPath)).GetFileClient(Path.GetFileName(item.FullPath));
var destFileClient = destShareClient.GetDirectoryClient(Path.GetDirectoryName(item.FullPath)).GetFileClient(Path.GetFileName(item.FullPath));
if (srcFileClient.Exists())
{
destFileClient.StartCopy(srcFileClient.Uri);
}
}
}
}
This code is throwing an error at
destFileClient.StartCopy(srcFileClient.Uri)
saying
sourceCopy is not verified, connection strings are given to both source & destination fileShare object
I am able to copy files from the same account storage.
When copying files (or blobs) across storage accounts, the source file (or blob) must be publicly accessible. This restriction does not apply when the source and destination are in the same storage account.
Because Azure Files are inherently private (there's no concept of ACL like we have in Blob Storage), you are getting this error as Azure Storage Service is not able to read the source file.
To fix this, you would need to create a SAS URL with at least read permission on the source file and use that SAS URL as copy source.

Issue with user permissions on azure web app (ApplicationPool - Identity)

I am trying to programmatically change the ApplicationPool - Identity property of the IIS server where my azure web app is hosted.
Why am I doing this?
I need to provide X.509 certificate. Implementing this certificate requires some local system data.
What have I done so far?
I use this particular code (pretty much the same from here https://stackoverflow.com/a/9341347/2900305)
private void SetAppPoolIdentity()
{
string appPoolUser = "myRDP_admin_user";
string appPoolPass = "my_super_secure_password";
Action<string> iis7fix = (appPoolName) =>
{
bool committed = false;
while (!committed)
{
try
{
using (ServerManager sm = new ServerManager())
{
var applicationPool = sm.ApplicationPools[appPoolName];
applicationPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser;
//applicationPool.ProcessModel.IdentityType = ProcessModelIdentityType.LocalSystem;
applicationPool.ProcessModel.UserName = appPoolUser;
applicationPool.ProcessModel.Password = appPoolPass;
sm.CommitChanges();
committed = true;
}
}
catch (FileLoadException fle)
{
Trace.TraceError("Trying again because: " + fle.Message);
}
}
};
var appPoolNames = new ServerManager().Sites.First().Applications.Select(x => x.ApplicationPoolName).ToList();
appPoolNames.ForEach(iis7fix);
}
My problem is that my user does not have enough permissions to change the ApplicationPool - Identity to LocalSystem.
And I do not have username and password for specific user (admin or local admin) on azure hosted web app.
Any different approach or idea or workaround are welcomed.
You cannot change the App Pool identity that an Azure Web App runs under. Web Apps execute in a sandboxed environment that generally don't allow this kind of modifications.
There are ways of uploading certificates, and you may want to ask that question specifically if that is what you're trying to achieve.

Elevating IIS worker identity to access Memory Mapped File

I need to access a memory mapped file from one of my routes in my Web API. Using the normal IIS worker settings I have no luck and my service always returns "File not found". I tried to add the prefix "Global/" but still no luck.
After reading many hours on the web I learned that I need to change the Identity of the IIS worker. So, just for testing purposes I changed the worker identity to the Administrator account. I uploaded a picture here:
http://imgur.com/MrA3byz
But still no luck. Does anyone here know how to configure IIS correctly?
Here is how I access the Memory Mapped File using c#:
string Message = "";
try
{
string MMF_In_Name = "Global\\MMF_Name";
MemoryMappedFile MMF_In = MemoryMappedFile.OpenExisting(MMF_In_Name);
Messages.Add("Connected to MMF");
}
catch (Exception ex)
{
Messages.Add(ex.Message);
}
I have double checked the name of the memory mapped file and it's correct. A command line tool run as Administrator works as expected.
I'm using IIS 8.5 on Windows Server 2012.
This works on Windows Server 2012 and IIS 8.5.
It's important to understand that the IIS worker runs in a different Terminal Server Session than normal applications. Much like a Windows Service.
So when the application exposing a Memory Mapped File it needs create it via the "Global\" prefix added to the name. But it also needs add a security descriptor or identity. In c# it would look like this:
string MMF_Name = #"Global\MyMemoryMappedFileName";
var security = new MemoryMappedFileSecurity();
security.AddAccessRule(new System.Security.AccessControl.AccessRule<MemoryMappedFileRights>(new SecurityIdentifier(WellKnownSidType.WorldSid, null)
, MemoryMappedFileRights.FullControl
, AccessControlType.Allow)
);
var mmf = MemoryMappedFile.CreateOrOpen(MMF_Name
, 1024 * 1024
, MemoryMappedFileAccess.ReadWrite
, MemoryMappedFileOptions.None
, security
, System.IO.HandleInheritability.Inheritable);
In C++ it would look like this:
TCHAR szName[] = TEXT("Global\MyMemoryMappedFileName");
HANDLE hMapFile;
LPCTSTR pBuf;
SECURITY_DESCRIPTOR sd;
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
printf("InitializeSecurityDescriptor failed %d\n", GetLastError());
if (!SetSecurityDescriptorDacl(&sd, true, 0, false))
printf("SetSecurityDescriptorDacl failed %d\n", GetLastError());
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = false;
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
&sa, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
BUF_SIZE, // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 1;
}
An application creating such objects needs to start with Admin rights.
Now when a client like the IIS worker tries to access the file it needs to make sure to use the correct name, aka use the "Global\" prefix. In C# it would look like:
string MMF_Name = #"Global\MyMemoryMappedFileName";
var MMF = MemoryMappedFile.OpenExisting(MMF_Name
, MemoryMappedFileRights.ReadWrite
, HandleInheritability.Inheritable);
In C++:
TCHAR szName[] = TEXT("Global\\MyMemoryMappedFileName");
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
TRUE, // !!!!! do inherit the name
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
return 1;
}
When all this is done. The IIS worker should be able to access the application via the memory mapped file. No need to change the identity of the worker. In fact, I run it in default settings.

AppPool Invoke returns Unknown name. Exception (DISP_E_UNKNOWNNAME)

When using Directory services in IIS7, I am unable to get the invoke(method) to work with the app pool. It consistently returns the unknown name exception.
Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))
I am able to use the InvokeGet command to get property data from the app pool, but invoke consistently fails. It's as if the method names were changed between IIS6 and IIS7.
The code is run by a web page running on an Windows 2003 box with IIS6, It is querying a Windows 2008 box with IIS7.5
Here is my code:
string machineName = this.MYMACH.Text;
string query;
string Usrnm = GetUSRNAME(); //decrypts admin user name
string Pswd = GetPSWORD(); //decrypts admin user password
query = String.Format("IIS://{0}/w3svc/AppPools/{1}", machineName, AppPoolName);
DirectoryEntry w3svc = new DirectoryEntry(query, Usrnm, Pswd);
try
{
if (4 == (int)w3svc.InvokeGet("AppPoolState")) // <--- works
{
w3svc.Invoke("Start", null);
errormsgs.Text = string.Format("Application pool {0} retarted", btn.Text);
}
else
{
w3svc.Invoke("Recycle", null); <--- Excepts
errormsgs.Text = string.Format("Application pool {0} recycled", btn.Text);
}
}
catch (Exception eee)
{
errormsgs.Text = string.Format("Application pool {0} recycle error {1}... Query text = {2}", btn.Text, eee.Message, query);
}
I've tried the invoke several ways:
w3svc.Invoke("Recycle", null);
w3svc.Invoke("Recycle", object[]{});
w3svc.Invoke("Recycle");
None of them work
any ideas?
This is because your code doesn't have the right to use local DCOM to do the invoke.
Try :
<system.web>
<identity impersonate="true" userName="" password="" />
</system.web>
Make sure you use a local domain account have the right to use DCOM on this machine.
Also, you can change the local DCOM setting to give your local app pool user rights.

Is there any way to create an application pool in IIS manager using c#?

Can anyone help create an Application Pool in IIS using C#?
Once this has been done, how do I assign the Application Pool to a virtual directory, again using C#?
If you're using IIS7:
To create an application pool using and set the .NET Framework version (to v2.0 in this case), do this:
using Microsoft.Web.Administration;
...
using(ServerManager serverManager = new ServerManager())
{
ApplicationPool newPool = serverManager.ApplicationPools.Add("MyNewPool");
newPool.ManagedRuntimeVersion = "v2.0";
serverManager.CommitChanges();
}
You should add a reference to Microsoft.Web.Administration.dll which can be found in:
%SYSTEMROOT%\System32\InetSrv
To assign a virtual directory to an application pool (though I think you mean an application):
using (ServerManager serverManager = new ServerManager())
{
// Find Default Website
Site site = serverManager.Sites.First(s => s.Id == 1);
Application newApp = site.Applications.Add("/MyNewApp",
#"C:\inetpub\wwwroot\mynewapp");
newApp.ApplicationPoolName = "MyNewPool";
serverManager.CommitChanges();
}
If you're using IIS6:
using (DirectoryEntry appPools =
new DirectoryEntry("IIS://localhost/W3SVC/AppPools"))
{
using (DirectoryEntry newPool = appPools.Children.Add("MyNewPool",
"IIsApplicationPool"))
{
// Just use NetworkService as pool account
newPool.Properties["AppPoolIdentityType"].Value = 2;
newPool.CommitChanges();
}
}
The following code creates an application called MyNewApp in the Default Web Site and assigns it to the application pool MyNewPool we created using the code example above:
using (DirectoryEntry siteRoot =
new DirectoryEntry(#"IIS://Localhost/W3SVC/1/root"))
{
using (DirectoryEntry newApp =
siteRoot.Children.Add("MyNewApp", "IIsWebVirtualDir"))
{
newApp.Properties["Path"].Value = #"C:\inetpub\wwwroot\mynewapp";
newApp.Properties["AccessScript"][0] = true;
newApp.Properties["AccessFlags"].Value = 513; // AccessScript | AccessRead
newApp.Properties["AuthFlags"].Value = 7;// AuthAnonymous|AuthBasic|AuthNTLM
newApp.Properties["AppIsolated"].Value = "2";
newApp.Properties["AppRoot"].Value =
newApp.Path.Replace("IIS://Localhost", "/LM");
newApp.Properties["AppPoolId"].Value = "MyNewPool";
newApp.Properties["AppFriendlyName"].Value = "MyNewApp";
newApp.CommitChanges();
}
}
I all of the above cases your code needs to be running as an administrator.
For more information see:
IIS7:
IIS 7 Configuration Reference
How to Use Microsoft.Web.Administration
IIS6:
Using System.DirectoryServices to Configure IIS
IIS Programmatic Administration Reference
IIS Metabase Properties
I believe this depends on which version of IIS you are using but check out:
http://msdn.microsoft.com/en-us/library/ms525598.aspx (example is for IIS7)
Source was from another question: Programmatically create a web site in IIS using C# and set port number

Resources