adauth 1.2.1 → 2.0.0pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +12 -0
- data/Gemfile.lock +13 -26
- data/Rakefile +1 -0
- data/Readme.md +48 -0
- data/adauth.gemspec +2 -1
- data/lib/adauth.rb +40 -28
- data/lib/adauth/ad_object.rb +104 -0
- data/lib/adauth/ad_objects/computer.rb +28 -0
- data/lib/adauth/ad_objects/group.rb +40 -0
- data/lib/adauth/ad_objects/ou.rb +41 -0
- data/lib/adauth/ad_objects/user.rb +45 -0
- data/lib/adauth/authenticate.rb +25 -46
- data/lib/adauth/config.rb +11 -28
- data/lib/adauth/connection.rb +19 -18
- data/lib/adauth/rails.rb +9 -0
- data/lib/adauth/rails/helpers.rb +29 -0
- data/lib/adauth/rails/model_bridge.rb +59 -0
- data/lib/adauth/version.rb +2 -3
- data/lib/generators/adauth/config/config_generator.rb +1 -1
- data/lib/generators/adauth/config/templates/config.rb.erb +18 -22
- data/lib/generators/adauth/sessions/sessions_generator.rb +2 -3
- data/lib/generators/adauth/sessions/templates/sessions_controller.rb.erb +1 -1
- data/spec/adauth_ad_object_computer_spec.rb +15 -0
- data/spec/adauth_ad_object_group_spec.rb +21 -0
- data/spec/adauth_ad_object_ou_spec.rb +18 -0
- data/spec/adauth_ad_object_user_spec.rb +27 -0
- data/spec/adauth_authenticate_spec.rb +39 -0
- data/spec/adauth_config_spec.rb +15 -0
- data/spec/adauth_rails_model_bridge_spec.rb +37 -0
- data/spec/adauth_spec.rb +2 -30
- data/spec/spec_helper.rb +34 -0
- metadata +52 -38
- data/Readme.rdoc +0 -66
- data/lib/adauth/admin_connection.rb +0 -26
- data/lib/adauth/group.rb +0 -100
- data/lib/adauth/helpers.rb +0 -28
- data/lib/adauth/user.rb +0 -114
- data/lib/adauth/user_model.rb +0 -76
- data/lib/generators/adauth/all/USAGE +0 -5
- data/lib/generators/adauth/all/all_generator.rb +0 -18
- data/lib/generators/adauth/user_model/USAGE +0 -14
- data/lib/generators/adauth/user_model/templates/model.rb.erb +0 -3
- data/lib/generators/adauth/user_model/user_model_generator.rb +0 -32
- data/spec/adauth_group_spec.rb +0 -51
- data/spec/adauth_user_model_spec.rb +0 -80
- data/spec/adauth_user_spec.rb +0 -213
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,41 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
adauth (
|
4
|
+
adauth (2.0.0pre)
|
5
5
|
net-ldap
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
builder (2.1.2)
|
22
|
-
diff-lcs (1.1.2)
|
23
|
-
i18n (0.5.0)
|
24
|
-
net-ldap (0.2.2)
|
25
|
-
rspec (2.6.0)
|
26
|
-
rspec-core (~> 2.6.0)
|
27
|
-
rspec-expectations (~> 2.6.0)
|
28
|
-
rspec-mocks (~> 2.6.0)
|
29
|
-
rspec-core (2.6.1)
|
30
|
-
rspec-expectations (2.6.0)
|
31
|
-
diff-lcs (~> 1.1.2)
|
32
|
-
rspec-mocks (2.6.0)
|
33
|
-
tzinfo (0.3.29)
|
10
|
+
diff-lcs (1.1.3)
|
11
|
+
net-ldap (0.3.1)
|
12
|
+
rake (0.9.2.2)
|
13
|
+
rspec (2.11.0)
|
14
|
+
rspec-core (~> 2.11.0)
|
15
|
+
rspec-expectations (~> 2.11.0)
|
16
|
+
rspec-mocks (~> 2.11.0)
|
17
|
+
rspec-core (2.11.1)
|
18
|
+
rspec-expectations (2.11.2)
|
19
|
+
diff-lcs (~> 1.1.3)
|
20
|
+
rspec-mocks (2.11.2)
|
34
21
|
|
35
22
|
PLATFORMS
|
36
23
|
ruby
|
37
24
|
|
38
25
|
DEPENDENCIES
|
39
|
-
activerecord
|
40
26
|
adauth!
|
27
|
+
rake
|
41
28
|
rspec
|
data/Rakefile
CHANGED
data/Readme.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Adauth
|
2
|
+
[RDoc](http://rubydoc.info/github/Arcath/Adauth/master/frames) | [www](http://adauth.arcath.net) | [Gempage](http://rubygems.org/gems/adauth) | [![Status](https://secure.travis-ci.org/Arcath/Adauth.png?branch=master)](http://travis-ci.org/Arcath/Adauth)
|
3
|
+
|
4
|
+
Easy to use Active Directory Authentication for Rails.
|
5
|
+
|
6
|
+
## Install
|
7
|
+
|
8
|
+
Add the Adauth gem to your Gemfile:
|
9
|
+
|
10
|
+
gem 'adauth'
|
11
|
+
|
12
|
+
and run a bundle install
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
First off create a new config file by running the config generator
|
17
|
+
|
18
|
+
rails g adauth:config
|
19
|
+
|
20
|
+
Fill out the config values in _config/initializers/adauth.rb_
|
21
|
+
|
22
|
+
### Joining a model to Adauth
|
23
|
+
|
24
|
+
If you want to link your user model to Adauth you can use this simple code:
|
25
|
+
|
26
|
+
class User < ActiveRecord::Base
|
27
|
+
include Adauth::Rails::ModelBridge
|
28
|
+
|
29
|
+
AdauthMappings = {
|
30
|
+
:login => :login
|
31
|
+
:group_strings => :cn_groups
|
32
|
+
}
|
33
|
+
|
34
|
+
AdauthSearchField = [:login, :login]
|
35
|
+
end
|
36
|
+
|
37
|
+
This gives you a bridge between Adauth and your model. When you call `User.create_from_adauth(adauth_model)` it does:
|
38
|
+
|
39
|
+
u = User.new
|
40
|
+
u.login = adauth_model.login
|
41
|
+
u.group_strings = adauth_model.cn_groups
|
42
|
+
u.save
|
43
|
+
|
44
|
+
This can be used for any model and anything that you pull over through adauth.
|
45
|
+
|
46
|
+
### SessionsController
|
47
|
+
|
48
|
+
TODO
|
data/adauth.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
2
|
$:.push File.expand_path("../lib", __FILE__)
|
3
3
|
require 'adauth/version'
|
4
4
|
|
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.homepage = "http://adauth.arcath.net"
|
12
12
|
s.summary = "Provides Active Directory authentication for Rails"
|
13
13
|
|
14
|
+
s.add_development_dependency "rake"
|
14
15
|
s.add_development_dependency "rspec"
|
15
16
|
s.add_dependency "net-ldap"
|
16
17
|
|
data/lib/adauth.rb
CHANGED
@@ -1,41 +1,53 @@
|
|
1
|
+
# Requires
|
1
2
|
require 'net/ldap'
|
2
3
|
require 'timeout'
|
4
|
+
# Version
|
3
5
|
require 'adauth/version'
|
4
|
-
|
6
|
+
# Classes
|
7
|
+
require 'adauth/ad_object'
|
8
|
+
require 'adauth/authenticate'
|
5
9
|
require 'adauth/config'
|
6
|
-
require 'adauth/helpers'
|
7
10
|
require 'adauth/connection'
|
8
|
-
|
9
|
-
require 'adauth/
|
10
|
-
require 'adauth/
|
11
|
-
require 'adauth/
|
11
|
+
# AdObjects
|
12
|
+
require 'adauth/ad_objects/computer'
|
13
|
+
require 'adauth/ad_objects/group'
|
14
|
+
require 'adauth/ad_objects/ou'
|
15
|
+
require 'adauth/ad_objects/user'
|
16
|
+
# Rails
|
17
|
+
require 'adauth/rails'
|
18
|
+
require 'adauth/rails/helpers'
|
19
|
+
require 'adauth/rails/model_bridge'
|
12
20
|
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# For Adauths documentation please see the github wiki.
|
21
|
+
# Adauth Container Module
|
16
22
|
module Adauth
|
17
|
-
|
18
|
-
# Used to configure Adauth
|
19
|
-
#
|
20
|
-
# Called as
|
21
|
-
# Adauth.configure do |c|
|
22
|
-
# c.foo = "bar"
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# Configures Adauth and is required for Adauth to work.
|
23
|
+
# Yields a new config object and then sets it as the Adauth Config
|
26
24
|
def self.configure
|
27
|
-
|
28
|
-
|
25
|
+
@config = Config.new
|
26
|
+
yield(@config)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns Adauths current connection to ActiveDirectory
|
30
|
+
def self.connection
|
31
|
+
raise "Adauth needs configuring before use" if @config == nil
|
32
|
+
connect unless @connection
|
33
|
+
@connection
|
29
34
|
end
|
30
35
|
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
def self.config
|
35
|
-
@config
|
36
|
+
# Connects to ActiveDirectory using the query user details
|
37
|
+
def self.connect
|
38
|
+
@connection = Adauth::Connection.new(connection_hash(@config.query_user, @config.query_password)).bind
|
36
39
|
end
|
37
40
|
|
38
|
-
#
|
39
|
-
|
41
|
+
# Generates a hash for the connection class, takes a username and password
|
42
|
+
def self.connection_hash(user, password)
|
43
|
+
{
|
44
|
+
:domain => @config.domain,
|
45
|
+
:server => @config.server,
|
46
|
+
:port => @config.port,
|
47
|
+
:base => @config.base,
|
48
|
+
:encryption => @config.encryption,
|
49
|
+
:username => user,
|
50
|
+
:password => password
|
51
|
+
}
|
40
52
|
end
|
41
|
-
end
|
53
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Adauth
|
2
|
+
# Active Directory Interface Object
|
3
|
+
#
|
4
|
+
# Objects inherit from this class.
|
5
|
+
#
|
6
|
+
# Provides all the common functions for Active Directory.
|
7
|
+
class AdObject
|
8
|
+
# Returns all objects which have the ObjectClass of the inherited class
|
9
|
+
def self.all
|
10
|
+
results = []
|
11
|
+
Adauth.connection.search(:filter => self::ObjectFilter).each do |result|
|
12
|
+
results.push self.new(result)
|
13
|
+
end
|
14
|
+
results
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns all the objects which match the supplied query
|
18
|
+
#
|
19
|
+
# Uses ObjectFilter to restrict to the current object
|
20
|
+
def self.where(field, value)
|
21
|
+
results = []
|
22
|
+
search_filter = Net::LDAP::Filter.eq(field, value)
|
23
|
+
joined_filter = search_filter & self::ObjectFilter
|
24
|
+
Adauth.connection.search(:filter => joined_filter).each do |result|
|
25
|
+
results.push self.new(result)
|
26
|
+
end
|
27
|
+
results
|
28
|
+
end
|
29
|
+
|
30
|
+
# Creates a new instance of the object and sets @ldap_object to the passed Net::LDAP entity
|
31
|
+
def initialize(ldap_object)
|
32
|
+
@ldap_object = ldap_object
|
33
|
+
end
|
34
|
+
|
35
|
+
# Allows direct access to @ldap_object
|
36
|
+
def ldap_object
|
37
|
+
@ldap_object
|
38
|
+
end
|
39
|
+
|
40
|
+
# Over rides method_missing and interacts with @ldap_object
|
41
|
+
def method_missing(method, *args)
|
42
|
+
if self.class::Fields.keys.include?(method)
|
43
|
+
field = self.class::Fields[method]
|
44
|
+
if field.is_a? Symbol
|
45
|
+
return @ldap_object.send(field).to_s
|
46
|
+
elsif field.is_a? Array
|
47
|
+
@ldap_object.send(field.first).collect(&field.last)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns all the groups the object is a member of
|
55
|
+
def groups
|
56
|
+
unless @groups
|
57
|
+
@groups = convert_to_objects(cn_groups)
|
58
|
+
end
|
59
|
+
@groups
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns all the ous the object is in
|
63
|
+
def ous
|
64
|
+
unless @ous
|
65
|
+
@ous = []
|
66
|
+
@ldap_object.dn.split(/,/).each do |entry|
|
67
|
+
@ous.push Adauth::AdObjects::OU.where('name', entry.gsub(/OU=/, '')).first if entry =~ /OU=/
|
68
|
+
end
|
69
|
+
end
|
70
|
+
@ous
|
71
|
+
end
|
72
|
+
|
73
|
+
# CSV Version of the ous list (can't be pulled over from AD)
|
74
|
+
def dn_ous
|
75
|
+
unless @dn_ous
|
76
|
+
@dn_ous = []
|
77
|
+
@ldap_object.dn.split(/,/).each do |entry|
|
78
|
+
@dn_ous.push entry.gsub(/OU=/, '').gsub(/CN=/,'') if entry =~ /OU=/ or entry == "CN=Users"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@dn_ous
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def convert_to_objects(array)
|
87
|
+
out = []
|
88
|
+
array.each do |entity|
|
89
|
+
out.push convert_to_object(entity)
|
90
|
+
end
|
91
|
+
out
|
92
|
+
end
|
93
|
+
|
94
|
+
def convert_to_object(entity)
|
95
|
+
user = Adauth::AdObjects::User.where('sAMAccountName', entity).first
|
96
|
+
group = Adauth::AdObjects::Group.where('sAMAccountName', entity).first
|
97
|
+
(user || group)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Container for Objects which inherit from Adauth::AdObject
|
102
|
+
module AdObjects
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Adauth
|
2
|
+
module AdObjects
|
3
|
+
# Active Directory Computer Object
|
4
|
+
#
|
5
|
+
# Inherits from Adauth::AdObject
|
6
|
+
class Computer < Adauth::AdObject
|
7
|
+
# Field mapping
|
8
|
+
#
|
9
|
+
# Maps methods to LDAP fields e.g.
|
10
|
+
#
|
11
|
+
# :foo => :bar
|
12
|
+
#
|
13
|
+
# Becomes
|
14
|
+
#
|
15
|
+
# Computer.name
|
16
|
+
#
|
17
|
+
# Which calls .name on the LDAP object
|
18
|
+
Fields = {
|
19
|
+
:name => :name
|
20
|
+
}
|
21
|
+
|
22
|
+
# Object Net::LDAP filter
|
23
|
+
#
|
24
|
+
# Used to restrict searches to just this object
|
25
|
+
ObjectFilter = Net::LDAP::Filter.eq("objectClass", "computer")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Adauth
|
2
|
+
module AdObjects
|
3
|
+
# Active Directory Group Object
|
4
|
+
#
|
5
|
+
# Inherits from Adauth::AdObject
|
6
|
+
class Group < Adauth::AdObject
|
7
|
+
# Field mapping
|
8
|
+
#
|
9
|
+
# Maps methods to LDAP fields e.g.
|
10
|
+
#
|
11
|
+
# :foo => :bar
|
12
|
+
#
|
13
|
+
# Becomes
|
14
|
+
#
|
15
|
+
# Computer.name
|
16
|
+
#
|
17
|
+
# Which calls .name on the LDAP object
|
18
|
+
Fields = {
|
19
|
+
:name => :samaccountname,
|
20
|
+
:cn_members => [ :member,
|
21
|
+
Proc.new {|g| g.sub(/.*?CN=(.*?),.*/, '\1')} ],
|
22
|
+
:cn_groups => [ :memberof,
|
23
|
+
Proc.new {|g| g.sub(/.*?CN=(.*?),.*/, '\1')} ]
|
24
|
+
}
|
25
|
+
|
26
|
+
# Object Net::LDAP filter
|
27
|
+
#
|
28
|
+
# Used to restrict searches to just this object
|
29
|
+
ObjectFilter = Net::LDAP::Filter.eq("objectClass", "group")
|
30
|
+
|
31
|
+
# Returns all the objects which are members of this group
|
32
|
+
def members
|
33
|
+
unless @members
|
34
|
+
@members = convert_to_objects(cn_members)
|
35
|
+
end
|
36
|
+
@members
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Adauth
|
2
|
+
module AdObjects
|
3
|
+
# Active Directory OU Object
|
4
|
+
#
|
5
|
+
# Inherits from Adauth::AdObject
|
6
|
+
class OU < Adauth::AdObject
|
7
|
+
# Field mapping
|
8
|
+
#
|
9
|
+
# Maps methods to LDAP fields e.g.
|
10
|
+
#
|
11
|
+
# :foo => :bar
|
12
|
+
#
|
13
|
+
# Becomes
|
14
|
+
#
|
15
|
+
# Computer.name
|
16
|
+
#
|
17
|
+
# Which calls .name on the LDAP object
|
18
|
+
Fields = {
|
19
|
+
:name => :name
|
20
|
+
}
|
21
|
+
|
22
|
+
# Object Net::LDAP filter
|
23
|
+
#
|
24
|
+
# Used to restrict searches to just this object
|
25
|
+
ObjectFilter = Net::LDAP::Filter.eq("objectClass", "organizationalUnit")
|
26
|
+
|
27
|
+
# Returns all objects contained with in this OU
|
28
|
+
def members
|
29
|
+
unless @members
|
30
|
+
@members = []
|
31
|
+
[Adauth::AdObjects::Computer, Adauth::AdObjects::Group, Adauth::AdObjects::User].each do |object|
|
32
|
+
object.all.each do |entity|
|
33
|
+
@members.push entity if entity.ldap_object.dn =~ /#{@ldap_object.dn}/
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@members
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Adauth
|
2
|
+
module AdObjects
|
3
|
+
# Active Directory User Object
|
4
|
+
#
|
5
|
+
# Inherits from Adauth::AdObject
|
6
|
+
class User < Adauth::AdObject
|
7
|
+
# Field mapping
|
8
|
+
#
|
9
|
+
# Maps methods to LDAP fields e.g.
|
10
|
+
#
|
11
|
+
# :foo => :bar
|
12
|
+
#
|
13
|
+
# Becomes
|
14
|
+
#
|
15
|
+
# Computer.name
|
16
|
+
#
|
17
|
+
# Which calls .name on the LDAP object
|
18
|
+
Fields = { :login => :samaccountname,
|
19
|
+
:first_name => :givenname,
|
20
|
+
:last_name => :sn,
|
21
|
+
:email => :mail,
|
22
|
+
:name => :name,
|
23
|
+
:cn_groups => [ :memberof,
|
24
|
+
Proc.new {|g| g.sub(/.*?CN=(.*?),.*/, '\1')} ]
|
25
|
+
}
|
26
|
+
|
27
|
+
# Object Net::LDAP filter
|
28
|
+
#
|
29
|
+
# Used to restrict searches to just this object
|
30
|
+
ObjectFilter = Net::LDAP::Filter.eq("objectClass", "user")
|
31
|
+
|
32
|
+
# Returns a connection to AD within the users context, used to check a user credentails
|
33
|
+
#
|
34
|
+
# Using this would by pass the group and OU Filtering provided by Adauth#authenticate
|
35
|
+
def self.authenticate(user, password)
|
36
|
+
user_connection = Adauth::Connection.new(Adauth.connection_hash(user, password)).bind
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns True/False if the user is member of the cupplied group
|
40
|
+
def member_of?(group)
|
41
|
+
cn_groups.include?(group)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|