Tuesday, March 11, 2008

It seems like I've deteriorated into semi-annual blog posts.  Sigh.  At least the discussion groups at www.directoryprogramming.net 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.

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.

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.

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.

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.

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.

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 Ryan there to bounce stuff around with, but so it goes.

Thanks also to Donovan 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.

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 Pamela Dingle 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.

She's got a nice follow up on the Wook Lee Challenge this year which I played a tiny role in.

Customizing-ADFS.zip (1.06 MB)

DotNet-DS-Programming.zip (1.27 MB)

Wednesday, March 12, 2008 3:41:56 AM (Central Daylight Time, UTC-05:00)  #    Comments [3]  | 
Tuesday, October 16, 2007

Given that I haven't posted on this blog for months, I'm not sure if anyone still reads it, but I thought I'd take a few moments to inform my loyal readers of a new addition to the family.

Micah Kaplan Yarbrough was born October 15, 2007 at 11:40 AM at Prentise Women's Hospital (part of Northwestern Memorial Hospital) in downtown Chicago, just like like his older brother Evan.

He arrived 10 days before he was expected and almost a month sooner than his brother (who was quite late) and was a little smaller, but still a robust 7lb 11oz and 20.25" long.

Mom and baby are doing fine.  They are both sleeping right now in fact.  We'll be heading home in a few days and start to figure out the mysteries of chasing two kids around.

Evan is at home with his grandparents right now trying to convince them that he goes to bed at 10:30 usually and get 10 cookies everynight before bed.

Here is a picture at 1 hour old.  He was sleeping then too.  He sleeps a lot so far.  He barely ever cries, but I'm sure he's just building up his strength for later. :)

Tuesday, October 16, 2007 1:23:54 PM (Central Daylight Time, UTC-05:00)  #    Comments [7]  | 
Friday, April 27, 2007

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 presented on at DEC 2006.  This year, I had to fly solo as Ryan could not attend.  :(

Here's what we did differently this time around:

  • No PowerShell (DEC already had 2 PowerShell sessions, so why bother?)
  • Focus on some new Longhorn LDAP and AD features (Fine Grained Password Policy)
  • 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).

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 Addison-Wesley marketing team for providing the books for your enjoyment.

For those of you interested in the Snippet Compiler tool I used in my demos, you can find it here.

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# :)). 

Note that my application of the "in chain" matching rule turns out to be incorrect usage.  Don't do it like that!  Read more here.  I feel silly.

Note that if you are confused about which API to use, S.DS or S.DS.P, I discussed that in some detail here.  There is really no right answer, but hopefully that helps. 

To ask us any specific questions about LDAP programming, please use the book's discussion forum.  This is the only place that Ryan and I both use together.

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...

DEC2007.zip (536.52 KB)
Friday, April 27, 2007 3:58:34 PM (Central Daylight Time, UTC-05:00)  #    Comments [1]  | 

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 here and the syntax looks like this:

(memberOf:1.2.840.113556.1.4.1941:=CN=some group,CN=xxxx,DC=xxxx,DC=xxxx)

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.

Ryan also wrote about this 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.

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.  :)

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. 

Now, when will we get some sort of transitive link expansion widget that actually works well for this purpose?

Friday, April 27, 2007 2:24:21 PM (Central Daylight Time, UTC-05:00)  #    Comments [2]  | 
Sunday, March 04, 2007

I've been using ADFS day in and day out for almost a year now and have run into a fairly stunning number of issues.  Most of these are simple problems with simple solutions, but they can cause hours or days of frustration to resolve.  One of the main themes that seems to pervade these little doses of IT misery is based on a misunderstanding of how cookies work and how ADFS uses cookies.  This post is my attempt to gather some of the lessons I've learned and hopefully make your time with ADFS a little easier. 

How Cookies Work in Web Browsers

Although many of us have a basic, foggy notion about what cookies do in web applications, many of us don't know all of the little rules that govern their behavior.  I'll try to run that down now based on my own understanding, which I believe is at least technically accurate enough for the purposes of the rest of this article.  Feel free to correct me if you know better or refer to the RFCs if you want more precision.

