I recently built a program that parses a remote file from \some_server\c$\directory\file.xls and it works fine on my local machine as just a normal aspx page.
Then I put the program into web part
form on my VM SharePoint server and I
get this error: Access to the path
'\some_server\c$\directory\file.xls'
is denied.
The file is shared to Domain\Authenticated Users so I am not sure why it would be denied? Is it possible my SharePoint is trying to call it with a local or network service account? How can I get it to read? Thank you.
Salamander is right, SharePoint doesn't run with trust to do this.
Changing the trust level for SharePoint in it's web.config from WSS_Medium to Full is the quick solution, but there are security implications..
Just a quick note, you could be running into the classic NTLM Double-Hop issue. You can authenticate to the front end, but because the front end does not have your password, it cannot then authenticate to a resource on another server.
Running with Elevated priviliges, and setting permissions based on the Application Pool identity could be one way of moving your forward.
I think you will need RunWithElevatedPrivleges which will make SharePoint use the application pool account. Also keep in mind you will have to make sure that application pool account has access to that network share. Avoid using full trust.
Can you explain further what exactly setting the trust level does for you?
I would think that if your app pool identity is a domain account you can use SPSecurity.RunWithElevatedPrivileges to use the app pool credentials to access the file. Or, use impersonate to explicitly pass another account's credentials.
SharePoint usually runs in a separate application pool. Please check the identity of this application pool.
I think to be able to access network path, your code has to run in FULL TRUST, which I don't think SharePoint does.
Why not store the file in SharePoint so you have better access to it? Put it in a hidden library and access it using SPSecurity.RunWithElevatedPrivledges.
There are caveats to RWEP. Any reference to SPSite and SPWeb obtained from the SPContext (ie SPContext.Current.Site) will still run under the privledges of the logged on user. You must explicity create a reference inside the RWEP delegate.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(SPContext.Current.Site.Url))
{
using (SPWeb web = site.OpenWeb())
{
//... Do something with SPWeb
}
}
});
If you need to access the file from outside sharepoint to update it with existing processes you can use the file share path which is available for all SPDocumentLibrary's but going to Actions --> Open with Windows Explorer to obtain the network path.
Related
I'm updating an Excel complement I made 2-3 years ago with C#. The goal is to get some files that are stored on a SharePoint site, copy them locally and then open them. I have permission to access the SharePoint site, but I have no admin right over the setting of the SharePoint (it is run by our IT service and the company Security is tight regarding data protection). We use MFA to log in to our Windows session and after that we can access the SharePoint and other services without need to input our password again. Until now I have used the code below, and it still work perfectly:
using Microsoft.SharePoint.Client;
using OfficeDevPnP.Core;
string tempFileName = System.IO.Path.GetTempPath() + "filename.xlsx";
AuthenticationManager mgr = new AuthenticationManager();
ClientContext context = mgr.GetWebLoginClientContext("https://xxx.sharepoint.com/teams/mypage");
FileInformation fileinfo = File.OpenBinaryDirect(context, "ServerRealtivePath");
context.ExecuteQuery();
System.IO.FileStream fStream = new System.IO.FileStream(tempFileName, System.IO.FileMode.Create);
await fileinfo.Stream.CopyToAsync(fStream);
fStream.Close();
fileinfo.Stream.Close();
So why try to fix something that is not broken… yet? The NuGet package SharePointPnPCoreOnline containing the OfficeDevPnP NameSpace is now marked as being retired and it is recommended to use PnPFramework instead. But the PnPFramework do not contained the AuthenticationManager.GetWebLoginClientContext() method. With the ever-growing need for data protection and new technology, I’m expecting the current method will stop working at some point. Do you have an equivalent method to connect to a sharepoint using a more modern way?
I don’t have any permission to register the app with Azure and I’m guessing it will be a big No from our IT service. I don’t mind asking the user to input his login at some point if needed. I never used REST or GRAPH API but if it can help, I can look into it. I want the right to access the files base on the current user permission. If the user doesn’t have permission to access the specified file, I don’t want the app to be able to download it.
I’m open to suggestions, Thanks
For my tool, I've just reworked the code from the GetWebLoginClientContext, it's neither big nor complicated. Here is also a newer version of it. So, what's inside: a simple form with a web browser control (that is based on Internet Explorer). When the browser control authenticates the user, the code gets the authentication cookies from the browser control using the platform web browser API, and uses that in the subsequent calls to SharePoint.
What can break here: Internet Explorer (and thus, the browser control) is deprecated, and the support for it ended last year. If the authentication window stops working when opened from a browser control, that would be a problem.
I've "fixed" that for myself by using the WebView2 instead of the browser control, and since it's evergreen, it should be fine. It also provides API to get cookies that we need to call the SharePoint.
I don't think the approach with cookie authentication is a problem by itself, but they may change cookies some day and then the app may need to be updated correspondingly then if that happens.
A more "robust" approach would be to register an application anyway in Azure AD (actually you don't absolutely have to ask your admins to register the app, you can register one for yourself without asking anyone, in your own "organization").
With this approach, the user must consent to use the app (to allow the app to access the data in the organization). The admin consent may be required, but it depends on organization settings (by default it's not required, user consent is good enough).
Please note that connecting using an "app" is actually more secure because when you grant access to an app, you only give it specific permissions (i.e. you get an intersection of the user permissions and the permissions that were granted to the app). When connecting as a user (i.e. using the "cookies" approach above), you get full access (i.e. you can do anything the user can).
Another point, for the app you don't really have to build anything on the web (no website is actually needed); the "callback url" to get the access token can be hosted in the application itself (localhost), or the app can be configured to use device code.
I am implementing an application that will create a folder on the NTFS File Server.
For that, I have set up the distributed environment. Meaning, I have machine on which I have hosted my C# Web API and I have NTFS file server on which I have to create folders.
I want my API to create a folder on NTFS machine. How can I do that?
Do I need to share NTFS Drive/Folder to create a subfolder? If so, then with whom I need to share a NTFS folder (either server user or IIS_USRS)?
Is there any other way to create a folder without sharing a drive/folder on NTFS folder.
When I have done this in the past I have done it through a temporary impersonation. For example...
using (Impersonator impersonate = new Impersonator(#"UserName", "Password", "Domain"))
{
//Create directory or copy files across the network
}
I believe I lifted my impersonator code from A small C# Class for impersonating a User
Case 1:
if web server and file server are in the same domain, you can consider to use a domain user, and created a shared folder on NTFS server and grant full access for the domain user accessing it. (depends on your requirements).
On web server, for the web application pool, set the domain user as the identity/credential to run the pool. so you can easily use IIS management tool to update it if password gets changed. for the authentication, you can use whatever you want based on requirements, but remember while you call the code to create folders on NTFS server, you need to use app pool user. (for example, if you turn on impersonation on a different user in authentication, in your code, you need to do impersonation using the pool user.)
Case 2,
web server and file server are not in the same domain, I usually will set up a ftp server on the file server to allow specific users to access it (creating folders and upload files....). Otherwise when you may need your IT administrator to make File server domain trust web server domain, then you can do the same thing as case 1.
About impersonation code, it could be something like:
//get the identity of an appPool
using(System.Security.Principal.WindowsIdentity wid = System.Security.Principal.WindowsIdentity.GetCurrent())
{
using (System.Security.Principal.WindowsImpersonationContext ImpersonationCtx = wid.Impersonate())
{
//creating folders, uploading files to UNC path...
ImpersonationCtx.Undo();
}
}
If your case is one of this, hope it helps.
I am trying to create a Directory in .NET using Directory.CreateDirectory, I followed the directions here to give access permission but I am still getting an UnauthorizedAccessException. Does anyone have any advice? Note, this is a web application that uses the IIS7 server.
In the directory you are attempting to create a new directory, make sure that your app pool user has Read/Write permissions for that directory. You have to specifically do that in addition to adding the user to the user groups.
2 more potential issues (+1 to user959729):
you are creating directory at different place than you think you are (i.e. you building path wrong)
the code runs under impersonated account (user's or anonymous) and such user does not have permissions to create folder (to verify try check System.Environment.UserName before creating directory). To fix you need to run code as process account.
I am currently creating a folder and writing a file to the folder that need to be create on a file server that we have. When i do a localhost test, it work perfectly but when i access the website from outside the localhost and from another pc. It said that
System.UnauthorizedAccessException: Access to the path 'My File Server
URL' is denied
ASP.NET is not authorized to access the requested resource. Consider
granting access rights to the resource to the ASP.NET request
identity. ASP.NET has a base process identity (typically
{MACHINE}\ASPNET on IIS 5 or Network Service on IIS 6) that is used if
the application is not impersonating. If the application is
impersonating via , the identity will be
the anonymous user (typically IUSR_MACHINENAME) or the authenticated
request user.
To grant ASP.NET access to a file, right-click the file in Explorer,
choose "Properties" and select the Security tab. Click "Add" to add
the appropriate user or group. Highlight the ASP.NET account, and
check the boxes for the desired access.
But the thing is that i have already set the identity impersonate="true" in the web.config and it still didn't work. My web server is running on Winder Server 2003 and IIS 6
Any advice and help will be deeply appreciated
Thanks
Brandon
You need to grant write, modify permission to the Users group for that file/folder.
Check your IIS Authentication setting and make sure that Anonymous authentication is enabled.
Hi Guys i manage to find the solution to it
If u are creating a folder, using this code before file or folder creation
WindowsImpersonationContext ctx = WindowsIdentity.Impersonate(IntPtr.Zero);
// Insert the create code here
ctx.Undo();
Well i do not know if this is the best solution. if anyone know the downside or implication of this code please share and comment.
no harm knowing more
I have a web application that needs to read (and possibly write) files from a network share. I was wondering what the best way to do this would be?
I can't give the network service or aspnet accounts access to the network share. I could possibly use impersonation.
The network share and the web application are both hosted on the same domain and I can create a new user on the domain specifically for this purpose however I'm not quite sure how to join the dots between creating the filestream and specifying the credentials to use in the web application.
Unfortunately the drive isn't mapped as a network drive on the machine, it's only available to me as a network share so unfortunately I can't make a transparent call.
There is one problem I can think of with impersonation... I can only impersonate one user per application domain I think but I'm happy to be corrected. I may need to write this file to several different shares which means I may have to impersonate several users.
I like the idea of creating a token... if I can do that I'll be able to ask the use up front for their credentials and then dynamically apply the security and give them meaningful error messages if access is denied... I'm off to play but I'll be back with an update.
Given everyone already has domain accounts. Try IIS integrated authentication. You will get an ugly logon box off network but your creds should pass down to the file share.
#lomaxx
Are you saying that only you have perms to the share or that you manually mapped it to a drive letter. If the later you can use ucn \host\share the same way you would use a c:\shared_folder.
Random
Would it be a burden to mirror the share to a local folder on the host? I hear ROBOCOPY is pretty handy.
Another Idea. Run IIS on your target share you can read via http and if you need to write investigate webdav.
I've had no problems connecting to network shares transparently as if they were local drives. The only issue you may have is what you mentioned: having the aspnet account gain access to the share. Impersonation is probably the best way to do this.
You should be able to use any filestream objects to access the network share as long as it has a drive letter on the server machine.
Impersonation worked well for me in this scenario. We had a wizard that uploaded a zip file through the website, but we load balanced the site. Therefore needed to setup a way to save the file on all the machines.
There are many different ways to do it. We decided to make all requests to run under the user we setup and just added the web.config entry and setup the security permissions on the folders for the user. This kb article explains the setup very well.
You do have some options and one of of those is impersonation as you mentioned. However, another one I like to use and have used in the past is a trusted service call. Let's assume for a moment that it's always much safer to limit access through IIS to ensure there are as few holes as possible. With that let's go down this road.
Build a WCF service that has a couple of entry points and the interface might look like this.
public interface IDocumentService
{
public string BuildTrustedRelationship(string privateKey);
public byte[] ReadFile(string token, string fileName);
public void WriteFile(string token, string fileName, byte[] file);
}
Now, you can host this service via a Windows service very easily and so now all you need to do is on Application_start build the relationship with the service to get your token and you're off to the races. The other nice thing here is that this service is internal, trusted, and I've even hosted it on the file server before and so it's much easier to grant permissions to this operation.
If you can create a new AD user, I think the simplest solution is to have the Application Pool run under that AD account's authority, which would mean your application is now running as the AD user. You would need to add the AD user to the IIS Worker Process Group on the machine running your application. Then as long as your AD user has write permissions on the network share, you should be able to use the UNC path in your file operations.