<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Joe Kaplan - LDAP</title>
    <link>http://www.joekaplan.net/</link>
    <description>.NET. LDAP. Geekery.</description>
    <language>en-us</language>
    <copyright>Joseph E. Kaplan</copyright>
    <lastBuildDate>Wed, 12 Mar 2008 04:41:56 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.6264.0</generator>
    <managingEditor>blog@joekaplan.net</managingEditor>
    <webMaster>blog@joekaplan.net</webMaster>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=c59ba3ad-6e76-4aa0-9117-e52626283b4e</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,c59ba3ad-6e76-4aa0-9117-e52626283b4e.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,c59ba3ad-6e76-4aa0-9117-e52626283b4e.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=c59ba3ad-6e76-4aa0-9117-e52626283b4e</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
It seems like I've deteriorated into semi-annual blog posts.  Sigh.  At
least the discussion groups at <a href="http://www.directoryprogramming.net">www.directoryprogramming.net</a> continue
to flourish and we are seeing a nice uptick in activity on the ADFS board there. 
I think the writing may be on the wall for me as a blogger, but who knows.  Perhaps
I'll get back on the wagon.
</p>
        <p>
Anyway, thanks to all the people who came to see my talks at DEC this year. 
I hope you enjoyed visiting my town and you got a lot out of the conference itself. 
DEC is one of my favorites and I'm happy to see it continue to do well.  I got
a lot of nice feedback on both of my talks and I'm always interested to hear what
you thought.
</p>
        <p>
My first talk this year was on customizing ADFS.  To my knowledge, this type
of stuff has never been talked about publicly before, so the session was a bit of
an experiment.  I essentially tried to cover all the different types of things
you should and could do to ADFS V1 or 1.1 (2003 R2 server or 2008 server) to make
it do different things.  It started off discussing some cosmetics to apply to
the pages displayed by the FS, moved through ADAM account store tweaks and then covered
custom claim transformation modules and some advanced hacks/mods such as non-Windows
authentication.  Some of that stuff has been discussed here on this blog and
nearly all of it was based on stuff we've actually done at work, so basically real
world experience.  My fear was that the subject matter would be a little over
the audience's head since it wasn't introductory at all (assumed you already knew
ADFS pretty well) and covered some developer stuff which might have seemed alien to
many of the audience members who tend to be more of the IT Pro sort.  Still,
I think it was valuable stuff.
</p>
        <p>
I mentioned a sample custom claim transform module that I'd post the source to. 
I'll follow that up in a separate post shortly.
</p>
        <p>
The audiences for all the ADFS talks were pretty small by comparison to the big AD
talks, but this doesn't surprise me.  Not only is ADFS still a new thing, but
to a great extent it is a luxury for most DEC attendees to be able to go to those
sessions.  ADFS largely assumes that both the directory and the identity provisioning
stuff is all a solved problem and that we have rich repositories filled with security
principals whose identity is trustworthy and stuffed with useful metadata that can
be converted to claims.  For many, that is not (yet) a solved problem at all
and federated identity is still largely wishful thinking.  Still, you have to
start somewhere.
</p>
        <p>
My second talk was essentially the talk I've done at DEC now for 3 years, although
this time modified heavily to cover the new .NET 3.5 stuff in System.DirectoryServices.AccountManagement. 
I was really dreading this talk and didn't finish the slides for it before the conference,
so between the last minute PPT work and the anxiety, I only got about an hour of sleep.
</p>
        <p>
Still, the talk seemed to go off pretty well.  I was in the big room this time
and in one of the last slots of the conference, so I had low expectations for turnout. 
It seemed like I had a pretty good crowd though (not the Dean and Joe show, but I'll
take it!) and people seemed to be into it.  I think it was probably the best
version of that talk I've done to date, so all in all I'm quite happy.  I miss
having <a href="http://www.dunnry.com/blog/">Ryan</a> there to bounce stuff around
with, but so it goes.
</p>
        <p>
Thanks also to <a href="http://blogs.msdn.com/donovanf/">Donovan</a> for inviting
me up for his case studies talk and giving me an opportunity to talk about some of
the real world stuff we are doing with federation at work and talking about the process
and legal stuff as much as the technical aspects.  People clearly have as many
if not more questions about those things than the engineering parts.
</p>
        <p>
I think I finally get CardSpace now, especially as it applies to the enterprise, and
am looking forward to having a chance to get it running internally.  That should
be interesting.  Stuart, I need some bits I can actually deploy.  :) 
Thanks to <a href="http://pamelaproject.com/">Pamela Dingle</a> for coming to DEC
and bringing both the CardSpace love and the non-MS platform perspective.  I'm
anxious to go to a conference where everyone knows her and no one knows me at all
and see how I do.
</p>
        <p>
She's got a nice <a href="http://eternaloptimist.wordpress.com/2008/03/10/dec-2008-this-ones-for-you-wook/">follow
up</a> on the Wook Lee Challenge this year which I played a tiny role in.
</p>
        <p>
        </p>
        <p>
          <a href="http://www.joekaplan.net/content/binary/Customizing-ADFS.zip">Customizing-ADFS.zip
(1.06 MB)</a>
        </p>
        <p>
          <a href="http://www.joekaplan.net/content/binary/DotNet-DS-Programming.zip">DotNet-DS-Programming.zip
(1.27 MB)</a>
        </p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=c59ba3ad-6e76-4aa0-9117-e52626283b4e" />
      </body>
      <title>DEC 2008 Wrap Up and Materials</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,c59ba3ad-6e76-4aa0-9117-e52626283b4e.aspx</guid>
      <link>http://www.joekaplan.net/DEC2008WrapUpAndMaterials.aspx</link>
      <pubDate>Wed, 12 Mar 2008 04:41:56 GMT</pubDate>
      <description>&lt;p&gt;
It seems like I've deteriorated into semi-annual blog posts.&amp;nbsp; Sigh.&amp;nbsp; At
least the discussion groups at &lt;a href="http://www.directoryprogramming.net"&gt;www.directoryprogramming.net&lt;/a&gt; continue
to flourish and we are seeing a nice uptick in activity on the ADFS board there.&amp;nbsp;
I think the writing may be on the wall for me as a blogger, but who knows.&amp;nbsp; Perhaps
I'll get back on the wagon.
&lt;/p&gt;
&lt;p&gt;
Anyway, thanks to all the people who came to see my talks at DEC this year.&amp;nbsp;
I hope you enjoyed visiting my town and you got a lot out of the conference itself.&amp;nbsp;
DEC is one of my favorites and I'm happy to see it continue to do well.&amp;nbsp; I got
a lot of nice feedback on both of my talks and I'm always interested to hear what
you thought.
&lt;/p&gt;
&lt;p&gt;
My first talk this year was on customizing ADFS.&amp;nbsp; To my knowledge, this type
of stuff has never been talked about publicly before, so the session was a bit of
an experiment.&amp;nbsp; I essentially tried to cover all the different types of things
you should and could do to ADFS V1 or 1.1 (2003 R2 server or 2008 server) to make
it do different things.&amp;nbsp; It started off discussing some cosmetics to apply to
the pages displayed by the FS, moved through ADAM account store tweaks and then covered
custom claim transformation modules and some advanced hacks/mods such as non-Windows
authentication.&amp;nbsp; Some of that stuff has been discussed here on this blog and
nearly all of it was based on stuff we've actually done at work, so basically real
world experience.&amp;nbsp; My fear was that the subject matter would be a little over
the audience's head since it wasn't introductory at all (assumed you already knew
ADFS pretty well) and covered some developer stuff which might have seemed alien to
many of the audience members who tend to be more of the IT Pro sort.&amp;nbsp; Still,
I think it was valuable stuff.
&lt;/p&gt;
&lt;p&gt;
I mentioned a sample custom claim transform module that I'd post the source to.&amp;nbsp;
I'll follow that up in a separate post shortly.
&lt;/p&gt;
&lt;p&gt;
The audiences for all the ADFS talks were pretty small by comparison to the big AD
talks, but this doesn't surprise me.&amp;nbsp; Not only is ADFS still a new thing, but
to a great extent it is a luxury for most DEC attendees to be able to go to those
sessions.&amp;nbsp; ADFS largely assumes that both the directory and the identity provisioning
stuff is all a solved problem and that we have rich repositories filled with security
principals whose identity is trustworthy and stuffed with useful metadata that can
be converted to claims.&amp;nbsp; For many, that is not (yet) a solved problem at all
and federated identity is still largely wishful thinking.&amp;nbsp; Still, you have to
start somewhere.
&lt;/p&gt;
&lt;p&gt;
My second talk was essentially the talk I've done at DEC now for 3 years, although
this time modified heavily to cover the new .NET 3.5 stuff in System.DirectoryServices.AccountManagement.&amp;nbsp;
I was really dreading this talk and didn't finish the slides for it before the conference,
so between the last minute PPT work and the anxiety, I only got about an hour of sleep.
&lt;/p&gt;
&lt;p&gt;
Still, the talk seemed to go off pretty well.&amp;nbsp; I was in the big room this time
and in one of the last slots of the conference, so I had low expectations for turnout.&amp;nbsp;
It seemed like I had a pretty good crowd though (not the Dean and Joe show, but I'll
take it!) and people seemed to be into it.&amp;nbsp; I think it was probably the best
version of that talk I've done to date, so all in all I'm quite happy.&amp;nbsp; I miss
having &lt;a href="http://www.dunnry.com/blog/"&gt;Ryan&lt;/a&gt; there to bounce stuff around
with, but so it goes.
&lt;/p&gt;
&lt;p&gt;
Thanks also to &lt;a href="http://blogs.msdn.com/donovanf/"&gt;Donovan&lt;/a&gt; for inviting
me up for his case studies talk and giving me an opportunity to talk about some of
the real world stuff we are doing with federation at work and talking about the process
and legal stuff as much as the technical aspects.&amp;nbsp; People clearly have as many
if not more questions about those things than the engineering parts.
&lt;/p&gt;
&lt;p&gt;
I think I finally get CardSpace now, especially as it applies to the enterprise, and
am looking forward to having a chance to get it running internally.&amp;nbsp; That should
be interesting.&amp;nbsp; Stuart, I need some bits I can actually deploy.&amp;nbsp; :)&amp;nbsp;
Thanks to &lt;a href="http://pamelaproject.com/"&gt;Pamela Dingle&lt;/a&gt; for coming to DEC
and bringing both the CardSpace love and the non-MS platform perspective.&amp;nbsp; I'm
anxious to go to a conference where everyone knows her and no one knows me at all
and see how I do.
&lt;/p&gt;
&lt;p&gt;
She's got a nice &lt;a href="http://eternaloptimist.wordpress.com/2008/03/10/dec-2008-this-ones-for-you-wook/"&gt;follow
up&lt;/a&gt; on the Wook Lee Challenge this year which I played a tiny role in.
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.joekaplan.net/content/binary/Customizing-ADFS.zip"&gt;Customizing-ADFS.zip
(1.06 MB)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.joekaplan.net/content/binary/DotNet-DS-Programming.zip"&gt;DotNet-DS-Programming.zip
(1.27 MB)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=c59ba3ad-6e76-4aa0-9117-e52626283b4e" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,c59ba3ad-6e76-4aa0-9117-e52626283b4e.aspx</comments>
      <category>General;Identity Federation;LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=5c846938-9aba-467a-b1b0-99bbef193bcb</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,5c846938-9aba-467a-b1b0-99bbef193bcb.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,5c846938-9aba-467a-b1b0-99bbef193bcb.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=5c846938-9aba-467a-b1b0-99bbef193bcb</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I was lucky enough to attend DEC again this year and was even more lucky to have been
asked to speak due to an unfortunate last minute cancellation.  This year, I
presented on a variation of the same type of stuff that Ryan and I <a href="http://dunnry.com/blog/DEC2006WrapUpAndPresentationMaterial.aspx">presented
on at DEC 2006</a>.  This year, I had to fly solo as Ryan could not attend. 
:(
</p>
        <p>
Here's what we did differently this time around:
</p>
        <ul>
          <li>
No PowerShell (DEC already had 2 PowerShell sessions, so why bother?) 
</li>
          <li>
Focus on some new Longhorn LDAP and AD features (Fine Grained Password Policy) 
</li>
          <li>
A "slideware" overview of what's coming in .NET 3.5 "Orcas" with the new System.DirectoryServices.AccountManagement
namespace (formerly known as the Principal API).</li>
        </ul>
        <p>
I'd like to thank all of those who attended.  I hope you enjoyed the talk and
hope that some of you got free books.  I apologize if I could not accomodate
all of you.  :(  Thanks to the <a href="http://www.awprofessional.com/index.asp?rl=1">Addison-Wesley</a> marketing
team for providing the books for your enjoyment.
</p>
        <p>
For those of you interested in the Snippet Compiler tool I used in my demos, you can
find it <a href="http://www.sliver.com/dotnet/SnippetCompiler/">here</a>.
</p>
        <p>
The slides and code for the demos are attached and I did get around to converting
them to VB for all of you VB people (I'm a VB.NET guy too; I really don't know why
I coded all the demos in C# :)).  
</p>
        <p>
Note that my application of the "in chain" matching rule turns out to be incorrect
usage.  Don't do it like that!  Read more <a href="http://www.joekaplan.net/InChainMatchingRuleShouldNotBeUsedForTransitiveLinkExpansion.aspx">here</a>. 
I feel silly.
</p>
        <p>
Note that if you are confused about which API to use, S.DS or S.DS.P, I discussed
that in some detail <a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx">here</a>. 
There is really no right answer, but hopefully that helps.  
</p>
        <p>
To ask us any specific questions about LDAP programming, please use the book's <a href="http://www.directoryprogramming.net">discussion
forum</a>.  This is the only place that Ryan and I both use together.
</p>
        <p>
As always, DEC is a treat and I really enjoyed all the conversations and interaction
and am happy to see ADFS gaining a little traction.  Now, about that hot chicken...
</p>
        <a href="http://www.joekaplan.net/content/binary/DEC2007.zip">DEC2007.zip (536.52
KB)</a>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=5c846938-9aba-467a-b1b0-99bbef193bcb" />
      </body>
      <title>DEC 2007 Follow Up</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,5c846938-9aba-467a-b1b0-99bbef193bcb.aspx</guid>
      <link>http://www.joekaplan.net/DEC2007FollowUp.aspx</link>
      <pubDate>Fri, 27 Apr 2007 16:58:34 GMT</pubDate>
      <description>&lt;p&gt;
I was lucky enough to attend DEC again this year and was even more lucky to have been
asked to speak due to an unfortunate last minute cancellation.&amp;nbsp; This year, I
presented on a variation of the same type of stuff that Ryan and I &lt;a href="http://dunnry.com/blog/DEC2006WrapUpAndPresentationMaterial.aspx"&gt;presented
on at DEC 2006&lt;/a&gt;.&amp;nbsp; This year, I had to fly solo as Ryan could not attend.&amp;nbsp;
:(
&lt;/p&gt;
&lt;p&gt;
Here's what we did differently this time around:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
No PowerShell (DEC already had 2 PowerShell sessions, so why bother?) 
&lt;li&gt;
Focus on some new Longhorn LDAP and AD features (Fine Grained Password Policy) 
&lt;li&gt;
A "slideware" overview of what's coming in .NET 3.5 "Orcas" with the new System.DirectoryServices.AccountManagement
namespace (formerly known as the Principal API).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
I'd like to thank all of those who attended.&amp;nbsp; I hope you enjoyed the talk and
hope that some of you got free books.&amp;nbsp; I apologize if I could not accomodate
all of you.&amp;nbsp; :(&amp;nbsp; Thanks to the &lt;a href="http://www.awprofessional.com/index.asp?rl=1"&gt;Addison-Wesley&lt;/a&gt; marketing
team for providing the books for your enjoyment.
&lt;/p&gt;
&lt;p&gt;
For those of you interested in the Snippet Compiler tool I used in my demos, you can
find it &lt;a href="http://www.sliver.com/dotnet/SnippetCompiler/"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
The slides and code for the demos are attached and I did get around to converting
them to VB for all of you VB people (I'm a VB.NET guy too; I really don't know why
I coded all the demos in C# :)).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
Note that my application of the "in chain" matching rule turns out to be incorrect
usage.&amp;nbsp; Don't do it like that!&amp;nbsp; Read more &lt;a href="http://www.joekaplan.net/InChainMatchingRuleShouldNotBeUsedForTransitiveLinkExpansion.aspx"&gt;here&lt;/a&gt;.&amp;nbsp;
I feel silly.
&lt;/p&gt;
&lt;p&gt;
Note that if you are confused about which API to use, S.DS or S.DS.P, I discussed
that in some detail &lt;a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx"&gt;here&lt;/a&gt;.&amp;nbsp;
There is really no right answer, but hopefully that helps.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
To ask us any specific questions about LDAP programming, please use the book's &lt;a href="http://www.directoryprogramming.net"&gt;discussion
forum&lt;/a&gt;.&amp;nbsp; This is the only place that Ryan and I both use together.
&lt;/p&gt;
&lt;p&gt;
As always, DEC is a treat and I really enjoyed all the conversations and interaction
and am happy to see ADFS gaining a little traction.&amp;nbsp; Now, about that hot chicken...
&lt;/p&gt;
&lt;a href="http://www.joekaplan.net/content/binary/DEC2007.zip"&gt;DEC2007.zip (536.52
KB)&lt;/a&gt;&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=5c846938-9aba-467a-b1b0-99bbef193bcb" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,5c846938-9aba-467a-b1b0-99bbef193bcb.aspx</comments>
      <category>General;Identity Federation;LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=622e9be0-6539-4ddc-8096-820c33893ffc</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,622e9be0-6539-4ddc-8096-820c33893ffc.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,622e9be0-6539-4ddc-8096-820c33893ffc.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=622e9be0-6539-4ddc-8096-820c33893ffc</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Microsoft has added a new LDAP feature to AD in Windows 2003 SP2 and Longhorn server
called the LDAP_MATCHING_RULE_IN_CHAIN.  Essentially, it is an extension filter
type that allows you to search withing the content of a distinguished name-syntax
attribute and do matching throughout the entire chain of linked values instead of
just within the immediate values.  The docs are <a href="http://msdn2.microsoft.com/en-us/library/aa746475.aspx">here</a> and
the syntax looks like this:
</p>
        <p>
          <font face="Courier New">(memberOf:1.2.840.113556.1.4.1941:=CN=some group,CN=xxxx,DC=xxxx,DC=xxxx)</font>
        </p>
        <p>
I showed some examples of this in my talk at DEC where I used some searches with and
without the extension filter type to show traversal of some nested group membership.
</p>
        <p>
          <a href="http://dunnry.com/blog/">Ryan</a> also <a href="http://dunnry.com/blog/TransitiveLinkValueFilterEvaluation.aspx">wrote
about this</a> a while ago and discovered that while useful, this technique is very
slow for expanding group membership and it seems to be much faster to just use recursive
searches.
</p>
        <p>
As it turns out, the problem is that we were trying to use this feature incorrectly. 
The "In Chain" filter type should NOT be used for transitive link expansion! 
It is intended to be used for matching only.  Perhaps that's why they called
it LDAP_MATCHING_RULE_IN_CHAIN.  :)
</p>
        <p>
As such, you should really only use it in a base level query.  If you use the
filter shown above in a base level query, it will still tell you if the object that
is used as the search root is a member of the specified group anywhere in the nesting
chain, but it will perform fine.  If you use it for anything else, you are asking
for trouble.  
</p>
        <p>
Now, when will we get some sort of transitive link expansion widget that actually
works well for this purpose?
</p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=622e9be0-6539-4ddc-8096-820c33893ffc" />
      </body>
      <title>In Chain Matching Rule should not be Used for Transitive Link Expansion</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,622e9be0-6539-4ddc-8096-820c33893ffc.aspx</guid>
      <link>http://www.joekaplan.net/InChainMatchingRuleShouldNotBeUsedForTransitiveLinkExpansion.aspx</link>
      <pubDate>Fri, 27 Apr 2007 15:24:21 GMT</pubDate>
      <description>&lt;p&gt;
Microsoft has added a new LDAP feature to AD in Windows 2003 SP2 and Longhorn server
called the LDAP_MATCHING_RULE_IN_CHAIN.&amp;nbsp; Essentially, it is an extension filter
type that allows you to search withing the content of a distinguished name-syntax
attribute and do matching throughout the entire chain of linked values instead of
just within the immediate values.&amp;nbsp; The docs are &lt;a href="http://msdn2.microsoft.com/en-us/library/aa746475.aspx"&gt;here&lt;/a&gt; and
the syntax looks like this:
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;(memberOf:1.2.840.113556.1.4.1941:=CN=some group,CN=xxxx,DC=xxxx,DC=xxxx)&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
I showed some examples of this in my talk at DEC where I used some searches with and
without the extension filter type to show traversal of some nested group membership.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/"&gt;Ryan&lt;/a&gt; also &lt;a href="http://dunnry.com/blog/TransitiveLinkValueFilterEvaluation.aspx"&gt;wrote
about this&lt;/a&gt; a while ago and discovered that while useful, this technique is very
slow for expanding group membership and it seems to be much faster to just use recursive
searches.
&lt;/p&gt;
&lt;p&gt;
As it turns out, the problem is that we were trying to use this feature incorrectly.&amp;nbsp;
The "In Chain" filter type should NOT be used for transitive link expansion!&amp;nbsp;
It is intended to&amp;nbsp;be used for matching only.&amp;nbsp; Perhaps that's why they called
it LDAP_MATCHING_RULE_IN_CHAIN.&amp;nbsp; :)
&lt;/p&gt;
&lt;p&gt;
As such, you should really only use it in a base level query.&amp;nbsp; If you use the
filter shown above in a base level query, it will still tell you if the object that
is used as the search root is a member of the specified group anywhere in the nesting
chain, but it will perform fine.&amp;nbsp; If you use it for anything else, you are asking
for trouble.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
Now, when will we get some sort of transitive link expansion widget that actually
works well for this purpose?
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=622e9be0-6539-4ddc-8096-820c33893ffc" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,622e9be0-6539-4ddc-8096-820c33893ffc.aspx</comments>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=3d6db311-dd87-4148-9d56-d7f677867c77</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,3d6db311-dd87-4148-9d56-d7f677867c77.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,3d6db311-dd87-4148-9d56-d7f677867c77.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=3d6db311-dd87-4148-9d56-d7f677867c77</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
After some lofty goals of getting this blog jumpstarted back in the fall, I did just
the opposite and let it drop into a black hole.  To all of my faithful readers,
I humbly apologize.
</p>
        <p>
As part of an effort to gain some momentum again, I thought I'd try to rattle off
a quick post here.  Today's topic is intended as a continuation of my article
on series of <a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx">"things
you can do in System.DirectoryServices.Protocols that you can't do in System.DirectoryServices"</a>. 
We already discussed the ability to do <a href=" http://www.joekaplan.net/AnotherSDSPonlyFeatureDigestAuthentication.aspx">Digest
authentication</a> and <a href="http://www.joekaplan.net/Example1ForSDSPSSLCertificates.aspx">process
server certificates</a>.  Today's topic shows how to use S.DS.P's ability to
invoke arbitrary extended operations using the ExtendedRequest/ExtendedResponse message
types.
</p>
        <p>
Briefly, extended requests in LDAP allow directory vendors to create whole new types
of operations that are not built in to the base LDAP specification.  Essentially,
the directory advertises that it supports a specific type of extended operation via
the "supportedExtension" attribute in RootDSE (not loaded by default, so make sure
you add it to your attribute list!).  If the client knows how to pass in the
data to the extension operation and knows how to interpret the results, it can invoke
the extended operation.  If not, too bad.
</p>
        <p>
One such common extended LDAP operation is the "Who Am I?" operation as defined by <a href="http://tools.ietf.org/html/rfc4532">RFC
4532</a>.  Basically, the intent is to allow the LDAP client to issue the extended
operation and receive a response that provides information about the identity of the
user who is currently authenticated to the current LDAP connection via a previous
bind operation (if a bind was performed).  
</p>
        <p>
Interestingly, ADAM now supports the "Who Am I?" operation, as will Active Directory
in the Longhorn server time frame.  As such, it makes an excellent target for
investigation here as "Who Am I?" currently has no strongly typed wrapper in S.DS.P
(yet) and is also exceedingly easy to both call and interpret the returned results. 
I just learned about the existence of this thing via a thread on the exceedingly great
mailing list "activedir.org".  I figured I should go ahead and give it a whirl
to see how it works.  
</p>
        <p>
Without further ado, I humbly submit a few lines of code that demonstrate binding
to an ADAM instance on localhost on the default port (389) as the currently logged
on user and then invoking the "Who Am I?" extended request to find out my own Windows
user name (in case I forgot it :)).  
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> AdamWhoAmI<br />
{<br />
    <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> Main()<br />
    {<br />
        <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">using</span> (LdapConnection
con <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> LdapConnection(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"localhost"</span>))<br />
        {<br />
            con.Bind(); <span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">//use
default credentials. Current user can bind to ADAM...</span><br />
            <br />
            ExtendedRequest
whoami <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> ExtendedRequest(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"1.3.6.1.4.1.4203.1.11.3"</span>); </span>
        </p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
          </span>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">            <span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">//whoami
OID shown above, as per RFC</span></span>
        </p>
        <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
          <span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
          </span>
          <p>
            <br />
            ExtendedResponse
whoamiResult <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> (ExtendedResponse)
con.SendRequest(whoami);<br />
            Console.WriteLine(System.Text.Encoding.UTF8.GetString(whoamiResult.ResponseValue));
</p>
          <p>
            //the result is
a simple byte array that happens to contain UTF8 text<br />
        }<br />
        Console.ReadLine();<br />
    }<br />
}
</p>
        </span>
        <p>
Wow, pretty fancy stuff!  This actually compiled and ran on my very first try,
which usually doesn't work out.  As such, I feel confident in describing this
as "exceedingly simple".  On my machine, the result looks something like:
</p>
        <p>
          <font face="Courier New">u:machine\joe</font>
        </p>
        <p>
The interesting thing here is that this "just works" and it shows a semi-practical
thing you can do with this particular extensibility mechanism in LDAP that just happens
to not be exposed in System.DirectoryServices at all.  I'm sure there are some
practical uses for this, but the main point is just to show how to use this feature
with the simplest example possible.
</p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=3d6db311-dd87-4148-9d56-d7f677867c77" />
      </body>
      <title>ADAM WhoAmI Control in S.DS.P</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,3d6db311-dd87-4148-9d56-d7f677867c77.aspx</guid>
      <link>http://www.joekaplan.net/ADAMWhoAmIControlInSDSP.aspx</link>
      <pubDate>Thu, 25 Jan 2007 18:32:39 GMT</pubDate>
      <description>&lt;p&gt;
After some lofty goals of getting this blog jumpstarted back in the fall, I did just
the opposite and let it drop into a black hole.&amp;nbsp; To all of my faithful readers,
I humbly apologize.
&lt;/p&gt;
&lt;p&gt;
As part of an effort to gain some momentum again, I thought I'd try to rattle off
a quick post here.&amp;nbsp; Today's topic is intended as a continuation of my article
on series of &lt;a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx"&gt;"things
you can do in System.DirectoryServices.Protocols that you can't do in System.DirectoryServices"&lt;/a&gt;.&amp;nbsp;
We already discussed the ability to do &lt;a href=" http://www.joekaplan.net/AnotherSDSPonlyFeatureDigestAuthentication.aspx"&gt;Digest
authentication&lt;/a&gt; and &lt;a href="http://www.joekaplan.net/Example1ForSDSPSSLCertificates.aspx"&gt;process
server certificates&lt;/a&gt;.&amp;nbsp; Today's topic shows how to use S.DS.P's ability to
invoke arbitrary extended operations using the ExtendedRequest/ExtendedResponse message
types.
&lt;/p&gt;
&lt;p&gt;
Briefly, extended requests in LDAP allow directory vendors to create whole new types
of operations that are not built in to the base LDAP specification.&amp;nbsp; Essentially,
the directory advertises that it supports a specific type of extended operation via
the "supportedExtension" attribute in RootDSE (not loaded by default, so make sure
you add it to your attribute list!).&amp;nbsp; If the client knows how to pass in the
data to the extension operation and knows how to interpret the results, it can invoke
the extended operation.&amp;nbsp; If not, too bad.
&lt;/p&gt;
&lt;p&gt;
One such common extended LDAP operation is the "Who Am I?" operation as defined by &lt;a href="http://tools.ietf.org/html/rfc4532"&gt;RFC
4532&lt;/a&gt;.&amp;nbsp; Basically, the intent is to allow the LDAP client to issue the extended
operation and receive a response that provides information about the identity of the
user who is currently authenticated to the current LDAP connection via a previous
bind operation (if a bind was performed).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
Interestingly, ADAM now supports the "Who Am I?" operation, as will Active Directory
in the Longhorn server time frame.&amp;nbsp; As such, it makes an excellent target for
investigation here as "Who Am I?" currently has no strongly typed wrapper in S.DS.P
(yet)&amp;nbsp;and is also exceedingly easy to both call and interpret the returned results.&amp;nbsp;
I just learned about the existence of this thing via a thread on the exceedingly great
mailing list "activedir.org".&amp;nbsp; I figured I should go ahead and give it a whirl
to see how it works.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
Without further ado, I humbly submit a few lines of code that demonstrate binding
to an ADAM instance on localhost on the default port (389) as the currently logged
on user and then invoking the "Who Am I?" extended request to find out my own Windows
user name (in case I forgot it :)).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; AdamWhoAmI&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; Main()&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;using&lt;/span&gt; (LdapConnection
con &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; LdapConnection(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"localhost"&lt;/span&gt;))&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;con.Bind(); &lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;//use
default credentials. Current user can bind to ADAM...&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExtendedRequest
whoami &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; ExtendedRequest(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"1.3.6.1.4.1.4203.1.11.3"&lt;/span&gt;);&amp;nbsp;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;/span&gt;&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;//whoami
OID shown above, as per RFC&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;/span&gt; 
&lt;p&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExtendedResponse
whoamiResult &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; (ExtendedResponse)
con.SendRequest(whoami);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(System.Text.Encoding.UTF8.GetString(whoamiResult.ResponseValue));
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //the result is
a simple byte array that happens to contain UTF8 text&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.ReadLine();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
}
&lt;/span&gt;&gt;
&lt;p&gt;
Wow, pretty fancy stuff!&amp;nbsp; This actually compiled and ran on my very first try,
which usually doesn't work out.&amp;nbsp; As such, I feel confident in describing this
as "exceedingly simple".&amp;nbsp; On my machine, the result looks something like:
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;u:machine\joe&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
The interesting thing here is that this "just works" and it shows a semi-practical
thing you can do with this particular extensibility mechanism in LDAP that just happens
to not be exposed in System.DirectoryServices at all.&amp;nbsp; I'm sure there are some
practical uses for this, but the main point is just to show how to use this feature
with the simplest example possible.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=3d6db311-dd87-4148-9d56-d7f677867c77" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,3d6db311-dd87-4148-9d56-d7f677867c77.aspx</comments>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=668538b6-547f-4b96-af85-4f9d3a6baad2</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,668538b6-547f-4b96-af85-4f9d3a6baad2.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,668538b6-547f-4b96-af85-4f9d3a6baad2.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=668538b6-547f-4b96-af85-4f9d3a6baad2</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of my favorite softies, <a href="http://blogs.technet.com/efleis/default.aspx">Eric
Fleischman</a>, is doing <a href="http://blogs.technet.com/efleis/archive/2006/10/26/finding-the-lost-found-container-in-s-ds-p-or-anything-that-isn-t-adsi-really.aspx">some
S.DS.P programming</a> these days.  He demonstrates a useful technique, which
is how to do WKGUID searches to find well-known objects in AD or ADAM.  For those
not familiar with this, AD and ADAM have a set of "well-known" objects that the directory
always contains and applications may need to find to do reasonable things.  However,
the names of these objects may be internationalized, so it may not be possible to
find them by name across different implementations of the directory.  By referencing
them by the "well-known" GUID, a published value, you can always find them.
</p>
        <p>
