Index: app/controllers/auth_sources_controller.rb =================================================================== --- app/controllers/auth_sources_controller.rb (revision 1614) +++ app/controllers/auth_sources_controller.rb (working copy) @@ -34,11 +34,19 @@ end def new - @auth_source = AuthSourceLdap.new + if params[:id]=='file' + @auth_source = AuthSourceFile.new + else + @auth_source = AuthSourceLdap.new + end end def create - @auth_source = AuthSourceLdap.new(params[:auth_source]) + if params[:id]=='file' + @auth_source = AuthSourceFile.new(params[:auth_source]) + else + @auth_source = AuthSourceLdap.new(params[:auth_source]) + end if @auth_source.save flash[:notice] = l(:notice_successful_create) redirect_to :action => 'list' @@ -47,6 +55,9 @@ end end + + + def edit @auth_source = AuthSource.find(params[:id]) end Index: app/controllers/users_controller.rb =================================================================== --- app/controllers/users_controller.rb (revision 1614) +++ app/controllers/users_controller.rb (working copy) @@ -56,7 +56,10 @@ @user = User.new(params[:user]) @user.admin = params[:user][:admin] || false @user.login = params[:user][:login] - @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id + if @user.passwd? + @user.password = params[:password] + @user.password_confirmation = params[:password_confirmation] + end if @user.save Mailer.deliver_account_information(@user, params[:password]) if params[:send_information] flash[:notice] = l(:notice_successful_create) Index: app/models/auth_source.rb =================================================================== --- app/models/auth_source.rb (revision 1614) +++ app/models/auth_source.rb (working copy) @@ -20,13 +20,15 @@ validates_presence_of :name validates_uniqueness_of :name - validates_length_of :name, :host, :maximum => 60 - validates_length_of :account_password, :maximum => 60, :allow_nil => true - validates_length_of :account, :base_dn, :maximum => 255 - validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30 + validates_length_of :name, :maximum => 60 + validates_length_of :account, :maximum => 255 def authenticate(login, password) end + + def passwd? + false + end def test_connection end Index: app/models/auth_source_file.rb =================================================================== --- app/models/auth_source_file.rb (revision 0) +++ app/models/auth_source_file.rb (revision 0) @@ -0,0 +1,61 @@ +# redMine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'htauth' + +class AuthSourceFile < AuthSource + + validates_presence_of :account + + def authenticate(login, password) + return nil if login.blank? || password.blank? + HTAuth::PasswdFile.open(self.account) do |pf| + dn = pf.fetch(login) + if dn and dn.authenticated?(password) + logger.debug "Authenticated #{login}: #{dn}" if logger && logger.debug? + return true + else + return false + end + end + end + + def passwd? + true + end + + def passwd(login,password) + return false if login.blank? || password.blank? + HTAuth::PasswdFile.open(self.account) do |pf| + logger.debug "add_or_update #{login}" if logger && logger.debug? + pf.add_or_update(login,password) + return true + end + end + + # test the connection to the LDAP + def test_connection + con = HTAuth::PasswdFile.open(self.account) + return con.is_a?(HTAuth::PasswdFile) + end + + def auth_method_name + "HTAUTH" + end + +private +end Index: app/models/auth_source_ldap.rb =================================================================== --- app/models/auth_source_ldap.rb (revision 1614) +++ app/models/auth_source_ldap.rb (working copy) @@ -21,6 +21,10 @@ class AuthSourceLdap < AuthSource validates_presence_of :host, :port, :attr_login validates_presence_of :attr_firstname, :attr_lastname, :attr_mail, :if => Proc.new { |a| a.onthefly_register? } + validates_length_of :host, :maximum => 60 + validates_length_of :account_password, :maximum => 60, :allow_nil => true + validates_length_of :base_dn, :maximum => 255 + validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30 def after_initialize self.port = 389 if self.port == 0 Index: app/models/user.rb =================================================================== --- app/models/user.rb (revision 1614) +++ app/models/user.rb (working copy) @@ -69,7 +69,12 @@ def before_save # update hashed_password if password was set - self.hashed_password = User.hash_password(self.password) if self.password + if self.password + self.hashed_password = User.hash_password(self.password) + if self.auth_source + self.auth_source.passwd(self.login,self.password) + end + end end def self.active @@ -131,6 +136,10 @@ self.status == STATUS_ACTIVE end + def passwd? + return true unless self.auth_source_id + self.auth_source.passwd? + end def registered? self.status == STATUS_REGISTERED end Index: app/views/auth_sources/_file_form.rhtml =================================================================== --- app/views/auth_sources/_file_form.rhtml (revision 0) +++ app/views/auth_sources/_file_form.rhtml (revision 0) @@ -0,0 +1,13 @@ +<%= error_messages_for 'auth_source' %> + +
+ +

