Why am I getting an UnauthorizedAccessException when trying to write a file to LocalStorage in Azure - azure

I have created a local storage in my web role called "MyTestCache" as so in my
ServiceDefinition.csdef file. But when ever I call the System.IO.File.WriteAllBytes method I get a UnauthorizedAccess exception. Does anyone know what would be causing this? I dont get this when creating the directory in the code below, only when writing. I am using SDK 1.3.
private void SaveFileToLocalStorage(byte[] remoteFile, string filePath)
{
try
{
LocalResource myIO = RoleEnvironment.GetLocalResource("MyTestCache");
// Creates directory if it doesn't exist (ie the first time)
if (!Directory.Exists(myIO.RootPath + "/thumbnails"))
{
Directory.CreateDirectory(myIO.RootPath + "/thumbnails");
}
string PathToFile = Path.Combine(myIO.RootPath + "/thumbnails", filePath);
var path = filePath.Split(Char.Parse("/"));
// Creates the directory for the content item (GUID)
if (!Directory.Exists(Path.Combine(myIO.RootPath + "/thumbnails", path[0])))
{
Directory.CreateDirectory(Path.Combine(myIO.RootPath + "/thumbnails", path[0]));
}
// Writes the file to local storage.
File.WriteAllBytes(PathToFile, remoteFile);
}
catch (Exception ex)
{
// do some exception handling
return;
}
}

Check ACLs. In SDK 1.3 by default web roles are started in full IIS worker process, using Network Service as identity of application pool. Make sure Network Service account has permissions to execute operations you expect. In your case you are trying to create a sub-directory, so most probably you need at least Write permission. If your role also modifies ACLs on this directory, you need to grant Full access to this directory.

Related

How to store file into inetpub\wwwroot instead of local machine folder on UWP application

I am currently developing a UWP application for my school project and one of the pages allows the user to take a picture of themselves. I created the feature by following this tutorial: CameraStarterKit
For now I am storing the pictures taken on my desktop's picture folder. But the requirement of my project is to store the pictures taken in a folder called "Photos" under inetpub\wwwroot.
I dont really understand what wwwroot or IIS is... hence, I have no idea how I should modify my codes and store them into the folder.
Here are my codes for storing on my local desktop:
private async Task TakePhotoAsync()
{
idleTimer.Stop();
idleTimer.Start();
var stream = new InMemoryRandomAccessStream();
//MediaPlayer mediaPlayer = new MediaPlayer();
//mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/camera-shutter-click-03.mp3"));
//mediaPlayer.Play();
Debug.WriteLine("Taking photo...");
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
try
{
var file = await _captureFolder.CreateFileAsync("NYPVisitPhoto.jpg", CreationCollisionOption.GenerateUniqueName);
Debug.WriteLine("Photo taken! Saving to " + file.Path);
var photoOrientation = CameraRotationHelper.ConvertSimpleOrientationToPhotoOrientation(_rotationHelper.GetCameraCaptureOrientation());
await ReencodeAndSavePhotoAsync(stream, file, photoOrientation);
Debug.WriteLine("Photo saved!");
}
catch (Exception ex)
{
// File I/O errors are reported as exceptions
Debug.WriteLine("Exception when taking a photo: " + ex.ToString());
}
}
For the storing of the files:
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, StorageFile file, PhotoOrientation photoOrientation)
{
using (var inputStream = stream)
{
var decoder = await BitmapDecoder.CreateAsync(inputStream);
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
await encoder.BitmapProperties.SetPropertiesAsync(properties);
await encoder.FlushAsync();
}
}
}
I would add an answer since there are tricky things about this requirement.
The first is the app can only access a few folders, inetpub is not one of them.
Using brokered Windows runtime component (I would suggest using FullTrustProcessLauncher, which is much simpler to develop and deploy) can enable UWP apps access folders in the same way as the traditional desktop applications do.
While this works for an ordinary folder, the inetpub folder, however, is different that it requires Administrators Privileges to write to, unless you turn UAC off.
The desktop component launched by the app does not have the adequate privileges to write to that folder, either.
So it think an alternative way would be setting up a virtual directory in IIS manager that maps to a folder in the public Pictures library, and the app saves picture to that folder.
From the website’s perspective, a virtual directory is the same as a real folder under inetpub, what differs is the access permissions.
Kennyzx is right here that you cannot access inetpub folder through your UWP application due to permissions.
But if your application fulfills following criteria then you can use Brokered Windows Component(a component within your app) to copy your file to any location in the system.
Your application is a LOB application
You are only targetting desktop devices(I assume this will be true because of your requirement)
You are using side-loading for your app installation and distribution.
If all three are Yes then use Brokered Windows Component for UWP, it's not a small thing that can be showed here on SO using an example. So give worth a try reading and implementing it.

Azure Blob Storage to host images / media - fetching with blob URL (without intermediary controller)