One of the things we didn't do in our book was provide matching S.DS.P samples for
most of the techniques.  In fact, we barely covered it at all.  I still
have some regrets about this, although I also think we probably did the right thing. 
If the book had been 800 pages due to all the extra samples, that would have been
tough.  I do think there might be a place to supplement the material with online
materials at some point.  I'm not sure another print tome dedicated to the subject
would ever sell very well as the audience is probably limited and likely needs the
material less than than the audience we originally wrote the book for (I could be
wrong about this).  The internal debate continues...
</p>
        <p>
One of the things that Eric does hit on is the somewhat sad state of affairs of the
MSDN DS API documentation.  The S.DS.P docs are especially heinous, as they
include almost NO samples and even have some stuff documented as wrong or misleading. 
For example, the documentation for the <a href="http://blogs.technet.com/efleis/archive/2006/10/26/finding-the-lost-found-container-in-s-ds-p-or-anything-that-isn-t-adsi-really.aspx">DistinguishedName</a> property
on the SearchRequest class doesn't even succeed in identifying that as the search
BASE of the search, instead calling it the "object to search for".  If it wasn't
for the fact that there is no other obvious choice, an experienced LDAP programmer
might not even understand what it is doing!
</p>
        <p>
Additionally, the SDK docs for the directories themselves (AD and ADAM) are still
mostly written for the unmanaged VB or C++ programmers with little attention to the
managed code devs (although ADAM is much better about that).  However, you won't
find a single S.DS.P sample in any of that.  It is as if the API didn't exist. 
The managed code docs are also spread out between the .NET SDK and the Directory Services
SDK, so it is hard to know where to look to get help.
</p>
        <p>
There are two things missing here.  
</p>
        <ul>
          <li>
The S.DS.P docs are just embarassing and must be improved.  I'll give it some
more time.  
</li>
          <li>
The overall DS API documentation lacks strategy and makes the platform harder to consume
than it needs to be.  Sure, that helps drive sales of our book, but trust me, we
didn't write it to make money.</li>
        </ul>
        <p>
On the bright side, there is a lot of low hanging fruit available here. :)
</p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=668538b6-547f-4b96-af85-4f9d3a6baad2" />
      </body>
      <title>Eric is doing some S.DS.P programming</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,668538b6-547f-4b96-af85-4f9d3a6baad2.aspx</guid>
      <link>http://www.joekaplan.net/EricIsDoingSomeSDSPProgramming.aspx</link>
      <pubDate>Sat, 28 Oct 2006 05:13:16 GMT</pubDate>
      <description>&lt;p&gt;
One of my favorite softies, &lt;a href="http://blogs.technet.com/efleis/default.aspx"&gt;Eric
Fleischman&lt;/a&gt;, is doing &lt;a href="http://blogs.technet.com/efleis/archive/2006/10/26/finding-the-lost-found-container-in-s-ds-p-or-anything-that-isn-t-adsi-really.aspx"&gt;some
S.DS.P programming&lt;/a&gt; these days.&amp;nbsp; He demonstrates a useful technique, which
is how to do WKGUID searches to find well-known objects in AD or ADAM.&amp;nbsp; For those
not familiar with this, AD and ADAM have a set of "well-known" objects that the directory
always contains and applications may need to find to do reasonable things.&amp;nbsp; However,
the names of these objects may be internationalized, so it may not be possible to
find them by name across different implementations of the directory.&amp;nbsp; By referencing
them by the "well-known" GUID, a published value, you can always find them.
&lt;/p&gt;
&lt;p&gt;
One of the things we didn't do in our book was provide matching S.DS.P samples for
most of the techniques.&amp;nbsp; In fact, we barely covered it at all.&amp;nbsp; I still
have some regrets about this, although I also think we probably did the right thing.&amp;nbsp;
If the book had been 800 pages due to all the extra samples, that would have been
tough.&amp;nbsp; I do think there might be a place to supplement the material with online
materials at some point.&amp;nbsp; I'm not sure another print tome dedicated to the subject
would ever sell very well as the audience is probably limited and likely needs the
material less than than the audience we originally wrote the book for (I could be
wrong about this).&amp;nbsp; The internal debate continues...
&lt;/p&gt;
&lt;p&gt;
One of the things that Eric does hit on is the somewhat sad state of affairs of the
MSDN&amp;nbsp;DS API documentation.&amp;nbsp; The S.DS.P docs are especially heinous, as they
include almost NO samples and even have some stuff documented as wrong or misleading.&amp;nbsp;
For example, the documentation for the &lt;a href="http://blogs.technet.com/efleis/archive/2006/10/26/finding-the-lost-found-container-in-s-ds-p-or-anything-that-isn-t-adsi-really.aspx"&gt;DistinguishedName&lt;/a&gt; property
on the SearchRequest class doesn't even succeed in identifying that as the search
BASE of the search, instead calling it the "object to search for".&amp;nbsp; If it wasn't
for the fact that there is no other obvious choice, an experienced LDAP programmer
might not even understand what it is doing!
&lt;/p&gt;
&lt;p&gt;
Additionally, the SDK docs for the directories themselves (AD and ADAM) are still
mostly written for the unmanaged VB or C++ programmers with little attention to the
managed code devs (although ADAM is much better about that).&amp;nbsp; However, you won't
find a single S.DS.P sample in any of that.&amp;nbsp; It is as if the API didn't exist.&amp;nbsp;
The managed code docs are also spread out between the .NET SDK and the Directory Services
SDK, so it is hard to know where to look to get help.
&lt;/p&gt;
&lt;p&gt;
There are two things missing here.&amp;nbsp; 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
The S.DS.P docs are just embarassing and must be improved.&amp;nbsp; I'll give it some
more time.&amp;nbsp; 
&lt;/li&gt;
&lt;li&gt;
The overall DS API documentation lacks strategy and makes the platform harder to consume
than it needs to be.&amp;nbsp; Sure, that helps drive sales of our book, but trust me,&amp;nbsp;we
didn't write it to make money.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
On the bright side, there is a lot of low hanging fruit available here. :)
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=668538b6-547f-4b96-af85-4f9d3a6baad2" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,668538b6-547f-4b96-af85-4f9d3a6baad2.aspx</comments>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
An interesting thread popped up on the newsgroups today involving a poster who was
trying to prevent his LDAP client from doing client certificate authentication by
using a feature in the LDAP API that allows you to supply a callback function that
handles the client certificate selection process.  Unfortunately, the poster
found what he thought was a memory leak.
</p>
        <p>
The intrepid <a href="http://www.joeware.net">Joe Richards</a> jumped in and with
the help of the trusty MVP source access, his brain and a helpful MS employee, <a href="http://blog.joeware.net/2006/10/06/656/">found
the bug, reported it and created a workaround</a>.  Nice job!  Joe goes
into excruciating detail, so I won't add anything to his investigation.
</p>
        <p>
The interesting thing for .NET developers is that this issue potentially affects users
of System.DirectoryServices.Protocols (SDS.P).  SDS.P provides a direct wrapper
around the leaking callback function in the LDAP API with the QueryClientCertificateDelegate
method.  I did a a little Reflectoring and it looks to me like the workaround
Joe suggested isn't implemented in SDS.P.
</p>
        <p>
Thus, if you are using this callback, you could have the same memory leak.  The
thing that really sucks is that Joe's workaround requires that you have a pointer
in the allocated structure so that you can pass it into the appropriate deallocation
function.  However, the .NET function prototype conveniently marshals all the
data for you into an array of byte arrays, so you no longer have the pointer. 
As such, you can't implement the workaround in .NET at all.
</p>
        <p>
As such, in order to deal with this situation, you probably need to the QFE that Joe
mentions (or perhaps a patch to SDS.P, although to my knowledge no such thing exists).  
</p>
        <p>
I discussed this particular function's friend, VerifyServerCertificateCallback, in
my <a href="http://www.joekaplan.net/Example1ForSDSPSSLCertificates.aspx">posting</a> describing
how to check a domain controller certificate expiration date on its SSL/LDAP cert. 
The QueryClientCertificateCallback is useful when you need to pick a specific client
cert, or when you want to prevent the automatic Schannel layer for looking for a client
certificate at all (which is what the original poster was doing).  The client
certificate negotiation can be really slow and isn't really helpful in a lot of circumstances
if you don't want to try to use client certificate authentication to bind with (which
is another black hole of MS LDAP client documentation void best saved for another
post).  
</p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530" />
      </body>
      <title>Joe Richards find LDAP Client API Bug that Affects S.DS.Protocols</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530.aspx</guid>
      <link>http://www.joekaplan.net/JoeRichardsFindLDAPClientAPIBugThatAffectsSDSProtocols.aspx</link>
      <pubDate>Sat, 07 Oct 2006 02:35:50 GMT</pubDate>
      <description>&lt;p&gt;
An interesting thread popped up on the newsgroups today involving a poster who was
trying to prevent his LDAP client from doing client certificate authentication by
using a feature in the LDAP API that allows you to supply a callback function that
handles the client certificate selection process.&amp;nbsp; Unfortunately, the poster
found what he thought was a memory leak.
&lt;/p&gt;
&lt;p&gt;
The intrepid &lt;a href="http://www.joeware.net"&gt;Joe Richards&lt;/a&gt; jumped in and with
the help of the trusty MVP source access, his brain and a helpful MS employee, &lt;a href="http://blog.joeware.net/2006/10/06/656/"&gt;found
the bug, reported it and created a workaround&lt;/a&gt;.&amp;nbsp; Nice job!&amp;nbsp; Joe goes
into excruciating detail, so I won't add anything to his investigation.
&lt;/p&gt;
&lt;p&gt;
The interesting thing for .NET developers is that this issue potentially affects users
of System.DirectoryServices.Protocols (SDS.P).&amp;nbsp; SDS.P provides a direct wrapper
around the leaking callback function in the LDAP API with the QueryClientCertificateDelegate
method.&amp;nbsp; I did a a little Reflectoring and it looks to me like the workaround
Joe suggested isn't implemented in SDS.P.
&lt;/p&gt;
&lt;p&gt;
Thus, if you are using this callback, you could have the same memory leak.&amp;nbsp; The
thing that really sucks is that Joe's workaround requires that you have a pointer
in the allocated structure so that you can pass it into the appropriate deallocation
function.&amp;nbsp; However, the .NET function prototype conveniently marshals all the
data for you into an array of byte arrays, so you no longer have the pointer.&amp;nbsp;
As such, you can't implement the workaround in .NET at all.
&lt;/p&gt;
&lt;p&gt;
As such, in order to deal with this situation, you probably need to the QFE that Joe
mentions (or perhaps a patch to SDS.P, although to my knowledge no such thing exists).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
I discussed this particular function's friend, VerifyServerCertificateCallback, in
my &lt;a href="http://www.joekaplan.net/Example1ForSDSPSSLCertificates.aspx"&gt;posting&lt;/a&gt; describing
how to check a domain controller certificate expiration date on its SSL/LDAP cert.&amp;nbsp;
The QueryClientCertificateCallback is useful when you need to pick a specific client
cert, or when you want to prevent the automatic Schannel layer for looking for a client
certificate at all (which is what the original poster was doing).&amp;nbsp; The client
certificate negotiation can be really slow and isn't really helpful in a lot of circumstances
if you don't want to try to use client certificate authentication to bind with (which
is another black hole of MS LDAP client documentation void best saved for another
post).&amp;nbsp; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,c92e0d51-90b9-4b6f-9d97-9dd9fb7d7530.aspx</comments>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=637a1db3-198d-4215-ae8f-6b0ee4b3c671</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,637a1db3-198d-4215-ae8f-6b0ee4b3c671.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,637a1db3-198d-4215-ae8f-6b0ee4b3c671.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=637a1db3-198d-4215-ae8f-6b0ee4b3c671</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
An interesting thread on LDAP and authentication came up again today on activedir.org. 
In the conversation, I had suggested that it would be a good feature if AD and ADAM
had a setting somewhere that could be enabled that would prevent LDAP simple bind
from working if the network channel was not secured (via SSL).  The problem with
simple bind (for those not in the know) is that the user's credentials are passed
over the network in plaintext, which is potentially a huge security risk (depending
on the network).  It is actually even worse (by just a little) that HTTP basic
authentication, as the credentials aren't even base64 encoded.
</p>
        <p>
Eric Fleischman then pointed out that ADAM actually already has such a switch. 
Tomek blogged about it <a href="http://blogs.dirteam.com/blogs/tomek/archive/2006/09/24/Disable-simple-bind-without-SSL-on-ADAM.aspx">here</a>,
so I'll let him cover the details on how to enable this.
</p>
        <p>
I went on to suggest that AD should also have this feature (off by default for backwards
compat most likely).  The problem is that without this feature, the AD admin
really has no way to prevent apps that use simple bind for auth from sending plaintext
credentials on the network, even if SSL has been configured.  You can't just
turn off port 389 access to AD without breaking other stuff as you might be able to
do in other directories.  Many of the NOS features of AD rely on port 389.
</p>
        <p>
I also suggested adding an ability to audit simple bind attempts over non-SSL channels,
including the IP address, so that admins have a way to track down rogue apps.
</p>
        <p>
In many IT organizations these days, we must specify policies about how we are going
to treat sensitive data (like passwords!) on the network and can get ourselves into
hot water with our auditors if we are found to not be in compliance with our own policies. 
At least with this auditing support in place, violations of the policy can be capture
and violators may be traceable.
</p>
        <p>
Also note that with most ADSI (and System.DirectoryServices programming in .NET),
simple binds are not used.  Windows secure binds (using GSS-SPNEGO, which amounts
to Kerberos or NTLM at the heart of it) are used by default.  You can get a simple
bind, but you must do more work.  As such, most ADSI script code is not likely
to have this problem.  You do have to be careful though.  We go into this
in a great deal more detail in ch. 3 of the <a href="http://www.directoryprogramming.net">book</a>. 
Simple binds are very common with cross platform apps, and especially those that use
non-MS LDAP libraries, as they often do not have the code they need to implement GSS-SPNEGO
at all.  Some of them just use simple bind because it is the lowest common denominator
protocol that all LDAP directories must support.
</p>
        <p>
Anyway, it will be interesting to see if any of these suggestions come to fruition. 
In the mean time, use SSL with your directories (ADAM too!) when doing simple
bind.  Getting certs can be painful, but usually not as painful as getting hacked
or failing an audit.  Unless your networks are totally secure between the endpoints
and there is no threat of snooping, you need a secure channel.  
</p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=637a1db3-198d-4215-ae8f-6b0ee4b3c671" />
      </body>
      <title>ADAM Can be Forced to Only Allow Simple Bind on a Secure Channel</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,637a1db3-198d-4215-ae8f-6b0ee4b3c671.aspx</guid>
      <link>http://www.joekaplan.net/ADAMCanBeForcedToOnlyAllowSimpleBindOnASecureChannel.aspx</link>
      <pubDate>Mon, 25 Sep 2006 04:42:39 GMT</pubDate>
      <description>&lt;p&gt;
An interesting thread on LDAP and authentication came up again today on activedir.org.&amp;nbsp;
In the conversation, I had suggested that it would be a good feature if AD and ADAM
had a setting somewhere that could be enabled that would prevent LDAP simple bind
from working if the network channel was not secured (via SSL).&amp;nbsp; The problem with
simple bind (for those not in the know) is that the user's credentials are passed
over the network in plaintext, which is potentially a huge security risk (depending
on the network).&amp;nbsp; It is actually even worse (by just a little) that HTTP basic
authentication, as the credentials aren't even base64 encoded.
&lt;/p&gt;
&lt;p&gt;
Eric Fleischman then pointed out that ADAM actually already has such a switch.&amp;nbsp;
Tomek blogged about it &lt;a href="http://blogs.dirteam.com/blogs/tomek/archive/2006/09/24/Disable-simple-bind-without-SSL-on-ADAM.aspx"&gt;here&lt;/a&gt;,
so I'll let him cover the details on how to enable this.
&lt;/p&gt;
&lt;p&gt;
I went on to suggest that AD should also have this feature (off by default for backwards
compat most likely).&amp;nbsp; The problem is that without this feature, the AD admin
really has no way to prevent apps that use simple bind for auth from sending plaintext
credentials on the network, even if SSL has been configured.&amp;nbsp; You can't just
turn off port 389 access to AD without breaking other stuff as you might be able to
do in other directories.&amp;nbsp; Many of the NOS features of AD rely on port 389.
&lt;/p&gt;
&lt;p&gt;
I also suggested adding an ability to audit simple bind attempts over non-SSL channels,
including the IP address, so that admins have a way to track down rogue apps.
&lt;/p&gt;
&lt;p&gt;
In many IT organizations these days, we must specify policies about how we are going
to treat sensitive data (like passwords!) on the network and can get ourselves into
hot water with our auditors if we are found to not be in compliance with our own policies.&amp;nbsp;
At least with this auditing support in place, violations of the policy can be capture
and violators may be traceable.
&lt;/p&gt;
&lt;p&gt;
Also note that with most ADSI (and System.DirectoryServices programming in .NET),
simple binds are not used.&amp;nbsp; Windows secure binds (using GSS-SPNEGO, which amounts
to Kerberos or NTLM at the heart of it) are used by default.&amp;nbsp; You can get a simple
bind, but you must do more work.&amp;nbsp; As such, most ADSI script code is not likely
to have this problem.&amp;nbsp; You do have to be careful though.&amp;nbsp; We go into this
in a great deal more detail in ch. 3 of the &lt;a href="http://www.directoryprogramming.net"&gt;book&lt;/a&gt;.&amp;nbsp;
Simple binds are very common with cross platform apps, and especially those that use
non-MS LDAP libraries, as they often do not have the code they need to implement GSS-SPNEGO
at all.&amp;nbsp; Some of them just use simple bind because it is the lowest common denominator
protocol that all LDAP directories must support.
&lt;/p&gt;
&lt;p&gt;
Anyway, it will be interesting to see if any of these suggestions come to fruition.&amp;nbsp;
In the mean time, use SSL with your directories (ADAM too!)&amp;nbsp;when doing simple
bind.&amp;nbsp; Getting certs can be painful, but usually not as painful as getting hacked
or failing an audit.&amp;nbsp; Unless your networks are totally secure between the endpoints
and there is no threat of snooping, you need a secure channel.&amp;nbsp; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=637a1db3-198d-4215-ae8f-6b0ee4b3c671" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,637a1db3-198d-4215-ae8f-6b0ee4b3c671.aspx</comments>
      <category>LDAP;Windows Security</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=9b25d233-a484-4905-a60b-8bb8748c7068</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,9b25d233-a484-4905-a60b-8bb8748c7068.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,9b25d233-a484-4905-a60b-8bb8748c7068.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=9b25d233-a484-4905-a60b-8bb8748c7068</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font size="4">Fast Concurrent Binding Overview</font>
        </p>
        <p>
One of the things I alluded to in my <a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx">post</a> that
highlighted the differences in capabilities between the ADSI-based System.DirectoryServices
(SDS) namespace and the raw LDAP-based System.DirectoryServices.Protocols (SDS.P)
was the ability to access a feature called <strong><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/using_ldap_for_password_authentication.asp?frame=true">Fast
Concurrent Binding (FCB)</a></strong>.
</p>
        <p>
FCB is a feature available in Active Directory 2003 (and later) and in ADAM. 
To explain it, first let’s cover what happens with a “regular” bind operation in LDAP
against AD or ADAM.  With a normal bind, the user’s credentials are presented
to the LDAP server, either in plaintext format or via the Windows security model if
using a secure binding protocol.  The server then attempts to authenticate these
credentials.  If the credentials are accepted, then the server builds a Windows
token for the user which will be used to for performing security checks on future
operations and changes the state of the current LDAP connection to an authenticated
state so that future requests will continue to use the newly established security
context and this operation is not repeated.  This is the main reason why LDAP
connections are stateful.
</p>
        <p>
FCB eliminates two parts of this equation.  It authenticates the user’s credentials,
but it does not build a Windows token for the user and the connection state stays
anonymous.  As such, the bind operation will give you an “up/down” result based
on whether the user’s name and password were valid, but it won’t let you do anything
else with that connection such as perform searches, except as an anonymous user (which
is pretty limited by default in AD 2003 and ADAM).
</p>
        <p>
The big upside of FCB is that the bind operation is MUCH faster than a normal bind
because the really expensive operation, expanding the user’s group membership to build
the token, is eliminated.  Hence the name <em><strong>fast</strong> concurrent
binding</em>.<sup>*</sup></p>
        <p>
The concurrent part comes from the fact that multiple users can be authenticated on
the same LDAP connection simultaneously without worrying about changing the authenticated
state of the connection, so the expense of setting up and tearing down the associated
socket can also be eliminated.  This makes it potentially even faster.
</p>
        <p>
The big downside with FCB is that it only supports LDAP simple bind, not SASL, and
simple bind does not have a built in mechanism for protecting the credentials on the
wire like the various SASL mechanisms do.  <strong>As such, it is never safe
to use FCB unless some form of transport security is used such as SSL or IPSEC!</strong></p>
        <p>
          <font size="4">When to Use Fast Concurrent Binding</font>
        </p>
        <p>
          <strong>Do</strong> use FCB when your application is doing pure authentication of
credentials via LDAP.  An example of this might be in a web-based application
that uses AD or ADAM as a user store and does LDAP authentication.  If you just
need a “yes/no” vote as to whether a username/password combo is good, FCB will give
you the best performance and may add a significant scalability increase to your application
as a result.  
</p>
        <p>
          <strong>Do not</strong> use FCB if you need to authenticate and then perform operations
against the directory on the user’s behalf (a delegation scenario from the architectural
perspective, although not necessarily using Windows Kerberos delegation features to
implement it).  Since the connection state does not change to “authenticated”,
the user’s credentials will not be used to perform subsequent operations and you won’t
get what you want.
</p>
        <p>
An obvious place where you might want to use FCB would be in something like the ActiveDirectoryMembershipProvider
in ASP.NET 2.0.  My understanding is that the development already thought about
this and tried to add this support already.  Thus, you may already have this
and not even know it!
</p>
        <p>
Another obvious place for this to be used would be in ADFS for authenticating users
in the ADAM store and potentially with users in the AD store as well when used with
the Federation Service Proxy (which accepts credentials via a forms or basic auth
interface in plaintext form).  As of this writing, I do not believe that ADFS
is taking advantage of this feature (or and SDS.P capabilities for that matter). 
Note to product team…
</p>
        <p>
          <font size="4">A Note on ADSI/SDS and Fast Concurrent Binding</font>
        </p>
        <p>
          <em>Hey Joe, I see that ADSI and SDS have an <font face="Courier New">AuthenticationTypes</font> flag
called <font face="Courier New">FastBind</font>.  Can’t I just use that to get
FCB?  Why are you telling me this requires SDS.P?</em>
        </p>
        <p>
The answer here is “no”, they are not the same thing, despite their unfortunately
similar names!  <font face="Courier New"><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/fast_binding_option_for_batch_writemodify_operations.asp?frame=true">FastBind</a></font> in
ADSI/SDS actually has nothing to do with the bind operation per say, but has to do
with what ADSI does after the bind when you go to access an object.  With <font face="Courier New">FastBind</font> NOT
set (the default), ADSI does a base-level search to the object you tried to access
to read its <font face="Courier New">objectClass</font> attribute <em>before</em> it
executes any other searches to load the property cache and such.  ADSI uses this
information to determine which ADSI interfaces to make available.  By default,
you get the core interfaces like <font face="Courier New">IADs</font>, but you don’t
necessarily get one of the “persistent object” interfaces like <font face="Courier New">IADsUser</font> or <font face="Courier New">IADsGroup</font> unless
ADSI knows that it is a user or group.  Without those interfaces, you loose access
to members like <font face="Courier New">SetPassword</font> and <font face="Courier New">Add</font> (for
group membership additions).  
</p>
        <p>
The reason <font face="Courier New">FastBind</font> is called “Fast” is that this
initial search is done in addition to any searches to load the property cache, which
generally means that at least <em>two</em> base-level searches to the directory will
be required to load any given ADSI object (as you normally use the property cache
for something!).  All these extra searches add up to lots of network chatter
and can slow certain types of operations to a crawl.  
</p>
        <p>
