##// END OF EJS Templates
Some code cleanups and fixes
marcink -
r1628:de71a4bd beta
parent child Browse files
Show More
@@ -1,241 +1,243 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # RhodeCode - Pylons environment configuration #
3 # RhodeCode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11 ################################################################################
11 ################################################################################
12 ## Uncomment and replace with the address which should receive ##
12 ## Uncomment and replace with the address which should receive ##
13 ## any error reports after application crash ##
13 ## any error reports after application crash ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 ################################################################################
15 ################################################################################
16 #email_to = admin@localhost
16 #email_to = admin@localhost
17 #error_email_from = paste_error@localhost
17 #error_email_from = paste_error@localhost
18 #app_email_from = rhodecode-noreply@localhost
18 #app_email_from = rhodecode-noreply@localhost
19 #error_message =
19 #error_message =
20
20
21 #smtp_server = mail.server.com
21 #smtp_server = mail.server.com
22 #smtp_username =
22 #smtp_username =
23 #smtp_password =
23 #smtp_password =
24 #smtp_port =
24 #smtp_port =
25 #smtp_use_tls = false
25 #smtp_use_tls = false
26 #smtp_use_ssl = true
26 #smtp_use_ssl = true
27 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
27 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 #smtp_auth =
28 #smtp_auth =
29
29
30 [server:main]
30 [server:main]
31 ##nr of threads to spawn
31 ##nr of threads to spawn
32 threadpool_workers = 5
32 threadpool_workers = 5
33
33
34 ##max request before thread respawn
34 ##max request before thread respawn
35 threadpool_max_requests = 6
35 threadpool_max_requests = 6
36
36
37 ##option to use threads of process
37 ##option to use threads of process
38 use_threadpool = true
38 use_threadpool = true
39
39
40 use = egg:Paste#http
40 use = egg:Paste#http
41 host = 0.0.0.0
41 host = 0.0.0.0
42 port = 5000
42 port = 5000
43
43
44 [app:main]
44 [app:main]
45 use = egg:rhodecode
45 use = egg:rhodecode
46 full_stack = true
46 full_stack = true
47 static_files = true
47 static_files = true
48 lang=en
48 lang=en
49 cache_dir = %(here)s/data
49 cache_dir = %(here)s/data
50 index_dir = %(here)s/data/index
50 index_dir = %(here)s/data/index
51 app_instance_uuid = develop
51 app_instance_uuid = develop
52 cut_off_limit = 256000
52 cut_off_limit = 256000
53 force_https = false
53 force_https = false
54 commit_parse_limit = 25
54 commit_parse_limit = 25
55 use_gravatar = true
55 use_gravatar = true
56 container_auth_enabled = false
57 proxypass_auth_enabled = false
56
58
57 ####################################
59 ####################################
58 ### CELERY CONFIG ####
60 ### CELERY CONFIG ####
59 ####################################
61 ####################################
60 use_celery = false
62 use_celery = false
61 broker.host = localhost
63 broker.host = localhost
62 broker.vhost = rabbitmqhost
64 broker.vhost = rabbitmqhost
63 broker.port = 5672
65 broker.port = 5672
64 broker.user = rabbitmq
66 broker.user = rabbitmq
65 broker.password = qweqwe
67 broker.password = qweqwe
66
68
67 celery.imports = rhodecode.lib.celerylib.tasks
69 celery.imports = rhodecode.lib.celerylib.tasks
68
70
69 celery.result.backend = amqp
71 celery.result.backend = amqp
70 celery.result.dburi = amqp://
72 celery.result.dburi = amqp://
71 celery.result.serialier = json
73 celery.result.serialier = json
72
74
73 #celery.send.task.error.emails = true
75 #celery.send.task.error.emails = true
74 #celery.amqp.task.result.expires = 18000
76 #celery.amqp.task.result.expires = 18000
75
77
76 celeryd.concurrency = 2
78 celeryd.concurrency = 2
77 #celeryd.log.file = celeryd.log
79 #celeryd.log.file = celeryd.log
78 celeryd.log.level = debug
80 celeryd.log.level = debug
79 celeryd.max.tasks.per.child = 1
81 celeryd.max.tasks.per.child = 1
80
82
81 #tasks will never be sent to the queue, but executed locally instead.
83 #tasks will never be sent to the queue, but executed locally instead.
82 celery.always.eager = false
84 celery.always.eager = false
83
85
84 ####################################
86 ####################################
85 ### BEAKER CACHE ####
87 ### BEAKER CACHE ####
86 ####################################
88 ####################################
87 beaker.cache.data_dir=%(here)s/data/cache/data
89 beaker.cache.data_dir=%(here)s/data/cache/data
88 beaker.cache.lock_dir=%(here)s/data/cache/lock
90 beaker.cache.lock_dir=%(here)s/data/cache/lock
89
91
90 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
92 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
91
93
92 beaker.cache.super_short_term.type=memory
94 beaker.cache.super_short_term.type=memory
93 beaker.cache.super_short_term.expire=10
95 beaker.cache.super_short_term.expire=10
94 beaker.cache.super_short_term.key_length = 256
96 beaker.cache.super_short_term.key_length = 256
95
97
96 beaker.cache.short_term.type=memory
98 beaker.cache.short_term.type=memory
97 beaker.cache.short_term.expire=60
99 beaker.cache.short_term.expire=60
98 beaker.cache.short_term.key_length = 256
100 beaker.cache.short_term.key_length = 256
99
101
100 beaker.cache.long_term.type=memory
102 beaker.cache.long_term.type=memory
101 beaker.cache.long_term.expire=36000
103 beaker.cache.long_term.expire=36000
102 beaker.cache.long_term.key_length = 256
104 beaker.cache.long_term.key_length = 256
103
105
104 beaker.cache.sql_cache_short.type=memory
106 beaker.cache.sql_cache_short.type=memory
105 beaker.cache.sql_cache_short.expire=10
107 beaker.cache.sql_cache_short.expire=10
106 beaker.cache.sql_cache_short.key_length = 256
108 beaker.cache.sql_cache_short.key_length = 256
107
109
108 beaker.cache.sql_cache_med.type=memory
110 beaker.cache.sql_cache_med.type=memory
109 beaker.cache.sql_cache_med.expire=360
111 beaker.cache.sql_cache_med.expire=360
110 beaker.cache.sql_cache_med.key_length = 256
112 beaker.cache.sql_cache_med.key_length = 256
111
113
112 beaker.cache.sql_cache_long.type=file
114 beaker.cache.sql_cache_long.type=file
113 beaker.cache.sql_cache_long.expire=3600
115 beaker.cache.sql_cache_long.expire=3600
114 beaker.cache.sql_cache_long.key_length = 256
116 beaker.cache.sql_cache_long.key_length = 256
115
117
116 ####################################
118 ####################################
117 ### BEAKER SESSION ####
119 ### BEAKER SESSION ####
118 ####################################
120 ####################################
119 ## Type of storage used for the session, current types are
121 ## Type of storage used for the session, current types are
120 ## dbm, file, memcached, database, and memory.
122 ## dbm, file, memcached, database, and memory.
121 ## The storage uses the Container API
123 ## The storage uses the Container API
122 ##that is also used by the cache system.
124 ##that is also used by the cache system.
123 beaker.session.type = file
125 beaker.session.type = file
124
126
125 beaker.session.key = rhodecode
127 beaker.session.key = rhodecode
126 beaker.session.secret = g654dcno0-9873jhgfreyu
128 beaker.session.secret = g654dcno0-9873jhgfreyu
127 beaker.session.timeout = 36000
129 beaker.session.timeout = 36000
128
130
129 ##auto save the session to not to use .save()
131 ##auto save the session to not to use .save()
130 beaker.session.auto = False
132 beaker.session.auto = False
131
133
132 ##true exire at browser close
134 ##true exire at browser close
133 #beaker.session.cookie_expires = 3600
135 #beaker.session.cookie_expires = 3600
134
136
135
137
136 ################################################################################
138 ################################################################################
137 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
139 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
138 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
140 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
139 ## execute malicious code after an exception is raised. ##
141 ## execute malicious code after an exception is raised. ##
140 ################################################################################
142 ################################################################################
141 #set debug = false
143 #set debug = false
142
144
143 ##################################
145 ##################################
144 ### LOGVIEW CONFIG ###
146 ### LOGVIEW CONFIG ###
145 ##################################
147 ##################################
146 logview.sqlalchemy = #faa
148 logview.sqlalchemy = #faa
147 logview.pylons.templating = #bfb
149 logview.pylons.templating = #bfb
148 logview.pylons.util = #eee
150 logview.pylons.util = #eee
149
151
150 #########################################################
152 #########################################################
151 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
153 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
152 #########################################################
154 #########################################################
153 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
155 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
154 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
156 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
155 sqlalchemy.db1.echo = false
157 sqlalchemy.db1.echo = false
156 sqlalchemy.db1.pool_recycle = 3600
158 sqlalchemy.db1.pool_recycle = 3600
157 sqlalchemy.convert_unicode = true
159 sqlalchemy.convert_unicode = true
158
160
159 ################################
161 ################################
160 ### LOGGING CONFIGURATION ####
162 ### LOGGING CONFIGURATION ####
161 ################################
163 ################################
162 [loggers]
164 [loggers]
163 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
165 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
164
166
165 [handlers]
167 [handlers]
166 keys = console, console_sql
168 keys = console, console_sql
167
169
168 [formatters]
170 [formatters]
169 keys = generic, color_formatter, color_formatter_sql
171 keys = generic, color_formatter, color_formatter_sql
170
172
171 #############
173 #############
172 ## LOGGERS ##
174 ## LOGGERS ##
173 #############
175 #############
174 [logger_root]
176 [logger_root]
175 level = NOTSET
177 level = NOTSET
176 handlers = console
178 handlers = console
177
179
178 [logger_routes]
180 [logger_routes]
179 level = DEBUG
181 level = DEBUG
180 handlers =
182 handlers =
181 qualname = routes.middleware
183 qualname = routes.middleware
182 # "level = DEBUG" logs the route matched and routing variables.
184 # "level = DEBUG" logs the route matched and routing variables.
183 propagate = 1
185 propagate = 1
184
186
185 [logger_beaker]
187 [logger_beaker]
186 level = DEBUG
188 level = DEBUG
187 handlers =
189 handlers =
188 qualname = beaker.container
190 qualname = beaker.container
189 propagate = 1
191 propagate = 1
190
192
191 [logger_templates]
193 [logger_templates]
192 level = INFO
194 level = INFO
193 handlers =
195 handlers =
194 qualname = pylons.templating
196 qualname = pylons.templating
195 propagate = 1
197 propagate = 1
196
198
197 [logger_rhodecode]
199 [logger_rhodecode]
198 level = DEBUG
200 level = DEBUG
199 handlers =
201 handlers =
200 qualname = rhodecode
202 qualname = rhodecode
201 propagate = 1
203 propagate = 1
202
204
203 [logger_sqlalchemy]
205 [logger_sqlalchemy]
204 level = INFO
206 level = INFO
205 handlers = console_sql
207 handlers = console_sql
206 qualname = sqlalchemy.engine
208 qualname = sqlalchemy.engine
207 propagate = 0
209 propagate = 0
208
210
209 ##############
211 ##############
210 ## HANDLERS ##
212 ## HANDLERS ##
211 ##############
213 ##############
212
214
213 [handler_console]
215 [handler_console]
214 class = StreamHandler
216 class = StreamHandler
215 args = (sys.stderr,)
217 args = (sys.stderr,)
216 level = DEBUG
218 level = DEBUG
217 formatter = color_formatter
219 formatter = color_formatter
218
220
219 [handler_console_sql]
221 [handler_console_sql]
220 class = StreamHandler
222 class = StreamHandler
221 args = (sys.stderr,)
223 args = (sys.stderr,)
222 level = DEBUG
224 level = DEBUG
223 formatter = color_formatter_sql
225 formatter = color_formatter_sql
224
226
225 ################
227 ################
226 ## FORMATTERS ##
228 ## FORMATTERS ##
227 ################
229 ################
228
230
229 [formatter_generic]
231 [formatter_generic]
230 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
232 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
231 datefmt = %Y-%m-%d %H:%M:%S
233 datefmt = %Y-%m-%d %H:%M:%S
232
234
233 [formatter_color_formatter]
235 [formatter_color_formatter]
234 class=rhodecode.lib.colored_formatter.ColorFormatter
236 class=rhodecode.lib.colored_formatter.ColorFormatter
235 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
237 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
236 datefmt = %Y-%m-%d %H:%M:%S
238 datefmt = %Y-%m-%d %H:%M:%S
237
239
238 [formatter_color_formatter_sql]
240 [formatter_color_formatter_sql]
239 class=rhodecode.lib.colored_formatter.ColorFormatterSql
241 class=rhodecode.lib.colored_formatter.ColorFormatterSql
240 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
242 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
241 datefmt = %Y-%m-%d %H:%M:%S
243 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,241 +1,243 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # RhodeCode - Pylons environment configuration #
3 # RhodeCode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11 ################################################################################
11 ################################################################################
12 ## Uncomment and replace with the address which should receive ##
12 ## Uncomment and replace with the address which should receive ##
13 ## any error reports after application crash ##
13 ## any error reports after application crash ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 ################################################################################
15 ################################################################################
16 #email_to = admin@localhost
16 #email_to = admin@localhost
17 #error_email_from = paste_error@localhost
17 #error_email_from = paste_error@localhost
18 #app_email_from = rhodecode-noreply@localhost
18 #app_email_from = rhodecode-noreply@localhost
19 #error_message =
19 #error_message =
20
20
21 #smtp_server = mail.server.com
21 #smtp_server = mail.server.com
22 #smtp_username =
22 #smtp_username =
23 #smtp_password =
23 #smtp_password =
24 #smtp_port =
24 #smtp_port =
25 #smtp_use_tls = false
25 #smtp_use_tls = false
26 #smtp_use_ssl = true
26 #smtp_use_ssl = true
27 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
27 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 #smtp_auth =
28 #smtp_auth =
29
29
30 [server:main]
30 [server:main]
31 ##nr of threads to spawn
31 ##nr of threads to spawn
32 threadpool_workers = 5
32 threadpool_workers = 5
33
33
34 ##max request before thread respawn
34 ##max request before thread respawn
35 threadpool_max_requests = 10
35 threadpool_max_requests = 10
36
36
37 ##option to use threads of process
37 ##option to use threads of process
38 use_threadpool = true
38 use_threadpool = true
39
39
40 use = egg:Paste#http
40 use = egg:Paste#http
41 host = 127.0.0.1
41 host = 127.0.0.1
42 port = 8001
42 port = 8001
43
43
44 [app:main]
44 [app:main]
45 use = egg:rhodecode
45 use = egg:rhodecode
46 full_stack = true
46 full_stack = true
47 static_files = true
47 static_files = true
48 lang=en
48 lang=en
49 cache_dir = %(here)s/data
49 cache_dir = %(here)s/data
50 index_dir = %(here)s/data/index
50 index_dir = %(here)s/data/index
51 app_instance_uuid = prod1234
51 app_instance_uuid = prod1234
52 cut_off_limit = 256000
52 cut_off_limit = 256000
53 force_https = false
53 force_https = false
54 commit_parse_limit = 50
54 commit_parse_limit = 50
55 use_gravatar = true
55 use_gravatar = true
56 container_auth_enabled = false
57 proxypass_auth_enabled = false
56
58
57 ####################################
59 ####################################
58 ### CELERY CONFIG ####
60 ### CELERY CONFIG ####
59 ####################################
61 ####################################
60 use_celery = false
62 use_celery = false
61 broker.host = localhost
63 broker.host = localhost
62 broker.vhost = rabbitmqhost
64 broker.vhost = rabbitmqhost
63 broker.port = 5672
65 broker.port = 5672
64 broker.user = rabbitmq
66 broker.user = rabbitmq
65 broker.password = qweqwe
67 broker.password = qweqwe
66
68
67 celery.imports = rhodecode.lib.celerylib.tasks
69 celery.imports = rhodecode.lib.celerylib.tasks
68
70
69 celery.result.backend = amqp
71 celery.result.backend = amqp
70 celery.result.dburi = amqp://
72 celery.result.dburi = amqp://
71 celery.result.serialier = json
73 celery.result.serialier = json
72
74
73 #celery.send.task.error.emails = true
75 #celery.send.task.error.emails = true
74 #celery.amqp.task.result.expires = 18000
76 #celery.amqp.task.result.expires = 18000
75
77
76 celeryd.concurrency = 2
78 celeryd.concurrency = 2
77 #celeryd.log.file = celeryd.log
79 #celeryd.log.file = celeryd.log
78 celeryd.log.level = debug
80 celeryd.log.level = debug
79 celeryd.max.tasks.per.child = 1
81 celeryd.max.tasks.per.child = 1
80
82
81 #tasks will never be sent to the queue, but executed locally instead.
83 #tasks will never be sent to the queue, but executed locally instead.
82 celery.always.eager = false
84 celery.always.eager = false
83
85
84 ####################################
86 ####################################
85 ### BEAKER CACHE ####
87 ### BEAKER CACHE ####
86 ####################################
88 ####################################
87 beaker.cache.data_dir=%(here)s/data/cache/data
89 beaker.cache.data_dir=%(here)s/data/cache/data
88 beaker.cache.lock_dir=%(here)s/data/cache/lock
90 beaker.cache.lock_dir=%(here)s/data/cache/lock
89
91
90 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
92 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
91
93
92 beaker.cache.super_short_term.type=memory
94 beaker.cache.super_short_term.type=memory
93 beaker.cache.super_short_term.expire=10
95 beaker.cache.super_short_term.expire=10
94 beaker.cache.super_short_term.key_length = 256
96 beaker.cache.super_short_term.key_length = 256
95
97
96 beaker.cache.short_term.type=memory
98 beaker.cache.short_term.type=memory
97 beaker.cache.short_term.expire=60
99 beaker.cache.short_term.expire=60
98 beaker.cache.short_term.key_length = 256
100 beaker.cache.short_term.key_length = 256
99
101
100 beaker.cache.long_term.type=memory
102 beaker.cache.long_term.type=memory
101 beaker.cache.long_term.expire=36000
103 beaker.cache.long_term.expire=36000
102 beaker.cache.long_term.key_length = 256
104 beaker.cache.long_term.key_length = 256
103
105
104 beaker.cache.sql_cache_short.type=memory
106 beaker.cache.sql_cache_short.type=memory
105 beaker.cache.sql_cache_short.expire=10
107 beaker.cache.sql_cache_short.expire=10
106 beaker.cache.sql_cache_short.key_length = 256
108 beaker.cache.sql_cache_short.key_length = 256
107
109
108 beaker.cache.sql_cache_med.type=memory
110 beaker.cache.sql_cache_med.type=memory
109 beaker.cache.sql_cache_med.expire=360
111 beaker.cache.sql_cache_med.expire=360
110 beaker.cache.sql_cache_med.key_length = 256
112 beaker.cache.sql_cache_med.key_length = 256
111
113
112 beaker.cache.sql_cache_long.type=file
114 beaker.cache.sql_cache_long.type=file
113 beaker.cache.sql_cache_long.expire=3600
115 beaker.cache.sql_cache_long.expire=3600
114 beaker.cache.sql_cache_long.key_length = 256
116 beaker.cache.sql_cache_long.key_length = 256
115
117
116 ####################################
118 ####################################
117 ### BEAKER SESSION ####
119 ### BEAKER SESSION ####
118 ####################################
120 ####################################
119 ## Type of storage used for the session, current types are
121 ## Type of storage used for the session, current types are
120 ## dbm, file, memcached, database, and memory.
122 ## dbm, file, memcached, database, and memory.
121 ## The storage uses the Container API
123 ## The storage uses the Container API
122 ##that is also used by the cache system.
124 ##that is also used by the cache system.
123 beaker.session.type = file
125 beaker.session.type = file
124
126
125 beaker.session.key = rhodecode
127 beaker.session.key = rhodecode
126 beaker.session.secret = g654dcno0-9873jhgfreyu
128 beaker.session.secret = g654dcno0-9873jhgfreyu
127 beaker.session.timeout = 36000
129 beaker.session.timeout = 36000
128
130
129 ##auto save the session to not to use .save()
131 ##auto save the session to not to use .save()
130 beaker.session.auto = False
132 beaker.session.auto = False
131
133
132 ##true exire at browser close
134 ##true exire at browser close
133 #beaker.session.cookie_expires = 3600
135 #beaker.session.cookie_expires = 3600
134
136
135
137
136 ################################################################################
138 ################################################################################
137 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
139 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
138 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
140 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
139 ## execute malicious code after an exception is raised. ##
141 ## execute malicious code after an exception is raised. ##
140 ################################################################################
142 ################################################################################
141 set debug = false
143 set debug = false
142
144
143 ##################################
145 ##################################
144 ### LOGVIEW CONFIG ###
146 ### LOGVIEW CONFIG ###
145 ##################################
147 ##################################
146 logview.sqlalchemy = #faa
148 logview.sqlalchemy = #faa
147 logview.pylons.templating = #bfb
149 logview.pylons.templating = #bfb
148 logview.pylons.util = #eee
150 logview.pylons.util = #eee
149
151
150 #########################################################
152 #########################################################
151 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
153 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
152 #########################################################
154 #########################################################
153 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
155 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
154 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
156 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
155 sqlalchemy.db1.echo = false
157 sqlalchemy.db1.echo = false
156 sqlalchemy.db1.pool_recycle = 3600
158 sqlalchemy.db1.pool_recycle = 3600
157 sqlalchemy.convert_unicode = true
159 sqlalchemy.convert_unicode = true
158
160
159 ################################
161 ################################
160 ### LOGGING CONFIGURATION ####
162 ### LOGGING CONFIGURATION ####
161 ################################
163 ################################
162 [loggers]
164 [loggers]
163 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
165 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
164
166
165 [handlers]
167 [handlers]
166 keys = console, console_sql
168 keys = console, console_sql
167
169
168 [formatters]
170 [formatters]
169 keys = generic, color_formatter, color_formatter_sql
171 keys = generic, color_formatter, color_formatter_sql
170
172
171 #############
173 #############
172 ## LOGGERS ##
174 ## LOGGERS ##
173 #############
175 #############
174 [logger_root]
176 [logger_root]
175 level = NOTSET
177 level = NOTSET
176 handlers = console
178 handlers = console
177
179
178 [logger_routes]
180 [logger_routes]
179 level = DEBUG
181 level = DEBUG
180 handlers =
182 handlers =
181 qualname = routes.middleware
183 qualname = routes.middleware
182 # "level = DEBUG" logs the route matched and routing variables.
184 # "level = DEBUG" logs the route matched and routing variables.
183 propagate = 1
185 propagate = 1
184
186
185 [logger_beaker]
187 [logger_beaker]
186 level = DEBUG
188 level = DEBUG
187 handlers =
189 handlers =
188 qualname = beaker.container
190 qualname = beaker.container
189 propagate = 1
191 propagate = 1
190
192
191 [logger_templates]
193 [logger_templates]
192 level = INFO
194 level = INFO
193 handlers =
195 handlers =
194 qualname = pylons.templating
196 qualname = pylons.templating
195 propagate = 1
197 propagate = 1
196
198
197 [logger_rhodecode]
199 [logger_rhodecode]
198 level = DEBUG
200 level = DEBUG
199 handlers =
201 handlers =
200 qualname = rhodecode
202 qualname = rhodecode
201 propagate = 1
203 propagate = 1
202
204
203 [logger_sqlalchemy]
205 [logger_sqlalchemy]
204 level = INFO
206 level = INFO
205 handlers = console_sql
207 handlers = console_sql
206 qualname = sqlalchemy.engine
208 qualname = sqlalchemy.engine
207 propagate = 0
209 propagate = 0
208
210
209 ##############
211 ##############
210 ## HANDLERS ##
212 ## HANDLERS ##
211 ##############
213 ##############
212
214
213 [handler_console]
215 [handler_console]
214 class = StreamHandler
216 class = StreamHandler
215 args = (sys.stderr,)
217 args = (sys.stderr,)
216 level = INFO
218 level = INFO
217 formatter = generic
219 formatter = generic
218
220
219 [handler_console_sql]
221 [handler_console_sql]
220 class = StreamHandler
222 class = StreamHandler
221 args = (sys.stderr,)
223 args = (sys.stderr,)
222 level = WARN
224 level = WARN
223 formatter = generic
225 formatter = generic
224
226
225 ################
227 ################
226 ## FORMATTERS ##
228 ## FORMATTERS ##
227 ################
229 ################
228
230
229 [formatter_generic]
231 [formatter_generic]
230 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
232 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
231 datefmt = %Y-%m-%d %H:%M:%S
233 datefmt = %Y-%m-%d %H:%M:%S
232
234
233 [formatter_color_formatter]
235 [formatter_color_formatter]
234 class=rhodecode.lib.colored_formatter.ColorFormatter
236 class=rhodecode.lib.colored_formatter.ColorFormatter
235 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
237 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
236 datefmt = %Y-%m-%d %H:%M:%S
238 datefmt = %Y-%m-%d %H:%M:%S
237
239
238 [formatter_color_formatter_sql]
240 [formatter_color_formatter_sql]
239 class=rhodecode.lib.colored_formatter.ColorFormatterSql
241 class=rhodecode.lib.colored_formatter.ColorFormatterSql
240 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
242 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
241 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
243 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,166 +1,166 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.login
3 rhodecode.controllers.login
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Login controller for rhodeocode
6 Login controller for rhodeocode
7
7
8 :created_on: Apr 22, 2010
8 :created_on: Apr 22, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import formencode
27 import formencode
28
28
29 from formencode import htmlfill
29 from formencode import htmlfill
30
30
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32 from pylons.controllers.util import abort, redirect
32 from pylons.controllers.util import abort, redirect
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34
34
35 import rhodecode.lib.helpers as h
35 import rhodecode.lib.helpers as h
36 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
36 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
37 from rhodecode.lib.base import BaseController, render
37 from rhodecode.lib.base import BaseController, render
38 from rhodecode.model.db import User
38 from rhodecode.model.db import User
39 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
39 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
40 from rhodecode.model.user import UserModel
40 from rhodecode.model.user import UserModel
41
41
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 class LoginController(BaseController):
46 class LoginController(BaseController):
47
47
48 def __before__(self):
48 def __before__(self):
49 super(LoginController, self).__before__()
49 super(LoginController, self).__before__()
50
50
51 def index(self):
51 def index(self):
52 #redirect if already logged in
52 # redirect if already logged in
53 c.came_from = request.GET.get('came_from', None)
53 c.came_from = request.GET.get('came_from', None)
54
54
55 if self.rhodecode_user.is_authenticated \
55 if self.rhodecode_user.is_authenticated \
56 and self.rhodecode_user.username != 'default':
56 and self.rhodecode_user.username != 'default':
57
57
58 return redirect(url('home'))
58 return redirect(url('home'))
59
59
60 if request.POST:
60 if request.POST:
61 #import Login Form validator class
61 #import Login Form validator class
62 login_form = LoginForm()
62 login_form = LoginForm()
63 try:
63 try:
64 c.form_result = login_form.to_python(dict(request.POST))
64 c.form_result = login_form.to_python(dict(request.POST))
65 #form checks for username/password, now we're authenticated
65 # form checks for username/password, now we're authenticated
66 username = c.form_result['username']
66 username = c.form_result['username']
67 user = User.get_by_username(username, case_insensitive=True)
67 user = User.get_by_username(username, case_insensitive=True)
68 auth_user = AuthUser(user.user_id)
68 auth_user = AuthUser(user.user_id)
69 auth_user.set_authenticated()
69 auth_user.set_authenticated()
70 session['rhodecode_user'] = auth_user
70 session['rhodecode_user'] = auth_user
71 session.save()
71 session.save()
72
72
73 log.info('user %s is now authenticated and stored in session',
73 log.info('user %s is now authenticated and stored in session',
74 username)
74 username)
75 user.update_lastlogin()
75 user.update_lastlogin()
76
76
77 if c.came_from:
77 if c.came_from:
78 return redirect(c.came_from)
78 return redirect(c.came_from)
79 else:
79 else:
80 return redirect(url('home'))
80 return redirect(url('home'))
81
81
82 except formencode.Invalid, errors:
82 except formencode.Invalid, errors:
83 return htmlfill.render(
83 return htmlfill.render(
84 render('/login.html'),
84 render('/login.html'),
85 defaults=errors.value,
85 defaults=errors.value,
86 errors=errors.error_dict or {},
86 errors=errors.error_dict or {},
87 prefix_error=False,
87 prefix_error=False,
88 encoding="UTF-8")
88 encoding="UTF-8")
89
89
90 return render('/login.html')
90 return render('/login.html')
91
91
92 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
92 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
93 'hg.register.manual_activate')
93 'hg.register.manual_activate')
94 def register(self):
94 def register(self):
95 user_model = UserModel()
95 user_model = UserModel()
96 c.auto_active = False
96 c.auto_active = False
97 for perm in User.get_by_username('default').user_perms:
97 for perm in User.get_by_username('default').user_perms:
98 if perm.permission.permission_name == 'hg.register.auto_activate':
98 if perm.permission.permission_name == 'hg.register.auto_activate':
99 c.auto_active = True
99 c.auto_active = True
100 break
100 break
101
101
102 if request.POST:
102 if request.POST:
103
103
104 register_form = RegisterForm()()
104 register_form = RegisterForm()()
105 try:
105 try:
106 form_result = register_form.to_python(dict(request.POST))
106 form_result = register_form.to_python(dict(request.POST))
107 form_result['active'] = c.auto_active
107 form_result['active'] = c.auto_active
108 user_model.create_registration(form_result)
108 user_model.create_registration(form_result)
109 h.flash(_('You have successfully registered into rhodecode'),
109 h.flash(_('You have successfully registered into rhodecode'),
110 category='success')
110 category='success')
111 return redirect(url('login_home'))
111 return redirect(url('login_home'))
112
112
113 except formencode.Invalid, errors:
113 except formencode.Invalid, errors:
114 return htmlfill.render(
114 return htmlfill.render(
115 render('/register.html'),
115 render('/register.html'),
116 defaults=errors.value,
116 defaults=errors.value,
117 errors=errors.error_dict or {},
117 errors=errors.error_dict or {},
118 prefix_error=False,
118 prefix_error=False,
119 encoding="UTF-8")
119 encoding="UTF-8")
120
120
121 return render('/register.html')
121 return render('/register.html')
122
122
123 def password_reset(self):
123 def password_reset(self):
124 user_model = UserModel()
124 user_model = UserModel()
125 if request.POST:
125 if request.POST:
126
126
127 password_reset_form = PasswordResetForm()()
127 password_reset_form = PasswordResetForm()()
128 try:
128 try:
129 form_result = password_reset_form.to_python(dict(request.POST))
129 form_result = password_reset_form.to_python(dict(request.POST))
130 user_model.reset_password_link(form_result)
130 user_model.reset_password_link(form_result)
131 h.flash(_('Your password reset link was sent'),
131 h.flash(_('Your password reset link was sent'),
132 category='success')
132 category='success')
133 return redirect(url('login_home'))
133 return redirect(url('login_home'))
134
134
135 except formencode.Invalid, errors:
135 except formencode.Invalid, errors:
136 return htmlfill.render(
136 return htmlfill.render(
137 render('/password_reset.html'),
137 render('/password_reset.html'),
138 defaults=errors.value,
138 defaults=errors.value,
139 errors=errors.error_dict or {},
139 errors=errors.error_dict or {},
140 prefix_error=False,
140 prefix_error=False,
141 encoding="UTF-8")
141 encoding="UTF-8")
142
142
143 return render('/password_reset.html')
143 return render('/password_reset.html')
144
144
145 def password_reset_confirmation(self):
145 def password_reset_confirmation(self):
146
146
147 if request.GET and request.GET.get('key'):
147 if request.GET and request.GET.get('key'):
148 try:
148 try:
149 user_model = UserModel()
149 user_model = UserModel()
150 user = User.get_by_api_key(request.GET.get('key'))
150 user = User.get_by_api_key(request.GET.get('key'))
151 data = dict(email=user.email)
151 data = dict(email=user.email)
152 user_model.reset_password(data)
152 user_model.reset_password(data)
153 h.flash(_('Your password reset was successful, '
153 h.flash(_('Your password reset was successful, '
154 'new password has been sent to your email'),
154 'new password has been sent to your email'),
155 category='success')
155 category='success')
156 except Exception, e:
156 except Exception, e:
157 log.error(e)
157 log.error(e)
158 return redirect(url('reset_password'))
158 return redirect(url('reset_password'))
159
159
160 return redirect(url('login_home'))
160 return redirect(url('login_home'))
161
161
162 def logout(self):
162 def logout(self):
163 del session['rhodecode_user']
163 del session['rhodecode_user']
164 session.save()
164 session.save()
165 log.info('Logging out and setting user as Empty')
165 log.info('Logging out and setting user as Empty')
166 redirect(url('home'))
166 redirect(url('home'))
@@ -1,663 +1,677 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.auth
3 rhodecode.lib.auth
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 authentication and permission libraries
6 authentication and permission libraries
7
7
8 :created_on: Apr 4, 2010
8 :created_on: Apr 4, 2010
9 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
9 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :license: GPLv3, see COPYING for more details.
10 :license: GPLv3, see COPYING for more details.
11 """
11 """
12 # This program is free software: you can redistribute it and/or modify
12 # This program is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation, either version 3 of the License, or
14 # the Free Software Foundation, either version 3 of the License, or
15 # (at your option) any later version.
15 # (at your option) any later version.
16 #
16 #
17 # This program is distributed in the hope that it will be useful,
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
20 # GNU General Public License for more details.
21 #
21 #
22 # You should have received a copy of the GNU General Public License
22 # You should have received a copy of the GNU General Public License
23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24
24
25 import random
25 import random
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import hashlib
28 import hashlib
29
29
30 from tempfile import _RandomNameSequence
30 from tempfile import _RandomNameSequence
31 from decorator import decorator
31 from decorator import decorator
32
32
33 from pylons import config, session, url, request
33 from pylons import config, session, url, request
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36
36
37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
38
38
39 if __platform__ in PLATFORM_WIN:
39 if __platform__ in PLATFORM_WIN:
40 from hashlib import sha256
40 from hashlib import sha256
41 if __platform__ in PLATFORM_OTHERS:
41 if __platform__ in PLATFORM_OTHERS:
42 import bcrypt
42 import bcrypt
43
43
44 from rhodecode.lib import str2bool, safe_unicode
44 from rhodecode.lib import str2bool, safe_unicode
45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
46 from rhodecode.lib.utils import get_repo_slug
46 from rhodecode.lib.utils import get_repo_slug
47 from rhodecode.lib.auth_ldap import AuthLdap
47 from rhodecode.lib.auth_ldap import AuthLdap
48
48
49 from rhodecode.model import meta
49 from rhodecode.model import meta
50 from rhodecode.model.user import UserModel
50 from rhodecode.model.user import UserModel
51 from rhodecode.model.db import Permission, RhodeCodeSettings, User
51 from rhodecode.model.db import Permission, RhodeCodeSettings, User
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55
55
56 class PasswordGenerator(object):
56 class PasswordGenerator(object):
57 """This is a simple class for generating password from
57 """This is a simple class for generating password from
58 different sets of characters
58 different sets of characters
59 usage:
59 usage:
60 passwd_gen = PasswordGenerator()
60 passwd_gen = PasswordGenerator()
61 #print 8-letter password containing only big and small letters
61 #print 8-letter password containing only big and small letters
62 of alphabet
62 of alphabet
63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
64 """
64 """
65 ALPHABETS_NUM = r'''1234567890'''
65 ALPHABETS_NUM = r'''1234567890'''
66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
70 + ALPHABETS_NUM + ALPHABETS_SPECIAL
70 + ALPHABETS_NUM + ALPHABETS_SPECIAL
71 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
71 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
72 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
72 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
73 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
73 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
74 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
74 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
75
75
76 def __init__(self, passwd=''):
76 def __init__(self, passwd=''):
77 self.passwd = passwd
77 self.passwd = passwd
78
78
79 def gen_password(self, len, type):
79 def gen_password(self, len, type):
80 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
80 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
81 return self.passwd
81 return self.passwd
82
82
83
83
84 class RhodeCodeCrypto(object):
84 class RhodeCodeCrypto(object):
85
85
86 @classmethod
86 @classmethod
87 def hash_string(cls, str_):
87 def hash_string(cls, str_):
88 """
88 """
89 Cryptographic function used for password hashing based on pybcrypt
89 Cryptographic function used for password hashing based on pybcrypt
90 or pycrypto in windows
90 or pycrypto in windows
91
91
92 :param password: password to hash
92 :param password: password to hash
93 """
93 """
94 if __platform__ in PLATFORM_WIN:
94 if __platform__ in PLATFORM_WIN:
95 return sha256(str_).hexdigest()
95 return sha256(str_).hexdigest()
96 elif __platform__ in PLATFORM_OTHERS:
96 elif __platform__ in PLATFORM_OTHERS:
97 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
97 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
98 else:
98 else:
99 raise Exception('Unknown or unsupported platform %s' \
99 raise Exception('Unknown or unsupported platform %s' \
100 % __platform__)
100 % __platform__)
101
101
102 @classmethod
102 @classmethod
103 def hash_check(cls, password, hashed):
103 def hash_check(cls, password, hashed):
104 """
104 """
105 Checks matching password with it's hashed value, runs different
105 Checks matching password with it's hashed value, runs different
106 implementation based on platform it runs on
106 implementation based on platform it runs on
107
107
108 :param password: password
108 :param password: password
109 :param hashed: password in hashed form
109 :param hashed: password in hashed form
110 """
110 """
111
111
112 if __platform__ in PLATFORM_WIN:
112 if __platform__ in PLATFORM_WIN:
113 return sha256(password).hexdigest() == hashed
113 return sha256(password).hexdigest() == hashed
114 elif __platform__ in PLATFORM_OTHERS:
114 elif __platform__ in PLATFORM_OTHERS:
115 return bcrypt.hashpw(password, hashed) == hashed
115 return bcrypt.hashpw(password, hashed) == hashed
116 else:
116 else:
117 raise Exception('Unknown or unsupported platform %s' \
117 raise Exception('Unknown or unsupported platform %s' \
118 % __platform__)
118 % __platform__)
119
119
120
120
121 def get_crypt_password(password):
121 def get_crypt_password(password):
122 return RhodeCodeCrypto.hash_string(password)
122 return RhodeCodeCrypto.hash_string(password)
123
123
124
124
125 def check_password(password, hashed):
125 def check_password(password, hashed):
126 return RhodeCodeCrypto.hash_check(password, hashed)
126 return RhodeCodeCrypto.hash_check(password, hashed)
127
127
128
128 def generate_api_key(str_, salt=None):
129 def generate_api_key(username, salt=None):
129 """
130 Generates API KEY from given string
131
132 :param str_:
133 :param salt:
134 """
135
130 if salt is None:
136 if salt is None:
131 salt = _RandomNameSequence().next()
137 salt = _RandomNameSequence().next()
132
138
133 return hashlib.sha1(username + salt).hexdigest()
139 return hashlib.sha1(str_ + salt).hexdigest()
134
140
135
141
136 def authfunc(environ, username, password):
142 def authfunc(environ, username, password):
137 """Dummy authentication function used in Mercurial/Git/ and access control,
143 """
144 Dummy authentication function used in Mercurial/Git/ and access control,
138
145
139 :param environ: needed only for using in Basic auth
146 :param environ: needed only for using in Basic auth
140 """
147 """
141 return authenticate(username, password)
148 return authenticate(username, password)
142
149
143
150
144 def authenticate(username, password):
151 def authenticate(username, password):
145 """Authentication function used for access control,
152 """
153 Authentication function used for access control,
146 firstly checks for db authentication then if ldap is enabled for ldap
154 firstly checks for db authentication then if ldap is enabled for ldap
147 authentication, also creates ldap user if not in database
155 authentication, also creates ldap user if not in database
148
156
149 :param username: username
157 :param username: username
150 :param password: password
158 :param password: password
151 """
159 """
152
160
153 user_model = UserModel()
161 user_model = UserModel()
154 user = User.get_by_username(username)
162 user = User.get_by_username(username)
155
163
156 log.debug('Authenticating user using RhodeCode account')
164 log.debug('Authenticating user using RhodeCode account')
157 if user is not None and not user.ldap_dn:
165 if user is not None and not user.ldap_dn:
158 if user.active:
166 if user.active:
159 if user.username == 'default' and user.active:
167 if user.username == 'default' and user.active:
160 log.info('user %s authenticated correctly as anonymous user',
168 log.info('user %s authenticated correctly as anonymous user',
161 username)
169 username)
162 return True
170 return True
163
171
164 elif user.username == username and check_password(password,
172 elif user.username == username and check_password(password,
165 user.password):
173 user.password):
166 log.info('user %s authenticated correctly', username)
174 log.info('user %s authenticated correctly', username)
167 return True
175 return True
168 else:
176 else:
169 log.warning('user %s is disabled', username)
177 log.warning('user %s is disabled', username)
170
178
171 else:
179 else:
172 log.debug('Regular authentication failed')
180 log.debug('Regular authentication failed')
173 user_obj = User.get_by_username(username, case_insensitive=True)
181 user_obj = User.get_by_username(username, case_insensitive=True)
174
182
175 if user_obj is not None and not user_obj.ldap_dn:
183 if user_obj is not None and not user_obj.ldap_dn:
176 log.debug('this user already exists as non ldap')
184 log.debug('this user already exists as non ldap')
177 return False
185 return False
178
186
179 ldap_settings = RhodeCodeSettings.get_ldap_settings()
187 ldap_settings = RhodeCodeSettings.get_ldap_settings()
180 #======================================================================
188 #======================================================================
181 # FALLBACK TO LDAP AUTH IF ENABLE
189 # FALLBACK TO LDAP AUTH IF ENABLE
182 #======================================================================
190 #======================================================================
183 if str2bool(ldap_settings.get('ldap_active')):
191 if str2bool(ldap_settings.get('ldap_active')):
184 log.debug("Authenticating user using ldap")
192 log.debug("Authenticating user using ldap")
185 kwargs = {
193 kwargs = {
186 'server': ldap_settings.get('ldap_host', ''),
194 'server': ldap_settings.get('ldap_host', ''),
187 'base_dn': ldap_settings.get('ldap_base_dn', ''),
195 'base_dn': ldap_settings.get('ldap_base_dn', ''),
188 'port': ldap_settings.get('ldap_port'),
196 'port': ldap_settings.get('ldap_port'),
189 'bind_dn': ldap_settings.get('ldap_dn_user'),
197 'bind_dn': ldap_settings.get('ldap_dn_user'),
190 'bind_pass': ldap_settings.get('ldap_dn_pass'),
198 'bind_pass': ldap_settings.get('ldap_dn_pass'),
191 'tls_kind': ldap_settings.get('ldap_tls_kind'),
199 'tls_kind': ldap_settings.get('ldap_tls_kind'),
192 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
200 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
193 'ldap_filter': ldap_settings.get('ldap_filter'),
201 'ldap_filter': ldap_settings.get('ldap_filter'),
194 'search_scope': ldap_settings.get('ldap_search_scope'),
202 'search_scope': ldap_settings.get('ldap_search_scope'),
195 'attr_login': ldap_settings.get('ldap_attr_login'),
203 'attr_login': ldap_settings.get('ldap_attr_login'),
196 'ldap_version': 3,
204 'ldap_version': 3,
197 }
205 }
198 log.debug('Checking for ldap authentication')
206 log.debug('Checking for ldap authentication')
199 try:
207 try:
200 aldap = AuthLdap(**kwargs)
208 aldap = AuthLdap(**kwargs)
201 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
209 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
202 password)
210 password)
203 log.debug('Got ldap DN response %s', user_dn)
211 log.debug('Got ldap DN response %s', user_dn)
204
212
205 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
213 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
206 .get(k), [''])[0]
214 .get(k), [''])[0]
207
215
208 user_attrs = {
216 user_attrs = {
209 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
217 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
210 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
218 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
211 'email': get_ldap_attr('ldap_attr_email'),
219 'email': get_ldap_attr('ldap_attr_email'),
212 }
220 }
213
221
214 if user_model.create_ldap(username, password, user_dn,
222 if user_model.create_ldap(username, password, user_dn,
215 user_attrs):
223 user_attrs):
216 log.info('created new ldap user %s', username)
224 log.info('created new ldap user %s', username)
217
225
218 return True
226 return True
219 except (LdapUsernameError, LdapPasswordError,):
227 except (LdapUsernameError, LdapPasswordError,):
220 pass
228 pass
221 except (Exception,):
229 except (Exception,):
222 log.error(traceback.format_exc())
230 log.error(traceback.format_exc())
223 pass
231 pass
224 return False
232 return False
225
233
226 def login_container_auth(username):
234 def login_container_auth(username):
227 user = User.get_by_username(username)
235 user = User.get_by_username(username)
228 if user is None:
236 if user is None:
229 user_model = UserModel()
237 user_model = UserModel()
230 user_attrs = {
238 user_attrs = {
231 'name': username,
239 'name': username,
232 'lastname': None,
240 'lastname': None,
233 'email': None,
241 'email': None,
234 }
242 }
235 if not user_model.create_for_container_auth(username, user_attrs):
243 user = user_model.create_for_container_auth(username, user_attrs)
244 if not user:
236 return None
245 return None
237 user = User.get_by_username(username)
238 log.info('User %s was created by container authentication', username)
246 log.info('User %s was created by container authentication', username)
239
247
240 if not user.active:
248 if not user.active:
241 return None
249 return None
242
250
243 user.update_lastlogin()
251 user.update_lastlogin()
244 log.debug('User %s is now logged in by container authentication', user.username)
252 log.debug('User %s is now logged in by container authentication',
253 user.username)
245 return user
254 return user
246
255
247 def get_container_username(environ, cfg=config):
256 def get_container_username(environ, cfg):
248 from paste.httpheaders import REMOTE_USER
257 from paste.httpheaders import REMOTE_USER
249 from paste.deploy.converters import asbool
258 from paste.deploy.converters import asbool
250
259
260 proxy_pass_enabled = asbool(cfg.get('proxypass_auth_enabled', False))
251 username = REMOTE_USER(environ)
261 username = REMOTE_USER(environ)
252
262
253 if not username and asbool(cfg.get('proxypass_auth_enabled', False)):
263 if not username and proxy_pass_enabled:
254 username = environ.get('HTTP_X_FORWARDED_USER')
264 username = environ.get('HTTP_X_FORWARDED_USER')
255
265
256 if username:
266 if username and proxy_pass_enabled:
257 #Removing realm and domain from username
267 # Removing realm and domain from username
258 username = username.partition('@')[0]
268 username = username.partition('@')[0]
259 username = username.rpartition('\\')[2]
269 username = username.rpartition('\\')[2]
260 log.debug('Received username %s from container', username)
270 log.debug('Received username %s from container', username)
261
271
262 return username
272 return username
263
273
264 class AuthUser(object):
274 class AuthUser(object):
265 """
275 """
266 A simple object that handles all attributes of user in RhodeCode
276 A simple object that handles all attributes of user in RhodeCode
267
277
268 It does lookup based on API key,given user, or user present in session
278 It does lookup based on API key,given user, or user present in session
269 Then it fills all required information for such user. It also checks if
279 Then it fills all required information for such user. It also checks if
270 anonymous access is enabled and if so, it returns default user as logged
280 anonymous access is enabled and if so, it returns default user as logged
271 in
281 in
272 """
282 """
273
283
274 def __init__(self, user_id=None, api_key=None, username=None):
284 def __init__(self, user_id=None, api_key=None, username=None):
275
285
276 self.user_id = user_id
286 self.user_id = user_id
277 self.api_key = None
287 self.api_key = None
278 self.username = username
288 self.username = username
279
289
280 self.name = ''
290 self.name = ''
281 self.lastname = ''
291 self.lastname = ''
282 self.email = ''
292 self.email = ''
283 self.is_authenticated = False
293 self.is_authenticated = False
284 self.admin = False
294 self.admin = False
285 self.permissions = {}
295 self.permissions = {}
286 self._api_key = api_key
296 self._api_key = api_key
287 self.propagate_data()
297 self.propagate_data()
288
298
289 def propagate_data(self):
299 def propagate_data(self):
290 user_model = UserModel()
300 user_model = UserModel()
291 self.anonymous_user = User.get_by_username('default')
301 self.anonymous_user = User.get_by_username('default')
292 is_user_loaded = False
302 is_user_loaded = False
303
304 # try go get user by api key
293 if self._api_key and self._api_key != self.anonymous_user.api_key:
305 if self._api_key and self._api_key != self.anonymous_user.api_key:
294 #try go get user by api key
295 log.debug('Auth User lookup by API KEY %s', self._api_key)
306 log.debug('Auth User lookup by API KEY %s', self._api_key)
296 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
307 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
297 elif self.user_id is not None \
308 # lookup by userid
298 and self.user_id != self.anonymous_user.user_id:
309 elif (self.user_id is not None and
310 self.user_id != self.anonymous_user.user_id):
299 log.debug('Auth User lookup by USER ID %s', self.user_id)
311 log.debug('Auth User lookup by USER ID %s', self.user_id)
300 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
312 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
313 # lookup by username
301 elif self.username:
314 elif self.username:
302 log.debug('Auth User lookup by USER NAME %s', self.username)
315 log.debug('Auth User lookup by USER NAME %s', self.username)
303 dbuser = login_container_auth(self.username)
316 dbuser = login_container_auth(self.username)
304 if dbuser is not None:
317 if dbuser is not None:
305 for k, v in dbuser.get_dict().items():
318 for k, v in dbuser.get_dict().items():
306 setattr(self, k, v)
319 setattr(self, k, v)
307 self.set_authenticated()
320 self.set_authenticated()
308 is_user_loaded = True
321 is_user_loaded = True
309
322
310 if not is_user_loaded:
323 if not is_user_loaded:
324 # if we cannot authenticate user try anonymous
311 if self.anonymous_user.active is True:
325 if self.anonymous_user.active is True:
312 user_model.fill_data(self,
326 user_model.fill_data(self,user_id=self.anonymous_user.user_id)
313 user_id=self.anonymous_user.user_id)
327 # then we set this user is logged in
314 #then we set this user is logged in
315 self.is_authenticated = True
328 self.is_authenticated = True
316 else:
329 else:
317 self.user_id = None
330 self.user_id = None
318 self.username = None
331 self.username = None
319 self.is_authenticated = False
332 self.is_authenticated = False
320
333
321 if not self.username:
334 if not self.username:
322 self.username = 'None'
335 self.username = 'None'
323
336
324 log.debug('Auth User is now %s', self)
337 log.debug('Auth User is now %s', self)
325 user_model.fill_perms(self)
338 user_model.fill_perms(self)
326
339
327 @property
340 @property
328 def is_admin(self):
341 def is_admin(self):
329 return self.admin
342 return self.admin
330
343
331 @property
344 @property
332 def full_contact(self):
345 def full_contact(self):
333 return '%s %s <%s>' % (self.name, self.lastname, self.email)
346 return '%s %s <%s>' % (self.name, self.lastname, self.email)
334
347
335 def __repr__(self):
348 def __repr__(self):
336 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
349 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
337 self.is_authenticated)
350 self.is_authenticated)
338
351
339 def set_authenticated(self, authenticated=True):
352 def set_authenticated(self, authenticated=True):
340
341 if self.user_id != self.anonymous_user.user_id:
353 if self.user_id != self.anonymous_user.user_id:
342 self.is_authenticated = authenticated
354 self.is_authenticated = authenticated
343
355
344
356
345 def set_available_permissions(config):
357 def set_available_permissions(config):
346 """This function will propagate pylons globals with all available defined
358 """
359 This function will propagate pylons globals with all available defined
347 permission given in db. We don't want to check each time from db for new
360 permission given in db. We don't want to check each time from db for new
348 permissions since adding a new permission also requires application restart
361 permissions since adding a new permission also requires application restart
349 ie. to decorate new views with the newly created permission
362 ie. to decorate new views with the newly created permission
350
363
351 :param config: current pylons config instance
364 :param config: current pylons config instance
352
365
353 """
366 """
354 log.info('getting information about all available permissions')
367 log.info('getting information about all available permissions')
355 try:
368 try:
356 sa = meta.Session()
369 sa = meta.Session()
357 all_perms = sa.query(Permission).all()
370 all_perms = sa.query(Permission).all()
358 except:
371 except:
359 pass
372 pass
360 finally:
373 finally:
361 meta.Session.remove()
374 meta.Session.remove()
362
375
363 config['available_permissions'] = [x.permission_name for x in all_perms]
376 config['available_permissions'] = [x.permission_name for x in all_perms]
364
377
365
378
366 #==============================================================================
379 #==============================================================================
367 # CHECK DECORATORS
380 # CHECK DECORATORS
368 #==============================================================================
381 #==============================================================================
369 class LoginRequired(object):
382 class LoginRequired(object):
370 """
383 """
371 Must be logged in to execute this function else
384 Must be logged in to execute this function else
372 redirect to login page
385 redirect to login page
373
386
374 :param api_access: if enabled this checks only for valid auth token
387 :param api_access: if enabled this checks only for valid auth token
375 and grants access based on valid token
388 and grants access based on valid token
376 """
389 """
377
390
378 def __init__(self, api_access=False):
391 def __init__(self, api_access=False):
379 self.api_access = api_access
392 self.api_access = api_access
380
393
381 def __call__(self, func):
394 def __call__(self, func):
382 return decorator(self.__wrapper, func)
395 return decorator(self.__wrapper, func)
383
396
384 def __wrapper(self, func, *fargs, **fkwargs):
397 def __wrapper(self, func, *fargs, **fkwargs):
385 cls = fargs[0]
398 cls = fargs[0]
386 user = cls.rhodecode_user
399 user = cls.rhodecode_user
387
400
388 api_access_ok = False
401 api_access_ok = False
389 if self.api_access:
402 if self.api_access:
390 log.debug('Checking API KEY access for %s', cls)
403 log.debug('Checking API KEY access for %s', cls)
391 if user.api_key == request.GET.get('api_key'):
404 if user.api_key == request.GET.get('api_key'):
392 api_access_ok = True
405 api_access_ok = True
393 else:
406 else:
394 log.debug("API KEY token not valid")
407 log.debug("API KEY token not valid")
395
408
396 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
409 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
397 if user.is_authenticated or api_access_ok:
410 if user.is_authenticated or api_access_ok:
398 log.debug('user %s is authenticated', user.username)
411 log.debug('user %s is authenticated', user.username)
399 return func(*fargs, **fkwargs)
412 return func(*fargs, **fkwargs)
400 else:
413 else:
401 log.warn('user %s NOT authenticated', user.username)
414 log.warn('user %s NOT authenticated', user.username)
402 p = url.current()
415 p = url.current()
403
416
404 log.debug('redirecting to login page with %s', p)
417 log.debug('redirecting to login page with %s', p)
405 return redirect(url('login_home', came_from=p))
418 return redirect(url('login_home', came_from=p))
406
419
407
420
408 class NotAnonymous(object):
421 class NotAnonymous(object):
409 """Must be logged in to execute this function else
422 """Must be logged in to execute this function else
410 redirect to login page"""
423 redirect to login page"""
411
424
412 def __call__(self, func):
425 def __call__(self, func):
413 return decorator(self.__wrapper, func)
426 return decorator(self.__wrapper, func)
414
427
415 def __wrapper(self, func, *fargs, **fkwargs):
428 def __wrapper(self, func, *fargs, **fkwargs):
416 cls = fargs[0]
429 cls = fargs[0]
417 self.user = cls.rhodecode_user
430 self.user = cls.rhodecode_user
418
431
419 log.debug('Checking if user is not anonymous @%s', cls)
432 log.debug('Checking if user is not anonymous @%s', cls)
420
433
421 anonymous = self.user.username == 'default'
434 anonymous = self.user.username == 'default'
422
435
423 if anonymous:
436 if anonymous:
424 p = url.current()
437 p = url.current()
425
438
426 import rhodecode.lib.helpers as h
439 import rhodecode.lib.helpers as h
427 h.flash(_('You need to be a registered user to '
440 h.flash(_('You need to be a registered user to '
428 'perform this action'),
441 'perform this action'),
429 category='warning')
442 category='warning')
430 return redirect(url('login_home', came_from=p))
443 return redirect(url('login_home', came_from=p))
431 else:
444 else:
432 return func(*fargs, **fkwargs)
445 return func(*fargs, **fkwargs)
433
446
434
447
435 class PermsDecorator(object):
448 class PermsDecorator(object):
436 """Base class for controller decorators"""
449 """Base class for controller decorators"""
437
450
438 def __init__(self, *required_perms):
451 def __init__(self, *required_perms):
439 available_perms = config['available_permissions']
452 available_perms = config['available_permissions']
440 for perm in required_perms:
453 for perm in required_perms:
441 if perm not in available_perms:
454 if perm not in available_perms:
442 raise Exception("'%s' permission is not defined" % perm)
455 raise Exception("'%s' permission is not defined" % perm)
443 self.required_perms = set(required_perms)
456 self.required_perms = set(required_perms)
444 self.user_perms = None
457 self.user_perms = None
445
458
446 def __call__(self, func):
459 def __call__(self, func):
447 return decorator(self.__wrapper, func)
460 return decorator(self.__wrapper, func)
448
461
449 def __wrapper(self, func, *fargs, **fkwargs):
462 def __wrapper(self, func, *fargs, **fkwargs):
450 cls = fargs[0]
463 cls = fargs[0]
451 self.user = cls.rhodecode_user
464 self.user = cls.rhodecode_user
452 self.user_perms = self.user.permissions
465 self.user_perms = self.user.permissions
453 log.debug('checking %s permissions %s for %s %s',
466 log.debug('checking %s permissions %s for %s %s',
454 self.__class__.__name__, self.required_perms, cls,
467 self.__class__.__name__, self.required_perms, cls,
455 self.user)
468 self.user)
456
469
457 if self.check_permissions():
470 if self.check_permissions():
458 log.debug('Permission granted for %s %s', cls, self.user)
471 log.debug('Permission granted for %s %s', cls, self.user)
459 return func(*fargs, **fkwargs)
472 return func(*fargs, **fkwargs)
460
473
461 else:
474 else:
462 log.warning('Permission denied for %s %s', cls, self.user)
475 log.warning('Permission denied for %s %s', cls, self.user)
463
476
464
477
465 anonymous = self.user.username == 'default'
478 anonymous = self.user.username == 'default'
466
479
467 if anonymous:
480 if anonymous:
468 p = url.current()
481 p = url.current()
469
482
470 import rhodecode.lib.helpers as h
483 import rhodecode.lib.helpers as h
471 h.flash(_('You need to be a signed in to '
484 h.flash(_('You need to be a signed in to '
472 'view this page'),
485 'view this page'),
473 category='warning')
486 category='warning')
474 return redirect(url('login_home', came_from=p))
487 return redirect(url('login_home', came_from=p))
475
488
476 else:
489 else:
477 #redirect with forbidden ret code
490 # redirect with forbidden ret code
478 return abort(403)
491 return abort(403)
479
492
480 def check_permissions(self):
493 def check_permissions(self):
481 """Dummy function for overriding"""
494 """Dummy function for overriding"""
482 raise Exception('You have to write this function in child class')
495 raise Exception('You have to write this function in child class')
483
496
484
497
485 class HasPermissionAllDecorator(PermsDecorator):
498 class HasPermissionAllDecorator(PermsDecorator):
486 """Checks for access permission for all given predicates. All of them
499 """Checks for access permission for all given predicates. All of them
487 have to be meet in order to fulfill the request
500 have to be meet in order to fulfill the request
488 """
501 """
489
502
490 def check_permissions(self):
503 def check_permissions(self):
491 if self.required_perms.issubset(self.user_perms.get('global')):
504 if self.required_perms.issubset(self.user_perms.get('global')):
492 return True
505 return True
493 return False
506 return False
494
507
495
508
496 class HasPermissionAnyDecorator(PermsDecorator):
509 class HasPermissionAnyDecorator(PermsDecorator):
497 """Checks for access permission for any of given predicates. In order to
510 """Checks for access permission for any of given predicates. In order to
498 fulfill the request any of predicates must be meet
511 fulfill the request any of predicates must be meet
499 """
512 """
500
513
501 def check_permissions(self):
514 def check_permissions(self):
502 if self.required_perms.intersection(self.user_perms.get('global')):
515 if self.required_perms.intersection(self.user_perms.get('global')):
503 return True
516 return True
504 return False
517 return False
505
518
506
519
507 class HasRepoPermissionAllDecorator(PermsDecorator):
520 class HasRepoPermissionAllDecorator(PermsDecorator):
508 """Checks for access permission for all given predicates for specific
521 """Checks for access permission for all given predicates for specific
509 repository. All of them have to be meet in order to fulfill the request
522 repository. All of them have to be meet in order to fulfill the request
510 """
523 """
511
524
512 def check_permissions(self):
525 def check_permissions(self):
513 repo_name = get_repo_slug(request)
526 repo_name = get_repo_slug(request)
514 try:
527 try:
515 user_perms = set([self.user_perms['repositories'][repo_name]])
528 user_perms = set([self.user_perms['repositories'][repo_name]])
516 except KeyError:
529 except KeyError:
517 return False
530 return False
518 if self.required_perms.issubset(user_perms):
531 if self.required_perms.issubset(user_perms):
519 return True
532 return True
520 return False
533 return False
521
534
522
535
523 class HasRepoPermissionAnyDecorator(PermsDecorator):
536 class HasRepoPermissionAnyDecorator(PermsDecorator):
524 """Checks for access permission for any of given predicates for specific
537 """Checks for access permission for any of given predicates for specific
525 repository. In order to fulfill the request any of predicates must be meet
538 repository. In order to fulfill the request any of predicates must be meet
526 """
539 """
527
540
528 def check_permissions(self):
541 def check_permissions(self):
529 repo_name = get_repo_slug(request)
542 repo_name = get_repo_slug(request)
530
543
531 try:
544 try:
532 user_perms = set([self.user_perms['repositories'][repo_name]])
545 user_perms = set([self.user_perms['repositories'][repo_name]])
533 except KeyError:
546 except KeyError:
534 return False
547 return False
535 if self.required_perms.intersection(user_perms):
548 if self.required_perms.intersection(user_perms):
536 return True
549 return True
537 return False
550 return False
538
551
539
552
540 #==============================================================================
553 #==============================================================================
541 # CHECK FUNCTIONS
554 # CHECK FUNCTIONS
542 #==============================================================================
555 #==============================================================================
543 class PermsFunction(object):
556 class PermsFunction(object):
544 """Base function for other check functions"""
557 """Base function for other check functions"""
545
558
546 def __init__(self, *perms):
559 def __init__(self, *perms):
547 available_perms = config['available_permissions']
560 available_perms = config['available_permissions']
548
561
549 for perm in perms:
562 for perm in perms:
550 if perm not in available_perms:
563 if perm not in available_perms:
551 raise Exception("'%s' permission in not defined" % perm)
564 raise Exception("'%s' permission in not defined" % perm)
552 self.required_perms = set(perms)
565 self.required_perms = set(perms)
553 self.user_perms = None
566 self.user_perms = None
554 self.granted_for = ''
567 self.granted_for = ''
555 self.repo_name = None
568 self.repo_name = None
556
569
557 def __call__(self, check_Location=''):
570 def __call__(self, check_Location=''):
558 user = session.get('rhodecode_user', False)
571 user = session.get('rhodecode_user', False)
559 if not user:
572 if not user:
560 return False
573 return False
561 self.user_perms = user.permissions
574 self.user_perms = user.permissions
562 self.granted_for = user
575 self.granted_for = user
563 log.debug('checking %s %s %s', self.__class__.__name__,
576 log.debug('checking %s %s %s', self.__class__.__name__,
564 self.required_perms, user)
577 self.required_perms, user)
565
578
566 if self.check_permissions():
579 if self.check_permissions():
567 log.debug('Permission granted %s @ %s', self.granted_for,
580 log.debug('Permission granted %s @ %s', self.granted_for,
568 check_Location or 'unspecified location')
581 check_Location or 'unspecified location')
569 return True
582 return True
570
583
571 else:
584 else:
572 log.warning('Permission denied for %s @ %s', self.granted_for,
585 log.warning('Permission denied for %s @ %s', self.granted_for,
573 check_Location or 'unspecified location')
586 check_Location or 'unspecified location')
574 return False
587 return False
575
588
576 def check_permissions(self):
589 def check_permissions(self):
577 """Dummy function for overriding"""
590 """Dummy function for overriding"""
578 raise Exception('You have to write this function in child class')
591 raise Exception('You have to write this function in child class')
579
592
580
593
581 class HasPermissionAll(PermsFunction):
594 class HasPermissionAll(PermsFunction):
582 def check_permissions(self):
595 def check_permissions(self):
583 if self.required_perms.issubset(self.user_perms.get('global')):
596 if self.required_perms.issubset(self.user_perms.get('global')):
584 return True
597 return True
585 return False
598 return False
586
599
587
600
588 class HasPermissionAny(PermsFunction):
601 class HasPermissionAny(PermsFunction):
589 def check_permissions(self):
602 def check_permissions(self):
590 if self.required_perms.intersection(self.user_perms.get('global')):
603 if self.required_perms.intersection(self.user_perms.get('global')):
591 return True
604 return True
592 return False
605 return False
593
606
594
607
595 class HasRepoPermissionAll(PermsFunction):
608 class HasRepoPermissionAll(PermsFunction):
596
609
597 def __call__(self, repo_name=None, check_Location=''):
610 def __call__(self, repo_name=None, check_Location=''):
598 self.repo_name = repo_name
611 self.repo_name = repo_name
599 return super(HasRepoPermissionAll, self).__call__(check_Location)
612 return super(HasRepoPermissionAll, self).__call__(check_Location)
600
613
601 def check_permissions(self):
614 def check_permissions(self):
602 if not self.repo_name:
615 if not self.repo_name:
603 self.repo_name = get_repo_slug(request)
616 self.repo_name = get_repo_slug(request)
604
617
605 try:
618 try:
606 self.user_perms = set([self.user_perms['reposit'
619 self.user_perms = set([self.user_perms['reposit'
607 'ories'][self.repo_name]])
620 'ories'][self.repo_name]])
608 except KeyError:
621 except KeyError:
609 return False
622 return False
610 self.granted_for = self.repo_name
623 self.granted_for = self.repo_name
611 if self.required_perms.issubset(self.user_perms):
624 if self.required_perms.issubset(self.user_perms):
612 return True
625 return True
613 return False
626 return False
614
627
615
628
616 class HasRepoPermissionAny(PermsFunction):
629 class HasRepoPermissionAny(PermsFunction):
617
630
618 def __call__(self, repo_name=None, check_Location=''):
631 def __call__(self, repo_name=None, check_Location=''):
619 self.repo_name = repo_name
632 self.repo_name = repo_name
620 return super(HasRepoPermissionAny, self).__call__(check_Location)
633 return super(HasRepoPermissionAny, self).__call__(check_Location)
621
634
622 def check_permissions(self):
635 def check_permissions(self):
623 if not self.repo_name:
636 if not self.repo_name:
624 self.repo_name = get_repo_slug(request)
637 self.repo_name = get_repo_slug(request)
625
638
626 try:
639 try:
627 self.user_perms = set([self.user_perms['reposi'
640 self.user_perms = set([self.user_perms['reposi'
628 'tories'][self.repo_name]])
641 'tories'][self.repo_name]])
629 except KeyError:
642 except KeyError:
630 return False
643 return False
631 self.granted_for = self.repo_name
644 self.granted_for = self.repo_name
632 if self.required_perms.intersection(self.user_perms):
645 if self.required_perms.intersection(self.user_perms):
633 return True
646 return True
634 return False
647 return False
635
648
636
649
637 #==============================================================================
650 #==============================================================================
638 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
651 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
639 #==============================================================================
652 #==============================================================================
640 class HasPermissionAnyMiddleware(object):
653 class HasPermissionAnyMiddleware(object):
641 def __init__(self, *perms):
654 def __init__(self, *perms):
642 self.required_perms = set(perms)
655 self.required_perms = set(perms)
643
656
644 def __call__(self, user, repo_name):
657 def __call__(self, user, repo_name):
645 usr = AuthUser(user.user_id)
658 usr = AuthUser(user.user_id)
646 try:
659 try:
647 self.user_perms = set([usr.permissions['repositories'][repo_name]])
660 self.user_perms = set([usr.permissions['repositories'][repo_name]])
648 except:
661 except:
649 self.user_perms = set()
662 self.user_perms = set()
650 self.granted_for = ''
663 self.granted_for = ''
651 self.username = user.username
664 self.username = user.username
652 self.repo_name = repo_name
665 self.repo_name = repo_name
653 return self.check_permissions()
666 return self.check_permissions()
654
667
655 def check_permissions(self):
668 def check_permissions(self):
656 log.debug('checking mercurial protocol '
669 log.debug('checking mercurial protocol '
657 'permissions %s for user:%s repository:%s', self.user_perms,
670 'permissions %s for user:%s repository:%s', self.user_perms,
658 self.username, self.repo_name)
671 self.username, self.repo_name)
659 if self.required_perms.intersection(self.user_perms):
672 if self.required_perms.intersection(self.user_perms):
660 log.debug('permission granted')
673 log.debug('permission granted')
661 return True
674 return True
662 log.debug('permission denied')
675 log.debug('permission denied')
663 return False
676 return False
677
@@ -1,92 +1,91 b''
1 """The base Controller API
1 """The base Controller API
2
2
3 Provides the BaseController class for subclassing.
3 Provides the BaseController class for subclassing.
4 """
4 """
5 import logging
5 import logging
6 import time
6 import time
7 from pylons import config, tmpl_context as c, request, session, url
7 from pylons import config, tmpl_context as c, request, session, url
8 from pylons.controllers import WSGIController
8 from pylons.controllers import WSGIController
9 from pylons.controllers.util import redirect
9 from pylons.controllers.util import redirect
10 from pylons.templating import render_mako as render
10 from pylons.templating import render_mako as render
11 from paste.deploy.converters import asbool
11 from paste.deploy.converters import asbool
12
12
13 from rhodecode import __version__
13 from rhodecode import __version__
14 from rhodecode.lib.auth import AuthUser, get_container_username
14 from rhodecode.lib.auth import AuthUser, get_container_username
15 from rhodecode.lib.utils import get_repo_slug
15 from rhodecode.lib.utils import get_repo_slug
16 from rhodecode.model import meta
16 from rhodecode.model import meta
17 from rhodecode.model.scm import ScmModel
17 from rhodecode.model.scm import ScmModel
18 from rhodecode import BACKENDS
18 from rhodecode import BACKENDS
19 from rhodecode.model.db import Repository
19 from rhodecode.model.db import Repository
20
20
21 log = logging.getLogger(__name__)
21 log = logging.getLogger(__name__)
22
22
23 class BaseController(WSGIController):
23 class BaseController(WSGIController):
24
24
25 def __before__(self):
25 def __before__(self):
26 c.rhodecode_version = __version__
26 c.rhodecode_version = __version__
27 c.rhodecode_name = config.get('rhodecode_title')
27 c.rhodecode_name = config.get('rhodecode_title')
28 c.ga_code = config.get('rhodecode_ga_code')
28 c.ga_code = config.get('rhodecode_ga_code')
29 c.repo_name = get_repo_slug(request)
29 c.repo_name = get_repo_slug(request)
30 c.backends = BACKENDS.keys()
30 c.backends = BACKENDS.keys()
31 self.cut_off_limit = int(config.get('cut_off_limit'))
31 self.cut_off_limit = int(config.get('cut_off_limit'))
32
32
33 self.sa = meta.Session()
33 self.sa = meta.Session()
34 self.scm_model = ScmModel(self.sa)
34 self.scm_model = ScmModel(self.sa)
35
35
36 #c.unread_journal = scm_model.get_unread_journal()
37
38 def __call__(self, environ, start_response):
36 def __call__(self, environ, start_response):
39 """Invoke the Controller"""
37 """Invoke the Controller"""
40 # WSGIController.__call__ dispatches to the Controller method
38 # WSGIController.__call__ dispatches to the Controller method
41 # the request is routed to. This routing information is
39 # the request is routed to. This routing information is
42 # available in environ['pylons.routes_dict']
40 # available in environ['pylons.routes_dict']
43 start = time.time()
41 start = time.time()
44 try:
42 try:
45 # putting this here makes sure that we update permissions each time
43 # make sure that we update permissions each time we call controller
46 api_key = request.GET.get('api_key')
44 api_key = request.GET.get('api_key')
47 user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
45 user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
48 if asbool(config.get('container_auth_enabled', False)):
46 if asbool(config.get('container_auth_enabled', False)):
49 username = get_container_username(environ)
47 username = get_container_username(environ)
50 else:
48 else:
51 username = None
49 username = None
52
50 auth_user = AuthUser(user_id, api_key, username)
53 self.rhodecode_user = c.rhodecode_user = AuthUser(user_id, api_key, username)
51 self.rhodecode_user = c.rhodecode_user = auth_user
54 if not self.rhodecode_user.is_authenticated and \
52 if not self.rhodecode_user.is_authenticated and \
55 self.rhodecode_user.user_id is not None:
53 self.rhodecode_user.user_id is not None:
56 self.rhodecode_user.set_authenticated(
54 self.rhodecode_user.set_authenticated(
57 getattr(session.get('rhodecode_user'),
55 getattr(session.get('rhodecode_user'),
58 'is_authenticated', False))
56 'is_authenticated', False))
59 session['rhodecode_user'] = self.rhodecode_user
57 session['rhodecode_user'] = self.rhodecode_user
60 session.save()
58 session.save()
61 return WSGIController.__call__(self, environ, start_response)
59 return WSGIController.__call__(self, environ, start_response)
62 finally:
60 finally:
63 log.debug('Request time: %.3fs' % (time.time()-start))
61 log.debug('Request time: %.3fs' % (time.time()-start))
64 meta.Session.remove()
62 meta.Session.remove()
65
63
66
64
67 class BaseRepoController(BaseController):
65 class BaseRepoController(BaseController):
68 """
66 """
69 Base class for controllers responsible for loading all needed data
67 Base class for controllers responsible for loading all needed data for
70 for those controllers, loaded items are
68 repository loaded items are
71
69
72 c.rhodecode_repo: instance of scm repository (taken from cache)
70 c.rhodecode_repo: instance of scm repository
73
71 c.rhodecode_db_repo: instance of db
72 c.repository_followers: number of followers
73 c.repository_forks: number of forks
74 """
74 """
75
75
76 def __before__(self):
76 def __before__(self):
77 super(BaseRepoController, self).__before__()
77 super(BaseRepoController, self).__before__()
78 if c.repo_name:
78 if c.repo_name:
79
79
80 c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
80 c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
81 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
81 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
82
82
83 if c.rhodecode_repo is None:
83 if c.rhodecode_repo is None:
84 log.error('%s this repository is present in database but it '
84 log.error('%s this repository is present in database but it '
85 'cannot be created as an scm instance', c.repo_name)
85 'cannot be created as an scm instance', c.repo_name)
86
86
87 redirect(url('home'))
87 redirect(url('home'))
88
88
89 c.repository_followers = \
89 c.repository_followers = self.scm_model.get_followers(c.repo_name)
90 self.scm_model.get_followers(c.repo_name)
91 c.repository_forks = self.scm_model.get_forks(c.repo_name)
90 c.repository_forks = self.scm_model.get_forks(c.repo_name)
92
91
@@ -1,694 +1,694 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import os
22 import os
23 import re
23 import re
24 import logging
24 import logging
25 import traceback
25 import traceback
26
26
27 import formencode
27 import formencode
28 from formencode import All
28 from formencode import All
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
30 Email, Bool, StringBoolean, Set
30 Email, Bool, StringBoolean, Set
31
31
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34
34
35 from rhodecode.config.routing import ADMIN_PREFIX
35 from rhodecode.config.routing import ADMIN_PREFIX
36 from rhodecode.lib.utils import repo_name_slug
36 from rhodecode.lib.utils import repo_name_slug
37 from rhodecode.lib.auth import authenticate, get_crypt_password
37 from rhodecode.lib.auth import authenticate, get_crypt_password
38 from rhodecode.lib.exceptions import LdapImportError
38 from rhodecode.lib.exceptions import LdapImportError
39 from rhodecode.model.user import UserModel
39 from rhodecode.model.user import UserModel
40 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.repo import RepoModel
41 from rhodecode.model.db import User, UsersGroup, Group
41 from rhodecode.model.db import User, UsersGroup, Group
42 from rhodecode import BACKENDS
42 from rhodecode import BACKENDS
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46 #this is needed to translate the messages using _() in validators
46 #this is needed to translate the messages using _() in validators
47 class State_obj(object):
47 class State_obj(object):
48 _ = staticmethod(_)
48 _ = staticmethod(_)
49
49
50 #==============================================================================
50 #==============================================================================
51 # VALIDATORS
51 # VALIDATORS
52 #==============================================================================
52 #==============================================================================
53 class ValidAuthToken(formencode.validators.FancyValidator):
53 class ValidAuthToken(formencode.validators.FancyValidator):
54 messages = {'invalid_token':_('Token mismatch')}
54 messages = {'invalid_token':_('Token mismatch')}
55
55
56 def validate_python(self, value, state):
56 def validate_python(self, value, state):
57
57
58 if value != authentication_token():
58 if value != authentication_token():
59 raise formencode.Invalid(self.message('invalid_token', state,
59 raise formencode.Invalid(self.message('invalid_token', state,
60 search_number=value), value, state)
60 search_number=value), value, state)
61
61
62 def ValidUsername(edit, old_data):
62 def ValidUsername(edit, old_data):
63 class _ValidUsername(formencode.validators.FancyValidator):
63 class _ValidUsername(formencode.validators.FancyValidator):
64
64
65 def validate_python(self, value, state):
65 def validate_python(self, value, state):
66 if value in ['default', 'new_user']:
66 if value in ['default', 'new_user']:
67 raise formencode.Invalid(_('Invalid username'), value, state)
67 raise formencode.Invalid(_('Invalid username'), value, state)
68 #check if user is unique
68 #check if user is unique
69 old_un = None
69 old_un = None
70 if edit:
70 if edit:
71 old_un = UserModel().get(old_data.get('user_id')).username
71 old_un = UserModel().get(old_data.get('user_id')).username
72
72
73 if old_un != value or not edit:
73 if old_un != value or not edit:
74 if User.get_by_username(value, case_insensitive=True):
74 if User.get_by_username(value, case_insensitive=True):
75 raise formencode.Invalid(_('This username already '
75 raise formencode.Invalid(_('This username already '
76 'exists') , value, state)
76 'exists') , value, state)
77
77
78 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
78 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
79 raise formencode.Invalid(_('Username may only contain '
79 raise formencode.Invalid(_('Username may only contain '
80 'alphanumeric characters '
80 'alphanumeric characters '
81 'underscores, periods or dashes '
81 'underscores, periods or dashes '
82 'and must begin with alphanumeric '
82 'and must begin with alphanumeric '
83 'character'), value, state)
83 'character'), value, state)
84
84
85 return _ValidUsername
85 return _ValidUsername
86
86
87
87
88 def ValidUsersGroup(edit, old_data):
88 def ValidUsersGroup(edit, old_data):
89
89
90 class _ValidUsersGroup(formencode.validators.FancyValidator):
90 class _ValidUsersGroup(formencode.validators.FancyValidator):
91
91
92 def validate_python(self, value, state):
92 def validate_python(self, value, state):
93 if value in ['default']:
93 if value in ['default']:
94 raise formencode.Invalid(_('Invalid group name'), value, state)
94 raise formencode.Invalid(_('Invalid group name'), value, state)
95 #check if group is unique
95 #check if group is unique
96 old_ugname = None
96 old_ugname = None
97 if edit:
97 if edit:
98 old_ugname = UsersGroup.get(
98 old_ugname = UsersGroup.get(
99 old_data.get('users_group_id')).users_group_name
99 old_data.get('users_group_id')).users_group_name
100
100
101 if old_ugname != value or not edit:
101 if old_ugname != value or not edit:
102 if UsersGroup.get_by_group_name(value, cache=False,
102 if UsersGroup.get_by_group_name(value, cache=False,
103 case_insensitive=True):
103 case_insensitive=True):
104 raise formencode.Invalid(_('This users group '
104 raise formencode.Invalid(_('This users group '
105 'already exists') , value,
105 'already exists') , value,
106 state)
106 state)
107
107
108
108
109 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
109 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
110 raise formencode.Invalid(_('Group name may only contain '
110 raise formencode.Invalid(_('Group name may only contain '
111 'alphanumeric characters '
111 'alphanumeric characters '
112 'underscores, periods or dashes '
112 'underscores, periods or dashes '
113 'and must begin with alphanumeric '
113 'and must begin with alphanumeric '
114 'character'), value, state)
114 'character'), value, state)
115
115
116 return _ValidUsersGroup
116 return _ValidUsersGroup
117
117
118
118
119 def ValidReposGroup(edit, old_data):
119 def ValidReposGroup(edit, old_data):
120 class _ValidReposGroup(formencode.validators.FancyValidator):
120 class _ValidReposGroup(formencode.validators.FancyValidator):
121
121
122 def validate_python(self, value, state):
122 def validate_python(self, value, state):
123 #TODO WRITE VALIDATIONS
123 #TODO WRITE VALIDATIONS
124 group_name = value.get('group_name')
124 group_name = value.get('group_name')
125 group_parent_id = int(value.get('group_parent_id') or -1)
125 group_parent_id = int(value.get('group_parent_id') or -1)
126
126
127 # slugify repo group just in case :)
127 # slugify repo group just in case :)
128 slug = repo_name_slug(group_name)
128 slug = repo_name_slug(group_name)
129
129
130 # check for parent of self
130 # check for parent of self
131 if edit and old_data['group_id'] == group_parent_id:
131 if edit and old_data['group_id'] == group_parent_id:
132 e_dict = {'group_parent_id':_('Cannot assign this group '
132 e_dict = {'group_parent_id':_('Cannot assign this group '
133 'as parent')}
133 'as parent')}
134 raise formencode.Invalid('', value, state,
134 raise formencode.Invalid('', value, state,
135 error_dict=e_dict)
135 error_dict=e_dict)
136
136
137 old_gname = None
137 old_gname = None
138 if edit:
138 if edit:
139 old_gname = Group.get(
139 old_gname = Group.get(
140 old_data.get('group_id')).group_name
140 old_data.get('group_id')).group_name
141
141
142 if old_gname != group_name or not edit:
142 if old_gname != group_name or not edit:
143 # check filesystem
143 # check filesystem
144 gr = Group.query().filter(Group.group_name == slug)\
144 gr = Group.query().filter(Group.group_name == slug)\
145 .filter(Group.group_parent_id == group_parent_id).scalar()
145 .filter(Group.group_parent_id == group_parent_id).scalar()
146
146
147 if gr:
147 if gr:
148 e_dict = {'group_name':_('This group already exists')}
148 e_dict = {'group_name':_('This group already exists')}
149 raise formencode.Invalid('', value, state,
149 raise formencode.Invalid('', value, state,
150 error_dict=e_dict)
150 error_dict=e_dict)
151
151
152 return _ValidReposGroup
152 return _ValidReposGroup
153
153
154 class ValidPassword(formencode.validators.FancyValidator):
154 class ValidPassword(formencode.validators.FancyValidator):
155
155
156 def to_python(self, value, state):
156 def to_python(self, value, state):
157
157
158 if value:
158 if value:
159
159
160 if value.get('password'):
160 if value.get('password'):
161 try:
161 try:
162 value['password'] = get_crypt_password(value['password'])
162 value['password'] = get_crypt_password(value['password'])
163 except UnicodeEncodeError:
163 except UnicodeEncodeError:
164 e_dict = {'password':_('Invalid characters in password')}
164 e_dict = {'password':_('Invalid characters in password')}
165 raise formencode.Invalid('', value, state, error_dict=e_dict)
165 raise formencode.Invalid('', value, state, error_dict=e_dict)
166
166
167 if value.get('password_confirmation'):
167 if value.get('password_confirmation'):
168 try:
168 try:
169 value['password_confirmation'] = \
169 value['password_confirmation'] = \
170 get_crypt_password(value['password_confirmation'])
170 get_crypt_password(value['password_confirmation'])
171 except UnicodeEncodeError:
171 except UnicodeEncodeError:
172 e_dict = {'password_confirmation':_('Invalid characters in password')}
172 e_dict = {'password_confirmation':_('Invalid characters in password')}
173 raise formencode.Invalid('', value, state, error_dict=e_dict)
173 raise formencode.Invalid('', value, state, error_dict=e_dict)
174
174
175 if value.get('new_password'):
175 if value.get('new_password'):
176 try:
176 try:
177 value['new_password'] = \
177 value['new_password'] = \
178 get_crypt_password(value['new_password'])
178 get_crypt_password(value['new_password'])
179 except UnicodeEncodeError:
179 except UnicodeEncodeError:
180 e_dict = {'new_password':_('Invalid characters in password')}
180 e_dict = {'new_password':_('Invalid characters in password')}
181 raise formencode.Invalid('', value, state, error_dict=e_dict)
181 raise formencode.Invalid('', value, state, error_dict=e_dict)
182
182
183 return value
183 return value
184
184
185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
186
186
187 def validate_python(self, value, state):
187 def validate_python(self, value, state):
188
188
189 pass_val = value.get('password') or value.get('new_password')
189 pass_val = value.get('password') or value.get('new_password')
190 if pass_val != value['password_confirmation']:
190 if pass_val != value['password_confirmation']:
191 e_dict = {'password_confirmation':
191 e_dict = {'password_confirmation':
192 _('Passwords do not match')}
192 _('Passwords do not match')}
193 raise formencode.Invalid('', value, state, error_dict=e_dict)
193 raise formencode.Invalid('', value, state, error_dict=e_dict)
194
194
195 class ValidAuth(formencode.validators.FancyValidator):
195 class ValidAuth(formencode.validators.FancyValidator):
196 messages = {
196 messages = {
197 'invalid_password':_('invalid password'),
197 'invalid_password':_('invalid password'),
198 'invalid_login':_('invalid user name'),
198 'invalid_login':_('invalid user name'),
199 'disabled_account':_('Your account is disabled')
199 'disabled_account':_('Your account is disabled')
200 }
200 }
201
201
202 # error mapping
202 # error mapping
203 e_dict = {'username':messages['invalid_login'],
203 e_dict = {'username':messages['invalid_login'],
204 'password':messages['invalid_password']}
204 'password':messages['invalid_password']}
205 e_dict_disable = {'username':messages['disabled_account']}
205 e_dict_disable = {'username':messages['disabled_account']}
206
206
207 def validate_python(self, value, state):
207 def validate_python(self, value, state):
208 password = value['password']
208 password = value['password']
209 username = value['username']
209 username = value['username']
210 user = User.get_by_username(username)
210 user = User.get_by_username(username)
211
211
212 if authenticate(username, password):
212 if authenticate(username, password):
213 return value
213 return value
214 else:
214 else:
215 if user and user.active is False:
215 if user and user.active is False:
216 log.warning('user %s is disabled', username)
216 log.warning('user %s is disabled', username)
217 raise formencode.Invalid(self.message('disabled_account',
217 raise formencode.Invalid(self.message('disabled_account',
218 state=State_obj),
218 state=State_obj),
219 value, state,
219 value, state,
220 error_dict=self.e_dict_disable)
220 error_dict=self.e_dict_disable)
221 else:
221 else:
222 log.warning('user %s not authenticated', username)
222 log.warning('user %s not authenticated', username)
223 raise formencode.Invalid(self.message('invalid_password',
223 raise formencode.Invalid(self.message('invalid_password',
224 state=State_obj), value, state,
224 state=State_obj), value, state,
225 error_dict=self.e_dict)
225 error_dict=self.e_dict)
226
226
227 class ValidRepoUser(formencode.validators.FancyValidator):
227 class ValidRepoUser(formencode.validators.FancyValidator):
228
228
229 def to_python(self, value, state):
229 def to_python(self, value, state):
230 try:
230 try:
231 User.query().filter(User.active == True)\
231 User.query().filter(User.active == True)\
232 .filter(User.username == value).one()
232 .filter(User.username == value).one()
233 except Exception:
233 except Exception:
234 raise formencode.Invalid(_('This username is not valid'),
234 raise formencode.Invalid(_('This username is not valid'),
235 value, state)
235 value, state)
236 return value
236 return value
237
237
238 def ValidRepoName(edit, old_data):
238 def ValidRepoName(edit, old_data):
239 class _ValidRepoName(formencode.validators.FancyValidator):
239 class _ValidRepoName(formencode.validators.FancyValidator):
240 def to_python(self, value, state):
240 def to_python(self, value, state):
241
241
242 repo_name = value.get('repo_name')
242 repo_name = value.get('repo_name')
243
243
244 slug = repo_name_slug(repo_name)
244 slug = repo_name_slug(repo_name)
245 if slug in [ADMIN_PREFIX, '']:
245 if slug in [ADMIN_PREFIX, '']:
246 e_dict = {'repo_name': _('This repository name is disallowed')}
246 e_dict = {'repo_name': _('This repository name is disallowed')}
247 raise formencode.Invalid('', value, state, error_dict=e_dict)
247 raise formencode.Invalid('', value, state, error_dict=e_dict)
248
248
249
249
250 if value.get('repo_group'):
250 if value.get('repo_group'):
251 gr = Group.get(value.get('repo_group'))
251 gr = Group.get(value.get('repo_group'))
252 group_path = gr.full_path
252 group_path = gr.full_path
253 # value needs to be aware of group name in order to check
253 # value needs to be aware of group name in order to check
254 # db key This is an actual just the name to store in the
254 # db key This is an actual just the name to store in the
255 # database
255 # database
256 repo_name_full = group_path + Group.url_sep() + repo_name
256 repo_name_full = group_path + Group.url_sep() + repo_name
257
257
258 else:
258 else:
259 group_path = ''
259 group_path = ''
260 repo_name_full = repo_name
260 repo_name_full = repo_name
261
261
262
262
263 value['repo_name_full'] = repo_name_full
263 value['repo_name_full'] = repo_name_full
264 rename = old_data.get('repo_name') != repo_name_full
264 rename = old_data.get('repo_name') != repo_name_full
265 create = not edit
265 create = not edit
266 if rename or create:
266 if rename or create:
267
267
268 if group_path != '':
268 if group_path != '':
269 if RepoModel().get_by_repo_name(repo_name_full,):
269 if RepoModel().get_by_repo_name(repo_name_full,):
270 e_dict = {'repo_name':_('This repository already '
270 e_dict = {'repo_name':_('This repository already '
271 'exists in a group "%s"') %
271 'exists in a group "%s"') %
272 gr.group_name}
272 gr.group_name}
273 raise formencode.Invalid('', value, state,
273 raise formencode.Invalid('', value, state,
274 error_dict=e_dict)
274 error_dict=e_dict)
275 elif Group.get_by_group_name(repo_name_full):
275 elif Group.get_by_group_name(repo_name_full):
276 e_dict = {'repo_name':_('There is a group with this'
276 e_dict = {'repo_name':_('There is a group with this'
277 ' name already "%s"') %
277 ' name already "%s"') %
278 repo_name_full}
278 repo_name_full}
279 raise formencode.Invalid('', value, state,
279 raise formencode.Invalid('', value, state,
280 error_dict=e_dict)
280 error_dict=e_dict)
281
281
282 elif RepoModel().get_by_repo_name(repo_name_full):
282 elif RepoModel().get_by_repo_name(repo_name_full):
283 e_dict = {'repo_name':_('This repository '
283 e_dict = {'repo_name':_('This repository '
284 'already exists')}
284 'already exists')}
285 raise formencode.Invalid('', value, state,
285 raise formencode.Invalid('', value, state,
286 error_dict=e_dict)
286 error_dict=e_dict)
287
287
288 return value
288 return value
289
289
290 return _ValidRepoName
290 return _ValidRepoName
291
291
292 def ValidForkName():
292 def ValidForkName():
293 class _ValidForkName(formencode.validators.FancyValidator):
293 class _ValidForkName(formencode.validators.FancyValidator):
294 def to_python(self, value, state):
294 def to_python(self, value, state):
295
295
296 repo_name = value.get('fork_name')
296 repo_name = value.get('fork_name')
297
297
298 slug = repo_name_slug(repo_name)
298 slug = repo_name_slug(repo_name)
299 if slug in [ADMIN_PREFIX, '']:
299 if slug in [ADMIN_PREFIX, '']:
300 e_dict = {'repo_name': _('This repository name is disallowed')}
300 e_dict = {'repo_name': _('This repository name is disallowed')}
301 raise formencode.Invalid('', value, state, error_dict=e_dict)
301 raise formencode.Invalid('', value, state, error_dict=e_dict)
302
302
303 if RepoModel().get_by_repo_name(repo_name):
303 if RepoModel().get_by_repo_name(repo_name):
304 e_dict = {'fork_name':_('This repository '
304 e_dict = {'fork_name':_('This repository '
305 'already exists')}
305 'already exists')}
306 raise formencode.Invalid('', value, state,
306 raise formencode.Invalid('', value, state,
307 error_dict=e_dict)
307 error_dict=e_dict)
308 return value
308 return value
309 return _ValidForkName
309 return _ValidForkName
310
310
311
311
312 def SlugifyName():
312 def SlugifyName():
313 class _SlugifyName(formencode.validators.FancyValidator):
313 class _SlugifyName(formencode.validators.FancyValidator):
314
314
315 def to_python(self, value, state):
315 def to_python(self, value, state):
316 return repo_name_slug(value)
316 return repo_name_slug(value)
317
317
318 return _SlugifyName
318 return _SlugifyName
319
319
320 def ValidCloneUri():
320 def ValidCloneUri():
321 from mercurial.httprepo import httprepository, httpsrepository
321 from mercurial.httprepo import httprepository, httpsrepository
322 from rhodecode.lib.utils import make_ui
322 from rhodecode.lib.utils import make_ui
323
323
324 class _ValidCloneUri(formencode.validators.FancyValidator):
324 class _ValidCloneUri(formencode.validators.FancyValidator):
325
325
326 def to_python(self, value, state):
326 def to_python(self, value, state):
327 if not value:
327 if not value:
328 pass
328 pass
329 elif value.startswith('https'):
329 elif value.startswith('https'):
330 try:
330 try:
331 httpsrepository(make_ui('db'), value).capabilities
331 httpsrepository(make_ui('db'), value).capabilities
332 except Exception, e:
332 except Exception, e:
333 log.error(traceback.format_exc())
333 log.error(traceback.format_exc())
334 raise formencode.Invalid(_('invalid clone url'), value,
334 raise formencode.Invalid(_('invalid clone url'), value,
335 state)
335 state)
336 elif value.startswith('http'):
336 elif value.startswith('http'):
337 try:
337 try:
338 httprepository(make_ui('db'), value).capabilities
338 httprepository(make_ui('db'), value).capabilities
339 except Exception, e:
339 except Exception, e:
340 log.error(traceback.format_exc())
340 log.error(traceback.format_exc())
341 raise formencode.Invalid(_('invalid clone url'), value,
341 raise formencode.Invalid(_('invalid clone url'), value,
342 state)
342 state)
343 else:
343 else:
344 raise formencode.Invalid(_('Invalid clone url, provide a '
344 raise formencode.Invalid(_('Invalid clone url, provide a '
345 'valid clone http\s url'), value,
345 'valid clone http\s url'), value,
346 state)
346 state)
347 return value
347 return value
348
348
349 return _ValidCloneUri
349 return _ValidCloneUri
350
350
351 def ValidForkType(old_data):
351 def ValidForkType(old_data):
352 class _ValidForkType(formencode.validators.FancyValidator):
352 class _ValidForkType(formencode.validators.FancyValidator):
353
353
354 def to_python(self, value, state):
354 def to_python(self, value, state):
355 if old_data['repo_type'] != value:
355 if old_data['repo_type'] != value:
356 raise formencode.Invalid(_('Fork have to be the same '
356 raise formencode.Invalid(_('Fork have to be the same '
357 'type as original'), value, state)
357 'type as original'), value, state)
358
358
359 return value
359 return value
360 return _ValidForkType
360 return _ValidForkType
361
361
362 class ValidPerms(formencode.validators.FancyValidator):
362 class ValidPerms(formencode.validators.FancyValidator):
363 messages = {'perm_new_member_name':_('This username or users group name'
363 messages = {'perm_new_member_name':_('This username or users group name'
364 ' is not valid')}
364 ' is not valid')}
365
365
366 def to_python(self, value, state):
366 def to_python(self, value, state):
367 perms_update = []
367 perms_update = []
368 perms_new = []
368 perms_new = []
369 #build a list of permission to update and new permission to create
369 #build a list of permission to update and new permission to create
370 for k, v in value.items():
370 for k, v in value.items():
371 #means new added member to permissions
371 #means new added member to permissions
372 if k.startswith('perm_new_member'):
372 if k.startswith('perm_new_member'):
373 new_perm = value.get('perm_new_member', False)
373 new_perm = value.get('perm_new_member', False)
374 new_member = value.get('perm_new_member_name', False)
374 new_member = value.get('perm_new_member_name', False)
375 new_type = value.get('perm_new_member_type')
375 new_type = value.get('perm_new_member_type')
376
376
377 if new_member and new_perm:
377 if new_member and new_perm:
378 if (new_member, new_perm, new_type) not in perms_new:
378 if (new_member, new_perm, new_type) not in perms_new:
379 perms_new.append((new_member, new_perm, new_type))
379 perms_new.append((new_member, new_perm, new_type))
380 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
380 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
381 member = k[7:]
381 member = k[7:]
382 t = {'u':'user',
382 t = {'u':'user',
383 'g':'users_group'}[k[0]]
383 'g':'users_group'}[k[0]]
384 if member == 'default':
384 if member == 'default':
385 if value['private']:
385 if value['private']:
386 #set none for default when updating to private repo
386 #set none for default when updating to private repo
387 v = 'repository.none'
387 v = 'repository.none'
388 perms_update.append((member, v, t))
388 perms_update.append((member, v, t))
389
389
390 value['perms_updates'] = perms_update
390 value['perms_updates'] = perms_update
391 value['perms_new'] = perms_new
391 value['perms_new'] = perms_new
392
392
393 #update permissions
393 #update permissions
394 for k, v, t in perms_new:
394 for k, v, t in perms_new:
395 try:
395 try:
396 if t is 'user':
396 if t is 'user':
397 self.user_db = User.query()\
397 self.user_db = User.query()\
398 .filter(User.active == True)\
398 .filter(User.active == True)\
399 .filter(User.username == k).one()
399 .filter(User.username == k).one()
400 if t is 'users_group':
400 if t is 'users_group':
401 self.user_db = UsersGroup.query()\
401 self.user_db = UsersGroup.query()\
402 .filter(UsersGroup.users_group_active == True)\
402 .filter(UsersGroup.users_group_active == True)\
403 .filter(UsersGroup.users_group_name == k).one()
403 .filter(UsersGroup.users_group_name == k).one()
404
404
405 except Exception:
405 except Exception:
406 msg = self.message('perm_new_member_name',
406 msg = self.message('perm_new_member_name',
407 state=State_obj)
407 state=State_obj)
408 raise formencode.Invalid(msg, value, state,
408 raise formencode.Invalid(msg, value, state,
409 error_dict={'perm_new_member_name':msg})
409 error_dict={'perm_new_member_name':msg})
410 return value
410 return value
411
411
412 class ValidSettings(formencode.validators.FancyValidator):
412 class ValidSettings(formencode.validators.FancyValidator):
413
413
414 def to_python(self, value, state):
414 def to_python(self, value, state):
415 #settings form can't edit user
415 #settings form can't edit user
416 if value.has_key('user'):
416 if value.has_key('user'):
417 del['value']['user']
417 del['value']['user']
418
418
419 return value
419 return value
420
420
421 class ValidPath(formencode.validators.FancyValidator):
421 class ValidPath(formencode.validators.FancyValidator):
422 def to_python(self, value, state):
422 def to_python(self, value, state):
423
423
424 if not os.path.isdir(value):
424 if not os.path.isdir(value):
425 msg = _('This is not a valid path')
425 msg = _('This is not a valid path')
426 raise formencode.Invalid(msg, value, state,
426 raise formencode.Invalid(msg, value, state,
427 error_dict={'paths_root_path':msg})
427 error_dict={'paths_root_path':msg})
428 return value
428 return value
429
429
430 def UniqSystemEmail(old_data):
430 def UniqSystemEmail(old_data):
431 class _UniqSystemEmail(formencode.validators.FancyValidator):
431 class _UniqSystemEmail(formencode.validators.FancyValidator):
432 def to_python(self, value, state):
432 def to_python(self, value, state):
433 value = value.lower()
433 value = value.lower()
434 if old_data.get('email') != value:
434 if old_data.get('email') != value:
435 user = User.query().filter(User.email == value).scalar()
435 user = User.query().filter(User.email == value).scalar()
436 if user:
436 if user:
437 raise formencode.Invalid(
437 raise formencode.Invalid(
438 _("This e-mail address is already taken"),
438 _("This e-mail address is already taken"),
439 value, state)
439 value, state)
440 return value
440 return value
441
441
442 return _UniqSystemEmail
442 return _UniqSystemEmail
443
443
444 class ValidSystemEmail(formencode.validators.FancyValidator):
444 class ValidSystemEmail(formencode.validators.FancyValidator):
445 def to_python(self, value, state):
445 def to_python(self, value, state):
446 value = value.lower()
446 value = value.lower()
447 user = User.query().filter(User.email == value).scalar()
447 user = User.query().filter(User.email == value).scalar()
448 if user is None:
448 if user is None:
449 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
449 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
450 value, state)
450 value, state)
451
451
452 return value
452 return value
453
453
454 class LdapLibValidator(formencode.validators.FancyValidator):
454 class LdapLibValidator(formencode.validators.FancyValidator):
455
455
456 def to_python(self, value, state):
456 def to_python(self, value, state):
457
457
458 try:
458 try:
459 import ldap
459 import ldap
460 except ImportError:
460 except ImportError:
461 raise LdapImportError
461 raise LdapImportError
462 return value
462 return value
463
463
464 class AttrLoginValidator(formencode.validators.FancyValidator):
464 class AttrLoginValidator(formencode.validators.FancyValidator):
465
465
466 def to_python(self, value, state):
466 def to_python(self, value, state):
467
467
468 if not value or not isinstance(value, (str, unicode)):
468 if not value or not isinstance(value, (str, unicode)):
469 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
469 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
470 "must be specified - this is the name "
470 "must be specified - this is the name "
471 "of the attribute that is equivalent "
471 "of the attribute that is equivalent "
472 "to 'username'"),
472 "to 'username'"),
473 value, state)
473 value, state)
474
474
475 return value
475 return value
476
476
477 #===============================================================================
477 #===============================================================================
478 # FORMS
478 # FORMS
479 #===============================================================================
479 #===============================================================================
480 class LoginForm(formencode.Schema):
480 class LoginForm(formencode.Schema):
481 allow_extra_fields = True
481 allow_extra_fields = True
482 filter_extra_fields = True
482 filter_extra_fields = True
483 username = UnicodeString(
483 username = UnicodeString(
484 strip=True,
484 strip=True,
485 min=1,
485 min=1,
486 not_empty=True,
486 not_empty=True,
487 messages={
487 messages={
488 'empty':_('Please enter a login'),
488 'empty':_('Please enter a login'),
489 'tooShort':_('Enter a value %(min)i characters long or more')}
489 'tooShort':_('Enter a value %(min)i characters long or more')}
490 )
490 )
491
491
492 password = UnicodeString(
492 password = UnicodeString(
493 strip=True,
493 strip=True,
494 min=3,
494 min=3,
495 not_empty=True,
495 not_empty=True,
496 messages={
496 messages={
497 'empty':_('Please enter a password'),
497 'empty':_('Please enter a password'),
498 'tooShort':_('Enter %(min)i characters or more')}
498 'tooShort':_('Enter %(min)i characters or more')}
499 )
499 )
500
500
501 chained_validators = [ValidAuth]
501 chained_validators = [ValidAuth]
502
502
503 def UserForm(edit=False, old_data={}):
503 def UserForm(edit=False, old_data={}):
504 class _UserForm(formencode.Schema):
504 class _UserForm(formencode.Schema):
505 allow_extra_fields = True
505 allow_extra_fields = True
506 filter_extra_fields = True
506 filter_extra_fields = True
507 username = All(UnicodeString(strip=True, min=1, not_empty=True),
507 username = All(UnicodeString(strip=True, min=1, not_empty=True),
508 ValidUsername(edit, old_data))
508 ValidUsername(edit, old_data))
509 if edit:
509 if edit:
510 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
510 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
511 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
511 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
512 admin = StringBoolean(if_missing=False)
512 admin = StringBoolean(if_missing=False)
513 else:
513 else:
514 password = All(UnicodeString(strip=True, min=6, not_empty=True))
514 password = All(UnicodeString(strip=True, min=6, not_empty=True))
515 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
515 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
516
516
517 active = StringBoolean(if_missing=False)
517 active = StringBoolean(if_missing=False)
518 name = UnicodeString(strip=True, min=1, not_empty=True)
518 name = UnicodeString(strip=True, min=1, not_empty=True)
519 lastname = UnicodeString(strip=True, min=1, not_empty=True)
519 lastname = UnicodeString(strip=True, min=1, not_empty=True)
520 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
520 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
521
521
522 chained_validators = [ValidPasswordsMatch, ValidPassword]
522 chained_validators = [ValidPasswordsMatch, ValidPassword]
523
523
524 return _UserForm
524 return _UserForm
525
525
526
526
527 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
527 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
528 class _UsersGroupForm(formencode.Schema):
528 class _UsersGroupForm(formencode.Schema):
529 allow_extra_fields = True
529 allow_extra_fields = True
530 filter_extra_fields = True
530 filter_extra_fields = True
531
531
532 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
532 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
533 ValidUsersGroup(edit, old_data))
533 ValidUsersGroup(edit, old_data))
534
534
535 users_group_active = StringBoolean(if_missing=False)
535 users_group_active = StringBoolean(if_missing=False)
536
536
537 if edit:
537 if edit:
538 users_group_members = OneOf(available_members, hideList=False,
538 users_group_members = OneOf(available_members, hideList=False,
539 testValueList=True,
539 testValueList=True,
540 if_missing=None, not_empty=False)
540 if_missing=None, not_empty=False)
541
541
542 return _UsersGroupForm
542 return _UsersGroupForm
543
543
544 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
544 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
545 class _ReposGroupForm(formencode.Schema):
545 class _ReposGroupForm(formencode.Schema):
546 allow_extra_fields = True
546 allow_extra_fields = True
547 filter_extra_fields = True
547 filter_extra_fields = True
548
548
549 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
549 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
550 SlugifyName())
550 SlugifyName())
551 group_description = UnicodeString(strip=True, min=1,
551 group_description = UnicodeString(strip=True, min=1,
552 not_empty=True)
552 not_empty=True)
553 group_parent_id = OneOf(available_groups, hideList=False,
553 group_parent_id = OneOf(available_groups, hideList=False,
554 testValueList=True,
554 testValueList=True,
555 if_missing=None, not_empty=False)
555 if_missing=None, not_empty=False)
556
556
557 chained_validators = [ValidReposGroup(edit, old_data)]
557 chained_validators = [ValidReposGroup(edit, old_data)]
558
558
559 return _ReposGroupForm
559 return _ReposGroupForm
560
560
561 def RegisterForm(edit=False, old_data={}):
561 def RegisterForm(edit=False, old_data={}):
562 class _RegisterForm(formencode.Schema):
562 class _RegisterForm(formencode.Schema):
563 allow_extra_fields = True
563 allow_extra_fields = True
564 filter_extra_fields = True
564 filter_extra_fields = True
565 username = All(ValidUsername(edit, old_data),
565 username = All(ValidUsername(edit, old_data),
566 UnicodeString(strip=True, min=1, not_empty=True))
566 UnicodeString(strip=True, min=1, not_empty=True))
567 password = All(UnicodeString(strip=True, min=6, not_empty=True))
567 password = All(UnicodeString(strip=True, min=6, not_empty=True))
568 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
568 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
569 active = StringBoolean(if_missing=False)
569 active = StringBoolean(if_missing=False)
570 name = UnicodeString(strip=True, min=1, not_empty=True)
570 name = UnicodeString(strip=True, min=1, not_empty=True)
571 lastname = UnicodeString(strip=True, min=1, not_empty=True)
571 lastname = UnicodeString(strip=True, min=1, not_empty=True)
572 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
572 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
573
573
574 chained_validators = [ValidPasswordsMatch, ValidPassword]
574 chained_validators = [ValidPasswordsMatch, ValidPassword]
575
575
576 return _RegisterForm
576 return _RegisterForm
577
577
578 def PasswordResetForm():
578 def PasswordResetForm():
579 class _PasswordResetForm(formencode.Schema):
579 class _PasswordResetForm(formencode.Schema):
580 allow_extra_fields = True
580 allow_extra_fields = True
581 filter_extra_fields = True
581 filter_extra_fields = True
582 email = All(ValidSystemEmail(), Email(not_empty=True))
582 email = All(ValidSystemEmail(), Email(not_empty=True))
583 return _PasswordResetForm
583 return _PasswordResetForm
584
584
585 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
585 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
586 repo_groups=[]):
586 repo_groups=[]):
587 class _RepoForm(formencode.Schema):
587 class _RepoForm(formencode.Schema):
588 allow_extra_fields = True
588 allow_extra_fields = True
589 filter_extra_fields = False
589 filter_extra_fields = False
590 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
590 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
591 SlugifyName())
591 SlugifyName())
592 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
592 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
593 ValidCloneUri()())
593 ValidCloneUri()())
594 repo_group = OneOf(repo_groups, hideList=True)
594 repo_group = OneOf(repo_groups, hideList=True)
595 repo_type = OneOf(supported_backends)
595 repo_type = OneOf(supported_backends)
596 description = UnicodeString(strip=True, min=1, not_empty=True)
596 description = UnicodeString(strip=True, min=1, not_empty=True)
597 private = StringBoolean(if_missing=False)
597 private = StringBoolean(if_missing=False)
598 enable_statistics = StringBoolean(if_missing=False)
598 enable_statistics = StringBoolean(if_missing=False)
599 enable_downloads = StringBoolean(if_missing=False)
599 enable_downloads = StringBoolean(if_missing=False)
600
600
601 if edit:
601 if edit:
602 #this is repo owner
602 #this is repo owner
603 user = All(UnicodeString(not_empty=True), ValidRepoUser)
603 user = All(UnicodeString(not_empty=True), ValidRepoUser)
604
604
605 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
605 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
606 return _RepoForm
606 return _RepoForm
607
607
608 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
608 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
609 class _RepoForkForm(formencode.Schema):
609 class _RepoForkForm(formencode.Schema):
610 allow_extra_fields = True
610 allow_extra_fields = True
611 filter_extra_fields = False
611 filter_extra_fields = False
612 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
612 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
613 SlugifyName())
613 SlugifyName())
614 description = UnicodeString(strip=True, min=1, not_empty=True)
614 description = UnicodeString(strip=True, min=1, not_empty=True)
615 private = StringBoolean(if_missing=False)
615 private = StringBoolean(if_missing=False)
616 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
616 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
617
617
618 chained_validators = [ValidForkName()]
618 chained_validators = [ValidForkName()]
619
619
620 return _RepoForkForm
620 return _RepoForkForm
621
621
622 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
622 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
623 repo_groups=[]):
623 repo_groups=[]):
624 class _RepoForm(formencode.Schema):
624 class _RepoForm(formencode.Schema):
625 allow_extra_fields = True
625 allow_extra_fields = True
626 filter_extra_fields = False
626 filter_extra_fields = False
627 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
627 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
628 SlugifyName())
628 SlugifyName())
629 description = UnicodeString(strip=True, min=1, not_empty=True)
629 description = UnicodeString(strip=True, min=1, not_empty=True)
630 repo_group = OneOf(repo_groups, hideList=True)
630 repo_group = OneOf(repo_groups, hideList=True)
631 private = StringBoolean(if_missing=False)
631 private = StringBoolean(if_missing=False)
632
632
633 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
633 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
634 ValidSettings]
634 ValidSettings]
635 return _RepoForm
635 return _RepoForm
636
636
637
637
638 def ApplicationSettingsForm():
638 def ApplicationSettingsForm():
639 class _ApplicationSettingsForm(formencode.Schema):
639 class _ApplicationSettingsForm(formencode.Schema):
640 allow_extra_fields = True
640 allow_extra_fields = True
641 filter_extra_fields = False
641 filter_extra_fields = False
642 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
642 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
643 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
643 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
644 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
644 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
645
645
646 return _ApplicationSettingsForm
646 return _ApplicationSettingsForm
647
647
648 def ApplicationUiSettingsForm():
648 def ApplicationUiSettingsForm():
649 class _ApplicationUiSettingsForm(formencode.Schema):
649 class _ApplicationUiSettingsForm(formencode.Schema):
650 allow_extra_fields = True
650 allow_extra_fields = True
651 filter_extra_fields = False
651 filter_extra_fields = False
652 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
652 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
653 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
653 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
654 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
654 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
655 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
655 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
656 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
656 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
657 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
657 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
658
658
659 return _ApplicationUiSettingsForm
659 return _ApplicationUiSettingsForm
660
660
661 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
661 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
662 class _DefaultPermissionsForm(formencode.Schema):
662 class _DefaultPermissionsForm(formencode.Schema):
663 allow_extra_fields = True
663 allow_extra_fields = True
664 filter_extra_fields = True
664 filter_extra_fields = True
665 overwrite_default = StringBoolean(if_missing=False)
665 overwrite_default = StringBoolean(if_missing=False)
666 anonymous = OneOf(['True', 'False'], if_missing=False)
666 anonymous = OneOf(['True', 'False'], if_missing=False)
667 default_perm = OneOf(perms_choices)
667 default_perm = OneOf(perms_choices)
668 default_register = OneOf(register_choices)
668 default_register = OneOf(register_choices)
669 default_create = OneOf(create_choices)
669 default_create = OneOf(create_choices)
670
670
671 return _DefaultPermissionsForm
671 return _DefaultPermissionsForm
672
672
673
673
674 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
674 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
675 class _LdapSettingsForm(formencode.Schema):
675 class _LdapSettingsForm(formencode.Schema):
676 allow_extra_fields = True
676 allow_extra_fields = True
677 filter_extra_fields = True
677 filter_extra_fields = True
678 pre_validators = [LdapLibValidator]
678 pre_validators = [LdapLibValidator]
679 ldap_active = StringBoolean(if_missing=False)
679 ldap_active = StringBoolean(if_missing=False)
680 ldap_host = UnicodeString(strip=True,)
680 ldap_host = UnicodeString(strip=True,)
681 ldap_port = Number(strip=True,)
681 ldap_port = Number(strip=True,)
682 ldap_tls_kind = OneOf(tls_kind_choices)
682 ldap_tls_kind = OneOf(tls_kind_choices)
683 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
683 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
684 ldap_dn_user = UnicodeString(strip=True,)
684 ldap_dn_user = UnicodeString(strip=True,)
685 ldap_dn_pass = UnicodeString(strip=True,)
685 ldap_dn_pass = UnicodeString(strip=True,)
686 ldap_base_dn = UnicodeString(strip=True,)
686 ldap_base_dn = UnicodeString(strip=True,)
687 ldap_filter = UnicodeString(strip=True,)
687 ldap_filter = UnicodeString(strip=True,)
688 ldap_search_scope = OneOf(search_scope_choices)
688 ldap_search_scope = OneOf(search_scope_choices)
689 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
689 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
690 ldap_attr_firstname = UnicodeString(strip=True,)
690 ldap_attr_firstname = UnicodeString(strip=True,)
691 ldap_attr_lastname = UnicodeString(strip=True,)
691 ldap_attr_lastname = UnicodeString(strip=True,)
692 ldap_attr_email = UnicodeString(strip=True,)
692 ldap_attr_email = UnicodeString(strip=True,)
693
693
694 return _LdapSettingsForm
694 return _LdapSettingsForm
@@ -1,422 +1,422 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 users model for RhodeCode
6 users model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30
30
31 from rhodecode.lib import safe_unicode
31 from rhodecode.lib import safe_unicode
32 from rhodecode.model import BaseModel
32 from rhodecode.model import BaseModel
33 from rhodecode.model.caching_query import FromCache
33 from rhodecode.model.caching_query import FromCache
34 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
34 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
35 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
35 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
36 from rhodecode.lib.exceptions import DefaultUserException, \
36 from rhodecode.lib.exceptions import DefaultUserException, \
37 UserOwnsReposException
37 UserOwnsReposException
38
38
39 from sqlalchemy.exc import DatabaseError
39 from sqlalchemy.exc import DatabaseError
40 from rhodecode.lib import generate_api_key
40 from rhodecode.lib import generate_api_key
41 from sqlalchemy.orm import joinedload
41 from sqlalchemy.orm import joinedload
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45 PERM_WEIGHTS = {'repository.none': 0,
45 PERM_WEIGHTS = {'repository.none': 0,
46 'repository.read': 1,
46 'repository.read': 1,
47 'repository.write': 3,
47 'repository.write': 3,
48 'repository.admin': 3}
48 'repository.admin': 3}
49
49
50
50
51 class UserModel(BaseModel):
51 class UserModel(BaseModel):
52 def get(self, user_id, cache=False):
52 def get(self, user_id, cache=False):
53 user = self.sa.query(User)
53 user = self.sa.query(User)
54 if cache:
54 if cache:
55 user = user.options(FromCache("sql_cache_short",
55 user = user.options(FromCache("sql_cache_short",
56 "get_user_%s" % user_id))
56 "get_user_%s" % user_id))
57 return user.get(user_id)
57 return user.get(user_id)
58
58
59 def get_by_username(self, username, cache=False, case_insensitive=False):
59 def get_by_username(self, username, cache=False, case_insensitive=False):
60
60
61 if case_insensitive:
61 if case_insensitive:
62 user = self.sa.query(User).filter(User.username.ilike(username))
62 user = self.sa.query(User).filter(User.username.ilike(username))
63 else:
63 else:
64 user = self.sa.query(User)\
64 user = self.sa.query(User)\
65 .filter(User.username == username)
65 .filter(User.username == username)
66 if cache:
66 if cache:
67 user = user.options(FromCache("sql_cache_short",
67 user = user.options(FromCache("sql_cache_short",
68 "get_user_%s" % username))
68 "get_user_%s" % username))
69 return user.scalar()
69 return user.scalar()
70
70
71 def get_by_api_key(self, api_key, cache=False):
71 def get_by_api_key(self, api_key, cache=False):
72
72
73 user = self.sa.query(User)\
73 user = self.sa.query(User)\
74 .filter(User.api_key == api_key)
74 .filter(User.api_key == api_key)
75 if cache:
75 if cache:
76 user = user.options(FromCache("sql_cache_short",
76 user = user.options(FromCache("sql_cache_short",
77 "get_user_%s" % api_key))
77 "get_user_%s" % api_key))
78 return user.scalar()
78 return user.scalar()
79
79
80 def create(self, form_data):
80 def create(self, form_data):
81 try:
81 try:
82 new_user = User()
82 new_user = User()
83 for k, v in form_data.items():
83 for k, v in form_data.items():
84 setattr(new_user, k, v)
84 setattr(new_user, k, v)
85
85
86 new_user.api_key = generate_api_key(form_data['username'])
86 new_user.api_key = generate_api_key(form_data['username'])
87 self.sa.add(new_user)
87 self.sa.add(new_user)
88 self.sa.commit()
88 self.sa.commit()
89 return new_user
89 return new_user
90 except:
90 except:
91 log.error(traceback.format_exc())
91 log.error(traceback.format_exc())
92 self.sa.rollback()
92 self.sa.rollback()
93 raise
93 raise
94
94
95 def create_for_container_auth(self, username, attrs):
95 def create_for_container_auth(self, username, attrs):
96 """
96 """
97 Creates the given user if it's not already in the database
97 Creates the given user if it's not already in the database
98
98
99 :param username:
99 :param username:
100 :param attrs:
100 :param attrs:
101 """
101 """
102 if self.get_by_username(username, case_insensitive=True) is None:
102 if self.get_by_username(username, case_insensitive=True) is None:
103 try:
103 try:
104 new_user = User()
104 new_user = User()
105 new_user.username = username
105 new_user.username = username
106 new_user.password = None
106 new_user.password = None
107 new_user.api_key = generate_api_key(username)
107 new_user.api_key = generate_api_key(username)
108 new_user.email = attrs['email']
108 new_user.email = attrs['email']
109 new_user.active = True
109 new_user.active = attrs.get('active', True)
110 new_user.name = attrs['name']
110 new_user.name = attrs['name']
111 new_user.lastname = attrs['lastname']
111 new_user.lastname = attrs['lastname']
112
112
113 self.sa.add(new_user)
113 self.sa.add(new_user)
114 self.sa.commit()
114 self.sa.commit()
115 return True
115 return new_user
116 except (DatabaseError,):
116 except (DatabaseError,):
117 log.error(traceback.format_exc())
117 log.error(traceback.format_exc())
118 self.sa.rollback()
118 self.sa.rollback()
119 raise
119 raise
120 log.debug('User %s already exists. Skipping creation of account for container auth.',
120 log.debug('User %s already exists. Skipping creation of account'
121 username)
121 ' for container auth.', username)
122 return False
122 return None
123
123
124 def create_ldap(self, username, password, user_dn, attrs):
124 def create_ldap(self, username, password, user_dn, attrs):
125 """
125 """
126 Checks if user is in database, if not creates this user marked
126 Checks if user is in database, if not creates this user marked
127 as ldap user
127 as ldap user
128
128
129 :param username:
129 :param username:
130 :param password:
130 :param password:
131 :param user_dn:
131 :param user_dn:
132 :param attrs:
132 :param attrs:
133 """
133 """
134 from rhodecode.lib.auth import get_crypt_password
134 from rhodecode.lib.auth import get_crypt_password
135 log.debug('Checking for such ldap account in RhodeCode database')
135 log.debug('Checking for such ldap account in RhodeCode database')
136 if self.get_by_username(username, case_insensitive=True) is None:
136 if self.get_by_username(username, case_insensitive=True) is None:
137 try:
137 try:
138 new_user = User()
138 new_user = User()
139 # add ldap account always lowercase
139 # add ldap account always lowercase
140 new_user.username = username.lower()
140 new_user.username = username.lower()
141 new_user.password = get_crypt_password(password)
141 new_user.password = get_crypt_password(password)
142 new_user.api_key = generate_api_key(username)
142 new_user.api_key = generate_api_key(username)
143 new_user.email = attrs['email']
143 new_user.email = attrs['email']
144 new_user.active = attrs.get('active',True)
144 new_user.active = attrs.get('active', True)
145 new_user.ldap_dn = safe_unicode(user_dn)
145 new_user.ldap_dn = safe_unicode(user_dn)
146 new_user.name = attrs['name']
146 new_user.name = attrs['name']
147 new_user.lastname = attrs['lastname']
147 new_user.lastname = attrs['lastname']
148
148
149 self.sa.add(new_user)
149 self.sa.add(new_user)
150 self.sa.commit()
150 self.sa.commit()
151 return True
151 return new_user
152 except (DatabaseError,):
152 except (DatabaseError,):
153 log.error(traceback.format_exc())
153 log.error(traceback.format_exc())
154 self.sa.rollback()
154 self.sa.rollback()
155 raise
155 raise
156 log.debug('this %s user exists skipping creation of ldap account',
156 log.debug('this %s user exists skipping creation of ldap account',
157 username)
157 username)
158 return False
158 return None
159
159
160 def create_registration(self, form_data):
160 def create_registration(self, form_data):
161 from rhodecode.lib.celerylib import tasks, run_task
161 from rhodecode.lib.celerylib import tasks, run_task
162 try:
162 try:
163 new_user = User()
163 new_user = User()
164 for k, v in form_data.items():
164 for k, v in form_data.items():
165 if k != 'admin':
165 if k != 'admin':
166 setattr(new_user, k, v)
166 setattr(new_user, k, v)
167
167
168 self.sa.add(new_user)
168 self.sa.add(new_user)
169 self.sa.commit()
169 self.sa.commit()
170 body = ('New user registration\n'
170 body = ('New user registration\n'
171 'username: %s\n'
171 'username: %s\n'
172 'email: %s\n')
172 'email: %s\n')
173 body = body % (form_data['username'], form_data['email'])
173 body = body % (form_data['username'], form_data['email'])
174
174
175 run_task(tasks.send_email, None,
175 run_task(tasks.send_email, None,
176 _('[RhodeCode] New User registration'),
176 _('[RhodeCode] New User registration'),
177 body)
177 body)
178 except:
178 except:
179 log.error(traceback.format_exc())
179 log.error(traceback.format_exc())
180 self.sa.rollback()
180 self.sa.rollback()
181 raise
181 raise
182
182
183 def update(self, user_id, form_data):
183 def update(self, user_id, form_data):
184 try:
184 try:
185 user = self.get(user_id, cache=False)
185 user = self.get(user_id, cache=False)
186 if user.username == 'default':
186 if user.username == 'default':
187 raise DefaultUserException(
187 raise DefaultUserException(
188 _("You can't Edit this user since it's"
188 _("You can't Edit this user since it's"
189 " crucial for entire application"))
189 " crucial for entire application"))
190
190
191 for k, v in form_data.items():
191 for k, v in form_data.items():
192 if k == 'new_password' and v != '':
192 if k == 'new_password' and v != '':
193 user.password = v
193 user.password = v
194 user.api_key = generate_api_key(user.username)
194 user.api_key = generate_api_key(user.username)
195 else:
195 else:
196 setattr(user, k, v)
196 setattr(user, k, v)
197
197
198 self.sa.add(user)
198 self.sa.add(user)
199 self.sa.commit()
199 self.sa.commit()
200 except:
200 except:
201 log.error(traceback.format_exc())
201 log.error(traceback.format_exc())
202 self.sa.rollback()
202 self.sa.rollback()
203 raise
203 raise
204
204
205 def update_my_account(self, user_id, form_data):
205 def update_my_account(self, user_id, form_data):
206 try:
206 try:
207 user = self.get(user_id, cache=False)
207 user = self.get(user_id, cache=False)
208 if user.username == 'default':
208 if user.username == 'default':
209 raise DefaultUserException(
209 raise DefaultUserException(
210 _("You can't Edit this user since it's"
210 _("You can't Edit this user since it's"
211 " crucial for entire application"))
211 " crucial for entire application"))
212 for k, v in form_data.items():
212 for k, v in form_data.items():
213 if k == 'new_password' and v != '':
213 if k == 'new_password' and v != '':
214 user.password = v
214 user.password = v
215 user.api_key = generate_api_key(user.username)
215 user.api_key = generate_api_key(user.username)
216 else:
216 else:
217 if k not in ['admin', 'active']:
217 if k not in ['admin', 'active']:
218 setattr(user, k, v)
218 setattr(user, k, v)
219
219
220 self.sa.add(user)
220 self.sa.add(user)
221 self.sa.commit()
221 self.sa.commit()
222 except:
222 except:
223 log.error(traceback.format_exc())
223 log.error(traceback.format_exc())
224 self.sa.rollback()
224 self.sa.rollback()
225 raise
225 raise
226
226
227 def delete(self, user_id):
227 def delete(self, user_id):
228 try:
228 try:
229 user = self.get(user_id, cache=False)
229 user = self.get(user_id, cache=False)
230 if user.username == 'default':
230 if user.username == 'default':
231 raise DefaultUserException(
231 raise DefaultUserException(
232 _("You can't remove this user since it's"
232 _("You can't remove this user since it's"
233 " crucial for entire application"))
233 " crucial for entire application"))
234 if user.repositories:
234 if user.repositories:
235 raise UserOwnsReposException(_('This user still owns %s '
235 raise UserOwnsReposException(_('This user still owns %s '
236 'repositories and cannot be '
236 'repositories and cannot be '
237 'removed. Switch owners or '
237 'removed. Switch owners or '
238 'remove those repositories') \
238 'remove those repositories') \
239 % user.repositories)
239 % user.repositories)
240 self.sa.delete(user)
240 self.sa.delete(user)
241 self.sa.commit()
241 self.sa.commit()
242 except:
242 except:
243 log.error(traceback.format_exc())
243 log.error(traceback.format_exc())
244 self.sa.rollback()
244 self.sa.rollback()
245 raise
245 raise
246
246
247 def reset_password_link(self, data):
247 def reset_password_link(self, data):
248 from rhodecode.lib.celerylib import tasks, run_task
248 from rhodecode.lib.celerylib import tasks, run_task
249 run_task(tasks.send_password_link, data['email'])
249 run_task(tasks.send_password_link, data['email'])
250
250
251 def reset_password(self, data):
251 def reset_password(self, data):
252 from rhodecode.lib.celerylib import tasks, run_task
252 from rhodecode.lib.celerylib import tasks, run_task
253 run_task(tasks.reset_user_password, data['email'])
253 run_task(tasks.reset_user_password, data['email'])
254
254
255 def fill_data(self, auth_user, user_id=None, api_key=None):
255 def fill_data(self, auth_user, user_id=None, api_key=None):
256 """
256 """
257 Fetches auth_user by user_id,or api_key if present.
257 Fetches auth_user by user_id,or api_key if present.
258 Fills auth_user attributes with those taken from database.
258 Fills auth_user attributes with those taken from database.
259 Additionally set's is_authenitated if lookup fails
259 Additionally set's is_authenitated if lookup fails
260 present in database
260 present in database
261
261
262 :param auth_user: instance of user to set attributes
262 :param auth_user: instance of user to set attributes
263 :param user_id: user id to fetch by
263 :param user_id: user id to fetch by
264 :param api_key: api key to fetch by
264 :param api_key: api key to fetch by
265 """
265 """
266 if user_id is None and api_key is None:
266 if user_id is None and api_key is None:
267 raise Exception('You need to pass user_id or api_key')
267 raise Exception('You need to pass user_id or api_key')
268
268
269 try:
269 try:
270 if api_key:
270 if api_key:
271 dbuser = self.get_by_api_key(api_key)
271 dbuser = self.get_by_api_key(api_key)
272 else:
272 else:
273 dbuser = self.get(user_id)
273 dbuser = self.get(user_id)
274
274
275 if dbuser is not None and dbuser.active:
275 if dbuser is not None and dbuser.active:
276 log.debug('filling %s data', dbuser)
276 log.debug('filling %s data', dbuser)
277 for k, v in dbuser.get_dict().items():
277 for k, v in dbuser.get_dict().items():
278 setattr(auth_user, k, v)
278 setattr(auth_user, k, v)
279 else:
279 else:
280 return False
280 return False
281
281
282 except:
282 except:
283 log.error(traceback.format_exc())
283 log.error(traceback.format_exc())
284 auth_user.is_authenticated = False
284 auth_user.is_authenticated = False
285 return False
285 return False
286
286
287 return True
287 return True
288
288
289 def fill_perms(self, user):
289 def fill_perms(self, user):
290 """
290 """
291 Fills user permission attribute with permissions taken from database
291 Fills user permission attribute with permissions taken from database
292 works for permissions given for repositories, and for permissions that
292 works for permissions given for repositories, and for permissions that
293 are granted to groups
293 are granted to groups
294
294
295 :param user: user instance to fill his perms
295 :param user: user instance to fill his perms
296 """
296 """
297
297
298 user.permissions['repositories'] = {}
298 user.permissions['repositories'] = {}
299 user.permissions['global'] = set()
299 user.permissions['global'] = set()
300
300
301 #======================================================================
301 #======================================================================
302 # fetch default permissions
302 # fetch default permissions
303 #======================================================================
303 #======================================================================
304 default_user = self.get_by_username('default', cache=True)
304 default_user = self.get_by_username('default', cache=True)
305
305
306 default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
306 default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
307 .join((Repository, RepoToPerm.repository_id ==
307 .join((Repository, RepoToPerm.repository_id ==
308 Repository.repo_id))\
308 Repository.repo_id))\
309 .join((Permission, RepoToPerm.permission_id ==
309 .join((Permission, RepoToPerm.permission_id ==
310 Permission.permission_id))\
310 Permission.permission_id))\
311 .filter(RepoToPerm.user == default_user).all()
311 .filter(RepoToPerm.user == default_user).all()
312
312
313 if user.is_admin:
313 if user.is_admin:
314 #==================================================================
314 #==================================================================
315 # #admin have all default rights set to admin
315 # #admin have all default rights set to admin
316 #==================================================================
316 #==================================================================
317 user.permissions['global'].add('hg.admin')
317 user.permissions['global'].add('hg.admin')
318
318
319 for perm in default_perms:
319 for perm in default_perms:
320 p = 'repository.admin'
320 p = 'repository.admin'
321 user.permissions['repositories'][perm.RepoToPerm.
321 user.permissions['repositories'][perm.RepoToPerm.
322 repository.repo_name] = p
322 repository.repo_name] = p
323
323
324 else:
324 else:
325 #==================================================================
325 #==================================================================
326 # set default permissions
326 # set default permissions
327 #==================================================================
327 #==================================================================
328 uid = user.user_id
328 uid = user.user_id
329
329
330 #default global
330 #default global
331 default_global_perms = self.sa.query(UserToPerm)\
331 default_global_perms = self.sa.query(UserToPerm)\
332 .filter(UserToPerm.user == default_user)
332 .filter(UserToPerm.user == default_user)
333
333
334 for perm in default_global_perms:
334 for perm in default_global_perms:
335 user.permissions['global'].add(perm.permission.permission_name)
335 user.permissions['global'].add(perm.permission.permission_name)
336
336
337 #default for repositories
337 #default for repositories
338 for perm in default_perms:
338 for perm in default_perms:
339 if perm.Repository.private and not (perm.Repository.user_id ==
339 if perm.Repository.private and not (perm.Repository.user_id ==
340 uid):
340 uid):
341 #diself.sable defaults for private repos,
341 #diself.sable defaults for private repos,
342 p = 'repository.none'
342 p = 'repository.none'
343 elif perm.Repository.user_id == uid:
343 elif perm.Repository.user_id == uid:
344 #set admin if owner
344 #set admin if owner
345 p = 'repository.admin'
345 p = 'repository.admin'
346 else:
346 else:
347 p = perm.Permission.permission_name
347 p = perm.Permission.permission_name
348
348
349 user.permissions['repositories'][perm.RepoToPerm.
349 user.permissions['repositories'][perm.RepoToPerm.
350 repository.repo_name] = p
350 repository.repo_name] = p
351
351
352 #==================================================================
352 #==================================================================
353 # overwrite default with user permissions if any
353 # overwrite default with user permissions if any
354 #==================================================================
354 #==================================================================
355
355
356 #user global
356 #user global
357 user_perms = self.sa.query(UserToPerm)\
357 user_perms = self.sa.query(UserToPerm)\
358 .options(joinedload(UserToPerm.permission))\
358 .options(joinedload(UserToPerm.permission))\
359 .filter(UserToPerm.user_id == uid).all()
359 .filter(UserToPerm.user_id == uid).all()
360
360
361 for perm in user_perms:
361 for perm in user_perms:
362 user.permissions['global'].add(perm.permission.
362 user.permissions['global'].add(perm.permission.
363 permission_name)
363 permission_name)
364
364
365 #user repositories
365 #user repositories
366 user_repo_perms = self.sa.query(RepoToPerm, Permission,
366 user_repo_perms = self.sa.query(RepoToPerm, Permission,
367 Repository)\
367 Repository)\
368 .join((Repository, RepoToPerm.repository_id ==
368 .join((Repository, RepoToPerm.repository_id ==
369 Repository.repo_id))\
369 Repository.repo_id))\
370 .join((Permission, RepoToPerm.permission_id ==
370 .join((Permission, RepoToPerm.permission_id ==
371 Permission.permission_id))\
371 Permission.permission_id))\
372 .filter(RepoToPerm.user_id == uid).all()
372 .filter(RepoToPerm.user_id == uid).all()
373
373
374 for perm in user_repo_perms:
374 for perm in user_repo_perms:
375 # set admin if owner
375 # set admin if owner
376 if perm.Repository.user_id == uid:
376 if perm.Repository.user_id == uid:
377 p = 'repository.admin'
377 p = 'repository.admin'
378 else:
378 else:
379 p = perm.Permission.permission_name
379 p = perm.Permission.permission_name
380 user.permissions['repositories'][perm.RepoToPerm.
380 user.permissions['repositories'][perm.RepoToPerm.
381 repository.repo_name] = p
381 repository.repo_name] = p
382
382
383 #==================================================================
383 #==================================================================
384 # check if user is part of groups for this repository and fill in
384 # check if user is part of groups for this repository and fill in
385 # (or replace with higher) permissions
385 # (or replace with higher) permissions
386 #==================================================================
386 #==================================================================
387
387
388 #users group global
388 #users group global
389 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
389 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
390 .options(joinedload(UsersGroupToPerm.permission))\
390 .options(joinedload(UsersGroupToPerm.permission))\
391 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
391 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
392 UsersGroupMember.users_group_id))\
392 UsersGroupMember.users_group_id))\
393 .filter(UsersGroupMember.user_id == uid).all()
393 .filter(UsersGroupMember.user_id == uid).all()
394
394
395 for perm in user_perms_from_users_groups:
395 for perm in user_perms_from_users_groups:
396 user.permissions['global'].add(perm.permission.permission_name)
396 user.permissions['global'].add(perm.permission.permission_name)
397
397
398 #users group repositories
398 #users group repositories
399 user_repo_perms_from_users_groups = self.sa.query(
399 user_repo_perms_from_users_groups = self.sa.query(
400 UsersGroupRepoToPerm,
400 UsersGroupRepoToPerm,
401 Permission, Repository,)\
401 Permission, Repository,)\
402 .join((Repository, UsersGroupRepoToPerm.repository_id ==
402 .join((Repository, UsersGroupRepoToPerm.repository_id ==
403 Repository.repo_id))\
403 Repository.repo_id))\
404 .join((Permission, UsersGroupRepoToPerm.permission_id ==
404 .join((Permission, UsersGroupRepoToPerm.permission_id ==
405 Permission.permission_id))\
405 Permission.permission_id))\
406 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
406 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
407 UsersGroupMember.users_group_id))\
407 UsersGroupMember.users_group_id))\
408 .filter(UsersGroupMember.user_id == uid).all()
408 .filter(UsersGroupMember.user_id == uid).all()
409
409
410 for perm in user_repo_perms_from_users_groups:
410 for perm in user_repo_perms_from_users_groups:
411 p = perm.Permission.permission_name
411 p = perm.Permission.permission_name
412 cur_perm = user.permissions['repositories'][perm.
412 cur_perm = user.permissions['repositories'][perm.
413 UsersGroupRepoToPerm.
413 UsersGroupRepoToPerm.
414 repository.repo_name]
414 repository.repo_name]
415 #overwrite permission only if it's greater than permission
415 #overwrite permission only if it's greater than permission
416 # given from other sources
416 # given from other sources
417 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
417 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
418 user.permissions['repositories'][perm.UsersGroupRepoToPerm.
418 user.permissions['repositories'][perm.UsersGroupRepoToPerm.
419 repository.repo_name] = p
419 repository.repo_name] = p
420
420
421 return user
421 return user
422
422
@@ -1,83 +1,82 b''
1 """Pylons application test package
1 """Pylons application test package
2
2
3 This package assumes the Pylons environment is already loaded, such as
3 This package assumes the Pylons environment is already loaded, such as
4 when this script is imported from the `nosetests --with-pylons=test.ini`
4 when this script is imported from the `nosetests --with-pylons=test.ini`
5 command.
5 command.
6
6
7 This module initializes the application via ``websetup`` (`paster
7 This module initializes the application via ``websetup`` (`paster
8 setup-app`) and provides the base testing objects.
8 setup-app`) and provides the base testing objects.
9 """
9 """
10 import os
10 import os
11 from os.path import join as jn
11 from os.path import join as jn
12
12
13 from unittest import TestCase
13 from unittest import TestCase
14
14
15 from paste.deploy import loadapp
15 from paste.deploy import loadapp
16 from paste.script.appinstall import SetupCommand
16 from paste.script.appinstall import SetupCommand
17 from pylons import config, url
17 from pylons import config, url
18 from routes.util import URLGenerator
18 from routes.util import URLGenerator
19 from webtest import TestApp
19 from webtest import TestApp
20
20
21 from rhodecode.model import meta
21 from rhodecode.model import meta
22 import logging
22 import logging
23
23
24
25 log = logging.getLogger(__name__)
24 log = logging.getLogger(__name__)
26
25
27 import pylons.test
26 import pylons.test
28
27
29 __all__ = ['environ', 'url', 'TestController', 'TESTS_TMP_PATH', 'HG_REPO',
28 __all__ = ['environ', 'url', 'TestController', 'TESTS_TMP_PATH', 'HG_REPO',
30 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO', 'HG_FORK', 'GIT_FORK',
29 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO', 'HG_FORK', 'GIT_FORK',
31 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS' ]
30 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS' ]
32
31
33 # Invoke websetup with the current config file
32 # Invoke websetup with the current config file
34 #SetupCommand('setup-app').run([config_file])
33 # SetupCommand('setup-app').run([config_file])
35
34
36 ##RUNNING DESIRED TESTS
35 ##RUNNING DESIRED TESTS
37 # nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
36 # nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
38 # nosetests --pdb --pdb-failures
37 # nosetests --pdb --pdb-failures
39 environ = {}
38 environ = {}
40
39
41 #SOME GLOBALS FOR TESTS
40 #SOME GLOBALS FOR TESTS
42 from tempfile import _RandomNameSequence
41 from tempfile import _RandomNameSequence
43 TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
42 TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
44 TEST_USER_ADMIN_LOGIN = 'test_admin'
43 TEST_USER_ADMIN_LOGIN = 'test_admin'
45 TEST_USER_ADMIN_PASS = 'test12'
44 TEST_USER_ADMIN_PASS = 'test12'
46 HG_REPO = 'vcs_test_hg'
45 HG_REPO = 'vcs_test_hg'
47 GIT_REPO = 'vcs_test_git'
46 GIT_REPO = 'vcs_test_git'
48
47
49 NEW_HG_REPO = 'vcs_test_hg_new'
48 NEW_HG_REPO = 'vcs_test_hg_new'
50 NEW_GIT_REPO = 'vcs_test_git_new'
49 NEW_GIT_REPO = 'vcs_test_git_new'
51
50
52 HG_FORK = 'vcs_test_hg_fork'
51 HG_FORK = 'vcs_test_hg_fork'
53 GIT_FORK = 'vcs_test_git_fork'
52 GIT_FORK = 'vcs_test_git_fork'
54
53
55 class TestController(TestCase):
54 class TestController(TestCase):
56
55
57 def __init__(self, *args, **kwargs):
56 def __init__(self, *args, **kwargs):
58 wsgiapp = pylons.test.pylonsapp
57 wsgiapp = pylons.test.pylonsapp
59 config = wsgiapp.config
58 config = wsgiapp.config
60
59
61 self.app = TestApp(wsgiapp)
60 self.app = TestApp(wsgiapp)
62 url._push_object(URLGenerator(config['routes.map'], environ))
61 url._push_object(URLGenerator(config['routes.map'], environ))
63 self.sa = meta.Session
62 self.sa = meta.Session
64 self.index_location = config['app_conf']['index_dir']
63 self.index_location = config['app_conf']['index_dir']
65 TestCase.__init__(self, *args, **kwargs)
64 TestCase.__init__(self, *args, **kwargs)
66
65
67 def log_user(self, username=TEST_USER_ADMIN_LOGIN,
66 def log_user(self, username=TEST_USER_ADMIN_LOGIN,
68 password=TEST_USER_ADMIN_PASS):
67 password=TEST_USER_ADMIN_PASS):
69 response = self.app.post(url(controller='login', action='index'),
68 response = self.app.post(url(controller='login', action='index'),
70 {'username':username,
69 {'username':username,
71 'password':password})
70 'password':password})
72
71
73 if 'invalid user name' in response.body:
72 if 'invalid user name' in response.body:
74 self.fail('could not login using %s %s' % (username, password))
73 self.fail('could not login using %s %s' % (username, password))
75
74
76 self.assertEqual(response.status, '302 Found')
75 self.assertEqual(response.status, '302 Found')
77 self.assertEqual(response.session['rhodecode_user'].username, username)
76 self.assertEqual(response.session['rhodecode_user'].username, username)
78 return response.follow()
77 return response.follow()
79
78
80 def checkSessionFlash(self, response, msg):
79 def checkSessionFlash(self, response, msg):
81 self.assertTrue('flash' in response.session)
80 self.assertTrue('flash' in response.session)
82 self.assertTrue(msg in response.session['flash'][0][1])
81 self.assertTrue(msg in response.session['flash'][0][1])
83
82
1 NO CONTENT: file renamed from rhodecode/tests/test_concurency.py to rhodecode/tests/_test_concurency.py
NO CONTENT: file renamed from rhodecode/tests/test_concurency.py to rhodecode/tests/_test_concurency.py
@@ -1,227 +1,229 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # RhodeCode - Pylons environment configuration #
3 # RhodeCode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11 ################################################################################
11 ################################################################################
12 ## Uncomment and replace with the address which should receive ##
12 ## Uncomment and replace with the address which should receive ##
13 ## any error reports after application crash ##
13 ## any error reports after application crash ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 ################################################################################
15 ################################################################################
16 #email_to = admin@localhost
16 #email_to = admin@localhost
17 #error_email_from = paste_error@localhost
17 #error_email_from = paste_error@localhost
18 #app_email_from = rhodecode-noreply@localhost
18 #app_email_from = rhodecode-noreply@localhost
19 #error_message =
19 #error_message =
20
20
21 #smtp_server = mail.server.com
21 #smtp_server = mail.server.com
22 #smtp_username =
22 #smtp_username =
23 #smtp_password =
23 #smtp_password =
24 #smtp_port =
24 #smtp_port =
25 #smtp_use_tls = false
25 #smtp_use_tls = false
26 #smtp_use_ssl = true
26 #smtp_use_ssl = true
27
27
28 [server:main]
28 [server:main]
29 ##nr of threads to spawn
29 ##nr of threads to spawn
30 threadpool_workers = 5
30 threadpool_workers = 5
31
31
32 ##max request before thread respawn
32 ##max request before thread respawn
33 threadpool_max_requests = 2
33 threadpool_max_requests = 2
34
34
35 ##option to use threads of process
35 ##option to use threads of process
36 use_threadpool = true
36 use_threadpool = true
37
37
38 use = egg:Paste#http
38 use = egg:Paste#http
39 host = 127.0.0.1
39 host = 127.0.0.1
40 port = 5000
40 port = 5000
41
41
42 [app:main]
42 [app:main]
43 use = egg:rhodecode
43 use = egg:rhodecode
44 full_stack = true
44 full_stack = true
45 static_files = true
45 static_files = true
46 lang=en
46 lang=en
47 cache_dir = /tmp/data
47 cache_dir = /tmp/data
48 index_dir = /tmp/index
48 index_dir = /tmp/index
49 app_instance_uuid = develop-test
49 app_instance_uuid = develop-test
50 cut_off_limit = 256000
50 cut_off_limit = 256000
51 force_https = false
51 force_https = false
52 commit_parse_limit = 25
52 commit_parse_limit = 25
53 use_gravatar = true
53 use_gravatar = true
54 container_auth_enabled = false
55 proxypass_auth_enabled = false
54
56
55 ####################################
57 ####################################
56 ### CELERY CONFIG ####
58 ### CELERY CONFIG ####
57 ####################################
59 ####################################
58 use_celery = false
60 use_celery = false
59 broker.host = localhost
61 broker.host = localhost
60 broker.vhost = rabbitmqhost
62 broker.vhost = rabbitmqhost
61 broker.port = 5672
63 broker.port = 5672
62 broker.user = rabbitmq
64 broker.user = rabbitmq
63 broker.password = qweqwe
65 broker.password = qweqwe
64
66
65 celery.imports = rhodecode.lib.celerylib.tasks
67 celery.imports = rhodecode.lib.celerylib.tasks
66
68
67 celery.result.backend = amqp
69 celery.result.backend = amqp
68 celery.result.dburi = amqp://
70 celery.result.dburi = amqp://
69 celery.result.serialier = json
71 celery.result.serialier = json
70
72
71 #celery.send.task.error.emails = true
73 #celery.send.task.error.emails = true
72 #celery.amqp.task.result.expires = 18000
74 #celery.amqp.task.result.expires = 18000
73
75
74 celeryd.concurrency = 2
76 celeryd.concurrency = 2
75 #celeryd.log.file = celeryd.log
77 #celeryd.log.file = celeryd.log
76 celeryd.log.level = debug
78 celeryd.log.level = debug
77 celeryd.max.tasks.per.child = 1
79 celeryd.max.tasks.per.child = 1
78
80
79 #tasks will never be sent to the queue, but executed locally instead.
81 #tasks will never be sent to the queue, but executed locally instead.
80 celery.always.eager = false
82 celery.always.eager = false
81
83
82 ####################################
84 ####################################
83 ### BEAKER CACHE ####
85 ### BEAKER CACHE ####
84 ####################################
86 ####################################
85 beaker.cache.data_dir=/tmp/data/cache/data
87 beaker.cache.data_dir=/tmp/data/cache/data
86 beaker.cache.lock_dir=/tmp/data/cache/lock
88 beaker.cache.lock_dir=/tmp/data/cache/lock
87 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
89 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
88
90
89 beaker.cache.super_short_term.type=memory
91 beaker.cache.super_short_term.type=memory
90 beaker.cache.super_short_term.expire=10
92 beaker.cache.super_short_term.expire=10
91 beaker.cache.super_short_term.key_length = 256
93 beaker.cache.super_short_term.key_length = 256
92
94
93 beaker.cache.short_term.type=memory
95 beaker.cache.short_term.type=memory
94 beaker.cache.short_term.expire=60
96 beaker.cache.short_term.expire=60
95 beaker.cache.short_term.key_length = 256
97 beaker.cache.short_term.key_length = 256
96
98
97 beaker.cache.long_term.type=memory
99 beaker.cache.long_term.type=memory
98 beaker.cache.long_term.expire=36000
100 beaker.cache.long_term.expire=36000
99 beaker.cache.long_term.key_length = 256
101 beaker.cache.long_term.key_length = 256
100
102
101 beaker.cache.sql_cache_short.type=memory
103 beaker.cache.sql_cache_short.type=memory
102 beaker.cache.sql_cache_short.expire=10
104 beaker.cache.sql_cache_short.expire=10
103 beaker.cache.sql_cache_short.key_length = 256
105 beaker.cache.sql_cache_short.key_length = 256
104
106
105 beaker.cache.sql_cache_med.type=memory
107 beaker.cache.sql_cache_med.type=memory
106 beaker.cache.sql_cache_med.expire=360
108 beaker.cache.sql_cache_med.expire=360
107 beaker.cache.sql_cache_med.key_length = 256
109 beaker.cache.sql_cache_med.key_length = 256
108
110
109 beaker.cache.sql_cache_long.type=file
111 beaker.cache.sql_cache_long.type=file
110 beaker.cache.sql_cache_long.expire=3600
112 beaker.cache.sql_cache_long.expire=3600
111 beaker.cache.sql_cache_long.key_length = 256
113 beaker.cache.sql_cache_long.key_length = 256
112
114
113 ####################################
115 ####################################
114 ### BEAKER SESSION ####
116 ### BEAKER SESSION ####
115 ####################################
117 ####################################
116 ## Type of storage used for the session, current types are
118 ## Type of storage used for the session, current types are
117 ## dbm, file, memcached, database, and memory.
119 ## dbm, file, memcached, database, and memory.
118 ## The storage uses the Container API
120 ## The storage uses the Container API
119 ##that is also used by the cache system.
121 ##that is also used by the cache system.
120 beaker.session.type = file
122 beaker.session.type = file
121
123
122 beaker.session.key = rhodecode
124 beaker.session.key = rhodecode
123 beaker.session.secret = g654dcno0-9873jhgfreyu
125 beaker.session.secret = g654dcno0-9873jhgfreyu
124 beaker.session.timeout = 36000
126 beaker.session.timeout = 36000
125
127
126 ##auto save the session to not to use .save()
128 ##auto save the session to not to use .save()
127 beaker.session.auto = False
129 beaker.session.auto = False
128
130
129 ##true exire at browser close
131 ##true exire at browser close
130 #beaker.session.cookie_expires = 3600
132 #beaker.session.cookie_expires = 3600
131
133
132
134
133 ################################################################################
135 ################################################################################
134 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
136 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
135 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
137 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
136 ## execute malicious code after an exception is raised. ##
138 ## execute malicious code after an exception is raised. ##
137 ################################################################################
139 ################################################################################
138 #set debug = false
140 #set debug = false
139
141
140 ##################################
142 ##################################
141 ### LOGVIEW CONFIG ###
143 ### LOGVIEW CONFIG ###
142 ##################################
144 ##################################
143 logview.sqlalchemy = #faa
145 logview.sqlalchemy = #faa
144 logview.pylons.templating = #bfb
146 logview.pylons.templating = #bfb
145 logview.pylons.util = #eee
147 logview.pylons.util = #eee
146
148
147 #########################################################
149 #########################################################
148 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
150 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
149 #########################################################
151 #########################################################
150 sqlalchemy.db1.url = sqlite:///%(here)s/test.db
152 sqlalchemy.db1.url = sqlite:///%(here)s/test.db
151 #sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
153 #sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
152 #sqlalchemy.db1.echo = false
154 #sqlalchemy.db1.echo = false
153 #sqlalchemy.db1.pool_recycle = 3600
155 #sqlalchemy.db1.pool_recycle = 3600
154 sqlalchemy.convert_unicode = true
156 sqlalchemy.convert_unicode = true
155
157
156 ################################
158 ################################
157 ### LOGGING CONFIGURATION ####
159 ### LOGGING CONFIGURATION ####
158 ################################
160 ################################
159 [loggers]
161 [loggers]
160 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
162 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
161
163
162 [handlers]
164 [handlers]
163 keys = console
165 keys = console
164
166
165 [formatters]
167 [formatters]
166 keys = generic, color_formatter
168 keys = generic, color_formatter
167
169
168 #############
170 #############
169 ## LOGGERS ##
171 ## LOGGERS ##
170 #############
172 #############
171 [logger_root]
173 [logger_root]
172 level = ERROR
174 level = ERROR
173 handlers = console
175 handlers = console
174
176
175 [logger_routes]
177 [logger_routes]
176 level = ERROR
178 level = ERROR
177 handlers =
179 handlers =
178 qualname = routes.middleware
180 qualname = routes.middleware
179 # "level = DEBUG" logs the route matched and routing variables.
181 # "level = DEBUG" logs the route matched and routing variables.
180 propagate = 1
182 propagate = 1
181
183
182 [logger_beaker]
184 [logger_beaker]
183 level = DEBUG
185 level = DEBUG
184 handlers =
186 handlers =
185 qualname = beaker.container
187 qualname = beaker.container
186 propagate = 1
188 propagate = 1
187
189
188 [logger_templates]
190 [logger_templates]
189 level = INFO
191 level = INFO
190 handlers =
192 handlers =
191 qualname = pylons.templating
193 qualname = pylons.templating
192 propagate = 1
194 propagate = 1
193
195
194 [logger_rhodecode]
196 [logger_rhodecode]
195 level = ERROR
197 level = ERROR
196 handlers =
198 handlers =
197 qualname = rhodecode
199 qualname = rhodecode
198 propagate = 1
200 propagate = 1
199
201
200 [logger_sqlalchemy]
202 [logger_sqlalchemy]
201 level = ERROR
203 level = ERROR
202 handlers = console
204 handlers = console
203 qualname = sqlalchemy.engine
205 qualname = sqlalchemy.engine
204 propagate = 0
206 propagate = 0
205
207
206 ##############
208 ##############
207 ## HANDLERS ##
209 ## HANDLERS ##
208 ##############
210 ##############
209
211
210 [handler_console]
212 [handler_console]
211 class = StreamHandler
213 class = StreamHandler
212 args = (sys.stderr,)
214 args = (sys.stderr,)
213 level = NOTSET
215 level = NOTSET
214 formatter = generic
216 formatter = generic
215
217
216 ################
218 ################
217 ## FORMATTERS ##
219 ## FORMATTERS ##
218 ################
220 ################
219
221
220 [formatter_generic]
222 [formatter_generic]
221 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
223 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
222 datefmt = %Y-%m-%d %H:%M:%S
224 datefmt = %Y-%m-%d %H:%M:%S
223
225
224 [formatter_color_formatter]
226 [formatter_color_formatter]
225 class=rhodecode.lib.colored_formatter.ColorFormatter
227 class=rhodecode.lib.colored_formatter.ColorFormatter
226 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
228 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
227 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
229 datefmt = %Y-%m-%d %H:%M:%S
General Comments 0
You need to be logged in to leave comments. Login now