Monday, October 8, 2012

LINQ to LDAP: Event Listeners

I'm adding support for listening to Add, Update, and Delete operations in the latest version of LINQ to LDAP. This will allow you to perform validation or logging operations before anything is executed. So let's try this out:



There are 3 interfaces that you can implement to subscribe to events: IPreAddEventListener, IPreDeleteEventListener, IPreUpdateEventListener. Each interface has a Notify method that will give you access to the entry being modified (the mapped object, the DirectoryAttributes, or the Distinguished Name in the case of Delete), the LdapConnection used for the modification, and the DirectoryRequest that will be sent. The DirectoryRequest won't have any of the attribute values added since you may want to do validation beforehand. You can also add / modify anything you want about the request.

Using your event listener is pretty straightforward:



When using the LdapConfiguration you can call RegisterListener and it will be used across all DirectoryContexts. When using the LdapConnection extension methods you can pass it in as a parameter. And that's about it.

Sunday, October 7, 2012

LINQ to LDAP: Attribute Scoped Queries

Active Directory has supported this feature since Windows Server 2003, however I only learned about it recently from Simon Garratt. An attribute scoped query allows you to search within any multivalued attribute of an entry. This becomes really useful when you want to search for users within a group without performing multiple queries.

Say you want to find all users in the sales department for a group:



So what's going on here? I'm looking for User objects stored in "CN=Group,DC=server,DC=com" and I'm using a base search scope since I'm looking within a specific distinguished name.

On the second line I call ScopeToAttribute and I give it the name of the attribute on the group (member in this case). On a side note, ScopeToAtribute is just some syntactic sugar for calling WithControls and passing in a AsqRequestControl.

On the third line I'm just creating a standard filter. Since I'm querying for users my filter will be in that context. I can search on any User property and create any projection from a User.

I think this is pretty cool since it goes for any multivalued attribute that links to other directory entries (members, groups, employees, etc.).

Sunday, July 8, 2012

LINQ to LDAP: The Other Lync

Lync is Microsoft's unified communication platform. It ships with a pretty awesome SDK that makes adding presence information to your WPF and Silverlght apps pretty easy. It's also possible to add presence information to your ASP.Net apps, but it's a little trickier. The first thing you'll need for WPF or Silverlight is the SDK. The installed assemblies should be located in Program Files (or the x86 variant if you're running 64bit) under Microsoft Lync\SDK\Assemblies.

You'll need Microsoft.Lync.Controls.Framework.dll, Microsoft.Lync.Controls.dll, Microsoft.Lync.Model.dll, and Microsoft.Lync.Utilities.dll. Reference those assemblies and you're ready to drop in a control:



The PresenceIndicator control gives you the familiar jelly bean and the image of the person. The Source property should be bound to the user's SIP Uri. What the heck is a SIP Uri? The short version is that it is the address for initiating a communication session with a user via Session Initiation Protocol. You can read the long version here and here.

You may be asking yourself what any of this has to do with LINQ to LDAP. Odds are if you are tracking anything about your users in your applications it's either the sAMAccountName or the Guid. The SIP Uri for those users, however, is stored in the msRTCSIP-PrimaryUserAddress attribute. You can perform a simple lookup to get this attribute. Query by example will not work in this case since the property name is invalid, but mapping or dynamic querying will work.



ASP.Net isn't quite as straightforward. Here's a great post about piggybacking on the NameCtrl in SharePoint 2010. Make sure you do not prefix the uri with "sip:" in the ASP.Net example or it won't work.

Friday, June 22, 2012

LINQ to LDAP: Closer to Home

During my experience with passwords I was working directly with an LdapConnection. After a while I wondered how easy it would be to add extension methods directly to the LdapConnection. It was actually pretty easy so all of the methods that don't rely on object mappings are now available from an LdapConnection object now.

Thursday, June 21, 2012

LINQ to LDAP: How do passwords work?

A couple hours of trial and error I have finally figured out setting passwords in Active Directory and Lightweight Directory Services. As a result of this I ported all of the dynamic functionality to some extension methods for LdapConnection.

Modifying passwords has been in the back of my head ever since the question was asked here. If I had looked closer at the answer on StackOverflow I would have seen that the solution was for Sun-One. If there's one thing I've learned working on LINQ to LDAP it's that every server has been implemented a little differently.

So let's get down to it. The first thing I learned is userPassword in AD LDS is not the "real" password attribute. That would be unicodePwd. I then received a very helpful "An operation error occurred." A few searches later and I found out that means you'll have to use port 636 instead of 389. Turns out Microsoft does not allow changing the password over a non SSL connection. However, you don't have to explicitly set SSL to true if you're post Windows 2000 (I hope you are). Okie dokie let's fire this up.

"The LDAP server is unavailable."

You'll get this error if SSL is not on for your server. This lead me to generating a self signed certificate and installing it for my local instance. You can read about the how and why here. Alright, now my server is responding to requests on 636, but I'm getting "A value in the request is invalid." That's when I found this post explaining how to do this the right way. I wish I had found that first. So here's the resulting code:



For those using AD LDS and you don't have SSL on, let me save you some trouble. I found this post later allowing you to enable modifying the password over port 389. Well I hope this was helpful.

update
I should probably add that you should not enable setting passwords over an unencrypted connection. I am working in a test environment so it's no big deal for me.

Monday, June 11, 2012

LINQ to LDAP: Documentation

Just a minor update. 3.0 is coming. I'm currently reviewing and updating the documentation over at CodePlex. I realized that I haven't touched it since sometime around 1.5 / 2.0 so it's in dire need of a refresh. There are a few things from 3.0 in there so don't download 2.5 and scream "WTF, this is all wrong!" :).