Note that <font face="Courier New">FastBind</font> is an ADSI/SDS thing though and
has no bearing on how things work at the lower level LDAP level, as this notion of
the persistent object interfaces and property caches is an ADSI abstraction layer.
</p>
        <p>
          <font size="4">How to Implement Fast Concurrent Binding in SDS.P</font>
        </p>
        <p>
There really isn’t too much too this.  All you really need to do is turn this
option on <strong>BEFORE</strong> your LdapConnection actually connects to the directory
for the first time and you are all set.  Briefly, the code looks something like:
</p>
        <p>
          <font face="Courier New">_authConnect.SessionOptions.FastConcurrentBind();</font>
        </p>
        <p>
In order to get a more thorough look, I’ll simply point you to the LdapAuth.cs class
from our book’s website in ch 12 of the <a href="http://directoryprogramming.net/files/default.aspx">Full
Samples </a>to see this in real usage.  
</p>
        <p>
          <strong>Important Warning</strong>
          <br />
There is a bug in the actual implementation printed in the book (first printing at
least; assuming there will be more than one and we actually fix it ?).  <a href="http://dunnry.com/blog/FastConcurrentBindingInSDSP.aspx">A
small last minute blunder caused the defect</a>.  Please use the version in the
full samples from the website.
</p>
        <p>
          <strong>There are some important caveats as well:</strong>
        </p>
        <ul>
          <li>
            <em>Both the server and client must support FCB</em>.  In the book sample, we
actually check the server first via its <font face="Courier New">supportedCapabilities</font><font face="Courier New">RootDSE</font> attribute
to find the specific OID.  On the client requirements, be aware the SDS.P requires
the client code to be run on Windows 2003 server or higher.  XP and below does
not support this!  Our code tries to handle this gracefully, but you should plan
ahead anyway.</li>
          <li>
            <em>You are using simple bind, so you need plaintext usernames and passwords and must
use a user name syntax supported by simple bind</em>.  For AD, this is NT Account
Name (domain\user), UPN or DN.  For ADAM, this is generally UPN or DN, but actually
could be a lot of things like displayName as well.  Ch 3 of our book goes into
more detail.</li>
          <li>
This is simple bind.  <em>You MUST encrypt the network traffic with SSL or something!</em></li>
        </ul>
        <p>
          <font size="4">Conclusion</font>
        </p>
        <p>
We already covered most of this information in our book, but I don’t think we hit
all of these things in as much detail as I have covered here.  Additionally,
not all of you will buy the book and this isn’t in the free chapter, and we want you
to be successful with this somewhat mysterious feature, regardless.  Happy fast(er)
binding!<br /><em><font size="1"></font></em></p>
        <p>
          <em>
            <font size="1">* Of course, with all performance optimizations, always measure
and never assume.  Premature optimization is one of the seven deadly sins of
software engineering, yada-yada-yada.</font>
          </em>
        </p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=9b25d233-a484-4905-a60b-8bb8748c7068" />
      </body>
      <title>Using Fast Concurrent Binding in SDS.P</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,9b25d233-a484-4905-a60b-8bb8748c7068.aspx</guid>
      <link>http://www.joekaplan.net/UsingFastConcurrentBindingInSDSP.aspx</link>
      <pubDate>Thu, 17 Aug 2006 18:05:52 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font size=4&gt;Fast Concurrent Binding Overview&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
One of the things I alluded to in my &lt;a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx"&gt;post&lt;/a&gt; that
highlighted the differences in capabilities between the ADSI-based System.DirectoryServices
(SDS) namespace and the raw LDAP-based System.DirectoryServices.Protocols (SDS.P)
was the ability to access a feature called &lt;strong&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/using_ldap_for_password_authentication.asp?frame=true"&gt;Fast
Concurrent Binding (FCB)&lt;/a&gt;&lt;/strong&gt;.
&lt;/p&gt;
&lt;p&gt;
FCB is a feature available in Active Directory 2003 (and later) and in ADAM.&amp;nbsp;
To explain it, first let’s cover what happens with a “regular” bind operation in LDAP
against AD or ADAM.&amp;nbsp; With a normal bind, the user’s credentials are presented
to the LDAP server, either in plaintext format or via the Windows security model if
using a secure binding protocol.&amp;nbsp; The server then attempts to authenticate these
credentials.&amp;nbsp; If the credentials are accepted, then the server builds a Windows
token for the user which will be used to for performing security checks on future
operations and changes the state of the current LDAP connection to an authenticated
state so that future requests will continue to use the newly established security
context and this operation is not repeated.&amp;nbsp; This is the main reason why LDAP
connections are stateful.
&lt;/p&gt;
&lt;p&gt;
FCB eliminates two parts of this equation.&amp;nbsp; It authenticates the user’s credentials,
but it does not build a Windows token for the user and the connection state stays
anonymous.&amp;nbsp; As such, the bind operation will give you an “up/down” result based
on whether the user’s name and password were valid, but it won’t let you do anything
else with that connection such as perform searches, except as an anonymous user (which
is pretty limited by default in AD 2003 and ADAM).
&lt;/p&gt;
&lt;p&gt;
The big upside of FCB is that the bind operation is MUCH faster than a normal bind
because the really expensive operation, expanding the user’s group membership to build
the token, is eliminated.&amp;nbsp; Hence the name&amp;nbsp;&lt;em&gt;&lt;strong&gt;fast&lt;/strong&gt; concurrent
binding&lt;/em&gt;.&lt;sup&gt;*&lt;/sup&gt;
&lt;/p&gt;
&lt;p&gt;
The concurrent part comes from the fact that multiple users can be authenticated on
the same LDAP connection simultaneously without worrying about changing the authenticated
state of the connection, so the expense of setting up and tearing down the associated
socket can also be eliminated.&amp;nbsp; This makes it potentially even faster.
&lt;/p&gt;
&lt;p&gt;
The big downside with FCB is that it only supports LDAP simple bind, not SASL, and
simple bind does not have a built in mechanism for protecting the credentials on the
wire like the various SASL mechanisms do.&amp;nbsp; &lt;strong&gt;As such, it is never safe
to use FCB unless some form of transport security is used such as SSL or IPSEC!&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;When to Use Fast Concurrent Binding&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Do&lt;/strong&gt; use FCB when your application is doing pure authentication of
credentials via LDAP.&amp;nbsp; An example of this might be in a web-based application
that uses AD or ADAM as a user store and does LDAP authentication.&amp;nbsp; If you just
need a “yes/no” vote as to whether a username/password combo is good, FCB will give
you the best performance and may add a significant scalability increase to your application
as a result.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Do not&lt;/strong&gt; use FCB if you need to authenticate and then perform operations
against the directory on the user’s behalf (a delegation scenario from the architectural
perspective, although not necessarily using Windows Kerberos delegation features to
implement it).&amp;nbsp; Since the connection state does not change to “authenticated”,
the user’s credentials will not be used to perform subsequent operations and you won’t
get what you want.
&lt;/p&gt;
&lt;p&gt;
An obvious place where you might want to use FCB would be in something like the ActiveDirectoryMembershipProvider
in ASP.NET 2.0.&amp;nbsp; My understanding is that the development already thought about
this and tried to add this support already.&amp;nbsp; Thus, you may already have this
and not even know it!
&lt;/p&gt;
&lt;p&gt;
Another obvious place for this to be used would be in ADFS for authenticating users
in the ADAM store and potentially with users in the AD store as well when used with
the Federation Service Proxy (which accepts credentials via a forms or basic auth
interface in plaintext form).&amp;nbsp; As of this writing, I do not believe that ADFS
is taking advantage of this feature (or and SDS.P capabilities for that matter).&amp;nbsp;
Note to product team…
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;A Note on ADSI/SDS and Fast Concurrent Binding&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;Hey Joe, I see that ADSI and SDS have an &lt;font face="Courier New"&gt;AuthenticationTypes&lt;/font&gt; flag
called &lt;font face="Courier New"&gt;FastBind&lt;/font&gt;.&amp;nbsp; Can’t I just use that to get
FCB?&amp;nbsp; Why are you telling me this requires SDS.P?&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
The answer here is “no”, they are not the same thing, despite their unfortunately
similar names!&amp;nbsp; &lt;font face="Courier New"&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/fast_binding_option_for_batch_writemodify_operations.asp?frame=true"&gt;FastBind&lt;/a&gt;&lt;/font&gt; in
ADSI/SDS actually has nothing to do with the bind operation per say, but has to do
with what ADSI does after the bind when you go to access an object.&amp;nbsp; With &lt;font face="Courier New"&gt;FastBind&lt;/font&gt; NOT
set (the default), ADSI does a base-level search to the object you tried to access
to read its &lt;font face="Courier New"&gt;objectClass&lt;/font&gt; attribute &lt;em&gt;before&lt;/em&gt; it
executes any other searches to load the property cache and such.&amp;nbsp; ADSI uses this
information to determine which ADSI interfaces to make available.&amp;nbsp; By default,
you get the core interfaces like &lt;font face="Courier New"&gt;IADs&lt;/font&gt;, but you don’t
necessarily get one of the “persistent object” interfaces like &lt;font face="Courier New"&gt;IADsUser&lt;/font&gt; or &lt;font face="Courier New"&gt;IADsGroup&lt;/font&gt; unless
ADSI knows that it is a user or group.&amp;nbsp; Without those interfaces, you loose access
to members like &lt;font face="Courier New"&gt;SetPassword&lt;/font&gt; and &lt;font face="Courier New"&gt;Add&lt;/font&gt; (for
group membership additions).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
The reason &lt;font face="Courier New"&gt;FastBind&lt;/font&gt; is called “Fast” is that this
initial search is done in addition to any searches to load the property cache, which
generally means that at least &lt;em&gt;two&lt;/em&gt; base-level searches to the directory will
be required to load any given ADSI object (as you normally use the property cache
for something!).&amp;nbsp; All these extra searches add up to lots of network chatter
and can slow certain types of operations to a crawl.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
Note that &lt;font face="Courier New"&gt;FastBind&lt;/font&gt; is an ADSI/SDS thing though and
has no bearing on how things work at the lower level LDAP level, as this notion of
the persistent object interfaces and property caches is an ADSI abstraction layer.
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;How to Implement Fast Concurrent Binding in SDS.P&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
There really isn’t too much too this.&amp;nbsp; All you really need to do is turn this
option on &lt;strong&gt;BEFORE&lt;/strong&gt; your LdapConnection actually connects to the directory
for the first time and you are all set.&amp;nbsp; Briefly, the code looks something like:
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;_authConnect.SessionOptions.FastConcurrentBind();&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
In order to get a more thorough look, I’ll simply point you to the LdapAuth.cs class
from our book’s website in ch 12 of the &lt;a href="http://directoryprogramming.net/files/default.aspx"&gt;Full
Samples &lt;/a&gt;to see this in real usage.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Important Warning&lt;/strong&gt;
&lt;br&gt;
There is a bug in the actual implementation printed in the book (first printing at
least; assuming there will be more than one and we actually fix it ?).&amp;nbsp; &lt;a href="http://dunnry.com/blog/FastConcurrentBindingInSDSP.aspx"&gt;A
small last minute blunder caused the defect&lt;/a&gt;.&amp;nbsp; Please use the version in the
full samples from the website.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;There are some important caveats as well:&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Both the server and client must support FCB&lt;/em&gt;.&amp;nbsp; In the book sample, we
actually check the server first via its &lt;font face="Courier New"&gt;supportedCapabilities&lt;/font&gt; &lt;font face="Courier New"&gt;RootDSE&lt;/font&gt; attribute
to find the specific OID.&amp;nbsp; On the client requirements, be aware the SDS.P requires
the client code to be run on Windows 2003 server or higher.&amp;nbsp; XP and below does
not support this!&amp;nbsp; Our code tries to handle this gracefully, but you should plan
ahead anyway.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;You are using simple bind, so you need plaintext usernames and passwords and must
use a user name syntax supported by simple bind&lt;/em&gt;.&amp;nbsp; For AD, this is NT Account
Name (domain\user), UPN or DN.&amp;nbsp; For ADAM, this is generally UPN or DN, but actually
could be a lot of things like displayName as well.&amp;nbsp; Ch 3 of our book goes into
more detail.&lt;/li&gt;
&lt;li&gt;
This is simple bind.&amp;nbsp; &lt;em&gt;You MUST encrypt the network traffic with SSL or something!&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;font size=4&gt;Conclusion&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
We already covered most of this information in our book, but I don’t think we hit
all of these things in as much detail as I have covered here.&amp;nbsp; Additionally,
not all of you will buy the book and this isn’t in the free chapter, and we want you
to be successful with this somewhat mysterious feature, regardless.&amp;nbsp; Happy fast(er)
binding!&lt;br&gt;
&lt;em&gt;&lt;font size=1&gt;&lt;/font&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;&lt;font size=1&gt;* Of course, with all performance optimizations, always measure and
never assume.&amp;nbsp; Premature optimization is one of the seven deadly sins of software
engineering, yada-yada-yada.&lt;/font&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=9b25d233-a484-4905-a60b-8bb8748c7068" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,9b25d233-a484-4905-a60b-8bb8748c7068.aspx</comments>
      <category>Application Architecture;LDAP;Windows Security</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=fcdf0808-8196-4eb7-b171-8b54a5790687</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,fcdf0808-8196-4eb7-b171-8b54a5790687.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,fcdf0808-8196-4eb7-b171-8b54a5790687.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=fcdf0808-8196-4eb7-b171-8b54a5790687</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font size="4">Authentication Mechanisms in SDS</font>
        </p>
        <p>
In ADSI and System.DirectoryServicess (SDS), we are really only given two choices
for how authentication will be performed when we do a bind operation.  We can
specify the "Secure" flag (AuthenticationTypes.Secure), and ADSI will attempt to the
bind to the remote directory using Windows SSPI authentication with the Negotiate
protocol.  As you may know, the Negotiate protocol is the primary authentication
protocol in Windows since Windows 2000 and selects between using Kerberos (always
preferred) and NTLM (there for backwards compatibility).  For the really nerdy
of you out there, the Negotiate protocol is implemented by Microsoft's LDAP API using
the GSS-SPNEGO SASL mechanism.
</p>
        <p>
