-
-
Save juliancheal/5cd9a9e390557f4e14aa to your computer and use it in GitHub Desktop.
Some VERY basic LDAP interaction in Ruby using Net::LDAP.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
####################################################################################################################### | |
# This Gist is some crib notes/tests/practice/whatever for talking to Active Directory via LDAP. The (surprisingly | |
# helpful) documentation for Net::LDAP can be found here: http://net-ldap.rubyforge.org/Net/LDAP.html | |
####################################################################################################################### | |
require 'rubygems' | |
require 'net/ldap' | |
####################################################################################################################### | |
# HELPER/UTILITY METHOD | |
# This method interprets the response/return code from an LDAP bind operation (bind, search, add, modify, rename, | |
# delete). This method isn't necessarily complete, but it's a good starting point for handling the response codes | |
# from an LDAP bind operation. | |
# | |
# Additional details for the get_operation_result method can be found here: | |
# http://net-ldap.rubyforge.org/Net/LDAP.html#method-i-get_operation_result | |
####################################################################################################################### | |
def get_ldap_response(ldap) | |
msg = "Response Code: #{ ldap.get_operation_result.code }, Message: #{ ldap.get_operation_result.message }" | |
raise msg unless ldap.get_operation_result.code == 0 | |
end | |
####################################################################################################################### | |
# SET UP LDAP CONNECTION | |
# Setting up a connection to the LDAP server using .new() does not actually send any network traffic to the LDAP | |
# server. When you call an operation on ldap (e.g. add or search), .bind is called implicitly. *That's* when the | |
# connection is made to the LDAP server. This means that each operation called on the ldap object will create its own | |
# network connection to the LDAP server. | |
####################################################################################################################### | |
ldap = Net::LDAP.new :host => # your LDAP host name or IP goes here, | |
:port => # your LDAP host port goes here, | |
:encryption => :simple_tls, | |
:base => # the base of your AD tree goes here, | |
:auth => { | |
:method => :simple, | |
:username => # a user w/sufficient privileges to read from AD goes here, | |
:password => # the user's password goes here | |
} | |
####################################################################################################################### | |
# ALTERNATIVE FOR OPENING LDAP CONNECTION | |
# Instead of using .new, you can call .open. Within .open's code block, you can perform whatever LDAP operations you | |
# need in the context of a single network connection. | |
####################################################################################################################### | |
host = # your LDAP host name or IP goes here | |
port = # your LDAP host port goes here | |
base = # the base of your AD tree goes here | |
credentials = { | |
:method => :simple, | |
:username => # a user w/sufficient privileges to read from AD goes here, | |
:password => # the user's password goes here | |
} | |
Net::LDAP.open(:host => host, :port => port, :encryption => :simple_tls, :base => base, :auth => credentials) do |ldap| | |
# Do all your LDAP stuff here... | |
end | |
####################################################################################################################### | |
# SOME SIMPLE LDAP SEARCHES | |
####################################################################################################################### | |
# GET THE DISPLAY NAME AND E-MAIL ADDRESS FOR A SINGLE USER | |
search_param = # the AD account goes here | |
result_attrs = ["sAMAccountName", "displayName", "mail"] # Whatever you want to bring back in your result set goes here | |
# Build filter | |
search_filter = Net::LDAP::Filter.eq("sAMAccountName", search_param) | |
# Execute search | |
ldap.search(:filter => search_filter, :attributes => result_attrs) { |item| | |
puts "#{item.sAMAccountName.first}: #{item.displayName.first} (#{item.mail.first})" | |
} | |
get_ldap_response(ldap) | |
# --------------------------------------------------------------------------------------------------------------------- | |
# GET THE DISPLAY NAME AND E-MAIL ADDRESS FOR AN E-MAIL DISTRIBUTION LIST | |
search_param = # the name of the distribution list you're looking for goes here | |
result_attrs = ["sAMAccountName", "displayName", "mail"] # Whatever you want to bring back in your result set goes here | |
# Build filter | |
search_filter = Net::LDAP::Filter.eq("sAMAccountName", search_param) | |
group_filter = Net::LDAP::Filter.eq("objectClass", "group") | |
composite_filter = Net::LDAP::Filter.join(search_filter, group_filter) | |
# Execute search | |
ldap.search(:filter => composite_filter, :attributes => result_attrs) { |item| | |
puts "#{item.sAMAccountName.first}: #{item.displayName.first} (#{item.mail.first})" | |
} | |
get_ldap_response(ldap) | |
# --------------------------------------------------------------------------------------------------------------------- | |
# GET THE MEMBERS OF AN E-MAIL DISTRIBUTION LIST | |
search_param = # the name of the distribution list you're looking for goes here | |
result_attrs = ["sAMAccountName", "displayName", "mail", "member"] | |
# Build filter | |
search_filter = Net::LDAP::Filter.eq("sAMAccountName", search_param) | |
group_filter = Net::LDAP::Filter.eq("objectClass", "group") | |
composite_filter = Net::LDAP::Filter.join(search_filter, group_filter) | |
# Execute search, extracting the AD account name from each member of the distribution list | |
ldap.search(:filter => composite_filter, :attributes => result_attrs) do |item| | |
puts "#{item.sAMAccountName.first}: #{item.displayName.first} (#{item.mail.first})" | |
item.member.map { |m| puts "\taccount: #{m.match(/(?<=\().+?(?=\))/)}" } | |
end | |
get_ldap_response(ldap) | |
# --------------------------------------------------------------------------------------------------------------------- | |
# GET THE DISPLAY NAME AND E-MAIL ADDRESS FOR ALL E-MAIL DISTRIBUTION LISTS | |
# Build filter | |
# This stackoverflow article was a HUGE help: http://stackoverflow.com/questions/6434752/better-way-to-query-an-ldap-users-via-ruby-net-ldap | |
group_filter = Net::LDAP::Filter.eq("objectClass", "group") | |
proxy_address_filter = Net::LDAP::Filter.eq("proxyAddresses", "*") | |
composite_filter = Net::LDAP::Filter.join(group_filter, proxy_address_filter) | |
# Execute search | |
ldap.search(:filter => composite_filter, :attributes => result_attrs) { |item| | |
puts "#{item.sAMAccountName.first}: #{item.mail.first}" | |
} | |
get_ldap_response(ldap) | |
####################################################################################################################### | |
# LDAP FILTER EXAMPLES | |
####################################################################################################################### | |
# CONSTRUCT AN OR FILTER WITH SEVERAL EQUALS | |
# If you come across a situation where you need to search LDAP for this == x | this == y | this == z, there isn't an | |
# easy way to deal with it. The Filter.intersect method takes two arguments, but that isn't enough (because we have | |
# 3 "OR" conditions). Fortunately, Net::LDAP::Filter has a .construct method that will build a valid query string for | |
# us (with a little help): | |
names = ["lstarr", "barf", "dmatrix", "pvespa", "yogurt"] | |
filters = names.map { |name| Net::LDAP::Filter.eq("sAMAccountName", name) } | |
search_filter = Net::LDAP::Filter.construct("(|#{ filters.join("") })") | |
# search_filter => (|(|(|(|(sAMAccountName=lstarr)(sAMAccountName=barf))(sAMAccountName=dmatrix))(sAMAccountName=pvespa))(sAMAccountName=yogurt)) | |
# Ugly, probabaly inefficient, but it'll work. Now we can do this: | |
emails = [] | |
ldap.search(:filter => search_filter, :attributes => ["mail"], :return_result => false) do |result| | |
emails << (result.mail.is_a?(Array) ? result.mail.first : result.mail) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment