##// END OF EJS Templates
permissions: enable caching by controlling short_term cache settings.
marcink -
r2796:3deed041 default
parent child Browse files
Show More
@@ -1,719 +1,720 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 use = egg:waitress#main
54 use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 threads = 5
56 threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 max_request_body_size = 107374182400
58 max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 asyncore_use_poll = true
61 asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 #use = egg:gunicorn#main
69 #use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 #workers = 2
74 #workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
76 ## generally recommended to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 #proc_name = rhodecode
79 #proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 #worker_class = gevent
82 #worker_class = gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 #max_requests = 1000
87 #max_requests = 1000
88 #max_requests_jitter = 30
88 #max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 #timeout = 21600
91 #timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 # During development the we want to have the debug toolbar enabled
111 # During development the we want to have the debug toolbar enabled
112 pyramid.includes =
112 pyramid.includes =
113 pyramid_debugtoolbar
113 pyramid_debugtoolbar
114 rhodecode.lib.middleware.request_wrapper
114 rhodecode.lib.middleware.request_wrapper
115
115
116 pyramid.reload_templates = true
116 pyramid.reload_templates = true
117
117
118 debugtoolbar.hosts = 0.0.0.0/0
118 debugtoolbar.hosts = 0.0.0.0/0
119 debugtoolbar.exclude_prefixes =
119 debugtoolbar.exclude_prefixes =
120 /css
120 /css
121 /fonts
121 /fonts
122 /images
122 /images
123 /js
123 /js
124
124
125 ## RHODECODE PLUGINS ##
125 ## RHODECODE PLUGINS ##
126 rhodecode.includes =
126 rhodecode.includes =
127 rhodecode.api
127 rhodecode.api
128
128
129
129
130 # api prefix url
130 # api prefix url
131 rhodecode.api.url = /_admin/api
131 rhodecode.api.url = /_admin/api
132
132
133
133
134 ## END RHODECODE PLUGINS ##
134 ## END RHODECODE PLUGINS ##
135
135
136 ## encryption key used to encrypt social plugin tokens,
136 ## encryption key used to encrypt social plugin tokens,
137 ## remote_urls with credentials etc, if not set it defaults to
137 ## remote_urls with credentials etc, if not set it defaults to
138 ## `beaker.session.secret`
138 ## `beaker.session.secret`
139 #rhodecode.encrypted_values.secret =
139 #rhodecode.encrypted_values.secret =
140
140
141 ## decryption strict mode (enabled by default). It controls if decryption raises
141 ## decryption strict mode (enabled by default). It controls if decryption raises
142 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
142 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
143 #rhodecode.encrypted_values.strict = false
143 #rhodecode.encrypted_values.strict = false
144
144
145 ## return gzipped responses from Rhodecode (static files/application)
145 ## return gzipped responses from Rhodecode (static files/application)
146 gzip_responses = false
146 gzip_responses = false
147
147
148 ## autogenerate javascript routes file on startup
148 ## autogenerate javascript routes file on startup
149 generate_js_files = false
149 generate_js_files = false
150
150
151 ## Optional Languages
151 ## Optional Languages
152 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
152 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
153 lang = en
153 lang = en
154
154
155 ## perform a full repository scan on each server start, this should be
155 ## perform a full repository scan on each server start, this should be
156 ## set to false after first startup, to allow faster server restarts.
156 ## set to false after first startup, to allow faster server restarts.
157 startup.import_repos = false
157 startup.import_repos = false
158
158
159 ## Uncomment and set this path to use archive download cache.
159 ## Uncomment and set this path to use archive download cache.
160 ## Once enabled, generated archives will be cached at this location
160 ## Once enabled, generated archives will be cached at this location
161 ## and served from the cache during subsequent requests for the same archive of
161 ## and served from the cache during subsequent requests for the same archive of
162 ## the repository.
162 ## the repository.
163 #archive_cache_dir = /tmp/tarballcache
163 #archive_cache_dir = /tmp/tarballcache
164
164
165 ## URL at which the application is running. This is used for bootstraping
165 ## URL at which the application is running. This is used for bootstraping
166 ## requests in context when no web request is available. Used in ishell, or
166 ## requests in context when no web request is available. Used in ishell, or
167 ## SSH calls. Set this for events to receive proper url for SSH calls.
167 ## SSH calls. Set this for events to receive proper url for SSH calls.
168 app.base_url = http://rhodecode.local
168 app.base_url = http://rhodecode.local
169
169
170 ## change this to unique ID for security
170 ## change this to unique ID for security
171 app_instance_uuid = rc-production
171 app_instance_uuid = rc-production
172
172
173 ## cut off limit for large diffs (size in bytes). If overall diff size on
173 ## cut off limit for large diffs (size in bytes). If overall diff size on
174 ## commit, or pull request exceeds this limit this diff will be displayed
174 ## commit, or pull request exceeds this limit this diff will be displayed
175 ## partially. E.g 512000 == 512Kb
175 ## partially. E.g 512000 == 512Kb
176 cut_off_limit_diff = 512000
176 cut_off_limit_diff = 512000
177
177
178 ## cut off limit for large files inside diffs (size in bytes). Each individual
178 ## cut off limit for large files inside diffs (size in bytes). Each individual
179 ## file inside diff which exceeds this limit will be displayed partially.
179 ## file inside diff which exceeds this limit will be displayed partially.
180 ## E.g 128000 == 128Kb
180 ## E.g 128000 == 128Kb
181 cut_off_limit_file = 128000
181 cut_off_limit_file = 128000
182
182
183 ## use cache version of scm repo everywhere
183 ## use cache version of scm repo everywhere
184 vcs_full_cache = true
184 vcs_full_cache = true
185
185
186 ## force https in RhodeCode, fixes https redirects, assumes it's always https
186 ## force https in RhodeCode, fixes https redirects, assumes it's always https
187 ## Normally this is controlled by proper http flags sent from http server
187 ## Normally this is controlled by proper http flags sent from http server
188 force_https = false
188 force_https = false
189
189
190 ## use Strict-Transport-Security headers
190 ## use Strict-Transport-Security headers
191 use_htsts = false
191 use_htsts = false
192
192
193 ## git rev filter option, --all is the default filter, if you need to
193 ## git rev filter option, --all is the default filter, if you need to
194 ## hide all refs in changelog switch this to --branches --tags
194 ## hide all refs in changelog switch this to --branches --tags
195 git_rev_filter = --branches --tags
195 git_rev_filter = --branches --tags
196
196
197 # Set to true if your repos are exposed using the dumb protocol
197 # Set to true if your repos are exposed using the dumb protocol
198 git_update_server_info = false
198 git_update_server_info = false
199
199
200 ## RSS/ATOM feed options
200 ## RSS/ATOM feed options
201 rss_cut_off_limit = 256000
201 rss_cut_off_limit = 256000
202 rss_items_per_page = 10
202 rss_items_per_page = 10
203 rss_include_diff = false
203 rss_include_diff = false
204
204
205 ## gist URL alias, used to create nicer urls for gist. This should be an
205 ## gist URL alias, used to create nicer urls for gist. This should be an
206 ## url that does rewrites to _admin/gists/{gistid}.
206 ## url that does rewrites to _admin/gists/{gistid}.
207 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
207 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
208 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
208 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
209 gist_alias_url =
209 gist_alias_url =
210
210
211 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
211 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
212 ## used for access.
212 ## used for access.
213 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
213 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
214 ## came from the the logged in user who own this authentication token.
214 ## came from the the logged in user who own this authentication token.
215 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
215 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
216 ## authentication token. Such view would be only accessible when used together
216 ## authentication token. Such view would be only accessible when used together
217 ## with this authentication token
217 ## with this authentication token
218 ##
218 ##
219 ## list of all views can be found under `/_admin/permissions/auth_token_access`
219 ## list of all views can be found under `/_admin/permissions/auth_token_access`
220 ## The list should be "," separated and on a single line.
220 ## The list should be "," separated and on a single line.
221 ##
221 ##
222 ## Most common views to enable:
222 ## Most common views to enable:
223 # RepoCommitsView:repo_commit_download
223 # RepoCommitsView:repo_commit_download
224 # RepoCommitsView:repo_commit_patch
224 # RepoCommitsView:repo_commit_patch
225 # RepoCommitsView:repo_commit_raw
225 # RepoCommitsView:repo_commit_raw
226 # RepoCommitsView:repo_commit_raw@TOKEN
226 # RepoCommitsView:repo_commit_raw@TOKEN
227 # RepoFilesView:repo_files_diff
227 # RepoFilesView:repo_files_diff
228 # RepoFilesView:repo_archivefile
228 # RepoFilesView:repo_archivefile
229 # RepoFilesView:repo_file_raw
229 # RepoFilesView:repo_file_raw
230 # GistView:*
230 # GistView:*
231 api_access_controllers_whitelist =
231 api_access_controllers_whitelist =
232
232
233 ## default encoding used to convert from and to unicode
233 ## default encoding used to convert from and to unicode
234 ## can be also a comma separated list of encoding in case of mixed encodings
234 ## can be also a comma separated list of encoding in case of mixed encodings
235 default_encoding = UTF-8
235 default_encoding = UTF-8
236
236
237 ## instance-id prefix
237 ## instance-id prefix
238 ## a prefix key for this instance used for cache invalidation when running
238 ## a prefix key for this instance used for cache invalidation when running
239 ## multiple instances of rhodecode, make sure it's globally unique for
239 ## multiple instances of rhodecode, make sure it's globally unique for
240 ## all running rhodecode instances. Leave empty if you don't use it
240 ## all running rhodecode instances. Leave empty if you don't use it
241 instance_id =
241 instance_id =
242
242
243 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
243 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
244 ## of an authentication plugin also if it is disabled by it's settings.
244 ## of an authentication plugin also if it is disabled by it's settings.
245 ## This could be useful if you are unable to log in to the system due to broken
245 ## This could be useful if you are unable to log in to the system due to broken
246 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
246 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
247 ## module to log in again and fix the settings.
247 ## module to log in again and fix the settings.
248 ##
248 ##
249 ## Available builtin plugin IDs (hash is part of the ID):
249 ## Available builtin plugin IDs (hash is part of the ID):
250 ## egg:rhodecode-enterprise-ce#rhodecode
250 ## egg:rhodecode-enterprise-ce#rhodecode
251 ## egg:rhodecode-enterprise-ce#pam
251 ## egg:rhodecode-enterprise-ce#pam
252 ## egg:rhodecode-enterprise-ce#ldap
252 ## egg:rhodecode-enterprise-ce#ldap
253 ## egg:rhodecode-enterprise-ce#jasig_cas
253 ## egg:rhodecode-enterprise-ce#jasig_cas
254 ## egg:rhodecode-enterprise-ce#headers
254 ## egg:rhodecode-enterprise-ce#headers
255 ## egg:rhodecode-enterprise-ce#crowd
255 ## egg:rhodecode-enterprise-ce#crowd
256 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
256 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
257
257
258 ## alternative return HTTP header for failed authentication. Default HTTP
258 ## alternative return HTTP header for failed authentication. Default HTTP
259 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
259 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
260 ## handling that causing a series of failed authentication calls.
260 ## handling that causing a series of failed authentication calls.
261 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
261 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
262 ## This will be served instead of default 401 on bad authnetication
262 ## This will be served instead of default 401 on bad authnetication
263 auth_ret_code =
263 auth_ret_code =
264
264
265 ## use special detection method when serving auth_ret_code, instead of serving
265 ## use special detection method when serving auth_ret_code, instead of serving
266 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
266 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
267 ## and then serve auth_ret_code to clients
267 ## and then serve auth_ret_code to clients
268 auth_ret_code_detection = false
268 auth_ret_code_detection = false
269
269
270 ## locking return code. When repository is locked return this HTTP code. 2XX
270 ## locking return code. When repository is locked return this HTTP code. 2XX
271 ## codes don't break the transactions while 4XX codes do
271 ## codes don't break the transactions while 4XX codes do
272 lock_ret_code = 423
272 lock_ret_code = 423
273
273
274 ## allows to change the repository location in settings page
274 ## allows to change the repository location in settings page
275 allow_repo_location_change = true
275 allow_repo_location_change = true
276
276
277 ## allows to setup custom hooks in settings page
277 ## allows to setup custom hooks in settings page
278 allow_custom_hooks_settings = true
278 allow_custom_hooks_settings = true
279
279
280 ## generated license token, goto license page in RhodeCode settings to obtain
280 ## generated license token, goto license page in RhodeCode settings to obtain
281 ## new token
281 ## new token
282 license_token =
282 license_token =
283
283
284 ## supervisor connection uri, for managing supervisor and logs.
284 ## supervisor connection uri, for managing supervisor and logs.
285 supervisor.uri =
285 supervisor.uri =
286 ## supervisord group name/id we only want this RC instance to handle
286 ## supervisord group name/id we only want this RC instance to handle
287 supervisor.group_id = dev
287 supervisor.group_id = dev
288
288
289 ## Display extended labs settings
289 ## Display extended labs settings
290 labs_settings_active = true
290 labs_settings_active = true
291
291
292 ####################################
292 ####################################
293 ### CELERY CONFIG ####
293 ### CELERY CONFIG ####
294 ####################################
294 ####################################
295 ## run: /path/to/celery worker \
295 ## run: /path/to/celery worker \
296 ## -E --beat --app rhodecode.lib.celerylib.loader \
296 ## -E --beat --app rhodecode.lib.celerylib.loader \
297 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
297 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
298 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
298 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
299
299
300 use_celery = false
300 use_celery = false
301
301
302 ## connection url to the message broker (default rabbitmq)
302 ## connection url to the message broker (default rabbitmq)
303 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
303 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
304
304
305 ## maximum tasks to execute before worker restart
305 ## maximum tasks to execute before worker restart
306 celery.max_tasks_per_child = 100
306 celery.max_tasks_per_child = 100
307
307
308 ## tasks will never be sent to the queue, but executed locally instead.
308 ## tasks will never be sent to the queue, but executed locally instead.
309 celery.task_always_eager = false
309 celery.task_always_eager = false
310
310
311 ####################################
311 ####################################
312 ### BEAKER CACHE ####
312 ### BEAKER CACHE ####
313 ####################################
313 ####################################
314 # default cache dir for templates. Putting this into a ramdisk
314 # default cache dir for templates. Putting this into a ramdisk
315 ## can boost performance, eg. %(here)s/data_ramdisk
315 ## can boost performance, eg. %(here)s/data_ramdisk
316 cache_dir = %(here)s/data
316 cache_dir = %(here)s/data
317
317
318 ## locking and default file storage for Beaker. Putting this into a ramdisk
318 ## locking and default file storage for Beaker. Putting this into a ramdisk
319 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
319 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
320 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
320 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
321 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
321 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
322
322
323 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
323 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
324
324
325 beaker.cache.super_short_term.type = memory
325 beaker.cache.super_short_term.type = memory
326 beaker.cache.super_short_term.expire = 10
326 beaker.cache.super_short_term.expire = 10
327 beaker.cache.super_short_term.key_length = 256
327 beaker.cache.super_short_term.key_length = 256
328
328
329 beaker.cache.short_term.type = memory
329 # used for caching user permissions
330 beaker.cache.short_term.expire = 60
330 beaker.cache.short_term.type = file
331 beaker.cache.short_term.expire = 0
331 beaker.cache.short_term.key_length = 256
332 beaker.cache.short_term.key_length = 256
332
333
333 beaker.cache.long_term.type = memory
334 beaker.cache.long_term.type = memory
334 beaker.cache.long_term.expire = 36000
335 beaker.cache.long_term.expire = 36000
335 beaker.cache.long_term.key_length = 256
336 beaker.cache.long_term.key_length = 256
336
337
337 beaker.cache.sql_cache_short.type = memory
338 beaker.cache.sql_cache_short.type = memory
338 beaker.cache.sql_cache_short.expire = 10
339 beaker.cache.sql_cache_short.expire = 10
339 beaker.cache.sql_cache_short.key_length = 256
340 beaker.cache.sql_cache_short.key_length = 256
340
341
341 ## default is memory cache, configure only if required
342 ## default is memory cache, configure only if required
342 ## using multi-node or multi-worker setup
343 ## using multi-node or multi-worker setup
343 #beaker.cache.auth_plugins.type = ext:database
344 #beaker.cache.auth_plugins.type = ext:database
344 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
345 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
345 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
346 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
346 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
347 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
347 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
348 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
348 #beaker.cache.auth_plugins.sa.pool_size = 10
349 #beaker.cache.auth_plugins.sa.pool_size = 10
349 #beaker.cache.auth_plugins.sa.max_overflow = 0
350 #beaker.cache.auth_plugins.sa.max_overflow = 0
350
351
351 beaker.cache.repo_cache_long.type = memorylru_base
352 beaker.cache.repo_cache_long.type = memorylru_base
352 beaker.cache.repo_cache_long.max_items = 4096
353 beaker.cache.repo_cache_long.max_items = 4096
353 beaker.cache.repo_cache_long.expire = 2592000
354 beaker.cache.repo_cache_long.expire = 2592000
354
355
355 ## default is memorylru_base cache, configure only if required
356 ## default is memorylru_base cache, configure only if required
356 ## using multi-node or multi-worker setup
357 ## using multi-node or multi-worker setup
357 #beaker.cache.repo_cache_long.type = ext:memcached
358 #beaker.cache.repo_cache_long.type = ext:memcached
358 #beaker.cache.repo_cache_long.url = localhost:11211
359 #beaker.cache.repo_cache_long.url = localhost:11211
359 #beaker.cache.repo_cache_long.expire = 1209600
360 #beaker.cache.repo_cache_long.expire = 1209600
360 #beaker.cache.repo_cache_long.key_length = 256
361 #beaker.cache.repo_cache_long.key_length = 256
361
362
362 ####################################
363 ####################################
363 ### BEAKER SESSION ####
364 ### BEAKER SESSION ####
364 ####################################
365 ####################################
365
366
366 ## .session.type is type of storage options for the session, current allowed
367 ## .session.type is type of storage options for the session, current allowed
367 ## types are file, ext:memcached, ext:database, and memory (default).
368 ## types are file, ext:memcached, ext:database, and memory (default).
368 beaker.session.type = file
369 beaker.session.type = file
369 beaker.session.data_dir = %(here)s/data/sessions/data
370 beaker.session.data_dir = %(here)s/data/sessions/data
370
371
371 ## db based session, fast, and allows easy management over logged in users
372 ## db based session, fast, and allows easy management over logged in users
372 #beaker.session.type = ext:database
373 #beaker.session.type = ext:database
373 #beaker.session.table_name = db_session
374 #beaker.session.table_name = db_session
374 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
375 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
375 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
376 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
376 #beaker.session.sa.pool_recycle = 3600
377 #beaker.session.sa.pool_recycle = 3600
377 #beaker.session.sa.echo = false
378 #beaker.session.sa.echo = false
378
379
379 beaker.session.key = rhodecode
380 beaker.session.key = rhodecode
380 beaker.session.secret = develop-rc-uytcxaz
381 beaker.session.secret = develop-rc-uytcxaz
381 beaker.session.lock_dir = %(here)s/data/sessions/lock
382 beaker.session.lock_dir = %(here)s/data/sessions/lock
382
383
383 ## Secure encrypted cookie. Requires AES and AES python libraries
384 ## Secure encrypted cookie. Requires AES and AES python libraries
384 ## you must disable beaker.session.secret to use this
385 ## you must disable beaker.session.secret to use this
385 #beaker.session.encrypt_key = key_for_encryption
386 #beaker.session.encrypt_key = key_for_encryption
386 #beaker.session.validate_key = validation_key
387 #beaker.session.validate_key = validation_key
387
388
388 ## sets session as invalid(also logging out user) if it haven not been
389 ## sets session as invalid(also logging out user) if it haven not been
389 ## accessed for given amount of time in seconds
390 ## accessed for given amount of time in seconds
390 beaker.session.timeout = 2592000
391 beaker.session.timeout = 2592000
391 beaker.session.httponly = true
392 beaker.session.httponly = true
392 ## Path to use for the cookie. Set to prefix if you use prefix middleware
393 ## Path to use for the cookie. Set to prefix if you use prefix middleware
393 #beaker.session.cookie_path = /custom_prefix
394 #beaker.session.cookie_path = /custom_prefix
394
395
395 ## uncomment for https secure cookie
396 ## uncomment for https secure cookie
396 beaker.session.secure = false
397 beaker.session.secure = false
397
398
398 ## auto save the session to not to use .save()
399 ## auto save the session to not to use .save()
399 beaker.session.auto = false
400 beaker.session.auto = false
400
401
401 ## default cookie expiration time in seconds, set to `true` to set expire
402 ## default cookie expiration time in seconds, set to `true` to set expire
402 ## at browser close
403 ## at browser close
403 #beaker.session.cookie_expires = 3600
404 #beaker.session.cookie_expires = 3600
404
405
405 ###################################
406 ###################################
406 ## SEARCH INDEXING CONFIGURATION ##
407 ## SEARCH INDEXING CONFIGURATION ##
407 ###################################
408 ###################################
408 ## Full text search indexer is available in rhodecode-tools under
409 ## Full text search indexer is available in rhodecode-tools under
409 ## `rhodecode-tools index` command
410 ## `rhodecode-tools index` command
410
411
411 ## WHOOSH Backend, doesn't require additional services to run
412 ## WHOOSH Backend, doesn't require additional services to run
412 ## it works good with few dozen repos
413 ## it works good with few dozen repos
413 search.module = rhodecode.lib.index.whoosh
414 search.module = rhodecode.lib.index.whoosh
414 search.location = %(here)s/data/index
415 search.location = %(here)s/data/index
415
416
416 ########################################
417 ########################################
417 ### CHANNELSTREAM CONFIG ####
418 ### CHANNELSTREAM CONFIG ####
418 ########################################
419 ########################################
419 ## channelstream enables persistent connections and live notification
420 ## channelstream enables persistent connections and live notification
420 ## in the system. It's also used by the chat system
421 ## in the system. It's also used by the chat system
421 channelstream.enabled = false
422 channelstream.enabled = false
422
423
423 ## server address for channelstream server on the backend
424 ## server address for channelstream server on the backend
424 channelstream.server = 127.0.0.1:9800
425 channelstream.server = 127.0.0.1:9800
425
426
426 ## location of the channelstream server from outside world
427 ## location of the channelstream server from outside world
427 ## use ws:// for http or wss:// for https. This address needs to be handled
428 ## use ws:// for http or wss:// for https. This address needs to be handled
428 ## by external HTTP server such as Nginx or Apache
429 ## by external HTTP server such as Nginx or Apache
429 ## see nginx/apache configuration examples in our docs
430 ## see nginx/apache configuration examples in our docs
430 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
431 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
431 channelstream.secret = secret
432 channelstream.secret = secret
432 channelstream.history.location = %(here)s/channelstream_history
433 channelstream.history.location = %(here)s/channelstream_history
433
434
434 ## Internal application path that Javascript uses to connect into.
435 ## Internal application path that Javascript uses to connect into.
435 ## If you use proxy-prefix the prefix should be added before /_channelstream
436 ## If you use proxy-prefix the prefix should be added before /_channelstream
436 channelstream.proxy_path = /_channelstream
437 channelstream.proxy_path = /_channelstream
437
438
438
439
439 ###################################
440 ###################################
440 ## APPENLIGHT CONFIG ##
441 ## APPENLIGHT CONFIG ##
441 ###################################
442 ###################################
442
443
443 ## Appenlight is tailored to work with RhodeCode, see
444 ## Appenlight is tailored to work with RhodeCode, see
444 ## http://appenlight.com for details how to obtain an account
445 ## http://appenlight.com for details how to obtain an account
445
446
446 ## appenlight integration enabled
447 ## appenlight integration enabled
447 appenlight = false
448 appenlight = false
448
449
449 appenlight.server_url = https://api.appenlight.com
450 appenlight.server_url = https://api.appenlight.com
450 appenlight.api_key = YOUR_API_KEY
451 appenlight.api_key = YOUR_API_KEY
451 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
452 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
452
453
453 # used for JS client
454 # used for JS client
454 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
455 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
455
456
456 ## TWEAK AMOUNT OF INFO SENT HERE
457 ## TWEAK AMOUNT OF INFO SENT HERE
457
458
458 ## enables 404 error logging (default False)
459 ## enables 404 error logging (default False)
459 appenlight.report_404 = false
460 appenlight.report_404 = false
460
461
461 ## time in seconds after request is considered being slow (default 1)
462 ## time in seconds after request is considered being slow (default 1)
462 appenlight.slow_request_time = 1
463 appenlight.slow_request_time = 1
463
464
464 ## record slow requests in application
465 ## record slow requests in application
465 ## (needs to be enabled for slow datastore recording and time tracking)
466 ## (needs to be enabled for slow datastore recording and time tracking)
466 appenlight.slow_requests = true
467 appenlight.slow_requests = true
467
468
468 ## enable hooking to application loggers
469 ## enable hooking to application loggers
469 appenlight.logging = true
470 appenlight.logging = true
470
471
471 ## minimum log level for log capture
472 ## minimum log level for log capture
472 appenlight.logging.level = WARNING
473 appenlight.logging.level = WARNING
473
474
474 ## send logs only from erroneous/slow requests
475 ## send logs only from erroneous/slow requests
475 ## (saves API quota for intensive logging)
476 ## (saves API quota for intensive logging)
476 appenlight.logging_on_error = false
477 appenlight.logging_on_error = false
477
478
478 ## list of additonal keywords that should be grabbed from environ object
479 ## list of additonal keywords that should be grabbed from environ object
479 ## can be string with comma separated list of words in lowercase
480 ## can be string with comma separated list of words in lowercase
480 ## (by default client will always send following info:
481 ## (by default client will always send following info:
481 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
482 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
482 ## start with HTTP* this list be extended with additional keywords here
483 ## start with HTTP* this list be extended with additional keywords here
483 appenlight.environ_keys_whitelist =
484 appenlight.environ_keys_whitelist =
484
485
485 ## list of keywords that should be blanked from request object
486 ## list of keywords that should be blanked from request object
486 ## can be string with comma separated list of words in lowercase
487 ## can be string with comma separated list of words in lowercase
487 ## (by default client will always blank keys that contain following words
488 ## (by default client will always blank keys that contain following words
488 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
489 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
489 ## this list be extended with additional keywords set here
490 ## this list be extended with additional keywords set here
490 appenlight.request_keys_blacklist =
491 appenlight.request_keys_blacklist =
491
492
492 ## list of namespaces that should be ignores when gathering log entries
493 ## list of namespaces that should be ignores when gathering log entries
493 ## can be string with comma separated list of namespaces
494 ## can be string with comma separated list of namespaces
494 ## (by default the client ignores own entries: appenlight_client.client)
495 ## (by default the client ignores own entries: appenlight_client.client)
495 appenlight.log_namespace_blacklist =
496 appenlight.log_namespace_blacklist =
496
497
497
498
498 ################################################################################
499 ################################################################################
499 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
500 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
500 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
501 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
501 ## execute malicious code after an exception is raised. ##
502 ## execute malicious code after an exception is raised. ##
502 ################################################################################
503 ################################################################################
503 #set debug = false
504 #set debug = false
504
505
505
506
506 ##############
507 ##############
507 ## STYLING ##
508 ## STYLING ##
508 ##############
509 ##############
509 debug_style = true
510 debug_style = true
510
511
511 ###########################################
512 ###########################################
512 ### MAIN RHODECODE DATABASE CONFIG ###
513 ### MAIN RHODECODE DATABASE CONFIG ###
513 ###########################################
514 ###########################################
514 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
515 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
515 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
516 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
516 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
517 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
517 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
518 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
518
519
519 # see sqlalchemy docs for other advanced settings
520 # see sqlalchemy docs for other advanced settings
520
521
521 ## print the sql statements to output
522 ## print the sql statements to output
522 sqlalchemy.db1.echo = false
523 sqlalchemy.db1.echo = false
523 ## recycle the connections after this amount of seconds
524 ## recycle the connections after this amount of seconds
524 sqlalchemy.db1.pool_recycle = 3600
525 sqlalchemy.db1.pool_recycle = 3600
525 sqlalchemy.db1.convert_unicode = true
526 sqlalchemy.db1.convert_unicode = true
526
527
527 ## the number of connections to keep open inside the connection pool.
528 ## the number of connections to keep open inside the connection pool.
528 ## 0 indicates no limit
529 ## 0 indicates no limit
529 #sqlalchemy.db1.pool_size = 5
530 #sqlalchemy.db1.pool_size = 5
530
531
531 ## the number of connections to allow in connection pool "overflow", that is
532 ## the number of connections to allow in connection pool "overflow", that is
532 ## connections that can be opened above and beyond the pool_size setting,
533 ## connections that can be opened above and beyond the pool_size setting,
533 ## which defaults to five.
534 ## which defaults to five.
534 #sqlalchemy.db1.max_overflow = 10
535 #sqlalchemy.db1.max_overflow = 10
535
536
536
537
537 ##################
538 ##################
538 ### VCS CONFIG ###
539 ### VCS CONFIG ###
539 ##################
540 ##################
540 vcs.server.enable = true
541 vcs.server.enable = true
541 vcs.server = localhost:9900
542 vcs.server = localhost:9900
542
543
543 ## Web server connectivity protocol, responsible for web based VCS operatations
544 ## Web server connectivity protocol, responsible for web based VCS operatations
544 ## Available protocols are:
545 ## Available protocols are:
545 ## `http` - use http-rpc backend (default)
546 ## `http` - use http-rpc backend (default)
546 vcs.server.protocol = http
547 vcs.server.protocol = http
547
548
548 ## Push/Pull operations protocol, available options are:
549 ## Push/Pull operations protocol, available options are:
549 ## `http` - use http-rpc backend (default)
550 ## `http` - use http-rpc backend (default)
550 ##
551 ##
551 vcs.scm_app_implementation = http
552 vcs.scm_app_implementation = http
552
553
553 ## Push/Pull operations hooks protocol, available options are:
554 ## Push/Pull operations hooks protocol, available options are:
554 ## `http` - use http-rpc backend (default)
555 ## `http` - use http-rpc backend (default)
555 vcs.hooks.protocol = http
556 vcs.hooks.protocol = http
556
557
557 vcs.server.log_level = debug
558 vcs.server.log_level = debug
558 ## Start VCSServer with this instance as a subprocess, usefull for development
559 ## Start VCSServer with this instance as a subprocess, usefull for development
559 vcs.start_server = false
560 vcs.start_server = false
560
561
561 ## List of enabled VCS backends, available options are:
562 ## List of enabled VCS backends, available options are:
562 ## `hg` - mercurial
563 ## `hg` - mercurial
563 ## `git` - git
564 ## `git` - git
564 ## `svn` - subversion
565 ## `svn` - subversion
565 vcs.backends = hg, git, svn
566 vcs.backends = hg, git, svn
566
567
567 vcs.connection_timeout = 3600
568 vcs.connection_timeout = 3600
568 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
569 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
569 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
570 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
570 #vcs.svn.compatible_version = pre-1.8-compatible
571 #vcs.svn.compatible_version = pre-1.8-compatible
571
572
572
573
573 ############################################################
574 ############################################################
574 ### Subversion proxy support (mod_dav_svn) ###
575 ### Subversion proxy support (mod_dav_svn) ###
575 ### Maps RhodeCode repo groups into SVN paths for Apache ###
576 ### Maps RhodeCode repo groups into SVN paths for Apache ###
576 ############################################################
577 ############################################################
577 ## Enable or disable the config file generation.
578 ## Enable or disable the config file generation.
578 svn.proxy.generate_config = false
579 svn.proxy.generate_config = false
579 ## Generate config file with `SVNListParentPath` set to `On`.
580 ## Generate config file with `SVNListParentPath` set to `On`.
580 svn.proxy.list_parent_path = true
581 svn.proxy.list_parent_path = true
581 ## Set location and file name of generated config file.
582 ## Set location and file name of generated config file.
582 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
583 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
583 ## alternative mod_dav config template. This needs to be a mako template
584 ## alternative mod_dav config template. This needs to be a mako template
584 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
585 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
585 ## Used as a prefix to the `Location` block in the generated config file.
586 ## Used as a prefix to the `Location` block in the generated config file.
586 ## In most cases it should be set to `/`.
587 ## In most cases it should be set to `/`.
587 svn.proxy.location_root = /
588 svn.proxy.location_root = /
588 ## Command to reload the mod dav svn configuration on change.
589 ## Command to reload the mod dav svn configuration on change.
589 ## Example: `/etc/init.d/apache2 reload`
590 ## Example: `/etc/init.d/apache2 reload`
590 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
591 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
591 ## If the timeout expires before the reload command finishes, the command will
592 ## If the timeout expires before the reload command finishes, the command will
592 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
593 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
593 #svn.proxy.reload_timeout = 10
594 #svn.proxy.reload_timeout = 10
594
595
595 ############################################################
596 ############################################################
596 ### SSH Support Settings ###
597 ### SSH Support Settings ###
597 ############################################################
598 ############################################################
598
599
599 ## Defines if a custom authorized_keys file should be created and written on
600 ## Defines if a custom authorized_keys file should be created and written on
600 ## any change user ssh keys. Setting this to false also disables posibility
601 ## any change user ssh keys. Setting this to false also disables posibility
601 ## of adding SSH keys by users from web interface. Super admins can still
602 ## of adding SSH keys by users from web interface. Super admins can still
602 ## manage SSH Keys.
603 ## manage SSH Keys.
603 ssh.generate_authorized_keyfile = false
604 ssh.generate_authorized_keyfile = false
604
605
605 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
606 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
606 # ssh.authorized_keys_ssh_opts =
607 # ssh.authorized_keys_ssh_opts =
607
608
608 ## Path to the authrozied_keys file where the generate entries are placed.
609 ## Path to the authrozied_keys file where the generate entries are placed.
609 ## It is possible to have multiple key files specified in `sshd_config` e.g.
610 ## It is possible to have multiple key files specified in `sshd_config` e.g.
610 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
611 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
611 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
612 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
612
613
613 ## Command to execute the SSH wrapper. The binary is available in the
614 ## Command to execute the SSH wrapper. The binary is available in the
614 ## rhodecode installation directory.
615 ## rhodecode installation directory.
615 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
616 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
616 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
617 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
617
618
618 ## Allow shell when executing the ssh-wrapper command
619 ## Allow shell when executing the ssh-wrapper command
619 ssh.wrapper_cmd_allow_shell = false
620 ssh.wrapper_cmd_allow_shell = false
620
621
621 ## Enables logging, and detailed output send back to the client during SSH
622 ## Enables logging, and detailed output send back to the client during SSH
622 ## operations. Usefull for debugging, shouldn't be used in production.
623 ## operations. Usefull for debugging, shouldn't be used in production.
623 ssh.enable_debug_logging = true
624 ssh.enable_debug_logging = true
624
625
625 ## Paths to binary executable, by default they are the names, but we can
626 ## Paths to binary executable, by default they are the names, but we can
626 ## override them if we want to use a custom one
627 ## override them if we want to use a custom one
627 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
628 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
628 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
629 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
629 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
630 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
630
631
631
632
632 ## Dummy marker to add new entries after.
633 ## Dummy marker to add new entries after.
633 ## Add any custom entries below. Please don't remove.
634 ## Add any custom entries below. Please don't remove.
634 custom.conf = 1
635 custom.conf = 1
635
636
636
637
637 ################################
638 ################################
638 ### LOGGING CONFIGURATION ####
639 ### LOGGING CONFIGURATION ####
639 ################################
640 ################################
640 [loggers]
641 [loggers]
641 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
642 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
642
643
643 [handlers]
644 [handlers]
644 keys = console, console_sql
645 keys = console, console_sql
645
646
646 [formatters]
647 [formatters]
647 keys = generic, color_formatter, color_formatter_sql
648 keys = generic, color_formatter, color_formatter_sql
648
649
649 #############
650 #############
650 ## LOGGERS ##
651 ## LOGGERS ##
651 #############
652 #############
652 [logger_root]
653 [logger_root]
653 level = NOTSET
654 level = NOTSET
654 handlers = console
655 handlers = console
655
656
656 [logger_sqlalchemy]
657 [logger_sqlalchemy]
657 level = INFO
658 level = INFO
658 handlers = console_sql
659 handlers = console_sql
659 qualname = sqlalchemy.engine
660 qualname = sqlalchemy.engine
660 propagate = 0
661 propagate = 0
661
662
662 [logger_beaker]
663 [logger_beaker]
663 level = DEBUG
664 level = DEBUG
664 handlers =
665 handlers =
665 qualname = beaker.container
666 qualname = beaker.container
666 propagate = 1
667 propagate = 1
667
668
668 [logger_rhodecode]
669 [logger_rhodecode]
669 level = DEBUG
670 level = DEBUG
670 handlers =
671 handlers =
671 qualname = rhodecode
672 qualname = rhodecode
672 propagate = 1
673 propagate = 1
673
674
674 [logger_ssh_wrapper]
675 [logger_ssh_wrapper]
675 level = DEBUG
676 level = DEBUG
676 handlers =
677 handlers =
677 qualname = ssh_wrapper
678 qualname = ssh_wrapper
678 propagate = 1
679 propagate = 1
679
680
680 [logger_celery]
681 [logger_celery]
681 level = DEBUG
682 level = DEBUG
682 handlers =
683 handlers =
683 qualname = celery
684 qualname = celery
684
685
685
686
686 ##############
687 ##############
687 ## HANDLERS ##
688 ## HANDLERS ##
688 ##############
689 ##############
689
690
690 [handler_console]
691 [handler_console]
691 class = StreamHandler
692 class = StreamHandler
692 args = (sys.stderr, )
693 args = (sys.stderr, )
693 level = DEBUG
694 level = DEBUG
694 formatter = color_formatter
695 formatter = color_formatter
695
696
696 [handler_console_sql]
697 [handler_console_sql]
697 class = StreamHandler
698 class = StreamHandler
698 args = (sys.stderr, )
699 args = (sys.stderr, )
699 level = DEBUG
700 level = DEBUG
700 formatter = color_formatter_sql
701 formatter = color_formatter_sql
701
702
702 ################
703 ################
703 ## FORMATTERS ##
704 ## FORMATTERS ##
704 ################
705 ################
705
706
706 [formatter_generic]
707 [formatter_generic]
707 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
708 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
708 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
709 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
709 datefmt = %Y-%m-%d %H:%M:%S
710 datefmt = %Y-%m-%d %H:%M:%S
710
711
711 [formatter_color_formatter]
712 [formatter_color_formatter]
712 class = rhodecode.lib.logging_formatter.ColorFormatter
713 class = rhodecode.lib.logging_formatter.ColorFormatter
713 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
714 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
714 datefmt = %Y-%m-%d %H:%M:%S
715 datefmt = %Y-%m-%d %H:%M:%S
715
716
716 [formatter_color_formatter_sql]
717 [formatter_color_formatter_sql]
717 class = rhodecode.lib.logging_formatter.ColorFormatterSql
718 class = rhodecode.lib.logging_formatter.ColorFormatterSql
718 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
719 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
719 datefmt = %Y-%m-%d %H:%M:%S
720 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,689 +1,690 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 #use = egg:waitress#main
54 #use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 #threads = 5
56 #threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 #max_request_body_size = 107374182400
58 #max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 #asyncore_use_poll = true
61 #asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 use = egg:gunicorn#main
69 use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 workers = 2
74 workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
76 ## generally recommended to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 proc_name = rhodecode
79 proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 worker_class = gevent
82 worker_class = gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 max_requests = 1000
87 max_requests = 1000
88 max_requests_jitter = 30
88 max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 timeout = 21600
91 timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 ## encryption key used to encrypt social plugin tokens,
111 ## encryption key used to encrypt social plugin tokens,
112 ## remote_urls with credentials etc, if not set it defaults to
112 ## remote_urls with credentials etc, if not set it defaults to
113 ## `beaker.session.secret`
113 ## `beaker.session.secret`
114 #rhodecode.encrypted_values.secret =
114 #rhodecode.encrypted_values.secret =
115
115
116 ## decryption strict mode (enabled by default). It controls if decryption raises
116 ## decryption strict mode (enabled by default). It controls if decryption raises
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
118 #rhodecode.encrypted_values.strict = false
118 #rhodecode.encrypted_values.strict = false
119
119
120 ## return gzipped responses from Rhodecode (static files/application)
120 ## return gzipped responses from Rhodecode (static files/application)
121 gzip_responses = false
121 gzip_responses = false
122
122
123 ## autogenerate javascript routes file on startup
123 ## autogenerate javascript routes file on startup
124 generate_js_files = false
124 generate_js_files = false
125
125
126 ## Optional Languages
126 ## Optional Languages
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
128 lang = en
128 lang = en
129
129
130 ## perform a full repository scan on each server start, this should be
130 ## perform a full repository scan on each server start, this should be
131 ## set to false after first startup, to allow faster server restarts.
131 ## set to false after first startup, to allow faster server restarts.
132 startup.import_repos = false
132 startup.import_repos = false
133
133
134 ## Uncomment and set this path to use archive download cache.
134 ## Uncomment and set this path to use archive download cache.
135 ## Once enabled, generated archives will be cached at this location
135 ## Once enabled, generated archives will be cached at this location
136 ## and served from the cache during subsequent requests for the same archive of
136 ## and served from the cache during subsequent requests for the same archive of
137 ## the repository.
137 ## the repository.
138 #archive_cache_dir = /tmp/tarballcache
138 #archive_cache_dir = /tmp/tarballcache
139
139
140 ## URL at which the application is running. This is used for bootstraping
140 ## URL at which the application is running. This is used for bootstraping
141 ## requests in context when no web request is available. Used in ishell, or
141 ## requests in context when no web request is available. Used in ishell, or
142 ## SSH calls. Set this for events to receive proper url for SSH calls.
142 ## SSH calls. Set this for events to receive proper url for SSH calls.
143 app.base_url = http://rhodecode.local
143 app.base_url = http://rhodecode.local
144
144
145 ## change this to unique ID for security
145 ## change this to unique ID for security
146 app_instance_uuid = rc-production
146 app_instance_uuid = rc-production
147
147
148 ## cut off limit for large diffs (size in bytes). If overall diff size on
148 ## cut off limit for large diffs (size in bytes). If overall diff size on
149 ## commit, or pull request exceeds this limit this diff will be displayed
149 ## commit, or pull request exceeds this limit this diff will be displayed
150 ## partially. E.g 512000 == 512Kb
150 ## partially. E.g 512000 == 512Kb
151 cut_off_limit_diff = 512000
151 cut_off_limit_diff = 512000
152
152
153 ## cut off limit for large files inside diffs (size in bytes). Each individual
153 ## cut off limit for large files inside diffs (size in bytes). Each individual
154 ## file inside diff which exceeds this limit will be displayed partially.
154 ## file inside diff which exceeds this limit will be displayed partially.
155 ## E.g 128000 == 128Kb
155 ## E.g 128000 == 128Kb
156 cut_off_limit_file = 128000
156 cut_off_limit_file = 128000
157
157
158 ## use cache version of scm repo everywhere
158 ## use cache version of scm repo everywhere
159 vcs_full_cache = true
159 vcs_full_cache = true
160
160
161 ## force https in RhodeCode, fixes https redirects, assumes it's always https
161 ## force https in RhodeCode, fixes https redirects, assumes it's always https
162 ## Normally this is controlled by proper http flags sent from http server
162 ## Normally this is controlled by proper http flags sent from http server
163 force_https = false
163 force_https = false
164
164
165 ## use Strict-Transport-Security headers
165 ## use Strict-Transport-Security headers
166 use_htsts = false
166 use_htsts = false
167
167
168 ## git rev filter option, --all is the default filter, if you need to
168 ## git rev filter option, --all is the default filter, if you need to
169 ## hide all refs in changelog switch this to --branches --tags
169 ## hide all refs in changelog switch this to --branches --tags
170 git_rev_filter = --branches --tags
170 git_rev_filter = --branches --tags
171
171
172 # Set to true if your repos are exposed using the dumb protocol
172 # Set to true if your repos are exposed using the dumb protocol
173 git_update_server_info = false
173 git_update_server_info = false
174
174
175 ## RSS/ATOM feed options
175 ## RSS/ATOM feed options
176 rss_cut_off_limit = 256000
176 rss_cut_off_limit = 256000
177 rss_items_per_page = 10
177 rss_items_per_page = 10
178 rss_include_diff = false
178 rss_include_diff = false
179
179
180 ## gist URL alias, used to create nicer urls for gist. This should be an
180 ## gist URL alias, used to create nicer urls for gist. This should be an
181 ## url that does rewrites to _admin/gists/{gistid}.
181 ## url that does rewrites to _admin/gists/{gistid}.
182 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
182 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
183 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
183 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
184 gist_alias_url =
184 gist_alias_url =
185
185
186 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
186 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
187 ## used for access.
187 ## used for access.
188 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
188 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
189 ## came from the the logged in user who own this authentication token.
189 ## came from the the logged in user who own this authentication token.
190 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
190 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
191 ## authentication token. Such view would be only accessible when used together
191 ## authentication token. Such view would be only accessible when used together
192 ## with this authentication token
192 ## with this authentication token
193 ##
193 ##
194 ## list of all views can be found under `/_admin/permissions/auth_token_access`
194 ## list of all views can be found under `/_admin/permissions/auth_token_access`
195 ## The list should be "," separated and on a single line.
195 ## The list should be "," separated and on a single line.
196 ##
196 ##
197 ## Most common views to enable:
197 ## Most common views to enable:
198 # RepoCommitsView:repo_commit_download
198 # RepoCommitsView:repo_commit_download
199 # RepoCommitsView:repo_commit_patch
199 # RepoCommitsView:repo_commit_patch
200 # RepoCommitsView:repo_commit_raw
200 # RepoCommitsView:repo_commit_raw
201 # RepoCommitsView:repo_commit_raw@TOKEN
201 # RepoCommitsView:repo_commit_raw@TOKEN
202 # RepoFilesView:repo_files_diff
202 # RepoFilesView:repo_files_diff
203 # RepoFilesView:repo_archivefile
203 # RepoFilesView:repo_archivefile
204 # RepoFilesView:repo_file_raw
204 # RepoFilesView:repo_file_raw
205 # GistView:*
205 # GistView:*
206 api_access_controllers_whitelist =
206 api_access_controllers_whitelist =
207
207
208 ## default encoding used to convert from and to unicode
208 ## default encoding used to convert from and to unicode
209 ## can be also a comma separated list of encoding in case of mixed encodings
209 ## can be also a comma separated list of encoding in case of mixed encodings
210 default_encoding = UTF-8
210 default_encoding = UTF-8
211
211
212 ## instance-id prefix
212 ## instance-id prefix
213 ## a prefix key for this instance used for cache invalidation when running
213 ## a prefix key for this instance used for cache invalidation when running
214 ## multiple instances of rhodecode, make sure it's globally unique for
214 ## multiple instances of rhodecode, make sure it's globally unique for
215 ## all running rhodecode instances. Leave empty if you don't use it
215 ## all running rhodecode instances. Leave empty if you don't use it
216 instance_id =
216 instance_id =
217
217
218 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
218 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
219 ## of an authentication plugin also if it is disabled by it's settings.
219 ## of an authentication plugin also if it is disabled by it's settings.
220 ## This could be useful if you are unable to log in to the system due to broken
220 ## This could be useful if you are unable to log in to the system due to broken
221 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
221 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
222 ## module to log in again and fix the settings.
222 ## module to log in again and fix the settings.
223 ##
223 ##
224 ## Available builtin plugin IDs (hash is part of the ID):
224 ## Available builtin plugin IDs (hash is part of the ID):
225 ## egg:rhodecode-enterprise-ce#rhodecode
225 ## egg:rhodecode-enterprise-ce#rhodecode
226 ## egg:rhodecode-enterprise-ce#pam
226 ## egg:rhodecode-enterprise-ce#pam
227 ## egg:rhodecode-enterprise-ce#ldap
227 ## egg:rhodecode-enterprise-ce#ldap
228 ## egg:rhodecode-enterprise-ce#jasig_cas
228 ## egg:rhodecode-enterprise-ce#jasig_cas
229 ## egg:rhodecode-enterprise-ce#headers
229 ## egg:rhodecode-enterprise-ce#headers
230 ## egg:rhodecode-enterprise-ce#crowd
230 ## egg:rhodecode-enterprise-ce#crowd
231 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
231 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
232
232
233 ## alternative return HTTP header for failed authentication. Default HTTP
233 ## alternative return HTTP header for failed authentication. Default HTTP
234 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
234 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
235 ## handling that causing a series of failed authentication calls.
235 ## handling that causing a series of failed authentication calls.
236 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
236 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
237 ## This will be served instead of default 401 on bad authnetication
237 ## This will be served instead of default 401 on bad authnetication
238 auth_ret_code =
238 auth_ret_code =
239
239
240 ## use special detection method when serving auth_ret_code, instead of serving
240 ## use special detection method when serving auth_ret_code, instead of serving
241 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
241 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
242 ## and then serve auth_ret_code to clients
242 ## and then serve auth_ret_code to clients
243 auth_ret_code_detection = false
243 auth_ret_code_detection = false
244
244
245 ## locking return code. When repository is locked return this HTTP code. 2XX
245 ## locking return code. When repository is locked return this HTTP code. 2XX
246 ## codes don't break the transactions while 4XX codes do
246 ## codes don't break the transactions while 4XX codes do
247 lock_ret_code = 423
247 lock_ret_code = 423
248
248
249 ## allows to change the repository location in settings page
249 ## allows to change the repository location in settings page
250 allow_repo_location_change = true
250 allow_repo_location_change = true
251
251
252 ## allows to setup custom hooks in settings page
252 ## allows to setup custom hooks in settings page
253 allow_custom_hooks_settings = true
253 allow_custom_hooks_settings = true
254
254
255 ## generated license token, goto license page in RhodeCode settings to obtain
255 ## generated license token, goto license page in RhodeCode settings to obtain
256 ## new token
256 ## new token
257 license_token =
257 license_token =
258
258
259 ## supervisor connection uri, for managing supervisor and logs.
259 ## supervisor connection uri, for managing supervisor and logs.
260 supervisor.uri =
260 supervisor.uri =
261 ## supervisord group name/id we only want this RC instance to handle
261 ## supervisord group name/id we only want this RC instance to handle
262 supervisor.group_id = prod
262 supervisor.group_id = prod
263
263
264 ## Display extended labs settings
264 ## Display extended labs settings
265 labs_settings_active = true
265 labs_settings_active = true
266
266
267 ####################################
267 ####################################
268 ### CELERY CONFIG ####
268 ### CELERY CONFIG ####
269 ####################################
269 ####################################
270 ## run: /path/to/celery worker \
270 ## run: /path/to/celery worker \
271 ## -E --beat --app rhodecode.lib.celerylib.loader \
271 ## -E --beat --app rhodecode.lib.celerylib.loader \
272 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
272 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
273 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
273 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
274
274
275 use_celery = false
275 use_celery = false
276
276
277 ## connection url to the message broker (default rabbitmq)
277 ## connection url to the message broker (default rabbitmq)
278 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
278 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
279
279
280 ## maximum tasks to execute before worker restart
280 ## maximum tasks to execute before worker restart
281 celery.max_tasks_per_child = 100
281 celery.max_tasks_per_child = 100
282
282
283 ## tasks will never be sent to the queue, but executed locally instead.
283 ## tasks will never be sent to the queue, but executed locally instead.
284 celery.task_always_eager = false
284 celery.task_always_eager = false
285
285
286 ####################################
286 ####################################
287 ### BEAKER CACHE ####
287 ### BEAKER CACHE ####
288 ####################################
288 ####################################
289 # default cache dir for templates. Putting this into a ramdisk
289 # default cache dir for templates. Putting this into a ramdisk
290 ## can boost performance, eg. %(here)s/data_ramdisk
290 ## can boost performance, eg. %(here)s/data_ramdisk
291 cache_dir = %(here)s/data
291 cache_dir = %(here)s/data
292
292
293 ## locking and default file storage for Beaker. Putting this into a ramdisk
293 ## locking and default file storage for Beaker. Putting this into a ramdisk
294 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
294 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
295 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
295 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
296 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
296 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
297
297
298 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
298 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
299
299
300 beaker.cache.super_short_term.type = memory
300 beaker.cache.super_short_term.type = memory
301 beaker.cache.super_short_term.expire = 10
301 beaker.cache.super_short_term.expire = 10
302 beaker.cache.super_short_term.key_length = 256
302 beaker.cache.super_short_term.key_length = 256
303
303
304 beaker.cache.short_term.type = memory
304 # used for caching user permissions
305 beaker.cache.short_term.expire = 60
305 beaker.cache.short_term.type = file
306 beaker.cache.short_term.expire = 0
306 beaker.cache.short_term.key_length = 256
307 beaker.cache.short_term.key_length = 256
307
308
308 beaker.cache.long_term.type = memory
309 beaker.cache.long_term.type = memory
309 beaker.cache.long_term.expire = 36000
310 beaker.cache.long_term.expire = 36000
310 beaker.cache.long_term.key_length = 256
311 beaker.cache.long_term.key_length = 256
311
312
312 beaker.cache.sql_cache_short.type = memory
313 beaker.cache.sql_cache_short.type = memory
313 beaker.cache.sql_cache_short.expire = 10
314 beaker.cache.sql_cache_short.expire = 10
314 beaker.cache.sql_cache_short.key_length = 256
315 beaker.cache.sql_cache_short.key_length = 256
315
316
316 ## default is memory cache, configure only if required
317 ## default is memory cache, configure only if required
317 ## using multi-node or multi-worker setup
318 ## using multi-node or multi-worker setup
318 #beaker.cache.auth_plugins.type = ext:database
319 #beaker.cache.auth_plugins.type = ext:database
319 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
320 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
320 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
321 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
321 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
322 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
322 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
323 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
323 #beaker.cache.auth_plugins.sa.pool_size = 10
324 #beaker.cache.auth_plugins.sa.pool_size = 10
324 #beaker.cache.auth_plugins.sa.max_overflow = 0
325 #beaker.cache.auth_plugins.sa.max_overflow = 0
325
326
326 beaker.cache.repo_cache_long.type = memorylru_base
327 beaker.cache.repo_cache_long.type = memorylru_base
327 beaker.cache.repo_cache_long.max_items = 4096
328 beaker.cache.repo_cache_long.max_items = 4096
328 beaker.cache.repo_cache_long.expire = 2592000
329 beaker.cache.repo_cache_long.expire = 2592000
329
330
330 ## default is memorylru_base cache, configure only if required
331 ## default is memorylru_base cache, configure only if required
331 ## using multi-node or multi-worker setup
332 ## using multi-node or multi-worker setup
332 #beaker.cache.repo_cache_long.type = ext:memcached
333 #beaker.cache.repo_cache_long.type = ext:memcached
333 #beaker.cache.repo_cache_long.url = localhost:11211
334 #beaker.cache.repo_cache_long.url = localhost:11211
334 #beaker.cache.repo_cache_long.expire = 1209600
335 #beaker.cache.repo_cache_long.expire = 1209600
335 #beaker.cache.repo_cache_long.key_length = 256
336 #beaker.cache.repo_cache_long.key_length = 256
336
337
337 ####################################
338 ####################################
338 ### BEAKER SESSION ####
339 ### BEAKER SESSION ####
339 ####################################
340 ####################################
340
341
341 ## .session.type is type of storage options for the session, current allowed
342 ## .session.type is type of storage options for the session, current allowed
342 ## types are file, ext:memcached, ext:database, and memory (default).
343 ## types are file, ext:memcached, ext:database, and memory (default).
343 beaker.session.type = file
344 beaker.session.type = file
344 beaker.session.data_dir = %(here)s/data/sessions/data
345 beaker.session.data_dir = %(here)s/data/sessions/data
345
346
346 ## db based session, fast, and allows easy management over logged in users
347 ## db based session, fast, and allows easy management over logged in users
347 #beaker.session.type = ext:database
348 #beaker.session.type = ext:database
348 #beaker.session.table_name = db_session
349 #beaker.session.table_name = db_session
349 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
350 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
350 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
351 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
351 #beaker.session.sa.pool_recycle = 3600
352 #beaker.session.sa.pool_recycle = 3600
352 #beaker.session.sa.echo = false
353 #beaker.session.sa.echo = false
353
354
354 beaker.session.key = rhodecode
355 beaker.session.key = rhodecode
355 beaker.session.secret = production-rc-uytcxaz
356 beaker.session.secret = production-rc-uytcxaz
356 beaker.session.lock_dir = %(here)s/data/sessions/lock
357 beaker.session.lock_dir = %(here)s/data/sessions/lock
357
358
358 ## Secure encrypted cookie. Requires AES and AES python libraries
359 ## Secure encrypted cookie. Requires AES and AES python libraries
359 ## you must disable beaker.session.secret to use this
360 ## you must disable beaker.session.secret to use this
360 #beaker.session.encrypt_key = key_for_encryption
361 #beaker.session.encrypt_key = key_for_encryption
361 #beaker.session.validate_key = validation_key
362 #beaker.session.validate_key = validation_key
362
363
363 ## sets session as invalid(also logging out user) if it haven not been
364 ## sets session as invalid(also logging out user) if it haven not been
364 ## accessed for given amount of time in seconds
365 ## accessed for given amount of time in seconds
365 beaker.session.timeout = 2592000
366 beaker.session.timeout = 2592000
366 beaker.session.httponly = true
367 beaker.session.httponly = true
367 ## Path to use for the cookie. Set to prefix if you use prefix middleware
368 ## Path to use for the cookie. Set to prefix if you use prefix middleware
368 #beaker.session.cookie_path = /custom_prefix
369 #beaker.session.cookie_path = /custom_prefix
369
370
370 ## uncomment for https secure cookie
371 ## uncomment for https secure cookie
371 beaker.session.secure = false
372 beaker.session.secure = false
372
373
373 ## auto save the session to not to use .save()
374 ## auto save the session to not to use .save()
374 beaker.session.auto = false
375 beaker.session.auto = false
375
376
376 ## default cookie expiration time in seconds, set to `true` to set expire
377 ## default cookie expiration time in seconds, set to `true` to set expire
377 ## at browser close
378 ## at browser close
378 #beaker.session.cookie_expires = 3600
379 #beaker.session.cookie_expires = 3600
379
380
380 ###################################
381 ###################################
381 ## SEARCH INDEXING CONFIGURATION ##
382 ## SEARCH INDEXING CONFIGURATION ##
382 ###################################
383 ###################################
383 ## Full text search indexer is available in rhodecode-tools under
384 ## Full text search indexer is available in rhodecode-tools under
384 ## `rhodecode-tools index` command
385 ## `rhodecode-tools index` command
385
386
386 ## WHOOSH Backend, doesn't require additional services to run
387 ## WHOOSH Backend, doesn't require additional services to run
387 ## it works good with few dozen repos
388 ## it works good with few dozen repos
388 search.module = rhodecode.lib.index.whoosh
389 search.module = rhodecode.lib.index.whoosh
389 search.location = %(here)s/data/index
390 search.location = %(here)s/data/index
390
391
391 ########################################
392 ########################################
392 ### CHANNELSTREAM CONFIG ####
393 ### CHANNELSTREAM CONFIG ####
393 ########################################
394 ########################################
394 ## channelstream enables persistent connections and live notification
395 ## channelstream enables persistent connections and live notification
395 ## in the system. It's also used by the chat system
396 ## in the system. It's also used by the chat system
396 channelstream.enabled = false
397 channelstream.enabled = false
397
398
398 ## server address for channelstream server on the backend
399 ## server address for channelstream server on the backend
399 channelstream.server = 127.0.0.1:9800
400 channelstream.server = 127.0.0.1:9800
400
401
401 ## location of the channelstream server from outside world
402 ## location of the channelstream server from outside world
402 ## use ws:// for http or wss:// for https. This address needs to be handled
403 ## use ws:// for http or wss:// for https. This address needs to be handled
403 ## by external HTTP server such as Nginx or Apache
404 ## by external HTTP server such as Nginx or Apache
404 ## see nginx/apache configuration examples in our docs
405 ## see nginx/apache configuration examples in our docs
405 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
406 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
406 channelstream.secret = secret
407 channelstream.secret = secret
407 channelstream.history.location = %(here)s/channelstream_history
408 channelstream.history.location = %(here)s/channelstream_history
408
409
409 ## Internal application path that Javascript uses to connect into.
410 ## Internal application path that Javascript uses to connect into.
410 ## If you use proxy-prefix the prefix should be added before /_channelstream
411 ## If you use proxy-prefix the prefix should be added before /_channelstream
411 channelstream.proxy_path = /_channelstream
412 channelstream.proxy_path = /_channelstream
412
413
413
414
414 ###################################
415 ###################################
415 ## APPENLIGHT CONFIG ##
416 ## APPENLIGHT CONFIG ##
416 ###################################
417 ###################################
417
418
418 ## Appenlight is tailored to work with RhodeCode, see
419 ## Appenlight is tailored to work with RhodeCode, see
419 ## http://appenlight.com for details how to obtain an account
420 ## http://appenlight.com for details how to obtain an account
420
421
421 ## appenlight integration enabled
422 ## appenlight integration enabled
422 appenlight = false
423 appenlight = false
423
424
424 appenlight.server_url = https://api.appenlight.com
425 appenlight.server_url = https://api.appenlight.com
425 appenlight.api_key = YOUR_API_KEY
426 appenlight.api_key = YOUR_API_KEY
426 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
427 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
427
428
428 # used for JS client
429 # used for JS client
429 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
430 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
430
431
431 ## TWEAK AMOUNT OF INFO SENT HERE
432 ## TWEAK AMOUNT OF INFO SENT HERE
432
433
433 ## enables 404 error logging (default False)
434 ## enables 404 error logging (default False)
434 appenlight.report_404 = false
435 appenlight.report_404 = false
435
436
436 ## time in seconds after request is considered being slow (default 1)
437 ## time in seconds after request is considered being slow (default 1)
437 appenlight.slow_request_time = 1
438 appenlight.slow_request_time = 1
438
439
439 ## record slow requests in application
440 ## record slow requests in application
440 ## (needs to be enabled for slow datastore recording and time tracking)
441 ## (needs to be enabled for slow datastore recording and time tracking)
441 appenlight.slow_requests = true
442 appenlight.slow_requests = true
442
443
443 ## enable hooking to application loggers
444 ## enable hooking to application loggers
444 appenlight.logging = true
445 appenlight.logging = true
445
446
446 ## minimum log level for log capture
447 ## minimum log level for log capture
447 appenlight.logging.level = WARNING
448 appenlight.logging.level = WARNING
448
449
449 ## send logs only from erroneous/slow requests
450 ## send logs only from erroneous/slow requests
450 ## (saves API quota for intensive logging)
451 ## (saves API quota for intensive logging)
451 appenlight.logging_on_error = false
452 appenlight.logging_on_error = false
452
453
453 ## list of additonal keywords that should be grabbed from environ object
454 ## list of additonal keywords that should be grabbed from environ object
454 ## can be string with comma separated list of words in lowercase
455 ## can be string with comma separated list of words in lowercase
455 ## (by default client will always send following info:
456 ## (by default client will always send following info:
456 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
457 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
457 ## start with HTTP* this list be extended with additional keywords here
458 ## start with HTTP* this list be extended with additional keywords here
458 appenlight.environ_keys_whitelist =
459 appenlight.environ_keys_whitelist =
459
460
460 ## list of keywords that should be blanked from request object
461 ## list of keywords that should be blanked from request object
461 ## can be string with comma separated list of words in lowercase
462 ## can be string with comma separated list of words in lowercase
462 ## (by default client will always blank keys that contain following words
463 ## (by default client will always blank keys that contain following words
463 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
464 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
464 ## this list be extended with additional keywords set here
465 ## this list be extended with additional keywords set here
465 appenlight.request_keys_blacklist =
466 appenlight.request_keys_blacklist =
466
467
467 ## list of namespaces that should be ignores when gathering log entries
468 ## list of namespaces that should be ignores when gathering log entries
468 ## can be string with comma separated list of namespaces
469 ## can be string with comma separated list of namespaces
469 ## (by default the client ignores own entries: appenlight_client.client)
470 ## (by default the client ignores own entries: appenlight_client.client)
470 appenlight.log_namespace_blacklist =
471 appenlight.log_namespace_blacklist =
471
472
472
473
473 ################################################################################
474 ################################################################################
474 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
475 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
475 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
476 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
476 ## execute malicious code after an exception is raised. ##
477 ## execute malicious code after an exception is raised. ##
477 ################################################################################
478 ################################################################################
478 set debug = false
479 set debug = false
479
480
480
481
481 ###########################################
482 ###########################################
482 ### MAIN RHODECODE DATABASE CONFIG ###
483 ### MAIN RHODECODE DATABASE CONFIG ###
483 ###########################################
484 ###########################################
484 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
485 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
485 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
486 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
486 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
487 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
487 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
488 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
488
489
489 # see sqlalchemy docs for other advanced settings
490 # see sqlalchemy docs for other advanced settings
490
491
491 ## print the sql statements to output
492 ## print the sql statements to output
492 sqlalchemy.db1.echo = false
493 sqlalchemy.db1.echo = false
493 ## recycle the connections after this amount of seconds
494 ## recycle the connections after this amount of seconds
494 sqlalchemy.db1.pool_recycle = 3600
495 sqlalchemy.db1.pool_recycle = 3600
495 sqlalchemy.db1.convert_unicode = true
496 sqlalchemy.db1.convert_unicode = true
496
497
497 ## the number of connections to keep open inside the connection pool.
498 ## the number of connections to keep open inside the connection pool.
498 ## 0 indicates no limit
499 ## 0 indicates no limit
499 #sqlalchemy.db1.pool_size = 5
500 #sqlalchemy.db1.pool_size = 5
500
501
501 ## the number of connections to allow in connection pool "overflow", that is
502 ## the number of connections to allow in connection pool "overflow", that is
502 ## connections that can be opened above and beyond the pool_size setting,
503 ## connections that can be opened above and beyond the pool_size setting,
503 ## which defaults to five.
504 ## which defaults to five.
504 #sqlalchemy.db1.max_overflow = 10
505 #sqlalchemy.db1.max_overflow = 10
505
506
506
507
507 ##################
508 ##################
508 ### VCS CONFIG ###
509 ### VCS CONFIG ###
509 ##################
510 ##################
510 vcs.server.enable = true
511 vcs.server.enable = true
511 vcs.server = localhost:9900
512 vcs.server = localhost:9900
512
513
513 ## Web server connectivity protocol, responsible for web based VCS operatations
514 ## Web server connectivity protocol, responsible for web based VCS operatations
514 ## Available protocols are:
515 ## Available protocols are:
515 ## `http` - use http-rpc backend (default)
516 ## `http` - use http-rpc backend (default)
516 vcs.server.protocol = http
517 vcs.server.protocol = http
517
518
518 ## Push/Pull operations protocol, available options are:
519 ## Push/Pull operations protocol, available options are:
519 ## `http` - use http-rpc backend (default)
520 ## `http` - use http-rpc backend (default)
520 ##
521 ##
521 vcs.scm_app_implementation = http
522 vcs.scm_app_implementation = http
522
523
523 ## Push/Pull operations hooks protocol, available options are:
524 ## Push/Pull operations hooks protocol, available options are:
524 ## `http` - use http-rpc backend (default)
525 ## `http` - use http-rpc backend (default)
525 vcs.hooks.protocol = http
526 vcs.hooks.protocol = http
526
527
527 vcs.server.log_level = info
528 vcs.server.log_level = info
528 ## Start VCSServer with this instance as a subprocess, usefull for development
529 ## Start VCSServer with this instance as a subprocess, usefull for development
529 vcs.start_server = false
530 vcs.start_server = false
530
531
531 ## List of enabled VCS backends, available options are:
532 ## List of enabled VCS backends, available options are:
532 ## `hg` - mercurial
533 ## `hg` - mercurial
533 ## `git` - git
534 ## `git` - git
534 ## `svn` - subversion
535 ## `svn` - subversion
535 vcs.backends = hg, git, svn
536 vcs.backends = hg, git, svn
536
537
537 vcs.connection_timeout = 3600
538 vcs.connection_timeout = 3600
538 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
539 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
539 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
540 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
540 #vcs.svn.compatible_version = pre-1.8-compatible
541 #vcs.svn.compatible_version = pre-1.8-compatible
541
542
542
543
543 ############################################################
544 ############################################################
544 ### Subversion proxy support (mod_dav_svn) ###
545 ### Subversion proxy support (mod_dav_svn) ###
545 ### Maps RhodeCode repo groups into SVN paths for Apache ###
546 ### Maps RhodeCode repo groups into SVN paths for Apache ###
546 ############################################################
547 ############################################################
547 ## Enable or disable the config file generation.
548 ## Enable or disable the config file generation.
548 svn.proxy.generate_config = false
549 svn.proxy.generate_config = false
549 ## Generate config file with `SVNListParentPath` set to `On`.
550 ## Generate config file with `SVNListParentPath` set to `On`.
550 svn.proxy.list_parent_path = true
551 svn.proxy.list_parent_path = true
551 ## Set location and file name of generated config file.
552 ## Set location and file name of generated config file.
552 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
553 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
553 ## alternative mod_dav config template. This needs to be a mako template
554 ## alternative mod_dav config template. This needs to be a mako template
554 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
555 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
555 ## Used as a prefix to the `Location` block in the generated config file.
556 ## Used as a prefix to the `Location` block in the generated config file.
556 ## In most cases it should be set to `/`.
557 ## In most cases it should be set to `/`.
557 svn.proxy.location_root = /
558 svn.proxy.location_root = /
558 ## Command to reload the mod dav svn configuration on change.
559 ## Command to reload the mod dav svn configuration on change.
559 ## Example: `/etc/init.d/apache2 reload`
560 ## Example: `/etc/init.d/apache2 reload`
560 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
561 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
561 ## If the timeout expires before the reload command finishes, the command will
562 ## If the timeout expires before the reload command finishes, the command will
562 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
563 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
563 #svn.proxy.reload_timeout = 10
564 #svn.proxy.reload_timeout = 10
564
565
565 ############################################################
566 ############################################################
566 ### SSH Support Settings ###
567 ### SSH Support Settings ###
567 ############################################################
568 ############################################################
568
569
569 ## Defines if a custom authorized_keys file should be created and written on
570 ## Defines if a custom authorized_keys file should be created and written on
570 ## any change user ssh keys. Setting this to false also disables posibility
571 ## any change user ssh keys. Setting this to false also disables posibility
571 ## of adding SSH keys by users from web interface. Super admins can still
572 ## of adding SSH keys by users from web interface. Super admins can still
572 ## manage SSH Keys.
573 ## manage SSH Keys.
573 ssh.generate_authorized_keyfile = false
574 ssh.generate_authorized_keyfile = false
574
575
575 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
576 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
576 # ssh.authorized_keys_ssh_opts =
577 # ssh.authorized_keys_ssh_opts =
577
578
578 ## Path to the authrozied_keys file where the generate entries are placed.
579 ## Path to the authrozied_keys file where the generate entries are placed.
579 ## It is possible to have multiple key files specified in `sshd_config` e.g.
580 ## It is possible to have multiple key files specified in `sshd_config` e.g.
580 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
581 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
581 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
582 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
582
583
583 ## Command to execute the SSH wrapper. The binary is available in the
584 ## Command to execute the SSH wrapper. The binary is available in the
584 ## rhodecode installation directory.
585 ## rhodecode installation directory.
585 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
586 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
586 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
587 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
587
588
588 ## Allow shell when executing the ssh-wrapper command
589 ## Allow shell when executing the ssh-wrapper command
589 ssh.wrapper_cmd_allow_shell = false
590 ssh.wrapper_cmd_allow_shell = false
590
591
591 ## Enables logging, and detailed output send back to the client during SSH
592 ## Enables logging, and detailed output send back to the client during SSH
592 ## operations. Usefull for debugging, shouldn't be used in production.
593 ## operations. Usefull for debugging, shouldn't be used in production.
593 ssh.enable_debug_logging = false
594 ssh.enable_debug_logging = false
594
595
595 ## Paths to binary executable, by default they are the names, but we can
596 ## Paths to binary executable, by default they are the names, but we can
596 ## override them if we want to use a custom one
597 ## override them if we want to use a custom one
597 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
598 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
598 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
599 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
599 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
600 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
600
601
601
602
602 ## Dummy marker to add new entries after.
603 ## Dummy marker to add new entries after.
603 ## Add any custom entries below. Please don't remove.
604 ## Add any custom entries below. Please don't remove.
604 custom.conf = 1
605 custom.conf = 1
605
606
606
607
607 ################################
608 ################################
608 ### LOGGING CONFIGURATION ####
609 ### LOGGING CONFIGURATION ####
609 ################################
610 ################################
610 [loggers]
611 [loggers]
611 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
612 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
612
613
613 [handlers]
614 [handlers]
614 keys = console, console_sql
615 keys = console, console_sql
615
616
616 [formatters]
617 [formatters]
617 keys = generic, color_formatter, color_formatter_sql
618 keys = generic, color_formatter, color_formatter_sql
618
619
619 #############
620 #############
620 ## LOGGERS ##
621 ## LOGGERS ##
621 #############
622 #############
622 [logger_root]
623 [logger_root]
623 level = NOTSET
624 level = NOTSET
624 handlers = console
625 handlers = console
625
626
626 [logger_sqlalchemy]
627 [logger_sqlalchemy]
627 level = INFO
628 level = INFO
628 handlers = console_sql
629 handlers = console_sql
629 qualname = sqlalchemy.engine
630 qualname = sqlalchemy.engine
630 propagate = 0
631 propagate = 0
631
632
632 [logger_beaker]
633 [logger_beaker]
633 level = DEBUG
634 level = DEBUG
634 handlers =
635 handlers =
635 qualname = beaker.container
636 qualname = beaker.container
636 propagate = 1
637 propagate = 1
637
638
638 [logger_rhodecode]
639 [logger_rhodecode]
639 level = DEBUG
640 level = DEBUG
640 handlers =
641 handlers =
641 qualname = rhodecode
642 qualname = rhodecode
642 propagate = 1
643 propagate = 1
643
644
644 [logger_ssh_wrapper]
645 [logger_ssh_wrapper]
645 level = DEBUG
646 level = DEBUG
646 handlers =
647 handlers =
647 qualname = ssh_wrapper
648 qualname = ssh_wrapper
648 propagate = 1
649 propagate = 1
649
650
650 [logger_celery]
651 [logger_celery]
651 level = DEBUG
652 level = DEBUG
652 handlers =
653 handlers =
653 qualname = celery
654 qualname = celery
654
655
655
656
656 ##############
657 ##############
657 ## HANDLERS ##
658 ## HANDLERS ##
658 ##############
659 ##############
659
660
660 [handler_console]
661 [handler_console]
661 class = StreamHandler
662 class = StreamHandler
662 args = (sys.stderr, )
663 args = (sys.stderr, )
663 level = INFO
664 level = INFO
664 formatter = generic
665 formatter = generic
665
666
666 [handler_console_sql]
667 [handler_console_sql]
667 class = StreamHandler
668 class = StreamHandler
668 args = (sys.stderr, )
669 args = (sys.stderr, )
669 level = WARN
670 level = WARN
670 formatter = generic
671 formatter = generic
671
672
672 ################
673 ################
673 ## FORMATTERS ##
674 ## FORMATTERS ##
674 ################
675 ################
675
676
676 [formatter_generic]
677 [formatter_generic]
677 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
678 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
678 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
679 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
679 datefmt = %Y-%m-%d %H:%M:%S
680 datefmt = %Y-%m-%d %H:%M:%S
680
681
681 [formatter_color_formatter]
682 [formatter_color_formatter]
682 class = rhodecode.lib.logging_formatter.ColorFormatter
683 class = rhodecode.lib.logging_formatter.ColorFormatter
683 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
684 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
684 datefmt = %Y-%m-%d %H:%M:%S
685 datefmt = %Y-%m-%d %H:%M:%S
685
686
686 [formatter_color_formatter_sql]
687 [formatter_color_formatter_sql]
687 class = rhodecode.lib.logging_formatter.ColorFormatterSql
688 class = rhodecode.lib.logging_formatter.ColorFormatterSql
688 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
689 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
689 datefmt = %Y-%m-%d %H:%M:%S
690 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,2190 +1,2196 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 authentication and permission libraries
22 authentication and permission libraries
23 """
23 """
24
24
25 import os
25 import os
26 import inspect
26 import inspect
27 import collections
27 import collections
28 import fnmatch
28 import fnmatch
29 import hashlib
29 import hashlib
30 import itertools
30 import itertools
31 import logging
31 import logging
32 import random
32 import random
33 import traceback
33 import traceback
34 from functools import wraps
34 from functools import wraps
35
35
36 import ipaddress
36 import ipaddress
37
37
38 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
38 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
39 from sqlalchemy.orm.exc import ObjectDeletedError
39 from sqlalchemy.orm.exc import ObjectDeletedError
40 from sqlalchemy.orm import joinedload
40 from sqlalchemy.orm import joinedload
41 from zope.cachedescriptors.property import Lazy as LazyProperty
41 from zope.cachedescriptors.property import Lazy as LazyProperty
42
42
43 import rhodecode
43 import rhodecode
44 from rhodecode.model import meta
44 from rhodecode.model import meta
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.user import UserModel
46 from rhodecode.model.user import UserModel
47 from rhodecode.model.db import (
47 from rhodecode.model.db import (
48 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
48 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
49 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
49 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
50 from rhodecode.lib import caches
50 from rhodecode.lib import caches
51 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5
51 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int
52 from rhodecode.lib.utils import (
52 from rhodecode.lib.utils import (
53 get_repo_slug, get_repo_group_slug, get_user_group_slug)
53 get_repo_slug, get_repo_group_slug, get_user_group_slug)
54 from rhodecode.lib.caching_query import FromCache
54 from rhodecode.lib.caching_query import FromCache
55
55
56
56
57 if rhodecode.is_unix:
57 if rhodecode.is_unix:
58 import bcrypt
58 import bcrypt
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62 csrf_token_key = "csrf_token"
62 csrf_token_key = "csrf_token"
63
63
64
64
65 class PasswordGenerator(object):
65 class PasswordGenerator(object):
66 """
66 """
67 This is a simple class for generating password from different sets of
67 This is a simple class for generating password from different sets of
68 characters
68 characters
69 usage::
69 usage::
70
70
71 passwd_gen = PasswordGenerator()
71 passwd_gen = PasswordGenerator()
72 #print 8-letter password containing only big and small letters
72 #print 8-letter password containing only big and small letters
73 of alphabet
73 of alphabet
74 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
74 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
75 """
75 """
76 ALPHABETS_NUM = r'''1234567890'''
76 ALPHABETS_NUM = r'''1234567890'''
77 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
77 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
78 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
78 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
79 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
79 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
80 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
80 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
81 + ALPHABETS_NUM + ALPHABETS_SPECIAL
81 + ALPHABETS_NUM + ALPHABETS_SPECIAL
82 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
82 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
83 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
83 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
84 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
84 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
86
86
87 def __init__(self, passwd=''):
87 def __init__(self, passwd=''):
88 self.passwd = passwd
88 self.passwd = passwd
89
89
90 def gen_password(self, length, type_=None):
90 def gen_password(self, length, type_=None):
91 if type_ is None:
91 if type_ is None:
92 type_ = self.ALPHABETS_FULL
92 type_ = self.ALPHABETS_FULL
93 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
93 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
94 return self.passwd
94 return self.passwd
95
95
96
96
97 class _RhodeCodeCryptoBase(object):
97 class _RhodeCodeCryptoBase(object):
98 ENC_PREF = None
98 ENC_PREF = None
99
99
100 def hash_create(self, str_):
100 def hash_create(self, str_):
101 """
101 """
102 hash the string using
102 hash the string using
103
103
104 :param str_: password to hash
104 :param str_: password to hash
105 """
105 """
106 raise NotImplementedError
106 raise NotImplementedError
107
107
108 def hash_check_with_upgrade(self, password, hashed):
108 def hash_check_with_upgrade(self, password, hashed):
109 """
109 """
110 Returns tuple in which first element is boolean that states that
110 Returns tuple in which first element is boolean that states that
111 given password matches it's hashed version, and the second is new hash
111 given password matches it's hashed version, and the second is new hash
112 of the password, in case this password should be migrated to new
112 of the password, in case this password should be migrated to new
113 cipher.
113 cipher.
114 """
114 """
115 checked_hash = self.hash_check(password, hashed)
115 checked_hash = self.hash_check(password, hashed)
116 return checked_hash, None
116 return checked_hash, None
117
117
118 def hash_check(self, password, hashed):
118 def hash_check(self, password, hashed):
119 """
119 """
120 Checks matching password with it's hashed value.
120 Checks matching password with it's hashed value.
121
121
122 :param password: password
122 :param password: password
123 :param hashed: password in hashed form
123 :param hashed: password in hashed form
124 """
124 """
125 raise NotImplementedError
125 raise NotImplementedError
126
126
127 def _assert_bytes(self, value):
127 def _assert_bytes(self, value):
128 """
128 """
129 Passing in an `unicode` object can lead to hard to detect issues
129 Passing in an `unicode` object can lead to hard to detect issues
130 if passwords contain non-ascii characters. Doing a type check
130 if passwords contain non-ascii characters. Doing a type check
131 during runtime, so that such mistakes are detected early on.
131 during runtime, so that such mistakes are detected early on.
132 """
132 """
133 if not isinstance(value, str):
133 if not isinstance(value, str):
134 raise TypeError(
134 raise TypeError(
135 "Bytestring required as input, got %r." % (value, ))
135 "Bytestring required as input, got %r." % (value, ))
136
136
137
137
138 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
138 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
139 ENC_PREF = ('$2a$10', '$2b$10')
139 ENC_PREF = ('$2a$10', '$2b$10')
140
140
141 def hash_create(self, str_):
141 def hash_create(self, str_):
142 self._assert_bytes(str_)
142 self._assert_bytes(str_)
143 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
143 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
144
144
145 def hash_check_with_upgrade(self, password, hashed):
145 def hash_check_with_upgrade(self, password, hashed):
146 """
146 """
147 Returns tuple in which first element is boolean that states that
147 Returns tuple in which first element is boolean that states that
148 given password matches it's hashed version, and the second is new hash
148 given password matches it's hashed version, and the second is new hash
149 of the password, in case this password should be migrated to new
149 of the password, in case this password should be migrated to new
150 cipher.
150 cipher.
151
151
152 This implements special upgrade logic which works like that:
152 This implements special upgrade logic which works like that:
153 - check if the given password == bcrypted hash, if yes then we
153 - check if the given password == bcrypted hash, if yes then we
154 properly used password and it was already in bcrypt. Proceed
154 properly used password and it was already in bcrypt. Proceed
155 without any changes
155 without any changes
156 - if bcrypt hash check is not working try with sha256. If hash compare
156 - if bcrypt hash check is not working try with sha256. If hash compare
157 is ok, it means we using correct but old hashed password. indicate
157 is ok, it means we using correct but old hashed password. indicate
158 hash change and proceed
158 hash change and proceed
159 """
159 """
160
160
161 new_hash = None
161 new_hash = None
162
162
163 # regular pw check
163 # regular pw check
164 password_match_bcrypt = self.hash_check(password, hashed)
164 password_match_bcrypt = self.hash_check(password, hashed)
165
165
166 # now we want to know if the password was maybe from sha256
166 # now we want to know if the password was maybe from sha256
167 # basically calling _RhodeCodeCryptoSha256().hash_check()
167 # basically calling _RhodeCodeCryptoSha256().hash_check()
168 if not password_match_bcrypt:
168 if not password_match_bcrypt:
169 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
169 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
170 new_hash = self.hash_create(password) # make new bcrypt hash
170 new_hash = self.hash_create(password) # make new bcrypt hash
171 password_match_bcrypt = True
171 password_match_bcrypt = True
172
172
173 return password_match_bcrypt, new_hash
173 return password_match_bcrypt, new_hash
174
174
175 def hash_check(self, password, hashed):
175 def hash_check(self, password, hashed):
176 """
176 """
177 Checks matching password with it's hashed value.
177 Checks matching password with it's hashed value.
178
178
179 :param password: password
179 :param password: password
180 :param hashed: password in hashed form
180 :param hashed: password in hashed form
181 """
181 """
182 self._assert_bytes(password)
182 self._assert_bytes(password)
183 try:
183 try:
184 return bcrypt.hashpw(password, hashed) == hashed
184 return bcrypt.hashpw(password, hashed) == hashed
185 except ValueError as e:
185 except ValueError as e:
186 # we're having a invalid salt here probably, we should not crash
186 # we're having a invalid salt here probably, we should not crash
187 # just return with False as it would be a wrong password.
187 # just return with False as it would be a wrong password.
188 log.debug('Failed to check password hash using bcrypt %s',
188 log.debug('Failed to check password hash using bcrypt %s',
189 safe_str(e))
189 safe_str(e))
190
190
191 return False
191 return False
192
192
193
193
194 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
194 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
195 ENC_PREF = '_'
195 ENC_PREF = '_'
196
196
197 def hash_create(self, str_):
197 def hash_create(self, str_):
198 self._assert_bytes(str_)
198 self._assert_bytes(str_)
199 return hashlib.sha256(str_).hexdigest()
199 return hashlib.sha256(str_).hexdigest()
200
200
201 def hash_check(self, password, hashed):
201 def hash_check(self, password, hashed):
202 """
202 """
203 Checks matching password with it's hashed value.
203 Checks matching password with it's hashed value.
204
204
205 :param password: password
205 :param password: password
206 :param hashed: password in hashed form
206 :param hashed: password in hashed form
207 """
207 """
208 self._assert_bytes(password)
208 self._assert_bytes(password)
209 return hashlib.sha256(password).hexdigest() == hashed
209 return hashlib.sha256(password).hexdigest() == hashed
210
210
211
211
212 class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase):
212 class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase):
213 ENC_PREF = '_'
213 ENC_PREF = '_'
214
214
215 def hash_create(self, str_):
215 def hash_create(self, str_):
216 self._assert_bytes(str_)
216 self._assert_bytes(str_)
217 return hashlib.md5(str_).hexdigest()
217 return hashlib.md5(str_).hexdigest()
218
218
219 def hash_check(self, password, hashed):
219 def hash_check(self, password, hashed):
220 """
220 """
221 Checks matching password with it's hashed value.
221 Checks matching password with it's hashed value.
222
222
223 :param password: password
223 :param password: password
224 :param hashed: password in hashed form
224 :param hashed: password in hashed form
225 """
225 """
226 self._assert_bytes(password)
226 self._assert_bytes(password)
227 return hashlib.md5(password).hexdigest() == hashed
227 return hashlib.md5(password).hexdigest() == hashed
228
228
229
229
230 def crypto_backend():
230 def crypto_backend():
231 """
231 """
232 Return the matching crypto backend.
232 Return the matching crypto backend.
233
233
234 Selection is based on if we run tests or not, we pick md5 backend to run
234 Selection is based on if we run tests or not, we pick md5 backend to run
235 tests faster since BCRYPT is expensive to calculate
235 tests faster since BCRYPT is expensive to calculate
236 """
236 """
237 if rhodecode.is_test:
237 if rhodecode.is_test:
238 RhodeCodeCrypto = _RhodeCodeCryptoMd5()
238 RhodeCodeCrypto = _RhodeCodeCryptoMd5()
239 else:
239 else:
240 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
240 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
241
241
242 return RhodeCodeCrypto
242 return RhodeCodeCrypto
243
243
244
244
245 def get_crypt_password(password):
245 def get_crypt_password(password):
246 """
246 """
247 Create the hash of `password` with the active crypto backend.
247 Create the hash of `password` with the active crypto backend.
248
248
249 :param password: The cleartext password.
249 :param password: The cleartext password.
250 :type password: unicode
250 :type password: unicode
251 """
251 """
252 password = safe_str(password)
252 password = safe_str(password)
253 return crypto_backend().hash_create(password)
253 return crypto_backend().hash_create(password)
254
254
255
255
256 def check_password(password, hashed):
256 def check_password(password, hashed):
257 """
257 """
258 Check if the value in `password` matches the hash in `hashed`.
258 Check if the value in `password` matches the hash in `hashed`.
259
259
260 :param password: The cleartext password.
260 :param password: The cleartext password.
261 :type password: unicode
261 :type password: unicode
262
262
263 :param hashed: The expected hashed version of the password.
263 :param hashed: The expected hashed version of the password.
264 :type hashed: The hash has to be passed in in text representation.
264 :type hashed: The hash has to be passed in in text representation.
265 """
265 """
266 password = safe_str(password)
266 password = safe_str(password)
267 return crypto_backend().hash_check(password, hashed)
267 return crypto_backend().hash_check(password, hashed)
268
268
269
269
270 def generate_auth_token(data, salt=None):
270 def generate_auth_token(data, salt=None):
271 """
271 """
272 Generates API KEY from given string
272 Generates API KEY from given string
273 """
273 """
274
274
275 if salt is None:
275 if salt is None:
276 salt = os.urandom(16)
276 salt = os.urandom(16)
277 return hashlib.sha1(safe_str(data) + salt).hexdigest()
277 return hashlib.sha1(safe_str(data) + salt).hexdigest()
278
278
279
279
280 def get_came_from(request):
280 def get_came_from(request):
281 """
281 """
282 get query_string+path from request sanitized after removing auth_token
282 get query_string+path from request sanitized after removing auth_token
283 """
283 """
284 _req = request
284 _req = request
285
285
286 path = _req.path
286 path = _req.path
287 if 'auth_token' in _req.GET:
287 if 'auth_token' in _req.GET:
288 # sanitize the request and remove auth_token for redirection
288 # sanitize the request and remove auth_token for redirection
289 _req.GET.pop('auth_token')
289 _req.GET.pop('auth_token')
290 qs = _req.query_string
290 qs = _req.query_string
291 if qs:
291 if qs:
292 path += '?' + qs
292 path += '?' + qs
293
293
294 return path
294 return path
295
295
296
296
297 class CookieStoreWrapper(object):
297 class CookieStoreWrapper(object):
298
298
299 def __init__(self, cookie_store):
299 def __init__(self, cookie_store):
300 self.cookie_store = cookie_store
300 self.cookie_store = cookie_store
301
301
302 def __repr__(self):
302 def __repr__(self):
303 return 'CookieStore<%s>' % (self.cookie_store)
303 return 'CookieStore<%s>' % (self.cookie_store)
304
304
305 def get(self, key, other=None):
305 def get(self, key, other=None):
306 if isinstance(self.cookie_store, dict):
306 if isinstance(self.cookie_store, dict):
307 return self.cookie_store.get(key, other)
307 return self.cookie_store.get(key, other)
308 elif isinstance(self.cookie_store, AuthUser):
308 elif isinstance(self.cookie_store, AuthUser):
309 return self.cookie_store.__dict__.get(key, other)
309 return self.cookie_store.__dict__.get(key, other)
310
310
311
311
312 def _cached_perms_data(user_id, scope, user_is_admin,
312 def _cached_perms_data(user_id, scope, user_is_admin,
313 user_inherit_default_permissions, explicit, algo,
313 user_inherit_default_permissions, explicit, algo,
314 calculate_super_admin):
314 calculate_super_admin):
315
315
316 permissions = PermissionCalculator(
316 permissions = PermissionCalculator(
317 user_id, scope, user_is_admin, user_inherit_default_permissions,
317 user_id, scope, user_is_admin, user_inherit_default_permissions,
318 explicit, algo, calculate_super_admin)
318 explicit, algo, calculate_super_admin)
319 return permissions.calculate()
319 return permissions.calculate()
320
320
321
321
322 class PermOrigin(object):
322 class PermOrigin(object):
323 SUPER_ADMIN = 'superadmin'
323 SUPER_ADMIN = 'superadmin'
324
324
325 REPO_USER = 'user:%s'
325 REPO_USER = 'user:%s'
326 REPO_USERGROUP = 'usergroup:%s'
326 REPO_USERGROUP = 'usergroup:%s'
327 REPO_OWNER = 'repo.owner'
327 REPO_OWNER = 'repo.owner'
328 REPO_DEFAULT = 'repo.default'
328 REPO_DEFAULT = 'repo.default'
329 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
329 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
330 REPO_PRIVATE = 'repo.private'
330 REPO_PRIVATE = 'repo.private'
331
331
332 REPOGROUP_USER = 'user:%s'
332 REPOGROUP_USER = 'user:%s'
333 REPOGROUP_USERGROUP = 'usergroup:%s'
333 REPOGROUP_USERGROUP = 'usergroup:%s'
334 REPOGROUP_OWNER = 'group.owner'
334 REPOGROUP_OWNER = 'group.owner'
335 REPOGROUP_DEFAULT = 'group.default'
335 REPOGROUP_DEFAULT = 'group.default'
336 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
336 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
337
337
338 USERGROUP_USER = 'user:%s'
338 USERGROUP_USER = 'user:%s'
339 USERGROUP_USERGROUP = 'usergroup:%s'
339 USERGROUP_USERGROUP = 'usergroup:%s'
340 USERGROUP_OWNER = 'usergroup.owner'
340 USERGROUP_OWNER = 'usergroup.owner'
341 USERGROUP_DEFAULT = 'usergroup.default'
341 USERGROUP_DEFAULT = 'usergroup.default'
342 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
342 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
343
343
344
344
345 class PermOriginDict(dict):
345 class PermOriginDict(dict):
346 """
346 """
347 A special dict used for tracking permissions along with their origins.
347 A special dict used for tracking permissions along with their origins.
348
348
349 `__setitem__` has been overridden to expect a tuple(perm, origin)
349 `__setitem__` has been overridden to expect a tuple(perm, origin)
350 `__getitem__` will return only the perm
350 `__getitem__` will return only the perm
351 `.perm_origin_stack` will return the stack of (perm, origin) set per key
351 `.perm_origin_stack` will return the stack of (perm, origin) set per key
352
352
353 >>> perms = PermOriginDict()
353 >>> perms = PermOriginDict()
354 >>> perms['resource'] = 'read', 'default'
354 >>> perms['resource'] = 'read', 'default'
355 >>> perms['resource']
355 >>> perms['resource']
356 'read'
356 'read'
357 >>> perms['resource'] = 'write', 'admin'
357 >>> perms['resource'] = 'write', 'admin'
358 >>> perms['resource']
358 >>> perms['resource']
359 'write'
359 'write'
360 >>> perms.perm_origin_stack
360 >>> perms.perm_origin_stack
361 {'resource': [('read', 'default'), ('write', 'admin')]}
361 {'resource': [('read', 'default'), ('write', 'admin')]}
362 """
362 """
363
363
364 def __init__(self, *args, **kw):
364 def __init__(self, *args, **kw):
365 dict.__init__(self, *args, **kw)
365 dict.__init__(self, *args, **kw)
366 self.perm_origin_stack = collections.OrderedDict()
366 self.perm_origin_stack = collections.OrderedDict()
367
367
368 def __setitem__(self, key, (perm, origin)):
368 def __setitem__(self, key, (perm, origin)):
369 self.perm_origin_stack.setdefault(key, []).append((perm, origin))
369 self.perm_origin_stack.setdefault(key, []).append((perm, origin))
370 dict.__setitem__(self, key, perm)
370 dict.__setitem__(self, key, perm)
371
371
372
372
373 class PermissionCalculator(object):
373 class PermissionCalculator(object):
374
374
375 def __init__(
375 def __init__(
376 self, user_id, scope, user_is_admin,
376 self, user_id, scope, user_is_admin,
377 user_inherit_default_permissions, explicit, algo,
377 user_inherit_default_permissions, explicit, algo,
378 calculate_super_admin=False):
378 calculate_super_admin=False):
379
379
380 self.user_id = user_id
380 self.user_id = user_id
381 self.user_is_admin = user_is_admin
381 self.user_is_admin = user_is_admin
382 self.inherit_default_permissions = user_inherit_default_permissions
382 self.inherit_default_permissions = user_inherit_default_permissions
383 self.explicit = explicit
383 self.explicit = explicit
384 self.algo = algo
384 self.algo = algo
385 self.calculate_super_admin = calculate_super_admin
385 self.calculate_super_admin = calculate_super_admin
386
386
387 scope = scope or {}
387 scope = scope or {}
388 self.scope_repo_id = scope.get('repo_id')
388 self.scope_repo_id = scope.get('repo_id')
389 self.scope_repo_group_id = scope.get('repo_group_id')
389 self.scope_repo_group_id = scope.get('repo_group_id')
390 self.scope_user_group_id = scope.get('user_group_id')
390 self.scope_user_group_id = scope.get('user_group_id')
391
391
392 self.default_user_id = User.get_default_user(cache=True).user_id
392 self.default_user_id = User.get_default_user(cache=True).user_id
393
393
394 self.permissions_repositories = PermOriginDict()
394 self.permissions_repositories = PermOriginDict()
395 self.permissions_repository_groups = PermOriginDict()
395 self.permissions_repository_groups = PermOriginDict()
396 self.permissions_user_groups = PermOriginDict()
396 self.permissions_user_groups = PermOriginDict()
397 self.permissions_global = set()
397 self.permissions_global = set()
398
398
399 self.default_repo_perms = Permission.get_default_repo_perms(
399 self.default_repo_perms = Permission.get_default_repo_perms(
400 self.default_user_id, self.scope_repo_id)
400 self.default_user_id, self.scope_repo_id)
401 self.default_repo_groups_perms = Permission.get_default_group_perms(
401 self.default_repo_groups_perms = Permission.get_default_group_perms(
402 self.default_user_id, self.scope_repo_group_id)
402 self.default_user_id, self.scope_repo_group_id)
403 self.default_user_group_perms = \
403 self.default_user_group_perms = \
404 Permission.get_default_user_group_perms(
404 Permission.get_default_user_group_perms(
405 self.default_user_id, self.scope_user_group_id)
405 self.default_user_id, self.scope_user_group_id)
406
406
407 def calculate(self):
407 def calculate(self):
408 if self.user_is_admin and not self.calculate_super_admin:
408 if self.user_is_admin and not self.calculate_super_admin:
409 return self._admin_permissions()
409 return self._admin_permissions()
410
410
411 self._calculate_global_default_permissions()
411 self._calculate_global_default_permissions()
412 self._calculate_global_permissions()
412 self._calculate_global_permissions()
413 self._calculate_default_permissions()
413 self._calculate_default_permissions()
414 self._calculate_repository_permissions()
414 self._calculate_repository_permissions()
415 self._calculate_repository_group_permissions()
415 self._calculate_repository_group_permissions()
416 self._calculate_user_group_permissions()
416 self._calculate_user_group_permissions()
417 return self._permission_structure()
417 return self._permission_structure()
418
418
419 def _admin_permissions(self):
419 def _admin_permissions(self):
420 """
420 """
421 admin user have all default rights for repositories
421 admin user have all default rights for repositories
422 and groups set to admin
422 and groups set to admin
423 """
423 """
424 self.permissions_global.add('hg.admin')
424 self.permissions_global.add('hg.admin')
425 self.permissions_global.add('hg.create.write_on_repogroup.true')
425 self.permissions_global.add('hg.create.write_on_repogroup.true')
426
426
427 # repositories
427 # repositories
428 for perm in self.default_repo_perms:
428 for perm in self.default_repo_perms:
429 r_k = perm.UserRepoToPerm.repository.repo_name
429 r_k = perm.UserRepoToPerm.repository.repo_name
430 p = 'repository.admin'
430 p = 'repository.admin'
431 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN
431 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN
432
432
433 # repository groups
433 # repository groups
434 for perm in self.default_repo_groups_perms:
434 for perm in self.default_repo_groups_perms:
435 rg_k = perm.UserRepoGroupToPerm.group.group_name
435 rg_k = perm.UserRepoGroupToPerm.group.group_name
436 p = 'group.admin'
436 p = 'group.admin'
437 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN
437 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN
438
438
439 # user groups
439 # user groups
440 for perm in self.default_user_group_perms:
440 for perm in self.default_user_group_perms:
441 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
441 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
442 p = 'usergroup.admin'
442 p = 'usergroup.admin'
443 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
443 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
444
444
445 return self._permission_structure()
445 return self._permission_structure()
446
446
447 def _calculate_global_default_permissions(self):
447 def _calculate_global_default_permissions(self):
448 """
448 """
449 global permissions taken from the default user
449 global permissions taken from the default user
450 """
450 """
451 default_global_perms = UserToPerm.query()\
451 default_global_perms = UserToPerm.query()\
452 .filter(UserToPerm.user_id == self.default_user_id)\
452 .filter(UserToPerm.user_id == self.default_user_id)\
453 .options(joinedload(UserToPerm.permission))
453 .options(joinedload(UserToPerm.permission))
454
454
455 for perm in default_global_perms:
455 for perm in default_global_perms:
456 self.permissions_global.add(perm.permission.permission_name)
456 self.permissions_global.add(perm.permission.permission_name)
457
457
458 if self.user_is_admin:
458 if self.user_is_admin:
459 self.permissions_global.add('hg.admin')
459 self.permissions_global.add('hg.admin')
460 self.permissions_global.add('hg.create.write_on_repogroup.true')
460 self.permissions_global.add('hg.create.write_on_repogroup.true')
461
461
462 def _calculate_global_permissions(self):
462 def _calculate_global_permissions(self):
463 """
463 """
464 Set global system permissions with user permissions or permissions
464 Set global system permissions with user permissions or permissions
465 taken from the user groups of the current user.
465 taken from the user groups of the current user.
466
466
467 The permissions include repo creating, repo group creating, forking
467 The permissions include repo creating, repo group creating, forking
468 etc.
468 etc.
469 """
469 """
470
470
471 # now we read the defined permissions and overwrite what we have set
471 # now we read the defined permissions and overwrite what we have set
472 # before those can be configured from groups or users explicitly.
472 # before those can be configured from groups or users explicitly.
473
473
474 # TODO: johbo: This seems to be out of sync, find out the reason
474 # TODO: johbo: This seems to be out of sync, find out the reason
475 # for the comment below and update it.
475 # for the comment below and update it.
476
476
477 # In case we want to extend this list we should be always in sync with
477 # In case we want to extend this list we should be always in sync with
478 # User.DEFAULT_USER_PERMISSIONS definitions
478 # User.DEFAULT_USER_PERMISSIONS definitions
479 _configurable = frozenset([
479 _configurable = frozenset([
480 'hg.fork.none', 'hg.fork.repository',
480 'hg.fork.none', 'hg.fork.repository',
481 'hg.create.none', 'hg.create.repository',
481 'hg.create.none', 'hg.create.repository',
482 'hg.usergroup.create.false', 'hg.usergroup.create.true',
482 'hg.usergroup.create.false', 'hg.usergroup.create.true',
483 'hg.repogroup.create.false', 'hg.repogroup.create.true',
483 'hg.repogroup.create.false', 'hg.repogroup.create.true',
484 'hg.create.write_on_repogroup.false',
484 'hg.create.write_on_repogroup.false',
485 'hg.create.write_on_repogroup.true',
485 'hg.create.write_on_repogroup.true',
486 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
486 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
487 ])
487 ])
488
488
489 # USER GROUPS comes first user group global permissions
489 # USER GROUPS comes first user group global permissions
490 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
490 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
491 .options(joinedload(UserGroupToPerm.permission))\
491 .options(joinedload(UserGroupToPerm.permission))\
492 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
492 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
493 UserGroupMember.users_group_id))\
493 UserGroupMember.users_group_id))\
494 .filter(UserGroupMember.user_id == self.user_id)\
494 .filter(UserGroupMember.user_id == self.user_id)\
495 .order_by(UserGroupToPerm.users_group_id)\
495 .order_by(UserGroupToPerm.users_group_id)\
496 .all()
496 .all()
497
497
498 # need to group here by groups since user can be in more than
498 # need to group here by groups since user can be in more than
499 # one group, so we get all groups
499 # one group, so we get all groups
500 _explicit_grouped_perms = [
500 _explicit_grouped_perms = [
501 [x, list(y)] for x, y in
501 [x, list(y)] for x, y in
502 itertools.groupby(user_perms_from_users_groups,
502 itertools.groupby(user_perms_from_users_groups,
503 lambda _x: _x.users_group)]
503 lambda _x: _x.users_group)]
504
504
505 for gr, perms in _explicit_grouped_perms:
505 for gr, perms in _explicit_grouped_perms:
506 # since user can be in multiple groups iterate over them and
506 # since user can be in multiple groups iterate over them and
507 # select the lowest permissions first (more explicit)
507 # select the lowest permissions first (more explicit)
508 # TODO: marcink: do this^^
508 # TODO: marcink: do this^^
509
509
510 # group doesn't inherit default permissions so we actually set them
510 # group doesn't inherit default permissions so we actually set them
511 if not gr.inherit_default_permissions:
511 if not gr.inherit_default_permissions:
512 # NEED TO IGNORE all previously set configurable permissions
512 # NEED TO IGNORE all previously set configurable permissions
513 # and replace them with explicitly set from this user
513 # and replace them with explicitly set from this user
514 # group permissions
514 # group permissions
515 self.permissions_global = self.permissions_global.difference(
515 self.permissions_global = self.permissions_global.difference(
516 _configurable)
516 _configurable)
517 for perm in perms:
517 for perm in perms:
518 self.permissions_global.add(perm.permission.permission_name)
518 self.permissions_global.add(perm.permission.permission_name)
519
519
520 # user explicit global permissions
520 # user explicit global permissions
521 user_perms = Session().query(UserToPerm)\
521 user_perms = Session().query(UserToPerm)\
522 .options(joinedload(UserToPerm.permission))\
522 .options(joinedload(UserToPerm.permission))\
523 .filter(UserToPerm.user_id == self.user_id).all()
523 .filter(UserToPerm.user_id == self.user_id).all()
524
524
525 if not self.inherit_default_permissions:
525 if not self.inherit_default_permissions:
526 # NEED TO IGNORE all configurable permissions and
526 # NEED TO IGNORE all configurable permissions and
527 # replace them with explicitly set from this user permissions
527 # replace them with explicitly set from this user permissions
528 self.permissions_global = self.permissions_global.difference(
528 self.permissions_global = self.permissions_global.difference(
529 _configurable)
529 _configurable)
530 for perm in user_perms:
530 for perm in user_perms:
531 self.permissions_global.add(perm.permission.permission_name)
531 self.permissions_global.add(perm.permission.permission_name)
532
532
533 def _calculate_default_permissions(self):
533 def _calculate_default_permissions(self):
534 """
534 """
535 Set default user permissions for repositories, repository groups
535 Set default user permissions for repositories, repository groups
536 taken from the default user.
536 taken from the default user.
537
537
538 Calculate inheritance of object permissions based on what we have now
538 Calculate inheritance of object permissions based on what we have now
539 in GLOBAL permissions. We check if .false is in GLOBAL since this is
539 in GLOBAL permissions. We check if .false is in GLOBAL since this is
540 explicitly set. Inherit is the opposite of .false being there.
540 explicitly set. Inherit is the opposite of .false being there.
541
541
542 .. note::
542 .. note::
543
543
544 the syntax is little bit odd but what we need to check here is
544 the syntax is little bit odd but what we need to check here is
545 the opposite of .false permission being in the list so even for
545 the opposite of .false permission being in the list so even for
546 inconsistent state when both .true/.false is there
546 inconsistent state when both .true/.false is there
547 .false is more important
547 .false is more important
548
548
549 """
549 """
550 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
550 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
551 in self.permissions_global)
551 in self.permissions_global)
552
552
553 # defaults for repositories, taken from `default` user permissions
553 # defaults for repositories, taken from `default` user permissions
554 # on given repo
554 # on given repo
555 for perm in self.default_repo_perms:
555 for perm in self.default_repo_perms:
556 r_k = perm.UserRepoToPerm.repository.repo_name
556 r_k = perm.UserRepoToPerm.repository.repo_name
557 p = perm.Permission.permission_name
557 p = perm.Permission.permission_name
558 o = PermOrigin.REPO_DEFAULT
558 o = PermOrigin.REPO_DEFAULT
559 self.permissions_repositories[r_k] = p, o
559 self.permissions_repositories[r_k] = p, o
560
560
561 # if we decide this user isn't inheriting permissions from
561 # if we decide this user isn't inheriting permissions from
562 # default user we set him to .none so only explicit
562 # default user we set him to .none so only explicit
563 # permissions work
563 # permissions work
564 if not user_inherit_object_permissions:
564 if not user_inherit_object_permissions:
565 p = 'repository.none'
565 p = 'repository.none'
566 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
566 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
567 self.permissions_repositories[r_k] = p, o
567 self.permissions_repositories[r_k] = p, o
568
568
569 if perm.Repository.private and not (
569 if perm.Repository.private and not (
570 perm.Repository.user_id == self.user_id):
570 perm.Repository.user_id == self.user_id):
571 # disable defaults for private repos,
571 # disable defaults for private repos,
572 p = 'repository.none'
572 p = 'repository.none'
573 o = PermOrigin.REPO_PRIVATE
573 o = PermOrigin.REPO_PRIVATE
574 self.permissions_repositories[r_k] = p, o
574 self.permissions_repositories[r_k] = p, o
575
575
576 elif perm.Repository.user_id == self.user_id:
576 elif perm.Repository.user_id == self.user_id:
577 # set admin if owner
577 # set admin if owner
578 p = 'repository.admin'
578 p = 'repository.admin'
579 o = PermOrigin.REPO_OWNER
579 o = PermOrigin.REPO_OWNER
580 self.permissions_repositories[r_k] = p, o
580 self.permissions_repositories[r_k] = p, o
581
581
582 if self.user_is_admin:
582 if self.user_is_admin:
583 p = 'repository.admin'
583 p = 'repository.admin'
584 o = PermOrigin.SUPER_ADMIN
584 o = PermOrigin.SUPER_ADMIN
585 self.permissions_repositories[r_k] = p, o
585 self.permissions_repositories[r_k] = p, o
586
586
587 # defaults for repository groups taken from `default` user permission
587 # defaults for repository groups taken from `default` user permission
588 # on given group
588 # on given group
589 for perm in self.default_repo_groups_perms:
589 for perm in self.default_repo_groups_perms:
590 rg_k = perm.UserRepoGroupToPerm.group.group_name
590 rg_k = perm.UserRepoGroupToPerm.group.group_name
591 p = perm.Permission.permission_name
591 p = perm.Permission.permission_name
592 o = PermOrigin.REPOGROUP_DEFAULT
592 o = PermOrigin.REPOGROUP_DEFAULT
593 self.permissions_repository_groups[rg_k] = p, o
593 self.permissions_repository_groups[rg_k] = p, o
594
594
595 # if we decide this user isn't inheriting permissions from default
595 # if we decide this user isn't inheriting permissions from default
596 # user we set him to .none so only explicit permissions work
596 # user we set him to .none so only explicit permissions work
597 if not user_inherit_object_permissions:
597 if not user_inherit_object_permissions:
598 p = 'group.none'
598 p = 'group.none'
599 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
599 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
600 self.permissions_repository_groups[rg_k] = p, o
600 self.permissions_repository_groups[rg_k] = p, o
601
601
602 if perm.RepoGroup.user_id == self.user_id:
602 if perm.RepoGroup.user_id == self.user_id:
603 # set admin if owner
603 # set admin if owner
604 p = 'group.admin'
604 p = 'group.admin'
605 o = PermOrigin.REPOGROUP_OWNER
605 o = PermOrigin.REPOGROUP_OWNER
606 self.permissions_repository_groups[rg_k] = p, o
606 self.permissions_repository_groups[rg_k] = p, o
607
607
608 if self.user_is_admin:
608 if self.user_is_admin:
609 p = 'group.admin'
609 p = 'group.admin'
610 o = PermOrigin.SUPER_ADMIN
610 o = PermOrigin.SUPER_ADMIN
611 self.permissions_repository_groups[rg_k] = p, o
611 self.permissions_repository_groups[rg_k] = p, o
612
612
613 # defaults for user groups taken from `default` user permission
613 # defaults for user groups taken from `default` user permission
614 # on given user group
614 # on given user group
615 for perm in self.default_user_group_perms:
615 for perm in self.default_user_group_perms:
616 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
616 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
617 p = perm.Permission.permission_name
617 p = perm.Permission.permission_name
618 o = PermOrigin.USERGROUP_DEFAULT
618 o = PermOrigin.USERGROUP_DEFAULT
619 self.permissions_user_groups[u_k] = p, o
619 self.permissions_user_groups[u_k] = p, o
620
620
621 # if we decide this user isn't inheriting permissions from default
621 # if we decide this user isn't inheriting permissions from default
622 # user we set him to .none so only explicit permissions work
622 # user we set him to .none so only explicit permissions work
623 if not user_inherit_object_permissions:
623 if not user_inherit_object_permissions:
624 p = 'usergroup.none'
624 p = 'usergroup.none'
625 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
625 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
626 self.permissions_user_groups[u_k] = p, o
626 self.permissions_user_groups[u_k] = p, o
627
627
628 if perm.UserGroup.user_id == self.user_id:
628 if perm.UserGroup.user_id == self.user_id:
629 # set admin if owner
629 # set admin if owner
630 p = 'usergroup.admin'
630 p = 'usergroup.admin'
631 o = PermOrigin.USERGROUP_OWNER
631 o = PermOrigin.USERGROUP_OWNER
632 self.permissions_user_groups[u_k] = p, o
632 self.permissions_user_groups[u_k] = p, o
633
633
634 if self.user_is_admin:
634 if self.user_is_admin:
635 p = 'usergroup.admin'
635 p = 'usergroup.admin'
636 o = PermOrigin.SUPER_ADMIN
636 o = PermOrigin.SUPER_ADMIN
637 self.permissions_user_groups[u_k] = p, o
637 self.permissions_user_groups[u_k] = p, o
638
638
639 def _calculate_repository_permissions(self):
639 def _calculate_repository_permissions(self):
640 """
640 """
641 Repository permissions for the current user.
641 Repository permissions for the current user.
642
642
643 Check if the user is part of user groups for this repository and
643 Check if the user is part of user groups for this repository and
644 fill in the permission from it. `_choose_permission` decides of which
644 fill in the permission from it. `_choose_permission` decides of which
645 permission should be selected based on selected method.
645 permission should be selected based on selected method.
646 """
646 """
647
647
648 # user group for repositories permissions
648 # user group for repositories permissions
649 user_repo_perms_from_user_group = Permission\
649 user_repo_perms_from_user_group = Permission\
650 .get_default_repo_perms_from_user_group(
650 .get_default_repo_perms_from_user_group(
651 self.user_id, self.scope_repo_id)
651 self.user_id, self.scope_repo_id)
652
652
653 multiple_counter = collections.defaultdict(int)
653 multiple_counter = collections.defaultdict(int)
654 for perm in user_repo_perms_from_user_group:
654 for perm in user_repo_perms_from_user_group:
655 r_k = perm.UserGroupRepoToPerm.repository.repo_name
655 r_k = perm.UserGroupRepoToPerm.repository.repo_name
656 multiple_counter[r_k] += 1
656 multiple_counter[r_k] += 1
657 p = perm.Permission.permission_name
657 p = perm.Permission.permission_name
658 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
658 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
659 .users_group.users_group_name
659 .users_group.users_group_name
660
660
661 if multiple_counter[r_k] > 1:
661 if multiple_counter[r_k] > 1:
662 cur_perm = self.permissions_repositories[r_k]
662 cur_perm = self.permissions_repositories[r_k]
663 p = self._choose_permission(p, cur_perm)
663 p = self._choose_permission(p, cur_perm)
664
664
665 self.permissions_repositories[r_k] = p, o
665 self.permissions_repositories[r_k] = p, o
666
666
667 if perm.Repository.user_id == self.user_id:
667 if perm.Repository.user_id == self.user_id:
668 # set admin if owner
668 # set admin if owner
669 p = 'repository.admin'
669 p = 'repository.admin'
670 o = PermOrigin.REPO_OWNER
670 o = PermOrigin.REPO_OWNER
671 self.permissions_repositories[r_k] = p, o
671 self.permissions_repositories[r_k] = p, o
672
672
673 if self.user_is_admin:
673 if self.user_is_admin:
674 p = 'repository.admin'
674 p = 'repository.admin'
675 o = PermOrigin.SUPER_ADMIN
675 o = PermOrigin.SUPER_ADMIN
676 self.permissions_repositories[r_k] = p, o
676 self.permissions_repositories[r_k] = p, o
677
677
678 # user explicit permissions for repositories, overrides any specified
678 # user explicit permissions for repositories, overrides any specified
679 # by the group permission
679 # by the group permission
680 user_repo_perms = Permission.get_default_repo_perms(
680 user_repo_perms = Permission.get_default_repo_perms(
681 self.user_id, self.scope_repo_id)
681 self.user_id, self.scope_repo_id)
682 for perm in user_repo_perms:
682 for perm in user_repo_perms:
683 r_k = perm.UserRepoToPerm.repository.repo_name
683 r_k = perm.UserRepoToPerm.repository.repo_name
684 p = perm.Permission.permission_name
684 p = perm.Permission.permission_name
685 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
685 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
686
686
687 if not self.explicit:
687 if not self.explicit:
688 cur_perm = self.permissions_repositories.get(
688 cur_perm = self.permissions_repositories.get(
689 r_k, 'repository.none')
689 r_k, 'repository.none')
690 p = self._choose_permission(p, cur_perm)
690 p = self._choose_permission(p, cur_perm)
691
691
692 self.permissions_repositories[r_k] = p, o
692 self.permissions_repositories[r_k] = p, o
693
693
694 if perm.Repository.user_id == self.user_id:
694 if perm.Repository.user_id == self.user_id:
695 # set admin if owner
695 # set admin if owner
696 p = 'repository.admin'
696 p = 'repository.admin'
697 o = PermOrigin.REPO_OWNER
697 o = PermOrigin.REPO_OWNER
698 self.permissions_repositories[r_k] = p, o
698 self.permissions_repositories[r_k] = p, o
699
699
700 if self.user_is_admin:
700 if self.user_is_admin:
701 p = 'repository.admin'
701 p = 'repository.admin'
702 o = PermOrigin.SUPER_ADMIN
702 o = PermOrigin.SUPER_ADMIN
703 self.permissions_repositories[r_k] = p, o
703 self.permissions_repositories[r_k] = p, o
704
704
705 def _calculate_repository_group_permissions(self):
705 def _calculate_repository_group_permissions(self):
706 """
706 """
707 Repository group permissions for the current user.
707 Repository group permissions for the current user.
708
708
709 Check if the user is part of user groups for repository groups and
709 Check if the user is part of user groups for repository groups and
710 fill in the permissions from it. `_choose_permission` decides of which
710 fill in the permissions from it. `_choose_permission` decides of which
711 permission should be selected based on selected method.
711 permission should be selected based on selected method.
712 """
712 """
713 # user group for repo groups permissions
713 # user group for repo groups permissions
714 user_repo_group_perms_from_user_group = Permission\
714 user_repo_group_perms_from_user_group = Permission\
715 .get_default_group_perms_from_user_group(
715 .get_default_group_perms_from_user_group(
716 self.user_id, self.scope_repo_group_id)
716 self.user_id, self.scope_repo_group_id)
717
717
718 multiple_counter = collections.defaultdict(int)
718 multiple_counter = collections.defaultdict(int)
719 for perm in user_repo_group_perms_from_user_group:
719 for perm in user_repo_group_perms_from_user_group:
720 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
720 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
721 multiple_counter[rg_k] += 1
721 multiple_counter[rg_k] += 1
722 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
722 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
723 .users_group.users_group_name
723 .users_group.users_group_name
724 p = perm.Permission.permission_name
724 p = perm.Permission.permission_name
725
725
726 if multiple_counter[rg_k] > 1:
726 if multiple_counter[rg_k] > 1:
727 cur_perm = self.permissions_repository_groups[rg_k]
727 cur_perm = self.permissions_repository_groups[rg_k]
728 p = self._choose_permission(p, cur_perm)
728 p = self._choose_permission(p, cur_perm)
729 self.permissions_repository_groups[rg_k] = p, o
729 self.permissions_repository_groups[rg_k] = p, o
730
730
731 if perm.RepoGroup.user_id == self.user_id:
731 if perm.RepoGroup.user_id == self.user_id:
732 # set admin if owner, even for member of other user group
732 # set admin if owner, even for member of other user group
733 p = 'group.admin'
733 p = 'group.admin'
734 o = PermOrigin.REPOGROUP_OWNER
734 o = PermOrigin.REPOGROUP_OWNER
735 self.permissions_repository_groups[rg_k] = p, o
735 self.permissions_repository_groups[rg_k] = p, o
736
736
737 if self.user_is_admin:
737 if self.user_is_admin:
738 p = 'group.admin'
738 p = 'group.admin'
739 o = PermOrigin.SUPER_ADMIN
739 o = PermOrigin.SUPER_ADMIN
740 self.permissions_repository_groups[rg_k] = p, o
740 self.permissions_repository_groups[rg_k] = p, o
741
741
742 # user explicit permissions for repository groups
742 # user explicit permissions for repository groups
743 user_repo_groups_perms = Permission.get_default_group_perms(
743 user_repo_groups_perms = Permission.get_default_group_perms(
744 self.user_id, self.scope_repo_group_id)
744 self.user_id, self.scope_repo_group_id)
745 for perm in user_repo_groups_perms:
745 for perm in user_repo_groups_perms:
746 rg_k = perm.UserRepoGroupToPerm.group.group_name
746 rg_k = perm.UserRepoGroupToPerm.group.group_name
747 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
747 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
748 .user.username
748 .user.username
749 p = perm.Permission.permission_name
749 p = perm.Permission.permission_name
750
750
751 if not self.explicit:
751 if not self.explicit:
752 cur_perm = self.permissions_repository_groups.get(
752 cur_perm = self.permissions_repository_groups.get(
753 rg_k, 'group.none')
753 rg_k, 'group.none')
754 p = self._choose_permission(p, cur_perm)
754 p = self._choose_permission(p, cur_perm)
755
755
756 self.permissions_repository_groups[rg_k] = p, o
756 self.permissions_repository_groups[rg_k] = p, o
757
757
758 if perm.RepoGroup.user_id == self.user_id:
758 if perm.RepoGroup.user_id == self.user_id:
759 # set admin if owner
759 # set admin if owner
760 p = 'group.admin'
760 p = 'group.admin'
761 o = PermOrigin.REPOGROUP_OWNER
761 o = PermOrigin.REPOGROUP_OWNER
762 self.permissions_repository_groups[rg_k] = p, o
762 self.permissions_repository_groups[rg_k] = p, o
763
763
764 if self.user_is_admin:
764 if self.user_is_admin:
765 p = 'group.admin'
765 p = 'group.admin'
766 o = PermOrigin.SUPER_ADMIN
766 o = PermOrigin.SUPER_ADMIN
767 self.permissions_repository_groups[rg_k] = p, o
767 self.permissions_repository_groups[rg_k] = p, o
768
768
769 def _calculate_user_group_permissions(self):
769 def _calculate_user_group_permissions(self):
770 """
770 """
771 User group permissions for the current user.
771 User group permissions for the current user.
772 """
772 """
773 # user group for user group permissions
773 # user group for user group permissions
774 user_group_from_user_group = Permission\
774 user_group_from_user_group = Permission\
775 .get_default_user_group_perms_from_user_group(
775 .get_default_user_group_perms_from_user_group(
776 self.user_id, self.scope_user_group_id)
776 self.user_id, self.scope_user_group_id)
777
777
778 multiple_counter = collections.defaultdict(int)
778 multiple_counter = collections.defaultdict(int)
779 for perm in user_group_from_user_group:
779 for perm in user_group_from_user_group:
780 ug_k = perm.UserGroupUserGroupToPerm\
780 ug_k = perm.UserGroupUserGroupToPerm\
781 .target_user_group.users_group_name
781 .target_user_group.users_group_name
782 multiple_counter[ug_k] += 1
782 multiple_counter[ug_k] += 1
783 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
783 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
784 .user_group.users_group_name
784 .user_group.users_group_name
785 p = perm.Permission.permission_name
785 p = perm.Permission.permission_name
786
786
787 if multiple_counter[ug_k] > 1:
787 if multiple_counter[ug_k] > 1:
788 cur_perm = self.permissions_user_groups[ug_k]
788 cur_perm = self.permissions_user_groups[ug_k]
789 p = self._choose_permission(p, cur_perm)
789 p = self._choose_permission(p, cur_perm)
790
790
791 self.permissions_user_groups[ug_k] = p, o
791 self.permissions_user_groups[ug_k] = p, o
792
792
793 if perm.UserGroup.user_id == self.user_id:
793 if perm.UserGroup.user_id == self.user_id:
794 # set admin if owner, even for member of other user group
794 # set admin if owner, even for member of other user group
795 p = 'usergroup.admin'
795 p = 'usergroup.admin'
796 o = PermOrigin.USERGROUP_OWNER
796 o = PermOrigin.USERGROUP_OWNER
797 self.permissions_user_groups[ug_k] = p, o
797 self.permissions_user_groups[ug_k] = p, o
798
798
799 if self.user_is_admin:
799 if self.user_is_admin:
800 p = 'usergroup.admin'
800 p = 'usergroup.admin'
801 o = PermOrigin.SUPER_ADMIN
801 o = PermOrigin.SUPER_ADMIN
802 self.permissions_user_groups[ug_k] = p, o
802 self.permissions_user_groups[ug_k] = p, o
803
803
804 # user explicit permission for user groups
804 # user explicit permission for user groups
805 user_user_groups_perms = Permission.get_default_user_group_perms(
805 user_user_groups_perms = Permission.get_default_user_group_perms(
806 self.user_id, self.scope_user_group_id)
806 self.user_id, self.scope_user_group_id)
807 for perm in user_user_groups_perms:
807 for perm in user_user_groups_perms:
808 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
808 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
809 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
809 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
810 .user.username
810 .user.username
811 p = perm.Permission.permission_name
811 p = perm.Permission.permission_name
812
812
813 if not self.explicit:
813 if not self.explicit:
814 cur_perm = self.permissions_user_groups.get(
814 cur_perm = self.permissions_user_groups.get(
815 ug_k, 'usergroup.none')
815 ug_k, 'usergroup.none')
816 p = self._choose_permission(p, cur_perm)
816 p = self._choose_permission(p, cur_perm)
817
817
818 self.permissions_user_groups[ug_k] = p, o
818 self.permissions_user_groups[ug_k] = p, o
819
819
820 if perm.UserGroup.user_id == self.user_id:
820 if perm.UserGroup.user_id == self.user_id:
821 # set admin if owner
821 # set admin if owner
822 p = 'usergroup.admin'
822 p = 'usergroup.admin'
823 o = PermOrigin.USERGROUP_OWNER
823 o = PermOrigin.USERGROUP_OWNER
824 self.permissions_user_groups[ug_k] = p, o
824 self.permissions_user_groups[ug_k] = p, o
825
825
826 if self.user_is_admin:
826 if self.user_is_admin:
827 p = 'usergroup.admin'
827 p = 'usergroup.admin'
828 o = PermOrigin.SUPER_ADMIN
828 o = PermOrigin.SUPER_ADMIN
829 self.permissions_user_groups[ug_k] = p, o
829 self.permissions_user_groups[ug_k] = p, o
830
830
831 def _choose_permission(self, new_perm, cur_perm):
831 def _choose_permission(self, new_perm, cur_perm):
832 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
832 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
833 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
833 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
834 if self.algo == 'higherwin':
834 if self.algo == 'higherwin':
835 if new_perm_val > cur_perm_val:
835 if new_perm_val > cur_perm_val:
836 return new_perm
836 return new_perm
837 return cur_perm
837 return cur_perm
838 elif self.algo == 'lowerwin':
838 elif self.algo == 'lowerwin':
839 if new_perm_val < cur_perm_val:
839 if new_perm_val < cur_perm_val:
840 return new_perm
840 return new_perm
841 return cur_perm
841 return cur_perm
842
842
843 def _permission_structure(self):
843 def _permission_structure(self):
844 return {
844 return {
845 'global': self.permissions_global,
845 'global': self.permissions_global,
846 'repositories': self.permissions_repositories,
846 'repositories': self.permissions_repositories,
847 'repositories_groups': self.permissions_repository_groups,
847 'repositories_groups': self.permissions_repository_groups,
848 'user_groups': self.permissions_user_groups,
848 'user_groups': self.permissions_user_groups,
849 }
849 }
850
850
851
851
852 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
852 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
853 """
853 """
854 Check if given controller_name is in whitelist of auth token access
854 Check if given controller_name is in whitelist of auth token access
855 """
855 """
856 if not whitelist:
856 if not whitelist:
857 from rhodecode import CONFIG
857 from rhodecode import CONFIG
858 whitelist = aslist(
858 whitelist = aslist(
859 CONFIG.get('api_access_controllers_whitelist'), sep=',')
859 CONFIG.get('api_access_controllers_whitelist'), sep=',')
860 # backward compat translation
860 # backward compat translation
861 compat = {
861 compat = {
862 # old controller, new VIEW
862 # old controller, new VIEW
863 'ChangesetController:*': 'RepoCommitsView:*',
863 'ChangesetController:*': 'RepoCommitsView:*',
864 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
864 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
865 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
865 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
866 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
866 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
867 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
867 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
868 'GistsController:*': 'GistView:*',
868 'GistsController:*': 'GistView:*',
869 }
869 }
870
870
871 log.debug(
871 log.debug(
872 'Allowed views for AUTH TOKEN access: %s' % (whitelist,))
872 'Allowed views for AUTH TOKEN access: %s' % (whitelist,))
873 auth_token_access_valid = False
873 auth_token_access_valid = False
874
874
875 for entry in whitelist:
875 for entry in whitelist:
876 token_match = True
876 token_match = True
877 if entry in compat:
877 if entry in compat:
878 # translate from old Controllers to Pyramid Views
878 # translate from old Controllers to Pyramid Views
879 entry = compat[entry]
879 entry = compat[entry]
880
880
881 if '@' in entry:
881 if '@' in entry:
882 # specific AuthToken
882 # specific AuthToken
883 entry, allowed_token = entry.split('@', 1)
883 entry, allowed_token = entry.split('@', 1)
884 token_match = auth_token == allowed_token
884 token_match = auth_token == allowed_token
885
885
886 if fnmatch.fnmatch(view_name, entry) and token_match:
886 if fnmatch.fnmatch(view_name, entry) and token_match:
887 auth_token_access_valid = True
887 auth_token_access_valid = True
888 break
888 break
889
889
890 if auth_token_access_valid:
890 if auth_token_access_valid:
891 log.debug('view: `%s` matches entry in whitelist: %s'
891 log.debug('view: `%s` matches entry in whitelist: %s'
892 % (view_name, whitelist))
892 % (view_name, whitelist))
893 else:
893 else:
894 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
894 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
895 % (view_name, whitelist))
895 % (view_name, whitelist))
896 if auth_token:
896 if auth_token:
897 # if we use auth token key and don't have access it's a warning
897 # if we use auth token key and don't have access it's a warning
898 log.warning(msg)
898 log.warning(msg)
899 else:
899 else:
900 log.debug(msg)
900 log.debug(msg)
901
901
902 return auth_token_access_valid
902 return auth_token_access_valid
903
903
904
904
905 class AuthUser(object):
905 class AuthUser(object):
906 """
906 """
907 A simple object that handles all attributes of user in RhodeCode
907 A simple object that handles all attributes of user in RhodeCode
908
908
909 It does lookup based on API key,given user, or user present in session
909 It does lookup based on API key,given user, or user present in session
910 Then it fills all required information for such user. It also checks if
910 Then it fills all required information for such user. It also checks if
911 anonymous access is enabled and if so, it returns default user as logged in
911 anonymous access is enabled and if so, it returns default user as logged in
912 """
912 """
913 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
913 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
914
914
915 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
915 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
916
916
917 self.user_id = user_id
917 self.user_id = user_id
918 self._api_key = api_key
918 self._api_key = api_key
919
919
920 self.api_key = None
920 self.api_key = None
921 self.username = username
921 self.username = username
922 self.ip_addr = ip_addr
922 self.ip_addr = ip_addr
923 self.name = ''
923 self.name = ''
924 self.lastname = ''
924 self.lastname = ''
925 self.first_name = ''
925 self.first_name = ''
926 self.last_name = ''
926 self.last_name = ''
927 self.email = ''
927 self.email = ''
928 self.is_authenticated = False
928 self.is_authenticated = False
929 self.admin = False
929 self.admin = False
930 self.inherit_default_permissions = False
930 self.inherit_default_permissions = False
931 self.password = ''
931 self.password = ''
932
932
933 self.anonymous_user = None # propagated on propagate_data
933 self.anonymous_user = None # propagated on propagate_data
934 self.propagate_data()
934 self.propagate_data()
935 self._instance = None
935 self._instance = None
936 self._permissions_scoped_cache = {} # used to bind scoped calculation
936 self._permissions_scoped_cache = {} # used to bind scoped calculation
937
937
938 @LazyProperty
938 @LazyProperty
939 def permissions(self):
939 def permissions(self):
940 return self.get_perms(user=self, cache=False)
940 return self.get_perms(user=self, cache=False)
941
941
942 @LazyProperty
942 @LazyProperty
943 def permissions_safe(self):
943 def permissions_safe(self):
944 """
944 """
945 Filtered permissions excluding not allowed repositories
945 Filtered permissions excluding not allowed repositories
946 """
946 """
947 perms = self.get_perms(user=self, cache=False)
947 perms = self.get_perms(user=self, cache=False)
948
948
949 perms['repositories'] = {
949 perms['repositories'] = {
950 k: v for k, v in perms['repositories'].iteritems()
950 k: v for k, v in perms['repositories'].iteritems()
951 if v != 'repository.none'}
951 if v != 'repository.none'}
952 perms['repositories_groups'] = {
952 perms['repositories_groups'] = {
953 k: v for k, v in perms['repositories_groups'].iteritems()
953 k: v for k, v in perms['repositories_groups'].iteritems()
954 if v != 'group.none'}
954 if v != 'group.none'}
955 perms['user_groups'] = {
955 perms['user_groups'] = {
956 k: v for k, v in perms['user_groups'].iteritems()
956 k: v for k, v in perms['user_groups'].iteritems()
957 if v != 'usergroup.none'}
957 if v != 'usergroup.none'}
958 return perms
958 return perms
959
959
960 @LazyProperty
960 @LazyProperty
961 def permissions_full_details(self):
961 def permissions_full_details(self):
962 return self.get_perms(
962 return self.get_perms(
963 user=self, cache=False, calculate_super_admin=True)
963 user=self, cache=False, calculate_super_admin=True)
964
964
965 def permissions_with_scope(self, scope):
965 def permissions_with_scope(self, scope):
966 """
966 """
967 Call the get_perms function with scoped data. The scope in that function
967 Call the get_perms function with scoped data. The scope in that function
968 narrows the SQL calls to the given ID of objects resulting in fetching
968 narrows the SQL calls to the given ID of objects resulting in fetching
969 Just particular permission we want to obtain. If scope is an empty dict
969 Just particular permission we want to obtain. If scope is an empty dict
970 then it basically narrows the scope to GLOBAL permissions only.
970 then it basically narrows the scope to GLOBAL permissions only.
971
971
972 :param scope: dict
972 :param scope: dict
973 """
973 """
974 if 'repo_name' in scope:
974 if 'repo_name' in scope:
975 obj = Repository.get_by_repo_name(scope['repo_name'])
975 obj = Repository.get_by_repo_name(scope['repo_name'])
976 if obj:
976 if obj:
977 scope['repo_id'] = obj.repo_id
977 scope['repo_id'] = obj.repo_id
978 _scope = {
978 _scope = {
979 'repo_id': -1,
979 'repo_id': -1,
980 'user_group_id': -1,
980 'user_group_id': -1,
981 'repo_group_id': -1,
981 'repo_group_id': -1,
982 }
982 }
983 _scope.update(scope)
983 _scope.update(scope)
984 cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b,
984 cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b,
985 _scope.items())))
985 _scope.items())))
986 if cache_key not in self._permissions_scoped_cache:
986 if cache_key not in self._permissions_scoped_cache:
987 # store in cache to mimic how the @LazyProperty works,
987 # store in cache to mimic how the @LazyProperty works,
988 # the difference here is that we use the unique key calculated
988 # the difference here is that we use the unique key calculated
989 # from params and values
989 # from params and values
990 res = self.get_perms(user=self, cache=False, scope=_scope)
990 res = self.get_perms(user=self, cache=False, scope=_scope)
991 self._permissions_scoped_cache[cache_key] = res
991 self._permissions_scoped_cache[cache_key] = res
992 return self._permissions_scoped_cache[cache_key]
992 return self._permissions_scoped_cache[cache_key]
993
993
994 def get_instance(self):
994 def get_instance(self):
995 return User.get(self.user_id)
995 return User.get(self.user_id)
996
996
997 def update_lastactivity(self):
997 def update_lastactivity(self):
998 if self.user_id:
998 if self.user_id:
999 User.get(self.user_id).update_lastactivity()
999 User.get(self.user_id).update_lastactivity()
1000
1000
1001 def propagate_data(self):
1001 def propagate_data(self):
1002 """
1002 """
1003 Fills in user data and propagates values to this instance. Maps fetched
1003 Fills in user data and propagates values to this instance. Maps fetched
1004 user attributes to this class instance attributes
1004 user attributes to this class instance attributes
1005 """
1005 """
1006 log.debug('AuthUser: starting data propagation for new potential user')
1006 log.debug('AuthUser: starting data propagation for new potential user')
1007 user_model = UserModel()
1007 user_model = UserModel()
1008 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1008 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1009 is_user_loaded = False
1009 is_user_loaded = False
1010
1010
1011 # lookup by userid
1011 # lookup by userid
1012 if self.user_id is not None and self.user_id != anon_user.user_id:
1012 if self.user_id is not None and self.user_id != anon_user.user_id:
1013 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1013 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1014 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1014 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1015
1015
1016 # try go get user by api key
1016 # try go get user by api key
1017 elif self._api_key and self._api_key != anon_user.api_key:
1017 elif self._api_key and self._api_key != anon_user.api_key:
1018 log.debug('Trying Auth User lookup by API KEY: `%s`', self._api_key)
1018 log.debug('Trying Auth User lookup by API KEY: `%s`', self._api_key)
1019 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1019 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1020
1020
1021 # lookup by username
1021 # lookup by username
1022 elif self.username:
1022 elif self.username:
1023 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1023 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1024 is_user_loaded = user_model.fill_data(self, username=self.username)
1024 is_user_loaded = user_model.fill_data(self, username=self.username)
1025 else:
1025 else:
1026 log.debug('No data in %s that could been used to log in', self)
1026 log.debug('No data in %s that could been used to log in', self)
1027
1027
1028 if not is_user_loaded:
1028 if not is_user_loaded:
1029 log.debug(
1029 log.debug(
1030 'Failed to load user. Fallback to default user %s', anon_user)
1030 'Failed to load user. Fallback to default user %s', anon_user)
1031 # if we cannot authenticate user try anonymous
1031 # if we cannot authenticate user try anonymous
1032 if anon_user.active:
1032 if anon_user.active:
1033 log.debug('default user is active, using it as a session user')
1033 log.debug('default user is active, using it as a session user')
1034 user_model.fill_data(self, user_id=anon_user.user_id)
1034 user_model.fill_data(self, user_id=anon_user.user_id)
1035 # then we set this user is logged in
1035 # then we set this user is logged in
1036 self.is_authenticated = True
1036 self.is_authenticated = True
1037 else:
1037 else:
1038 log.debug('default user is NOT active')
1038 log.debug('default user is NOT active')
1039 # in case of disabled anonymous user we reset some of the
1039 # in case of disabled anonymous user we reset some of the
1040 # parameters so such user is "corrupted", skipping the fill_data
1040 # parameters so such user is "corrupted", skipping the fill_data
1041 for attr in ['user_id', 'username', 'admin', 'active']:
1041 for attr in ['user_id', 'username', 'admin', 'active']:
1042 setattr(self, attr, None)
1042 setattr(self, attr, None)
1043 self.is_authenticated = False
1043 self.is_authenticated = False
1044
1044
1045 if not self.username:
1045 if not self.username:
1046 self.username = 'None'
1046 self.username = 'None'
1047
1047
1048 log.debug('AuthUser: propagated user is now %s', self)
1048 log.debug('AuthUser: propagated user is now %s', self)
1049
1049
1050 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1050 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1051 calculate_super_admin=False, cache=False):
1051 calculate_super_admin=False, cache=False):
1052 """
1052 """
1053 Fills user permission attribute with permissions taken from database
1053 Fills user permission attribute with permissions taken from database
1054 works for permissions given for repositories, and for permissions that
1054 works for permissions given for repositories, and for permissions that
1055 are granted to groups
1055 are granted to groups
1056
1056
1057 :param user: instance of User object from database
1057 :param user: instance of User object from database
1058 :param explicit: In case there are permissions both for user and a group
1058 :param explicit: In case there are permissions both for user and a group
1059 that user is part of, explicit flag will defiine if user will
1059 that user is part of, explicit flag will defiine if user will
1060 explicitly override permissions from group, if it's False it will
1060 explicitly override permissions from group, if it's False it will
1061 make decision based on the algo
1061 make decision based on the algo
1062 :param algo: algorithm to decide what permission should be choose if
1062 :param algo: algorithm to decide what permission should be choose if
1063 it's multiple defined, eg user in two different groups. It also
1063 it's multiple defined, eg user in two different groups. It also
1064 decides if explicit flag is turned off how to specify the permission
1064 decides if explicit flag is turned off how to specify the permission
1065 for case when user is in a group + have defined separate permission
1065 for case when user is in a group + have defined separate permission
1066 """
1066 """
1067 user_id = user.user_id
1067 user_id = user.user_id
1068 user_is_admin = user.is_admin
1068 user_is_admin = user.is_admin
1069
1069
1070 # inheritance of global permissions like create repo/fork repo etc
1070 # inheritance of global permissions like create repo/fork repo etc
1071 user_inherit_default_permissions = user.inherit_default_permissions
1071 user_inherit_default_permissions = user.inherit_default_permissions
1072
1072
1073 log.debug('Computing PERMISSION tree for scope %s' % (scope, ))
1073 cache_seconds = safe_int(
1074 rhodecode.CONFIG.get('beaker.cache.short_term.expire'))
1075 cache_on = cache or cache_seconds > 0
1076 log.debug(
1077 'Computing PERMISSION tree for scope `%s` with caching: %s' % (
1078 scope, cache_on))
1079
1074 compute = caches.conditional_cache(
1080 compute = caches.conditional_cache(
1075 'short_term', 'cache_desc',
1081 'short_term', 'cache_desc',
1076 condition=cache, func=_cached_perms_data)
1082 condition=cache_on, func=_cached_perms_data)
1077 result = compute(user_id, scope, user_is_admin,
1083 result = compute(user_id, scope, user_is_admin,
1078 user_inherit_default_permissions, explicit, algo,
1084 user_inherit_default_permissions, explicit, algo,
1079 calculate_super_admin)
1085 calculate_super_admin)
1080
1086
1081 result_repr = []
1087 result_repr = []
1082 for k in result:
1088 for k in result:
1083 result_repr.append((k, len(result[k])))
1089 result_repr.append((k, len(result[k])))
1084
1090
1085 log.debug('PERMISSION tree computed %s' % (result_repr,))
1091 log.debug('PERMISSION tree computed %s' % (result_repr,))
1086 return result
1092 return result
1087
1093
1088 @property
1094 @property
1089 def is_default(self):
1095 def is_default(self):
1090 return self.username == User.DEFAULT_USER
1096 return self.username == User.DEFAULT_USER
1091
1097
1092 @property
1098 @property
1093 def is_admin(self):
1099 def is_admin(self):
1094 return self.admin
1100 return self.admin
1095
1101
1096 @property
1102 @property
1097 def is_user_object(self):
1103 def is_user_object(self):
1098 return self.user_id is not None
1104 return self.user_id is not None
1099
1105
1100 @property
1106 @property
1101 def repositories_admin(self):
1107 def repositories_admin(self):
1102 """
1108 """
1103 Returns list of repositories you're an admin of
1109 Returns list of repositories you're an admin of
1104 """
1110 """
1105 return [
1111 return [
1106 x[0] for x in self.permissions['repositories'].iteritems()
1112 x[0] for x in self.permissions['repositories'].iteritems()
1107 if x[1] == 'repository.admin']
1113 if x[1] == 'repository.admin']
1108
1114
1109 @property
1115 @property
1110 def repository_groups_admin(self):
1116 def repository_groups_admin(self):
1111 """
1117 """
1112 Returns list of repository groups you're an admin of
1118 Returns list of repository groups you're an admin of
1113 """
1119 """
1114 return [
1120 return [
1115 x[0] for x in self.permissions['repositories_groups'].iteritems()
1121 x[0] for x in self.permissions['repositories_groups'].iteritems()
1116 if x[1] == 'group.admin']
1122 if x[1] == 'group.admin']
1117
1123
1118 @property
1124 @property
1119 def user_groups_admin(self):
1125 def user_groups_admin(self):
1120 """
1126 """
1121 Returns list of user groups you're an admin of
1127 Returns list of user groups you're an admin of
1122 """
1128 """
1123 return [
1129 return [
1124 x[0] for x in self.permissions['user_groups'].iteritems()
1130 x[0] for x in self.permissions['user_groups'].iteritems()
1125 if x[1] == 'usergroup.admin']
1131 if x[1] == 'usergroup.admin']
1126
1132
1127 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1133 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1128 """
1134 """
1129 Returns list of repository ids that user have access to based on given
1135 Returns list of repository ids that user have access to based on given
1130 perms. The cache flag should be only used in cases that are used for
1136 perms. The cache flag should be only used in cases that are used for
1131 display purposes, NOT IN ANY CASE for permission checks.
1137 display purposes, NOT IN ANY CASE for permission checks.
1132 """
1138 """
1133 from rhodecode.model.scm import RepoList
1139 from rhodecode.model.scm import RepoList
1134 if not perms:
1140 if not perms:
1135 perms = [
1141 perms = [
1136 'repository.read', 'repository.write', 'repository.admin']
1142 'repository.read', 'repository.write', 'repository.admin']
1137
1143
1138 def _cached_repo_acl(user_id, perm_def, name_filter):
1144 def _cached_repo_acl(user_id, perm_def, name_filter):
1139 qry = Repository.query()
1145 qry = Repository.query()
1140 if name_filter:
1146 if name_filter:
1141 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1147 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1142 qry = qry.filter(
1148 qry = qry.filter(
1143 Repository.repo_name.ilike(ilike_expression))
1149 Repository.repo_name.ilike(ilike_expression))
1144
1150
1145 return [x.repo_id for x in
1151 return [x.repo_id for x in
1146 RepoList(qry, perm_set=perm_def)]
1152 RepoList(qry, perm_set=perm_def)]
1147
1153
1148 compute = caches.conditional_cache(
1154 compute = caches.conditional_cache(
1149 'long_term', 'repo_acl_ids',
1155 'long_term', 'repo_acl_ids',
1150 condition=cache, func=_cached_repo_acl)
1156 condition=cache, func=_cached_repo_acl)
1151 return compute(self.user_id, perms, name_filter)
1157 return compute(self.user_id, perms, name_filter)
1152
1158
1153 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1159 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1154 """
1160 """
1155 Returns list of repository group ids that user have access to based on given
1161 Returns list of repository group ids that user have access to based on given
1156 perms. The cache flag should be only used in cases that are used for
1162 perms. The cache flag should be only used in cases that are used for
1157 display purposes, NOT IN ANY CASE for permission checks.
1163 display purposes, NOT IN ANY CASE for permission checks.
1158 """
1164 """
1159 from rhodecode.model.scm import RepoGroupList
1165 from rhodecode.model.scm import RepoGroupList
1160 if not perms:
1166 if not perms:
1161 perms = [
1167 perms = [
1162 'group.read', 'group.write', 'group.admin']
1168 'group.read', 'group.write', 'group.admin']
1163
1169
1164 def _cached_repo_group_acl(user_id, perm_def, name_filter):
1170 def _cached_repo_group_acl(user_id, perm_def, name_filter):
1165 qry = RepoGroup.query()
1171 qry = RepoGroup.query()
1166 if name_filter:
1172 if name_filter:
1167 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1173 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1168 qry = qry.filter(
1174 qry = qry.filter(
1169 RepoGroup.group_name.ilike(ilike_expression))
1175 RepoGroup.group_name.ilike(ilike_expression))
1170
1176
1171 return [x.group_id for x in
1177 return [x.group_id for x in
1172 RepoGroupList(qry, perm_set=perm_def)]
1178 RepoGroupList(qry, perm_set=perm_def)]
1173
1179
1174 compute = caches.conditional_cache(
1180 compute = caches.conditional_cache(
1175 'long_term', 'repo_group_acl_ids',
1181 'long_term', 'repo_group_acl_ids',
1176 condition=cache, func=_cached_repo_group_acl)
1182 condition=cache, func=_cached_repo_group_acl)
1177 return compute(self.user_id, perms, name_filter)
1183 return compute(self.user_id, perms, name_filter)
1178
1184
1179 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1185 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1180 """
1186 """
1181 Returns list of user group ids that user have access to based on given
1187 Returns list of user group ids that user have access to based on given
1182 perms. The cache flag should be only used in cases that are used for
1188 perms. The cache flag should be only used in cases that are used for
1183 display purposes, NOT IN ANY CASE for permission checks.
1189 display purposes, NOT IN ANY CASE for permission checks.
1184 """
1190 """
1185 from rhodecode.model.scm import UserGroupList
1191 from rhodecode.model.scm import UserGroupList
1186 if not perms:
1192 if not perms:
1187 perms = [
1193 perms = [
1188 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1194 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1189
1195
1190 def _cached_user_group_acl(user_id, perm_def, name_filter):
1196 def _cached_user_group_acl(user_id, perm_def, name_filter):
1191 qry = UserGroup.query()
1197 qry = UserGroup.query()
1192 if name_filter:
1198 if name_filter:
1193 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1199 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1194 qry = qry.filter(
1200 qry = qry.filter(
1195 UserGroup.users_group_name.ilike(ilike_expression))
1201 UserGroup.users_group_name.ilike(ilike_expression))
1196
1202
1197 return [x.users_group_id for x in
1203 return [x.users_group_id for x in
1198 UserGroupList(qry, perm_set=perm_def)]
1204 UserGroupList(qry, perm_set=perm_def)]
1199
1205
1200 compute = caches.conditional_cache(
1206 compute = caches.conditional_cache(
1201 'long_term', 'user_group_acl_ids',
1207 'long_term', 'user_group_acl_ids',
1202 condition=cache, func=_cached_user_group_acl)
1208 condition=cache, func=_cached_user_group_acl)
1203 return compute(self.user_id, perms, name_filter)
1209 return compute(self.user_id, perms, name_filter)
1204
1210
1205 @property
1211 @property
1206 def ip_allowed(self):
1212 def ip_allowed(self):
1207 """
1213 """
1208 Checks if ip_addr used in constructor is allowed from defined list of
1214 Checks if ip_addr used in constructor is allowed from defined list of
1209 allowed ip_addresses for user
1215 allowed ip_addresses for user
1210
1216
1211 :returns: boolean, True if ip is in allowed ip range
1217 :returns: boolean, True if ip is in allowed ip range
1212 """
1218 """
1213 # check IP
1219 # check IP
1214 inherit = self.inherit_default_permissions
1220 inherit = self.inherit_default_permissions
1215 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1221 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1216 inherit_from_default=inherit)
1222 inherit_from_default=inherit)
1217 @property
1223 @property
1218 def personal_repo_group(self):
1224 def personal_repo_group(self):
1219 return RepoGroup.get_user_personal_repo_group(self.user_id)
1225 return RepoGroup.get_user_personal_repo_group(self.user_id)
1220
1226
1221 @LazyProperty
1227 @LazyProperty
1222 def feed_token(self):
1228 def feed_token(self):
1223 return self.get_instance().feed_token
1229 return self.get_instance().feed_token
1224
1230
1225 @classmethod
1231 @classmethod
1226 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1232 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1227 allowed_ips = AuthUser.get_allowed_ips(
1233 allowed_ips = AuthUser.get_allowed_ips(
1228 user_id, cache=True, inherit_from_default=inherit_from_default)
1234 user_id, cache=True, inherit_from_default=inherit_from_default)
1229 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1235 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1230 log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
1236 log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
1231 return True
1237 return True
1232 else:
1238 else:
1233 log.info('Access for IP:%s forbidden, '
1239 log.info('Access for IP:%s forbidden, '
1234 'not in %s' % (ip_addr, allowed_ips))
1240 'not in %s' % (ip_addr, allowed_ips))
1235 return False
1241 return False
1236
1242
1237 def __repr__(self):
1243 def __repr__(self):
1238 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1244 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1239 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1245 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1240
1246
1241 def set_authenticated(self, authenticated=True):
1247 def set_authenticated(self, authenticated=True):
1242 if self.user_id != self.anonymous_user.user_id:
1248 if self.user_id != self.anonymous_user.user_id:
1243 self.is_authenticated = authenticated
1249 self.is_authenticated = authenticated
1244
1250
1245 def get_cookie_store(self):
1251 def get_cookie_store(self):
1246 return {
1252 return {
1247 'username': self.username,
1253 'username': self.username,
1248 'password': md5(self.password or ''),
1254 'password': md5(self.password or ''),
1249 'user_id': self.user_id,
1255 'user_id': self.user_id,
1250 'is_authenticated': self.is_authenticated
1256 'is_authenticated': self.is_authenticated
1251 }
1257 }
1252
1258
1253 @classmethod
1259 @classmethod
1254 def from_cookie_store(cls, cookie_store):
1260 def from_cookie_store(cls, cookie_store):
1255 """
1261 """
1256 Creates AuthUser from a cookie store
1262 Creates AuthUser from a cookie store
1257
1263
1258 :param cls:
1264 :param cls:
1259 :param cookie_store:
1265 :param cookie_store:
1260 """
1266 """
1261 user_id = cookie_store.get('user_id')
1267 user_id = cookie_store.get('user_id')
1262 username = cookie_store.get('username')
1268 username = cookie_store.get('username')
1263 api_key = cookie_store.get('api_key')
1269 api_key = cookie_store.get('api_key')
1264 return AuthUser(user_id, api_key, username)
1270 return AuthUser(user_id, api_key, username)
1265
1271
1266 @classmethod
1272 @classmethod
1267 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1273 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1268 _set = set()
1274 _set = set()
1269
1275
1270 if inherit_from_default:
1276 if inherit_from_default:
1271 default_ips = UserIpMap.query().filter(
1277 default_ips = UserIpMap.query().filter(
1272 UserIpMap.user == User.get_default_user(cache=True))
1278 UserIpMap.user == User.get_default_user(cache=True))
1273 if cache:
1279 if cache:
1274 default_ips = default_ips.options(
1280 default_ips = default_ips.options(
1275 FromCache("sql_cache_short", "get_user_ips_default"))
1281 FromCache("sql_cache_short", "get_user_ips_default"))
1276
1282
1277 # populate from default user
1283 # populate from default user
1278 for ip in default_ips:
1284 for ip in default_ips:
1279 try:
1285 try:
1280 _set.add(ip.ip_addr)
1286 _set.add(ip.ip_addr)
1281 except ObjectDeletedError:
1287 except ObjectDeletedError:
1282 # since we use heavy caching sometimes it happens that
1288 # since we use heavy caching sometimes it happens that
1283 # we get deleted objects here, we just skip them
1289 # we get deleted objects here, we just skip them
1284 pass
1290 pass
1285
1291
1286 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1292 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1287 if cache:
1293 if cache:
1288 user_ips = user_ips.options(
1294 user_ips = user_ips.options(
1289 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1295 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1290
1296
1291 for ip in user_ips:
1297 for ip in user_ips:
1292 try:
1298 try:
1293 _set.add(ip.ip_addr)
1299 _set.add(ip.ip_addr)
1294 except ObjectDeletedError:
1300 except ObjectDeletedError:
1295 # since we use heavy caching sometimes it happens that we get
1301 # since we use heavy caching sometimes it happens that we get
1296 # deleted objects here, we just skip them
1302 # deleted objects here, we just skip them
1297 pass
1303 pass
1298 return _set or set(['0.0.0.0/0', '::/0'])
1304 return _set or set(['0.0.0.0/0', '::/0'])
1299
1305
1300
1306
1301 def set_available_permissions(settings):
1307 def set_available_permissions(settings):
1302 """
1308 """
1303 This function will propagate pyramid settings with all available defined
1309 This function will propagate pyramid settings with all available defined
1304 permission given in db. We don't want to check each time from db for new
1310 permission given in db. We don't want to check each time from db for new
1305 permissions since adding a new permission also requires application restart
1311 permissions since adding a new permission also requires application restart
1306 ie. to decorate new views with the newly created permission
1312 ie. to decorate new views with the newly created permission
1307
1313
1308 :param settings: current pyramid registry.settings
1314 :param settings: current pyramid registry.settings
1309
1315
1310 """
1316 """
1311 log.debug('auth: getting information about all available permissions')
1317 log.debug('auth: getting information about all available permissions')
1312 try:
1318 try:
1313 sa = meta.Session
1319 sa = meta.Session
1314 all_perms = sa.query(Permission).all()
1320 all_perms = sa.query(Permission).all()
1315 settings.setdefault('available_permissions',
1321 settings.setdefault('available_permissions',
1316 [x.permission_name for x in all_perms])
1322 [x.permission_name for x in all_perms])
1317 log.debug('auth: set available permissions')
1323 log.debug('auth: set available permissions')
1318 except Exception:
1324 except Exception:
1319 log.exception('Failed to fetch permissions from the database.')
1325 log.exception('Failed to fetch permissions from the database.')
1320 raise
1326 raise
1321
1327
1322
1328
1323 def get_csrf_token(session, force_new=False, save_if_missing=True):
1329 def get_csrf_token(session, force_new=False, save_if_missing=True):
1324 """
1330 """
1325 Return the current authentication token, creating one if one doesn't
1331 Return the current authentication token, creating one if one doesn't
1326 already exist and the save_if_missing flag is present.
1332 already exist and the save_if_missing flag is present.
1327
1333
1328 :param session: pass in the pyramid session, else we use the global ones
1334 :param session: pass in the pyramid session, else we use the global ones
1329 :param force_new: force to re-generate the token and store it in session
1335 :param force_new: force to re-generate the token and store it in session
1330 :param save_if_missing: save the newly generated token if it's missing in
1336 :param save_if_missing: save the newly generated token if it's missing in
1331 session
1337 session
1332 """
1338 """
1333 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1339 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1334 # from pyramid.csrf import get_csrf_token
1340 # from pyramid.csrf import get_csrf_token
1335
1341
1336 if (csrf_token_key not in session and save_if_missing) or force_new:
1342 if (csrf_token_key not in session and save_if_missing) or force_new:
1337 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1343 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1338 session[csrf_token_key] = token
1344 session[csrf_token_key] = token
1339 if hasattr(session, 'save'):
1345 if hasattr(session, 'save'):
1340 session.save()
1346 session.save()
1341 return session.get(csrf_token_key)
1347 return session.get(csrf_token_key)
1342
1348
1343
1349
1344 def get_request(perm_class_instance):
1350 def get_request(perm_class_instance):
1345 from pyramid.threadlocal import get_current_request
1351 from pyramid.threadlocal import get_current_request
1346 pyramid_request = get_current_request()
1352 pyramid_request = get_current_request()
1347 return pyramid_request
1353 return pyramid_request
1348
1354
1349
1355
1350 # CHECK DECORATORS
1356 # CHECK DECORATORS
1351 class CSRFRequired(object):
1357 class CSRFRequired(object):
1352 """
1358 """
1353 Decorator for authenticating a form
1359 Decorator for authenticating a form
1354
1360
1355 This decorator uses an authorization token stored in the client's
1361 This decorator uses an authorization token stored in the client's
1356 session for prevention of certain Cross-site request forgery (CSRF)
1362 session for prevention of certain Cross-site request forgery (CSRF)
1357 attacks (See
1363 attacks (See
1358 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1364 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1359 information).
1365 information).
1360
1366
1361 For use with the ``webhelpers.secure_form`` helper functions.
1367 For use with the ``webhelpers.secure_form`` helper functions.
1362
1368
1363 """
1369 """
1364 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1370 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1365 except_methods=None):
1371 except_methods=None):
1366 self.token = token
1372 self.token = token
1367 self.header = header
1373 self.header = header
1368 self.except_methods = except_methods or []
1374 self.except_methods = except_methods or []
1369
1375
1370 def __call__(self, func):
1376 def __call__(self, func):
1371 return get_cython_compat_decorator(self.__wrapper, func)
1377 return get_cython_compat_decorator(self.__wrapper, func)
1372
1378
1373 def _get_csrf(self, _request):
1379 def _get_csrf(self, _request):
1374 return _request.POST.get(self.token, _request.headers.get(self.header))
1380 return _request.POST.get(self.token, _request.headers.get(self.header))
1375
1381
1376 def check_csrf(self, _request, cur_token):
1382 def check_csrf(self, _request, cur_token):
1377 supplied_token = self._get_csrf(_request)
1383 supplied_token = self._get_csrf(_request)
1378 return supplied_token and supplied_token == cur_token
1384 return supplied_token and supplied_token == cur_token
1379
1385
1380 def _get_request(self):
1386 def _get_request(self):
1381 return get_request(self)
1387 return get_request(self)
1382
1388
1383 def __wrapper(self, func, *fargs, **fkwargs):
1389 def __wrapper(self, func, *fargs, **fkwargs):
1384 request = self._get_request()
1390 request = self._get_request()
1385
1391
1386 if request.method in self.except_methods:
1392 if request.method in self.except_methods:
1387 return func(*fargs, **fkwargs)
1393 return func(*fargs, **fkwargs)
1388
1394
1389 cur_token = get_csrf_token(request.session, save_if_missing=False)
1395 cur_token = get_csrf_token(request.session, save_if_missing=False)
1390 if self.check_csrf(request, cur_token):
1396 if self.check_csrf(request, cur_token):
1391 if request.POST.get(self.token):
1397 if request.POST.get(self.token):
1392 del request.POST[self.token]
1398 del request.POST[self.token]
1393 return func(*fargs, **fkwargs)
1399 return func(*fargs, **fkwargs)
1394 else:
1400 else:
1395 reason = 'token-missing'
1401 reason = 'token-missing'
1396 supplied_token = self._get_csrf(request)
1402 supplied_token = self._get_csrf(request)
1397 if supplied_token and cur_token != supplied_token:
1403 if supplied_token and cur_token != supplied_token:
1398 reason = 'token-mismatch [%s:%s]' % (
1404 reason = 'token-mismatch [%s:%s]' % (
1399 cur_token or ''[:6], supplied_token or ''[:6])
1405 cur_token or ''[:6], supplied_token or ''[:6])
1400
1406
1401 csrf_message = \
1407 csrf_message = \
1402 ("Cross-site request forgery detected, request denied. See "
1408 ("Cross-site request forgery detected, request denied. See "
1403 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1409 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1404 "more information.")
1410 "more information.")
1405 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1411 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1406 'REMOTE_ADDR:%s, HEADERS:%s' % (
1412 'REMOTE_ADDR:%s, HEADERS:%s' % (
1407 request, reason, request.remote_addr, request.headers))
1413 request, reason, request.remote_addr, request.headers))
1408
1414
1409 raise HTTPForbidden(explanation=csrf_message)
1415 raise HTTPForbidden(explanation=csrf_message)
1410
1416
1411
1417
1412 class LoginRequired(object):
1418 class LoginRequired(object):
1413 """
1419 """
1414 Must be logged in to execute this function else
1420 Must be logged in to execute this function else
1415 redirect to login page
1421 redirect to login page
1416
1422
1417 :param api_access: if enabled this checks only for valid auth token
1423 :param api_access: if enabled this checks only for valid auth token
1418 and grants access based on valid token
1424 and grants access based on valid token
1419 """
1425 """
1420 def __init__(self, auth_token_access=None):
1426 def __init__(self, auth_token_access=None):
1421 self.auth_token_access = auth_token_access
1427 self.auth_token_access = auth_token_access
1422
1428
1423 def __call__(self, func):
1429 def __call__(self, func):
1424 return get_cython_compat_decorator(self.__wrapper, func)
1430 return get_cython_compat_decorator(self.__wrapper, func)
1425
1431
1426 def _get_request(self):
1432 def _get_request(self):
1427 return get_request(self)
1433 return get_request(self)
1428
1434
1429 def __wrapper(self, func, *fargs, **fkwargs):
1435 def __wrapper(self, func, *fargs, **fkwargs):
1430 from rhodecode.lib import helpers as h
1436 from rhodecode.lib import helpers as h
1431 cls = fargs[0]
1437 cls = fargs[0]
1432 user = cls._rhodecode_user
1438 user = cls._rhodecode_user
1433 request = self._get_request()
1439 request = self._get_request()
1434 _ = request.translate
1440 _ = request.translate
1435
1441
1436 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1442 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1437 log.debug('Starting login restriction checks for user: %s' % (user,))
1443 log.debug('Starting login restriction checks for user: %s' % (user,))
1438 # check if our IP is allowed
1444 # check if our IP is allowed
1439 ip_access_valid = True
1445 ip_access_valid = True
1440 if not user.ip_allowed:
1446 if not user.ip_allowed:
1441 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1447 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1442 category='warning')
1448 category='warning')
1443 ip_access_valid = False
1449 ip_access_valid = False
1444
1450
1445 # check if we used an APIKEY and it's a valid one
1451 # check if we used an APIKEY and it's a valid one
1446 # defined white-list of controllers which API access will be enabled
1452 # defined white-list of controllers which API access will be enabled
1447 _auth_token = request.GET.get(
1453 _auth_token = request.GET.get(
1448 'auth_token', '') or request.GET.get('api_key', '')
1454 'auth_token', '') or request.GET.get('api_key', '')
1449 auth_token_access_valid = allowed_auth_token_access(
1455 auth_token_access_valid = allowed_auth_token_access(
1450 loc, auth_token=_auth_token)
1456 loc, auth_token=_auth_token)
1451
1457
1452 # explicit controller is enabled or API is in our whitelist
1458 # explicit controller is enabled or API is in our whitelist
1453 if self.auth_token_access or auth_token_access_valid:
1459 if self.auth_token_access or auth_token_access_valid:
1454 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1460 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1455 db_user = user.get_instance()
1461 db_user = user.get_instance()
1456
1462
1457 if db_user:
1463 if db_user:
1458 if self.auth_token_access:
1464 if self.auth_token_access:
1459 roles = self.auth_token_access
1465 roles = self.auth_token_access
1460 else:
1466 else:
1461 roles = [UserApiKeys.ROLE_HTTP]
1467 roles = [UserApiKeys.ROLE_HTTP]
1462 token_match = db_user.authenticate_by_token(
1468 token_match = db_user.authenticate_by_token(
1463 _auth_token, roles=roles)
1469 _auth_token, roles=roles)
1464 else:
1470 else:
1465 log.debug('Unable to fetch db instance for auth user: %s', user)
1471 log.debug('Unable to fetch db instance for auth user: %s', user)
1466 token_match = False
1472 token_match = False
1467
1473
1468 if _auth_token and token_match:
1474 if _auth_token and token_match:
1469 auth_token_access_valid = True
1475 auth_token_access_valid = True
1470 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1476 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1471 else:
1477 else:
1472 auth_token_access_valid = False
1478 auth_token_access_valid = False
1473 if not _auth_token:
1479 if not _auth_token:
1474 log.debug("AUTH TOKEN *NOT* present in request")
1480 log.debug("AUTH TOKEN *NOT* present in request")
1475 else:
1481 else:
1476 log.warning(
1482 log.warning(
1477 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1483 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1478
1484
1479 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1485 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1480 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1486 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1481 else 'AUTH_TOKEN_AUTH'
1487 else 'AUTH_TOKEN_AUTH'
1482
1488
1483 if ip_access_valid and (
1489 if ip_access_valid and (
1484 user.is_authenticated or auth_token_access_valid):
1490 user.is_authenticated or auth_token_access_valid):
1485 log.info(
1491 log.info(
1486 'user %s authenticating with:%s IS authenticated on func %s'
1492 'user %s authenticating with:%s IS authenticated on func %s'
1487 % (user, reason, loc))
1493 % (user, reason, loc))
1488
1494
1489 # update user data to check last activity
1495 # update user data to check last activity
1490 user.update_lastactivity()
1496 user.update_lastactivity()
1491 Session().commit()
1497 Session().commit()
1492 return func(*fargs, **fkwargs)
1498 return func(*fargs, **fkwargs)
1493 else:
1499 else:
1494 log.warning(
1500 log.warning(
1495 'user %s authenticating with:%s NOT authenticated on '
1501 'user %s authenticating with:%s NOT authenticated on '
1496 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1502 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1497 % (user, reason, loc, ip_access_valid,
1503 % (user, reason, loc, ip_access_valid,
1498 auth_token_access_valid))
1504 auth_token_access_valid))
1499 # we preserve the get PARAM
1505 # we preserve the get PARAM
1500 came_from = get_came_from(request)
1506 came_from = get_came_from(request)
1501
1507
1502 log.debug('redirecting to login page with %s' % (came_from,))
1508 log.debug('redirecting to login page with %s' % (came_from,))
1503 raise HTTPFound(
1509 raise HTTPFound(
1504 h.route_path('login', _query={'came_from': came_from}))
1510 h.route_path('login', _query={'came_from': came_from}))
1505
1511
1506
1512
1507 class NotAnonymous(object):
1513 class NotAnonymous(object):
1508 """
1514 """
1509 Must be logged in to execute this function else
1515 Must be logged in to execute this function else
1510 redirect to login page
1516 redirect to login page
1511 """
1517 """
1512
1518
1513 def __call__(self, func):
1519 def __call__(self, func):
1514 return get_cython_compat_decorator(self.__wrapper, func)
1520 return get_cython_compat_decorator(self.__wrapper, func)
1515
1521
1516 def _get_request(self):
1522 def _get_request(self):
1517 return get_request(self)
1523 return get_request(self)
1518
1524
1519 def __wrapper(self, func, *fargs, **fkwargs):
1525 def __wrapper(self, func, *fargs, **fkwargs):
1520 import rhodecode.lib.helpers as h
1526 import rhodecode.lib.helpers as h
1521 cls = fargs[0]
1527 cls = fargs[0]
1522 self.user = cls._rhodecode_user
1528 self.user = cls._rhodecode_user
1523 request = self._get_request()
1529 request = self._get_request()
1524 _ = request.translate
1530 _ = request.translate
1525 log.debug('Checking if user is not anonymous @%s' % cls)
1531 log.debug('Checking if user is not anonymous @%s' % cls)
1526
1532
1527 anonymous = self.user.username == User.DEFAULT_USER
1533 anonymous = self.user.username == User.DEFAULT_USER
1528
1534
1529 if anonymous:
1535 if anonymous:
1530 came_from = get_came_from(request)
1536 came_from = get_came_from(request)
1531 h.flash(_('You need to be a registered user to '
1537 h.flash(_('You need to be a registered user to '
1532 'perform this action'),
1538 'perform this action'),
1533 category='warning')
1539 category='warning')
1534 raise HTTPFound(
1540 raise HTTPFound(
1535 h.route_path('login', _query={'came_from': came_from}))
1541 h.route_path('login', _query={'came_from': came_from}))
1536 else:
1542 else:
1537 return func(*fargs, **fkwargs)
1543 return func(*fargs, **fkwargs)
1538
1544
1539
1545
1540 class PermsDecorator(object):
1546 class PermsDecorator(object):
1541 """
1547 """
1542 Base class for controller decorators, we extract the current user from
1548 Base class for controller decorators, we extract the current user from
1543 the class itself, which has it stored in base controllers
1549 the class itself, which has it stored in base controllers
1544 """
1550 """
1545
1551
1546 def __init__(self, *required_perms):
1552 def __init__(self, *required_perms):
1547 self.required_perms = set(required_perms)
1553 self.required_perms = set(required_perms)
1548
1554
1549 def __call__(self, func):
1555 def __call__(self, func):
1550 return get_cython_compat_decorator(self.__wrapper, func)
1556 return get_cython_compat_decorator(self.__wrapper, func)
1551
1557
1552 def _get_request(self):
1558 def _get_request(self):
1553 return get_request(self)
1559 return get_request(self)
1554
1560
1555 def __wrapper(self, func, *fargs, **fkwargs):
1561 def __wrapper(self, func, *fargs, **fkwargs):
1556 import rhodecode.lib.helpers as h
1562 import rhodecode.lib.helpers as h
1557 cls = fargs[0]
1563 cls = fargs[0]
1558 _user = cls._rhodecode_user
1564 _user = cls._rhodecode_user
1559 request = self._get_request()
1565 request = self._get_request()
1560 _ = request.translate
1566 _ = request.translate
1561
1567
1562 log.debug('checking %s permissions %s for %s %s',
1568 log.debug('checking %s permissions %s for %s %s',
1563 self.__class__.__name__, self.required_perms, cls, _user)
1569 self.__class__.__name__, self.required_perms, cls, _user)
1564
1570
1565 if self.check_permissions(_user):
1571 if self.check_permissions(_user):
1566 log.debug('Permission granted for %s %s', cls, _user)
1572 log.debug('Permission granted for %s %s', cls, _user)
1567 return func(*fargs, **fkwargs)
1573 return func(*fargs, **fkwargs)
1568
1574
1569 else:
1575 else:
1570 log.debug('Permission denied for %s %s', cls, _user)
1576 log.debug('Permission denied for %s %s', cls, _user)
1571 anonymous = _user.username == User.DEFAULT_USER
1577 anonymous = _user.username == User.DEFAULT_USER
1572
1578
1573 if anonymous:
1579 if anonymous:
1574 came_from = get_came_from(self._get_request())
1580 came_from = get_came_from(self._get_request())
1575 h.flash(_('You need to be signed in to view this page'),
1581 h.flash(_('You need to be signed in to view this page'),
1576 category='warning')
1582 category='warning')
1577 raise HTTPFound(
1583 raise HTTPFound(
1578 h.route_path('login', _query={'came_from': came_from}))
1584 h.route_path('login', _query={'came_from': came_from}))
1579
1585
1580 else:
1586 else:
1581 # redirect with 404 to prevent resource discovery
1587 # redirect with 404 to prevent resource discovery
1582 raise HTTPNotFound()
1588 raise HTTPNotFound()
1583
1589
1584 def check_permissions(self, user):
1590 def check_permissions(self, user):
1585 """Dummy function for overriding"""
1591 """Dummy function for overriding"""
1586 raise NotImplementedError(
1592 raise NotImplementedError(
1587 'You have to write this function in child class')
1593 'You have to write this function in child class')
1588
1594
1589
1595
1590 class HasPermissionAllDecorator(PermsDecorator):
1596 class HasPermissionAllDecorator(PermsDecorator):
1591 """
1597 """
1592 Checks for access permission for all given predicates. All of them
1598 Checks for access permission for all given predicates. All of them
1593 have to be meet in order to fulfill the request
1599 have to be meet in order to fulfill the request
1594 """
1600 """
1595
1601
1596 def check_permissions(self, user):
1602 def check_permissions(self, user):
1597 perms = user.permissions_with_scope({})
1603 perms = user.permissions_with_scope({})
1598 if self.required_perms.issubset(perms['global']):
1604 if self.required_perms.issubset(perms['global']):
1599 return True
1605 return True
1600 return False
1606 return False
1601
1607
1602
1608
1603 class HasPermissionAnyDecorator(PermsDecorator):
1609 class HasPermissionAnyDecorator(PermsDecorator):
1604 """
1610 """
1605 Checks for access permission for any of given predicates. In order to
1611 Checks for access permission for any of given predicates. In order to
1606 fulfill the request any of predicates must be meet
1612 fulfill the request any of predicates must be meet
1607 """
1613 """
1608
1614
1609 def check_permissions(self, user):
1615 def check_permissions(self, user):
1610 perms = user.permissions_with_scope({})
1616 perms = user.permissions_with_scope({})
1611 if self.required_perms.intersection(perms['global']):
1617 if self.required_perms.intersection(perms['global']):
1612 return True
1618 return True
1613 return False
1619 return False
1614
1620
1615
1621
1616 class HasRepoPermissionAllDecorator(PermsDecorator):
1622 class HasRepoPermissionAllDecorator(PermsDecorator):
1617 """
1623 """
1618 Checks for access permission for all given predicates for specific
1624 Checks for access permission for all given predicates for specific
1619 repository. All of them have to be meet in order to fulfill the request
1625 repository. All of them have to be meet in order to fulfill the request
1620 """
1626 """
1621 def _get_repo_name(self):
1627 def _get_repo_name(self):
1622 _request = self._get_request()
1628 _request = self._get_request()
1623 return get_repo_slug(_request)
1629 return get_repo_slug(_request)
1624
1630
1625 def check_permissions(self, user):
1631 def check_permissions(self, user):
1626 perms = user.permissions
1632 perms = user.permissions
1627 repo_name = self._get_repo_name()
1633 repo_name = self._get_repo_name()
1628
1634
1629 try:
1635 try:
1630 user_perms = set([perms['repositories'][repo_name]])
1636 user_perms = set([perms['repositories'][repo_name]])
1631 except KeyError:
1637 except KeyError:
1632 log.debug('cannot locate repo with name: `%s` in permissions defs',
1638 log.debug('cannot locate repo with name: `%s` in permissions defs',
1633 repo_name)
1639 repo_name)
1634 return False
1640 return False
1635
1641
1636 log.debug('checking `%s` permissions for repo `%s`',
1642 log.debug('checking `%s` permissions for repo `%s`',
1637 user_perms, repo_name)
1643 user_perms, repo_name)
1638 if self.required_perms.issubset(user_perms):
1644 if self.required_perms.issubset(user_perms):
1639 return True
1645 return True
1640 return False
1646 return False
1641
1647
1642
1648
1643 class HasRepoPermissionAnyDecorator(PermsDecorator):
1649 class HasRepoPermissionAnyDecorator(PermsDecorator):
1644 """
1650 """
1645 Checks for access permission for any of given predicates for specific
1651 Checks for access permission for any of given predicates for specific
1646 repository. In order to fulfill the request any of predicates must be meet
1652 repository. In order to fulfill the request any of predicates must be meet
1647 """
1653 """
1648 def _get_repo_name(self):
1654 def _get_repo_name(self):
1649 _request = self._get_request()
1655 _request = self._get_request()
1650 return get_repo_slug(_request)
1656 return get_repo_slug(_request)
1651
1657
1652 def check_permissions(self, user):
1658 def check_permissions(self, user):
1653 perms = user.permissions
1659 perms = user.permissions
1654 repo_name = self._get_repo_name()
1660 repo_name = self._get_repo_name()
1655
1661
1656 try:
1662 try:
1657 user_perms = set([perms['repositories'][repo_name]])
1663 user_perms = set([perms['repositories'][repo_name]])
1658 except KeyError:
1664 except KeyError:
1659 log.debug(
1665 log.debug(
1660 'cannot locate repo with name: `%s` in permissions defs',
1666 'cannot locate repo with name: `%s` in permissions defs',
1661 repo_name)
1667 repo_name)
1662 return False
1668 return False
1663
1669
1664 log.debug('checking `%s` permissions for repo `%s`',
1670 log.debug('checking `%s` permissions for repo `%s`',
1665 user_perms, repo_name)
1671 user_perms, repo_name)
1666 if self.required_perms.intersection(user_perms):
1672 if self.required_perms.intersection(user_perms):
1667 return True
1673 return True
1668 return False
1674 return False
1669
1675
1670
1676
1671 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1677 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1672 """
1678 """
1673 Checks for access permission for all given predicates for specific
1679 Checks for access permission for all given predicates for specific
1674 repository group. All of them have to be meet in order to
1680 repository group. All of them have to be meet in order to
1675 fulfill the request
1681 fulfill the request
1676 """
1682 """
1677 def _get_repo_group_name(self):
1683 def _get_repo_group_name(self):
1678 _request = self._get_request()
1684 _request = self._get_request()
1679 return get_repo_group_slug(_request)
1685 return get_repo_group_slug(_request)
1680
1686
1681 def check_permissions(self, user):
1687 def check_permissions(self, user):
1682 perms = user.permissions
1688 perms = user.permissions
1683 group_name = self._get_repo_group_name()
1689 group_name = self._get_repo_group_name()
1684 try:
1690 try:
1685 user_perms = set([perms['repositories_groups'][group_name]])
1691 user_perms = set([perms['repositories_groups'][group_name]])
1686 except KeyError:
1692 except KeyError:
1687 log.debug(
1693 log.debug(
1688 'cannot locate repo group with name: `%s` in permissions defs',
1694 'cannot locate repo group with name: `%s` in permissions defs',
1689 group_name)
1695 group_name)
1690 return False
1696 return False
1691
1697
1692 log.debug('checking `%s` permissions for repo group `%s`',
1698 log.debug('checking `%s` permissions for repo group `%s`',
1693 user_perms, group_name)
1699 user_perms, group_name)
1694 if self.required_perms.issubset(user_perms):
1700 if self.required_perms.issubset(user_perms):
1695 return True
1701 return True
1696 return False
1702 return False
1697
1703
1698
1704
1699 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1705 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1700 """
1706 """
1701 Checks for access permission for any of given predicates for specific
1707 Checks for access permission for any of given predicates for specific
1702 repository group. In order to fulfill the request any
1708 repository group. In order to fulfill the request any
1703 of predicates must be met
1709 of predicates must be met
1704 """
1710 """
1705 def _get_repo_group_name(self):
1711 def _get_repo_group_name(self):
1706 _request = self._get_request()
1712 _request = self._get_request()
1707 return get_repo_group_slug(_request)
1713 return get_repo_group_slug(_request)
1708
1714
1709 def check_permissions(self, user):
1715 def check_permissions(self, user):
1710 perms = user.permissions
1716 perms = user.permissions
1711 group_name = self._get_repo_group_name()
1717 group_name = self._get_repo_group_name()
1712
1718
1713 try:
1719 try:
1714 user_perms = set([perms['repositories_groups'][group_name]])
1720 user_perms = set([perms['repositories_groups'][group_name]])
1715 except KeyError:
1721 except KeyError:
1716 log.debug(
1722 log.debug(
1717 'cannot locate repo group with name: `%s` in permissions defs',
1723 'cannot locate repo group with name: `%s` in permissions defs',
1718 group_name)
1724 group_name)
1719 return False
1725 return False
1720
1726
1721 log.debug('checking `%s` permissions for repo group `%s`',
1727 log.debug('checking `%s` permissions for repo group `%s`',
1722 user_perms, group_name)
1728 user_perms, group_name)
1723 if self.required_perms.intersection(user_perms):
1729 if self.required_perms.intersection(user_perms):
1724 return True
1730 return True
1725 return False
1731 return False
1726
1732
1727
1733
1728 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1734 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1729 """
1735 """
1730 Checks for access permission for all given predicates for specific
1736 Checks for access permission for all given predicates for specific
1731 user group. All of them have to be meet in order to fulfill the request
1737 user group. All of them have to be meet in order to fulfill the request
1732 """
1738 """
1733 def _get_user_group_name(self):
1739 def _get_user_group_name(self):
1734 _request = self._get_request()
1740 _request = self._get_request()
1735 return get_user_group_slug(_request)
1741 return get_user_group_slug(_request)
1736
1742
1737 def check_permissions(self, user):
1743 def check_permissions(self, user):
1738 perms = user.permissions
1744 perms = user.permissions
1739 group_name = self._get_user_group_name()
1745 group_name = self._get_user_group_name()
1740 try:
1746 try:
1741 user_perms = set([perms['user_groups'][group_name]])
1747 user_perms = set([perms['user_groups'][group_name]])
1742 except KeyError:
1748 except KeyError:
1743 return False
1749 return False
1744
1750
1745 if self.required_perms.issubset(user_perms):
1751 if self.required_perms.issubset(user_perms):
1746 return True
1752 return True
1747 return False
1753 return False
1748
1754
1749
1755
1750 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1756 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1751 """
1757 """
1752 Checks for access permission for any of given predicates for specific
1758 Checks for access permission for any of given predicates for specific
1753 user group. In order to fulfill the request any of predicates must be meet
1759 user group. In order to fulfill the request any of predicates must be meet
1754 """
1760 """
1755 def _get_user_group_name(self):
1761 def _get_user_group_name(self):
1756 _request = self._get_request()
1762 _request = self._get_request()
1757 return get_user_group_slug(_request)
1763 return get_user_group_slug(_request)
1758
1764
1759 def check_permissions(self, user):
1765 def check_permissions(self, user):
1760 perms = user.permissions
1766 perms = user.permissions
1761 group_name = self._get_user_group_name()
1767 group_name = self._get_user_group_name()
1762 try:
1768 try:
1763 user_perms = set([perms['user_groups'][group_name]])
1769 user_perms = set([perms['user_groups'][group_name]])
1764 except KeyError:
1770 except KeyError:
1765 return False
1771 return False
1766
1772
1767 if self.required_perms.intersection(user_perms):
1773 if self.required_perms.intersection(user_perms):
1768 return True
1774 return True
1769 return False
1775 return False
1770
1776
1771
1777
1772 # CHECK FUNCTIONS
1778 # CHECK FUNCTIONS
1773 class PermsFunction(object):
1779 class PermsFunction(object):
1774 """Base function for other check functions"""
1780 """Base function for other check functions"""
1775
1781
1776 def __init__(self, *perms):
1782 def __init__(self, *perms):
1777 self.required_perms = set(perms)
1783 self.required_perms = set(perms)
1778 self.repo_name = None
1784 self.repo_name = None
1779 self.repo_group_name = None
1785 self.repo_group_name = None
1780 self.user_group_name = None
1786 self.user_group_name = None
1781
1787
1782 def __bool__(self):
1788 def __bool__(self):
1783 frame = inspect.currentframe()
1789 frame = inspect.currentframe()
1784 stack_trace = traceback.format_stack(frame)
1790 stack_trace = traceback.format_stack(frame)
1785 log.error('Checking bool value on a class instance of perm '
1791 log.error('Checking bool value on a class instance of perm '
1786 'function is not allowed: %s' % ''.join(stack_trace))
1792 'function is not allowed: %s' % ''.join(stack_trace))
1787 # rather than throwing errors, here we always return False so if by
1793 # rather than throwing errors, here we always return False so if by
1788 # accident someone checks truth for just an instance it will always end
1794 # accident someone checks truth for just an instance it will always end
1789 # up in returning False
1795 # up in returning False
1790 return False
1796 return False
1791 __nonzero__ = __bool__
1797 __nonzero__ = __bool__
1792
1798
1793 def __call__(self, check_location='', user=None):
1799 def __call__(self, check_location='', user=None):
1794 if not user:
1800 if not user:
1795 log.debug('Using user attribute from global request')
1801 log.debug('Using user attribute from global request')
1796 # TODO: remove this someday,put as user as attribute here
1802 # TODO: remove this someday,put as user as attribute here
1797 request = self._get_request()
1803 request = self._get_request()
1798 user = request.user
1804 user = request.user
1799
1805
1800 # init auth user if not already given
1806 # init auth user if not already given
1801 if not isinstance(user, AuthUser):
1807 if not isinstance(user, AuthUser):
1802 log.debug('Wrapping user %s into AuthUser', user)
1808 log.debug('Wrapping user %s into AuthUser', user)
1803 user = AuthUser(user.user_id)
1809 user = AuthUser(user.user_id)
1804
1810
1805 cls_name = self.__class__.__name__
1811 cls_name = self.__class__.__name__
1806 check_scope = self._get_check_scope(cls_name)
1812 check_scope = self._get_check_scope(cls_name)
1807 check_location = check_location or 'unspecified location'
1813 check_location = check_location or 'unspecified location'
1808
1814
1809 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1815 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1810 self.required_perms, user, check_scope, check_location)
1816 self.required_perms, user, check_scope, check_location)
1811 if not user:
1817 if not user:
1812 log.warning('Empty user given for permission check')
1818 log.warning('Empty user given for permission check')
1813 return False
1819 return False
1814
1820
1815 if self.check_permissions(user):
1821 if self.check_permissions(user):
1816 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1822 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1817 check_scope, user, check_location)
1823 check_scope, user, check_location)
1818 return True
1824 return True
1819
1825
1820 else:
1826 else:
1821 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1827 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1822 check_scope, user, check_location)
1828 check_scope, user, check_location)
1823 return False
1829 return False
1824
1830
1825 def _get_request(self):
1831 def _get_request(self):
1826 return get_request(self)
1832 return get_request(self)
1827
1833
1828 def _get_check_scope(self, cls_name):
1834 def _get_check_scope(self, cls_name):
1829 return {
1835 return {
1830 'HasPermissionAll': 'GLOBAL',
1836 'HasPermissionAll': 'GLOBAL',
1831 'HasPermissionAny': 'GLOBAL',
1837 'HasPermissionAny': 'GLOBAL',
1832 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1838 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1833 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1839 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1834 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1840 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1835 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1841 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1836 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1842 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1837 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1843 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1838 }.get(cls_name, '?:%s' % cls_name)
1844 }.get(cls_name, '?:%s' % cls_name)
1839
1845
1840 def check_permissions(self, user):
1846 def check_permissions(self, user):
1841 """Dummy function for overriding"""
1847 """Dummy function for overriding"""
1842 raise Exception('You have to write this function in child class')
1848 raise Exception('You have to write this function in child class')
1843
1849
1844
1850
1845 class HasPermissionAll(PermsFunction):
1851 class HasPermissionAll(PermsFunction):
1846 def check_permissions(self, user):
1852 def check_permissions(self, user):
1847 perms = user.permissions_with_scope({})
1853 perms = user.permissions_with_scope({})
1848 if self.required_perms.issubset(perms.get('global')):
1854 if self.required_perms.issubset(perms.get('global')):
1849 return True
1855 return True
1850 return False
1856 return False
1851
1857
1852
1858
1853 class HasPermissionAny(PermsFunction):
1859 class HasPermissionAny(PermsFunction):
1854 def check_permissions(self, user):
1860 def check_permissions(self, user):
1855 perms = user.permissions_with_scope({})
1861 perms = user.permissions_with_scope({})
1856 if self.required_perms.intersection(perms.get('global')):
1862 if self.required_perms.intersection(perms.get('global')):
1857 return True
1863 return True
1858 return False
1864 return False
1859
1865
1860
1866
1861 class HasRepoPermissionAll(PermsFunction):
1867 class HasRepoPermissionAll(PermsFunction):
1862 def __call__(self, repo_name=None, check_location='', user=None):
1868 def __call__(self, repo_name=None, check_location='', user=None):
1863 self.repo_name = repo_name
1869 self.repo_name = repo_name
1864 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1870 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1865
1871
1866 def _get_repo_name(self):
1872 def _get_repo_name(self):
1867 if not self.repo_name:
1873 if not self.repo_name:
1868 _request = self._get_request()
1874 _request = self._get_request()
1869 self.repo_name = get_repo_slug(_request)
1875 self.repo_name = get_repo_slug(_request)
1870 return self.repo_name
1876 return self.repo_name
1871
1877
1872 def check_permissions(self, user):
1878 def check_permissions(self, user):
1873 self.repo_name = self._get_repo_name()
1879 self.repo_name = self._get_repo_name()
1874 perms = user.permissions
1880 perms = user.permissions
1875 try:
1881 try:
1876 user_perms = set([perms['repositories'][self.repo_name]])
1882 user_perms = set([perms['repositories'][self.repo_name]])
1877 except KeyError:
1883 except KeyError:
1878 return False
1884 return False
1879 if self.required_perms.issubset(user_perms):
1885 if self.required_perms.issubset(user_perms):
1880 return True
1886 return True
1881 return False
1887 return False
1882
1888
1883
1889
1884 class HasRepoPermissionAny(PermsFunction):
1890 class HasRepoPermissionAny(PermsFunction):
1885 def __call__(self, repo_name=None, check_location='', user=None):
1891 def __call__(self, repo_name=None, check_location='', user=None):
1886 self.repo_name = repo_name
1892 self.repo_name = repo_name
1887 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1893 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1888
1894
1889 def _get_repo_name(self):
1895 def _get_repo_name(self):
1890 if not self.repo_name:
1896 if not self.repo_name:
1891 _request = self._get_request()
1897 _request = self._get_request()
1892 self.repo_name = get_repo_slug(_request)
1898 self.repo_name = get_repo_slug(_request)
1893 return self.repo_name
1899 return self.repo_name
1894
1900
1895 def check_permissions(self, user):
1901 def check_permissions(self, user):
1896 self.repo_name = self._get_repo_name()
1902 self.repo_name = self._get_repo_name()
1897 perms = user.permissions
1903 perms = user.permissions
1898 try:
1904 try:
1899 user_perms = set([perms['repositories'][self.repo_name]])
1905 user_perms = set([perms['repositories'][self.repo_name]])
1900 except KeyError:
1906 except KeyError:
1901 return False
1907 return False
1902 if self.required_perms.intersection(user_perms):
1908 if self.required_perms.intersection(user_perms):
1903 return True
1909 return True
1904 return False
1910 return False
1905
1911
1906
1912
1907 class HasRepoGroupPermissionAny(PermsFunction):
1913 class HasRepoGroupPermissionAny(PermsFunction):
1908 def __call__(self, group_name=None, check_location='', user=None):
1914 def __call__(self, group_name=None, check_location='', user=None):
1909 self.repo_group_name = group_name
1915 self.repo_group_name = group_name
1910 return super(HasRepoGroupPermissionAny, self).__call__(
1916 return super(HasRepoGroupPermissionAny, self).__call__(
1911 check_location, user)
1917 check_location, user)
1912
1918
1913 def check_permissions(self, user):
1919 def check_permissions(self, user):
1914 perms = user.permissions
1920 perms = user.permissions
1915 try:
1921 try:
1916 user_perms = set(
1922 user_perms = set(
1917 [perms['repositories_groups'][self.repo_group_name]])
1923 [perms['repositories_groups'][self.repo_group_name]])
1918 except KeyError:
1924 except KeyError:
1919 return False
1925 return False
1920 if self.required_perms.intersection(user_perms):
1926 if self.required_perms.intersection(user_perms):
1921 return True
1927 return True
1922 return False
1928 return False
1923
1929
1924
1930
1925 class HasRepoGroupPermissionAll(PermsFunction):
1931 class HasRepoGroupPermissionAll(PermsFunction):
1926 def __call__(self, group_name=None, check_location='', user=None):
1932 def __call__(self, group_name=None, check_location='', user=None):
1927 self.repo_group_name = group_name
1933 self.repo_group_name = group_name
1928 return super(HasRepoGroupPermissionAll, self).__call__(
1934 return super(HasRepoGroupPermissionAll, self).__call__(
1929 check_location, user)
1935 check_location, user)
1930
1936
1931 def check_permissions(self, user):
1937 def check_permissions(self, user):
1932 perms = user.permissions
1938 perms = user.permissions
1933 try:
1939 try:
1934 user_perms = set(
1940 user_perms = set(
1935 [perms['repositories_groups'][self.repo_group_name]])
1941 [perms['repositories_groups'][self.repo_group_name]])
1936 except KeyError:
1942 except KeyError:
1937 return False
1943 return False
1938 if self.required_perms.issubset(user_perms):
1944 if self.required_perms.issubset(user_perms):
1939 return True
1945 return True
1940 return False
1946 return False
1941
1947
1942
1948
1943 class HasUserGroupPermissionAny(PermsFunction):
1949 class HasUserGroupPermissionAny(PermsFunction):
1944 def __call__(self, user_group_name=None, check_location='', user=None):
1950 def __call__(self, user_group_name=None, check_location='', user=None):
1945 self.user_group_name = user_group_name
1951 self.user_group_name = user_group_name
1946 return super(HasUserGroupPermissionAny, self).__call__(
1952 return super(HasUserGroupPermissionAny, self).__call__(
1947 check_location, user)
1953 check_location, user)
1948
1954
1949 def check_permissions(self, user):
1955 def check_permissions(self, user):
1950 perms = user.permissions
1956 perms = user.permissions
1951 try:
1957 try:
1952 user_perms = set([perms['user_groups'][self.user_group_name]])
1958 user_perms = set([perms['user_groups'][self.user_group_name]])
1953 except KeyError:
1959 except KeyError:
1954 return False
1960 return False
1955 if self.required_perms.intersection(user_perms):
1961 if self.required_perms.intersection(user_perms):
1956 return True
1962 return True
1957 return False
1963 return False
1958
1964
1959
1965
1960 class HasUserGroupPermissionAll(PermsFunction):
1966 class HasUserGroupPermissionAll(PermsFunction):
1961 def __call__(self, user_group_name=None, check_location='', user=None):
1967 def __call__(self, user_group_name=None, check_location='', user=None):
1962 self.user_group_name = user_group_name
1968 self.user_group_name = user_group_name
1963 return super(HasUserGroupPermissionAll, self).__call__(
1969 return super(HasUserGroupPermissionAll, self).__call__(
1964 check_location, user)
1970 check_location, user)
1965
1971
1966 def check_permissions(self, user):
1972 def check_permissions(self, user):
1967 perms = user.permissions
1973 perms = user.permissions
1968 try:
1974 try:
1969 user_perms = set([perms['user_groups'][self.user_group_name]])
1975 user_perms = set([perms['user_groups'][self.user_group_name]])
1970 except KeyError:
1976 except KeyError:
1971 return False
1977 return False
1972 if self.required_perms.issubset(user_perms):
1978 if self.required_perms.issubset(user_perms):
1973 return True
1979 return True
1974 return False
1980 return False
1975
1981
1976
1982
1977 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1983 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1978 class HasPermissionAnyMiddleware(object):
1984 class HasPermissionAnyMiddleware(object):
1979 def __init__(self, *perms):
1985 def __init__(self, *perms):
1980 self.required_perms = set(perms)
1986 self.required_perms = set(perms)
1981
1987
1982 def __call__(self, user, repo_name):
1988 def __call__(self, user, repo_name):
1983 # repo_name MUST be unicode, since we handle keys in permission
1989 # repo_name MUST be unicode, since we handle keys in permission
1984 # dict by unicode
1990 # dict by unicode
1985 repo_name = safe_unicode(repo_name)
1991 repo_name = safe_unicode(repo_name)
1986 user = AuthUser(user.user_id)
1992 user = AuthUser(user.user_id)
1987 log.debug(
1993 log.debug(
1988 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1994 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1989 self.required_perms, user, repo_name)
1995 self.required_perms, user, repo_name)
1990
1996
1991 if self.check_permissions(user, repo_name):
1997 if self.check_permissions(user, repo_name):
1992 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1998 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1993 repo_name, user, 'PermissionMiddleware')
1999 repo_name, user, 'PermissionMiddleware')
1994 return True
2000 return True
1995
2001
1996 else:
2002 else:
1997 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
2003 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1998 repo_name, user, 'PermissionMiddleware')
2004 repo_name, user, 'PermissionMiddleware')
1999 return False
2005 return False
2000
2006
2001 def check_permissions(self, user, repo_name):
2007 def check_permissions(self, user, repo_name):
2002 perms = user.permissions_with_scope({'repo_name': repo_name})
2008 perms = user.permissions_with_scope({'repo_name': repo_name})
2003
2009
2004 try:
2010 try:
2005 user_perms = set([perms['repositories'][repo_name]])
2011 user_perms = set([perms['repositories'][repo_name]])
2006 except Exception:
2012 except Exception:
2007 log.exception('Error while accessing user permissions')
2013 log.exception('Error while accessing user permissions')
2008 return False
2014 return False
2009
2015
2010 if self.required_perms.intersection(user_perms):
2016 if self.required_perms.intersection(user_perms):
2011 return True
2017 return True
2012 return False
2018 return False
2013
2019
2014
2020
2015 # SPECIAL VERSION TO HANDLE API AUTH
2021 # SPECIAL VERSION TO HANDLE API AUTH
2016 class _BaseApiPerm(object):
2022 class _BaseApiPerm(object):
2017 def __init__(self, *perms):
2023 def __init__(self, *perms):
2018 self.required_perms = set(perms)
2024 self.required_perms = set(perms)
2019
2025
2020 def __call__(self, check_location=None, user=None, repo_name=None,
2026 def __call__(self, check_location=None, user=None, repo_name=None,
2021 group_name=None, user_group_name=None):
2027 group_name=None, user_group_name=None):
2022 cls_name = self.__class__.__name__
2028 cls_name = self.__class__.__name__
2023 check_scope = 'global:%s' % (self.required_perms,)
2029 check_scope = 'global:%s' % (self.required_perms,)
2024 if repo_name:
2030 if repo_name:
2025 check_scope += ', repo_name:%s' % (repo_name,)
2031 check_scope += ', repo_name:%s' % (repo_name,)
2026
2032
2027 if group_name:
2033 if group_name:
2028 check_scope += ', repo_group_name:%s' % (group_name,)
2034 check_scope += ', repo_group_name:%s' % (group_name,)
2029
2035
2030 if user_group_name:
2036 if user_group_name:
2031 check_scope += ', user_group_name:%s' % (user_group_name,)
2037 check_scope += ', user_group_name:%s' % (user_group_name,)
2032
2038
2033 log.debug(
2039 log.debug(
2034 'checking cls:%s %s %s @ %s'
2040 'checking cls:%s %s %s @ %s'
2035 % (cls_name, self.required_perms, check_scope, check_location))
2041 % (cls_name, self.required_perms, check_scope, check_location))
2036 if not user:
2042 if not user:
2037 log.debug('Empty User passed into arguments')
2043 log.debug('Empty User passed into arguments')
2038 return False
2044 return False
2039
2045
2040 # process user
2046 # process user
2041 if not isinstance(user, AuthUser):
2047 if not isinstance(user, AuthUser):
2042 user = AuthUser(user.user_id)
2048 user = AuthUser(user.user_id)
2043 if not check_location:
2049 if not check_location:
2044 check_location = 'unspecified'
2050 check_location = 'unspecified'
2045 if self.check_permissions(user.permissions, repo_name, group_name,
2051 if self.check_permissions(user.permissions, repo_name, group_name,
2046 user_group_name):
2052 user_group_name):
2047 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2053 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2048 check_scope, user, check_location)
2054 check_scope, user, check_location)
2049 return True
2055 return True
2050
2056
2051 else:
2057 else:
2052 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2058 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2053 check_scope, user, check_location)
2059 check_scope, user, check_location)
2054 return False
2060 return False
2055
2061
2056 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2062 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2057 user_group_name=None):
2063 user_group_name=None):
2058 """
2064 """
2059 implement in child class should return True if permissions are ok,
2065 implement in child class should return True if permissions are ok,
2060 False otherwise
2066 False otherwise
2061
2067
2062 :param perm_defs: dict with permission definitions
2068 :param perm_defs: dict with permission definitions
2063 :param repo_name: repo name
2069 :param repo_name: repo name
2064 """
2070 """
2065 raise NotImplementedError()
2071 raise NotImplementedError()
2066
2072
2067
2073
2068 class HasPermissionAllApi(_BaseApiPerm):
2074 class HasPermissionAllApi(_BaseApiPerm):
2069 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2075 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2070 user_group_name=None):
2076 user_group_name=None):
2071 if self.required_perms.issubset(perm_defs.get('global')):
2077 if self.required_perms.issubset(perm_defs.get('global')):
2072 return True
2078 return True
2073 return False
2079 return False
2074
2080
2075
2081
2076 class HasPermissionAnyApi(_BaseApiPerm):
2082 class HasPermissionAnyApi(_BaseApiPerm):
2077 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2083 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2078 user_group_name=None):
2084 user_group_name=None):
2079 if self.required_perms.intersection(perm_defs.get('global')):
2085 if self.required_perms.intersection(perm_defs.get('global')):
2080 return True
2086 return True
2081 return False
2087 return False
2082
2088
2083
2089
2084 class HasRepoPermissionAllApi(_BaseApiPerm):
2090 class HasRepoPermissionAllApi(_BaseApiPerm):
2085 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2091 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2086 user_group_name=None):
2092 user_group_name=None):
2087 try:
2093 try:
2088 _user_perms = set([perm_defs['repositories'][repo_name]])
2094 _user_perms = set([perm_defs['repositories'][repo_name]])
2089 except KeyError:
2095 except KeyError:
2090 log.warning(traceback.format_exc())
2096 log.warning(traceback.format_exc())
2091 return False
2097 return False
2092 if self.required_perms.issubset(_user_perms):
2098 if self.required_perms.issubset(_user_perms):
2093 return True
2099 return True
2094 return False
2100 return False
2095
2101
2096
2102
2097 class HasRepoPermissionAnyApi(_BaseApiPerm):
2103 class HasRepoPermissionAnyApi(_BaseApiPerm):
2098 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2104 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2099 user_group_name=None):
2105 user_group_name=None):
2100 try:
2106 try:
2101 _user_perms = set([perm_defs['repositories'][repo_name]])
2107 _user_perms = set([perm_defs['repositories'][repo_name]])
2102 except KeyError:
2108 except KeyError:
2103 log.warning(traceback.format_exc())
2109 log.warning(traceback.format_exc())
2104 return False
2110 return False
2105 if self.required_perms.intersection(_user_perms):
2111 if self.required_perms.intersection(_user_perms):
2106 return True
2112 return True
2107 return False
2113 return False
2108
2114
2109
2115
2110 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2116 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2111 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2117 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2112 user_group_name=None):
2118 user_group_name=None):
2113 try:
2119 try:
2114 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2120 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2115 except KeyError:
2121 except KeyError:
2116 log.warning(traceback.format_exc())
2122 log.warning(traceback.format_exc())
2117 return False
2123 return False
2118 if self.required_perms.intersection(_user_perms):
2124 if self.required_perms.intersection(_user_perms):
2119 return True
2125 return True
2120 return False
2126 return False
2121
2127
2122
2128
2123 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2129 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2124 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2130 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2125 user_group_name=None):
2131 user_group_name=None):
2126 try:
2132 try:
2127 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2133 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2128 except KeyError:
2134 except KeyError:
2129 log.warning(traceback.format_exc())
2135 log.warning(traceback.format_exc())
2130 return False
2136 return False
2131 if self.required_perms.issubset(_user_perms):
2137 if self.required_perms.issubset(_user_perms):
2132 return True
2138 return True
2133 return False
2139 return False
2134
2140
2135
2141
2136 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2142 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2137 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2143 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2138 user_group_name=None):
2144 user_group_name=None):
2139 try:
2145 try:
2140 _user_perms = set([perm_defs['user_groups'][user_group_name]])
2146 _user_perms = set([perm_defs['user_groups'][user_group_name]])
2141 except KeyError:
2147 except KeyError:
2142 log.warning(traceback.format_exc())
2148 log.warning(traceback.format_exc())
2143 return False
2149 return False
2144 if self.required_perms.intersection(_user_perms):
2150 if self.required_perms.intersection(_user_perms):
2145 return True
2151 return True
2146 return False
2152 return False
2147
2153
2148
2154
2149 def check_ip_access(source_ip, allowed_ips=None):
2155 def check_ip_access(source_ip, allowed_ips=None):
2150 """
2156 """
2151 Checks if source_ip is a subnet of any of allowed_ips.
2157 Checks if source_ip is a subnet of any of allowed_ips.
2152
2158
2153 :param source_ip:
2159 :param source_ip:
2154 :param allowed_ips: list of allowed ips together with mask
2160 :param allowed_ips: list of allowed ips together with mask
2155 """
2161 """
2156 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
2162 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
2157 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2163 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2158 if isinstance(allowed_ips, (tuple, list, set)):
2164 if isinstance(allowed_ips, (tuple, list, set)):
2159 for ip in allowed_ips:
2165 for ip in allowed_ips:
2160 ip = safe_unicode(ip)
2166 ip = safe_unicode(ip)
2161 try:
2167 try:
2162 network_address = ipaddress.ip_network(ip, strict=False)
2168 network_address = ipaddress.ip_network(ip, strict=False)
2163 if source_ip_address in network_address:
2169 if source_ip_address in network_address:
2164 log.debug('IP %s is network %s' %
2170 log.debug('IP %s is network %s' %
2165 (source_ip_address, network_address))
2171 (source_ip_address, network_address))
2166 return True
2172 return True
2167 # for any case we cannot determine the IP, don't crash just
2173 # for any case we cannot determine the IP, don't crash just
2168 # skip it and log as error, we want to say forbidden still when
2174 # skip it and log as error, we want to say forbidden still when
2169 # sending bad IP
2175 # sending bad IP
2170 except Exception:
2176 except Exception:
2171 log.error(traceback.format_exc())
2177 log.error(traceback.format_exc())
2172 continue
2178 continue
2173 return False
2179 return False
2174
2180
2175
2181
2176 def get_cython_compat_decorator(wrapper, func):
2182 def get_cython_compat_decorator(wrapper, func):
2177 """
2183 """
2178 Creates a cython compatible decorator. The previously used
2184 Creates a cython compatible decorator. The previously used
2179 decorator.decorator() function seems to be incompatible with cython.
2185 decorator.decorator() function seems to be incompatible with cython.
2180
2186
2181 :param wrapper: __wrapper method of the decorator class
2187 :param wrapper: __wrapper method of the decorator class
2182 :param func: decorated function
2188 :param func: decorated function
2183 """
2189 """
2184 @wraps(func)
2190 @wraps(func)
2185 def local_wrapper(*args, **kwds):
2191 def local_wrapper(*args, **kwds):
2186 return wrapper(func, *args, **kwds)
2192 return wrapper(func, *args, **kwds)
2187 local_wrapper.__wrapped__ = func
2193 local_wrapper.__wrapped__ = func
2188 return local_wrapper
2194 return local_wrapper
2189
2195
2190
2196
@@ -1,690 +1,690 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 0.0.0.0
46 host = 0.0.0.0
47 port = 5000
47 port = 5000
48
48
49 ##########################
49 ##########################
50 ## GUNICORN WSGI SERVER ##
50 ## GUNICORN WSGI SERVER ##
51 ##########################
51 ##########################
52 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
52 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
53
53
54 use = egg:gunicorn#main
54 use = egg:gunicorn#main
55 ## Sets the number of process workers. You must set `instance_id = *`
55 ## Sets the number of process workers. You must set `instance_id = *`
56 ## when this option is set to more than one worker, recommended
56 ## when this option is set to more than one worker, recommended
57 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
57 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
58 ## The `instance_id = *` must be set in the [app:main] section below
58 ## The `instance_id = *` must be set in the [app:main] section below
59 #workers = 2
59 #workers = 2
60 ## number of threads for each of the worker, must be set to 1 for gevent
60 ## number of threads for each of the worker, must be set to 1 for gevent
61 ## generally recommened to be at 1
61 ## generally recommened to be at 1
62 #threads = 1
62 #threads = 1
63 ## process name
63 ## process name
64 #proc_name = rhodecode
64 #proc_name = rhodecode
65 ## type of worker class, one of sync, gevent
65 ## type of worker class, one of sync, gevent
66 ## recommended for bigger setup is using of of other than sync one
66 ## recommended for bigger setup is using of of other than sync one
67 #worker_class = sync
67 #worker_class = sync
68 ## The maximum number of simultaneous clients. Valid only for Gevent
68 ## The maximum number of simultaneous clients. Valid only for Gevent
69 #worker_connections = 10
69 #worker_connections = 10
70 ## max number of requests that worker will handle before being gracefully
70 ## max number of requests that worker will handle before being gracefully
71 ## restarted, could prevent memory leaks
71 ## restarted, could prevent memory leaks
72 #max_requests = 1000
72 #max_requests = 1000
73 #max_requests_jitter = 30
73 #max_requests_jitter = 30
74 ## amount of time a worker can spend with handling a request before it
74 ## amount of time a worker can spend with handling a request before it
75 ## gets killed and restarted. Set to 6hrs
75 ## gets killed and restarted. Set to 6hrs
76 #timeout = 21600
76 #timeout = 21600
77
77
78 ## prefix middleware for RhodeCode.
78 ## prefix middleware for RhodeCode.
79 ## recommended when using proxy setup.
79 ## recommended when using proxy setup.
80 ## allows to set RhodeCode under a prefix in server.
80 ## allows to set RhodeCode under a prefix in server.
81 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
81 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
82 ## And set your prefix like: `prefix = /custom_prefix`
82 ## And set your prefix like: `prefix = /custom_prefix`
83 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
83 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
84 ## to make your cookies only work on prefix url
84 ## to make your cookies only work on prefix url
85 [filter:proxy-prefix]
85 [filter:proxy-prefix]
86 use = egg:PasteDeploy#prefix
86 use = egg:PasteDeploy#prefix
87 prefix = /
87 prefix = /
88
88
89 [app:main]
89 [app:main]
90 is_test = True
90 is_test = True
91 use = egg:rhodecode-enterprise-ce
91 use = egg:rhodecode-enterprise-ce
92
92
93 ## enable proxy prefix middleware, defined above
93 ## enable proxy prefix middleware, defined above
94 #filter-with = proxy-prefix
94 #filter-with = proxy-prefix
95
95
96
96
97 ## RHODECODE PLUGINS ##
97 ## RHODECODE PLUGINS ##
98 rhodecode.includes = rhodecode.api
98 rhodecode.includes = rhodecode.api
99
99
100 # api prefix url
100 # api prefix url
101 rhodecode.api.url = /_admin/api
101 rhodecode.api.url = /_admin/api
102
102
103
103
104 ## END RHODECODE PLUGINS ##
104 ## END RHODECODE PLUGINS ##
105
105
106 ## encryption key used to encrypt social plugin tokens,
106 ## encryption key used to encrypt social plugin tokens,
107 ## remote_urls with credentials etc, if not set it defaults to
107 ## remote_urls with credentials etc, if not set it defaults to
108 ## `beaker.session.secret`
108 ## `beaker.session.secret`
109 #rhodecode.encrypted_values.secret =
109 #rhodecode.encrypted_values.secret =
110
110
111 ## decryption strict mode (enabled by default). It controls if decryption raises
111 ## decryption strict mode (enabled by default). It controls if decryption raises
112 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
112 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
113 #rhodecode.encrypted_values.strict = false
113 #rhodecode.encrypted_values.strict = false
114
114
115 ## return gzipped responses from Rhodecode (static files/application)
115 ## return gzipped responses from Rhodecode (static files/application)
116 gzip_responses = false
116 gzip_responses = false
117
117
118 ## autogenerate javascript routes file on startup
118 ## autogenerate javascript routes file on startup
119 generate_js_files = false
119 generate_js_files = false
120
120
121 ## Optional Languages
121 ## Optional Languages
122 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
122 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
123 lang = en
123 lang = en
124
124
125 ## perform a full repository scan on each server start, this should be
125 ## perform a full repository scan on each server start, this should be
126 ## set to false after first startup, to allow faster server restarts.
126 ## set to false after first startup, to allow faster server restarts.
127 startup.import_repos = true
127 startup.import_repos = true
128
128
129 ## Uncomment and set this path to use archive download cache.
129 ## Uncomment and set this path to use archive download cache.
130 ## Once enabled, generated archives will be cached at this location
130 ## Once enabled, generated archives will be cached at this location
131 ## and served from the cache during subsequent requests for the same archive of
131 ## and served from the cache during subsequent requests for the same archive of
132 ## the repository.
132 ## the repository.
133 #archive_cache_dir = /tmp/tarballcache
133 #archive_cache_dir = /tmp/tarballcache
134
134
135 ## URL at which the application is running. This is used for bootstraping
135 ## URL at which the application is running. This is used for bootstraping
136 ## requests in context when no web request is available. Used in ishell, or
136 ## requests in context when no web request is available. Used in ishell, or
137 ## SSH calls. Set this for events to receive proper url for SSH calls.
137 ## SSH calls. Set this for events to receive proper url for SSH calls.
138 app.base_url = http://rhodecode.local
138 app.base_url = http://rhodecode.local
139
139
140 ## change this to unique ID for security
140 ## change this to unique ID for security
141 app_instance_uuid = rc-production
141 app_instance_uuid = rc-production
142
142
143 ## cut off limit for large diffs (size in bytes)
143 ## cut off limit for large diffs (size in bytes)
144 cut_off_limit_diff = 1024000
144 cut_off_limit_diff = 1024000
145 cut_off_limit_file = 256000
145 cut_off_limit_file = 256000
146
146
147 ## use cache version of scm repo everywhere
147 ## use cache version of scm repo everywhere
148 vcs_full_cache = false
148 vcs_full_cache = false
149
149
150 ## force https in RhodeCode, fixes https redirects, assumes it's always https
150 ## force https in RhodeCode, fixes https redirects, assumes it's always https
151 ## Normally this is controlled by proper http flags sent from http server
151 ## Normally this is controlled by proper http flags sent from http server
152 force_https = false
152 force_https = false
153
153
154 ## use Strict-Transport-Security headers
154 ## use Strict-Transport-Security headers
155 use_htsts = false
155 use_htsts = false
156
156
157 ## git rev filter option, --all is the default filter, if you need to
157 ## git rev filter option, --all is the default filter, if you need to
158 ## hide all refs in changelog switch this to --branches --tags
158 ## hide all refs in changelog switch this to --branches --tags
159 git_rev_filter = --all
159 git_rev_filter = --all
160
160
161 # Set to true if your repos are exposed using the dumb protocol
161 # Set to true if your repos are exposed using the dumb protocol
162 git_update_server_info = false
162 git_update_server_info = false
163
163
164 ## RSS/ATOM feed options
164 ## RSS/ATOM feed options
165 rss_cut_off_limit = 256000
165 rss_cut_off_limit = 256000
166 rss_items_per_page = 10
166 rss_items_per_page = 10
167 rss_include_diff = false
167 rss_include_diff = false
168
168
169 ## gist URL alias, used to create nicer urls for gist. This should be an
169 ## gist URL alias, used to create nicer urls for gist. This should be an
170 ## url that does rewrites to _admin/gists/{gistid}.
170 ## url that does rewrites to _admin/gists/{gistid}.
171 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
171 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
172 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
172 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
173 gist_alias_url =
173 gist_alias_url =
174
174
175 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
175 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
176 ## used for access.
176 ## used for access.
177 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
177 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
178 ## came from the the logged in user who own this authentication token.
178 ## came from the the logged in user who own this authentication token.
179 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
179 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
180 ## authentication token. Such view would be only accessible when used together
180 ## authentication token. Such view would be only accessible when used together
181 ## with this authentication token
181 ## with this authentication token
182 ##
182 ##
183 ## list of all views can be found under `/_admin/permissions/auth_token_access`
183 ## list of all views can be found under `/_admin/permissions/auth_token_access`
184 ## The list should be "," separated and on a single line.
184 ## The list should be "," separated and on a single line.
185 ##
185 ##
186 ## Most common views to enable:
186 ## Most common views to enable:
187 # RepoCommitsView:repo_commit_download
187 # RepoCommitsView:repo_commit_download
188 # RepoCommitsView:repo_commit_patch
188 # RepoCommitsView:repo_commit_patch
189 # RepoCommitsView:repo_commit_raw
189 # RepoCommitsView:repo_commit_raw
190 # RepoCommitsView:repo_commit_raw@TOKEN
190 # RepoCommitsView:repo_commit_raw@TOKEN
191 # RepoFilesView:repo_files_diff
191 # RepoFilesView:repo_files_diff
192 # RepoFilesView:repo_archivefile
192 # RepoFilesView:repo_archivefile
193 # RepoFilesView:repo_file_raw
193 # RepoFilesView:repo_file_raw
194 # GistView:*
194 # GistView:*
195 api_access_controllers_whitelist =
195 api_access_controllers_whitelist =
196
196
197 ## default encoding used to convert from and to unicode
197 ## default encoding used to convert from and to unicode
198 ## can be also a comma separated list of encoding in case of mixed encodings
198 ## can be also a comma separated list of encoding in case of mixed encodings
199 default_encoding = UTF-8
199 default_encoding = UTF-8
200
200
201 ## instance-id prefix
201 ## instance-id prefix
202 ## a prefix key for this instance used for cache invalidation when running
202 ## a prefix key for this instance used for cache invalidation when running
203 ## multiple instances of rhodecode, make sure it's globally unique for
203 ## multiple instances of rhodecode, make sure it's globally unique for
204 ## all running rhodecode instances. Leave empty if you don't use it
204 ## all running rhodecode instances. Leave empty if you don't use it
205 instance_id =
205 instance_id =
206
206
207 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
207 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
208 ## of an authentication plugin also if it is disabled by it's settings.
208 ## of an authentication plugin also if it is disabled by it's settings.
209 ## This could be useful if you are unable to log in to the system due to broken
209 ## This could be useful if you are unable to log in to the system due to broken
210 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
210 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
211 ## module to log in again and fix the settings.
211 ## module to log in again and fix the settings.
212 ##
212 ##
213 ## Available builtin plugin IDs (hash is part of the ID):
213 ## Available builtin plugin IDs (hash is part of the ID):
214 ## egg:rhodecode-enterprise-ce#rhodecode
214 ## egg:rhodecode-enterprise-ce#rhodecode
215 ## egg:rhodecode-enterprise-ce#pam
215 ## egg:rhodecode-enterprise-ce#pam
216 ## egg:rhodecode-enterprise-ce#ldap
216 ## egg:rhodecode-enterprise-ce#ldap
217 ## egg:rhodecode-enterprise-ce#jasig_cas
217 ## egg:rhodecode-enterprise-ce#jasig_cas
218 ## egg:rhodecode-enterprise-ce#headers
218 ## egg:rhodecode-enterprise-ce#headers
219 ## egg:rhodecode-enterprise-ce#crowd
219 ## egg:rhodecode-enterprise-ce#crowd
220 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
220 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
221
221
222 ## alternative return HTTP header for failed authentication. Default HTTP
222 ## alternative return HTTP header for failed authentication. Default HTTP
223 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
223 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
224 ## handling that causing a series of failed authentication calls.
224 ## handling that causing a series of failed authentication calls.
225 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
225 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
226 ## This will be served instead of default 401 on bad authnetication
226 ## This will be served instead of default 401 on bad authnetication
227 auth_ret_code =
227 auth_ret_code =
228
228
229 ## use special detection method when serving auth_ret_code, instead of serving
229 ## use special detection method when serving auth_ret_code, instead of serving
230 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
230 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
231 ## and then serve auth_ret_code to clients
231 ## and then serve auth_ret_code to clients
232 auth_ret_code_detection = false
232 auth_ret_code_detection = false
233
233
234 ## locking return code. When repository is locked return this HTTP code. 2XX
234 ## locking return code. When repository is locked return this HTTP code. 2XX
235 ## codes don't break the transactions while 4XX codes do
235 ## codes don't break the transactions while 4XX codes do
236 lock_ret_code = 423
236 lock_ret_code = 423
237
237
238 ## allows to change the repository location in settings page
238 ## allows to change the repository location in settings page
239 allow_repo_location_change = true
239 allow_repo_location_change = true
240
240
241 ## allows to setup custom hooks in settings page
241 ## allows to setup custom hooks in settings page
242 allow_custom_hooks_settings = true
242 allow_custom_hooks_settings = true
243
243
244 ## generated license token, goto license page in RhodeCode settings to obtain
244 ## generated license token, goto license page in RhodeCode settings to obtain
245 ## new token
245 ## new token
246 license_token = abra-cada-bra1-rce3
246 license_token = abra-cada-bra1-rce3
247
247
248 ## supervisor connection uri, for managing supervisor and logs.
248 ## supervisor connection uri, for managing supervisor and logs.
249 supervisor.uri =
249 supervisor.uri =
250 ## supervisord group name/id we only want this RC instance to handle
250 ## supervisord group name/id we only want this RC instance to handle
251 supervisor.group_id = dev
251 supervisor.group_id = dev
252
252
253 ## Display extended labs settings
253 ## Display extended labs settings
254 labs_settings_active = true
254 labs_settings_active = true
255
255
256 ####################################
256 ####################################
257 ### CELERY CONFIG ####
257 ### CELERY CONFIG ####
258 ####################################
258 ####################################
259 use_celery = false
259 use_celery = false
260 broker.host = localhost
260 broker.host = localhost
261 broker.vhost = rabbitmqhost
261 broker.vhost = rabbitmqhost
262 broker.port = 5672
262 broker.port = 5672
263 broker.user = rabbitmq
263 broker.user = rabbitmq
264 broker.password = qweqwe
264 broker.password = qweqwe
265
265
266 celery.imports = rhodecode.lib.celerylib.tasks
266 celery.imports = rhodecode.lib.celerylib.tasks
267
267
268 celery.result.backend = amqp
268 celery.result.backend = amqp
269 celery.result.dburi = amqp://
269 celery.result.dburi = amqp://
270 celery.result.serialier = json
270 celery.result.serialier = json
271
271
272 #celery.send.task.error.emails = true
272 #celery.send.task.error.emails = true
273 #celery.amqp.task.result.expires = 18000
273 #celery.amqp.task.result.expires = 18000
274
274
275 celeryd.concurrency = 2
275 celeryd.concurrency = 2
276 #celeryd.log.file = celeryd.log
276 #celeryd.log.file = celeryd.log
277 celeryd.log.level = debug
277 celeryd.log.level = debug
278 celeryd.max.tasks.per.child = 1
278 celeryd.max.tasks.per.child = 1
279
279
280 ## tasks will never be sent to the queue, but executed locally instead.
280 ## tasks will never be sent to the queue, but executed locally instead.
281 celery.always.eager = false
281 celery.always.eager = false
282
282
283 ####################################
283 ####################################
284 ### BEAKER CACHE ####
284 ### BEAKER CACHE ####
285 ####################################
285 ####################################
286 # default cache dir for templates. Putting this into a ramdisk
286 # default cache dir for templates. Putting this into a ramdisk
287 ## can boost performance, eg. %(here)s/data_ramdisk
287 ## can boost performance, eg. %(here)s/data_ramdisk
288 cache_dir = %(here)s/data
288 cache_dir = %(here)s/data
289
289
290 ## locking and default file storage for Beaker. Putting this into a ramdisk
290 ## locking and default file storage for Beaker. Putting this into a ramdisk
291 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
291 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
292 beaker.cache.data_dir = %(here)s/rc/data/cache/beaker_data
292 beaker.cache.data_dir = %(here)s/rc/data/cache/beaker_data
293 beaker.cache.lock_dir = %(here)s/rc/data/cache/beaker_lock
293 beaker.cache.lock_dir = %(here)s/rc/data/cache/beaker_lock
294
294
295 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
295 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
296
296
297 beaker.cache.super_short_term.type = memory
297 beaker.cache.super_short_term.type = memory
298 beaker.cache.super_short_term.expire = 1
298 beaker.cache.super_short_term.expire = 1
299 beaker.cache.super_short_term.key_length = 256
299 beaker.cache.super_short_term.key_length = 256
300
300
301 beaker.cache.short_term.type = memory
301 beaker.cache.short_term.type = file
302 beaker.cache.short_term.expire = 60
302 beaker.cache.short_term.expire = 0
303 beaker.cache.short_term.key_length = 256
303 beaker.cache.short_term.key_length = 256
304
304
305 beaker.cache.long_term.type = memory
305 beaker.cache.long_term.type = memory
306 beaker.cache.long_term.expire = 36000
306 beaker.cache.long_term.expire = 36000
307 beaker.cache.long_term.key_length = 256
307 beaker.cache.long_term.key_length = 256
308
308
309 beaker.cache.sql_cache_short.type = memory
309 beaker.cache.sql_cache_short.type = memory
310 beaker.cache.sql_cache_short.expire = 1
310 beaker.cache.sql_cache_short.expire = 1
311 beaker.cache.sql_cache_short.key_length = 256
311 beaker.cache.sql_cache_short.key_length = 256
312
312
313 ## default is memory cache, configure only if required
313 ## default is memory cache, configure only if required
314 ## using multi-node or multi-worker setup
314 ## using multi-node or multi-worker setup
315 #beaker.cache.auth_plugins.type = memory
315 #beaker.cache.auth_plugins.type = memory
316 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
316 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
317 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
317 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
318 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
318 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
319 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
319 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
320 #beaker.cache.auth_plugins.sa.pool_size = 10
320 #beaker.cache.auth_plugins.sa.pool_size = 10
321 #beaker.cache.auth_plugins.sa.max_overflow = 0
321 #beaker.cache.auth_plugins.sa.max_overflow = 0
322
322
323 beaker.cache.repo_cache_long.type = memorylru_base
323 beaker.cache.repo_cache_long.type = memorylru_base
324 beaker.cache.repo_cache_long.max_items = 4096
324 beaker.cache.repo_cache_long.max_items = 4096
325 beaker.cache.repo_cache_long.expire = 2592000
325 beaker.cache.repo_cache_long.expire = 2592000
326
326
327 ## default is memorylru_base cache, configure only if required
327 ## default is memorylru_base cache, configure only if required
328 ## using multi-node or multi-worker setup
328 ## using multi-node or multi-worker setup
329 #beaker.cache.repo_cache_long.type = ext:memcached
329 #beaker.cache.repo_cache_long.type = ext:memcached
330 #beaker.cache.repo_cache_long.url = localhost:11211
330 #beaker.cache.repo_cache_long.url = localhost:11211
331 #beaker.cache.repo_cache_long.expire = 1209600
331 #beaker.cache.repo_cache_long.expire = 1209600
332 #beaker.cache.repo_cache_long.key_length = 256
332 #beaker.cache.repo_cache_long.key_length = 256
333
333
334 ####################################
334 ####################################
335 ### BEAKER SESSION ####
335 ### BEAKER SESSION ####
336 ####################################
336 ####################################
337
337
338 ## .session.type is type of storage options for the session, current allowed
338 ## .session.type is type of storage options for the session, current allowed
339 ## types are file, ext:memcached, ext:database, and memory (default).
339 ## types are file, ext:memcached, ext:database, and memory (default).
340 beaker.session.type = file
340 beaker.session.type = file
341 beaker.session.data_dir = %(here)s/rc/data/sessions/data
341 beaker.session.data_dir = %(here)s/rc/data/sessions/data
342
342
343 ## db based session, fast, and allows easy management over logged in users
343 ## db based session, fast, and allows easy management over logged in users
344 #beaker.session.type = ext:database
344 #beaker.session.type = ext:database
345 #beaker.session.table_name = db_session
345 #beaker.session.table_name = db_session
346 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
346 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
347 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
347 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
348 #beaker.session.sa.pool_recycle = 3600
348 #beaker.session.sa.pool_recycle = 3600
349 #beaker.session.sa.echo = false
349 #beaker.session.sa.echo = false
350
350
351 beaker.session.key = rhodecode
351 beaker.session.key = rhodecode
352 beaker.session.secret = test-rc-uytcxaz
352 beaker.session.secret = test-rc-uytcxaz
353 beaker.session.lock_dir = %(here)s/rc/data/sessions/lock
353 beaker.session.lock_dir = %(here)s/rc/data/sessions/lock
354
354
355 ## Secure encrypted cookie. Requires AES and AES python libraries
355 ## Secure encrypted cookie. Requires AES and AES python libraries
356 ## you must disable beaker.session.secret to use this
356 ## you must disable beaker.session.secret to use this
357 #beaker.session.encrypt_key = key_for_encryption
357 #beaker.session.encrypt_key = key_for_encryption
358 #beaker.session.validate_key = validation_key
358 #beaker.session.validate_key = validation_key
359
359
360 ## sets session as invalid(also logging out user) if it haven not been
360 ## sets session as invalid(also logging out user) if it haven not been
361 ## accessed for given amount of time in seconds
361 ## accessed for given amount of time in seconds
362 beaker.session.timeout = 2592000
362 beaker.session.timeout = 2592000
363 beaker.session.httponly = true
363 beaker.session.httponly = true
364 ## Path to use for the cookie. Set to prefix if you use prefix middleware
364 ## Path to use for the cookie. Set to prefix if you use prefix middleware
365 #beaker.session.cookie_path = /custom_prefix
365 #beaker.session.cookie_path = /custom_prefix
366
366
367 ## uncomment for https secure cookie
367 ## uncomment for https secure cookie
368 beaker.session.secure = false
368 beaker.session.secure = false
369
369
370 ## auto save the session to not to use .save()
370 ## auto save the session to not to use .save()
371 beaker.session.auto = false
371 beaker.session.auto = false
372
372
373 ## default cookie expiration time in seconds, set to `true` to set expire
373 ## default cookie expiration time in seconds, set to `true` to set expire
374 ## at browser close
374 ## at browser close
375 #beaker.session.cookie_expires = 3600
375 #beaker.session.cookie_expires = 3600
376
376
377 ###################################
377 ###################################
378 ## SEARCH INDEXING CONFIGURATION ##
378 ## SEARCH INDEXING CONFIGURATION ##
379 ###################################
379 ###################################
380 ## Full text search indexer is available in rhodecode-tools under
380 ## Full text search indexer is available in rhodecode-tools under
381 ## `rhodecode-tools index` command
381 ## `rhodecode-tools index` command
382
382
383 ## WHOOSH Backend, doesn't require additional services to run
383 ## WHOOSH Backend, doesn't require additional services to run
384 ## it works good with few dozen repos
384 ## it works good with few dozen repos
385 search.module = rhodecode.lib.index.whoosh
385 search.module = rhodecode.lib.index.whoosh
386 search.location = %(here)s/data/index
386 search.location = %(here)s/data/index
387
387
388 ########################################
388 ########################################
389 ### CHANNELSTREAM CONFIG ####
389 ### CHANNELSTREAM CONFIG ####
390 ########################################
390 ########################################
391 ## channelstream enables persistent connections and live notification
391 ## channelstream enables persistent connections and live notification
392 ## in the system. It's also used by the chat system
392 ## in the system. It's also used by the chat system
393
393
394 channelstream.enabled = false
394 channelstream.enabled = false
395
395
396 ## server address for channelstream server on the backend
396 ## server address for channelstream server on the backend
397 channelstream.server = 127.0.0.1:9800
397 channelstream.server = 127.0.0.1:9800
398 ## location of the channelstream server from outside world
398 ## location of the channelstream server from outside world
399 ## use ws:// for http or wss:// for https. This address needs to be handled
399 ## use ws:// for http or wss:// for https. This address needs to be handled
400 ## by external HTTP server such as Nginx or Apache
400 ## by external HTTP server such as Nginx or Apache
401 ## see nginx/apache configuration examples in our docs
401 ## see nginx/apache configuration examples in our docs
402 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
402 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
403 channelstream.secret = secret
403 channelstream.secret = secret
404 channelstream.history.location = %(here)s/channelstream_history
404 channelstream.history.location = %(here)s/channelstream_history
405
405
406 ## Internal application path that Javascript uses to connect into.
406 ## Internal application path that Javascript uses to connect into.
407 ## If you use proxy-prefix the prefix should be added before /_channelstream
407 ## If you use proxy-prefix the prefix should be added before /_channelstream
408 channelstream.proxy_path = /_channelstream
408 channelstream.proxy_path = /_channelstream
409
409
410
410
411 ###################################
411 ###################################
412 ## APPENLIGHT CONFIG ##
412 ## APPENLIGHT CONFIG ##
413 ###################################
413 ###################################
414
414
415 ## Appenlight is tailored to work with RhodeCode, see
415 ## Appenlight is tailored to work with RhodeCode, see
416 ## http://appenlight.com for details how to obtain an account
416 ## http://appenlight.com for details how to obtain an account
417
417
418 ## appenlight integration enabled
418 ## appenlight integration enabled
419 appenlight = false
419 appenlight = false
420
420
421 appenlight.server_url = https://api.appenlight.com
421 appenlight.server_url = https://api.appenlight.com
422 appenlight.api_key = YOUR_API_KEY
422 appenlight.api_key = YOUR_API_KEY
423 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
423 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
424
424
425 # used for JS client
425 # used for JS client
426 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
426 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
427
427
428 ## TWEAK AMOUNT OF INFO SENT HERE
428 ## TWEAK AMOUNT OF INFO SENT HERE
429
429
430 ## enables 404 error logging (default False)
430 ## enables 404 error logging (default False)
431 appenlight.report_404 = false
431 appenlight.report_404 = false
432
432
433 ## time in seconds after request is considered being slow (default 1)
433 ## time in seconds after request is considered being slow (default 1)
434 appenlight.slow_request_time = 1
434 appenlight.slow_request_time = 1
435
435
436 ## record slow requests in application
436 ## record slow requests in application
437 ## (needs to be enabled for slow datastore recording and time tracking)
437 ## (needs to be enabled for slow datastore recording and time tracking)
438 appenlight.slow_requests = true
438 appenlight.slow_requests = true
439
439
440 ## enable hooking to application loggers
440 ## enable hooking to application loggers
441 appenlight.logging = true
441 appenlight.logging = true
442
442
443 ## minimum log level for log capture
443 ## minimum log level for log capture
444 appenlight.logging.level = WARNING
444 appenlight.logging.level = WARNING
445
445
446 ## send logs only from erroneous/slow requests
446 ## send logs only from erroneous/slow requests
447 ## (saves API quota for intensive logging)
447 ## (saves API quota for intensive logging)
448 appenlight.logging_on_error = false
448 appenlight.logging_on_error = false
449
449
450 ## list of additonal keywords that should be grabbed from environ object
450 ## list of additonal keywords that should be grabbed from environ object
451 ## can be string with comma separated list of words in lowercase
451 ## can be string with comma separated list of words in lowercase
452 ## (by default client will always send following info:
452 ## (by default client will always send following info:
453 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
453 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
454 ## start with HTTP* this list be extended with additional keywords here
454 ## start with HTTP* this list be extended with additional keywords here
455 appenlight.environ_keys_whitelist =
455 appenlight.environ_keys_whitelist =
456
456
457 ## list of keywords that should be blanked from request object
457 ## list of keywords that should be blanked from request object
458 ## can be string with comma separated list of words in lowercase
458 ## can be string with comma separated list of words in lowercase
459 ## (by default client will always blank keys that contain following words
459 ## (by default client will always blank keys that contain following words
460 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
460 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
461 ## this list be extended with additional keywords set here
461 ## this list be extended with additional keywords set here
462 appenlight.request_keys_blacklist =
462 appenlight.request_keys_blacklist =
463
463
464 ## list of namespaces that should be ignores when gathering log entries
464 ## list of namespaces that should be ignores when gathering log entries
465 ## can be string with comma separated list of namespaces
465 ## can be string with comma separated list of namespaces
466 ## (by default the client ignores own entries: appenlight_client.client)
466 ## (by default the client ignores own entries: appenlight_client.client)
467 appenlight.log_namespace_blacklist =
467 appenlight.log_namespace_blacklist =
468
468
469
469
470 ################################################################################
470 ################################################################################
471 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
471 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
472 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
472 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
473 ## execute malicious code after an exception is raised. ##
473 ## execute malicious code after an exception is raised. ##
474 ################################################################################
474 ################################################################################
475 set debug = false
475 set debug = false
476
476
477
477
478 ##############
478 ##############
479 ## STYLING ##
479 ## STYLING ##
480 ##############
480 ##############
481 debug_style = false
481 debug_style = false
482
482
483 ###########################################
483 ###########################################
484 ### MAIN RHODECODE DATABASE CONFIG ###
484 ### MAIN RHODECODE DATABASE CONFIG ###
485 ###########################################
485 ###########################################
486 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
486 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
487 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test
487 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test
488 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode_test
488 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode_test
489 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
489 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
490
490
491 # see sqlalchemy docs for other advanced settings
491 # see sqlalchemy docs for other advanced settings
492
492
493 ## print the sql statements to output
493 ## print the sql statements to output
494 sqlalchemy.db1.echo = false
494 sqlalchemy.db1.echo = false
495 ## recycle the connections after this amount of seconds
495 ## recycle the connections after this amount of seconds
496 sqlalchemy.db1.pool_recycle = 3600
496 sqlalchemy.db1.pool_recycle = 3600
497 sqlalchemy.db1.convert_unicode = true
497 sqlalchemy.db1.convert_unicode = true
498
498
499 ## the number of connections to keep open inside the connection pool.
499 ## the number of connections to keep open inside the connection pool.
500 ## 0 indicates no limit
500 ## 0 indicates no limit
501 #sqlalchemy.db1.pool_size = 5
501 #sqlalchemy.db1.pool_size = 5
502
502
503 ## the number of connections to allow in connection pool "overflow", that is
503 ## the number of connections to allow in connection pool "overflow", that is
504 ## connections that can be opened above and beyond the pool_size setting,
504 ## connections that can be opened above and beyond the pool_size setting,
505 ## which defaults to five.
505 ## which defaults to five.
506 #sqlalchemy.db1.max_overflow = 10
506 #sqlalchemy.db1.max_overflow = 10
507
507
508
508
509 ##################
509 ##################
510 ### VCS CONFIG ###
510 ### VCS CONFIG ###
511 ##################
511 ##################
512 vcs.server.enable = true
512 vcs.server.enable = true
513 vcs.server = localhost:9901
513 vcs.server = localhost:9901
514
514
515 ## Web server connectivity protocol, responsible for web based VCS operatations
515 ## Web server connectivity protocol, responsible for web based VCS operatations
516 ## Available protocols are:
516 ## Available protocols are:
517 ## `http` - use http-rpc backend (default)
517 ## `http` - use http-rpc backend (default)
518 vcs.server.protocol = http
518 vcs.server.protocol = http
519
519
520 ## Push/Pull operations protocol, available options are:
520 ## Push/Pull operations protocol, available options are:
521 ## `http` - use http-rpc backend (default)
521 ## `http` - use http-rpc backend (default)
522 ## `vcsserver.scm_app` - internal app (EE only)
522 ## `vcsserver.scm_app` - internal app (EE only)
523 vcs.scm_app_implementation = http
523 vcs.scm_app_implementation = http
524
524
525 ## Push/Pull operations hooks protocol, available options are:
525 ## Push/Pull operations hooks protocol, available options are:
526 ## `http` - use http-rpc backend (default)
526 ## `http` - use http-rpc backend (default)
527 vcs.hooks.protocol = http
527 vcs.hooks.protocol = http
528
528
529 vcs.server.log_level = debug
529 vcs.server.log_level = debug
530 ## Start VCSServer with this instance as a subprocess, usefull for development
530 ## Start VCSServer with this instance as a subprocess, usefull for development
531 vcs.start_server = false
531 vcs.start_server = false
532
532
533 ## List of enabled VCS backends, available options are:
533 ## List of enabled VCS backends, available options are:
534 ## `hg` - mercurial
534 ## `hg` - mercurial
535 ## `git` - git
535 ## `git` - git
536 ## `svn` - subversion
536 ## `svn` - subversion
537 vcs.backends = hg, git, svn
537 vcs.backends = hg, git, svn
538
538
539 vcs.connection_timeout = 3600
539 vcs.connection_timeout = 3600
540 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
540 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
541 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
541 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
542 #vcs.svn.compatible_version = pre-1.8-compatible
542 #vcs.svn.compatible_version = pre-1.8-compatible
543
543
544
544
545 ############################################################
545 ############################################################
546 ### Subversion proxy support (mod_dav_svn) ###
546 ### Subversion proxy support (mod_dav_svn) ###
547 ### Maps RhodeCode repo groups into SVN paths for Apache ###
547 ### Maps RhodeCode repo groups into SVN paths for Apache ###
548 ############################################################
548 ############################################################
549 ## Enable or disable the config file generation.
549 ## Enable or disable the config file generation.
550 svn.proxy.generate_config = false
550 svn.proxy.generate_config = false
551 ## Generate config file with `SVNListParentPath` set to `On`.
551 ## Generate config file with `SVNListParentPath` set to `On`.
552 svn.proxy.list_parent_path = true
552 svn.proxy.list_parent_path = true
553 ## Set location and file name of generated config file.
553 ## Set location and file name of generated config file.
554 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
554 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
555 ## Used as a prefix to the `Location` block in the generated config file.
555 ## Used as a prefix to the `Location` block in the generated config file.
556 ## In most cases it should be set to `/`.
556 ## In most cases it should be set to `/`.
557 svn.proxy.location_root = /
557 svn.proxy.location_root = /
558 ## Command to reload the mod dav svn configuration on change.
558 ## Command to reload the mod dav svn configuration on change.
559 ## Example: `/etc/init.d/apache2 reload`
559 ## Example: `/etc/init.d/apache2 reload`
560 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
560 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
561 ## If the timeout expires before the reload command finishes, the command will
561 ## If the timeout expires before the reload command finishes, the command will
562 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
562 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
563 #svn.proxy.reload_timeout = 10
563 #svn.proxy.reload_timeout = 10
564
564
565 ############################################################
565 ############################################################
566 ### SSH Support Settings ###
566 ### SSH Support Settings ###
567 ############################################################
567 ############################################################
568
568
569 ## Defines if the authorized_keys file should be written on any change of
569 ## Defines if the authorized_keys file should be written on any change of
570 ## user ssh keys, setting this to false also disables posibility of adding
570 ## user ssh keys, setting this to false also disables posibility of adding
571 ## ssh keys for users from web interface.
571 ## ssh keys for users from web interface.
572 ssh.generate_authorized_keyfile = true
572 ssh.generate_authorized_keyfile = true
573
573
574 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
574 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
575 # ssh.authorized_keys_ssh_opts =
575 # ssh.authorized_keys_ssh_opts =
576
576
577 ## File to generate the authorized keys together with options
577 ## File to generate the authorized keys together with options
578 ## It is possible to have multiple key files specified in `sshd_config` e.g.
578 ## It is possible to have multiple key files specified in `sshd_config` e.g.
579 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
579 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
580 ssh.authorized_keys_file_path = %(here)s/rc/authorized_keys_rhodecode
580 ssh.authorized_keys_file_path = %(here)s/rc/authorized_keys_rhodecode
581
581
582 ## Command to execute the SSH wrapper. The binary is available in the
582 ## Command to execute the SSH wrapper. The binary is available in the
583 ## rhodecode installation directory.
583 ## rhodecode installation directory.
584 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
584 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
585 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
585 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
586
586
587 ## Allow shell when executing the ssh-wrapper command
587 ## Allow shell when executing the ssh-wrapper command
588 ssh.wrapper_cmd_allow_shell = false
588 ssh.wrapper_cmd_allow_shell = false
589
589
590 ## Enables logging, and detailed output send back to the client. Usefull for
590 ## Enables logging, and detailed output send back to the client. Usefull for
591 ## debugging, shouldn't be used in production.
591 ## debugging, shouldn't be used in production.
592 ssh.enable_debug_logging = false
592 ssh.enable_debug_logging = false
593
593
594 ## Paths to binary executrables, by default they are the names, but we can
594 ## Paths to binary executrables, by default they are the names, but we can
595 ## override them if we want to use a custom one
595 ## override them if we want to use a custom one
596 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
596 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
597 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
597 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
598 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
598 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
599
599
600
600
601 ## Dummy marker to add new entries after.
601 ## Dummy marker to add new entries after.
602 ## Add any custom entries below. Please don't remove.
602 ## Add any custom entries below. Please don't remove.
603 custom.conf = 1
603 custom.conf = 1
604
604
605
605
606 ################################
606 ################################
607 ### LOGGING CONFIGURATION ####
607 ### LOGGING CONFIGURATION ####
608 ################################
608 ################################
609 [loggers]
609 [loggers]
610 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
610 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
611
611
612 [handlers]
612 [handlers]
613 keys = console, console_sql
613 keys = console, console_sql
614
614
615 [formatters]
615 [formatters]
616 keys = generic, color_formatter, color_formatter_sql
616 keys = generic, color_formatter, color_formatter_sql
617
617
618 #############
618 #############
619 ## LOGGERS ##
619 ## LOGGERS ##
620 #############
620 #############
621 [logger_root]
621 [logger_root]
622 level = NOTSET
622 level = NOTSET
623 handlers = console
623 handlers = console
624
624
625 [logger_routes]
625 [logger_routes]
626 level = DEBUG
626 level = DEBUG
627 handlers =
627 handlers =
628 qualname = routes.middleware
628 qualname = routes.middleware
629 ## "level = DEBUG" logs the route matched and routing variables.
629 ## "level = DEBUG" logs the route matched and routing variables.
630 propagate = 1
630 propagate = 1
631
631
632 [logger_beaker]
632 [logger_beaker]
633 level = DEBUG
633 level = DEBUG
634 handlers =
634 handlers =
635 qualname = beaker.container
635 qualname = beaker.container
636 propagate = 1
636 propagate = 1
637
637
638 [logger_rhodecode]
638 [logger_rhodecode]
639 level = DEBUG
639 level = DEBUG
640 handlers =
640 handlers =
641 qualname = rhodecode
641 qualname = rhodecode
642 propagate = 1
642 propagate = 1
643
643
644 [logger_sqlalchemy]
644 [logger_sqlalchemy]
645 level = ERROR
645 level = ERROR
646 handlers = console_sql
646 handlers = console_sql
647 qualname = sqlalchemy.engine
647 qualname = sqlalchemy.engine
648 propagate = 0
648 propagate = 0
649
649
650 [logger_ssh_wrapper]
650 [logger_ssh_wrapper]
651 level = DEBUG
651 level = DEBUG
652 handlers =
652 handlers =
653 qualname = ssh_wrapper
653 qualname = ssh_wrapper
654 propagate = 1
654 propagate = 1
655
655
656
656
657 ##############
657 ##############
658 ## HANDLERS ##
658 ## HANDLERS ##
659 ##############
659 ##############
660
660
661 [handler_console]
661 [handler_console]
662 class = StreamHandler
662 class = StreamHandler
663 args = (sys.stderr,)
663 args = (sys.stderr,)
664 level = DEBUG
664 level = DEBUG
665 formatter = generic
665 formatter = generic
666
666
667 [handler_console_sql]
667 [handler_console_sql]
668 class = StreamHandler
668 class = StreamHandler
669 args = (sys.stderr,)
669 args = (sys.stderr,)
670 level = WARN
670 level = WARN
671 formatter = generic
671 formatter = generic
672
672
673 ################
673 ################
674 ## FORMATTERS ##
674 ## FORMATTERS ##
675 ################
675 ################
676
676
677 [formatter_generic]
677 [formatter_generic]
678 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
678 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
679 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
679 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
680 datefmt = %Y-%m-%d %H:%M:%S
680 datefmt = %Y-%m-%d %H:%M:%S
681
681
682 [formatter_color_formatter]
682 [formatter_color_formatter]
683 class = rhodecode.lib.logging_formatter.ColorFormatter
683 class = rhodecode.lib.logging_formatter.ColorFormatter
684 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
684 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
685 datefmt = %Y-%m-%d %H:%M:%S
685 datefmt = %Y-%m-%d %H:%M:%S
686
686
687 [formatter_color_formatter_sql]
687 [formatter_color_formatter_sql]
688 class = rhodecode.lib.logging_formatter.ColorFormatterSql
688 class = rhodecode.lib.logging_formatter.ColorFormatterSql
689 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
689 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
690 datefmt = %Y-%m-%d %H:%M:%S
690 datefmt = %Y-%m-%d %H:%M:%S
General Comments 0
You need to be logged in to leave comments. Login now