In this article, the author provides a way to upload via a WebAPI controller. This makes sense to me.
He then recommends using an API Controller and a dedicated service method to deliver the blob:
public async Task<HttpResponseMessage> GetBlobDownload(int blobId)
{
// IMPORTANT: This must return HttpResponseMessage instead of IHttpActionResult
try
{
var result = await _service.DownloadBlob(blobId);
if (result == null)
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
// Reset the stream position; otherwise, download will not work
result.BlobStream.Position = 0;
// Create response message with blob stream as its content
var message = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(result.BlobStream)
};
// Set content headers
message.Content.Headers.ContentLength = result.BlobLength;
message.Content.Headers.ContentType = new MediaTypeHeaderValue(result.BlobContentType);
message.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = HttpUtility.UrlDecode(result.BlobFileName),
Size = result.BlobLength
};
return message;
}
catch (Exception ex)
{
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
Content = new StringContent(ex.Message)
};
}
}
My question is - why can't we just reference the blob URL directly after storing it in the database (instead of fetching via Blob ID)?
What's the benefit of fetching through a controller like this?
You can certainly deliver a blob directly, which then avoids using resources of your app tier (vm, app service, etc). Just note that, if blobs are private, you'd have to provide a special signed URI to the client app (e.g. adding a shared access signature) to allow this URI to be used publicly (for a temporary period of time). You'd generate the SAS within your app tier.
You'd still have all of your access control logic in your controller, to decide who has the rights to the object, for how long, etc. But you'd no longer need to stream the content through your app (consuming cpu, memory, & network resources). And you'd still be able to use https with direct storage access.
Quite simply, you can enforce access control centrally when you use a controller. You have way more control over who/what/why is accessing the file. You can also log requests pretty easily too.
Longer term, you might want to change the locations of your files, add a partitioning strategy for scalability, or do something else in your app that requires a change that you don't see right now. When you use a controller you can isolate the client code from all of those inevitable changes.

Remote File Accessing from Sharepoint Application Page

In my Sharepoint Application Page, I'm trying to copy a file from a Network Shared Folder.. And my code's like below..
try
{
File.Copy("\\MShare\Public\Test.txt", "C:\Temp\Test.txt", true);
LblMessage.Text = "File copied.";
}
catch (Exception ex)
{
LblMessage.Text = ex.ToString() + " - " + ex.Message;
}
It's working well if I test the same code in ASP.NET Website.. But I'm getting error as follow with SP Application Page..
System.UnauthorizedAccessException: Access to the path '\\MShare\Public\Test.txt' is denied. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite) at System.IO.File.Copy(String sourceFileName, String destFileName, Boolean overwrite) at TestApp.PullingFile.ButGet_Click(Object sender, EventArgs e) - Access to the path '\\MShare\Public\Test.txt' is denied.
I've tried implementing impersonation by following this post.. Not working..
And I tried by changing at web.config with <trust level="WSS_Medium" originUrl="" /> also..
By default SharePoint uses impersonating. Meaning your code runs under the credentials of the current user. This user has not (and should not have) access to the server's file system.
What you can do is revert to the system accounts credentials in order to access the file system:
SPSecurity.RunWithElevatedPrivileges(() =>
{
File.Copy("\\MShare\Public\Test.txt", "C:\Temp\Test.txt", true);
});
What you have to keep in mind:
The system account (application pool account) has not necessarily access to the file system (least privileges scenario). (SO question)
The system account (application pool account) has not necessarily access to the network share.
Any user accessing your application page can execute your file copy code. You have to care about authorization yourself.
Last but not least:
Why do you have to copy the file to the server's file system after all? Do you need it physically on the server or is this just temporary (as one could guess by the path).

azure reading mounted VHD

I am developing "azure web application".
I have created drive and drivePath static members in WebRole as follows:
public static CloudDrive drive = null;
public static string drivePath = "";
I have created development storage drive in WebRole.OnStart as follows:
LocalResource azureDriveCache = RoleEnvironment.GetLocalResource("cache");
CloudDrive.InitializeCache(azureDriveCache.RootPath, azureDriveCache.MaximumSizeInMegabytes);
CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
// for a console app, reading from App.config
//configSetter(ConfigurationManager.AppSettings[configName]);
// OR, if running in the Windows Azure environment
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});
CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
CloudBlobClient blobClient = account.CreateCloudBlobClient();
blobClient.GetContainerReference("drives").CreateIfNotExist();
drive = account.CreateCloudDrive(
blobClient
.GetContainerReference("drives")
.GetPageBlobReference("mysupercooldrive.vhd")
.Uri.ToString()
);
try
{
drive.Create(64);
}
catch (CloudDriveException ex)
{
// handle exception here
// exception is also thrown if all is well but the drive already exists
}
string path = drive.Mount(azureDriveCache.MaximumSizeInMegabytes, DriveMountOptions.None);
IDictionary<String, Uri> listDrives = Microsoft.WindowsAzure.StorageClient.CloudDrive.GetMountedDrives();
drivePath = path;
The drive keeps visible and accessible till execution scope remain in WebRole.OnStart, as soon as execution scope leave WebRole.OnStart, drive become unavailable from application and static members get reset (such as drivePath get set to "")
Am I missing some configuration or some other error ?
Where's the other code where you're expecting to use drivePath? Is it in a web application?
If so, are you using SDK 1.3? In SDK 1.3, the default mode for a web application is to run under full IIS, which means running in a separate app domain from your RoleEntryPoint code (like OnStart), so you can't share static variables across the two. If this is the problem, you might consider moving this initialization code to Application_Begin in Global.asax.cs instead (which is in the web application's app domain).
I found the solution:
In development machine, request originate for localhost, which was making the system to crash.
Commenting "Sites" tag in ServiceDefinition.csdef, resolves the issue.

Sharepoint Privileges

When checking in a document I execute a web service within the ItemCheckingInEvent. In Dev, no problems. I deployed the app out and it turns out I don't have enough privileges to read a configuration file. My code reads a config file to create the WCF proxy. The real issue is how can I get a return back from my function if I use the SPSecurity.RunWithElevatedPrivileges function?
For example:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
// exec service call
});
// need data from service call here
Just declare your working object before the elevated delegate, and assign it inside:
object myServiceData = null;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
myServiceData = DoServiceStuff();
});
//do things with myServiceData

Resources