Categorized | Lead Stories

ActiveDirectory and Ruby

Now for something completely different… Since this is a week where I’m only coding (yes!), I thought it would be nice to go over some of the snippets of code that I thought  other voice mashup guys would want to have around.  Here’s one: ActiveDirectory and Ruby.

The short story is Microsoft rules the Enterprise, and there’s nothing anyone can do about that, and Web technologies rule mashups, and never the twain shall meet… without a bit of pain.

The long story: When you sign up to do an Enterprise development, you have to buy into the fact that only Microsoft elements are likely to be available to you.  Don’t expect to see MySQL… expect to see Microsoft SQL Server.  Don’t expect to see Apache… expect to see IIS.  And, if you are dealing with a employee database, expect to see something called ActiveDirectory.  ActiveDirectory is Microsoft’s approach to centralizing employee information and security.  And, as you might imagine it’s pretty darn close to proprietary. So, how do you take that wonderful Web goodness, all condensed for me in Ruby, and stick it into a Microsoft architecture?  Bit by bit.  I needed this little piece of hackery when I did the password reset application: the passwords are all kept on an ActiveDirectory server, yet the voice application is written in Ruby, and sits on Adhearsion and Asterisk.  I needed to be able to:

  1. Read employee data to verify that the inbound caller is who they say they are
  2. Reset the password to some value when they answered the right questions

Luckily, somebody at Microsoft deployed ActiveDirectory on LDAP, which closer to an open standard than they normally get, so we’ve got hope. We’ll use Ruby’s LDAP support to attach to AD.  Here’s my first bit of code. If you want to log in to an Active Directory Server to get information, this will do it for you.  Make sure you include ldap into your script.  Based on an employeeID, this will print out the complete hash of the matching record.

require 'pp'
require 'ldap'
include LDAP

connection= Conn.new('192.168.111.100')
connection.set_option(LDAP_OPT_PROTOCOL_VERSION, 3)
connection.bind("cn=prtldap,ou=accounts,dc=blahsystems,dc=net", "passwurd") do |conn|
base="ou=accounts,dc=blahsystems,dc=net"
results = conn.search2(base, LDAP::LDAP_SCOPE_SUBTREE, '(employeeID=73737)')
results.each { |entry|
puts "------------------"

puts entry.class
entry.each {|k,v| puts "#{k} ==> #{v.inspect}"}
}
end

Let’s clean this up a bit, and then use it to reset somebody’s password. I’ll define the variables up front, and I’ll use SSL to connect up to the server.  Notice the funky Microsoft password encoding block…. scares me.


username = "howethomas"
admin="admin"
password = "passwurd"
newpassword = "neverguessthis"
server_location = "192.168.1.100"
base_dn = "ou=accounts,dc=blahsystems,dc=net"

# require 'rubygems' (required if using outside of rails)
require 'net/ldap'
ldap = Net::LDAP.new
ldap.port = 636 #must be 636 for SSL
ldap.host = server_location
ldap.encryption :simple_tls
ldap.auth admin,password
ldap.bind

# encoding password in format Microsoft wants
newPass = ""
newpassword = "\"" + newpassword + "\""
newpassword.length.times{|i|
newPass+= "#{newpassword[i..i]}\000"
}

#finding location of the user, as the change password operation requires the full path to the user
dn = ldap.search(:filter=> Net::LDAP::Filter.eq("samaccountname",username), :base=>base_dn)[0].dn

#Replace the password

ldap.replace_attribute dn, :unicodePwd, newPass

All there is to it.

Leave a Reply

Twitter

    Got an idea?

    If you have an idea on how to improve how businesses are run using communications, have a nifty product or service, Tell us about it!