The other option in SDS is to NOT specify AuthenticationTypes.Secure and it will
attempt to use an LDAP simple bind instead<sup><font size="1">*</font></sup>. 
The only authentication mechanism defined by LDAP specification is the simple bind,
so every directory implements it.  As such, it ends up being the cross-platform
lowest common denominator approach.  The problem with the simple bind is that
it is totally insecure by itself.  Simple bind passes the user's plaintext credentials
on the network, so unless some sort of channel encryption is provided (like SSL, the
defacto cross-platform standard here as well), anyone who can sniff the wire traffic
can recover the user's password.  This sort of thing is generally frowned on
my security enthusiasts.  :(
</p>
        <p>
          <font size="4">Digest Authentication in LDAP API/SDS.P</font>
        </p>
        <p>
There is, however, a richer set of authentication mechanisms supported by Microsoft's
LDAP API than what ADSI/SDS get to use, and these are available to System.DirectoryServices.Protocols
(SDS.P).  One of the most interesting of these is the Digest authentication protocol. 
Digest is a <a href="http://www.faqs.org/rfcs/rfc2831.html">standard</a>, secure authentication
protocol that does not involve the exchange of plaintext credentials and is implemented
by AD and ADAM, as well as some other LDAP directories.  In SDS.P, we can use
it very easily.  Here is a short sample illustrating this (and no, there is no
ADAM instance at adam.joekaplan.net; dream on...):
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">bool</span> DoDigestAuth(NetworkCredential
cred)<br />
{ 
<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
const</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">int</span> LDAP_INVALID_CREDENTIALS <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> 49;<br />
    LdapConnection conn <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">       
new</span> LdapConnection(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"adam.joekaplan.net:389"</span>);<br />
    conn.AuthType <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> AuthType.Digest;<br />
    conn.Credential <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> cred;<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
try</span><br />
    {<br />
        conn.Bind();<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">       
return</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>;<br />
    }<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
catch</span> (LdapException ex)<br />
    {<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">       
if</span> (ex.ErrorCode == LDAP_INVALID_CREDENTIALS)<br />
        {<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">           
return</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">false</span>;<br />
        }<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">       
else</span><br />
        {<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">           
throw</span>;<br />
        }<br />
    }<br />
}</span>
        </p>
        <p>
Here, we have a trivial little sample that shows how this might be done.  Note
that we probably wouldn't create a new <font face="Courier New">LdapConnection</font> object
each time this is called and we'd also try to find a way to clean that up with a proper
Dispose, but the point here is to illustrate that all we really have to do is set
the <font face="Courier New">AuthType</font> property to <font face="Courier New">AuthType.Digest</font> and
it works.  The credentials are specified with a standard <font face="Courier New">NetworkCredential</font> object. 
For Digest, just specify the username and password, not the domain parameter.
</p>
        <p>
          <font size="4">Why is This Important?</font>
        </p>
        <p>
Digest authentication is really interesting particularly for ADAM, as it is supported
by ADAM principals.  Before ADAM supported Digest auth (as of SP1), the only
way to authenticate an ADAM principal was with a simple bind.  That wasn't secure
(see above), so SSL was required to make it secure.  However, SSL certs are not
always easy to procure and take extra effort to install, so many people were missing
this and were insecure.  :(
</p>
        <p>
The other cool thing with Digest is that since it is implemented through Microsoft's
SSPI model, it can also be used as a mechanism for getting channel encryption and
signing, just like negotiate auth supports today<sup><font size="1">**</font></sup>. 
This means that not only can you get secure binding for free, but all of your network
traffic after the bind can be encrypted and signed for free (no SSL required). 
This is done through setting the <font face="Courier New">Signing</font> and <font face="Courier New">Sealing</font> properties
to true on the <font face="Courier New">LdapSessionOptions</font> class.  This,
in turn, allows a way to do LDAP password operations on ADAM principals without using
SSL and without having to change the setting in ADAM to turn off the requirement for
a secure channel on password ops (another big security frown sandwich there...).  
</p>
        <p>
One great scenario for this feature would be to use it with <strong>ADFS for their
ADAM Account Store support</strong>.  This would allow secure authentication
without requiring SSL out of the box and would also provide free channel encryption.  <strong>Product
team please take note!</strong></p>
        <p>
          <sub>* There is a feature in Windows Server 2003 SP1 ADSI will try Digest auth
when the Secure flag is specified and ADSI detects that the server supports Digest
but not negotiate auth.  However, this doesn't help us for AD or ADAM, since
they both support negotiate auth.  The problem with negotiate auth for ADAM is
that it is only used for authenticating Windows users, not ADAM principals.</sub>
        </p>
        <p>
          <sub>** There appears to be a bug in the implementation in ADAM SP1 where the channel
encryption feature only works if the network traffic is NOT on the loopback
(localhost) port.  This is different from the way negotiate channel encryption
works.  This appears to be an oversight in the implementation and not an underlying
issue in the design, so presumably this will get fixed someday.</sub>
        </p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=fcdf0808-8196-4eb7-b171-8b54a5790687" />
      </body>
      <title>Another SDS.P-only feature: Digest authentication</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,fcdf0808-8196-4eb7-b171-8b54a5790687.aspx</guid>
      <link>http://www.joekaplan.net/AnotherSDSPonlyFeatureDigestAuthentication.aspx</link>
      <pubDate>Mon, 07 Aug 2006 15:31:20 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font size=4&gt;Authentication Mechanisms in SDS&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
In ADSI and System.DirectoryServicess (SDS), we are really only given two choices
for how authentication will be performed when we do a bind operation.&amp;nbsp; We can
specify the "Secure" flag (AuthenticationTypes.Secure), and ADSI will attempt to the
bind to the remote directory using Windows SSPI authentication with the Negotiate
protocol.&amp;nbsp; As you may know, the Negotiate protocol is the primary authentication
protocol in Windows since Windows 2000 and selects between using Kerberos (always
preferred) and NTLM (there for backwards compatibility).&amp;nbsp; For the really nerdy
of you out there, the Negotiate protocol is implemented by Microsoft's LDAP API using
the GSS-SPNEGO SASL mechanism.
&lt;/p&gt;
&lt;p&gt;
The other option&amp;nbsp;in SDS is to NOT specify AuthenticationTypes.Secure and it will
attempt to use an LDAP simple bind instead&lt;sup&gt;&lt;font size=1&gt;*&lt;/font&gt;&lt;/sup&gt;.&amp;nbsp;
The only authentication mechanism defined by LDAP specification is the simple bind,
so every directory implements it.&amp;nbsp; As such, it ends up being the cross-platform
lowest common denominator approach.&amp;nbsp; The problem with the simple bind is that
it is totally insecure by itself.&amp;nbsp; Simple bind passes the user's plaintext credentials
on the network, so unless some sort of channel encryption is provided (like SSL, the
defacto cross-platform standard here as well), anyone who can sniff the wire traffic
can recover the user's password.&amp;nbsp; This sort of thing is generally frowned on
my security enthusiasts.&amp;nbsp; :(
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;Digest Authentication in LDAP API/SDS.P&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
There is, however, a richer set of authentication mechanisms supported by Microsoft's
LDAP API than what ADSI/SDS get to use, and these are available to System.DirectoryServices.Protocols
(SDS.P).&amp;nbsp; One of the most interesting of these is the Digest authentication protocol.&amp;nbsp;
Digest is a &lt;a href="http://www.faqs.org/rfcs/rfc2831.html"&gt;standard&lt;/a&gt;,&amp;nbsp;secure&amp;nbsp;authentication
protocol that does not involve the exchange of plaintext credentials and is implemented
by AD and ADAM, as well as some other LDAP directories.&amp;nbsp; In SDS.P, we can use
it very easily.&amp;nbsp; Here is a short sample illustrating this (and no, there is no
ADAM instance at adam.joekaplan.net; dream on...):
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;bool&lt;/span&gt; DoDigestAuth(NetworkCredential
cred)&lt;br&gt;
{ 
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
const&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;int&lt;/span&gt; LDAP_INVALID_CREDENTIALS &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; 49;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; LdapConnection conn &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; 
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
new&lt;/span&gt; LdapConnection(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"adam.joekaplan.net:389"&lt;/span&gt;);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; conn.AuthType &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; AuthType.Digest;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; conn.Credential &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; cred;&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
try&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; conn.Bind();&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
catch&lt;/span&gt; (LdapException ex)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
if&lt;/span&gt; (ex.ErrorCode == LDAP_INVALID_CREDENTIALS)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;false&lt;/span&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
else&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
throw&lt;/span&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Here, we have a trivial little sample that shows how this might be done.&amp;nbsp; Note
that we probably wouldn't create a new &lt;font face="Courier New"&gt;LdapConnection&lt;/font&gt; object
each time this is called and we'd also try to find a way to clean that up with a proper
Dispose, but the point here is to illustrate that all we really have to do is set
the &lt;font face="Courier New"&gt;AuthType&lt;/font&gt; property to &lt;font face="Courier New"&gt;AuthType.Digest&lt;/font&gt; and
it works.&amp;nbsp; The credentials are specified with a standard &lt;font face="Courier New"&gt;NetworkCredential&lt;/font&gt; object.&amp;nbsp;
For Digest, just specify the username and password, not the domain parameter.
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;Why is This Important?&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
Digest authentication is really interesting particularly for ADAM, as it is supported
by ADAM principals.&amp;nbsp; Before ADAM supported Digest auth (as of SP1), the only
way to authenticate an ADAM principal was with a simple bind.&amp;nbsp; That wasn't secure
(see above), so SSL was required to make it secure.&amp;nbsp; However, SSL certs are not
always easy to procure and take extra effort to install, so many people were missing
this and were insecure.&amp;nbsp; :(
&lt;/p&gt;
&lt;p&gt;
The other cool thing with Digest is that since it is implemented through Microsoft's
SSPI model, it can also be used as a mechanism for getting channel encryption and
signing, just like negotiate auth supports today&lt;sup&gt;&lt;font size=1&gt;**&lt;/font&gt;&lt;/sup&gt;.&amp;nbsp;
This means that not only can you get secure binding for free, but all of your network
traffic after the bind can be encrypted and signed for free (no SSL required).&amp;nbsp;
This is done through setting the &lt;font face="Courier New"&gt;Signing&lt;/font&gt; and &lt;font face="Courier New"&gt;Sealing&lt;/font&gt; properties
to true on the &lt;font face="Courier New"&gt;LdapSessionOptions&lt;/font&gt; class.&amp;nbsp; This,
in turn, allows a way to do LDAP password operations on ADAM principals without using
SSL and without having to change the setting in ADAM to turn off the requirement for
a secure channel on password ops (another big security frown sandwich there...).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
One great scenario for this feature would be to use it with &lt;strong&gt;ADFS for their
ADAM Account Store support&lt;/strong&gt;.&amp;nbsp; This would allow secure authentication
without requiring SSL out of the box and would also provide free channel encryption.&amp;nbsp; &lt;strong&gt;Product
team please take note!&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;sub&gt;* There is a feature in Windows Server 2003 SP1&amp;nbsp;ADSI will try Digest auth
when the Secure flag is specified and ADSI detects that the server supports Digest
but not negotiate auth.&amp;nbsp; However, this doesn't help us for AD or ADAM, since
they both support negotiate auth.&amp;nbsp; The problem with negotiate auth for ADAM is
that it is only used for authenticating Windows users, not ADAM principals.&lt;/sub&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;sub&gt;** There appears to be a bug in the implementation in ADAM SP1 where the channel
encryption feature&amp;nbsp;only works&amp;nbsp;if the network traffic is NOT on the loopback
(localhost) port.&amp;nbsp; This is different from the way negotiate channel encryption
works.&amp;nbsp; This appears to be an oversight in the implementation and not an underlying
issue in the design, so presumably this will get fixed someday.&lt;/sub&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=fcdf0808-8196-4eb7-b171-8b54a5790687" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,fcdf0808-8196-4eb7-b171-8b54a5790687.aspx</comments>
      <category>Identity Federation;LDAP;Windows Security</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=5e43e8de-8367-4ca4-b939-d4ded7a296c8</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,5e43e8de-8367-4ca4-b939-d4ded7a296c8.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,5e43e8de-8367-4ca4-b939-d4ded7a296c8.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=5e43e8de-8367-4ca4-b939-d4ded7a296c8</wfw:commentRss>
      <slash:comments>7</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In a <a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx">previous posting</a>,
I mentioned that even though System.DirectoryServices (SDS) and System.DirectoryServices.Protocols
(SDS.P) share a lot of overlap in functionality, there are some important things
that can only be done in SDS.P.  One that I mentioned is handling server and
client certificates that are using when doing SSL/LDAP.
</p>
        <p>
Both SDS and SDS.P support SSL/LDAP.  Basically, if your server is configured
to support SSL (and both AD and ADAM can support this, although neither have the required
certificates provisioned "out of the box"), you can just turn on SSL LDAP with the
appropriate setting and it will just work.  However, SDS doesn't give you much
control over the process.  It doesn't expose any information about the certificate
the server supplied, nor does it let you choose which client certificate to use (if
a choice is possible).  Additionally, if there is a problem with the server's
certificate such a certificate trust issue or expiration, with SDS, that is automatically
counted as an error.
</p>
        <p>
In SDS.P, we get more control.  Not only can I inspect the certificate to find
out information about it, but i can select my own client certificate and I have control
over whether or not to trust the server's certificate if I want.  I can thus
choose to ignore potential problems (at my peril, of course) and connect anyway.
</p>
        <p>
SDS.P implements the client and server certificate verification stuff via callbacks
implemented as delegates, specifically the <font face="Courier New">QueryClientCertificateCallback</font> and <font face="Courier New">VerifyServerCertificateCallback</font> delegates. 
In order to use them, you create a method with the matching signature of the delegate
and then set the <font face="Courier New">LdapSessionOptions.QueryClientCertificate</font> or <font face="Courier New">LdapSessionOptions.VerifyServerCertificate</font> properties
for options set up on your <font face="Courier New">LdapConnection</font>.  Do
this before you bind.  BTW, the <font face="Courier New">LdapSessionOptions</font> class
is where a lot of the cool advanced features are in SDS.P that allow you access
to features not exposed by SDS.  It is worth spending some time staring at it. 
:)
</p>
        <p>
Here is a brief code snippet example of doing this in C#:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">LdapConnection
con <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> LdapConnection(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> LdapDirectoryIdentifier(dc <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">":636"</span>, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">false</span>));<br />
con.SessionOptions.SecureSocketLayer <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>;<br />
con.SessionOptions.VerifyServerCertificate <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> VerifyServerCertificateCallback(ServerCallback);<br />
con.SessionOptions.QueryClientCertificate <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> QueryClientCertificateCallback(ClientCallback);</span>
        </p>
        <p>
Here, the method ServerCallback looks something like this:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">bool</span> ServerCallback(<br />
LdapConnection connection, 
<br />
X509Certificate certificate<br />
)<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">//do
some stuff here</span><br />
}</span>
        </p>
        <p>
          <font size="4">The Sample App</font>
        </p>
        <p>
Now, let's put this together into a useful example.  In my scenario here, I have
an AD domain with third-party issued certificates that I'm responsible for maintaining
by hand.  If these certificates expire, my apps that use SSL/LDAP may break and
cause me embarassment and scorn amongst my colleagues (or worse).  As such, I'd
like to have a list of the certificates on my DCs in order of expiration, so that
I can plan my renewal/replacement work in advance.
</p>
        <p>
The sample code shows how we can use the <font face="Courier New">VerifyServerCertificateCallback</font> to
simply grab the server's current certificate and find its expiration date.  It
shoves that into an in memory data structure and eventually dumps out the results
to the console.  The sample shows the power of the new System.DirectoryServices.ActiveDirectory
(SDS.AD) namespace to quickly and easily enumerate the DCs in my domain with no hassle. 
This also shows how these two different LDAP stacks can be integrated to do the things
that each is best at.
</p>
        <p>
For good measure, I tried to make the sample fast.  We might have a lot of DCs,
so instead of querying them one at a time and waiting for all that network stuff to
happen, why not use the .NET thread pool and let it hit them "simultaneously" (more
or less)?  Try that with that goofy script stuff.  :)
</p>
        <p>
