“Access Denied” when trying to connect to remote IIS server - C#

[亡魂溺海] 提交于 2019-12-03 22:12:59

If it is an identity problem, you could try setting your IIS 5.1 application to use Integrated Windows Authentication, and then add the following to you web.config on your IIS5.1 web site under system.web to enable impersonation.

<identity impersonate="true"/>
<authentication mode="Windows" />

Since this is an ASP.NET application, it runs in an Application Pool of IIS. This Application Pool runs using a specific user("Local System", "Network Service" or another user).

Does this user have enough rights to connect to a remote server ?

See MSDN for more info.

This looks like it may be a double-hop issue. If you are impersonating the current user of a website using NTLM, that impersonation is only valid on that server (your IIS 5.1 server in this case). If you try to connect to another server using the web site, you are actually going to have issues as it cannot pass the token to another server that was used during impersonation. The same is true if you are debugging your site through your machine, going to another box. Your local machine is authenticating you, but it cannot impersonate you to another server.

All of the solutions I have used in the past require you to hard code the app pool to use an account that has permissions, set the annony. account to a domain account with permissions on the other machine, or use a windows service running on the IIS 5.1 machine, under a domain account, to connect to the other server.

If you are using Kerberos, this wouldn't apply, but AD uses NTLM by default.

Where exactly are you trying to read too? Is it in under the same path as your application?

When I had this problem, I found that simply authenticating my self on a Windows file share solved the problem. From experience, I think that WMI/ADSI/COM doesn't have great support for not-already-authenticated users. I believe this issue occurs when you're not associated with a Windows domain.

If it is indeed a NTLM doublehop issue you could use the SETSPN utility to create service principal named instances for your target IIS servers.

Then you could go into Active Directory, and then allow the computer object (basically the NETWORK SERVICE or LOCAL SERVICE principals) to delegate its credentials to a correctly registered SPN.

Then you could hop-hop-hop all over the place! But, be warned! People can hurt themselves on sharp pointy things when you enable double-hop!

Good KB articles to read:

http://support.microsoft.com/kb/929650

I believe that DirectoryEntry.Exists silently ignores any credentials supplied and uses the creds of the authenticated user. This seems to match the behaviour you've described. For AD work, we never use it for this reason.

I'm sort of stumped at the moment as to why you can't get this working. There is a temporary work around you could try. When instantiating the DirectoryEntry object you could use one of the following constructor overloads:

public DirectoryEntry(
    string path,
    string username,
    string password
)

Documented at: MSDN: DirectoryEntry Constructor (String, String, String)

...or...

public DirectoryEntry(
    string path,
    string username,
    string password,
    AuthenticationTypes authenticationType
)

Documented at: MSDN: DirectoryEntry Constructor (String, String, String, AuthenticationTypes)

As it happens I'm building a test AD environment on my virtual server box for a new project to do similar stuff. When I get it up and running I'll have a play around to see if I can reproduce the problem you're encountering. In the meantime let us know what happens if you try these constructor overloads referenced above.

Update (In answer to Michaels comment):

For reasons that evade me just now, we couldn't use DirectoryEntry.Exists() in a particular scenario, there is this snippet of code that gets called now and again in one of our apps:

public static bool MetabasePathExists(string metabasePath)
{
  try
  {
    using(DirectoryEntry site = new DirectoryEntry(metabasePath))
    {
      if(site.Name != String.Empty)
      {
        return true;
      }
      return false;
    }
  }
  catch(COMException ex)
  {
    if(ex.Message.StartsWith("The system cannot find the path specified"))
    {
      return false;
    }
    LogError(ex, String.Format("metabasePath={0}", metabasePath));
    throw;
  }
  catch(Exception ex)
  {
    LogError(ex, String.Format("metabasePath={0}", metabasePath));
    throw;
  }
}

You could replace the constructor with one of the ones from above. Admittedly it's a stab in the dark :).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!