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/lib/adauth/authenticate.rb
CHANGED
@@ -1,74 +1,53 @@
|
|
1
1
|
module Adauth
|
2
|
-
#
|
2
|
+
# Authenticates the specifed user agains the domain
|
3
3
|
#
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
# Checks the groups & ous are in the allow/deny lists
|
5
|
+
def self.authenticate(username, password)
|
6
|
+
begin
|
7
|
+
if Adauth::AdObjects::User.authenticate(username, password)
|
8
|
+
user = Adauth::AdObjects::User.where('sAMAccountName', username).first
|
9
|
+
if allowed_group_login(user) && allowed_ou_login(user)
|
10
|
+
return user
|
11
|
+
else
|
12
|
+
return false
|
13
|
+
end
|
14
|
+
else
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
rescue RuntimeError
|
18
|
+
return false
|
13
19
|
end
|
14
20
|
end
|
15
21
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# Called as
|
19
|
-
# Adauth.authentication("Username")
|
20
|
-
#
|
21
|
-
# Will return `nil` if the username is worng, if the admin details are not set an error will be raised.
|
22
|
-
def self.passwordless_login(login)
|
23
|
-
@conn = Adauth::AdminConnection.bind
|
24
|
-
if user = @conn.search(:filter => Net::LDAP::Filter.eq('sAMAccountName', login)).first
|
25
|
-
return Adauth::User.new(user)
|
26
|
-
else
|
27
|
-
return nil
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Checks weather an users groups are allowed to login
|
32
|
-
#
|
33
|
-
# Called as:
|
34
|
-
# Adauth.allowed_group_login(Adauth::User)
|
35
|
-
#
|
36
|
-
# Returns true if the user can login and false if the user cant
|
22
|
+
# Makes sure the user meets the group requirements
|
37
23
|
def self.allowed_group_login(user)
|
38
24
|
if @config.allowed_groups != []
|
39
|
-
allowed = (user && @config.allowed_groups != (@config.allowed_groups - user.
|
25
|
+
allowed = (user && @config.allowed_groups != (@config.allowed_groups - user.cn_groups)) ? user : nil
|
40
26
|
else
|
41
27
|
allowed = user
|
42
28
|
end
|
43
|
-
|
29
|
+
|
44
30
|
if @config.denied_groups != []
|
45
|
-
denied = (user && @config.denied_groups == (@config.denied_groups - user.
|
31
|
+
denied = (user && @config.denied_groups == (@config.denied_groups - user.cn_groups)) ? user : nil
|
46
32
|
else
|
47
33
|
denied = user
|
48
34
|
end
|
49
|
-
|
50
35
|
allowed == denied
|
51
36
|
end
|
52
37
|
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# Called as:
|
56
|
-
# Adauth.allowed_ou_login(Adauth::User)
|
57
|
-
#
|
58
|
-
# Returns true if the user can login and false if the user cant
|
38
|
+
# Makes sure the user meets the ou requirements
|
59
39
|
def self.allowed_ou_login(user)
|
60
40
|
if @config.allowed_ous != []
|
61
|
-
allowed = (user && @config.allowed_ous != (@config.allowed_ous - user.
|
41
|
+
allowed = (user && @config.allowed_ous != (@config.allowed_ous - user.dn_ous)) ? user : nil
|
62
42
|
else
|
63
43
|
allowed = user
|
64
44
|
end
|
65
|
-
|
45
|
+
|
66
46
|
if @config.denied_ous != []
|
67
|
-
denied = (user && @config.denied_ous == (@config.denied_ous - user.
|
47
|
+
denied = (user && @config.denied_ous == (@config.denied_ous - user.dn_ous)) ? user : nil
|
68
48
|
else
|
69
49
|
denied = user
|
70
50
|
end
|
71
|
-
|
72
51
|
allowed == denied
|
73
52
|
end
|
74
|
-
end
|
53
|
+
end
|
data/lib/adauth/config.rb
CHANGED
@@ -1,40 +1,23 @@
|
|
1
1
|
module Adauth
|
2
|
-
|
3
|
-
#
|
2
|
+
# Holds all of Adauths Config values.
|
3
|
+
#
|
4
|
+
# Sets the defaults an create and generates guess values.
|
4
5
|
class Config
|
5
|
-
attr_accessor :domain, :port, :base, :server, :
|
6
|
-
:
|
6
|
+
attr_accessor :domain, :port, :base, :server, :encryption, :query_user, :query_password,
|
7
|
+
:allowed_groups, :denied_groups, :allowed_ous, :denied_ous
|
7
8
|
|
8
|
-
# Creates a new instance of Adauth::Config
|
9
|
-
#
|
10
|
-
# Sets port, allowed_groups, denied_groups, ad_sv_attrs and ad_mv_attrs to default so they can be omitted from the config
|
11
9
|
def initialize
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@allowed_ous = []
|
18
|
-
@denied_ous = []
|
19
|
-
@ad_sv_group_attrs = {}
|
20
|
-
@ad_mv_group_attrs = {}
|
10
|
+
@port = 389
|
11
|
+
@allowed_groups = []
|
12
|
+
@allowed_ous = []
|
13
|
+
@denied_groups =[]
|
14
|
+
@denied_ous = []
|
21
15
|
end
|
22
16
|
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# Called as:
|
26
|
-
# Adauth::Config.domain=(s)
|
27
|
-
#
|
28
|
-
# Calculates both base string and server
|
17
|
+
# Guesses the Server and Base string
|
29
18
|
def domain=(s)
|
30
19
|
@domain = s
|
31
|
-
work_out_base(s)
|
32
20
|
@server ||= s
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def work_out_base(s)
|
38
21
|
@base ||= s.gsub(/\./,', dc=').gsub(/^/,"dc=")
|
39
22
|
end
|
40
23
|
end
|
data/lib/adauth/connection.rb
CHANGED
@@ -1,32 +1,33 @@
|
|
1
1
|
module Adauth
|
2
|
-
|
3
|
-
# Create a connection to LDAP using Net::LDAP
|
2
|
+
# Active Directory Connection wrapper
|
4
3
|
#
|
5
|
-
#
|
6
|
-
# Adauth::Connection.bind(username, password)
|
7
|
-
#
|
8
|
-
#
|
4
|
+
# Handles errors and configures the connection.
|
9
5
|
class Connection
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
10
9
|
|
11
|
-
#
|
10
|
+
# Attempts to bind to Active Directory
|
12
11
|
#
|
13
|
-
#
|
14
|
-
# Adauth::Connection.bind(username, password)
|
12
|
+
# If it works it returns the connection
|
15
13
|
#
|
16
|
-
#
|
17
|
-
def
|
18
|
-
conn = Net::LDAP.new
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
# If it fails it raises and exception
|
15
|
+
def bind
|
16
|
+
conn = Net::LDAP.new :host => @config[:server],
|
17
|
+
:port => @config[:port],
|
18
|
+
:base => @config[:base]
|
19
|
+
if @config[:encryption]
|
20
|
+
conn.encryption = @config[:encryption]
|
21
|
+
end
|
22
|
+
|
23
|
+
conn.auth "#{@config[:username]}@#{@config[:domain]}", @config[:password]
|
24
|
+
|
24
25
|
begin
|
25
26
|
Timeout::timeout(10){
|
26
27
|
if conn.bind
|
27
28
|
return conn
|
28
29
|
else
|
29
|
-
|
30
|
+
raise "Query User Rejected"
|
30
31
|
end
|
31
32
|
}
|
32
33
|
rescue Timeout::Error
|
data/lib/adauth/rails.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Adauth
|
2
|
+
module Rails
|
3
|
+
# Helper methods for rails
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
# Creates a form_tag for the adauth form
|
7
|
+
#
|
8
|
+
# Sets the html id to "adauth_login" and the form destination to "/adauth"
|
9
|
+
def adauth_form
|
10
|
+
form_tag '/adauth', :id => "adauth_login" do
|
11
|
+
yield.html_safe
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create the default form by calling `adauth_form` and passing a username and password input
|
16
|
+
def default_adauth_form
|
17
|
+
adauth_form do
|
18
|
+
"<p>#{label_tag :username}:
|
19
|
+
#{text_field_tag :username}</p>
|
20
|
+
<p>#{label_tag :password}:
|
21
|
+
#{password_field_tag :password}</p>
|
22
|
+
<p>#{submit_tag "Login!"}</p>"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
ActionView::Base.send :include, Adauth::Rails::Helpers if defined? ActionView
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Adauth
|
2
|
+
module Rails
|
3
|
+
# Included into Models in Rails
|
4
|
+
#
|
5
|
+
# Requires you to set 2 Constants
|
6
|
+
#
|
7
|
+
# AdauthMappings
|
8
|
+
#
|
9
|
+
# A hash which controls how Adauth maps its values to rails e.g.
|
10
|
+
#
|
11
|
+
# AdauthMappings = {
|
12
|
+
# :name => :login
|
13
|
+
# }
|
14
|
+
#
|
15
|
+
# This will store Adauths 'login' value in the 'name' field.
|
16
|
+
#
|
17
|
+
# AdauthSearchField
|
18
|
+
#
|
19
|
+
# This is an array which contains 2 values and is used to find the objects record e.g.
|
20
|
+
#
|
21
|
+
# AdauthSearchField = [:login, :name]
|
22
|
+
#
|
23
|
+
# This will cause RailsModel.find_by_name(AdauthObject.login)
|
24
|
+
#
|
25
|
+
# The Order is [adauth_field, rails_field]
|
26
|
+
module ModelBridge
|
27
|
+
# Registers the class methods when ModelBridge is included
|
28
|
+
def self.included(base)
|
29
|
+
base.extend ClassMethods
|
30
|
+
end
|
31
|
+
|
32
|
+
# Uses AdauthMappings to update the values on the model using the ones from Adauth
|
33
|
+
def update_from_adauth(adauth_model)
|
34
|
+
self.class::AdauthMappings.each do |k, v|
|
35
|
+
setter = "#{k.to_s}=".to_sym
|
36
|
+
self.send(setter, adauth_model.send(v))
|
37
|
+
end
|
38
|
+
self.save
|
39
|
+
end
|
40
|
+
|
41
|
+
# Class Methods for ModelBridge
|
42
|
+
module ClassMethods
|
43
|
+
# Creates a new RailsModel from the adauth_model
|
44
|
+
def create_from_adauth(adauth_model)
|
45
|
+
rails_model = self.new
|
46
|
+
rails_model.update_from_adauth(adauth_model)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Used to create the RailsModel if it doesn't exist and update it if it does
|
50
|
+
def return_and_create_from_adauth(adauth_model)
|
51
|
+
find_method = "find_by_#{self::AdauthSearchField.last}".to_sym
|
52
|
+
rails_model = (self.send(find_method, adauth_model.send(self::AdauthSearchField.first)) || create_from_adauth(adauth_model))
|
53
|
+
rails_model.update_from_adauth(adauth_model)
|
54
|
+
return rails_model
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/adauth/version.rb
CHANGED
@@ -5,53 +5,49 @@ Adauth.configure do |c|
|
|
5
5
|
#
|
6
6
|
# If you don't know your domain contact your IT support,
|
7
7
|
# it will be the DNS suffix applied to your machines
|
8
|
-
c.domain = "example.com"
|
9
|
-
|
8
|
+
c.domain = "example.com"
|
9
|
+
|
10
|
+
# Adauth needs a query user to interact with the domain.
|
11
|
+
# This user can be anything with domain access
|
12
|
+
#
|
13
|
+
# If Adauth doesn't work contact your IT support and make sure this account has full query access
|
14
|
+
c.query_user = "username"
|
15
|
+
c.query_password = "password"
|
16
|
+
|
10
17
|
# The IP address or Hostname of a DC (Domain Controller) on your network
|
11
18
|
#
|
12
19
|
# This could be anything and probably wont be 127.0.0.1
|
13
20
|
#
|
14
21
|
# Again contact your IT Support if you can't work this out
|
15
22
|
c.server = "127.0.0.1"
|
16
|
-
|
23
|
+
|
17
24
|
# The LDAP base of your domain/intended users
|
18
25
|
#
|
19
26
|
# For all users in your domain the base would be:
|
20
27
|
# dc=example, dc=com
|
21
28
|
# OUs can be prepeneded to restrict access to your app
|
22
29
|
c.base = "dc=example, dc=com"
|
23
|
-
|
30
|
+
|
24
31
|
# The port isn't always needed as Adauth defaults to 389 the LDAP Port
|
25
32
|
#
|
26
33
|
# If your DC is on the other side of a firewall you may need to change the port
|
34
|
+
# If your DC is using SSL, the port may be 636.
|
27
35
|
#c.port = 389
|
28
|
-
|
36
|
+
|
37
|
+
# If your DC is using SSL, set encryption to :simple_tls
|
38
|
+
#c.encryption = :simple_tls
|
39
|
+
|
29
40
|
# Windows Security groups to allow
|
30
41
|
#
|
31
42
|
# Only allow members of set windows security groups to login
|
32
|
-
#
|
43
|
+
#
|
33
44
|
# Takes an array for group names
|
34
45
|
#c.allowed_groups = ["Group1", "Group2"]
|
35
|
-
|
46
|
+
|
36
47
|
# Windows Security groups to deny
|
37
48
|
#
|
38
49
|
# Only allow users who aren't in these groups to login
|
39
50
|
#
|
40
51
|
# Takes an array for group names
|
41
52
|
#c.denied_groups = ["Group1", "Group2"]
|
42
|
-
|
43
|
-
# Additional single attributes to fetch
|
44
|
-
#
|
45
|
-
# Single Values to fetch from Active Directory for example phone number
|
46
|
-
#
|
47
|
-
# Takes a hash in the form { :method_on_Adauth::User => :field_in_ad }
|
48
|
-
#c.ad_sv_attrs = { :phone => :telephonenumber }
|
49
|
-
|
50
|
-
# Additional multi attributes to fetch
|
51
|
-
#
|
52
|
-
# Multiple Values to fetch from Active Directory
|
53
|
-
#
|
54
|
-
# Takes a hash in the form { :method_on_Adauth::User => [ :field_in_ad, Proc.new { |g| operations_to_turn_field_into_array } ] }
|
55
|
-
# Example os for groups (already provided)
|
56
|
-
#c.ad_mv_attrs(:groups => [ :memberof, Proc.new {|g| g.sub(/.*?CN=(.*?),.*/, '\1')} ])
|
57
53
|
end
|
@@ -1,8 +1,7 @@
|
|
1
1
|
module Adauth
|
2
2
|
module Generators
|
3
|
-
|
4
3
|
# Generates the sessions controller
|
5
|
-
class SessionsGenerator < Rails::Generators::Base
|
4
|
+
class SessionsGenerator < ::Rails::Generators::Base
|
6
5
|
source_root File.expand_path('../templates', __FILE__)
|
7
6
|
argument :model_name, :type => :string, :default => "user"
|
8
7
|
|
@@ -28,4 +27,4 @@ module Adauth
|
|
28
27
|
end
|
29
28
|
end
|
30
29
|
end
|
31
|
-
end
|
30
|
+
end
|
@@ -6,7 +6,7 @@ class SessionsController < ApplicationController
|
|
6
6
|
def create
|
7
7
|
ldap_user = Adauth.authenticate(params[:username], params[:password])
|
8
8
|
if ldap_user
|
9
|
-
user = <%= model_name.camelize %>.
|
9
|
+
user = <%= model_name.camelize %>.return_and_create_from_adauth(ldap_user)
|
10
10
|
session[:user_id] = user.id
|
11
11
|
redirect_to root_path
|
12
12
|
else
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Adauth::AdObjects::Computer do
|
4
|
+
it "Should find a computer" do
|
5
|
+
default_config
|
6
|
+
pdc.should be_a Adauth::AdObjects::Computer
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be in an ou" do
|
10
|
+
default_config
|
11
|
+
pdc.ous.should be_a Array
|
12
|
+
pdc.ous.first.should be_a Adauth::AdObjects::OU
|
13
|
+
pdc.ous.first.name.should eq "Domain Controllers"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Adauth::AdObjects::Group do
|
4
|
+
it "should have a name" do
|
5
|
+
default_config
|
6
|
+
group = domain_admins
|
7
|
+
group.name.should eq "Domain Admins"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a members list" do
|
11
|
+
default_config
|
12
|
+
group = domain_admins
|
13
|
+
group.members.first.name.should be_a String
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be a member of" do
|
17
|
+
default_config
|
18
|
+
group = domain_admins
|
19
|
+
group.groups.should be_a Array
|
20
|
+
end
|
21
|
+
end
|