Pergunta

We are trying to save a file temporarily from the SharePoint 2010 Server to a shared folder in the network from a custom application page.

This part is done in the code behind file of the application page in C#. If we debug the solution / page on the SharePoint Server itself, it works all fine, but when we try to call the page from a client machine, we always get the error

"Access denied"

at the step while creating the file on the shared folder.

Now our question is, which user account do we have to give access to the shared folder? We already tried different accounts, but nothing help yet.

Can anyone give a hint?

Foi útil?

Solução

You're probably facing a "double-hop" issue: the connection to the share folder is done in the context of the calling user. This works fine when browsing the server locally, but not in normal cases, where the server does not know the user password, only a token of it. Thus, it cannot authenticate against the file share as the initial user.

One common way to workaround this, is to establish the connection as the identity of the application pool: whoever browses the application triggers a connection to the file share as the same "service" identity (and you grant permissions on the file share only to that app pool identity, the one set in IIS). Reverting to the identity of the app pool is known as a "revert-to-self" operation. Do that only for the portion of code you need it. And it's then your responsability to check whether the current user is allowed post to that share.

Code to "revert-to-self" may be simple in ASP.NET environment:

using (HostingEnvironment.Impersonate())
{
// Access to the file share will be done as the app pool identity, password is known by the process
}

There's other techniques to "revert-to-self" but that's the simplest I know of.
You could also impersonate a given user (not the app pool's one), but that means storing the associated password somewhere... I don't recommend that.

Outras dicas

You will need to impersonate the user while accessing shared folder with the user who has write access on shared folder.

Add a "ImpersonateUser.cs" class file in your solution and paste below code in it. Replace the namespace name with your namespace.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace YourNameSpaceName
{
    class ImpersonateUser : IDisposable
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

        [DllImport("kernel32", SetLastError = true)]
        private static extern bool CloseHandle(IntPtr hObject);

        private IntPtr userHandle = IntPtr.Zero;
        private WindowsImpersonationContext impersonationContext;

        public ImpersonateUser(string user, string domain, string password)
        {
            if (!string.IsNullOrEmpty(user))
            {
                // Call LogonUser to get a token for the user
                bool loggedOn = LogonUser(user, domain, password,
                    9 /*(int)LogonType.LOGON32_LOGON_NEW_CREDENTIALS*/,
                    3 /*(int)LogonProvider.LOGON32_PROVIDER_WINNT50*/,
                    out userHandle);
                if (!loggedOn)
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                // Begin impersonating the user
                impersonationContext = WindowsIdentity.Impersonate(userHandle);
            }
        }

        public void Dispose()
        {
            if (userHandle != IntPtr.Zero)
                CloseHandle(userHandle);
            if (impersonationContext != null)
                impersonationContext.Undo();
        }
    }
}

And in your application page add below code and inside this insert your code to call/write shared folder. In parameters, pass username, domain and password of the user who has write access on shared folder.

using (new ImpersonateUser(UserName, Domain, Password))
{
 Your code here to access network folder
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a sharepoint.stackexchange
scroll top