Project

General

Profile

Feature #2647 » redmine-2.3-12119_repository_auth-2.patch

Robert Rath, 2013-09-04 06:24

View differences:

app/helpers/repositories_helper.rb (working copy)
150 150
  end
151 151

  
152 152
  def subversion_field_tags(form, repository)
153
      content_tag('p', form.text_field(:url, :size => 60, :required => true,
154
                       :disabled => !repository.safe_attribute?('url')) +
155
                       '<br />'.html_safe +
156
                       '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
157
      content_tag('p', form.text_field(:login, :size => 30)) +
158
      content_tag('p', form.password_field(
159
                            :password, :size => 30, :name => 'ignore',
160
                            :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
161
                            :onfocus => "this.value=''; this.name='repository[password]';",
162
                            :onchange => "this.name='repository[password]';"))
153
    login_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']]
154
    login_options << [l("repository_login_usernamepassword"), 0] 
155
    login_options << [l("repository_login_current_username"), 1] 
156
    login_options << [l("repository_login_current_role"), 2] 
157

  
158
    content_tag('p', form.text_field(:url, :size => 60, :required => true,
159
                     :disabled => (repository && !repository.root_url.blank?)) +
160
                     '<br />'.html_safe +
161
                     '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
162
    content_tag('p', form.text_field(:root_url, :size => 60) +
163
                     '<br />'.html_safe + '(this needs to be set to the to the highest level in the SVN tree allowed if not the URL)') +
164
    content_tag('p', form.select(:login_method, login_options) +
165
                     '<br />'.html_safe +
166
                     '(Where method is a current user, credentials should be provided for the authz access handler)') +
167
    content_tag('p', form.text_field(:login, :size => 30)) +
168
    content_tag('p', form.password_field(
169
                          :password, :size => 30, :name => 'ignore',
170
                          :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
171
                          :onfocus => "this.value=''; this.name='repository[password]';",
172
                          :onchange => "this.name='repository[password]';")) +
173
    content_tag('p', form.password_field(:security_token, :size => 30, :name => 'ignore',
174
                          :value => ((repository.new_record? || repository.security_token.blank?) ? '' : ('x'*15)),
175
                          :onfocus => "this.value=''; this.name='repository[security_token]';",
176
                          :onchange => "this.name='repository[security_token]';") +
177
                          '<br />'.html_safe +
178
                          '(The security token for the authz access handler needed for current user logon methods)')
163 179
  end
164 180

  
181
#  select_tag('login_method', options_for_select(login_method, repository.class.name.demodulize),
182
#                     :onchange => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)") ) +
183

  
165 184
  def darcs_field_tags(form, repository)
166 185
    content_tag('p', form.text_field(
167 186
                     :url, :label => l(:field_path_to_repository),
app/models/repository.rb (working copy)
51 51
    'password',
52 52
    'path_encoding',
53 53
    'log_encoding',
54
    'is_default'
54
    'is_default',
55
    'login_method',
56
    'root_url',
57
    'security_token'
55 58

  
56 59
  safe_attributes 'url',
57 60
    :if => lambda {|repository, user| repository.new_record?}
......
94 97

  
95 98
  def scm
96 99
    unless @scm
97
      @scm = self.scm_adapter.new(url, root_url,
98
                                  login, password, path_encoding)
100
      @scm = self.scm_adapter.new(url, root_url, login, password, path_encoding, login_method, security_token, project)
99 101
      if root_url.blank? && @scm.root_url.present?
100 102
        update_attribute(:root_url, @scm.root_url)
101 103
      end
app/models/repository/subversion.rb (working copy)
18 18
require 'redmine/scm/adapters/subversion_adapter'
19 19

  
20 20
class Repository::Subversion < Repository
21
  attr_protected :root_url
21
  #attr_protected :root_url
22 22
  validates_presence_of :url
23 23
  validates_format_of :url, :with => /\A(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+/i
24 24

  
app/controllers/repositories_controller.rb (working copy)
70 70
    end
71 71
    @repository.project = @project
72 72
    if request.put? && @repository.save
73
      @repository.save
73 74
      redirect_to settings_project_path(@project, :tab => 'repositories')
74 75
    else
75 76
      render :action => 'edit'
extra/svn/Redmine.pm (working copy)
1
package Apache::Authn::Redmine;
1
package Apache::Redmine;
2 2

  
3
=head1 Apache::Authn::Redmine
3
=head1 Apache::Redmine
4 4

  
5 5
Redmine - a mod_perl module to authenticate webdav subversion users
6 6
against redmine database
7 7

  
8
In addition this module allows to authenticate a redmine server
9
for webdav subversion access, bypassing full authentication, still
10
allowing to apply repository based security (e.g. .authz files)
11

  
12

  
8 13
=head1 SYNOPSIS
9 14

  
10 15
This module allow anonymous users to browse public project and
......
37 42
=head1 CONFIGURATION
38 43

  
39 44
   ## This module has to be in your perl path
40
   ## eg:  /usr/lib/perl5/Apache/Authn/Redmine.pm
41
   PerlLoadModule Apache::Authn::Redmine
45
   ## eg:  /usr/lib/perl5/Apache/Redmine.pm
46
   PerlLoadModule Apache::Redmine
42 47
   <Location /svn>
43 48
     DAV svn
44 49
     SVNParentPath "/var/svn"
......
47 52
     AuthName redmine
48 53
     Require valid-user
49 54

  
50
     PerlAccessHandler Apache::Authn::Redmine::access_handler
51
     PerlAuthenHandler Apache::Authn::Redmine::authen_handler
55
     PerlAccessHandler Apache::Redmine::access_handler
56
     PerlAuthenHandler Apache::Redmine::authen_handler
52 57

  
53 58
     ## for mysql
54 59
     RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
......
73 78
     Order deny,allow
74 79
     Deny from all
75 80
     # only allow reading orders
81

  
82
     AuthType Basic
83
     AuthName redmine
84
     Require valid-user
85

  
86
     PerlAccessHandler Apache::Redmine::redmine_access_handler
87
     PerlAuthenHandler Apache::Redmine::redmine_authen_handler
88

  
89
     RedmineSecurityToken "redmine"
90
     
76 91
     <Limit GET PROPFIND OPTIONS REPORT>
77 92
       Allow from redmine.server.ip
78 93
     </Limit>
......
229 244
    errmsg => 'RedmineCacheCredsMax must be decimal number',
230 245
  },
231 246
  {
247
    name => 'RedmineSecurityToken',
248
    req_override => OR_AUTHCFG,
249
    args_how => TAKE1,
250
    errmsg => 'RedmineSecurityToken additional authentication token',
251
  },  {
232 252
    name => 'RedmineGitSmartHttp',
233 253
    req_override => OR_AUTHCFG,
234 254
    args_how => TAKE1,
......
256 276

  
257 277
sub RedmineDbUser { set_val('RedmineDbUser', @_); }
258 278
sub RedmineDbPass { set_val('RedmineDbPass', @_); }
279
sub RedmineSecurityToken { set_val('RedmineSecurityToken', @_); }
259 280
sub RedmineDbWhereClause {
260 281
  my ($self, $parms, $arg) = @_;
261 282
  $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
......
319 340
  my $r = shift;
320 341

  
321 342
  unless ($r->some_auth_required) {
322
      $r->log_reason("No authentication has been configured");
343
      $r->log_reason("Apache::Redmine - No authentication has been configured in webserver (access_handler)");
323 344
      return FORBIDDEN;
324 345
  }
325 346

  
......
541 562
    return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
542 563
}
543 564

  
565
sub redmine_access_handler {
566
  my $r = shift;
567

  
568
  unless ($r->some_auth_required) {
569
      $r->log_reason("Apache::Redmine - No auth has been configured in vhost conf (redmine_access_handler)");
570
      return FORBIDDEN;
571
  }
572

  
573
  my $method = $r->method;
574
  return OK unless defined $read_only_methods{$method};
575

  
576
  my $project_id = get_project_identifier($r);
577

  
578
  $r->set_handlers(PerlAuthenHandler => [\&OK])
579
      if is_public_project($project_id, $r);
580

  
581
  return OK
582
}
583

  
584
sub redmine_authen_handler {
585
  my $r = shift;
586

  
587
  my ($res, $redmine_pass) =  $r->get_basic_auth_pw();
588
  return $res unless $res == OK;
589

  
590
  my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
591

  
592
  if ($cfg->{RedmineSecurityToken}) {
593
    my $securityToken = $cfg->{RedmineSecurityToken};
594

  
595
    if ($securityToken ne $redmine_pass) {
596
      $r->log_error("Apache::Redmine - Provided SecurityToken did not match (redmine_authen_handler)");
597
      $r->note_auth_failure();
598
      return AUTH_REQUIRED; 
599
    }    
600
  }  
601
  return OK;
602
}
603

  
544 604
1;
db/migrate/109_add_special_repository_security.rb (revision 0)
1
class AddSpecialRepositorySecurity < ActiveRecord::Migration
2
  def self.down
3
    remove_column :repositories, :login_method
4
    remove_column :repositories, :security_token
5
  end
6

  
7
  def self.up
8
    add_column :repositories, :login_method, :int, :default => 0, :null => true
9
    add_column :repositories, :security_token, :string, :limit => 60, :default => "", :null => true
10
  end
11
end
config/locales/en-GB.yml (working copy)
312 312
  field_text: Text field
313 313
  field_visible: Visible
314 314
  field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
315
  field_login_method: Authentication method
316
  field_security_token: Security token
317
  field_root_url: Root URL
315 318

  
319
  repository_login_usernamepassword: Provided credentials
320
  repository_login_current_username: Name of current user
321
  repository_login_current_role: Role of current user
322

  
316 323
  setting_app_title: Application title
317 324
  setting_app_subtitle: Application subtitle
318 325
  setting_welcome_text: Welcome text
config/locales/en.yml (working copy)
331 331
  field_board_parent: Parent forum
332 332
  field_private_notes: Private notes
333 333
  field_inherit_members: Inherit members
334
  field_login_method: Authentication method
335
  field_security_token: Security token
336
  field_root_url: Root URL
334 337

  
338
  repository_login_usernamepassword: Provided credentials
339
  repository_login_current_username: Name of current user
340
  repository_login_current_role: Role of current user
341

  
335 342
  setting_app_title: Application title
336 343
  setting_app_subtitle: Application subtitle
337 344
  setting_welcome_text: Welcome text
lib/redmine/scm/adapters/subversion_adapter.rb (working copy)
257 257
        private
258 258

  
259 259
        def credentials_string
260
          str = ''
261
          str << " --username #{shell_quote(@login)}" unless @login.blank?
262
          str << " --password #{shell_quote(@password)}" unless @login.blank? || @password.blank?
260
          if !(User.current.is_a?(AnonymousUser))
261

  
262
            if (@login_method == 1)
263
              str = ''
264
              str << " --username #{shell_quote(User.current.login)}"
265
              str << " --password #{shell_quote( (@security_token.blank? ? "foo" : @security_token) )}"   
266
            end
267

  
268
            if (@login_method == 2) && (!@project.nil?)
269
              role = User.current.role_for_project(@project)
270

  
271
              if !role.blank?
272
                str = ''
273
                str << " --username #{shell_quote(role.name)}"
274
                str << " --password #{shell_quote( (@security_token.blank? ? "foo" : @security_token) )}"   
275
              end
276
            end
277

  
278
          end
279

  
280
          if (str.blank?)
281
            str = ''
282
            str << " --username #{shell_quote(@login)}" unless @login.blank?
283
            str << " --password #{shell_quote(@password)}" unless @login.blank? || @password.blank?
284
          end
285

  
263 286
          str << " --no-auth-cache --non-interactive"
264 287
          str
265 288
        end
lib/redmine/scm/adapters/abstract_adapter.rb (working copy)
79 79
          end
80 80
        end
81 81

  
82
        def initialize(url, root_url=nil, login=nil, password=nil,
83
                       path_encoding=nil)
82
        def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil, login_method=nil, security_token=nil, project=nil)
84 83
          @url = url
85 84
          @login = login if login && !login.empty?
86 85
          @password = (password || "") if @login
87 86
          @root_url = root_url.blank? ? retrieve_root_url : root_url
87
          @login_method = login_method.blank? ? 0 : login_method
88
          @security_token = security_token.blank? ? "" : security_token
89
          @project = project
88 90
        end
89 91

  
90 92
        def adapter_name
......
99 101
          respond_to?('annotate')
100 102
        end
101 103

  
104
        def use_current_user
105
          @use_current_user
106
        end
107

  
102 108
        def root_url
103 109
          @root_url
104 110
        end
(5-5/6)