Basically, a cookie is a small piece of textual data that is sent by a web server to a web browser.  The job of the browser is to return this piece of data back to the server when it makes another request to the server, based on the rules that I'll detail shortly.  Cookies are generally used in web applications as a means of maintaining state in the web server across multiple requests made by the browser.

Cookies are implemented as well-known HTTP headers in the request data sent by the browser and the response data sent.  The request header name is called Cookie and the response header name is Set-Cookie.  The server always initiates the usage of cookies by returning a response with a Set-Cookie header in it that contains the data and some other instructions.  The browser's job is to then add a Cookie header on all subsequent requests to the server that contains exactly the data the server sent in the Set-Cookie header.  However, exactly when the browser will add the Cookie header to its request is based on the other instructions in the Set-Cookie header and the rules for cookie behavior. 

First, let's examine the "other instructions".  The Set-Cookie header may contain these bits of info:

  • Name
  • Value
  • Domain (optional)
  • Path (optional)
  • Expires (optional)
  • Secure flag (optional)
  • HttpOnly flag (optional)

Cookie Name and Value

The Cookie Name is just what it sounds like.  Since a web app may use many different cookies, this is how they can be distinguished.  The Cookie Value is just some textual data.  It could be anything.  Oftentimes, it may contain some data that has been encrypted that the browser can't even interpret it--only the server can.  This is not a problem.  The data is for the server anyway.  The browser's job is to dutifully sending it back to the server, not understand it.

Cookie Expires, Secure and HttpOnly

I'll skip ahead to the last three, as they easy to explain and not terribly problematic (for our purposes).  The optional Expires field may contain a date/time value that tells the browser when to stop sending the cookie back to the server.  This one is interesting because it alone determines whether a cookie is a session cookie or a file-based cookie

If there is no expiration specified, the cookie defaults to a session cookie and will be returned as long as the browser session continues.  In IE and FireFox (and probably most other browsers on Windows), the session is basically the duration that the browser process is open.  Note that a browser process may span many windows and may originate in a non-obvious place like an email or an instant messenger client, so you may sometimes be surprised to see a cookie being sent back to a server even after a window was closed (or seemingly all windows for that matter!). 

If the expiration date is set, then the cookie is "file-based" and will be written to disk.  It will survive across multiple browser processes being launched and stopped.  The browser will continue to send it until the expiration time is exceeded.

The Secure flag instructs the browser to only return the cookie back to the server if the request uses the HTTPS (SSL) protocol.  This flag is often used when the cookie contains sensitive data that could be useful by a bad guy if it was intercepted on the wire.  I consider it to be bad practice to ever use any kind of forms-based authentication cookie without the Secure flag set, although this then requires SSL.  If you are serious about security, you use SSL for secure websites.  End of story.

The HttpOnly flag is the new guy and not all browsers support it (although many do).  It basically says that this cookie will only be sent on the wire.  The browser will not allow the cookie to show up in the browser's Document Object Model (DOM) cookie collection.  This prevents scripts from being able to view and manipulate the cookie and can help prevent some kinds of cross-site scripting (XSS) attacks.

Cookie Domain

For our purposes, The Cookie Domain and Path are the most interesting values, as this is the heart of all of the trouble in ADFS, so we cover them last.  The domain specifies which hosts the browser will replay the cookie to.  If the domain is not specified, the browser will only replay the cookie to host that sent the Set-Cookie header in the first place.  Here, the host is determined by the host portion of the URL.  For example, in http://www.joekaplan.net/default.aspx, the host is www.joekaplan.net

