November Happy Hour will be moved to Thursday December 5th.

Help - Active Directory Role Provider - "An invalid dn syntax has been specified"

Vote:
 

We're trying to evaluate EpiServer and, we are trying to get Active Directory integration up and running. I can get authenticated, and have specified an AD group to allow access to the dashboard/admin areas. However, whenever I try to search for a group to set up rights for our website, I get an error. 

An invalid dn syntax has been specified.

I have installed EPIServer 9 in a development environment. I have tried adjusting with clear LDAP insted of secure, changing the attributeMapUsername, among other things. 

Sadly, it appears several people have blogged about this very problem (for example http://world.episerver.com/blogs/Leif-Bostrom/Dates/2010/7/Exposing-the-root-cause-of-ActiveDirectoryRoleProvider-errors/ ), however each references another now defunct blog instead of actually posting the info. If anyone remembers the secret this old blog article revealed, that may help.  The blog I linked appears to think it is related to items in our domain with special characters, but I cannot control that and have no way to identify them if that is the case.

Relevent portions of web.config with account names, password, domain names replaced.






type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ActiveDirectoryProviderConnection"
connectionProtection="Secure"
connectionUsername="domain\account"
connectionPassword="password"
enableSearchMethods="true"
attributeMapUsername="sAMAccountName" />







type="EPiServer.Security.ActiveDirectoryRoleProvider, EPiServer"
connectionStringName="ActiveDirectoryProviderConnection"
connectionProtection="Secure"
connectionUsername="domain\account"
connectionPassword="password"
attributeMapUsername="sAMAccountName" />




COMPLETE ERROR

Server Error in '/' Application.

An invalid dn syntax has been specified.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.DirectoryServices.DirectoryServicesCOMException: An invalid dn syntax has been specified.


Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.


Stack Trace:

[DirectoryServicesCOMException (0x80072032): An invalid dn syntax has been specified.
]
   System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) +576737
   System.DirectoryServices.DirectoryEntry.Bind() +45
   System.DirectoryServices.DirectoryEntry.get_AdsObject() +40
   System.DirectoryServices.PropertyCollection.Contains(String propertyName) +26
   EPiServer.Security.AdsiDataFactory.CreateDirectoryDataFromDirectoryEntry(DirectoryEntry entry) +189
   EPiServer.Security.AdsiDataFactory.GetEntry(String distinguishedName) +173
   EPiServer.Security.ActiveDirectoryRoleProvider.GetAllRoles() +224
   EPiServer.Security.MultiplexingRoleProvider.GetAllRoles() +163
   EPiServer.Security.MembershipSecurityEntityProvider.SearchRoles(String partOfName, Int32 startIndex, Int32 maxRows, Int32& totalCount) +184
   EPiServer.Security.MembershipSecurityEntityProvider.Search(String partOfValue, String claimType) +41
   EPiServer.UI.Edit.MembershipBrowser.SearchRolesByName(String query) +143
   EPiServer.UI.Edit.MembershipBrowser.PopulateGroupsUserList(String name, String email) +160
   EPiServer.UI.Edit.MembershipBrowser.OnLoad(EventArgs e) +232
   System.Web.UI.Control.LoadRecursive() +68
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4498
#169214
Oct 25, 2016 18:30
Vote:
 

Hi, Hans,

If it's the same issue I had, here is the code for the role provider:

    public class AdRoleProvider : ActiveDirectoryRoleProvider
    {
        public AdRoleProvider()
        {
            DirectoryDataFactory = new AdsiDataFactory();
        }
    }

And here is the AdsiDataFactory you need:

/// <summary>
    /// This is basically a disassembled AdsiDataFactory written by EPiServer
    /// The only method that is changed is CreateDirectoryDataFromDirectoryEntry
    /// due to an unfriendly exception that is thrown on the server that needs to be cought
    /// see: http://world.episerver.com/Blogs/Leif-Bostrom/Dates/2010/7/Exposing-the-root-cause-of-ActiveDirectoryRoleProvider-errors/ 
    /// </summary>
    public class AdsiDataFactory : DirectoryDataFactory
    {
        private const string _rootCacheKey = "EPiServer:DirectoryServiceRoot";
        private const string _cacheKeyEntryPrefix = "EPiServer:DirectoryServiceEntry:";
        private const string _cacheKeyFindOnePrefix = "EPiServer:DirectoryServiceFindOne:";
        private const string _cacheKeyFindAllPrefix = "EPiServer:DirectoryServiceFindAll:";
        private const string _distingushedNameAttribute = "distinguishedName";
        private const string _objectClassAttribute = "objectClass";
        private const string _reservedCharacters = "\r\n+\\\"<>;/";
        private string _connectionString;
        private string _username;
        private string _password;
        private AuthenticationTypes _connectionProtection;
        private List<string> _propertiesToLoad;
        private TimeSpan _cacheTimeout;
        private string _baseConnectionString;

        /// <summary>
        /// Gets or sets the connection string.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// The connection string.
        /// </value>
        /// 
        /// <remarks>
        /// The string for connecting to the Active Directory server. It should be in the format LDAP://dns.name.for.machine or LDAP://dns.name.for.active.directory.domain
        /// 
        /// </remarks>
        public string ConnectionString
        {
            get
            {
                return this._connectionString;
            }
            protected set
            {
                this._connectionString = value;
            }
        }

        /// <summary>
        /// Gets or sets the user name.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// The user name.
        /// </value>
        /// 
        /// <remarks>
        /// The user name to use for connecting to the Active Directory domain as defined by ConnectionString.
        /// 
        /// </remarks>
        public string Username
        {
            get
            {
                return this._username;
            }
            protected set
            {
                this._username = value;
            }
        }

        /// <summary>
        /// Gets or sets the password.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// The password.
        /// </value>
        /// 
        /// <remarks>
        /// The password used, together with the Username, to connect to the Active Directory domain.
        /// 
        /// </remarks>
        public string Password
        {
            get
            {
                return this._password;
            }
            protected set
            {
                this._password = value;
            }
        }

        /// <summary>
        /// Gets or sets the connection protection.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// The connection protection.
        /// </value>
        /// 
        /// <remarks>
        /// Defines the type and level of protection for the Active Directory communications.
        /// 
        /// </remarks>
        public AuthenticationTypes ConnectionProtection
        {
            get
            {
                return this._connectionProtection;
            }
            protected set
            {
                this._connectionProtection = value;
            }
        }

        /// <summary>
        /// Gets or sets the page size
        /// 
        /// </summary>
        /// 
        /// <remarks>
        /// The maximum number of objects the server can return in a paged search. The default is zero, which means do not do a paged search.
        /// 
        /// </remarks>
        public int PageSize { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:EPiServer.Security.AdsiDataFactory"/> class.
        /// 
        /// </summary>
        public AdsiDataFactory()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:EPiServer.Security.DirectoryDataFactory"/> class.
        /// 
        /// </summary>
        /// <param name="connectionString">The connection string.</param><param name="username">The username.</param><param name="password">The password.</param><param name="connectionProtection">The connection protection.</param><param name="absoluteCacheTimeout">The absolute cache timeout.</param>
        /// <remarks>
        /// Create and initialize an instance of this class for accessing Active Directory data.
        /// 
        /// </remarks>
        public AdsiDataFactory(string connectionString, string username, string password, AuthenticationTypes connectionProtection, TimeSpan absoluteCacheTimeout)
        {
            this._connectionString = connectionString;
            this._username = username;
            this._password = password;
            this._connectionProtection = connectionProtection;
            this._cacheTimeout = absoluteCacheTimeout;
            this.Initialize();
        }

        /// <summary>
        /// Initializes an instance of the <see cref="T:EPiServer.Security.DirectoryDataFactory"/> class.
        /// 
        /// </summary>
        /// <param name="config">The configuration data to use.</param>
        /// <remarks>
        /// This method is intended to be called from within a providers Initialize method. It will read its settings from the config parameter and
        ///             initialize this instance.
        ///             Required settings in config are:
        ///             connectionStringName = name of the connection string to use for connecting to the Active Directory server.
        ///             connectionUsername = username for the connection.
        ///             connectionPassword = password for the connection.
        /// 
        ///             Optional settings in config are:
        ///             connectionProtection = level of protection and security for the Active Directory connection. None or Secure (default).
        ///             cacheTimeout = how long cached Active Directory entries stys in the cache. Default is 10 minutes.
        /// 
        /// </remarks>
        public override void Initialize(NameValueCollection config)
        {
            this.GetParametersFromConfig(config);
            this.Initialize();
        }

        /// <summary>
        /// Adds a property to load on access to Active Directory.
        /// 
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <remarks>
        /// This class keeps a list of property names to query for whenever an Active Directory entry is retrieved. By calling this method you
        ///             can expand this list with custom properties.
        /// 
        /// </remarks>
        public override void AddPropertyToLoad(string propertyName)
        {
            if (this._propertiesToLoad.Contains(propertyName))
                return;
            this._propertiesToLoad.Add(propertyName);
            this.ClearCache();
        }

        /// <summary>
        /// Clears the Active Directory cache.
        /// 
        /// </summary>
        public void ClearCache()
        {
            HttpRuntime.Cache.Remove("EPiServer:DirectoryServiceRoot");
        }

        /// <summary>
        /// Gets a specific Active Directory entry as a DirectoryData object.
        /// 
        /// </summary>
        /// <param name="distinguishedName">Distinguished name of the entry.</param>
        /// <returns>
        /// A DirectoryData instance containing the properties defined by PropertiesToLoad.
        /// </returns>
        /// 
        /// <remarks>
        /// This method uses caching to speed up the operation, if the DirectoryData object is found in the cache,
        ///             no communication with the Active Directory domain will take place.
        /// 
        /// </remarks>
        public override DirectoryData GetEntry(string distinguishedName)
        {
            string cacheKey = "EPiServer:DirectoryServiceEntry:" + distinguishedName;
            DirectoryData directoryData = (DirectoryData)HttpRuntime.Cache[cacheKey];
            if (directoryData != null)
                return directoryData;
            using (DirectoryEntry directoryEntry = this.CreateDirectoryEntry(distinguishedName))
                directoryData = this.CreateDirectoryDataFromDirectoryEntry(directoryEntry, distinguishedName);
            if (directoryData != null)
                this.StoreInCache(cacheKey, (object)directoryData);
            return directoryData;
        }

        /// <summary>
        /// Find on Active Directory entry based on search filter.
        /// 
        /// </summary>
        /// <param name="filter">The filter, which is a LDAP query.</param><param name="scope">The scope at which to search.</param>
        /// <returns>
        /// A DirectoryData instance with the entry, or null if the search did not find an entry.
        /// </returns>
        /// 
        /// <remarks>
        /// This method uses caching to speed up the operation, if the DirectoryData object is found in the cache,
        ///             no communication with the Active Directory domain will take place.
        /// 
        /// </remarks>
        public override DirectoryData FindOne(string filter, SearchScope scope)
        {
            string cacheKey = "EPiServer:DirectoryServiceFindOne:" + filter + ((object)scope).ToString();
            DirectoryData directoryData = (DirectoryData)HttpRuntime.Cache[cacheKey];
            if (directoryData != null)
                return directoryData;
            using (DirectorySearcher directorySearcher = new DirectorySearcher(this.CreateDirectoryEntry(), filter, this._propertiesToLoad.ToArray(), scope))
            {
                directoryData = this.CreateDirectoryDataFromSearchResult(directorySearcher.FindOne());
                if (directoryData == null)
                    return (DirectoryData)null;
            }
            this.StoreInCache(cacheKey, (object)directoryData);
            return directoryData;
        }

        /// <summary>
        /// Finds all directory entries that match the filter criteria.
        /// 
        /// </summary>
        /// <param name="filter">The LDAP filter.</param><param name="scope">The search scope.</param><param name="sortByProperty">The property to sort directory entries by.</param>
        /// <returns>
        /// An IList of DirectoryData objects, sorted by the indicated property.
        /// 
        /// </returns>
        /// 
        /// <remarks>
        /// If sortByProperty is set to null, the list will be returned without sorting. This method will make use of caching, if the serach has already beem
        ///             done, the result will be returned without accessing Active Directory.
        /// 
        /// </remarks>
        public override IList<DirectoryData> FindAll(string filter, SearchScope scope, string sortByProperty)
        {
            string cacheKey = "EPiServer:DirectoryServiceFindAll:" + filter + ((object)scope).ToString();
            IList<DirectoryData> list = (IList<DirectoryData>)HttpRuntime.Cache[cacheKey];
            if (list != null)
                return list;
            using (DirectorySearcher directorySearcher = new DirectorySearcher(this.CreateDirectoryEntry(), filter, this._propertiesToLoad.ToArray(), scope))
            {
                directorySearcher.PageSize = this.PageSize;
                using (SearchResultCollection all = directorySearcher.FindAll())
                {
                    if (all == null)
                        return (IList<DirectoryData>)null;
                    if (sortByProperty == null)
                    {
                        list = (IList<DirectoryData>)new List<DirectoryData>(all.Count);
                        foreach (SearchResult result in all)
                            list.Add(this.CreateDirectoryDataFromSearchResult(result));
                    }
                    else
                    {
                        SortedList<string, DirectoryData> sortedList = new SortedList<string, DirectoryData>(all.Count);
                        foreach (SearchResult result in all)
                        {
                            DirectoryData fromSearchResult = this.CreateDirectoryDataFromSearchResult(result);
                            sortedList.Add(fromSearchResult.GetFirstPropertyValue(sortByProperty), fromSearchResult);
                        }
                        list = sortedList.Values;
                    }
                }
            }
            this.StoreInCache(cacheKey, (object)list);
            return list;
        }

        /// <summary>
        /// Creates a directory entry.
        /// 
        /// </summary>
        /// 
        /// <returns>
        /// An initialized <see cref="T:System.DirectoryServices.DirectoryEntry"/>
        /// </returns>
        /// 
        /// <remarks>
        /// The directory entry is configured with connection string, user credentials etc.
        /// 
        /// </remarks>
        protected DirectoryEntry CreateDirectoryEntry()
        {
            return new DirectoryEntry(this._connectionString, this._username, this._password, this._connectionProtection);
        }

        /// <summary>
        /// Creates a directory entry.
        /// 
        /// </summary>
        /// <param name="rootDistinguishedName">Distinguished name of the root where the directory entry is used.</param>
        /// <returns>
        /// An initialized <see cref="T:System.DirectoryServices.DirectoryEntry"/>, or null if <paramref name="rootDistinguishedName"/>
        ///             is not within the specified subtree for this instance.
        /// </returns>
        protected DirectoryEntry CreateDirectoryEntry(string rootDistinguishedName)
        {
            if (!this.IsWithinSubtree(rootDistinguishedName))
                return (DirectoryEntry)null;
            else
                return new DirectoryEntry(this._baseConnectionString + this.EscapeDistinguishedName(rootDistinguishedName), this._username, this._password, this._connectionProtection);
        }

        /// <summary>
        /// Escapes reserved characters in the distinguished name.
        /// 
        /// </summary>
        /// <param name="distinguishedName">The distinguished name.</param>
        /// <returns>
        /// The escaped representation of the string.
        /// </returns>
        /// 
        /// <remarks>
        /// The following characters will be escaped by prefixing them with a backslash (\): Carriage return, Linefeed, '+', '\', '"', '<', '>', ';', '/'
        /// 
        /// </remarks>
        protected string EscapeDistinguishedName(string distinguishedName)
        {
            StringBuilder stringBuilder = new StringBuilder(distinguishedName.Length);
            foreach (char ch in distinguishedName)
            {
                if ("\r\n+\\\"<>;/".IndexOf(ch) >= 0)
                    stringBuilder.Append('\\');
                stringBuilder.Append(ch);
            }
            return ((object)stringBuilder).ToString();
        }

        /// <summary>
        /// Creates a directory data object from a directory entry.
        /// 
        /// </summary>
        /// <param name="entry">The <see cref="T:System.DirectoryServices.DirectoryEntry"/>.</param>
        /// <param name="distinguishedName">AD name that has been searched for - transferred to this method by us in order to throw a proper error</param>
        /// <returns>
        /// A DirectoryData object populated with information from <paramref name="entry"/>.
        /// </returns>
        /// 
        /// <remarks>
        /// DirectoryData can be viewed as a Data Transfer Object, craeting an implementation-independent representation of
        ///             the data to avoid tying the implementetation too tightly to the System.DirectoryServices namespace.
        /// 
        /// </remarks>
        protected DirectoryData CreateDirectoryDataFromDirectoryEntry(DirectoryEntry entry, string distinguishedName)  
        { 
            if (entry == null)
            {   
                return null;   
            }   
            Dictionary<string, string[]> properties = new Dictionary<string, string[]>(this._propertiesToLoad.Count);
            
            foreach (string str in this._propertiesToLoad) 
            { 
                try 
                {  
                    if (entry.Properties.Contains(str)) 
                    { 
                        PropertyValueCollection values = entry.Properties[str];
                        string[] strArray = new string[values.Count]; 
                        for (int i = 0; i < values.Count; i++) 
                        { 
                            strArray[i] = values[i].ToString();  
                        }
                        properties.Add(str, strArray); 
                    }
                } 
                catch (DirectoryServicesCOMException ex) 
                {
                    StringBuilder sb = new StringBuilder();  
                    foreach (string s in this._propertiesToLoad)
                    { 
                        sb.Append(" | " + s); 
                    } 
                    throw new Exception("Error in CreateDirectoryDataFromDirectoryEntry!" + Environment.NewLine + 
                        "Value of last str: " + str + Environment.NewLine + 
                        "All Properties: " + sb + Environment.NewLine +  
                        "distinguishedName: " + distinguishedName, ex);
                } 
            } 
            return new DirectoryData(this.DistinguishedName(properties), entry.SchemaClassName, properties); 
        }

        /// <summary>
        /// Creates a directory data instance from search result.
        /// 
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns>
        /// The populated <see cref="T:EPiServer.Security.DirectoryData"/> instance.
        /// </returns>
        /// 
        /// <remarks>
        /// DirectoryData can be viewed as a Data Transfer Object, craeting an implementation-independent representation of
        ///             the data to avoid tying the implementetation too tightly to the System.DirectoryServices namespace.
        /// 
        /// </remarks>
        protected DirectoryData CreateDirectoryDataFromSearchResult(SearchResult result)
        {
            if (result == null)
                return (DirectoryData)null;
            Dictionary<string, string[]> properties = new Dictionary<string, string[]>(this._propertiesToLoad.Count);
            foreach (string index1 in this._propertiesToLoad)
            {
                if (result.Properties.Contains(index1))
                {
                    ResultPropertyValueCollection propertyValueCollection = result.Properties[index1];
                    string[] strArray = new string[propertyValueCollection.Count];
                    for (int index2 = 0; index2 < propertyValueCollection.Count; ++index2)
                        strArray[index2] = propertyValueCollection[index2].ToString();
                    properties.Add(index1, strArray);
                }
            }
            return new DirectoryData(this.DistinguishedName(properties), this.SchemaClassName(properties), (IDictionary<string, string[]>)properties);
        }

        /// <summary>
        /// Gets the distinguisheds name from a dictionary.
        /// 
        /// </summary>
        /// <param name="properties">The properties as collected from a <see cref="T:System.DirectoryServices.DirectoryEntry"/>.</param>
        /// <returns>
        /// A string with the distinguished name.
        /// </returns>
        /// 
        /// <remarks>
        /// Primarily used internally when converting from DirectoryEntry to DirectoryData.
        /// 
        /// </remarks>
        protected string DistinguishedName(Dictionary<string, string[]> properties)
        {
            return properties["distinguishedName"][0];
        }

        /// <summary>
        /// Gets the schema class name from a dictionary.
        /// 
        /// </summary>
        /// <param name="properties">The properties as collected from a <see cref="T:System.DirectoryServices.DirectoryEntry"/>.</param>
        /// <returns>
        /// A string with the schema class name.
        /// </returns>
        /// 
        /// <remarks>
        /// Primarily used internally when converting from DirectoryEntry to DirectoryData.
        /// 
        /// </remarks>
        protected string SchemaClassName(Dictionary<string, string[]> properties)
        {
            string str = string.Empty;
            string[] strArray = properties["objectClass"];
            if (strArray != null)
                str = strArray[strArray.Length - 1];
            return str;
        }

        /// <summary>
        /// Stores the data in cache.
        /// 
        /// </summary>
        /// <param name="cacheKey">The cache key.</param><param name="data">The data.</param>
        protected void StoreInCache(string cacheKey, object data)
        {
            if (HttpRuntime.Cache["EPiServer:DirectoryServiceRoot"] == null)
                HttpRuntime.Cache.Insert("EPiServer:DirectoryServiceRoot", new object());
            HttpRuntime.Cache.Insert(cacheKey, data, new CacheDependency((string[])null, new string[1]
      {
        "EPiServer:DirectoryServiceRoot"
      }), DateTime.Now.Add(this._cacheTimeout), Cache.NoSlidingExpiration);
        }

        /// <summary>
        /// Get value from from config and remove it if found.
        /// 
        /// </summary>
        /// <param name="config">The collection of configuration values.</param><param name="name">The name of the parameter.</param><param name="value">The value of the parameter.</param>
        /// <returns>
        /// True if the parameter was found, False otherwise.
        /// </returns>
        protected bool TryGetDestructive(NameValueCollection config, string name, out string value)
        {
            value = config[name];
            if (value != null)
                config.Remove(name);
            if (!string.IsNullOrEmpty(value))
                return true;
            value = (string)null;
            return false;
        }

        private void GetParametersFromConfig(NameValueCollection config)
        {
            string index;
            if (!this.TryGetDestructive(config, "connectionStringName", out index))
                throw new ProviderException("Required attribute connectionStringName not supplied.");
            ConnectionStringSettings connectionStringSettings = WebConfigurationManager.ConnectionStrings[index];
            if (connectionStringSettings == null)
                throw new ProviderException(string.Format("Connection string {0} not found.", (object)index));
            this._connectionString = connectionStringSettings.ConnectionString;
            if (string.IsNullOrEmpty(this._connectionString))
                throw new ProviderException(string.Format("Connection string {0} is empty.", (object)index));
            if (!this.TryGetDestructive(config, "connectionUsername", out this._username))
                throw new ProviderException("Required attribute connectionUsername not supplied.");
            if (!this.TryGetDestructive(config, "connectionPassword", out this._password))
                throw new ProviderException("Required attribute connectionPassword not supplied.");
            this._connectionProtection = AuthenticationTypes.Secure;
            string str;
            if (this.TryGetDestructive(config, "connectionProtection", out str))
            {
                try
                {
                    this._connectionProtection = (AuthenticationTypes)Enum.Parse(typeof(AuthenticationTypes), str, true);
                }
                catch
                {
                    throw new ProviderException(string.Format("Attribute connectionProtection has illegal value {0}, supported values are {1}.", (object)str, (object)string.Join(", ", Enum.GetNames(typeof(AuthenticationTypes)))));
                }
            }
            string s;
            if (this.TryGetDestructive(config, "cacheTimeout", out s))
            {
                if (!TimeSpan.TryParse(s, out this._cacheTimeout))
                    throw new ProviderException(string.Format("Attribute cacheTimeout has illegal value {0}, should be formatted as \"hours:minutes:seconds\"", (object)s));
            }
            else
                this._cacheTimeout = new TimeSpan(0, 10, 0);
        }

        /// <summary>
        /// Final initialization steps for a newly created instance.
        /// 
        /// </summary>
        private void Initialize()
        {
            this._propertiesToLoad = new List<string>(5);
            this._propertiesToLoad.Add("distinguishedName");
            this._propertiesToLoad.Add("objectClass");
            int num1 = this._connectionString.IndexOf("://");
            if (num1 < 0)
                throw new ProviderException(string.Format("Protocol specification missing from connection string {0}", (object)this._connectionString));
            int num2 = this._connectionString.IndexOf("/", num1 + 3);
            this._baseConnectionString = num2 >= 0 ? (num2 + 1 >= this._connectionString.Length ? this._connectionString : this._connectionString.Remove(num2 + 1)) : this._connectionString + "/";
            using (DirectoryEntry directoryEntry = this.CreateDirectoryEntry())
                this.RootDistinguishedName = directoryEntry.Properties["distinguishedName"][0].ToString();
        }
    }

Then, you only need to change the web.config to point to the new AD role provider instead of the built-in one:

<add name="ActiveDirectoryRoleProvider" type="YourNamespace.AdRoleProvider, YourNamespace, Version=1.0.0.0, Culture=neutral" connectionStringName="ActiveDirectoryProviderConnection" connectionUsername="x" connectionPassword="y" attributeMapUsername="z" />

Hope this helps :)

Marija

#170686
Oct 26, 2016 15:27
Vote:
 

Thanks Marija. We were able to do something similar last night and discovered a number of objects with \ and # characters that appear to cause the failure. Reviewing what you have helps find the best way to handle this so we can connect to our AD; we did a quick and dirty proof of concept fix to just fail to return invalid groups.

#170697
Oct 26, 2016 18:07
Vote:
 

I stumbled across this with the same problem! We modified the factory code to filter the AD list down to the small subset of groups we wanted to use for roles in the site (instead of the large list of Domain Groups in our forest).

Thanks for the code and help, Marija!

#174228
Jan 22, 2017 22:19
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.