I wrote this sample using <a href="http://weblogs.asp.net/jkey/">Jeff Key's</a> fantastic <a href="http://www.sliver.com/dotnet/SnippetCompiler/">Snippet
Compiler 2</a>, which is a nice tool for rattling off quicky .NET stuff.  It
doesn't make you bust out VS.NET and create a whole project for throwaway stuff. 
It also doesn't make you buy VS.NET, although Microsoft has made that easier with
the express editions.  Sure, you can always use the free SDK, but this is quite
a bit easier to use than notepad and a hand-written MSBuild file.  You'll need
assembly references to mscorlib,system,system.directoryservices and system.directoryservices.protocols. 
You'll obviously need the .NET 2.0 runtime installed to use the binary.
</p>
        <p>
Enjoy!  All feedback is appreciated.
</p>
        <a href="http://www.joekaplan.net/content/binary/adcertexp.zip">adcertexp.zip (4.66
KB)</a>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=5e43e8de-8367-4ca4-b939-d4ded7a296c8" />
      </body>
      <title>Example 1 for SDS.P: SSL Certificates</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,5e43e8de-8367-4ca4-b939-d4ded7a296c8.aspx</guid>
      <link>http://www.joekaplan.net/Example1ForSDSPSSLCertificates.aspx</link>
      <pubDate>Thu, 03 Aug 2006 19:34:49 GMT</pubDate>
      <description>&lt;p&gt;
In a &lt;a href="http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx"&gt;previous posting&lt;/a&gt;,
I mentioned that even though System.DirectoryServices (SDS)&amp;nbsp;and System.DirectoryServices.Protocols
(SDS.P)&amp;nbsp;share a lot of overlap in functionality, there are some important things
that can only be done in SDS.P.&amp;nbsp; One that I mentioned is handling server and
client certificates that are using when doing SSL/LDAP.
&lt;/p&gt;
&lt;p&gt;
Both SDS and SDS.P support SSL/LDAP.&amp;nbsp; Basically, if your server is configured
to support SSL (and both AD and ADAM can support this, although neither have the required
certificates provisioned "out of the box"), you can just turn on SSL LDAP with the
appropriate setting and it will just work.&amp;nbsp; However, SDS doesn't give you much
control over the process.&amp;nbsp; It doesn't expose any information about the certificate
the server supplied, nor does it let you choose which client certificate to use (if
a choice is possible).&amp;nbsp; Additionally, if there is a problem with the server's
certificate such a certificate trust issue or expiration, with SDS, that is automatically
counted as an error.
&lt;/p&gt;
&lt;p&gt;
In SDS.P, we get more control.&amp;nbsp; Not only can I inspect the certificate to find
out information about it, but i can select my own client certificate and I have control
over whether or not to trust the server's certificate if I want.&amp;nbsp; I can thus
choose to ignore potential problems (at my peril, of course) and connect anyway.
&lt;/p&gt;
&lt;p&gt;
SDS.P implements the client and server certificate verification stuff via callbacks
implemented as delegates, specifically the &lt;font face="Courier New"&gt;QueryClientCertificateCallback&lt;/font&gt; and &lt;font face="Courier New"&gt;VerifyServerCertificateCallback&lt;/font&gt; delegates.&amp;nbsp;
In order to use them, you create a method with the matching signature of the delegate
and then set the &lt;font face="Courier New"&gt;LdapSessionOptions.QueryClientCertificate&lt;/font&gt; or &lt;font face="Courier New"&gt;LdapSessionOptions.VerifyServerCertificate&lt;/font&gt; properties
for options set up on your &lt;font face="Courier New"&gt;LdapConnection&lt;/font&gt;.&amp;nbsp; Do
this before you bind.&amp;nbsp; BTW, the &lt;font face="Courier New"&gt;LdapSessionOptions&lt;/font&gt; class
is where&amp;nbsp;a lot of the cool advanced features are in SDS.P that allow you access
to features not exposed by SDS.&amp;nbsp; It is worth spending some time staring at it.&amp;nbsp;
:)
&lt;/p&gt;
&lt;p&gt;
Here is a brief code snippet example of doing this in C#:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;LdapConnection
con &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; 
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; LdapConnection(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; LdapDirectoryIdentifier(dc &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;":636"&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;false&lt;/span&gt;));&lt;br&gt;
con.SessionOptions.SecureSocketLayer &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;;&lt;br&gt;
con.SessionOptions.VerifyServerCertificate &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; 
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; VerifyServerCertificateCallback(ServerCallback);&lt;br&gt;
con.SessionOptions.QueryClientCertificate &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; 
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; QueryClientCertificateCallback(ClientCallback);&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Here, the method ServerCallback looks something like this:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;bool&lt;/span&gt; ServerCallback(&lt;br&gt;
LdapConnection connection, 
&lt;br&gt;
X509Certificate certificate&lt;br&gt;
)&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;//do
some stuff here&lt;/span&gt;
&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;The Sample App&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
Now, let's put this together into a useful example.&amp;nbsp; In my scenario here, I have
an AD domain with third-party issued certificates that I'm responsible for maintaining
by hand.&amp;nbsp; If these certificates expire, my apps that use SSL/LDAP may break and
cause me embarassment and scorn amongst my colleagues (or worse).&amp;nbsp; As such, I'd
like to have a list of the certificates on my DCs in order of expiration, so that
I can plan my renewal/replacement work in advance.
&lt;/p&gt;
&lt;p&gt;
The sample code shows how we can use the &lt;font face="Courier New"&gt;VerifyServerCertificateCallback&lt;/font&gt; to
simply grab the server's current certificate and find its expiration date.&amp;nbsp; It
shoves that into an in memory data structure and eventually dumps out the results
to the console.&amp;nbsp; The sample shows the power of the new System.DirectoryServices.ActiveDirectory
(SDS.AD) namespace to quickly and easily enumerate the DCs in my domain with no hassle.&amp;nbsp;
This also shows how these two different LDAP stacks can be integrated to do the things
that each is best at.
&lt;/p&gt;
&lt;p&gt;
For good measure, I tried to make the sample fast.&amp;nbsp; We might have a lot of DCs,
so instead of querying them one at a time and waiting for all that network stuff to
happen, why not use the .NET thread pool and let it hit them "simultaneously" (more
or less)?&amp;nbsp; Try that with that goofy script stuff.&amp;nbsp; :)
&lt;/p&gt;
&lt;p&gt;
I wrote this sample using &lt;a href="http://weblogs.asp.net/jkey/"&gt;Jeff Key's&lt;/a&gt; fantastic &lt;a href="http://www.sliver.com/dotnet/SnippetCompiler/"&gt;Snippet
Compiler 2&lt;/a&gt;, which is a nice tool for rattling off quicky .NET stuff.&amp;nbsp; It
doesn't make you bust out VS.NET and create a whole project for throwaway stuff.&amp;nbsp;
It also doesn't make you buy VS.NET, although Microsoft has made that easier with
the express editions.&amp;nbsp; Sure, you can always use the free SDK, but&amp;nbsp;this is&amp;nbsp;quite
a bit easier to use than notepad and a hand-written MSBuild file.&amp;nbsp; You'll need
assembly references to mscorlib,system,system.directoryservices and system.directoryservices.protocols.&amp;nbsp;
You'll obviously need the .NET 2.0 runtime installed to use the binary.
&lt;/p&gt;
&lt;p&gt;
Enjoy!&amp;nbsp; All feedback is appreciated.
&lt;/p&gt;
&lt;a href="http://www.joekaplan.net/content/binary/adcertexp.zip"&gt;adcertexp.zip (4.66
KB)&lt;/a&gt;&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=5e43e8de-8367-4ca4-b939-d4ded7a296c8" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,5e43e8de-8367-4ca4-b939-d4ded7a296c8.aspx</comments>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=46c70dac-3839-42a2-9533-1a9a35003465</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,46c70dac-3839-42a2-9533-1a9a35003465.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,46c70dac-3839-42a2-9533-1a9a35003465.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=46c70dac-3839-42a2-9533-1a9a35003465</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <font size="4">A Tale of Two LDAP Stacks</font>
        <p>
As you may or may not know, .NET contains two completely different ways to program
LDAP.  Version 1.x contained the <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.aspx">System.DirectoryServices</a> (SDS)
namespace, which is a managed wrapper around <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/active_directory_service_interfaces_adsi.asp?frame=true">ADSI</a> and
supports LDAP programming via the LDAP ADSI provider.  This is what most people
tend to think of when then think of LDAP programming in .NET. 2.0 adds a bunch
of new features, but is generally speaking the exact same thing for S.DS.
</p>
        <p>
However, .NET 2.0 also contains something new and entirely different called <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.protocols.aspx">System.DirectoryServices.Protocols</a> (SDS.P). 
Instead of using ADSI, SDS.P interops directly with Microsoft's LDAP API (implemented
in wldap32.dll), which is a lower level mechanism for doing LDAP that provides complete
control over all of the features exposed by the LDAP in general, including some things
that are simply not possible with ADSI (either due to the the design of ADSI or the
fact that they things are obscure enough to have never been wrapped).  Another
interesting aspect of SDS.P is that it also supports the <a href="http://www.oasis-open.org/specs/index.php#dsmlv2">Directory
Services Markup Language</a> (DSML) protocol, which basically let's you talk LDAP
using SOAP over HTTP.  Microsoft actually <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dsml/dsml/portal.asp">ships
a DSML server for AD and ADAM</a>, but it is surprisingly unpopular, especially given
all the focus on SOAP these days.  One of the  big problems for adoption
with DSML in the past was that you had to do all the SOAP stuff in raw XML as there
was no WSDL to generate friendly proxies, so maybe having an easy to program API will
change that?  I've never used it.  :)  Anyway, DSML and "normal" TCP/IP
LDAP are actually implemented using a provider model, which makes the object model
pretty easy to consume for both.  Most of it is identical except for the initial
connection setup.
</p>
        <p>
          <font size="4">It Used to Be So Simple...</font>
        </p>
        <p>
So, which to use?  In the past, there was a great natural disparity between pure
LDAP programming and ADSI programming, as LDAP only supported C or C++ language bindings,
while ADSI was designed from the go for scripting and OLE automation and was vastly
easier to consume.  Even if you really needed some of the features you could
only get with pure LDAP, the C compiler requirement tended to price most people right
out of the skill set needed to accomplish such things.
</p>
        <p>
However, that's really no longer true in .NET 2.0.  While it is definitely the
case that SDS.P is generally more complicated to do the same stuff and will often
take 2x as much code, the difference between the two is actually much smaller. 
For example, I can now program SDS and SDS.P in VB.NET and can actually mix the two
in the same program if I'm so inclined.  The gap is much narrower.
</p>
        <p>
When <a href="http://www.dunnry.com/blog">Ryan</a> and I first started working on <a href="http://www.directoryprogramming.net">the
book</a>, .NET 2.0 was still out on the horizon and we hadn't really seen much SDS.P
yet.  We came from a background of having built some nasty stuff using SDS and
felt like we had some really deeply useful information to share there.  However,
as the writing took us longer and longer and .NET 2.0 got closer and closer, we realized
that a) we really needed to cover .NET 2.0, and b) that SDS.P was a part of the story
that we needed to figure out a way to tell.
</p>
        <p>
The approach we took in the book to deal with this was a little mixed in my opinion. 
We really didn't cover much SDS.P at all.  To the extent that we taught a lot
of the fundamentals of programming AD and ADAM that could apply to any protocol, I
think we were successful in providing a lot of information that could have been easily
translated to SDS.P.  However, we didn't really take the approach of building
up the basics like we did with SDS.  Instead, we basically just dove into SDS.P
when we ran out of room in SDS, leaving some of our SDS.P examples as fairly hairy
(the async one comes to mind here, especially as the first code sample to use SDS.P!). 
Of course, if we had done the opposite, the book would have been much longer and we
might have never finished, so there is that...
</p>
        <p>
The other thing is that Ryan and I are both nerds and SDS.P is kind of like a new
toy, so we are both now tempted to use it for everything, even if it takes twice as
long, just because it is interesting.  However, that doesn't make any practical
sense, especially when someone else is paying for your time and may have less skilled
developers inheriting your stuff!  So, when to use SDS.P?  I'll submit my
humble list and then try to show some examples of some of this stuff over the next
few weeks:
</p>
        <p>
          <font size="4">When You Really DO Need SDS.P</font>
        </p>
        <ul>
          <li>
