Active Directory is funny.

Or should I say "permissions in Active Directory are funny."

I find that whenever I'm "stuck" on a problem for a good chunk of the day (AD or not) , about 80% of the time it's a permissions issue.  A couple of days ago I was stuck on an issue that I knew was a permissions issue, but I couldn't figure out why.  I mean, here I was, supposedly something of an development expert in directory services, but I couldn't get my DirectoryServices code to delete a simple AD object.  I could create objects, but I couldn't delete them.

Now, at this particular client they've tightened down the screws in their environment substantially, so simply increasing my permissions willy-nilly was out of the question.  No domain admin privileges here.  I'm not even sure any of the developers on this project even use Active Directory Users & Computers, they seem to only use home-grown LDAP tools for examining AD.  They are able to delete items with one particular home-grown tool, but it was written in VB - in all it's COM, late-binding, who-knows-what's-really-lurking-under-this-IUnknown-interface glory.

Has anyone ever tried to peer into the ObjectSecurity class?  It's not for the faint of heart.  And it wasn't something that I was going to be able to decipher in an afternoon.  So I downloaded the old Windows 2003 admin pack, installed it on my XP development box, and went into all the gory details that are AD ACLs.

The question was, why could the old VB code delete the object when my DirectoryServices code not do it?  According to AD Users & Computers, the credentials I was using did not have "delete" permission on the object.  I knew that.  That's what "access denied" usually means.  How could I explain this to the fellow who was successfully deleting with the VB code and expected me to do the same?  DirectoryEntry.DeleteTree() simply would not work. 

However, upon further examination, I could see that the OU that I was dealing with did allow my credentials to create and delete child objects.  Hmm...  One more quick test confirmed it.  Although DirectoryEntry.DeleteTree() failed, with the OU I could do DirectoryEntry.Children.Remove(objectInQuestion).  That's just crazy.  Boggles the mind.  But it works.

Of course, if the AD admins want to save another developer further grief (and there's no reason to believe they would - I know some sadistic infrastructure folks), then they'll just add the delete permission and avoid further confusion.


 
October 26, 2007
@ 08:58 PM

You might be saying to yourself, wouldn't this be your first big idea? Well, no. I just haven't talked about a lot of them before. I need something "enterprisey" (and I don't mean that in a bad way) to occupy my learning time, which is generally about 10pm to 2am. I've tried a few things – checking out http://rentacoder.com or http://topcoder.com, or thought of a few ideas, like writing a text based game or a utility, working on an open-source project, or starting an open-source project. They seem to last for a couple days and then I become disinterested.

I think I've found something that I may be able to sink my digital teeth into for awhile. Membership/Role Providers & Portals. Except for the default SQL provider, and there's nothing wrong with that, the others are over bloated and too tightly coupled. The AD Membership & Role providers, for instance, are a big pile of… well, you get the idea. And the documentation is lousy. I mean, none of the code for one ever works the way I expect, and the configurations are incomprehensible. There's no separation of concerns, and you can't even TEST one outside of ASP.NET. What about the ASP.NET MVC Framework? We'll need something that's testable, and we'll need Models, Views, and Controllers/Presenters since the idea of "web-controls" may largely go out the window. Same for Monorail right now. Perhaps with NHibernate as a data-access scheme you could do something interesting. log4net could be used to capture instrumentation statistics in a DB or ADAM.

Here's one – Do you hate to extend AD just to accommodate the AD Membership Provider? Me too. I've messed up AD on more than one occasion doing that. How about we "extend" AD into a SQL Server DB, but keep the other authentication mechanisms elsewhere? How about allowing people to use multiple unique values in a directory (AD, SQL, ADAM, etc.) as login name, such as username, UPN, email address, customer number, etc.

And how come there aren't any "starter portals" out there where you can go out and do all the good things that put a face on these providers to the public. Single Sign On? It's a chore, but doable right now. Let's make it easy. I'm committing myself to it! <tongueInCheek>at least until I get bored with it and move on</tongueInCheek>


 
May 28, 2007
@ 07:03 PM

I spent a good chunk of one morning last week explaining in an email to some colleagues how some code I'd written for the MIIS GroupPopulator worked. Someone wrote back and said I should just put this in my blog for posterity – it sounds like a good idea to me, so…

In Microsoft Identity Integration Server 2003, the GroupPopulator is definitely the most difficult piece of MIIS to "grok" in my opinion.

These are the steps of the synchronization process (for groups):

  • Run GroupPopulator.exe – explained below – the output of which is a file with the .LDIF extension
  • MIIS - Import the .LDIF file
  • MIIS - Synchronize the LDIF Management Agent
  • MIIS - Export new group information to whatever MA(s) you like, such as AD
  • MIIS – Delta-import group information back from AD (or whatever) to confirm a successful export

GroupPopulator.exe is the key to the whole operation.  It takes group information out of a database somewhere, SQL Server for exampleand puts it into a form in which MIIS can better digest.  Yes, MIIS has both SQL Server Management Agent and Oracle Management Agent types, but for groups the LDIF file describes the relationship between groups and their members better than can be done via the database Management Agents.

The code GroupPopulator that MIIS comes with depends on an additional table that holds meta-data for querying you different SQL groups, but I prefer to simply make my own doggone views for the different groups and leave it at that – it's also clearer in my opinion. So you end up with an LDIF file that looks something like the following (this may not be exact, but):

 

DN: cn=dseelinger,OU=employees,DC=emc,DC=COM

objectClass: user

givenName: Doug

sn: Seelinger

guid: {12345-67890-…}

etc…

 

DN: cn=juser,OU=employees,DC=emc,DC=COM

objectClass: user

givenName: Joe

sn: user

guid: {22345-67890-…}

etc…

 

DN: cn=madmin,OU=employees,DC=emc,DC=COM

objectClass: user

givenName: Mary

sn: Admin

guid: {32345-67890-…}

etc…

 

uid: AppDev

objectClass: group

member: {12345-67890-…}

member: {22345-67890-…}

member: {32345-67890-…}

 

uid: Group2

objectClass: group

member: {12345-67890-…}

member: {22345-67890-…}

member: {32345-67890-…}

etc…

 

The GUIDs actually come out of MIIS and are guids for the existing metaverse entries as you'll see from the code.  It is critical that both the users and groups appear in the LDIF file as I've shown.  When I was developing it (based off of the "group poulator" sample application from Microsoft that comes with MIIS), I assumed that since my people already existed in the MIIS Metaverse that I wouldn't have to have them listed in the LDIF file preceding the group definitions.  I was wrong.  When you import this file into MIIS, MIIS realizes that the guids with the groups in the LDIF reference the guids for the people in the LDIF, and thus are really person objects.  And when you Synchronize the LDIF MA, MIIS associates those people in those groups with their entry in AD (or ADAM, in your case apparently).  Thus, when you export the AD groups, it's exporting the correct values for the "member" AD attribute.

The other nice thing about re-implementing the Group Populator via TDD was that the Testing C# project can be considered the "specifications" for the GroupPopulator program, since each test confirms one of the requirements (that's one reason I love Test Driven Development).