adauth 1.2.1 → 2.0.0pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|