##// END OF EJS Templates
typo fixes
marcink -
r1644:59c26a9a beta
parent child Browse files
Show More
@@ -1,207 +1,207 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.users
3 rhodecode.controllers.admin.users
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Users crud controller for pylons
6 Users crud controller for pylons
7
7
8 :created_on: Apr 4, 2010
8 :created_on: Apr 4, 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 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31 from pylons import request, session, tmpl_context as c, url, config
31 from pylons import request, session, tmpl_context as c, url, config
32 from pylons.controllers.util import abort, redirect
32 from pylons.controllers.util import abort, redirect
33 from pylons.i18n.translation import _
33 from pylons.i18n.translation import _
34
34
35 from rhodecode.lib.exceptions import DefaultUserException, \
35 from rhodecode.lib.exceptions import DefaultUserException, \
36 UserOwnsReposException
36 UserOwnsReposException
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
39 from rhodecode.lib.base import BaseController, render
39 from rhodecode.lib.base import BaseController, render
40
40
41 from rhodecode.model.db import User, UserRepoToPerm, UserToPerm, Permission
41 from rhodecode.model.db import User, UserRepoToPerm, UserToPerm, Permission
42 from rhodecode.model.forms import UserForm
42 from rhodecode.model.forms import UserForm
43 from rhodecode.model.user import UserModel
43 from rhodecode.model.user import UserModel
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 class UsersController(BaseController):
48 class UsersController(BaseController):
49 """REST Controller styled on the Atom Publishing Protocol"""
49 """REST Controller styled on the Atom Publishing Protocol"""
50 # To properly map this controller, ensure your config/routing.py
50 # To properly map this controller, ensure your config/routing.py
51 # file has a resource setup:
51 # file has a resource setup:
52 # map.resource('user', 'users')
52 # map.resource('user', 'users')
53
53
54 @LoginRequired()
54 @LoginRequired()
55 @HasPermissionAllDecorator('hg.admin')
55 @HasPermissionAllDecorator('hg.admin')
56 def __before__(self):
56 def __before__(self):
57 c.admin_user = session.get('admin_user')
57 c.admin_user = session.get('admin_user')
58 c.admin_username = session.get('admin_username')
58 c.admin_username = session.get('admin_username')
59 super(UsersController, self).__before__()
59 super(UsersController, self).__before__()
60 c.available_permissions = config['available_permissions']
60 c.available_permissions = config['available_permissions']
61
61
62 def index(self, format='html'):
62 def index(self, format='html'):
63 """GET /users: All items in the collection"""
63 """GET /users: All items in the collection"""
64 # url('users')
64 # url('users')
65
65
66 c.users_list = self.sa.query(User).all()
66 c.users_list = self.sa.query(User).all()
67 return render('admin/users/users.html')
67 return render('admin/users/users.html')
68
68
69 def create(self):
69 def create(self):
70 """POST /users: Create a new item"""
70 """POST /users: Create a new item"""
71 # url('users')
71 # url('users')
72
72
73 user_model = UserModel()
73 user_model = UserModel()
74 login_form = UserForm()()
74 user_form = UserForm()()
75 try:
75 try:
76 form_result = login_form.to_python(dict(request.POST))
76 form_result = user_form.to_python(dict(request.POST))
77 user_model.create(form_result)
77 user_model.create(form_result)
78 h.flash(_('created user %s') % form_result['username'],
78 h.flash(_('created user %s') % form_result['username'],
79 category='success')
79 category='success')
80 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
80 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
81 except formencode.Invalid, errors:
81 except formencode.Invalid, errors:
82 return htmlfill.render(
82 return htmlfill.render(
83 render('admin/users/user_add.html'),
83 render('admin/users/user_add.html'),
84 defaults=errors.value,
84 defaults=errors.value,
85 errors=errors.error_dict or {},
85 errors=errors.error_dict or {},
86 prefix_error=False,
86 prefix_error=False,
87 encoding="UTF-8")
87 encoding="UTF-8")
88 except Exception:
88 except Exception:
89 log.error(traceback.format_exc())
89 log.error(traceback.format_exc())
90 h.flash(_('error occurred during creation of user %s') \
90 h.flash(_('error occurred during creation of user %s') \
91 % request.POST.get('username'), category='error')
91 % request.POST.get('username'), category='error')
92 return redirect(url('users'))
92 return redirect(url('users'))
93
93
94 def new(self, format='html'):
94 def new(self, format='html'):
95 """GET /users/new: Form to create a new item"""
95 """GET /users/new: Form to create a new item"""
96 # url('new_user')
96 # url('new_user')
97 return render('admin/users/user_add.html')
97 return render('admin/users/user_add.html')
98
98
99 def update(self, id):
99 def update(self, id):
100 """PUT /users/id: Update an existing item"""
100 """PUT /users/id: Update an existing item"""
101 # Forms posted to this method should contain a hidden field:
101 # Forms posted to this method should contain a hidden field:
102 # <input type="hidden" name="_method" value="PUT" />
102 # <input type="hidden" name="_method" value="PUT" />
103 # Or using helpers:
103 # Or using helpers:
104 # h.form(url('update_user', id=ID),
104 # h.form(url('update_user', id=ID),
105 # method='put')
105 # method='put')
106 # url('user', id=ID)
106 # url('user', id=ID)
107 user_model = UserModel()
107 user_model = UserModel()
108 c.user = user_model.get(id)
108 c.user = user_model.get(id)
109
109
110 _form = UserForm(edit=True, old_data={'user_id': id,
110 _form = UserForm(edit=True, old_data={'user_id': id,
111 'email': c.user.email})()
111 'email': c.user.email})()
112 form_result = {}
112 form_result = {}
113 try:
113 try:
114 form_result = _form.to_python(dict(request.POST))
114 form_result = _form.to_python(dict(request.POST))
115 user_model.update(id, form_result)
115 user_model.update(id, form_result)
116 h.flash(_('User updated successfully'), category='success')
116 h.flash(_('User updated successfully'), category='success')
117
117
118 except formencode.Invalid, errors:
118 except formencode.Invalid, errors:
119 e = errors.error_dict or {}
119 e = errors.error_dict or {}
120 perm = Permission.get_by_key('hg.create.repository')
120 perm = Permission.get_by_key('hg.create.repository')
121 e.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
121 e.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
122 return htmlfill.render(
122 return htmlfill.render(
123 render('admin/users/user_edit.html'),
123 render('admin/users/user_edit.html'),
124 defaults=errors.value,
124 defaults=errors.value,
125 errors=e,
125 errors=e,
126 prefix_error=False,
126 prefix_error=False,
127 encoding="UTF-8")
127 encoding="UTF-8")
128 except Exception:
128 except Exception:
129 log.error(traceback.format_exc())
129 log.error(traceback.format_exc())
130 h.flash(_('error occurred during update of user %s') \
130 h.flash(_('error occurred during update of user %s') \
131 % form_result.get('username'), category='error')
131 % form_result.get('username'), category='error')
132
132
133 return redirect(url('users'))
133 return redirect(url('users'))
134
134
135 def delete(self, id):
135 def delete(self, id):
136 """DELETE /users/id: Delete an existing item"""
136 """DELETE /users/id: Delete an existing item"""
137 # Forms posted to this method should contain a hidden field:
137 # Forms posted to this method should contain a hidden field:
138 # <input type="hidden" name="_method" value="DELETE" />
138 # <input type="hidden" name="_method" value="DELETE" />
139 # Or using helpers:
139 # Or using helpers:
140 # h.form(url('delete_user', id=ID),
140 # h.form(url('delete_user', id=ID),
141 # method='delete')
141 # method='delete')
142 # url('user', id=ID)
142 # url('user', id=ID)
143 user_model = UserModel()
143 user_model = UserModel()
144 try:
144 try:
145 user_model.delete(id)
145 user_model.delete(id)
146 h.flash(_('successfully deleted user'), category='success')
146 h.flash(_('successfully deleted user'), category='success')
147 except (UserOwnsReposException, DefaultUserException), e:
147 except (UserOwnsReposException, DefaultUserException), e:
148 h.flash(str(e), category='warning')
148 h.flash(str(e), category='warning')
149 except Exception:
149 except Exception:
150 h.flash(_('An error occurred during deletion of user'),
150 h.flash(_('An error occurred during deletion of user'),
151 category='error')
151 category='error')
152 return redirect(url('users'))
152 return redirect(url('users'))
153
153
154 def show(self, id, format='html'):
154 def show(self, id, format='html'):
155 """GET /users/id: Show a specific item"""
155 """GET /users/id: Show a specific item"""
156 # url('user', id=ID)
156 # url('user', id=ID)
157
157
158 def edit(self, id, format='html'):
158 def edit(self, id, format='html'):
159 """GET /users/id/edit: Form to edit an existing item"""
159 """GET /users/id/edit: Form to edit an existing item"""
160 # url('edit_user', id=ID)
160 # url('edit_user', id=ID)
161 user_model = UserModel()
161 user_model = UserModel()
162 c.user = user_model.get(id)
162 c.user = user_model.get(id)
163 if not c.user:
163 if not c.user:
164 return redirect(url('users'))
164 return redirect(url('users'))
165 if c.user.username == 'default':
165 if c.user.username == 'default':
166 h.flash(_("You can't edit this user"), category='warning')
166 h.flash(_("You can't edit this user"), category='warning')
167 return redirect(url('users'))
167 return redirect(url('users'))
168 c.user.permissions = {}
168 c.user.permissions = {}
169 c.granted_permissions = user_model.fill_perms(c.user)\
169 c.granted_permissions = user_model.fill_perms(c.user)\
170 .permissions['global']
170 .permissions['global']
171
171
172 defaults = c.user.get_dict()
172 defaults = c.user.get_dict()
173 perm = Permission.get_by_key('hg.create.repository')
173 perm = Permission.get_by_key('hg.create.repository')
174 defaults.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
174 defaults.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
175
175
176 return htmlfill.render(
176 return htmlfill.render(
177 render('admin/users/user_edit.html'),
177 render('admin/users/user_edit.html'),
178 defaults=defaults,
178 defaults=defaults,
179 encoding="UTF-8",
179 encoding="UTF-8",
180 force_defaults=False
180 force_defaults=False
181 )
181 )
182
182
183 def update_perm(self, id):
183 def update_perm(self, id):
184 """PUT /users_perm/id: Update an existing item"""
184 """PUT /users_perm/id: Update an existing item"""
185 # url('user_perm', id=ID, method='put')
185 # url('user_perm', id=ID, method='put')
186
186
187 grant_perm = request.POST.get('create_repo_perm', False)
187 grant_perm = request.POST.get('create_repo_perm', False)
188
188
189 if grant_perm:
189 if grant_perm:
190 perm = Permission.get_by_key('hg.create.none')
190 perm = Permission.get_by_key('hg.create.none')
191 UserToPerm.revoke_perm(id, perm)
191 UserToPerm.revoke_perm(id, perm)
192
192
193 perm = Permission.get_by_key('hg.create.repository')
193 perm = Permission.get_by_key('hg.create.repository')
194 UserToPerm.grant_perm(id, perm)
194 UserToPerm.grant_perm(id, perm)
195 h.flash(_("Granted 'repository create' permission to user"),
195 h.flash(_("Granted 'repository create' permission to user"),
196 category='success')
196 category='success')
197
197
198 else:
198 else:
199 perm = Permission.get_by_key('hg.create.repository')
199 perm = Permission.get_by_key('hg.create.repository')
200 UserToPerm.revoke_perm(id, perm)
200 UserToPerm.revoke_perm(id, perm)
201
201
202 perm = Permission.get_by_key('hg.create.none')
202 perm = Permission.get_by_key('hg.create.none')
203 UserToPerm.grant_perm(id, perm)
203 UserToPerm.grant_perm(id, perm)
204 h.flash(_("Revoked 'repository create' permission to user"),
204 h.flash(_("Revoked 'repository create' permission to user"),
205 category='success')
205 category='success')
206
206
207 return redirect(url('edit_user', id=id))
207 return redirect(url('edit_user', id=id))
@@ -1,677 +1,678 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, RhodeCodeSetting, User
51 from rhodecode.model.db import Permission, RhodeCodeSetting, 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 def generate_api_key(str_, salt=None):
128 def generate_api_key(str_, salt=None):
129 """
129 """
130 Generates API KEY from given string
130 Generates API KEY from given string
131
131
132 :param str_:
132 :param str_:
133 :param salt:
133 :param salt:
134 """
134 """
135
135
136 if salt is None:
136 if salt is None:
137 salt = _RandomNameSequence().next()
137 salt = _RandomNameSequence().next()
138
138
139 return hashlib.sha1(str_ + salt).hexdigest()
139 return hashlib.sha1(str_ + salt).hexdigest()
140
140
141
141
142 def authfunc(environ, username, password):
142 def authfunc(environ, username, password):
143 """
143 """
144 Dummy authentication function used in Mercurial/Git/ and access control,
144 Dummy authentication wrapper function used in Mercurial and Git for
145 access control.
145
146
146 :param environ: needed only for using in Basic auth
147 :param environ: needed only for using in Basic auth
147 """
148 """
148 return authenticate(username, password)
149 return authenticate(username, password)
149
150
150
151
151 def authenticate(username, password):
152 def authenticate(username, password):
152 """
153 """
153 Authentication function used for access control,
154 Authentication function used for access control,
154 firstly checks for db authentication then if ldap is enabled for ldap
155 firstly checks for db authentication then if ldap is enabled for ldap
155 authentication, also creates ldap user if not in database
156 authentication, also creates ldap user if not in database
156
157
157 :param username: username
158 :param username: username
158 :param password: password
159 :param password: password
159 """
160 """
160
161
161 user_model = UserModel()
162 user_model = UserModel()
162 user = User.get_by_username(username)
163 user = User.get_by_username(username)
163
164
164 log.debug('Authenticating user using RhodeCode account')
165 log.debug('Authenticating user using RhodeCode account')
165 if user is not None and not user.ldap_dn:
166 if user is not None and not user.ldap_dn:
166 if user.active:
167 if user.active:
167 if user.username == 'default' and user.active:
168 if user.username == 'default' and user.active:
168 log.info('user %s authenticated correctly as anonymous user',
169 log.info('user %s authenticated correctly as anonymous user',
169 username)
170 username)
170 return True
171 return True
171
172
172 elif user.username == username and check_password(password,
173 elif user.username == username and check_password(password,
173 user.password):
174 user.password):
174 log.info('user %s authenticated correctly', username)
175 log.info('user %s authenticated correctly', username)
175 return True
176 return True
176 else:
177 else:
177 log.warning('user %s is disabled', username)
178 log.warning('user %s is disabled', username)
178
179
179 else:
180 else:
180 log.debug('Regular authentication failed')
181 log.debug('Regular authentication failed')
181 user_obj = User.get_by_username(username, case_insensitive=True)
182 user_obj = User.get_by_username(username, case_insensitive=True)
182
183
183 if user_obj is not None and not user_obj.ldap_dn:
184 if user_obj is not None and not user_obj.ldap_dn:
184 log.debug('this user already exists as non ldap')
185 log.debug('this user already exists as non ldap')
185 return False
186 return False
186
187
187 ldap_settings = RhodeCodeSetting.get_ldap_settings()
188 ldap_settings = RhodeCodeSetting.get_ldap_settings()
188 #======================================================================
189 #======================================================================
189 # FALLBACK TO LDAP AUTH IF ENABLE
190 # FALLBACK TO LDAP AUTH IF ENABLE
190 #======================================================================
191 #======================================================================
191 if str2bool(ldap_settings.get('ldap_active')):
192 if str2bool(ldap_settings.get('ldap_active')):
192 log.debug("Authenticating user using ldap")
193 log.debug("Authenticating user using ldap")
193 kwargs = {
194 kwargs = {
194 'server': ldap_settings.get('ldap_host', ''),
195 'server': ldap_settings.get('ldap_host', ''),
195 'base_dn': ldap_settings.get('ldap_base_dn', ''),
196 'base_dn': ldap_settings.get('ldap_base_dn', ''),
196 'port': ldap_settings.get('ldap_port'),
197 'port': ldap_settings.get('ldap_port'),
197 'bind_dn': ldap_settings.get('ldap_dn_user'),
198 'bind_dn': ldap_settings.get('ldap_dn_user'),
198 'bind_pass': ldap_settings.get('ldap_dn_pass'),
199 'bind_pass': ldap_settings.get('ldap_dn_pass'),
199 'tls_kind': ldap_settings.get('ldap_tls_kind'),
200 'tls_kind': ldap_settings.get('ldap_tls_kind'),
200 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
201 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
201 'ldap_filter': ldap_settings.get('ldap_filter'),
202 'ldap_filter': ldap_settings.get('ldap_filter'),
202 'search_scope': ldap_settings.get('ldap_search_scope'),
203 'search_scope': ldap_settings.get('ldap_search_scope'),
203 'attr_login': ldap_settings.get('ldap_attr_login'),
204 'attr_login': ldap_settings.get('ldap_attr_login'),
204 'ldap_version': 3,
205 'ldap_version': 3,
205 }
206 }
206 log.debug('Checking for ldap authentication')
207 log.debug('Checking for ldap authentication')
207 try:
208 try:
208 aldap = AuthLdap(**kwargs)
209 aldap = AuthLdap(**kwargs)
209 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
210 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
210 password)
211 password)
211 log.debug('Got ldap DN response %s', user_dn)
212 log.debug('Got ldap DN response %s', user_dn)
212
213
213 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
214 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
214 .get(k), [''])[0]
215 .get(k), [''])[0]
215
216
216 user_attrs = {
217 user_attrs = {
217 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
218 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
218 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
219 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
219 'email': get_ldap_attr('ldap_attr_email'),
220 'email': get_ldap_attr('ldap_attr_email'),
220 }
221 }
221
222
222 if user_model.create_ldap(username, password, user_dn,
223 if user_model.create_ldap(username, password, user_dn,
223 user_attrs):
224 user_attrs):
224 log.info('created new ldap user %s', username)
225 log.info('created new ldap user %s', username)
225
226
226 return True
227 return True
227 except (LdapUsernameError, LdapPasswordError,):
228 except (LdapUsernameError, LdapPasswordError,):
228 pass
229 pass
229 except (Exception,):
230 except (Exception,):
230 log.error(traceback.format_exc())
231 log.error(traceback.format_exc())
231 pass
232 pass
232 return False
233 return False
233
234
234 def login_container_auth(username):
235 def login_container_auth(username):
235 user = User.get_by_username(username)
236 user = User.get_by_username(username)
236 if user is None:
237 if user is None:
237 user_model = UserModel()
238 user_model = UserModel()
238 user_attrs = {
239 user_attrs = {
239 'name': username,
240 'name': username,
240 'lastname': None,
241 'lastname': None,
241 'email': None,
242 'email': None,
242 }
243 }
243 user = user_model.create_for_container_auth(username, user_attrs)
244 user = user_model.create_for_container_auth(username, user_attrs)
244 if not user:
245 if not user:
245 return None
246 return None
246 log.info('User %s was created by container authentication', username)
247 log.info('User %s was created by container authentication', username)
247
248
248 if not user.active:
249 if not user.active:
249 return None
250 return None
250
251
251 user.update_lastlogin()
252 user.update_lastlogin()
252 log.debug('User %s is now logged in by container authentication',
253 log.debug('User %s is now logged in by container authentication',
253 user.username)
254 user.username)
254 return user
255 return user
255
256
256 def get_container_username(environ, config):
257 def get_container_username(environ, config):
257 username = None
258 username = None
258
259
259 if str2bool(config.get('container_auth_enabled', False)):
260 if str2bool(config.get('container_auth_enabled', False)):
260 from paste.httpheaders import REMOTE_USER
261 from paste.httpheaders import REMOTE_USER
261 username = REMOTE_USER(environ)
262 username = REMOTE_USER(environ)
262
263
263 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
264 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
264 username = environ.get('HTTP_X_FORWARDED_USER')
265 username = environ.get('HTTP_X_FORWARDED_USER')
265
266
266 if username:
267 if username:
267 # Removing realm and domain from username
268 # Removing realm and domain from username
268 username = username.partition('@')[0]
269 username = username.partition('@')[0]
269 username = username.rpartition('\\')[2]
270 username = username.rpartition('\\')[2]
270 log.debug('Received username %s from container', username)
271 log.debug('Received username %s from container', username)
271
272
272 return username
273 return username
273
274
274 class AuthUser(object):
275 class AuthUser(object):
275 """
276 """
276 A simple object that handles all attributes of user in RhodeCode
277 A simple object that handles all attributes of user in RhodeCode
277
278
278 It does lookup based on API key,given user, or user present in session
279 It does lookup based on API key,given user, or user present in session
279 Then it fills all required information for such user. It also checks if
280 Then it fills all required information for such user. It also checks if
280 anonymous access is enabled and if so, it returns default user as logged
281 anonymous access is enabled and if so, it returns default user as logged
281 in
282 in
282 """
283 """
283
284
284 def __init__(self, user_id=None, api_key=None, username=None):
285 def __init__(self, user_id=None, api_key=None, username=None):
285
286
286 self.user_id = user_id
287 self.user_id = user_id
287 self.api_key = None
288 self.api_key = None
288 self.username = username
289 self.username = username
289
290
290 self.name = ''
291 self.name = ''
291 self.lastname = ''
292 self.lastname = ''
292 self.email = ''
293 self.email = ''
293 self.is_authenticated = False
294 self.is_authenticated = False
294 self.admin = False
295 self.admin = False
295 self.permissions = {}
296 self.permissions = {}
296 self._api_key = api_key
297 self._api_key = api_key
297 self.propagate_data()
298 self.propagate_data()
298
299
299 def propagate_data(self):
300 def propagate_data(self):
300 user_model = UserModel()
301 user_model = UserModel()
301 self.anonymous_user = User.get_by_username('default')
302 self.anonymous_user = User.get_by_username('default')
302 is_user_loaded = False
303 is_user_loaded = False
303
304
304 # try go get user by api key
305 # try go get user by api key
305 if self._api_key and self._api_key != self.anonymous_user.api_key:
306 if self._api_key and self._api_key != self.anonymous_user.api_key:
306 log.debug('Auth User lookup by API KEY %s', self._api_key)
307 log.debug('Auth User lookup by API KEY %s', self._api_key)
307 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
308 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
308 # lookup by userid
309 # lookup by userid
309 elif (self.user_id is not None and
310 elif (self.user_id is not None and
310 self.user_id != self.anonymous_user.user_id):
311 self.user_id != self.anonymous_user.user_id):
311 log.debug('Auth User lookup by USER ID %s', self.user_id)
312 log.debug('Auth User lookup by USER ID %s', self.user_id)
312 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
313 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
313 # lookup by username
314 # lookup by username
314 elif self.username:
315 elif self.username:
315 log.debug('Auth User lookup by USER NAME %s', self.username)
316 log.debug('Auth User lookup by USER NAME %s', self.username)
316 dbuser = login_container_auth(self.username)
317 dbuser = login_container_auth(self.username)
317 if dbuser is not None:
318 if dbuser is not None:
318 for k, v in dbuser.get_dict().items():
319 for k, v in dbuser.get_dict().items():
319 setattr(self, k, v)
320 setattr(self, k, v)
320 self.set_authenticated()
321 self.set_authenticated()
321 is_user_loaded = True
322 is_user_loaded = True
322
323
323 if not is_user_loaded:
324 if not is_user_loaded:
324 # if we cannot authenticate user try anonymous
325 # if we cannot authenticate user try anonymous
325 if self.anonymous_user.active is True:
326 if self.anonymous_user.active is True:
326 user_model.fill_data(self,user_id=self.anonymous_user.user_id)
327 user_model.fill_data(self,user_id=self.anonymous_user.user_id)
327 # then we set this user is logged in
328 # then we set this user is logged in
328 self.is_authenticated = True
329 self.is_authenticated = True
329 else:
330 else:
330 self.user_id = None
331 self.user_id = None
331 self.username = None
332 self.username = None
332 self.is_authenticated = False
333 self.is_authenticated = False
333
334
334 if not self.username:
335 if not self.username:
335 self.username = 'None'
336 self.username = 'None'
336
337
337 log.debug('Auth User is now %s', self)
338 log.debug('Auth User is now %s', self)
338 user_model.fill_perms(self)
339 user_model.fill_perms(self)
339
340
340 @property
341 @property
341 def is_admin(self):
342 def is_admin(self):
342 return self.admin
343 return self.admin
343
344
344 @property
345 @property
345 def full_contact(self):
346 def full_contact(self):
346 return '%s %s <%s>' % (self.name, self.lastname, self.email)
347 return '%s %s <%s>' % (self.name, self.lastname, self.email)
347
348
348 def __repr__(self):
349 def __repr__(self):
349 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
350 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
350 self.is_authenticated)
351 self.is_authenticated)
351
352
352 def set_authenticated(self, authenticated=True):
353 def set_authenticated(self, authenticated=True):
353 if self.user_id != self.anonymous_user.user_id:
354 if self.user_id != self.anonymous_user.user_id:
354 self.is_authenticated = authenticated
355 self.is_authenticated = authenticated
355
356
356
357
357 def set_available_permissions(config):
358 def set_available_permissions(config):
358 """
359 """
359 This function will propagate pylons globals with all available defined
360 This function will propagate pylons globals with all available defined
360 permission given in db. We don't want to check each time from db for new
361 permission given in db. We don't want to check each time from db for new
361 permissions since adding a new permission also requires application restart
362 permissions since adding a new permission also requires application restart
362 ie. to decorate new views with the newly created permission
363 ie. to decorate new views with the newly created permission
363
364
364 :param config: current pylons config instance
365 :param config: current pylons config instance
365
366
366 """
367 """
367 log.info('getting information about all available permissions')
368 log.info('getting information about all available permissions')
368 try:
369 try:
369 sa = meta.Session()
370 sa = meta.Session()
370 all_perms = sa.query(Permission).all()
371 all_perms = sa.query(Permission).all()
371 except:
372 except:
372 pass
373 pass
373 finally:
374 finally:
374 meta.Session.remove()
375 meta.Session.remove()
375
376
376 config['available_permissions'] = [x.permission_name for x in all_perms]
377 config['available_permissions'] = [x.permission_name for x in all_perms]
377
378
378
379
379 #==============================================================================
380 #==============================================================================
380 # CHECK DECORATORS
381 # CHECK DECORATORS
381 #==============================================================================
382 #==============================================================================
382 class LoginRequired(object):
383 class LoginRequired(object):
383 """
384 """
384 Must be logged in to execute this function else
385 Must be logged in to execute this function else
385 redirect to login page
386 redirect to login page
386
387
387 :param api_access: if enabled this checks only for valid auth token
388 :param api_access: if enabled this checks only for valid auth token
388 and grants access based on valid token
389 and grants access based on valid token
389 """
390 """
390
391
391 def __init__(self, api_access=False):
392 def __init__(self, api_access=False):
392 self.api_access = api_access
393 self.api_access = api_access
393
394
394 def __call__(self, func):
395 def __call__(self, func):
395 return decorator(self.__wrapper, func)
396 return decorator(self.__wrapper, func)
396
397
397 def __wrapper(self, func, *fargs, **fkwargs):
398 def __wrapper(self, func, *fargs, **fkwargs):
398 cls = fargs[0]
399 cls = fargs[0]
399 user = cls.rhodecode_user
400 user = cls.rhodecode_user
400
401
401 api_access_ok = False
402 api_access_ok = False
402 if self.api_access:
403 if self.api_access:
403 log.debug('Checking API KEY access for %s', cls)
404 log.debug('Checking API KEY access for %s', cls)
404 if user.api_key == request.GET.get('api_key'):
405 if user.api_key == request.GET.get('api_key'):
405 api_access_ok = True
406 api_access_ok = True
406 else:
407 else:
407 log.debug("API KEY token not valid")
408 log.debug("API KEY token not valid")
408
409
409 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
410 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
410 if user.is_authenticated or api_access_ok:
411 if user.is_authenticated or api_access_ok:
411 log.debug('user %s is authenticated', user.username)
412 log.debug('user %s is authenticated', user.username)
412 return func(*fargs, **fkwargs)
413 return func(*fargs, **fkwargs)
413 else:
414 else:
414 log.warn('user %s NOT authenticated', user.username)
415 log.warn('user %s NOT authenticated', user.username)
415 p = url.current()
416 p = url.current()
416
417
417 log.debug('redirecting to login page with %s', p)
418 log.debug('redirecting to login page with %s', p)
418 return redirect(url('login_home', came_from=p))
419 return redirect(url('login_home', came_from=p))
419
420
420
421
421 class NotAnonymous(object):
422 class NotAnonymous(object):
422 """Must be logged in to execute this function else
423 """Must be logged in to execute this function else
423 redirect to login page"""
424 redirect to login page"""
424
425
425 def __call__(self, func):
426 def __call__(self, func):
426 return decorator(self.__wrapper, func)
427 return decorator(self.__wrapper, func)
427
428
428 def __wrapper(self, func, *fargs, **fkwargs):
429 def __wrapper(self, func, *fargs, **fkwargs):
429 cls = fargs[0]
430 cls = fargs[0]
430 self.user = cls.rhodecode_user
431 self.user = cls.rhodecode_user
431
432
432 log.debug('Checking if user is not anonymous @%s', cls)
433 log.debug('Checking if user is not anonymous @%s', cls)
433
434
434 anonymous = self.user.username == 'default'
435 anonymous = self.user.username == 'default'
435
436
436 if anonymous:
437 if anonymous:
437 p = url.current()
438 p = url.current()
438
439
439 import rhodecode.lib.helpers as h
440 import rhodecode.lib.helpers as h
440 h.flash(_('You need to be a registered user to '
441 h.flash(_('You need to be a registered user to '
441 'perform this action'),
442 'perform this action'),
442 category='warning')
443 category='warning')
443 return redirect(url('login_home', came_from=p))
444 return redirect(url('login_home', came_from=p))
444 else:
445 else:
445 return func(*fargs, **fkwargs)
446 return func(*fargs, **fkwargs)
446
447
447
448
448 class PermsDecorator(object):
449 class PermsDecorator(object):
449 """Base class for controller decorators"""
450 """Base class for controller decorators"""
450
451
451 def __init__(self, *required_perms):
452 def __init__(self, *required_perms):
452 available_perms = config['available_permissions']
453 available_perms = config['available_permissions']
453 for perm in required_perms:
454 for perm in required_perms:
454 if perm not in available_perms:
455 if perm not in available_perms:
455 raise Exception("'%s' permission is not defined" % perm)
456 raise Exception("'%s' permission is not defined" % perm)
456 self.required_perms = set(required_perms)
457 self.required_perms = set(required_perms)
457 self.user_perms = None
458 self.user_perms = None
458
459
459 def __call__(self, func):
460 def __call__(self, func):
460 return decorator(self.__wrapper, func)
461 return decorator(self.__wrapper, func)
461
462
462 def __wrapper(self, func, *fargs, **fkwargs):
463 def __wrapper(self, func, *fargs, **fkwargs):
463 cls = fargs[0]
464 cls = fargs[0]
464 self.user = cls.rhodecode_user
465 self.user = cls.rhodecode_user
465 self.user_perms = self.user.permissions
466 self.user_perms = self.user.permissions
466 log.debug('checking %s permissions %s for %s %s',
467 log.debug('checking %s permissions %s for %s %s',
467 self.__class__.__name__, self.required_perms, cls,
468 self.__class__.__name__, self.required_perms, cls,
468 self.user)
469 self.user)
469
470
470 if self.check_permissions():
471 if self.check_permissions():
471 log.debug('Permission granted for %s %s', cls, self.user)
472 log.debug('Permission granted for %s %s', cls, self.user)
472 return func(*fargs, **fkwargs)
473 return func(*fargs, **fkwargs)
473
474
474 else:
475 else:
475 log.warning('Permission denied for %s %s', cls, self.user)
476 log.warning('Permission denied for %s %s', cls, self.user)
476
477
477
478
478 anonymous = self.user.username == 'default'
479 anonymous = self.user.username == 'default'
479
480
480 if anonymous:
481 if anonymous:
481 p = url.current()
482 p = url.current()
482
483
483 import rhodecode.lib.helpers as h
484 import rhodecode.lib.helpers as h
484 h.flash(_('You need to be a signed in to '
485 h.flash(_('You need to be a signed in to '
485 'view this page'),
486 'view this page'),
486 category='warning')
487 category='warning')
487 return redirect(url('login_home', came_from=p))
488 return redirect(url('login_home', came_from=p))
488
489
489 else:
490 else:
490 # redirect with forbidden ret code
491 # redirect with forbidden ret code
491 return abort(403)
492 return abort(403)
492
493
493 def check_permissions(self):
494 def check_permissions(self):
494 """Dummy function for overriding"""
495 """Dummy function for overriding"""
495 raise Exception('You have to write this function in child class')
496 raise Exception('You have to write this function in child class')
496
497
497
498
498 class HasPermissionAllDecorator(PermsDecorator):
499 class HasPermissionAllDecorator(PermsDecorator):
499 """Checks for access permission for all given predicates. All of them
500 """Checks for access permission for all given predicates. All of them
500 have to be meet in order to fulfill the request
501 have to be meet in order to fulfill the request
501 """
502 """
502
503
503 def check_permissions(self):
504 def check_permissions(self):
504 if self.required_perms.issubset(self.user_perms.get('global')):
505 if self.required_perms.issubset(self.user_perms.get('global')):
505 return True
506 return True
506 return False
507 return False
507
508
508
509
509 class HasPermissionAnyDecorator(PermsDecorator):
510 class HasPermissionAnyDecorator(PermsDecorator):
510 """Checks for access permission for any of given predicates. In order to
511 """Checks for access permission for any of given predicates. In order to
511 fulfill the request any of predicates must be meet
512 fulfill the request any of predicates must be meet
512 """
513 """
513
514
514 def check_permissions(self):
515 def check_permissions(self):
515 if self.required_perms.intersection(self.user_perms.get('global')):
516 if self.required_perms.intersection(self.user_perms.get('global')):
516 return True
517 return True
517 return False
518 return False
518
519
519
520
520 class HasRepoPermissionAllDecorator(PermsDecorator):
521 class HasRepoPermissionAllDecorator(PermsDecorator):
521 """Checks for access permission for all given predicates for specific
522 """Checks for access permission for all given predicates for specific
522 repository. All of them have to be meet in order to fulfill the request
523 repository. All of them have to be meet in order to fulfill the request
523 """
524 """
524
525
525 def check_permissions(self):
526 def check_permissions(self):
526 repo_name = get_repo_slug(request)
527 repo_name = get_repo_slug(request)
527 try:
528 try:
528 user_perms = set([self.user_perms['repositories'][repo_name]])
529 user_perms = set([self.user_perms['repositories'][repo_name]])
529 except KeyError:
530 except KeyError:
530 return False
531 return False
531 if self.required_perms.issubset(user_perms):
532 if self.required_perms.issubset(user_perms):
532 return True
533 return True
533 return False
534 return False
534
535
535
536
536 class HasRepoPermissionAnyDecorator(PermsDecorator):
537 class HasRepoPermissionAnyDecorator(PermsDecorator):
537 """Checks for access permission for any of given predicates for specific
538 """Checks for access permission for any of given predicates for specific
538 repository. In order to fulfill the request any of predicates must be meet
539 repository. In order to fulfill the request any of predicates must be meet
539 """
540 """
540
541
541 def check_permissions(self):
542 def check_permissions(self):
542 repo_name = get_repo_slug(request)
543 repo_name = get_repo_slug(request)
543
544
544 try:
545 try:
545 user_perms = set([self.user_perms['repositories'][repo_name]])
546 user_perms = set([self.user_perms['repositories'][repo_name]])
546 except KeyError:
547 except KeyError:
547 return False
548 return False
548 if self.required_perms.intersection(user_perms):
549 if self.required_perms.intersection(user_perms):
549 return True
550 return True
550 return False
551 return False
551
552
552
553
553 #==============================================================================
554 #==============================================================================
554 # CHECK FUNCTIONS
555 # CHECK FUNCTIONS
555 #==============================================================================
556 #==============================================================================
556 class PermsFunction(object):
557 class PermsFunction(object):
557 """Base function for other check functions"""
558 """Base function for other check functions"""
558
559
559 def __init__(self, *perms):
560 def __init__(self, *perms):
560 available_perms = config['available_permissions']
561 available_perms = config['available_permissions']
561
562
562 for perm in perms:
563 for perm in perms:
563 if perm not in available_perms:
564 if perm not in available_perms:
564 raise Exception("'%s' permission in not defined" % perm)
565 raise Exception("'%s' permission in not defined" % perm)
565 self.required_perms = set(perms)
566 self.required_perms = set(perms)
566 self.user_perms = None
567 self.user_perms = None
567 self.granted_for = ''
568 self.granted_for = ''
568 self.repo_name = None
569 self.repo_name = None
569
570
570 def __call__(self, check_Location=''):
571 def __call__(self, check_Location=''):
571 user = session.get('rhodecode_user', False)
572 user = session.get('rhodecode_user', False)
572 if not user:
573 if not user:
573 return False
574 return False
574 self.user_perms = user.permissions
575 self.user_perms = user.permissions
575 self.granted_for = user
576 self.granted_for = user
576 log.debug('checking %s %s %s', self.__class__.__name__,
577 log.debug('checking %s %s %s', self.__class__.__name__,
577 self.required_perms, user)
578 self.required_perms, user)
578
579
579 if self.check_permissions():
580 if self.check_permissions():
580 log.debug('Permission granted %s @ %s', self.granted_for,
581 log.debug('Permission granted %s @ %s', self.granted_for,
581 check_Location or 'unspecified location')
582 check_Location or 'unspecified location')
582 return True
583 return True
583
584
584 else:
585 else:
585 log.warning('Permission denied for %s @ %s', self.granted_for,
586 log.warning('Permission denied for %s @ %s', self.granted_for,
586 check_Location or 'unspecified location')
587 check_Location or 'unspecified location')
587 return False
588 return False
588
589
589 def check_permissions(self):
590 def check_permissions(self):
590 """Dummy function for overriding"""
591 """Dummy function for overriding"""
591 raise Exception('You have to write this function in child class')
592 raise Exception('You have to write this function in child class')
592
593
593
594
594 class HasPermissionAll(PermsFunction):
595 class HasPermissionAll(PermsFunction):
595 def check_permissions(self):
596 def check_permissions(self):
596 if self.required_perms.issubset(self.user_perms.get('global')):
597 if self.required_perms.issubset(self.user_perms.get('global')):
597 return True
598 return True
598 return False
599 return False
599
600
600
601
601 class HasPermissionAny(PermsFunction):
602 class HasPermissionAny(PermsFunction):
602 def check_permissions(self):
603 def check_permissions(self):
603 if self.required_perms.intersection(self.user_perms.get('global')):
604 if self.required_perms.intersection(self.user_perms.get('global')):
604 return True
605 return True
605 return False
606 return False
606
607
607
608
608 class HasRepoPermissionAll(PermsFunction):
609 class HasRepoPermissionAll(PermsFunction):
609
610
610 def __call__(self, repo_name=None, check_Location=''):
611 def __call__(self, repo_name=None, check_Location=''):
611 self.repo_name = repo_name
612 self.repo_name = repo_name
612 return super(HasRepoPermissionAll, self).__call__(check_Location)
613 return super(HasRepoPermissionAll, self).__call__(check_Location)
613
614
614 def check_permissions(self):
615 def check_permissions(self):
615 if not self.repo_name:
616 if not self.repo_name:
616 self.repo_name = get_repo_slug(request)
617 self.repo_name = get_repo_slug(request)
617
618
618 try:
619 try:
619 self.user_perms = set([self.user_perms['reposit'
620 self.user_perms = set([self.user_perms['reposit'
620 'ories'][self.repo_name]])
621 'ories'][self.repo_name]])
621 except KeyError:
622 except KeyError:
622 return False
623 return False
623 self.granted_for = self.repo_name
624 self.granted_for = self.repo_name
624 if self.required_perms.issubset(self.user_perms):
625 if self.required_perms.issubset(self.user_perms):
625 return True
626 return True
626 return False
627 return False
627
628
628
629
629 class HasRepoPermissionAny(PermsFunction):
630 class HasRepoPermissionAny(PermsFunction):
630
631
631 def __call__(self, repo_name=None, check_Location=''):
632 def __call__(self, repo_name=None, check_Location=''):
632 self.repo_name = repo_name
633 self.repo_name = repo_name
633 return super(HasRepoPermissionAny, self).__call__(check_Location)
634 return super(HasRepoPermissionAny, self).__call__(check_Location)
634
635
635 def check_permissions(self):
636 def check_permissions(self):
636 if not self.repo_name:
637 if not self.repo_name:
637 self.repo_name = get_repo_slug(request)
638 self.repo_name = get_repo_slug(request)
638
639
639 try:
640 try:
640 self.user_perms = set([self.user_perms['reposi'
641 self.user_perms = set([self.user_perms['reposi'
641 'tories'][self.repo_name]])
642 'tories'][self.repo_name]])
642 except KeyError:
643 except KeyError:
643 return False
644 return False
644 self.granted_for = self.repo_name
645 self.granted_for = self.repo_name
645 if self.required_perms.intersection(self.user_perms):
646 if self.required_perms.intersection(self.user_perms):
646 return True
647 return True
647 return False
648 return False
648
649
649
650
650 #==============================================================================
651 #==============================================================================
651 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
652 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
652 #==============================================================================
653 #==============================================================================
653 class HasPermissionAnyMiddleware(object):
654 class HasPermissionAnyMiddleware(object):
654 def __init__(self, *perms):
655 def __init__(self, *perms):
655 self.required_perms = set(perms)
656 self.required_perms = set(perms)
656
657
657 def __call__(self, user, repo_name):
658 def __call__(self, user, repo_name):
658 usr = AuthUser(user.user_id)
659 usr = AuthUser(user.user_id)
659 try:
660 try:
660 self.user_perms = set([usr.permissions['repositories'][repo_name]])
661 self.user_perms = set([usr.permissions['repositories'][repo_name]])
661 except:
662 except:
662 self.user_perms = set()
663 self.user_perms = set()
663 self.granted_for = ''
664 self.granted_for = ''
664 self.username = user.username
665 self.username = user.username
665 self.repo_name = repo_name
666 self.repo_name = repo_name
666 return self.check_permissions()
667 return self.check_permissions()
667
668
668 def check_permissions(self):
669 def check_permissions(self):
669 log.debug('checking mercurial protocol '
670 log.debug('checking mercurial protocol '
670 'permissions %s for user:%s repository:%s', self.user_perms,
671 'permissions %s for user:%s repository:%s', self.user_perms,
671 self.username, self.repo_name)
672 self.username, self.repo_name)
672 if self.required_perms.intersection(self.user_perms):
673 if self.required_perms.intersection(self.user_perms):
673 log.debug('permission granted')
674 log.debug('permission granted')
674 return True
675 return True
675 log.debug('permission denied')
676 log.debug('permission denied')
676 return False
677 return False
677
678
General Comments 0
You need to be logged in to leave comments. Login now