##// END OF EJS Templates
Set a default timeout value (#19851)....
Jean-Philippe Lang -
r13972:752c414e8abd
parent child
Show More
@@ -1,223 +1,224
1 1 require 'active_support/core_ext/object/to_query'
2 2 require 'rack/utils'
3 3
4 4 module Redmine
5 5 module SudoMode
6 6
7 7 class SudoRequired < StandardError
8 8 end
9 9
10 10
11 11 class Form
12 12 include ActiveModel::Validations
13 13
14 14 attr_accessor :password, :original_fields
15 15 validate :check_password
16 16
17 17 def initialize(password = nil)
18 18 self.password = password
19 19 end
20 20
21 21 def check_password
22 22 unless password.present? && User.current.check_password?(password)
23 23 errors[:password] << :invalid
24 24 end
25 25 end
26 26 end
27 27
28 28
29 29 module Helper
30 30 # Represents params data from hash as hidden fields
31 31 #
32 32 # taken from https://github.com/brianhempel/hash_to_hidden_fields
33 33 def hash_to_hidden_fields(hash)
34 34 cleaned_hash = hash.reject { |k, v| v.nil? }
35 35 pairs = cleaned_hash.to_query.split(Rack::Utils::DEFAULT_SEP)
36 36 tags = pairs.map do |pair|
37 37 key, value = pair.split('=', 2).map { |str| Rack::Utils.unescape(str) }
38 38 hidden_field_tag(key, value)
39 39 end
40 40 tags.join("\n").html_safe
41 41 end
42 42 end
43 43
44 44
45 45 module Controller
46 46 extend ActiveSupport::Concern
47 47
48 48 included do
49 49 around_filter :sudo_mode
50 50 end
51 51
52 52 # Sudo mode Around Filter
53 53 #
54 54 # Checks the 'last used' timestamp from session and sets the
55 55 # SudoMode::active? flag accordingly.
56 56 #
57 57 # After the request refreshes the timestamp if sudo mode was used during
58 58 # this request.
59 59 def sudo_mode
60 60 if sudo_timestamp_valid?
61 61 SudoMode.active!
62 62 end
63 63 yield
64 64 update_sudo_timestamp! if SudoMode.was_used?
65 65 end
66 66
67 67 # This renders the sudo mode form / handles sudo form submission.
68 68 #
69 69 # Call this method in controller actions if sudo permissions are required
70 70 # for processing this request. This approach is good in cases where the
71 71 # action needs to be protected in any case or where the check is simple.
72 72 #
73 73 # In cases where this decision depends on complex conditions in the model,
74 74 # consider the declarative approach using the require_sudo_mode class
75 75 # method and a corresponding declaration in the model that causes it to throw
76 76 # a SudoRequired Error when necessary.
77 77 #
78 78 # All parameter names given are included as hidden fields to be resubmitted
79 79 # along with the password.
80 80 #
81 81 # Returns true when processing the action should continue, false otherwise.
82 82 # If false is returned, render has already been called for display of the
83 83 # password form.
84 84 #
85 85 # if @user.mail_changed?
86 86 # require_sudo_mode :user or return
87 87 # end
88 88 #
89 89 def require_sudo_mode(*param_names)
90 90 return true if SudoMode.active?
91 91
92 92 if param_names.blank?
93 93 param_names = params.keys - %w(id action controller sudo_password)
94 94 end
95 95
96 96 process_sudo_form
97 97
98 98 if SudoMode.active?
99 99 true
100 100 else
101 101 render_sudo_form param_names
102 102 false
103 103 end
104 104 end
105 105
106 106 # display the sudo password form
107 107 def render_sudo_form(param_names)
108 108 @sudo_form ||= SudoMode::Form.new
109 109 @sudo_form.original_fields = params.slice( *param_names )
110 110 # a simple 'render "sudo_mode/new"' works when used directly inside an
111 111 # action, but not when called from a before_filter:
112 112 respond_to do |format|
113 113 format.html { render 'sudo_mode/new' }
114 114 format.js { render 'sudo_mode/new' }
115 115 end
116 116 end
117 117
118 118 # handle sudo password form submit
119 119 def process_sudo_form
120 120 if params[:sudo_password]
121 121 @sudo_form = SudoMode::Form.new(params[:sudo_password])
122 122 if @sudo_form.valid?
123 123 SudoMode.active!
124 124 else
125 125 flash.now[:error] = l(:notice_account_wrong_password)
126 126 end
127 127 end
128 128 end
129 129
130 130 def sudo_timestamp_valid?
131 131 session[:sudo_timestamp].to_i > SudoMode.timeout.ago.to_i
132 132 end
133 133
134 134 def update_sudo_timestamp!(new_value = Time.now.to_i)
135 135 session[:sudo_timestamp] = new_value
136 136 end
137 137
138 138 # Before Filter which is used by the require_sudo_mode class method.
139 139 class SudoRequestFilter < Struct.new(:parameters, :request_methods)
140 140 def before(controller)
141 141 method_matches = request_methods.blank? || request_methods.include?(controller.request.method_symbol)
142 142 if controller.api_request?
143 143 true
144 144 elsif SudoMode.possible? && method_matches
145 145 controller.require_sudo_mode( *parameters )
146 146 else
147 147 true
148 148 end
149 149 end
150 150 end
151 151
152 152 module ClassMethods
153 153
154 154 # Handles sudo requirements for the given actions, preserving the named
155 155 # parameters, or any parameters if you omit the :parameters option.
156 156 #
157 157 # Sudo enforcement by default is active for all requests to an action
158 158 # but may be limited to a certain subset of request methods via the
159 159 # :only option.
160 160 #
161 161 # Examples:
162 162 #
163 163 # require_sudo_mode :account, only: :post
164 164 # require_sudo_mode :update, :create, parameters: %w(role)
165 165 # require_sudo_mode :destroy
166 166 #
167 167 def require_sudo_mode(*args)
168 168 actions = args.dup
169 169 options = actions.extract_options!
170 170 filter = SudoRequestFilter.new Array(options[:parameters]), Array(options[:only])
171 171 before_filter filter, only: actions
172 172 end
173 173 end
174 174 end
175 175
176 176
177 177 # true if the sudo mode state was queried during this request
178 178 def self.was_used?
179 179 !!RequestStore.store[:sudo_mode_was_used]
180 180 end
181 181
182 182 # true if sudo mode is currently active.
183 183 #
184 184 # Calling this method also turns was_used? to true, therefore
185 185 # it is important to only call this when sudo is actually needed, as the last
186 186 # condition to determine wether a change can be done or not.
187 187 #
188 188 # If you do it wrong, timeout of the sudo mode will happen too late or not at
189 189 # all.
190 190 def self.active?
191 191 if !!RequestStore.store[:sudo_mode]
192 192 RequestStore.store[:sudo_mode_was_used] = true
193 193 end
194 194 end
195 195
196 196 def self.active!
197 197 RequestStore.store[:sudo_mode] = true
198 198 end
199 199
200 200 def self.possible?
201 201 enabled? && User.current.logged?
202 202 end
203 203
204 204 # Turn off sudo mode (never require password entry).
205 205 def self.disable!
206 206 RequestStore.store[:sudo_mode_disabled] = true
207 207 end
208 208
209 209 # Turn sudo mode back on
210 210 def self.enable!
211 211 RequestStore.store[:sudo_mode_disabled] = nil
212 212 end
213 213
214 214 def self.enabled?
215 215 Redmine::Configuration['sudo_mode'] && !RequestStore.store[:sudo_mode_disabled]
216 216 end
217 217
218 218 # Timespan after which sudo mode expires when unused.
219 219 def self.timeout
220 Redmine::Configuration['sudo_mode_timeout'].to_i.minutes
220 m = Redmine::Configuration['sudo_mode_timeout'].to_i
221 (m > 0 ? m : 15).minutes
221 222 end
222 223 end
223 224 end
General Comments 0
You need to be logged in to leave comments. Login now