Domains can also be specified hierarchically.  I could set the cookie domain to .joekaplan.net and then my browser would return the cookie to any host within the joekaplan.net DNS namespace such as www.joekaplan.net, blogs.joekaplan.net and junk.joekaplan.net (neither of which exist in the latter two examples, but that isn't important).

One might wonder if one can set a cookie for a domain other than the domain of the host.  The answer is "it depends", but usually no.  As one can imagine, this could (and has!) lead to all kinds of crazy hacking where one site writes over another site's cookies.  In IE, the ability to do this is locked down by the various security levels and assigned by zone.  I haven't seen many legitimate uses for such a design personally, so I'm happy this is restricted now.

Another important picky detail about the domain value is that it doesn't consider the port component of the hostname in the URL.  Basically, this means that it treats the host www.joekaplan.net:80 and www.joekaplan.net:8080 as the same host, even if those map to completely different websites on your web server.  This can lead to surprises.

Cookie Path

The final modifier is the Path.  The path value is like the domain, except that is specifies the scope in the path hierarchy that the cookie will be replayed to.  Here, the path is the part of the URL that comes after the host name.  If the path is set to /, then the cookie will be replayed to any part of the hierarchy of the website.  If the path is set to /site, then the cookie will only be replayed to requests for URLs at or below /site.

One tricky detail with the path value is that it is case-sensitive.  If you set the path to /site and your URL is http://www.joekaplan.net/Site/default.aspx (note the capital "S"), guess what?  The cookie will not be returned with the request!  This little gotcha can easily confound IIS developers, as IIS is generally quite happy to treat folders and virtual directories as case-insensitive.  Developers on "other" web server platforms where URLs (and file names) are case-sensitive tend to be a little more hip to this. :)

A Brief Tour of the ADFS Cookies

ADFS, like most other HTTP authentication protocols that don't use the built in HTTP authentication specifications (Basic, Digest, Negotiate, Kerberos, NTLM, etc.), use cookies for a lot of stuff.  There are three primary cookies to know about:

  • Authentication/Token cookie (_WebSsoAuth)
  • Home Realm Cookie (_LSRealm)
  • Logout Cookie (_LSCleanup)

Let's take each in turn.

Authentication/Token Cookie

The _WebSsoAuth cookie is certainly the most important one, as that is the cookie that represents the user's login to a federation resource.  This cookie is always a session cookie, in that the Expires field is never set, so it goes away when the browser process does.  Expiration of this cookie is handled by timestamps set in the data in the cookie itself and is a programmatic feature of the protocol and is not related to how the browser treats cookie expiration. 

The cookie basically contains the SAML 1.1 token issued by a federation server that allows access to a specific resource.  The format of the cookie for ADFS is in some crazy compressed format that MS came up with that isn't documented, but that is supposedly cool because the WS-Federation PRP spec doesn't actually contain any details about what this should look like and leaves it implementation specific.  These cookies are only consumed by the server/app that issued them (hopefully!), so this isn't a big deal.  Sometimes you may see a _WebSsoAuth0 cookie or additional numbering.  This can happen if the SAML token is very large and the compressed size of the XML in the SAML token may exceed the allowed size of a cookie.  ADFS breaks these up for you to overcome this.  This is a picky and unimportant detail for our discussion, but I figured I'd mention it in case you saw it and were curious.

The Set-Cookie header for this cookie usually looks something like this (data clipped for brevity):

Set-Cookie: _WebSsoAuth=eNrNWWuTqkgS9acYzpfd6LV5qAhGd8cWDxUVFMVnbMREASWiQ.....CdagA; path=/adfs/ls/; secure; HttpOnly

In this case, this is the authentication cookie issued by the federation server itself.  In ADFS, each federation server the user logs in to (at least one, maybe two if there is an account partner/resource partner set up) will issue a _WebSsoAuth cookie.  Additionally, each application that the user visits will issue a _WebSsoAuth cookie that is specific to the application. 

Each _WebSsoAuth cookie is different and is intended only for the app/server that issued it.  However, you probably noticed how they all have the same name.  Because they all have the same name, they must different by domain and path so that the browser will know which cookie to send to which app/server.  If you've ever configured an ADFS token-based or claims-based application, you will have noticed that you are required to specify the domain and path for the cookie when configuring the application.  All it takes is a naive mistake with this configuration to cause the browser to start sending the wrong cookie to the wrong place and ADFS chaos ensues.

Home Realm Cookie

The _LSRealm cookie is a file-based cookie issued by the resource federation server after you have successfully logged in that specifies the federation server URI (usually urn:federation:foo or something) of the server that authenticated you.  This is done so that the resource federation server doesn't have to prompt you for your home organization again if it has multiple potential partners.  We already discussed a little bit about these values and home realm discovery query strings in a post last summer, so I won't get into much more detail.  These things rarely cause trouble except that you have to clear your cookies if you want to get a resource federation server to prompt you for your home realm again after you log in the first time.  They are issued for one month as I recall; I'm too lazy to check for certain right now.  :)

Logout Cookie

The _LSCleanup cookie assists in the logout process by keeping track of which federation servers and applications you've visited.  When ADFS does a log out, it attempts to "drain the swamp" by logging you out of everything.  To do this, the built-in logout page attempts to visit the logout URL for every federation server you've visited and every app you've visited.  These logout URLs set the _WebSsoAuth cookie value for the cookies they issued to "null".  This cookie is also a session cookie.  These cookies can get screwed up just like the authentication cookies, but usually this fact never comes up because once the authentication cookies are hosed, things tend to break before you ever try to log out.

Common ADFS Problems Caused by Incorrect Cookie Settings

There are two ADFS problems I've seen frequently that cause much pain that are related to cookie problems and probably some variants that I'm forgetting:

  • Invalid SAML Audience
  • Infinite Loop Detected

Invalid SAML Audience

This occurs when one ADFS application get's another ADFS application's cookie.  Like I said before, each application has an application-specific cookie and there is a piece of data in the SAML token called the audience that says exactly where the cookie was supposed to go.  This is identified by the application's configured URL in the trust policy and the web site. 

There are a variety of ways you can create this error.  One easy way is by setting the cookie domain to something like .domain.com and having your apps set up with host names like app1.domain.com and app2.domain.com.  Since these are both basically children of .domain.com, the browser will happily send a _WebSsoAuth cookie to app2 that app1 issued if the paths are the same.  Since the path is often set to /, this is not uncommon.  You can also have pseudo-chaos that is even more difficult to debug if the path's aren't the same but contain some overlap in hierarchy.

I'm still trying to figure out a reason why you would ever set the cookie domain in an ADFS system.  Generally, you only ever want an ADFS cookie going back to the host that issued it, so why not leave it at the default setting of "null"?  In my experience, nothing but trouble ever comes from setting the domain.  If you think of a use case for setting this, please let me know.

I also mentioned overlapping paths.  These are a significant cause of trouble.  Let's say you have an app at the root of the site / and an app below that /Site.  Basically, if they have the same host name, you can't do that in ADFS.  They need to be strict siblings like /Site1 and /Site2

Overlapping paths can show up in subtle ways as well.  Sometimes, you may not think that overlapping paths are a problem because you aren't aware that you have overlapping domains.  If you use the ADFS Step-by-Step Guide to put together your ADFS demo lab, you may find yourself using host names like this to try out different application styles and using different TCP/IP ports for SSL to split them up in IIS:

  • https://apps.domain.com:8081/
  • https://apps.domain.com:8082/

While this makes things easy from the IIS perspective in terms of setting up multiple sites and it makes it easier to deal with few host names (and less DNS and certificate mucking around), remember that the browser treats those two hosts as being the same thing for cookie purposes.  You now have overlapping domains.  Therefore, it simply falls to the cookie path to make a distinction between them.  If you use a path like:

  • /claimsapp
  • /tokenapp

...for each one, you are fine, but if you naively put one or both of those apps in the root, you will have problems if you try to do SSO between them with the previously mentioned error.

Infinite Loop Errors and the Like

The other problem we can easily create is the "infinite loop" problem or "same token request within the last 20 seconds" problem on the federation server.  I've seen this happen when we have a capitalization different between the browser URL and the cookie path.  As we explained above, the cookie path is treated as case sensitive by the browser, but IIS is generally very happy to treat a URL folder or virtual directory path as case-insensitive.  The problem then manifests itself in ADFS with an interaction like this:

  1. User logs into federation server after being redirected to do so by the application they were trying to access
  2. Federation server generates SAML token for resource application and redirects browser to POST the token to that URL (app.domain.com/site/)
  3. Resource application receives the token via POST, verifies it and issues the browser a cookie with the token contents for use with subsequent visits.  The path in the Set-Cookie header is /Site.  App redirects the user back to itself with the exact URL originally requested.
  4. Browser receives the cookie, but it is using a URL like https://app.domain.com/site/default.aspx, not https://app.domain.com/Site/default.aspx.  Since those are clearly different (note the capital S!), the browser does not include the authentication cookie in the request.
  5. App receives the request from the browser without the cookie and decides "this guy should log in if I'm going to allow access, so go back to my federation server, get a token and I'll see you later" and redirects the user back to the federation server with instructions to sign in.
  6. Federation server is clever and notices that it just issued a token for this user for this app a second ago or so and throws an error because it knows that something just isn't right.

This one is a little subtle, but easily fixable.

Conclusion

Cookies are at the heart and soul of how ADFS works (with the Passive Requester Profile anyway), so understanding the rules that govern their behavior in the browser and how ADFS expects you to use them will save you potentially hours or days of troubleshooting misery. 

Tools for Viewing Headers and Cookies

When working with ADFS (or really just about any web app I've found), having a way to view the raw request and response headers associated with all of the traffic generated by the browser and server is invaluable.  There are great plugins for IE (ieHttpHeaders) and FireFox (Live Headers) that do a fine job of this and are free. 

(edited March 4, 2007, to add some additional formatting, fix some wording and add the section on viewing headers)

Sunday, March 04, 2007 5:09:13 PM (Central Standard Time, UTC-06:00)  #    Comments [2]  | 
Saturday, January 27, 2007

Both of the readers of my blog probably think of me primarily as a .NET LDAP/Security/ADFS guy, and that's fine with me.  The vast majority of my posts aren't about my personal life, so that's what I seem like.  However, those who know me better know that I also play drums and have played in a few bands in my day.

I went on hiatus from doing any serious band stuff after my son was born and thought I was pretty much done.  There does come a time when one packs that sort of thing in, although I'm not certain what that threshold is.

Apparently I haven't quite hit that yet, because I was recently lured back into playing in a band again.  I am now the drummer for Arriver (replacing the dude in the left in the photo), which is basically a metal project started by Dan MacAdam, the guitarist from my previous band, Viza-Noir, and Dan and Rob Sullivan.

I've played with Dan M. for years and have also played with the Sullivan brothers for years as well, although never in a serious songwriting type of band.  The Sullivans and I, along with Jimmy "Bigstacks" Grabowski, formed the core of the legendary Dave LaCrone and the Mistletones, a band that existed only to play a rather insane annual holiday party.  The 'tones also played quite a few of my friends' weddings and a prom in a cover band capacity.

Dan M. played with the Sullivans and their other brother Andy in a straight up bluegrass band called Skeeter Pete and the Sullivan Mountain Boys, which I was fortunate enough to record a few years ago.  Them boys can sing and they pick pretty well too.  :)  I also recorded a record for Dan Sullivan for his Nad Navillus project, which was a singer/songwriter project featuring Dan's virtuoso guitar playing and some more introspective material.

The Sullivan brothers also play in one of the most ambitious rock bands in Chicago, the Butcher Shop Quartet.  The BSQ plays arrangements of contemporary classical pieces for rock band (generally 2x guitar, bass and drums).  They are most famous for their truly impressive rendering of Stravinsky's Rite of Spring, something that has to be heard to be believed.

You are also plenty likely to find Rob playing bass at a bar near you with the Blue Line Riders, a 6 piece honky tonk band with one of the most impressive set lists I've ever seen.

Arriver is a metal band.  This takes me back to my childhood, as that's what I grew up listening to in the South as a kid (didn't everyone?).  However, metal has changed a lot since I was into it.  I had pretty much switched to indy rock by the time thrash metal and speed metal transformed the genre.  We now have blast beats, crazy time signatures and demonic vocals to round out the power chords and "widdly-widdly" guitar solos.  Sick double kick chops are assumed as the price of admission.  I've got a lot of catching up to do. :)