+<%= text_field 'auth_source', 'name' %>

+ +

+<%= text_field 'auth_source', 'account' %>

+ +
+ + Index: app/views/auth_sources/list.rhtml =================================================================== --- app/views/auth_sources/list.rhtml (revision 1614) +++ app/views/auth_sources/list.rhtml (working copy) @@ -1,5 +1,6 @@
-<%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %> +<%= link_to l(:label_auth_source_ldap_new), {:action => 'new'}, :class => 'icon icon-add' %> +<%= link_to l(:label_auth_source_file_new), {:action => 'new',:id=>'file'}, :class => 'icon icon-add' %>

<%=l(:label_auth_source_plural)%>

Index: app/views/auth_sources/new.rhtml =================================================================== --- app/views/auth_sources/new.rhtml (revision 1614) +++ app/views/auth_sources/new.rhtml (working copy) @@ -1,6 +1,17 @@

<%=l(:label_auth_source_new)%> (<%= @auth_source.auth_method_name %>)

-<% form_tag({:action => 'create'}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_create) %> -<% end %> + <% if @auth_source.is_a?(AuthSourceFile) %> + + <% form_tag({:action => 'create', :id=>'file'}, :class => "tabular") do %> + <%= render :partial => 'file_form' %> + <%= submit_tag l(:button_create) %> + <% end %> + + <%else%> + + <% form_tag({:action => 'create'}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> + <% end %> + + <%end%> Index: app/views/users/_form.rhtml =================================================================== --- app/views/users/_form.rhtml (revision 1614) +++ app/views/users/_form.rhtml (working copy) @@ -18,9 +18,10 @@

<%=l(:label_authentication)%>

<% unless @auth_sources.empty? %> -

<%= 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');}" %>

+

<%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {} %>

<% end %> -
+ +

<%= password_field_tag 'password', nil, :size => 25 %>
<%= l(:text_caracters_minimum, 4) %>

Index: lang/en.yml =================================================================== --- lang/en.yml (revision 1614) +++ lang/en.yml (working copy) @@ -294,6 +294,8 @@ label_environment: Environment label_authentication: Authentication label_auth_source: Authentication mode +label_auth_source_ldap_new: New Ldap authentication mode +label_auth_source_file_new: New htpasswd authentication mode label_auth_source_new: New authentication mode label_auth_source_plural: Authentication modes label_subproject_plural: Subprojects Index: test/unit/auth_source_file_test.rb =================================================================== --- test/unit/auth_source_file_test.rb (revision 0) +++ test/unit/auth_source_file_test.rb (revision 0) @@ -0,0 +1,45 @@ + +require File.dirname(__FILE__) + '/../test_helper' + +class AuthSourceFileTest < Test::Unit::TestCase + fixtures :projects, :boards, :messages + + def setup + system("htpasswd -c -b auth_file admin admin ") + system("htpasswd -b auth_file test test ") + @auth = AuthSourceFile.create(:account => 'auth_file') + end + + def test_auth_name + assert_equal "HTAUTH",@auth.auth_method_name + end + + def test_connection + assert @auth.test_connection + end + + def test_auth_test_ok + assert @auth.authenticate('test','test') + end + + def test_auth_test_bad_password + assert !@auth.authenticate('test','xxx') + end + + def test_auth_test_bad_username + assert !@auth.authenticate('testx','xxx') + end + + def test_passwd_add_user + assert !@auth.authenticate('testx','xxx') + assert @auth.passwd('testx','xxx') + assert @auth.authenticate('testx','xxx') + end + + def test_passwd_update_user + assert !@auth.authenticate('test','xxx') + assert @auth.passwd('test','xxx') + assert @auth.authenticate('test','xxx') + end + +end \ No newline at end of file