Code Monkey home page Code Monkey logo

active_directory's Introduction

*** Well, I was full of hope to modify this code and bring it up to speed with the latest Rails 4+ and Active Directory, etc.... but too many other projects got in the way. Perhaps some day.***

= Active Directory

Ruby Integration with Microsoft's Active Directory system based on original code by Justin Mecham and James Hunt at http://rubyforge.org/projects/activedirectory

See documentation on ActiveDirectory::Base for more information.

Caching: Queries for membership and group membership are based on the distinguished name of objects. Doing a lot of queries, especially for a Rails app, is a sizable slowdown. To alleviate the problem, I've implemented a very basic cache for queries which search by :distinguishedname. This is diabled by default. All other queries are unaffected.

INSTALL (with Bundler for instance)

In Gemfile:
gem 'active_directory', :git => 'git://github.com/richardun/active_directory.git'

Run bundle install: :; is my prompt

:; bundle install

Base setup

You can do this next part however you like, but I put the settings global variable in ../config/initializers/ad.rb...
# Uses the same settings as net/ldap
AD_SETTINGS = {
	:host => 'domain-controller.example.local',
	:base => 'dc=example,dc=local',
	:port => 636,
	:encryption => :simple_tls,
	:auth => {
	  :method => :simple,
	  :username => "username",
	  :password => "password"
	}
}

Simple finds using attributes

Then I put the base initialization in ../app/controllers/application_controller.rb...
ActiveDirectory::Base.setup(settings)

Then in my model, or anywhere really, I can look for AD users, etc.

ActiveDirectory::User.find(:all)
ActiveDirectory::User.find(:first, :userprincipalname => "[email protected]")

ActiveDirectory::Group.find(:all)

#Caching is disabled by default, to enable:
ActiveDirectory::Base.enable_cache
ActiveDirectory::Base.disable_cache
ActiveDirectory::Base.cache?

ActiveRecord example

You can also limit the fields that get returned, just like with ActiveRecord.

In ActiveRecord, you use ":select => ['select this', 'or', 'that']" - you can do this or use the net/ldap syntax of ":attributes => ..." You should use one or the other, but not both.

ad_user = ActiveDirectory::User.find(:all, :attributes => ['givenname', 'sn'])

# if you don't give it an array and just one item, that's ok too...
ad_user = ActiveDirectory::User.find(:all, :attributes => 'givenname')

puts ad_user.givenname #=> Richard
puts ad_user.sn #=> Navarrete
puts ad_user.name #=> Richard Navarrete

# But looking for a field you didn't return will raise an ArgumentError.
puts ad_user.mail #=> ArgumentError: no id given

Net::LDAP::Filter

You can pass any filter you can make in Net::LDAP::Filter along in the find.
In this example, I have a couple of groups that a given user can be a member of.
If they are a member of either of the groups (memberOf) then a user will be returned.
groups = ['CN=admins,OU=Security,OU=Groups,DC=Example,DC=Local', 'CN=HR,OU=Security,OU=Groups,DC=Example,DC=Local']

# Don't miss this important step -> be sure to put double quotes in the value, no matter if it's a
# single variable string that you're interpolating... it must be there or Net::LDAP::Filter will
# treat it like an Array and won't find gsub and error out!
filter = Net::LDAP::Filter.eq('distinguishedName', "#{session[:current_user][:dn]}")


# Same thing here with the memberOf equals... must have double quotes!
# Notice the |= under else, this will make the groups all OR conditions.
# Obviously replace this with &= if you require that the give user be 
# a member of ALL the given groups. 
right_filter = nil
groups.each do |group|
    if right_filter.nil?
        right_filter = Net::LDAP::Filter.eq('memberOf', "#{group}")
    else
        right_filter |= Net::LDAP::Filter.eq('memberOf', "#{group}")
    end
end

filter = filter & (right_filter)

# Assuming you already setup the Base, but just in case...
ActiveDirectory::Base.setup(AD_SETTINGS)

ad_user = ActiveDirectory::User.find(:all, filter)

Updating thumbnailPhoto attribute in AD!

First, why would you want to do this? I did it so that users could upload a photo in one place, and it would update other applications with user avatars where it was more convenient instead of making those applications point to a URL. Basically, if you update thumbnailPhoto with an image, the user pic will show up for users in MS Outlook, MS Lync, etc. Here is something I included in a user model (with email as an attribute), to update the corresponding AD account with a thumbnailPhoto. Use AD gem's "update_attribute."
def update_ad_profile_pic
    begin
        ad_user = ActiveDirectory::User.find(:first, :mail => self.email)
        if ad_user.present?
            picture_data = image_to_bytes
            ad_user.update_attribute(:thumbnailPhoto, picture_data)
        else
            false
        end
    rescue Exception => e
        logger.error("** Failed updating AD photo for: #{self.email} \n#{e.message}")
    end
end

private

convert this user's "image_tiny" byte-by-byte and return

using Dragonfly here for the image, but you can use anything... it's just an image

def image_to_bytes picture_data = "" file = File.open("#{Rails.root}/public/#{self.image_tiny.remote_url}",'rb') file.read.each_byte do |byte| picture_data << byte end file.close picture_data end

active_directory's People

Contributors

ajrkerr avatar frsantos avatar jhunt avatar keithpitty avatar mikegee avatar richardun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

active_directory's Issues

ArgumentError on member_of? in only some cases

I'm getting an ArgumentError ("no id given") when I use member_of? on only certain users.

Here's an example:

require 'active_directory'

Load settings from file in config/

AD_PEOPLE_SETTINGS = YAML.load_file("#{Rails.root.to_s}/config/database.yml")['ad_people']
AD_GROUPS_SETTINGS = YAML.load_file("#{Rails.root.to_s}/config/database.yml")['ad_groups']

Will be the user later

u = nil

Run through multiple paths in the tree to find where the user is kept

AD_PEOPLE_SETTINGS.each do |entry|
settings = {
:host => entry['host'],
:base => entry['base'],
:port => 636,
:encryption => :simple_tls,
:auth => {
:method => :simple,
:username => entry['user'],
:password => entry['pass']
}
}

puts "Trying #{entry['base']}"

ActiveDirectory::Base.setup(settings)
u = ActiveDirectory::User.find(:first, :samaccountname => "the_problem_user")
break unless u.nil?
end

u is a valid user at this point, load the desired group

settings = {
:host => AD_GROUPS_SETTINGS['host'],
:base => AD_GROUPS_SETTINGS['base'],
:port => 636,
:encryption => :simple_tls,
:auth => {
:method => :simple,
:username => AD_GROUPS_SETTINGS['user'],
:password => AD_GROUPS_SETTINGS['pass']
}
}

ActiveDirectory::Base.setup(settings)
g = ActiveDirectory::Group.find(:first, :cn => "the_group")

u.member_of? g # throws ArgumentError

It's also an inconsistent error. For instance, in writing this test case using a certain loginid, the problem stopped happening and I had to try another user to recreate the problem.

Any idea how I can debug this?

Issue with "member_of?" function

I get an error when I am attempting to add a user to a group they already belong to:

group.has_member?(user)
TypeError: can't convert Symbol into Integer
from /home/acaeti/.rvm/gems/ruby-1.9.3-p392/gems/active_directory-1.5.5/lib/active_directory/base.rb:345:in []' from /home/acaeti/.rvm/gems/ruby-1.9.3-p392/gems/active_directory-1.5.5/lib/active_directory/base.rb:345:in=='
from /home/acaeti/.rvm/gems/ruby-1.9.3-p392/gems/active_directory-1.5.5/lib/active_directory/member.rb:31:in include?' from /home/acaeti/.rvm/gems/ruby-1.9.3-p392/gems/active_directory-1.5.5/lib/active_directory/member.rb:31:inmember_of?'
from /home/acaeti/.rvm/gems/ruby-1.9.3-p392/gems/active_directory-1.5.5/lib/active_directory/group.rb:48:in has_member?' from (irb):31 from /home/acaeti/.rvm/rubies/ruby-1.9.3-p392/bin/irb:13:in

'

It seems to stem from code in the member.rb function "member_of?".

At line 28 in member.rb it seems you set a variable "group_dns":
group_dns = memberOf
And at line 31 you see if this "includes?" the DN of the group in question:
group_dns.include?(usergroup.dn)

However, the "group_dns" is an Array of ActiveDirectory::Group objects, which is being compared by the include?() to a Net::BER::BerIdentifiedString. This isn't going to work :).

I think the line 31 code should be "group_dns.include?(usergroup)" instead.

"memberof" attribute very slow

Hello

It seems the "memberof" attribute is slow. For example, if I do this:

aduser = ActiveDirectory::User.find(:first, :samaccountname => "something")
aduser.memberof

Depending on the number of groups the user is a member of, this can be super slow. I had tried this with caching (and performed my User.find against a distinguished name) but it was still pretty slow.

Is there any way to speed this up?

Same credentials on subsequent connections?

hello, I'm trying to use your gem to authenticate my application users through Active Directory server.

My approach is the following:

  1. Connect to ldap server with a granted user
  2. Searching for user by 'givenname' attribute
  3. Trying to connect again to ldap server using user's givenname and password
  4. if it connects, ok everything is ok

Anyway I discovered that it doesn't work because it does not close and open again the connection with the updated parameters when you change them.

Thanks in advance.

Davide

Cannot use a filter and an attributes at the same time

Hello,

Seems I can run a query using either a filter, or attributes, but not both.

If I try to specify both:

user = ActiveDirectory::Users.find(:all, filter, :select => ['sn','givenname'])

I get back results as if I submitted only the filter.

Attributes work fine if I submit with a simple-type find, however:

user = ActiveDirectory::Users.find(:all, :displayname => "Bob*", :select => ['sn','givenname'])

NPM

ActiveDirectory::User.member_of? fails if the wrong server is selected

(Note: This may be the intended behavior but I had no indication this was occurring and had to do some head scratching to figure it out.)

We use two AD servers, one with users and the other with groups. If I fail to re-call ActiveDirectory::Base.setup for the group server, User.member_of? returns false even if the answer is true.

Hash.blank? is Rails-specific

Hash.blank? does not work under irb but does work under the Rails console. As far as I can tell, Rails has augmented the Hash class.

It would be nice if active_directory did not necessarily require Rails.

For example, try searching for a user, which eventually invokes this line in base.rb:246:

options = {
:filter => (args[1].blank?) ? NIL_FILTER : args[1],
:in => '',
:attributes => Array.new
}

args[1].blank? fails in irb, i.e. try {}.blank? and see what happens.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.