c# - app - AD Group membership search crashes app for all users but me!

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • maxx233
    New Member
    • Nov 2007
    • 32

    c# - app - AD Group membership search crashes app for all users but me!

    I'm trying to get my program checking Active Directory to see if the user is a member of certain groups. I got it working, tested, etc. So I was very surprised when I deployed the program (just copying the .exe to their computer as I have in the past) and it wouldn't work for anyone!

    I've tried it from multiple computers under multiple users, and it only runs under my username, but then works fine from any computer when *I* log in. I had a coworker with the same local and domain privileges and group memberships as me log into a computer and it wouldn't even work under her login! The group-checking function is done under a method called authenticateUse r(), and if I just skip the call to that method the program works fine when deployed to all users - so that rules out file-level security. I'm fresh out of ideas and can't seem to find anything online. If anyone knows offhand what might be the problem that'd be great. Is there a way to debug from VS05 under a different user-name? That way I could at least track down more detail on the problem. Only other detail I can think to mention is that this is the first change I've made since migrating to a Vista machine, which I *hate* btw (still with VS05). Let me know if you have any ideas, my code is below:

    Code:
    private void authenticateUser()
            {
                 DirectoryEntry de = new DirectoryEntry();
                de.Path = "WinNT://myDomain/" + SystemInformation.UserName.ToString() + ",user";
                _Teller = de.Properties["FullName"].Value.ToString();
                _Client = SystemInformation.ComputerName.ToString();
                Program._Teller = _Teller;
    
    //THE ABOVE WORKS FINE TO FIND THE LOGGED-IN USER'S NAME, HAS BEEN IN PRODUCTION FOR SEVERAL VERSIONS
    
                DirectoryEntry DE = new DirectoryEntry("LDAP://myDomain.com");
                DirectorySearcher search = new DirectorySearcher();
                search.SearchRoot = DE;
                search.Filter = "(givenName=" + SystemInformation.UserName.ToString() + ")";
                search.PropertiesToLoad.Add("memberOf");
    
    // THE ABOVE IS NEW, ALONG WITH ANYTHING RELATED BELOW
    
                try
                {
                    SearchResult result = search.FindOne();
    
    //I THINK THE ABOVE LINE IS WHERE THE FAILURE ULTIMATELY OCCURS
    
                    int propertyCount = result.Properties["memberOf"].Count;
                    string dn;
                    for (int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
                    {
                        dn = (string)result.Properties["memberOf"][propertyCounter];
                        try { dn = dn.Replace("CN=", ""); } catch { }
                        try { dn = dn.Replace("OU=", ""); } catch { }
                        try { dn = dn.Remove(dn.IndexOf(",")); } catch { }
                        switch (dn)
                        {
                            case "Auditor":
                                if (_SupervisorLevel < 2) { _SupervisorLevel = 2; }
                                break;
                            case "Cashier":
                                if (_SupervisorLevel < 3) { _SupervisorLevel = 3; }
                                break;
                            case "Supervisor":
                                if (_SupervisorLevel < 5) { _SupervisorLevel = 5; }
                                break;
                            case "Assistant Manager":
                                if (_SupervisorLevel < 7) { _SupervisorLevel = 7; }
                                break;
                            case "Manager":
                                if (_SupervisorLevel < 9) { _SupervisorLevel = 9; }
                                break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("Error: " + ex.Message);
                }
    
    
                if (_SupervisorLevel == 2)
                {
                    //Do Stuff
    
                }
                if (_SupervisorLevel >= 3)
                {
                    //Do Stuff      
                }
                if (_SupervisorLevel >= 5)
                {
                    //Do Stuff
                }
            }
  • Plater
    Recognized Expert Expert
    • Apr 2007
    • 7872

    #2
    Are you able to discover which line caused the failure?
    What was the exception?

    I got "object reference not set to an instance of an object" right around:
    int propertyCount = result.Properti es["memberOf"].Count;

    (I did notice and remember to change the "mydomain" to my actual domain)

    Comment

    • maxx233
      New Member
      • Nov 2007
      • 32

      #3
      Originally posted by Plater
      Are you able to discover which line caused the failure?
      What was the exception?

      I got "object reference not set to an instance of an object" right around:
      int propertyCount = result.Properti es["memberOf"].Count;

      (I did notice and remember to change the "mydomain" to my actual domain)
      No, I'm not able to figure out where I'm having issues - when I hit F5 to begin debugging it works fine (because I'm logged in as me)... if I take the .exe it produces though and drop it on another computer it will only run when I'm logged into that pc. Is there any way to run debugging as a different user?

      I believe that's the same place I'm having issues - when the exe fails on the test machine and i debug that, it says the 'object reference not set' error, but I can't trace down exactly where it's coming from other than my authenticateUse r() method.

      But I don't understand why running it as a different user with appropriate permissions would cause a hangup there when it works fine for my account.

      Comment

      • Plater
        Recognized Expert Expert
        • Apr 2007
        • 7872

        #4
        You could make a special "debug" version or your program with Console.Writeli ne()s (or MessageBox.Show ()s) before every line of the function, the last one to show will tell you what line it crashed on?

        I also did this (had it return a datatable of all the properties it found)
        Code:
        private DataTable authenticateUser()
        {
        	DataTable dt = new DataTable();
        	dt.Columns.Add("Name");
        	dt.Columns.Add("Value");
          string mydomain = "mydomain";
          int _SupervisorLevel = 0;
          string _Teller = "";
          string _Client = "";
        
          DirectoryEntry de = new DirectoryEntry();
          de.Path = "WinNT://"+mydomain+"/" + SystemInformation.UserName.ToString() + ",user";
          _Teller = de.Properties["FullName"].Value.ToString();
          _Client = SystemInformation.ComputerName.ToString();
          //Program._Teller = _Teller;
        
          DirectoryEntry DE = new DirectoryEntry("LDAP://" + mydomain);
          DirectorySearcher search = new DirectorySearcher();
          search.SearchRoot = DE;
          //search.Filter = "(givenName=" + SystemInformation.UserName.ToString() + ")";
          //search.PropertiesToLoad.Add("memberOf");
        
          try
          {
        	  SearchResult result = search.FindOne();
        	  foreach (string PropertyName in result.Properties.PropertyNames)
        	  {
        	    DataRow dr = dt.NewRow();
        	    dr["Name"] = PropertyName;
        	    string valstring = "";
        	    ResultPropertyValueCollection rvpc = result.Properties[PropertyName];
        	    for (int i = 0; i < rvpc.Count; i++)
        	    {
        	    	valstring += o.ToString() + "\r\n";
        	    }
        	    dr["Value"] = valstring;
        	    dt.Rows.Add(dr);
        	  }
              
          }
          catch (Exception ex)
          {
              throw new Exception("Error: " + ex.Message);
          }
        }
        Then I looked at it in a DataGridView, there was nothing about "memberof" or "givenName"

        Comment

        • maxx233
          New Member
          • Nov 2007
          • 32

          #5
          Originally posted by Plater
          You could make a special "debug" version or your program with Console.Writeli ne()s (or MessageBox.Show ()s) before every line of the function, the last one to show will tell you what line it crashed on?

          I also did this (had it return a datatable of all the properties it found)
          Code:
          private DataTable authenticateUser()
          {
          	DataTable dt = new DataTable();
          	dt.Columns.Add("Name");
          	dt.Columns.Add("Value");
            string mydomain = "mydomain";
            int _SupervisorLevel = 0;
            string _Teller = "";
            string _Client = "";
          
            DirectoryEntry de = new DirectoryEntry();
            de.Path = "WinNT://"+mydomain+"/" + SystemInformation.UserName.ToString() + ",user";
            _Teller = de.Properties["FullName"].Value.ToString();
            _Client = SystemInformation.ComputerName.ToString();
            //Program._Teller = _Teller;
          
            DirectoryEntry DE = new DirectoryEntry("LDAP://" + mydomain);
            DirectorySearcher search = new DirectorySearcher();
            search.SearchRoot = DE;
            //search.Filter = "(givenName=" + SystemInformation.UserName.ToString() + ")";
            //search.PropertiesToLoad.Add("memberOf");
          
            try
            {
          	  SearchResult result = search.FindOne();
          	  foreach (string PropertyName in result.Properties.PropertyNames)
          	  {
          	    DataRow dr = dt.NewRow();
          	    dr["Name"] = PropertyName;
          	    string valstring = "";
          	    ResultPropertyValueCollection rvpc = result.Properties[PropertyName];
          	    for (int i = 0; i < rvpc.Count; i++)
          	    {
          	    	valstring += o.ToString() + "\r\n";
          	    }
          	    dr["Value"] = valstring;
          	    dt.Rows.Add(dr);
          	  }
                
            }
            catch (Exception ex)
            {
                throw new Exception("Error: " + ex.Message);
            }
          }
          Then I looked at it in a DataGridView, there was nothing about "memberof" or "givenName"
          I got it figured out. It was a stupid mistake on my part (go figure) ;) I somehow misunderstood the definition of givenName - it just happened to work for me because of what my username is and what my name is. That's why it wouldn't work for anyone else though - they weren't so fortunate. What I was really looking for there instead of givenName as my filter, was sAMAccountName - the login account as seen by AD. So after replacing that it works fine - my SystemInformati on.Username matches up with the sAMAccountName, it filters by that so it's just looking at my AD object (or the AD object of whoever's logged in and using my app), and then iterates through the groups I belong to (at least the ones I directly belong to) and matches up the best one for this app. Thanks for your help on it, I appreciate it!

          Maxx

          Comment

          • Plater
            Recognized Expert Expert
            • Apr 2007
            • 7872

            #6
            So did the MemberOf thing work for you?
            I happen to know I'm in the DomainAdmins group but I saw no group memberships listed?

            Comment

            • maxx233
              New Member
              • Nov 2007
              • 32

              #7
              Originally posted by Plater
              So did the MemberOf thing work for you?
              I happen to know I'm in the DomainAdmins group but I saw no group memberships listed?
              Yeah, it's working good for me now. Loads the groups into 'result', and then iterates through them to check for membership. You'd probably have to edit the filtering I'm doing below (see notes in code), but other than that it should be good. Here's the relevant code I've got

              Code:
                      private void authenticateUser()
                      {
                          DirectoryEntry DE = new DirectoryEntry("LDAP://myDomain.com");
                          DirectorySearcher search = new DirectorySearcher();
                          search.SearchRoot = DE;
                          search.Filter = "(sAMAccountName=" + SystemInformation.UserName.ToString() + ")";
                          search.PropertiesToLoad.Add("memberOf");
              
                          try
                          {
                              SearchResult result = search.FindOne();
                              int propertyCount = result.Properties["memberOf"].Count;
                              string dn;
                              for (int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
                              {
                                  dn = (string)result.Properties["memberOf"][propertyCounter];
                                  try { dn = dn.Replace("CN=", ""); } catch { }
                                  try { dn = dn.Replace("OU=", ""); } catch { }
                                  try { dn = dn.Remove(dn.IndexOf(",")); } catch { }
              
              // THE ABOVE MAY NEED TO BE EDITTED TO REFLECT YOUR ORGANIZATION'S AD STRUCTURE.  IT'S JUST FILTERING OUT ALL THE UNWANTED STRUCTURE/LOCATION INFO FOR THE GROUP NAMES
              
                              }
                          }
                          catch (Exception ex)
                          {
                              throw new Exception("Error: " + ex.Message);
                          }
              }

              Comment

              • Plater
                Recognized Expert Expert
                • Apr 2007
                • 7872

                #8
                It did in fact work without me changing anything except inserting my own domain.
                Out came all the groups I was registered in. The code knocked it down to only the first group, but stepping through showed me all of them.

                Interesting, but now I've forgotten what you used this code for?

                Comment

                • maxx233
                  New Member
                  • Nov 2007
                  • 32

                  #9
                  Originally posted by Plater
                  It did in fact work without me changing anything except inserting my own domain.
                  Out came all the groups I was registered in. The code knocked it down to only the first group, but stepping through showed me all of them.

                  Interesting, but now I've forgotten what you used this code for?
                  I'm using it for authentication/setting permissions on a program we've got running downstairs.

                  The department that uses it has fairly high turnover, so I wanted to relieve the pain for everyone involved of having that department's managers maintain an integrated user DB for this program - so instead when we make the users' AD accounts upstairs in IT we now assign them as a member of a group in AD pertaining to their access level in this program (programX user, programX supervisor, programX manager, etc)... Voila! All the user has to do is login to their machine with a single account, and it checks group membership when they run this program, and assigns permissions within the program accordingly. Easy for us to administer, painless for department managers, less confusing for the users, and less paperwork.

                  Maxx

                  Comment

                  Working...