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