Saturday, June 2, 2012

Stop Checking CanExecute!

I stumbled upon an interesting problem in WPF. I've only seen a few rumblings about it on the internet so it may just be me doing something stupid. I can reproduce it so that's enough for me to look into it.

It's a common setup. There's a view model that manages workspaces (tabs, windows, whatever) similar to Josh Smith's example. However, when removing a view model from the ObservableCollection my view continues to poll the CanExecute of the commands it's bound too. No big deal, just set them to null and raise property changed and problem solved. Well what happens if you just want to unbind your current view and rebind to a new view? The view model has all the state in MVVM after all.

You could have some sort of unbind implementation on your workspaces that will null your commands and reinitialize them (bleh). The simplest option I've found is to set DataContext to null on your view when it unloads.


You can then just inherit from this control and call it a day.


Here's a project demonstrating the problem.

Saturday, March 17, 2012

LINQ To LDAP: 2.5

Been a while since my last post. There are quite a few changes in 2.5, but I want to focus on the biggest ones.

Multiple Naming Contexts and Configurations
First big change is now you can query for mapped objects in any naming context. This makes it easier to reuse a mapping for different parts of the directory or even with a completely different directory. The naming context you specify here will always override whatever you have mapped.
context.Query<User>(namingContext: "naming context");

This leads me to the next change. I've had a lot of questions about having dynamic configurations and multiple directory support. I decided to give you more control over the lifespan of LdapConfiguration. I've also exposed DirectoryMapper so you can share your mappings among multiple configurations. Each configuration has it's own connection factory so this should handle connecting to multiple directories.

You can store your configurations with your favorite IoC container, in a static class, or whatever your preference. You can still use a single global one by calling UseStaticStorage on the configuration.

Custom Mapping
I've also added support for mapping properties to custom values. There's a new method on ClassMap called MapCustom. Here's an example of mapping ObjectGuid as a custom property:
MapCustom(s => s.ObjectGuid).Named("objectGuid")
    .ConvertFromDirectoryUsing(d =>
                                    {
                                        var bytes = d.GetValues(typeof(byte[]))[0] as byte[];
                                        return new Guid(bytes);
                                    })
    .ConvertToFilterUsing(v => v.ToStringOctet())
    .ConvertToDirectoryUsing(v => v.ToByteArray())
    .CompareChangesUsing((guid1, guid2) => guid1.Equals(guid2));
At a minimum you have to implement ConvertFromDirectoryUsing. If you want to filter by it you have to implement ConvertToFilterUsing. And if you want to update the property then you have to implement ConvertToDirectoryUsing. CompareChangesUsing is optional. If you've implemented IDrectoryObject or subclassed DirectoryObjectBase and your custom mapping is for something that can't really use the default Equals implementation then you'll want to implement it.

I've also added support for forwarding values in place of others. Right now it's only available when mapping DateTimes (due to the 9223372036854775807 value meaning "not set"). I plan to expand this to other property types if necessary. Here's how you use it:
Map(c => c.AccountExpires)
    .Named("accountExpires")
    .DateTimeFormat(null)
    .DirectoryValue("9223372036854775807").Returns(null)
    .InstanceValue(DateTime.MinValue).Sends("9223372036854775807")
    .InstanceValueNullOrDefault().Sends("9223372036854775807");

Querying
I just want to add a small note about the Filter class. Previously I was escaping any special characters you passed in. I think now that I should give you more control over the values. You can now use Filter.Equal("attribute", "*"). However, if you want to escape any special characters you can use Filter.Equal("attribute", "some value".CleanFilterValue()).

You can read more about what's in this release here.

Wednesday, January 11, 2012

LINQ To LDAP: More CRUD

I just realized that I never actually finished writing about CRUD operations with LINQ to LDAP. I guess I don't have to worry too much because someone else did it for me! He plans to have a full series on using LINQ to LDAP with Visual Studio LightSwitch.