ASP.NET ActiveDirectoryMembershipProvider and port 445 (SMB)

This post has been republished via RSS; it originally appeared at: IIS Support Blog articles.

NOTE: ASP.NET Membership, including the ActiveDirectoryMembershipProvider, are deprecated and no longer recommended for use. For new development please using more modern authentication methods, such as ADFS, OAuth, etc.

 

Under-the-hood, the ASP.NET ActiveDirectoryMembershipProvider uses System.DirectoryServices (S.DS) APIs to do the legwork. A lot of the work in the S.DS namespace is done by the Win32 AD DS APIs. During the initialization phase of the provider, some APIs are called that use RPC-over-SMB when communicating with a DC. Port 445 is designated for SMB.

 

Note: using other classes to perform LDAP communication doesn't require port 445, but 445 is still required when supplying an LDAP URI to the provider.

 

You cannot use the ActiveDirectoryMembershipProvider on the Azure App Service platform because outgoing traffic to port 445 is blocked, regardless of the destination. When attempting to use the provider on that platform, you will encounter an error that looks something like this:

Message: Access is denied.
(D:\home\site\wwwroot\web.config line 78)
Exception type: System.Configuration.ConfigurationErrorsException
Stack trace: 
at System.Web.Security.Membership.Initialize()
at [redacted]

Message: Access is denied.
Exception type: System.UnauthorizedAccessException
Stack trace: 
at System.DirectoryServices.ActiveDirectory.DirectoryContext.IsContextValid(DirectoryContext context, DirectoryContextType contextType)
at System.DirectoryServices.ActiveDirectory.DirectoryContext.isServer()
at System.DirectoryServices.ActiveDirectory.Domain.GetDomain(DirectoryContext context)
at System.Web.Security.DirectoryInformation.InitializeDomainAndForestName()
at System.Web.Security.ActiveDirectoryMembershipProvider.Initialize(String name, NameValueCollection config)
at [redacted]
at System.Web.Configuration.ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)

Message: Access is denied.
Exception type: System.Runtime.InteropServices.COMException
Stack trace: 
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.ActiveDirectory.DirectoryContext.IsContextValid(DirectoryContext context, DirectoryContextType contextType)

 

If you're using this provider and there's a firewall dropping/blocking port 445, then you'll see something like this error:

Exception type: System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException

Message: The specified domain or server could not be contacted.

(this actually results in a System.Configuration.Provider.ProviderException to be thrown once the above is caught internally)
   at System.Web.Security.DirectoryInformation.InitializeDomainAndForestName()
   at System.Web.Security.ActiveDirectoryMembershipProvider.Initialize(String name, NameValueCollection config)
   at System.Web.Security.Membership.InitializeSettings(Boolean initializeGeneralSettings, RuntimeConfig appConfig, MembershipSection settings)
   at System.Web.Security.Membership.Initialize()
   at System.Web.Security.Membership.get_Provider()

 

Both failures actually occur at the same place, but the result for the two scenarios is slightly different due to the internal exception-handling code.

 

If you want to work around using port 445, then I believe (not tested myself) you can point the provider to an ADAM/AD LDS instance instead. However, getting this up and running probably costs way more management overhead and time vs. using more modern auth methods in the first place.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.