I actually got a double bass drum pedal when I was 16, as all the cool kids had one and I wanted one too.  I used it for years in various band projects, although I never learned how to do the fast metal rolls that you need to have to play this stuff.  20 years later, I sill have the same DW 5000 double kick pedal.  It works ok, but I might need an update.  It is pretty lose and the sprockets are all worn down.

China cymbals, often frowned on in indy rock as being too "something" (having to do with uncool I'm sure) are welcome in metal, so some of my other 20 year old gear is geting a ride again.  I'm actually using 2 on my current set, something I've never done before (a 20+ year old 19" K china and a 10 year old 22" swish knocker with rivets that I bought when they reissued them a few years ago; obnoxious cymbal!).  This part I like quite a lot.  I haven't yet gone over the top with my set-up, still just using a 4 piece kit with 4 cymbals, but the 2 china thing is super fun.  I also only have 1 crash, which is weird for me.  Maybe I'll round this thing out with something that goes "ping". 

The odd time signatures are things I'm pretty used to, so that's less of a struggle.  I'm not going to sound like Meshuggah anytime soon (although the same can be said for a lot of others who are trying way harder than we are), but I know how to play in 5 and 7.  My double kick and blast beats are a little embarassing right now, but that will motivate me to get better.  Arriver has as much appreciation for Man-O-War as we do for the cerebral stuff and is pretty song-oriented in general, so I doubt we'll ever go over the top into pure inaccessibility.

If you are 30+ drummer getting back into music and have decided to add blast beats and blazing double kick into your repertoire, drop me a line and let me know how you did it.  :)

