Patch #1568 ยป htauth_patch.patch
| app/controllers/auth_sources_controller.rb (working copy) | ||
|---|---|---|
| 34 | 34 |
end |
| 35 | 35 | |
| 36 | 36 |
def new |
| 37 |
@auth_source = AuthSourceLdap.new |
|
| 37 |
if params[:id]=='file' |
|
| 38 |
@auth_source = AuthSourceFile.new |
|
| 39 |
else |
|
| 40 |
@auth_source = AuthSourceLdap.new |
|
| 41 |
end |
|
| 38 | 42 |
end |
| 39 | 43 | |
| 40 | 44 |
def create |
| 41 |
@auth_source = AuthSourceLdap.new(params[:auth_source]) |
|
| 45 |
if params[:id]=='file' |
|
| 46 |
@auth_source = AuthSourceFile.new(params[:auth_source]) |
|
| 47 |
else |
|
| 48 |
@auth_source = AuthSourceLdap.new(params[:auth_source]) |
|
| 49 |
end |
|
| 42 | 50 |
if @auth_source.save |
| 43 | 51 |
flash[:notice] = l(:notice_successful_create) |
| 44 | 52 |
redirect_to :action => 'list' |
| ... | ... | |
| 47 | 55 |
end |
| 48 | 56 |
end |
| 49 | 57 | |
| 58 | ||
| 59 | ||
| 60 | ||
| 50 | 61 |
def edit |
| 51 | 62 |
@auth_source = AuthSource.find(params[:id]) |
| 52 | 63 |
end |
| app/controllers/users_controller.rb (working copy) | ||
|---|---|---|
| 56 | 56 |
@user = User.new(params[:user]) |
| 57 | 57 |
@user.admin = params[:user][:admin] || false |
| 58 | 58 |
@user.login = params[:user][:login] |
| 59 |
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id |
|
| 59 |
if @user.passwd? |
|
| 60 |
@user.password = params[:password] |
|
| 61 |
@user.password_confirmation = params[:password_confirmation] |
|
| 62 |
end |
|
| 60 | 63 |
if @user.save |
| 61 | 64 |
Mailer.deliver_account_information(@user, params[:password]) if params[:send_information] |
| 62 | 65 |
flash[:notice] = l(:notice_successful_create) |
| app/models/auth_source.rb (working copy) | ||
|---|---|---|
| 20 | 20 |
|
| 21 | 21 |
validates_presence_of :name |
| 22 | 22 |
validates_uniqueness_of :name |
| 23 |
validates_length_of :name, :host, :maximum => 60 |
|
| 24 |
validates_length_of :account_password, :maximum => 60, :allow_nil => true |
|
| 25 |
validates_length_of :account, :base_dn, :maximum => 255 |
|
| 26 |
validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30 |
|
| 23 |
validates_length_of :name, :maximum => 60 |
|
| 24 |
validates_length_of :account, :maximum => 255 |
|
| 27 | 25 | |
| 28 | 26 |
def authenticate(login, password) |
| 29 | 27 |
end |
| 28 | ||
| 29 |
def passwd? |
|
| 30 |
false |
|
| 31 |
end |
|
| 30 | 32 |
|
| 31 | 33 |
def test_connection |
| 32 | 34 |
end |
| app/models/auth_source_file.rb (revision 0) | ||
|---|---|---|
| 1 |
# redMine - project management software |
|
| 2 |
# Copyright (C) 2006 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 | ||
| 18 |
require 'htauth' |
|
| 19 | ||
| 20 |
class AuthSourceFile < AuthSource |
|
| 21 | ||
| 22 |
validates_presence_of :account |
|
| 23 |
|
|
| 24 |
def authenticate(login, password) |
|
| 25 |
return nil if login.blank? || password.blank? |
|
| 26 |
HTAuth::PasswdFile.open(self.account) do |pf| |
|
| 27 |
dn = pf.fetch(login) |
|
| 28 |
if dn and dn.authenticated?(password) |
|
| 29 |
logger.debug "Authenticated #{login}: #{dn}" if logger && logger.debug?
|
|
| 30 |
return true |
|
| 31 |
else |
|
| 32 |
return false |
|
| 33 |
end |
|
| 34 |
end |
|
| 35 |
end |
|
| 36 |
|
|
| 37 |
def passwd? |
|
| 38 |
true |
|
| 39 |
end |
|
| 40 | ||
| 41 |
def passwd(login,password) |
|
| 42 |
return false if login.blank? || password.blank? |
|
| 43 |
HTAuth::PasswdFile.open(self.account) do |pf| |
|
| 44 |
logger.debug "add_or_update #{login}" if logger && logger.debug?
|
|
| 45 |
pf.add_or_update(login,password) |
|
| 46 |
return true |
|
| 47 |
end |
|
| 48 |
end |
|
| 49 | ||
| 50 |
# test the connection to the LDAP |
|
| 51 |
def test_connection |
|
| 52 |
con = HTAuth::PasswdFile.open(self.account) |
|
| 53 |
return con.is_a?(HTAuth::PasswdFile) |
|
| 54 |
end |
|
| 55 |
|
|
| 56 |
def auth_method_name |
|
| 57 |
"HTAUTH" |
|
| 58 |
end |
|
| 59 |
|
|
| 60 |
private |
|
| 61 |
end |
|
| 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_presence_of :attr_firstname, :attr_lastname, :attr_mail, :if => Proc.new { |a| a.onthefly_register? }
|
| 24 |
validates_length_of :host, :maximum => 60 |
|
| 25 |
validates_length_of :account_password, :maximum => 60, :allow_nil => true |
|
| 26 |
validates_length_of :base_dn, :maximum => 255 |
|
| 27 |
validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30 |
|
| 24 | 28 |
|
| 25 | 29 |
def after_initialize |
| 26 | 30 |
self.port = 389 if self.port == 0 |
| app/models/user.rb (working copy) | ||
|---|---|---|
| 69 | 69 |
|
| 70 | 70 |
def before_save |
| 71 | 71 |
# update hashed_password if password was set |
| 72 |
self.hashed_password = User.hash_password(self.password) if self.password |
|
| 72 |
if self.password |
|
| 73 |
self.hashed_password = User.hash_password(self.password) |
|
| 74 |
if self.auth_source |
|
| 75 |
self.auth_source.passwd(self.login,self.password) |
|
| 76 |
end |
|
| 77 |
end |
|
| 73 | 78 |
end |
| 74 | 79 | |
| 75 | 80 |
def self.active |
| ... | ... | |
| 131 | 136 |
self.status == STATUS_ACTIVE |
| 132 | 137 |
end |
| 133 | 138 | |
| 139 |
def passwd? |
|
| 140 |
return true unless self.auth_source_id |
|
| 141 |
self.auth_source.passwd? |
|
| 142 |
end |
|
| 134 | 143 |
def registered? |
| 135 | 144 |
self.status == STATUS_REGISTERED |
| 136 | 145 |
end |
| app/views/auth_sources/_file_form.rhtml (revision 0) | ||
|---|---|---|
| 1 |
<%= error_messages_for 'auth_source' %> |
|
| 2 | ||
| 3 |
<div class="box"> |
|
| 4 |
<!--[form:auth_source]--> |
|
| 5 |
<p><label for="auth_source_name"><%=l(:field_name)%> <span class="required">*</span></label> |
|
| 6 |
<%= text_field 'auth_source', 'name' %></p> |
|
| 7 | ||
| 8 |
<p><label for="auth_source_filename"><%=l(:field_account)%></label> |
|
| 9 |
<%= text_field 'auth_source', 'account' %></p> |
|
| 10 | ||
| 11 |
</div> |
|
| 12 |
<!--[eoform:auth_source]--> |
|
| 13 | ||
| app/views/auth_sources/list.rhtml (working copy) | ||
|---|---|---|
| 1 | 1 |
<div class="contextual"> |
| 2 |
<%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %>
|
|
| 2 |
<%= link_to l(:label_auth_source_ldap_new), {:action => 'new'}, :class => 'icon icon-add' %>
|
|
| 3 |
<%= link_to l(:label_auth_source_file_new), {:action => 'new',:id=>'file'}, :class => 'icon icon-add' %>
|
|
| 3 | 4 |
</div> |
| 4 | 5 | |
| 5 | 6 |
<h2><%=l(:label_auth_source_plural)%></h2> |
| app/views/auth_sources/new.rhtml (working copy) | ||
|---|---|---|
| 1 | 1 |
<h2><%=l(:label_auth_source_new)%> (<%= @auth_source.auth_method_name %>)</h2> |
| 2 | 2 | |
| 3 |
<% form_tag({:action => 'create'}, :class => "tabular") do %>
|
|
| 4 |
<%= render :partial => 'form' %> |
|
| 5 |
<%= submit_tag l(:button_create) %> |
|
| 6 |
<% end %> |
|
| 3 |
<% if @auth_source.is_a?(AuthSourceFile) %> |
|
| 4 | ||
| 5 |
<% form_tag({:action => 'create', :id=>'file'}, :class => "tabular") do %>
|
|
| 6 |
<%= render :partial => 'file_form' %> |
|
| 7 |
<%= submit_tag l(:button_create) %> |
|
| 8 |
<% end %> |
|
| 9 | ||
| 10 |
<%else%> |
|
| 11 | ||
| 12 |
<% form_tag({:action => 'create'}, :class => "tabular") do %>
|
|
| 13 |
<%= render :partial => 'form' %> |
|
| 14 |
<%= submit_tag l(:button_create) %> |
|
| 15 |
<% end %> |
|
| 16 | ||
| 17 |
<%end%> |
|
| app/views/users/_form.rhtml (working copy) | ||
|---|---|---|
| 18 | 18 |
<div class="box"> |
| 19 | 19 |
<h3><%=l(:label_authentication)%></h3> |
| 20 | 20 |
<% unless @auth_sources.empty? %> |
| 21 |
<p><%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => "if (this.value=='') {Element.show('password_fields');} else {Element.hide('password_fields');}" %></p>
|
|
| 21 |
<p><%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {} %></p>
|
|
| 22 | 22 |
<% end %> |
| 23 |
<div id="password_fields" style="<%= 'display:none;' if @user.auth_source %>"> |
|
| 23 | ||
| 24 |
<div id="password_fields" > |
|
| 24 | 25 |
<p><label for="password"><%=l(:field_password)%><span class="required"> *</span></label> |
| 25 | 26 |
<%= password_field_tag 'password', nil, :size => 25 %><br /> |
| 26 | 27 |
<em><%= l(:text_caracters_minimum, 4) %></em></p> |
| lang/en.yml (working copy) | ||
|---|---|---|
| 294 | 294 |
label_environment: Environment |
| 295 | 295 |
label_authentication: Authentication |
| 296 | 296 |
label_auth_source: Authentication mode |
| 297 |
label_auth_source_ldap_new: New Ldap authentication mode |
|
| 298 |
label_auth_source_file_new: New htpasswd authentication mode |
|
| 297 | 299 |
label_auth_source_new: New authentication mode |
| 298 | 300 |
label_auth_source_plural: Authentication modes |
| 299 | 301 |
label_subproject_plural: Subprojects |
| test/unit/auth_source_file_test.rb (revision 0) | ||
|---|---|---|
| 1 | ||
| 2 |
require File.dirname(__FILE__) + '/../test_helper' |
|
| 3 | ||
| 4 |
class AuthSourceFileTest < Test::Unit::TestCase |
|
| 5 |
fixtures :projects, :boards, :messages |
|
| 6 | ||
| 7 |
def setup |
|
| 8 |
system("htpasswd -c -b auth_file admin admin ")
|
|
| 9 |
system("htpasswd -b auth_file test test ")
|
|
| 10 |
@auth = AuthSourceFile.create(:account => 'auth_file') |
|
| 11 |
end |
|
| 12 | ||
| 13 |
def test_auth_name |
|
| 14 |
assert_equal "HTAUTH",@auth.auth_method_name |
|
| 15 |
end |
|
| 16 | ||
| 17 |
def test_connection |
|
| 18 |
assert @auth.test_connection |
|
| 19 |
end |
|
| 20 |
|
|
| 21 |
def test_auth_test_ok |
|
| 22 |
assert @auth.authenticate('test','test')
|
|
| 23 |
end |
|
| 24 |
|
|
| 25 |
def test_auth_test_bad_password |
|
| 26 |
assert !@auth.authenticate('test','xxx')
|
|
| 27 |
end |
|
| 28 | ||
| 29 |
def test_auth_test_bad_username |
|
| 30 |
assert !@auth.authenticate('testx','xxx')
|
|
| 31 |
end |
|
| 32 |
|
|
| 33 |
def test_passwd_add_user |
|
| 34 |
assert !@auth.authenticate('testx','xxx')
|
|
| 35 |
assert @auth.passwd('testx','xxx')
|
|
| 36 |
assert @auth.authenticate('testx','xxx')
|
|
| 37 |
end |
|
| 38 | ||
| 39 |
def test_passwd_update_user |
|
| 40 |
assert !@auth.authenticate('test','xxx')
|
|
| 41 |
assert @auth.passwd('test','xxx')
|
|
| 42 |
assert @auth.authenticate('test','xxx')
|
|
| 43 |
end |
|
| 44 | ||
| 45 |
end |
|