You really do need to do DSML (maybe I'll meet one of you someday :)) 
</li>
          <li>
Digest authentication against ADAM 
</li>
          <li>
Explicit control over client or server certificate handling with SSL/LDAP 
</li>
          <li>
Phantom root queries 
</li>
          <li>
Fast concurrent binding in AD 2003 and ADAM (not the same as the FastBind flag in
SDS!) 
</li>
          <li>
Access to the LDAP Compare operation 
</li>
          <li>
Working with LDAP V2 directories that support a custom schema (nothing MS ships...) 
</li>
          <li>
Applications where explicit control over the LDAP connection is important for scalability,
such as programmatic LDAP authentication, or web applications that use Kerberos delegation
to acces the directory and support many many different simultaneous users (ADSI really
fights you here) 
</li>
          <li>
Applications where the ADSI schema mapping mechanism is more of a problem than a boon 
</li>
          <li>
Server apps where there can be a real scalability benefit to using the full asynch
capabilities of SDS.P 
</li>
          <li>
Needing to change credentials when chasing a referral (a nasty situation, but sometimes
this happens)</li>
        </ul>
        <p>
There will also always be people who come from an LDAP or JNDI background, for whom
SDS.P will probably feel more comfortable.  Additionally, if one were building
a fully abstracted DAL over an LDAP store, the incremental difference in using SDS.P
might not be so much, especially if you invested up front in some code gen. 
But otherwise, SDS is probably still the sweet spot for most of us.
</p>
        <p>
In my next post on this topic, I'll show how you can do something with SDS.P and SSL
that you simply cannot do in SDS--get the expiration date of each certificate on each
DC in your forest!  If you use external certificates and need to renew by hand,
this is pretty handy.
</p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=46c70dac-3839-42a2-9533-1a9a35003465" />
      </body>
      <title>A Tale of Two LDAP Stacks</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,46c70dac-3839-42a2-9533-1a9a35003465.aspx</guid>
      <link>http://www.joekaplan.net/ATaleOfTwoLDAPStacks.aspx</link>
      <pubDate>Sun, 30 Jul 2006 22:00:33 GMT</pubDate>
      <description>&lt;font size=4&gt;A Tale of Two LDAP Stacks&lt;/font&gt; 
&lt;p&gt;
As you may or may not&amp;nbsp;know, .NET contains two completely different ways to program
LDAP.&amp;nbsp; Version 1.x contained the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.aspx"&gt;System.DirectoryServices&lt;/a&gt; (SDS)
namespace, which is a managed wrapper around &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/active_directory_service_interfaces_adsi.asp?frame=true"&gt;ADSI&lt;/a&gt; and
supports LDAP programming via the LDAP ADSI provider.&amp;nbsp; This is what most people
tend to think of when then think of LDAP programming in .NET.&amp;nbsp;2.0 adds a bunch
of new features, but is generally speaking the exact same thing for S.DS.
&lt;/p&gt;
&lt;p&gt;
However, .NET 2.0 also contains something new and entirely different called &lt;a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.protocols.aspx"&gt;System.DirectoryServices.Protocols&lt;/a&gt; (SDS.P).&amp;nbsp;
Instead of using ADSI, SDS.P interops directly with Microsoft's LDAP API (implemented
in wldap32.dll), which is a lower level mechanism for doing LDAP that provides complete
control over all of the features exposed by the LDAP in general, including some things
that are simply not possible with ADSI (either due to the the design of ADSI or the
fact that they things are obscure enough to have never been wrapped).&amp;nbsp; Another
interesting aspect of SDS.P is that it also supports the &lt;a href="http://www.oasis-open.org/specs/index.php#dsmlv2"&gt;Directory
Services Markup Language&lt;/a&gt; (DSML) protocol, which basically let's you talk LDAP
using SOAP over HTTP.&amp;nbsp; Microsoft actually &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dsml/dsml/portal.asp"&gt;ships
a DSML server for AD and ADAM&lt;/a&gt;, but it is surprisingly unpopular, especially given
all the focus on SOAP these days.&amp;nbsp; One of the&amp;nbsp; big problems for adoption
with DSML in the past was that you had to do all the SOAP stuff in raw XML as there
was no WSDL to generate friendly proxies, so maybe having an easy to program API will
change that?&amp;nbsp; I've never used it.&amp;nbsp; :)&amp;nbsp; Anyway, DSML and "normal" TCP/IP
LDAP are actually implemented using a provider model, which makes the object model
pretty easy to consume for both.&amp;nbsp; Most of it is identical except for the initial
connection setup.
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;It Used to Be So Simple...&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
So, which to use?&amp;nbsp; In the past, there was a great natural disparity between pure
LDAP programming and ADSI programming, as LDAP only supported C or C++ language bindings,
while ADSI was designed from the go for scripting and OLE automation and was vastly
easier to consume.&amp;nbsp; Even if you really needed some of the features you could
only get with pure LDAP, the C compiler requirement tended to price most people right
out of the skill set needed to accomplish such things.
&lt;/p&gt;
&lt;p&gt;
However, that's really no longer true in .NET 2.0.&amp;nbsp; While it is definitely the
case that SDS.P is generally more complicated to do the same stuff and will often
take 2x as much code, the difference between the two is actually much smaller.&amp;nbsp;
For example, I can now program SDS and SDS.P in VB.NET and can actually mix the two
in the same program if I'm so inclined.&amp;nbsp; The gap is much narrower.
&lt;/p&gt;
&lt;p&gt;
When &lt;a href="http://www.dunnry.com/blog"&gt;Ryan&lt;/a&gt; and I first started working on &lt;a href="http://www.directoryprogramming.net"&gt;the
book&lt;/a&gt;, .NET 2.0 was still out on the horizon and we hadn't really seen much SDS.P
yet.&amp;nbsp; We came from a background of having built some nasty stuff using SDS and
felt like we had some really deeply useful information to share there.&amp;nbsp; However,
as the writing took us longer and longer and .NET 2.0 got closer and closer, we realized
that a) we really needed to cover .NET 2.0, and b) that SDS.P was a part of the story
that we needed to figure out a way to tell.
&lt;/p&gt;
&lt;p&gt;
The approach we took in the book to deal with this was a little mixed in my opinion.&amp;nbsp;
We really didn't cover much SDS.P at all.&amp;nbsp; To the extent that we taught a lot
of the fundamentals of programming AD and ADAM that could apply to any protocol, I
think we were successful in providing a lot of information that could have been easily
translated to SDS.P.&amp;nbsp; However, we didn't really take the approach of building
up the basics like we did with SDS.&amp;nbsp; Instead, we basically just dove into SDS.P
when we ran out of room in SDS, leaving some of our SDS.P examples as fairly hairy
(the async one comes to mind here, especially as the first code sample to use SDS.P!).&amp;nbsp;
Of course, if we had done the opposite, the book would have been much longer and we
might have never finished, so there is that...
&lt;/p&gt;
&lt;p&gt;
The other thing is that Ryan and I are both nerds and SDS.P is kind of like a new
toy, so we are both now tempted to use it for everything, even if it takes twice as
long, just because it is interesting.&amp;nbsp; However, that doesn't make any practical
sense, especially when someone else is paying for your time and may have less skilled
developers inheriting your stuff!&amp;nbsp; So, when to use SDS.P?&amp;nbsp; I'll submit my
humble list and then try to show some examples of some of this stuff over the next
few weeks:
&lt;/p&gt;
&lt;p&gt;
&lt;font size=4&gt;When You Really DO Need SDS.P&lt;/font&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
You really do need to do DSML (maybe I'll meet one of you someday :)) 
&lt;li&gt;
Digest authentication against ADAM 
&lt;li&gt;
Explicit control over client or server certificate handling with SSL/LDAP 
&lt;li&gt;
Phantom root queries 
&lt;li&gt;
Fast concurrent binding in AD 2003 and ADAM (not the same as the FastBind flag in
SDS!) 
&lt;li&gt;
Access to the LDAP Compare operation 
&lt;li&gt;
Working with LDAP V2 directories that support a custom schema (nothing MS ships...) 
&lt;li&gt;
Applications where explicit control over the LDAP connection is important for scalability,
such as programmatic LDAP authentication, or web applications that use Kerberos delegation
to acces the directory and support many many different simultaneous users (ADSI really
fights you here) 
&lt;li&gt;
Applications where the ADSI schema mapping mechanism is more of a problem than a boon 
&lt;li&gt;
Server apps where there can be a real scalability benefit to using the full asynch
capabilities of SDS.P 
&lt;li&gt;
Needing to change credentials when chasing a referral (a nasty situation, but sometimes
this happens)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
There will also always be people who come from an LDAP or JNDI background, for whom
SDS.P will probably feel more comfortable.&amp;nbsp; Additionally, if one were building
a fully abstracted DAL over an LDAP store, the incremental difference in using SDS.P
might not be so much, especially if you invested up front in some code gen.&amp;nbsp;
But otherwise, SDS is probably still the sweet spot for most of us.
&lt;/p&gt;
&lt;p&gt;
In my next post on this topic, I'll show how you can do something with SDS.P and SSL
that you simply cannot do in SDS--get the expiration date of each certificate on each
DC in your forest!&amp;nbsp; If you use external certificates and need to renew by hand,
this is pretty handy.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=46c70dac-3839-42a2-9533-1a9a35003465" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,46c70dac-3839-42a2-9533-1a9a35003465.aspx</comments>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://www.joekaplan.net/Trackback.aspx?guid=ac8e564c-1b19-44e7-9ab0-6a4ef74bd614</trackback:ping>
      <pingback:server>http://www.joekaplan.net/pingback.aspx</pingback:server>
      <pingback:target>http://www.joekaplan.net/PermaLink,guid,ac8e564c-1b19-44e7-9ab0-6a4ef74bd614.aspx</pingback:target>
      <dc:creator>Joe Kaplan</dc:creator>
      <wfw:comment>http://www.joekaplan.net/CommentView,guid,ac8e564c-1b19-44e7-9ab0-6a4ef74bd614.aspx</wfw:comment>
      <wfw:commentRss>http://www.joekaplan.net/SyndicationService.asmx/GetEntryCommentsRss?guid=ac8e564c-1b19-44e7-9ab0-6a4ef74bd614</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I've been telling myself I was going to finally get into the blogging racket for almost
2 years now, but even though I've had the hosting all put together for that entire
time, it took me forever to actually get it together.  I just had to do it myself
instead of using another site...
</p>
        <p>
Anyway, this blog will probably resemble the blogs I already read, in that it will
be mostly technical with a focus on building software using Microsoft's .NET platform. 
It will probably lean heavily on my specialties, .NET LDAP programming and application
security, but will likely also feature other stuff I'm into like application architecture,
agile development, identity federation, cryptography, and setup development in MSI
using <a href="http://wix.sourceforge.net">WiX</a>.  
</p>
        <p>
Speaking of .NET and LDAP, if you've ever heard of me before, it is most likely because
you might have stumbled across one of the myriad usenet posts I've made over the last
4-5 years on the Microsoft newsgroups, or perhaps I answered your question directly. 
Micrsosoft has actually designated me an <a href="http://mvp.support.microsoft.com">MVP</a> in
this area, and I've even written a <a href="http://www.directoryprogramming.net">book</a> about
this with my intrepid co-author, <a href="http://www.dunnry.com/blog">Ryan Dunn</a>,
to further our aim of providing resources for the .NET community in this obscure,
but stranglely difficult and increasingly important aspect of software development.
</p>
        <p>
That's all for now.  Maybe some real content next time, eh?
</p>
        <img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=ac8e564c-1b19-44e7-9ab0-6a4ef74bd614" />
      </body>
      <title>About time...</title>
      <guid isPermaLink="false">http://www.joekaplan.net/PermaLink,guid,ac8e564c-1b19-44e7-9ab0-6a4ef74bd614.aspx</guid>
      <link>http://www.joekaplan.net/AboutTime.aspx</link>
      <pubDate>Sun, 30 Jul 2006 15:25:14 GMT</pubDate>
      <description>&lt;p&gt;
I've been telling myself I was going to finally get into the blogging racket for almost
2 years now, but even though I've had the hosting all put together for that entire
time, it took me forever to actually get it together.&amp;nbsp; I just had to do it myself
instead of using another site...
&lt;/p&gt;
&lt;p&gt;
Anyway, this blog will probably resemble the blogs I already read, in that it will
be mostly technical with a focus on building software using Microsoft's .NET platform.&amp;nbsp;
It will probably lean heavily on my specialties, .NET LDAP programming and&amp;nbsp;application
security, but will likely also feature other stuff I'm into like application architecture,
agile development, identity federation, cryptography, and setup development in MSI
using &lt;a href="http://wix.sourceforge.net"&gt;WiX&lt;/a&gt;.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
Speaking of .NET and LDAP, if you've ever heard of me before, it is most likely because
you might have stumbled across one of the myriad usenet posts I've made over the last
4-5 years on the Microsoft newsgroups, or perhaps I answered your question directly.&amp;nbsp;
Micrsosoft has actually designated me an &lt;a href="http://mvp.support.microsoft.com"&gt;MVP&lt;/a&gt; in
this area, and I've even written a &lt;a href="http://www.directoryprogramming.net"&gt;book&lt;/a&gt; about
this with my intrepid co-author, &lt;a href="http://www.dunnry.com/blog"&gt;Ryan Dunn&lt;/a&gt;,
to further our aim of providing resources for the .NET community in this obscure,
but stranglely difficult and increasingly important aspect of software development.
&lt;/p&gt;
&lt;p&gt;
That's all for now.&amp;nbsp; Maybe some real content next time, eh?
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joekaplan.net/aggbug.ashx?id=ac8e564c-1b19-44e7-9ab0-6a4ef74bd614" /&gt;</description>
      <comments>http://www.joekaplan.net/CommentView,guid,ac8e564c-1b19-44e7-9ab0-6a4ef74bd614.aspx</comments>
      <category>General;LDAP;Windows Security;WiX;Identity Federation;Cryptography;Agile;Application Architecture;Software Engineering</category>
    </item>
  </channel>
</rss>