Saturday, January 27, 2007 3:00:29 PM (Central Standard Time, UTC-06:00)  #    Comments [0]  | 
Thursday, January 25, 2007

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.

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 "things you can do in System.DirectoryServices.Protocols that you can't do in System.DirectoryServices".  We already discussed the ability to do Digest authentication and process server certificates.  Today's topic shows how to use S.DS.P's ability to invoke arbitrary extended operations using the ExtendedRequest/ExtendedResponse message types.

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.

One such common extended LDAP operation is the "Who Am I?" operation as defined by RFC 4532.  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). 

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. 

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 :)). 

public class AdamWhoAmI
{
    public static void Main()
    {
        using (LdapConnection con = new LdapConnection("localhost"))
        {
            con.Bind(); //use default credentials. Current user can bind to ADAM...
            
            ExtendedRequest whoami = new ExtendedRequest("1.3.6.1.4.1.4203.1.11.3"); 

            //whoami OID shown above, as per RFC


            ExtendedResponse whoamiResult = (ExtendedResponse) con.SendRequest(whoami);
            Console.WriteLine(System.Text.Encoding.UTF8.GetString(whoamiResult.ResponseValue));

            //the result is a simple byte array that happens to contain UTF8 text
        }
        Console.ReadLine();
    }
}

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:

