Feature #1838 » bulk_import_ldap2.patch
app/views/auth_sources/_form.rhtml (working copy) | ||
---|---|---|
23 | 23 |
<p><label for="auth_source_base_dn"><%=l(:field_base_dn)%> <span class="required">*</span></label> |
24 | 24 |
<%= text_field 'auth_source', 'base_dn', :size => 60 %></p> |
25 | 25 |
|
26 |
<p><label for="auth_source_user_filter"><%=l(:field_user_filter)%></label> |
|
27 |
<%= text_field 'auth_source', 'user_filter', :size => 60 %></p> |
|
28 |
|
|
26 | 29 |
<p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label> |
27 | 30 |
<%= check_box 'auth_source', 'onthefly_register' %></p> |
28 | 31 |
</div> |
app/views/auth_sources/list.rhtml (working copy) | ||
---|---|---|
19 | 19 |
<td align="center"><%= source.auth_method_name %></td> |
20 | 20 |
<td align="center"><%= source.host %></td> |
21 | 21 |
<td align="center"><%= link_to l(:button_test), :action => 'test_connection', :id => source %></td> |
22 |
<td align="center"><%= link_to l(:button_import_ldap), :action => 'import', :id => source %></td> |
|
22 | 23 |
<td align="center"><%= button_to l(:button_delete), { :action => 'destroy', :id => source }, :confirm => l(:text_are_you_sure), :class => "button-small" %></td> |
23 | 24 |
</tr> |
24 | 25 |
<% end %> |
app/controllers/auth_sources_controller.rb (working copy) | ||
---|---|---|
61 | 61 |
end |
62 | 62 |
end |
63 | 63 |
|
64 |
def import |
|
65 |
@auth_source = AuthSource.find(params[:id]) |
|
66 |
begin |
|
67 |
result = @auth_source.import |
|
68 |
msg = "Found #{result[:found]} users, imported #{result[:imported]}, skipped: #{result[:skipped].join ', '}" |
|
69 |
flash[:notice] = l(msg) |
|
70 |
rescue => err |
|
71 |
flash[:error] = "Unable to import (#{err})" |
|
72 |
end |
|
73 |
redirect_to :action => 'list' |
|
74 |
end |
|
75 |
|
|
64 | 76 |
def test_connection |
65 |
@auth_method = AuthSource.find(params[:id])
|
|
77 |
@auth_source = AuthSource.find(params[:id])
|
|
66 | 78 |
begin |
67 |
@auth_method.test_connection
|
|
79 |
@auth_source.test_connection
|
|
68 | 80 |
flash[:notice] = l(:notice_successful_connection) |
69 | 81 |
rescue => text |
70 | 82 |
flash[:error] = "Unable to connect (#{text})" |
lang/en.yml (working copy) | ||
---|---|---|
560 | 562 |
button_annotate: Annotate |
561 | 563 |
button_update: Update |
562 | 564 |
button_configure: Configure |
565 |
button_import_ldap: Bulk import |
|
563 | 566 |
|
564 | 567 |
status_active: active |
565 | 568 |
status_registered: registered |
db/migrate/096_add_auth_sources_user_filter.rb (revision 0) | ||
---|---|---|
1 |
class AddAuthSourcesUserFilter < ActiveRecord::Migration |
|
2 |
def self.up |
|
3 |
add_column :auth_sources, :user_filter, :string, :default => '(objectClass=*)', :null => true |
|
4 |
end |
|
5 |
|
|
6 |
def self.down |
|
7 |
remove_column :auth_sources, :user_filter |
|
8 |
end |
|
9 |
end |
app/models/auth_source.rb (working copy) | ||
---|---|---|
32 | 32 |
"Abstract" |
33 | 33 |
end |
34 | 34 |
|
35 |
def import |
|
36 |
# bulk create AR User classes from auth_source so |
|
37 |
# users from external auth sources don't need to login |
|
38 |
# just to be visible in the UI |
|
39 |
end |
|
40 |
|
|
35 | 41 |
# Try to authenticate a user not yet registered against available sources |
36 | 42 |
def self.authenticate(login, password) |
37 | 43 |
AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source| |
app/models/auth_source_ldap.rb (working copy) | ||
---|---|---|
21 | 21 |
class AuthSourceLdap < AuthSource |
22 | 22 |
validates_presence_of :host, :port, :attr_login |
23 | 23 |
validates_length_of :name, :host, :account_password, :maximum => 60, :allow_nil => true |
24 |
validates_length_of :account, :base_dn, :maximum => 255, :allow_nil => true |
|
24 |
validates_length_of :account, :base_dn, :user_filter, :maximum => 255, :allow_nil => true
|
|
25 | 25 |
validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true |
26 | 26 |
validates_numericality_of :port, :only_integer => true |
27 | 27 |
|
... | ... | |
59 | 59 |
raise "LdapError: " + text |
60 | 60 |
end |
61 | 61 |
|
62 |
def import |
|
63 |
ldap_con = initialize_ldap_con(self.account, self.account_password) |
|
64 |
if self.user_filter |
|
65 |
search_filter = self.user_filter |
|
66 |
else |
|
67 |
search_filter = Net::LDAP::Filter.eq("objectClass", "*") |
|
68 |
end |
|
69 |
found = created = 0 |
|
70 |
skipped = [] |
|
71 |
ldap_con.search( |
|
72 |
:base => self.base_dn, |
|
73 |
:filter => search_filter, |
|
74 |
:attributes => ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail, self.attr_login] |
|
75 |
) do | entry | |
|
76 |
logger.debug("Found entry with DN: #{entry.dn}") if logger |
|
77 |
found += 1 |
|
78 |
skip = false |
|
79 |
attrs = [:firstname => (AuthSourceLdap.get_attr(entry, self.attr_firstname) != nil ? \ |
|
80 |
AuthSourceLdap.get_attr(entry, self.attr_firstname) : "Unknown"), |
|
81 |
:lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), |
|
82 |
:mail => AuthSourceLdap.get_attr(entry, self.attr_mail), |
|
83 |
:auth_source_id => self.id ] |
|
84 |
#sanity checking (all the above attributes are required) |
|
85 |
login = AuthSourceLdap.get_attr(entry, self.attr_login) |
|
86 |
catch :SKIP do |
|
87 |
skip = false |
|
88 |
attrs.each { |e| |
|
89 |
e.each { |k, v| |
|
90 |
if v == nil |
|
91 |
# give the admin a clue why importing failed... |
|
92 |
logger.debug("User #{login} misses value for attribute '#{k}'.") |
|
93 |
skipped.push(login+"(missing attribute '#{k}')") |
|
94 |
skip = true |
|
95 |
throw :SKIP |
|
96 |
end |
|
97 |
} |
|
98 |
} |
|
99 |
end |
|
100 |
next if skip |
|
101 |
if User.find(:first, :conditions => ["login=?", login]) |
|
102 |
logger.debug("User #{login} already there, skipping...") if logger |
|
103 |
skipped.push(login+'(exists)') |
|
104 |
next |
|
105 |
end |
|
106 |
|
|
107 |
#create user |
|
108 |
begin |
|
109 |
logger.debug("Trying to create user with attrs: %s" % attrs.to_s) if logger |
|
110 |
u = User.create(*attrs) |
|
111 |
u.login = login |
|
112 |
u.language = Setting.default_language |
|
113 |
if u.save |
|
114 |
created += 1 |
|
115 |
else |
|
116 |
skipped.push(login+'(add failed)') |
|
117 |
end |
|
118 |
end |
|
119 |
end |
|
120 |
logger.info("Found #{found} users, imported #{created}.") |
|
121 |
logger.info("Skipped users: #{skipped.join(" ")}") |
|
122 |
return {:found => found, :imported => created, :skipped => skipped} |
|
123 |
end |
|
124 |
|
|
62 | 125 |
# test the connection to the LDAP |
63 | 126 |
def test_connection |
64 | 127 |
ldap_con = initialize_ldap_con(self.account, self.account_password) |