@@ -0,0 +1,10 | |||||
|
1 | <h2><%= l :label_api_access_key %></h2> | |||
|
2 | ||||
|
3 | <div class="box"> | |||
|
4 | <pre><%= @user.api_key %></pre> | |||
|
5 | </div> | |||
|
6 | ||||
|
7 | <p><%= link_to l(:button_back), action: 'account' %></p> | |||
|
8 | ||||
|
9 | ||||
|
10 |
@@ -0,0 +1,1 | |||||
|
1 | $('#api-access-key').html('<%= escape_javascript @user.api_key %>').toggle(); |
@@ -0,0 +1,19 | |||||
|
1 | <h3 class="title"><%= l(:label_password_required) %></h3> | |||
|
2 | <%= form_tag({}, remote: true) do %> | |||
|
3 | ||||
|
4 | <%= hidden_field_tag '_method', request.request_method %> | |||
|
5 | <%= hash_to_hidden_fields @sudo_form.original_fields %> | |||
|
6 | <%= render_flash_messages %> | |||
|
7 | <div class="box tabular"> | |||
|
8 | <p> | |||
|
9 | <label for="sudo_password"><%= l :field_password %><span class="required">*</span></label> | |||
|
10 | <%= password_field_tag :sudo_password, nil, size: 25 %> | |||
|
11 | </p> | |||
|
12 | </div> | |||
|
13 | ||||
|
14 | <p class="buttons"> | |||
|
15 | <%= submit_tag l(:button_confirm_password), onclick: "hideModal(this);" %> | |||
|
16 | <%= submit_tag l(:button_cancel), name: nil, onclick: "hideModal(this);", type: 'button' %> | |||
|
17 | </p> | |||
|
18 | <% end %> | |||
|
19 |
@@ -0,0 +1,17 | |||||
|
1 | <h2><%= l :label_password_required %></h2> | |||
|
2 | <%= form_tag({}, class: 'tabular') do %> | |||
|
3 | ||||
|
4 | <%= hidden_field_tag '_method', request.request_method %> | |||
|
5 | <%= hash_to_hidden_fields @sudo_form.original_fields %> | |||
|
6 | ||||
|
7 | <div class="box"> | |||
|
8 | <p> | |||
|
9 | <label for="sudo_password"><%= l :field_password %><span class="required">*</span></label> | |||
|
10 | <%= password_field_tag :sudo_password, nil, size: 25 %> | |||
|
11 | </p> | |||
|
12 | </div> | |||
|
13 | <%= submit_tag l(:button_confirm_password) %> | |||
|
14 | <% end %> | |||
|
15 | <%= javascript_tag "$('#sudo_password').focus();" %> | |||
|
16 | ||||
|
17 |
@@ -0,0 +1,4 | |||||
|
1 | $('#ajax-modal').html('<%= escape_javascript render partial: 'sudo_mode/new_modal' %>'); | |||
|
2 | showModal('ajax-modal', '400px'); | |||
|
3 | $('#sudo_password').focus(); | |||
|
4 |
@@ -0,0 +1,224 | |||||
|
1 | require 'active_support/core_ext/object/to_query' | |||
|
2 | require 'rack/utils' | |||
|
3 | ||||
|
4 | module Redmine | |||
|
5 | module SudoMode | |||
|
6 | ||||
|
7 | # timespan after which sudo mode expires when unused. | |||
|
8 | MAX_INACTIVITY = 15.minutes | |||
|
9 | ||||
|
10 | ||||
|
11 | class SudoRequired < StandardError | |||
|
12 | end | |||
|
13 | ||||
|
14 | ||||
|
15 | class Form | |||
|
16 | include ActiveModel::Validations | |||
|
17 | ||||
|
18 | attr_accessor :password, :original_fields | |||
|
19 | validate :check_password | |||
|
20 | ||||
|
21 | def initialize(password = nil) | |||
|
22 | self.password = password | |||
|
23 | end | |||
|
24 | ||||
|
25 | def check_password | |||
|
26 | unless password.present? && User.current.check_password?(password) | |||
|
27 | errors[:password] << :invalid | |||
|
28 | end | |||
|
29 | end | |||
|
30 | end | |||
|
31 | ||||
|
32 | ||||
|
33 | module Helper | |||
|
34 | # Represents params data from hash as hidden fields | |||
|
35 | # | |||
|
36 | # taken from https://github.com/brianhempel/hash_to_hidden_fields | |||
|
37 | def hash_to_hidden_fields(hash) | |||
|
38 | cleaned_hash = hash.reject { |k, v| v.nil? } | |||
|
39 | pairs = cleaned_hash.to_query.split(Rack::Utils::DEFAULT_SEP) | |||
|
40 | tags = pairs.map do |pair| | |||
|
41 | key, value = pair.split('=', 2).map { |str| Rack::Utils.unescape(str) } | |||
|
42 | hidden_field_tag(key, value) | |||
|
43 | end | |||
|
44 | tags.join("\n").html_safe | |||
|
45 | end | |||
|
46 | end | |||
|
47 | ||||
|
48 | ||||
|
49 | module Controller | |||
|
50 | extend ActiveSupport::Concern | |||
|
51 | ||||
|
52 | included do | |||
|
53 | around_filter :sudo_mode | |||
|
54 | end | |||
|
55 | ||||
|
56 | # Sudo mode Around Filter | |||
|
57 | # | |||
|
58 | # Checks the 'last used' timestamp from session and sets the | |||
|
59 | # SudoMode::active? flag accordingly. | |||
|
60 | # | |||
|
61 | # After the request refreshes the timestamp if sudo mode was used during | |||
|
62 | # this request. | |||
|
63 | def sudo_mode | |||
|
64 | if api_request? | |||
|
65 | SudoMode.disable! | |||
|
66 | elsif sudo_timestamp_valid? | |||
|
67 | SudoMode.active! | |||
|
68 | end | |||
|
69 | yield | |||
|
70 | update_sudo_timestamp! if SudoMode.was_used? | |||
|
71 | end | |||
|
72 | ||||
|
73 | # This renders the sudo mode form / handles sudo form submission. | |||
|
74 | # | |||
|
75 | # Call this method in controller actions if sudo permissions are required | |||
|
76 | # for processing this request. This approach is good in cases where the | |||
|
77 | # action needs to be protected in any case or where the check is simple. | |||
|
78 | # | |||
|
79 | # In cases where this decision depends on complex conditions in the model, | |||
|
80 | # consider the declarative approach using the require_sudo_mode class | |||
|
81 | # method and a corresponding declaration in the model that causes it to throw | |||
|
82 | # a SudoRequired Error when necessary. | |||
|
83 | # | |||
|
84 | # All parameter names given are included as hidden fields to be resubmitted | |||
|
85 | # along with the password. | |||
|
86 | # | |||
|
87 | # Returns true when processing the action should continue, false otherwise. | |||
|
88 | # If false is returned, render has already been called for display of the | |||
|
89 | # password form. | |||
|
90 | # | |||
|
91 | # if @user.mail_changed? | |||
|
92 | # require_sudo_mode :user or return | |||
|
93 | # end | |||
|
94 | # | |||
|
95 | def require_sudo_mode(*param_names) | |||
|
96 | return true if SudoMode.active? | |||
|
97 | ||||
|
98 | if param_names.blank? | |||
|
99 | param_names = params.keys - %w(id action controller sudo_password) | |||
|
100 | end | |||
|
101 | ||||
|
102 | process_sudo_form | |||
|
103 | ||||
|
104 | if SudoMode.active? | |||
|
105 | true | |||
|
106 | else | |||
|
107 | render_sudo_form param_names | |||
|
108 | false | |||
|
109 | end | |||
|
110 | end | |||
|
111 | ||||
|
112 | # display the sudo password form | |||
|
113 | def render_sudo_form(param_names) | |||
|
114 | @sudo_form ||= SudoMode::Form.new | |||
|
115 | @sudo_form.original_fields = params.slice( *param_names ) | |||
|
116 | # a simple 'render "sudo_mode/new"' works when used directly inside an | |||
|
117 | # action, but not when called from a before_filter: | |||
|
118 | respond_to do |format| | |||
|
119 | format.html { render 'sudo_mode/new' } | |||
|
120 | format.js { render 'sudo_mode/new' } | |||
|
121 | end | |||
|
122 | end | |||
|
123 | ||||
|
124 | # handle sudo password form submit | |||
|
125 | def process_sudo_form | |||
|
126 | if params[:sudo_password] | |||
|
127 | @sudo_form = SudoMode::Form.new(params[:sudo_password]) | |||
|
128 | if @sudo_form.valid? | |||
|
129 | SudoMode.active! | |||
|
130 | else | |||
|
131 | flash.now[:error] = l(:notice_account_wrong_password) | |||
|
132 | end | |||
|
133 | end | |||
|
134 | end | |||
|
135 | ||||
|
136 | def sudo_timestamp_valid? | |||
|
137 | session[:sudo_timestamp].to_i > MAX_INACTIVITY.ago.to_i | |||
|
138 | end | |||
|
139 | ||||
|
140 | def update_sudo_timestamp!(new_value = Time.now.to_i) | |||
|
141 | session[:sudo_timestamp] = new_value | |||
|
142 | end | |||
|
143 | ||||
|
144 | # Before Filter which is used by the require_sudo_mode class method. | |||
|
145 | class SudoRequestFilter < Struct.new(:parameters, :request_methods) | |||
|
146 | def before(controller) | |||
|
147 | method_matches = request_methods.blank? || request_methods.include?(controller.request.method_symbol) | |||
|
148 | if SudoMode.possible? && method_matches | |||
|
149 | controller.require_sudo_mode( *parameters ) | |||
|
150 | else | |||
|
151 | true | |||
|
152 | end | |||
|
153 | end | |||
|
154 | end | |||
|
155 | ||||
|
156 | module ClassMethods | |||
|
157 | ||||
|
158 | # Handles sudo requirements for the given actions, preserving the named | |||
|
159 | # parameters, or any parameters if you omit the :parameters option. | |||
|
160 | # | |||
|
161 | # Sudo enforcement by default is active for all requests to an action | |||
|
162 | # but may be limited to a certain subset of request methods via the | |||
|
163 | # :only option. | |||
|
164 | # | |||
|
165 | # Examples: | |||
|
166 | # | |||
|
167 | # require_sudo_mode :account, only: :post | |||
|
168 | # require_sudo_mode :update, :create, parameters: %w(role) | |||
|
169 | # require_sudo_mode :destroy | |||
|
170 | # | |||
|
171 | def require_sudo_mode(*args) | |||
|
172 | actions = args.dup | |||
|
173 | options = actions.extract_options! | |||
|
174 | filter = SudoRequestFilter.new Array(options[:parameters]), Array(options[:only]) | |||
|
175 | before_filter filter, only: actions | |||
|
176 | end | |||
|
177 | end | |||
|
178 | end | |||
|
179 | ||||
|
180 | ||||
|
181 | # true if the sudo mode state was queried during this request | |||
|
182 | def self.was_used? | |||
|
183 | !!RequestStore.store[:sudo_mode_was_used] | |||
|
184 | end | |||
|
185 | ||||
|
186 | # true if sudo mode is currently active. | |||
|
187 | # | |||
|
188 | # Calling this method also turns was_used? to true, therefore | |||
|
189 | # it is important to only call this when sudo is actually needed, as the last | |||
|
190 | # condition to determine wether a change can be done or not. | |||
|
191 | # | |||
|
192 | # If you do it wrong, timeout of the sudo mode will happen too late or not at | |||
|
193 | # all. | |||
|
194 | def self.active? | |||
|
195 | if !!RequestStore.store[:sudo_mode] | |||
|
196 | RequestStore.store[:sudo_mode_was_used] = true | |||
|
197 | end | |||
|
198 | end | |||
|
199 | ||||
|
200 | def self.active! | |||
|
201 | RequestStore.store[:sudo_mode] = true | |||
|
202 | end | |||
|
203 | ||||
|
204 | def self.possible? | |||
|
205 | !disabled? && User.current.logged? | |||
|
206 | end | |||
|
207 | ||||
|
208 | # Turn off sudo mode (never require password entry). | |||
|
209 | def self.disable! | |||
|
210 | RequestStore.store[:sudo_mode_disabled] = true | |||
|
211 | end | |||
|
212 | ||||
|
213 | # Turn sudo mode back on | |||
|
214 | def self.enable! | |||
|
215 | RequestStore.store[:sudo_mode_disabled] = nil | |||
|
216 | end | |||
|
217 | ||||
|
218 | def self.disabled? | |||
|
219 | !!RequestStore.store[:sudo_mode_disabled] | |||
|
220 | end | |||
|
221 | ||||
|
222 | end | |||
|
223 | end | |||
|
224 |
@@ -0,0 +1,126 | |||||
|
1 | require File.expand_path('../../test_helper', __FILE__) | |||
|
2 | ||||
|
3 | class SudoTest < Redmine::IntegrationTest | |||
|
4 | fixtures :projects, :members, :member_roles, :roles, :users | |||
|
5 | ||||
|
6 | def setup | |||
|
7 | Redmine::SudoMode.enable! | |||
|
8 | end | |||
|
9 | ||||
|
10 | def teardown | |||
|
11 | Redmine::SudoMode.disable! | |||
|
12 | end | |||
|
13 | ||||
|
14 | def test_create_member_xhr | |||
|
15 | log_user 'admin', 'admin' | |||
|
16 | get '/projects/ecookbook/settings/members' | |||
|
17 | assert_response :success | |||
|
18 | ||||
|
19 | assert_no_difference 'Member.count' do | |||
|
20 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7} | |||
|
21 | end | |||
|
22 | ||||
|
23 | assert_no_difference 'Member.count' do | |||
|
24 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: '' | |||
|
25 | end | |||
|
26 | ||||
|
27 | assert_no_difference 'Member.count' do | |||
|
28 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'wrong' | |||
|
29 | end | |||
|
30 | ||||
|
31 | assert_difference 'Member.count' do | |||
|
32 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'admin' | |||
|
33 | end | |||
|
34 | assert User.find(7).member_of?(Project.find(1)) | |||
|
35 | end | |||
|
36 | ||||
|
37 | def test_create_member | |||
|
38 | log_user 'admin', 'admin' | |||
|
39 | get '/projects/ecookbook/settings/members' | |||
|
40 | assert_response :success | |||
|
41 | ||||
|
42 | assert_no_difference 'Member.count' do | |||
|
43 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7} | |||
|
44 | end | |||
|
45 | ||||
|
46 | assert_no_difference 'Member.count' do | |||
|
47 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: '' | |||
|
48 | end | |||
|
49 | ||||
|
50 | assert_no_difference 'Member.count' do | |||
|
51 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'wrong' | |||
|
52 | end | |||
|
53 | ||||
|
54 | assert_difference 'Member.count' do | |||
|
55 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'admin' | |||
|
56 | end | |||
|
57 | ||||
|
58 | assert_redirected_to '/projects/ecookbook/settings/members' | |||
|
59 | assert User.find(7).member_of?(Project.find(1)) | |||
|
60 | end | |||
|
61 | ||||
|
62 | def test_create_role | |||
|
63 | log_user 'admin', 'admin' | |||
|
64 | get '/roles' | |||
|
65 | assert_response :success | |||
|
66 | ||||
|
67 | get '/roles/new' | |||
|
68 | assert_response :success | |||
|
69 | ||||
|
70 | post '/roles', role: { } | |||
|
71 | assert_response :success | |||
|
72 | assert_select 'h2', 'Confirm your password to continue' | |||
|
73 | assert_select 'form[action="/roles"]' | |||
|
74 | assert assigns(:sudo_form).errors.blank? | |||
|
75 | ||||
|
76 | post '/roles', role: { name: 'new role', issues_visibility: 'all' } | |||
|
77 | assert_response :success | |||
|
78 | assert_select 'h2', 'Confirm your password to continue' | |||
|
79 | assert_select 'form[action="/roles"]' | |||
|
80 | assert_match /"new role"/, response.body | |||
|
81 | assert assigns(:sudo_form).errors.blank? | |||
|
82 | ||||
|
83 | post '/roles', role: { name: 'new role', issues_visibility: 'all' }, sudo_password: 'wrong' | |||
|
84 | assert_response :success | |||
|
85 | assert_select 'h2', 'Confirm your password to continue' | |||
|
86 | assert_select 'form[action="/roles"]' | |||
|
87 | assert_match /"new role"/, response.body | |||
|
88 | assert assigns(:sudo_form).errors[:password].present? | |||
|
89 | ||||
|
90 | assert_difference 'Role.count' do | |||
|
91 | post '/roles', role: { name: 'new role', issues_visibility: 'all', assignable: '1', permissions: %w(view_calendar) }, sudo_password: 'admin' | |||
|
92 | end | |||
|
93 | assert_redirected_to '/roles' | |||
|
94 | end | |||
|
95 | ||||
|
96 | def test_update_email_address | |||
|
97 | log_user 'jsmith', 'jsmith' | |||
|
98 | get '/my/account' | |||
|
99 | assert_response :success | |||
|
100 | post '/my/account', user: { mail: 'newmail@test.com' } | |||
|
101 | assert_response :success | |||
|
102 | assert_select 'h2', 'Confirm your password to continue' | |||
|
103 | assert_select 'form[action="/my/account"]' | |||
|
104 | assert_match /"newmail@test\.com"/, response.body | |||
|
105 | assert assigns(:sudo_form).errors.blank? | |||
|
106 | ||||
|
107 | # wrong password | |||
|
108 | post '/my/account', user: { mail: 'newmail@test.com' }, sudo_password: 'wrong' | |||
|
109 | assert_response :success | |||
|
110 | assert_select 'h2', 'Confirm your password to continue' | |||
|
111 | assert_select 'form[action="/my/account"]' | |||
|
112 | assert_match /"newmail@test\.com"/, response.body | |||
|
113 | assert assigns(:sudo_form).errors[:password].present? | |||
|
114 | ||||
|
115 | # correct password | |||
|
116 | post '/my/account', user: { mail: 'newmail@test.com' }, sudo_password: 'jsmith' | |||
|
117 | assert_redirected_to '/my/account' | |||
|
118 | assert_equal 'newmail@test.com', User.find_by_login('jsmith').mail | |||
|
119 | ||||
|
120 | # sudo mode should now be active and not require password again | |||
|
121 | post '/my/account', user: { mail: 'even.newer.mail@test.com' } | |||
|
122 | assert_redirected_to '/my/account' | |||
|
123 | assert_equal 'even.newer.mail@test.com', User.find_by_login('jsmith').mail | |||
|
124 | end | |||
|
125 | ||||
|
126 | end |
@@ -59,6 +59,8 class ApplicationController < ActionController::Base | |||||
59 | include Redmine::MenuManager::MenuController |
|
59 | include Redmine::MenuManager::MenuController | |
60 | helper Redmine::MenuManager::MenuHelper |
|
60 | helper Redmine::MenuManager::MenuHelper | |
61 |
|
61 | |||
|
62 | include Redmine::SudoMode::Controller | |||
|
63 | ||||
62 | def session_expiration |
|
64 | def session_expiration | |
63 | if session[:user_id] |
|
65 | if session[:user_id] | |
64 | if session_expired? && !try_to_autologin |
|
66 | if session_expired? && !try_to_autologin |
@@ -21,6 +21,7 class AuthSourcesController < ApplicationController | |||||
21 |
|
21 | |||
22 | before_filter :require_admin |
|
22 | before_filter :require_admin | |
23 | before_filter :find_auth_source, :only => [:edit, :update, :test_connection, :destroy] |
|
23 | before_filter :find_auth_source, :only => [:edit, :update, :test_connection, :destroy] | |
|
24 | require_sudo_mode :update, :destroy | |||
24 |
|
25 | |||
25 | def index |
|
26 | def index | |
26 | @auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 25 |
|
27 | @auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 25 |
@@ -18,6 +18,7 | |||||
18 | class EmailAddressesController < ApplicationController |
|
18 | class EmailAddressesController < ApplicationController | |
19 | before_filter :find_user, :require_admin_or_current_user |
|
19 | before_filter :find_user, :require_admin_or_current_user | |
20 | before_filter :find_email_address, :only => [:update, :destroy] |
|
20 | before_filter :find_email_address, :only => [:update, :destroy] | |
|
21 | require_sudo_mode :create, :update, :destroy | |||
21 |
|
22 | |||
22 | def index |
|
23 | def index | |
23 | @addresses = @user.email_addresses.order(:id).where(:is_default => false).to_a |
|
24 | @addresses = @user.email_addresses.order(:id).where(:is_default => false).to_a |
@@ -22,6 +22,8 class GroupsController < ApplicationController | |||||
22 | before_filter :find_group, :except => [:index, :new, :create] |
|
22 | before_filter :find_group, :except => [:index, :new, :create] | |
23 | accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user |
|
23 | accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user | |
24 |
|
24 | |||
|
25 | require_sudo_mode :add_users, :remove_user, :create, :update, :destroy, :edit_membership, :destroy_membership | |||
|
26 | ||||
25 | helper :custom_fields |
|
27 | helper :custom_fields | |
26 | helper :principal_memberships |
|
28 | helper :principal_memberships | |
27 |
|
29 |
@@ -23,6 +23,8 class MembersController < ApplicationController | |||||
23 | before_filter :authorize |
|
23 | before_filter :authorize | |
24 | accept_api_auth :index, :show, :create, :update, :destroy |
|
24 | accept_api_auth :index, :show, :create, :update, :destroy | |
25 |
|
25 | |||
|
26 | require_sudo_mode :create, :update, :destroy | |||
|
27 | ||||
26 | def index |
|
28 | def index | |
27 | scope = @project.memberships.active |
|
29 | scope = @project.memberships.active | |
28 | @offset, @limit = api_offset_and_limit |
|
30 | @offset, @limit = api_offset_and_limit |
@@ -20,6 +20,9 class MyController < ApplicationController | |||||
20 | # let user change user's password when user has to |
|
20 | # let user change user's password when user has to | |
21 | skip_before_filter :check_password_change, :only => :password |
|
21 | skip_before_filter :check_password_change, :only => :password | |
22 |
|
22 | |||
|
23 | require_sudo_mode :account, only: :post | |||
|
24 | require_sudo_mode :reset_rss_key, :reset_api_key, :show_api_key, :destroy | |||
|
25 | ||||
23 | helper :issues |
|
26 | helper :issues | |
24 | helper :users |
|
27 | helper :users | |
25 | helper :custom_fields |
|
28 | helper :custom_fields | |
@@ -123,6 +126,10 class MyController < ApplicationController | |||||
123 | redirect_to my_account_path |
|
126 | redirect_to my_account_path | |
124 | end |
|
127 | end | |
125 |
|
128 | |||
|
129 | def show_api_key | |||
|
130 | @user = User.current | |||
|
131 | end | |||
|
132 | ||||
126 | # Create a new API key |
|
133 | # Create a new API key | |
127 | def reset_api_key |
|
134 | def reset_api_key | |
128 | if request.post? |
|
135 | if request.post? |
@@ -25,6 +25,7 class ProjectsController < ApplicationController | |||||
25 | before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] |
|
25 | before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] | |
26 | accept_rss_auth :index |
|
26 | accept_rss_auth :index | |
27 | accept_api_auth :index, :show, :create, :update, :destroy |
|
27 | accept_api_auth :index, :show, :create, :update, :destroy | |
|
28 | require_sudo_mode :destroy | |||
28 |
|
29 | |||
29 | after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller| |
|
30 | after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller| | |
30 | if controller.request.post? |
|
31 | if controller.request.post? |
@@ -23,6 +23,8 class RolesController < ApplicationController | |||||
23 | before_filter :find_role, :only => [:show, :edit, :update, :destroy] |
|
23 | before_filter :find_role, :only => [:show, :edit, :update, :destroy] | |
24 | accept_api_auth :index, :show |
|
24 | accept_api_auth :index, :show | |
25 |
|
25 | |||
|
26 | require_sudo_mode :create, :update, :destroy | |||
|
27 | ||||
26 | def index |
|
28 | def index | |
27 | respond_to do |format| |
|
29 | respond_to do |format| | |
28 | format.html { |
|
30 | format.html { |
@@ -23,6 +23,8 class SettingsController < ApplicationController | |||||
23 |
|
23 | |||
24 | before_filter :require_admin |
|
24 | before_filter :require_admin | |
25 |
|
25 | |||
|
26 | require_sudo_mode :index, :edit, :plugin | |||
|
27 | ||||
26 | def index |
|
28 | def index | |
27 | edit |
|
29 | edit | |
28 | render :action => 'edit' |
|
30 | render :action => 'edit' |
@@ -28,6 +28,8 class UsersController < ApplicationController | |||||
28 | include CustomFieldsHelper |
|
28 | include CustomFieldsHelper | |
29 | helper :principal_memberships |
|
29 | helper :principal_memberships | |
30 |
|
30 | |||
|
31 | require_sudo_mode :create, :update, :destroy | |||
|
32 | ||||
31 | def index |
|
33 | def index | |
32 | sort_init 'login', 'asc' |
|
34 | sort_init 'login', 'asc' | |
33 | sort_update %w(login firstname lastname admin created_on last_login_on) |
|
35 | sort_update %w(login firstname lastname admin created_on last_login_on) |
@@ -25,6 +25,7 module ApplicationHelper | |||||
25 | include Redmine::I18n |
|
25 | include Redmine::I18n | |
26 | include GravatarHelper::PublicMethods |
|
26 | include GravatarHelper::PublicMethods | |
27 | include Redmine::Pagination::Helper |
|
27 | include Redmine::Pagination::Helper | |
|
28 | include Redmine::SudoMode::Helper | |||
28 |
|
29 | |||
29 | extend Forwardable |
|
30 | extend Forwardable | |
30 | def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter |
|
31 | def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter |
@@ -21,8 +21,8 | |||||
21 | <% if Setting.rest_api_enabled? %> |
|
21 | <% if Setting.rest_api_enabled? %> | |
22 | <h4><%= l(:label_api_access_key) %></h4> |
|
22 | <h4><%= l(:label_api_access_key) %></h4> | |
23 | <div> |
|
23 | <div> | |
24 | <%= link_to_function(l(:button_show), "$('#api-access-key').toggle();")%> |
|
24 | <%= link_to l(:button_show), {:action => 'show_api_key'}, :remote => true %> | |
25 |
<pre id='api-access-key' class='autoscroll'>< |
|
25 | <pre id='api-access-key' class='autoscroll'></pre> | |
26 | </div> |
|
26 | </div> | |
27 | <%= javascript_tag("$('#api-access-key').hide();") %> |
|
27 | <%= javascript_tag("$('#api-access-key').hide();") %> | |
28 | <p> |
|
28 | <p> |
@@ -163,6 +163,7 de: | |||||
163 | button_close: Schließen |
|
163 | button_close: Schließen | |
164 | button_collapse_all: Alle einklappen |
|
164 | button_collapse_all: Alle einklappen | |
165 | button_configure: Konfigurieren |
|
165 | button_configure: Konfigurieren | |
|
166 | button_confirm_password: Kennwort bestätigen | |||
166 | button_copy: Kopieren |
|
167 | button_copy: Kopieren | |
167 | button_copy_and_follow: Kopieren und Ticket anzeigen |
|
168 | button_copy_and_follow: Kopieren und Ticket anzeigen | |
168 | button_create: Anlegen |
|
169 | button_create: Anlegen | |
@@ -670,6 +671,7 de: | |||||
670 | label_overview: Übersicht |
|
671 | label_overview: Übersicht | |
671 | label_parent_revision: Vorgänger |
|
672 | label_parent_revision: Vorgänger | |
672 | label_password_lost: Kennwort vergessen |
|
673 | label_password_lost: Kennwort vergessen | |
|
674 | label_password_required: Bitte geben Sie Ihr Kennwort ein | |||
673 | label_permissions: Berechtigungen |
|
675 | label_permissions: Berechtigungen | |
674 | label_permissions_report: Berechtigungsübersicht |
|
676 | label_permissions_report: Berechtigungsübersicht | |
675 | label_personalize_page: Diese Seite anpassen |
|
677 | label_personalize_page: Diese Seite anpassen |
@@ -554,6 +554,7 en: | |||||
554 | label_register: Register |
|
554 | label_register: Register | |
555 | label_login_with_open_id_option: or login with OpenID |
|
555 | label_login_with_open_id_option: or login with OpenID | |
556 | label_password_lost: Lost password |
|
556 | label_password_lost: Lost password | |
|
557 | label_password_required: Confirm your password to continue | |||
557 | label_home: Home |
|
558 | label_home: Home | |
558 | label_my_page: My page |
|
559 | label_my_page: My page | |
559 | label_my_account: My account |
|
560 | label_my_account: My account | |
@@ -989,6 +990,7 en: | |||||
989 | button_reset: Reset |
|
990 | button_reset: Reset | |
990 | button_rename: Rename |
|
991 | button_rename: Rename | |
991 | button_change_password: Change password |
|
992 | button_change_password: Change password | |
|
993 | button_confirm_password: Confirm password | |||
992 | button_copy: Copy |
|
994 | button_copy: Copy | |
993 | button_copy_and_follow: Copy and follow |
|
995 | button_copy_and_follow: Copy and follow | |
994 | button_annotate: Annotate |
|
996 | button_annotate: Annotate |
@@ -67,6 +67,7 Rails.application.routes.draw do | |||||
67 | match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page |
|
67 | match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page | |
68 | match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post |
|
68 | match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post | |
69 | match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post |
|
69 | match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post | |
|
70 | match 'my/show_api_key', :controller => 'my', :action => 'show_api_key', :via => :get | |||
70 | match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post] |
|
71 | match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post] | |
71 | match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get |
|
72 | match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get | |
72 | match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post |
|
73 | match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post |
@@ -22,6 +22,7 class AuthSourcesControllerTest < ActionController::TestCase | |||||
22 |
|
22 | |||
23 | def setup |
|
23 | def setup | |
24 | @request.session[:user_id] = 1 |
|
24 | @request.session[:user_id] = 1 | |
|
25 | Redmine::SudoMode.disable! | |||
25 | end |
|
26 | end | |
26 |
|
27 | |||
27 | def test_index |
|
28 | def test_index |
@@ -22,6 +22,7 class EmailAddressesControllerTest < ActionController::TestCase | |||||
22 |
|
22 | |||
23 | def setup |
|
23 | def setup | |
24 | User.current = nil |
|
24 | User.current = nil | |
|
25 | Redmine::SudoMode.disable! | |||
25 | end |
|
26 | end | |
26 |
|
27 | |||
27 | def test_index_with_no_additional_emails |
|
28 | def test_index_with_no_additional_emails |
@@ -22,6 +22,7 class GroupsControllerTest < ActionController::TestCase | |||||
22 |
|
22 | |||
23 | def setup |
|
23 | def setup | |
24 | @request.session[:user_id] = 1 |
|
24 | @request.session[:user_id] = 1 | |
|
25 | Redmine::SudoMode.disable! | |||
25 | end |
|
26 | end | |
26 |
|
27 | |||
27 | def test_index |
|
28 | def test_index |
@@ -23,6 +23,7 class MembersControllerTest < ActionController::TestCase | |||||
23 | def setup |
|
23 | def setup | |
24 | User.current = nil |
|
24 | User.current = nil | |
25 | @request.session[:user_id] = 2 |
|
25 | @request.session[:user_id] = 2 | |
|
26 | Redmine::SudoMode.disable! | |||
26 | end |
|
27 | end | |
27 |
|
28 | |||
28 | def test_new |
|
29 | def test_new |
@@ -23,6 +23,7 class MyControllerTest < ActionController::TestCase | |||||
23 |
|
23 | |||
24 | def setup |
|
24 | def setup | |
25 | @request.session[:user_id] = 2 |
|
25 | @request.session[:user_id] = 2 | |
|
26 | Redmine::SudoMode.disable! | |||
26 | end |
|
27 | end | |
27 |
|
28 | |||
28 | def test_index |
|
29 | def test_index | |
@@ -253,6 +254,12 class MyControllerTest < ActionController::TestCase | |||||
253 | assert_redirected_to '/my/account' |
|
254 | assert_redirected_to '/my/account' | |
254 | end |
|
255 | end | |
255 |
|
256 | |||
|
257 | def test_show_api_key | |||
|
258 | get :show_api_key | |||
|
259 | assert_response :success | |||
|
260 | assert_select 'pre', User.find(2).api_key | |||
|
261 | end | |||
|
262 | ||||
256 | def test_reset_api_key_with_existing_key |
|
263 | def test_reset_api_key_with_existing_key | |
257 | @previous_token_value = User.find(2).api_key # Will generate one if it's missing |
|
264 | @previous_token_value = User.find(2).api_key # Will generate one if it's missing | |
258 | post :reset_api_key |
|
265 | post :reset_api_key |
@@ -28,6 +28,7 class ProjectsControllerTest < ActionController::TestCase | |||||
28 | def setup |
|
28 | def setup | |
29 | @request.session[:user_id] = nil |
|
29 | @request.session[:user_id] = nil | |
30 | Setting.default_language = 'en' |
|
30 | Setting.default_language = 'en' | |
|
31 | Redmine::SudoMode.disable! | |||
31 | end |
|
32 | end | |
32 |
|
33 | |||
33 | def test_index_by_anonymous_should_not_show_private_projects |
|
34 | def test_index_by_anonymous_should_not_show_private_projects |
@@ -23,6 +23,7 class RolesControllerTest < ActionController::TestCase | |||||
23 | def setup |
|
23 | def setup | |
24 | User.current = nil |
|
24 | User.current = nil | |
25 | @request.session[:user_id] = 1 # admin |
|
25 | @request.session[:user_id] = 1 # admin | |
|
26 | Redmine::SudoMode.disable! | |||
26 | end |
|
27 | end | |
27 |
|
28 | |||
28 | def test_index |
|
29 | def test_index |
@@ -24,6 +24,7 class SettingsControllerTest < ActionController::TestCase | |||||
24 | def setup |
|
24 | def setup | |
25 | User.current = nil |
|
25 | User.current = nil | |
26 | @request.session[:user_id] = 1 # admin |
|
26 | @request.session[:user_id] = 1 # admin | |
|
27 | Redmine::SudoMode.disable! | |||
27 | end |
|
28 | end | |
28 |
|
29 | |||
29 | def test_index |
|
30 | def test_index |
@@ -30,6 +30,7 class UsersControllerTest < ActionController::TestCase | |||||
30 | def setup |
|
30 | def setup | |
31 | User.current = nil |
|
31 | User.current = nil | |
32 | @request.session[:user_id] = 1 # admin |
|
32 | @request.session[:user_id] = 1 # admin | |
|
33 | Redmine::SudoMode.disable! | |||
33 | end |
|
34 | end | |
34 |
|
35 | |||
35 | def test_index |
|
36 | def test_index |
@@ -26,6 +26,14 class AdminTest < Redmine::IntegrationTest | |||||
26 | :members, |
|
26 | :members, | |
27 | :enabled_modules |
|
27 | :enabled_modules | |
28 |
|
28 | |||
|
29 | def setup | |||
|
30 | Redmine::SudoMode.enable! | |||
|
31 | end | |||
|
32 | ||||
|
33 | def teardown | |||
|
34 | Redmine::SudoMode.disable! | |||
|
35 | end | |||
|
36 | ||||
29 | def test_add_user |
|
37 | def test_add_user | |
30 | log_user("admin", "admin") |
|
38 | log_user("admin", "admin") | |
31 | get "/users/new" |
|
39 | get "/users/new" | |
@@ -36,6 +44,15 class AdminTest < Redmine::IntegrationTest | |||||
36 | :lastname => "Smith", :mail => "psmith@somenet.foo", |
|
44 | :lastname => "Smith", :mail => "psmith@somenet.foo", | |
37 | :language => "en", :password => "psmith09", |
|
45 | :language => "en", :password => "psmith09", | |
38 | :password_confirmation => "psmith09" } |
|
46 | :password_confirmation => "psmith09" } | |
|
47 | assert_response :success | |||
|
48 | assert_nil User.find_by_login("psmith") | |||
|
49 | ||||
|
50 | post "/users", | |||
|
51 | :user => { :login => "psmith", :firstname => "Paul", | |||
|
52 | :lastname => "Smith", :mail => "psmith@somenet.foo", | |||
|
53 | :language => "en", :password => "psmith09", | |||
|
54 | :password_confirmation => "psmith09" }, | |||
|
55 | :sudo_password => 'admin' | |||
39 |
|
56 | |||
40 | user = User.find_by_login("psmith") |
|
57 | user = User.find_by_login("psmith") | |
41 | assert_kind_of User, user |
|
58 | assert_kind_of User, user |
General Comments 0
You need to be logged in to leave comments.
Login now