u:machine\joe

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.

Thursday, January 25, 2007 5:32:39 PM (Central Standard Time, UTC-06:00)  #    Comments [0]  | 
Saturday, October 28, 2006

One of my favorite softies, Eric Fleischman, is doing some S.DS.P programming 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.

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...

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 DistinguishedName 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!

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.

There are two things missing here. 

  • The S.DS.P docs are just embarassing and must be improved.  I'll give it some more time. 
  • 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.

On the bright side, there is a lot of low hanging fruit available here. :)

Saturday, October 28, 2006 4:13:16 AM (Central Daylight Time, UTC-05:00)  #    Comments [1]  | 
Friday, October 27, 2006

Ok, so I've bought a new house, sold my old one, moved and have my life returning to its typical state of order.  Baseball season ended tonight (congrats to the Cards; I couldn't really get into it though), I have broadband and the weather is starting to lend itself towards staying inside.  As such, it is time to start blogging again and getting back into some technology. 

For anyone who may have ever subscribed to this humble sign post and was not impressed by the quantity of content forthcoming, I will now try to ratchet things back up.

On my mind these days are still ADFS and Identity Federation in general (which we are getting close to deploying at the mothership now), directory programming (as usual), crypto and application-level authorization approaches (a la AzMan).  Let's see what I can come up with.  :)

Saturday, October 28, 2006 3:41:47 AM (Central Daylight Time, UTC-05:00)  #    Comments [0]  | 
Friday, October 06, 2006

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.

The intrepid Joe Richards jumped in and with the help of the trusty MVP source access, his brain and a helpful MS employee, found the bug, reported it and created a workaround.  Nice job!  Joe goes into excruciating detail, so I won't add anything to his investigation.

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.

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.

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). 

I discussed this particular function's friend, VerifyServerCertificateCallback, in my posting 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). 

Saturday, October 07, 2006 1:35:50 AM (Central Daylight Time, UTC-05:00)  #    Comments [1]  | 

Theme design by Jelle Druyts