##// END OF EJS Templates
artifacts: expose a special auth-token based artifacts download urls....
marcink -
r4003:09f31efc default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,49 +1,52 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 import os
20 import os
21 from rhodecode.apps.file_store import config_keys
21 from rhodecode.apps.file_store import config_keys
22 from rhodecode.config.middleware import _bool_setting, _string_setting
22 from rhodecode.config.middleware import _bool_setting, _string_setting
23
23
24
24
25 def _sanitize_settings_and_apply_defaults(settings):
25 def _sanitize_settings_and_apply_defaults(settings):
26 """
26 """
27 Set defaults, convert to python types and validate settings.
27 Set defaults, convert to python types and validate settings.
28 """
28 """
29 _bool_setting(settings, config_keys.enabled, 'true')
29 _bool_setting(settings, config_keys.enabled, 'true')
30
30
31 _string_setting(settings, config_keys.backend, 'local')
31 _string_setting(settings, config_keys.backend, 'local')
32
32
33 default_store = os.path.join(os.path.dirname(settings['__file__']), 'upload_store')
33 default_store = os.path.join(os.path.dirname(settings['__file__']), 'upload_store')
34 _string_setting(settings, config_keys.store_path, default_store)
34 _string_setting(settings, config_keys.store_path, default_store)
35
35
36
36
37 def includeme(config):
37 def includeme(config):
38 settings = config.registry.settings
38 settings = config.registry.settings
39 _sanitize_settings_and_apply_defaults(settings)
39 _sanitize_settings_and_apply_defaults(settings)
40
40
41 config.add_route(
41 config.add_route(
42 name='upload_file',
42 name='upload_file',
43 pattern='/_file_store/upload')
43 pattern='/_file_store/upload')
44 config.add_route(
44 config.add_route(
45 name='download_file',
45 name='download_file',
46 pattern='/_file_store/download/{fid}')
46 pattern='/_file_store/download/{fid}')
47 config.add_route(
48 name='download_file_by_token',
49 pattern='/_file_store/token-download/{_auth_token}/{fid}')
47
50
48 # Scan module for configuration decorators.
51 # Scan module for configuration decorators.
49 config.scan('.views', ignore='.tests')
52 config.scan('.views', ignore='.tests')
@@ -1,146 +1,166 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 import logging
20 import logging
21
21
22 from pyramid.view import view_config
22 from pyramid.view import view_config
23 from pyramid.response import FileResponse
23 from pyramid.response import FileResponse
24 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
24 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
25
25
26 from rhodecode.apps._base import BaseAppView
26 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps.file_store import utils
27 from rhodecode.apps.file_store import utils
28 from rhodecode.apps.file_store.exceptions import (
28 from rhodecode.apps.file_store.exceptions import (
29 FileNotAllowedException, FileOverSizeException)
29 FileNotAllowedException, FileOverSizeException)
30
30
31 from rhodecode.lib import helpers as h
31 from rhodecode.lib import helpers as h
32 from rhodecode.lib import audit_logger
32 from rhodecode.lib import audit_logger
33 from rhodecode.lib.auth import (CSRFRequired, NotAnonymous, HasRepoPermissionAny, HasRepoGroupPermissionAny)
33 from rhodecode.lib.auth import (
34 from rhodecode.model.db import Session, FileStore
34 CSRFRequired, NotAnonymous, HasRepoPermissionAny, HasRepoGroupPermissionAny,
35 LoginRequired)
36 from rhodecode.model.db import Session, FileStore, UserApiKeys
35
37
36 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
37
39
38
40
39 class FileStoreView(BaseAppView):
41 class FileStoreView(BaseAppView):
40 upload_key = 'store_file'
42 upload_key = 'store_file'
41
43
42 def load_default_context(self):
44 def load_default_context(self):
43 c = self._get_local_tmpl_context()
45 c = self._get_local_tmpl_context()
44 self.storage = utils.get_file_storage(self.request.registry.settings)
46 self.storage = utils.get_file_storage(self.request.registry.settings)
45 return c
47 return c
46
48
49 @LoginRequired()
47 @NotAnonymous()
50 @NotAnonymous()
48 @CSRFRequired()
51 @CSRFRequired()
49 @view_config(route_name='upload_file', request_method='POST', renderer='json_ext')
52 @view_config(route_name='upload_file', request_method='POST', renderer='json_ext')
50 def upload_file(self):
53 def upload_file(self):
51 self.load_default_context()
54 self.load_default_context()
52 file_obj = self.request.POST.get(self.upload_key)
55 file_obj = self.request.POST.get(self.upload_key)
53
56
54 if file_obj is None:
57 if file_obj is None:
55 return {'store_fid': None,
58 return {'store_fid': None,
56 'access_path': None,
59 'access_path': None,
57 'error': '{} data field is missing'.format(self.upload_key)}
60 'error': '{} data field is missing'.format(self.upload_key)}
58
61
59 if not hasattr(file_obj, 'filename'):
62 if not hasattr(file_obj, 'filename'):
60 return {'store_fid': None,
63 return {'store_fid': None,
61 'access_path': None,
64 'access_path': None,
62 'error': 'filename cannot be read from the data field'}
65 'error': 'filename cannot be read from the data field'}
63
66
64 filename = file_obj.filename
67 filename = file_obj.filename
65
68
66 metadata = {
69 metadata = {
67 'user_uploaded': {'username': self._rhodecode_user.username,
70 'user_uploaded': {'username': self._rhodecode_user.username,
68 'user_id': self._rhodecode_user.user_id,
71 'user_id': self._rhodecode_user.user_id,
69 'ip': self._rhodecode_user.ip_addr}}
72 'ip': self._rhodecode_user.ip_addr}}
70 try:
73 try:
71 store_uid, metadata = self.storage.save_file(
74 store_uid, metadata = self.storage.save_file(
72 file_obj.file, filename, extra_metadata=metadata)
75 file_obj.file, filename, extra_metadata=metadata)
73 except FileNotAllowedException:
76 except FileNotAllowedException:
74 return {'store_fid': None,
77 return {'store_fid': None,
75 'access_path': None,
78 'access_path': None,
76 'error': 'File {} is not allowed.'.format(filename)}
79 'error': 'File {} is not allowed.'.format(filename)}
77
80
78 except FileOverSizeException:
81 except FileOverSizeException:
79 return {'store_fid': None,
82 return {'store_fid': None,
80 'access_path': None,
83 'access_path': None,
81 'error': 'File {} is exceeding allowed limit.'.format(filename)}
84 'error': 'File {} is exceeding allowed limit.'.format(filename)}
82
85
83 try:
86 try:
84 entry = FileStore.create(
87 entry = FileStore.create(
85 file_uid=store_uid, filename=metadata["filename"],
88 file_uid=store_uid, filename=metadata["filename"],
86 file_hash=metadata["sha256"], file_size=metadata["size"],
89 file_hash=metadata["sha256"], file_size=metadata["size"],
87 file_description='upload attachment',
90 file_description='upload attachment',
88 check_acl=False, user_id=self._rhodecode_user.user_id
91 check_acl=False, user_id=self._rhodecode_user.user_id
89 )
92 )
90 Session().add(entry)
93 Session().add(entry)
91 Session().commit()
94 Session().commit()
92 log.debug('Stored upload in DB as %s', entry)
95 log.debug('Stored upload in DB as %s', entry)
93 except Exception:
96 except Exception:
94 log.exception('Failed to store file %s', filename)
97 log.exception('Failed to store file %s', filename)
95 return {'store_fid': None,
98 return {'store_fid': None,
96 'access_path': None,
99 'access_path': None,
97 'error': 'File {} failed to store in DB.'.format(filename)}
100 'error': 'File {} failed to store in DB.'.format(filename)}
98
101
99 return {'store_fid': store_uid,
102 return {'store_fid': store_uid,
100 'access_path': h.route_path('download_file', fid=store_uid)}
103 'access_path': h.route_path('download_file', fid=store_uid)}
101
104
102 @view_config(route_name='download_file')
105 def _serve_file(self, file_uid):
103 def download_file(self):
104 self.load_default_context()
105 file_uid = self.request.matchdict['fid']
106 log.debug('Requesting FID:%s from store %s', file_uid, self.storage)
107
106
108 if not self.storage.exists(file_uid):
107 if not self.storage.exists(file_uid):
109 store_path = self.storage.store_path(file_uid)
108 store_path = self.storage.store_path(file_uid)
110 log.debug('File with FID:%s not found in the store under `%s`',
109 log.debug('File with FID:%s not found in the store under `%s`',
111 file_uid, store_path)
110 file_uid, store_path)
112 raise HTTPNotFound()
111 raise HTTPNotFound()
113
112
114 db_obj = FileStore().query().filter(FileStore.file_uid == file_uid).scalar()
113 db_obj = FileStore().query().filter(FileStore.file_uid == file_uid).scalar()
115 if not db_obj:
114 if not db_obj:
116 raise HTTPNotFound()
115 raise HTTPNotFound()
117
116
118 # private upload for user
117 # private upload for user
119 if db_obj.check_acl and db_obj.scope_user_id:
118 if db_obj.check_acl and db_obj.scope_user_id:
120 user = db_obj.user
119 user = db_obj.user
121 if self._rhodecode_db_user.user_id != user.user_id:
120 if self._rhodecode_db_user.user_id != user.user_id:
122 log.warning('Access to file store object forbidden')
121 log.warning('Access to file store object forbidden')
123 raise HTTPNotFound()
122 raise HTTPNotFound()
124
123
125 # scoped to repository permissions
124 # scoped to repository permissions
126 if db_obj.check_acl and db_obj.scope_repo_id:
125 if db_obj.check_acl and db_obj.scope_repo_id:
127 repo = db_obj.repo
126 repo = db_obj.repo
128 perm_set = ['repository.read', 'repository.write', 'repository.admin']
127 perm_set = ['repository.read', 'repository.write', 'repository.admin']
129 has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'FileStore check')
128 has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'FileStore check')
130 if not has_perm:
129 if not has_perm:
131 log.warning('Access to file store object forbidden')
130 log.warning('Access to file store object `%s` forbidden', file_uid)
132 raise HTTPNotFound()
131 raise HTTPNotFound()
133
132
134 # scoped to repository group permissions
133 # scoped to repository group permissions
135 if db_obj.check_acl and db_obj.scope_repo_group_id:
134 if db_obj.check_acl and db_obj.scope_repo_group_id:
136 repo_group = db_obj.repo_group
135 repo_group = db_obj.repo_group
137 perm_set = ['group.read', 'group.write', 'group.admin']
136 perm_set = ['group.read', 'group.write', 'group.admin']
138 has_perm = HasRepoGroupPermissionAny(*perm_set)(repo_group.group_name, 'FileStore check')
137 has_perm = HasRepoGroupPermissionAny(*perm_set)(repo_group.group_name, 'FileStore check')
139 if not has_perm:
138 if not has_perm:
140 log.warning('Access to file store object forbidden')
139 log.warning('Access to file store object `%s` forbidden', file_uid)
141 raise HTTPNotFound()
140 raise HTTPNotFound()
142
141
143 FileStore.bump_access_counter(file_uid)
142 FileStore.bump_access_counter(file_uid)
144
143
145 file_path = self.storage.store_path(file_uid)
144 file_path = self.storage.store_path(file_uid)
146 return FileResponse(file_path)
145 return FileResponse(file_path)
146
147 # ACL is checked by scopes, if no scope the file is accessible to all
148 @view_config(route_name='download_file')
149 def download_file(self):
150 self.load_default_context()
151 file_uid = self.request.matchdict['fid']
152 log.debug('Requesting FID:%s from store %s', file_uid, self.storage)
153 return self._serve_file(file_uid)
154
155 @LoginRequired(auth_token_access=[UserApiKeys.ROLE_ARTIFACT_DOWNLOAD])
156 @view_config(route_name='download_file_by_token')
157 def download_file_by_token(self):
158 """
159 Special view that allows to access the download file by special URL that
160 is stored inside the URL.
161
162 http://example.com/_file_store/token-download/TOKEN/FILE_UID
163 """
164 self.load_default_context()
165 file_uid = self.request.matchdict['fid']
166 return self._serve_file(file_uid)
@@ -1,2352 +1,2369 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 authentication and permission libraries
22 authentication and permission libraries
23 """
23 """
24
24
25 import os
25 import os
26 import time
26 import time
27 import inspect
27 import inspect
28 import collections
28 import collections
29 import fnmatch
29 import fnmatch
30 import hashlib
30 import hashlib
31 import itertools
31 import itertools
32 import logging
32 import logging
33 import random
33 import random
34 import traceback
34 import traceback
35 from functools import wraps
35 from functools import wraps
36
36
37 import ipaddress
37 import ipaddress
38
38
39 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
39 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
40 from sqlalchemy.orm.exc import ObjectDeletedError
40 from sqlalchemy.orm.exc import ObjectDeletedError
41 from sqlalchemy.orm import joinedload
41 from sqlalchemy.orm import joinedload
42 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from zope.cachedescriptors.property import Lazy as LazyProperty
43
43
44 import rhodecode
44 import rhodecode
45 from rhodecode.model import meta
45 from rhodecode.model import meta
46 from rhodecode.model.meta import Session
46 from rhodecode.model.meta import Session
47 from rhodecode.model.user import UserModel
47 from rhodecode.model.user import UserModel
48 from rhodecode.model.db import (
48 from rhodecode.model.db import (
49 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
49 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
50 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
50 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
51 from rhodecode.lib import rc_cache
51 from rhodecode.lib import rc_cache
52 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int, sha1
52 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int, sha1
53 from rhodecode.lib.utils import (
53 from rhodecode.lib.utils import (
54 get_repo_slug, get_repo_group_slug, get_user_group_slug)
54 get_repo_slug, get_repo_group_slug, get_user_group_slug)
55 from rhodecode.lib.caching_query import FromCache
55 from rhodecode.lib.caching_query import FromCache
56
56
57
57
58 if rhodecode.is_unix:
58 if rhodecode.is_unix:
59 import bcrypt
59 import bcrypt
60
60
61 log = logging.getLogger(__name__)
61 log = logging.getLogger(__name__)
62
62
63 csrf_token_key = "csrf_token"
63 csrf_token_key = "csrf_token"
64
64
65
65
66 class PasswordGenerator(object):
66 class PasswordGenerator(object):
67 """
67 """
68 This is a simple class for generating password from different sets of
68 This is a simple class for generating password from different sets of
69 characters
69 characters
70 usage::
70 usage::
71 passwd_gen = PasswordGenerator()
71 passwd_gen = PasswordGenerator()
72 #print 8-letter password containing only big and small letters
72 #print 8-letter password containing only big and small letters
73 of alphabet
73 of alphabet
74 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
74 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
75 """
75 """
76 ALPHABETS_NUM = r'''1234567890'''
76 ALPHABETS_NUM = r'''1234567890'''
77 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
77 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
78 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
78 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
79 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
79 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
80 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
80 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
81 + ALPHABETS_NUM + ALPHABETS_SPECIAL
81 + ALPHABETS_NUM + ALPHABETS_SPECIAL
82 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
82 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
83 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
83 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
84 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
84 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
86
86
87 def __init__(self, passwd=''):
87 def __init__(self, passwd=''):
88 self.passwd = passwd
88 self.passwd = passwd
89
89
90 def gen_password(self, length, type_=None):
90 def gen_password(self, length, type_=None):
91 if type_ is None:
91 if type_ is None:
92 type_ = self.ALPHABETS_FULL
92 type_ = self.ALPHABETS_FULL
93 self.passwd = ''.join([random.choice(type_) for _ in range(length)])
93 self.passwd = ''.join([random.choice(type_) for _ in range(length)])
94 return self.passwd
94 return self.passwd
95
95
96
96
97 class _RhodeCodeCryptoBase(object):
97 class _RhodeCodeCryptoBase(object):
98 ENC_PREF = None
98 ENC_PREF = None
99
99
100 def hash_create(self, str_):
100 def hash_create(self, str_):
101 """
101 """
102 hash the string using
102 hash the string using
103
103
104 :param str_: password to hash
104 :param str_: password to hash
105 """
105 """
106 raise NotImplementedError
106 raise NotImplementedError
107
107
108 def hash_check_with_upgrade(self, password, hashed):
108 def hash_check_with_upgrade(self, password, hashed):
109 """
109 """
110 Returns tuple in which first element is boolean that states that
110 Returns tuple in which first element is boolean that states that
111 given password matches it's hashed version, and the second is new hash
111 given password matches it's hashed version, and the second is new hash
112 of the password, in case this password should be migrated to new
112 of the password, in case this password should be migrated to new
113 cipher.
113 cipher.
114 """
114 """
115 checked_hash = self.hash_check(password, hashed)
115 checked_hash = self.hash_check(password, hashed)
116 return checked_hash, None
116 return checked_hash, None
117
117
118 def hash_check(self, password, hashed):
118 def hash_check(self, password, hashed):
119 """
119 """
120 Checks matching password with it's hashed value.
120 Checks matching password with it's hashed value.
121
121
122 :param password: password
122 :param password: password
123 :param hashed: password in hashed form
123 :param hashed: password in hashed form
124 """
124 """
125 raise NotImplementedError
125 raise NotImplementedError
126
126
127 def _assert_bytes(self, value):
127 def _assert_bytes(self, value):
128 """
128 """
129 Passing in an `unicode` object can lead to hard to detect issues
129 Passing in an `unicode` object can lead to hard to detect issues
130 if passwords contain non-ascii characters. Doing a type check
130 if passwords contain non-ascii characters. Doing a type check
131 during runtime, so that such mistakes are detected early on.
131 during runtime, so that such mistakes are detected early on.
132 """
132 """
133 if not isinstance(value, str):
133 if not isinstance(value, str):
134 raise TypeError(
134 raise TypeError(
135 "Bytestring required as input, got %r." % (value, ))
135 "Bytestring required as input, got %r." % (value, ))
136
136
137
137
138 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
138 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
139 ENC_PREF = ('$2a$10', '$2b$10')
139 ENC_PREF = ('$2a$10', '$2b$10')
140
140
141 def hash_create(self, str_):
141 def hash_create(self, str_):
142 self._assert_bytes(str_)
142 self._assert_bytes(str_)
143 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
143 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
144
144
145 def hash_check_with_upgrade(self, password, hashed):
145 def hash_check_with_upgrade(self, password, hashed):
146 """
146 """
147 Returns tuple in which first element is boolean that states that
147 Returns tuple in which first element is boolean that states that
148 given password matches it's hashed version, and the second is new hash
148 given password matches it's hashed version, and the second is new hash
149 of the password, in case this password should be migrated to new
149 of the password, in case this password should be migrated to new
150 cipher.
150 cipher.
151
151
152 This implements special upgrade logic which works like that:
152 This implements special upgrade logic which works like that:
153 - check if the given password == bcrypted hash, if yes then we
153 - check if the given password == bcrypted hash, if yes then we
154 properly used password and it was already in bcrypt. Proceed
154 properly used password and it was already in bcrypt. Proceed
155 without any changes
155 without any changes
156 - if bcrypt hash check is not working try with sha256. If hash compare
156 - if bcrypt hash check is not working try with sha256. If hash compare
157 is ok, it means we using correct but old hashed password. indicate
157 is ok, it means we using correct but old hashed password. indicate
158 hash change and proceed
158 hash change and proceed
159 """
159 """
160
160
161 new_hash = None
161 new_hash = None
162
162
163 # regular pw check
163 # regular pw check
164 password_match_bcrypt = self.hash_check(password, hashed)
164 password_match_bcrypt = self.hash_check(password, hashed)
165
165
166 # now we want to know if the password was maybe from sha256
166 # now we want to know if the password was maybe from sha256
167 # basically calling _RhodeCodeCryptoSha256().hash_check()
167 # basically calling _RhodeCodeCryptoSha256().hash_check()
168 if not password_match_bcrypt:
168 if not password_match_bcrypt:
169 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
169 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
170 new_hash = self.hash_create(password) # make new bcrypt hash
170 new_hash = self.hash_create(password) # make new bcrypt hash
171 password_match_bcrypt = True
171 password_match_bcrypt = True
172
172
173 return password_match_bcrypt, new_hash
173 return password_match_bcrypt, new_hash
174
174
175 def hash_check(self, password, hashed):
175 def hash_check(self, password, hashed):
176 """
176 """
177 Checks matching password with it's hashed value.
177 Checks matching password with it's hashed value.
178
178
179 :param password: password
179 :param password: password
180 :param hashed: password in hashed form
180 :param hashed: password in hashed form
181 """
181 """
182 self._assert_bytes(password)
182 self._assert_bytes(password)
183 try:
183 try:
184 return bcrypt.hashpw(password, hashed) == hashed
184 return bcrypt.hashpw(password, hashed) == hashed
185 except ValueError as e:
185 except ValueError as e:
186 # we're having a invalid salt here probably, we should not crash
186 # we're having a invalid salt here probably, we should not crash
187 # just return with False as it would be a wrong password.
187 # just return with False as it would be a wrong password.
188 log.debug('Failed to check password hash using bcrypt %s',
188 log.debug('Failed to check password hash using bcrypt %s',
189 safe_str(e))
189 safe_str(e))
190
190
191 return False
191 return False
192
192
193
193
194 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
194 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
195 ENC_PREF = '_'
195 ENC_PREF = '_'
196
196
197 def hash_create(self, str_):
197 def hash_create(self, str_):
198 self._assert_bytes(str_)
198 self._assert_bytes(str_)
199 return hashlib.sha256(str_).hexdigest()
199 return hashlib.sha256(str_).hexdigest()
200
200
201 def hash_check(self, password, hashed):
201 def hash_check(self, password, hashed):
202 """
202 """
203 Checks matching password with it's hashed value.
203 Checks matching password with it's hashed value.
204
204
205 :param password: password
205 :param password: password
206 :param hashed: password in hashed form
206 :param hashed: password in hashed form
207 """
207 """
208 self._assert_bytes(password)
208 self._assert_bytes(password)
209 return hashlib.sha256(password).hexdigest() == hashed
209 return hashlib.sha256(password).hexdigest() == hashed
210
210
211
211
212 class _RhodeCodeCryptoTest(_RhodeCodeCryptoBase):
212 class _RhodeCodeCryptoTest(_RhodeCodeCryptoBase):
213 ENC_PREF = '_'
213 ENC_PREF = '_'
214
214
215 def hash_create(self, str_):
215 def hash_create(self, str_):
216 self._assert_bytes(str_)
216 self._assert_bytes(str_)
217 return sha1(str_)
217 return sha1(str_)
218
218
219 def hash_check(self, password, hashed):
219 def hash_check(self, password, hashed):
220 """
220 """
221 Checks matching password with it's hashed value.
221 Checks matching password with it's hashed value.
222
222
223 :param password: password
223 :param password: password
224 :param hashed: password in hashed form
224 :param hashed: password in hashed form
225 """
225 """
226 self._assert_bytes(password)
226 self._assert_bytes(password)
227 return sha1(password) == hashed
227 return sha1(password) == hashed
228
228
229
229
230 def crypto_backend():
230 def crypto_backend():
231 """
231 """
232 Return the matching crypto backend.
232 Return the matching crypto backend.
233
233
234 Selection is based on if we run tests or not, we pick sha1-test backend to run
234 Selection is based on if we run tests or not, we pick sha1-test backend to run
235 tests faster since BCRYPT is expensive to calculate
235 tests faster since BCRYPT is expensive to calculate
236 """
236 """
237 if rhodecode.is_test:
237 if rhodecode.is_test:
238 RhodeCodeCrypto = _RhodeCodeCryptoTest()
238 RhodeCodeCrypto = _RhodeCodeCryptoTest()
239 else:
239 else:
240 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
240 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
241
241
242 return RhodeCodeCrypto
242 return RhodeCodeCrypto
243
243
244
244
245 def get_crypt_password(password):
245 def get_crypt_password(password):
246 """
246 """
247 Create the hash of `password` with the active crypto backend.
247 Create the hash of `password` with the active crypto backend.
248
248
249 :param password: The cleartext password.
249 :param password: The cleartext password.
250 :type password: unicode
250 :type password: unicode
251 """
251 """
252 password = safe_str(password)
252 password = safe_str(password)
253 return crypto_backend().hash_create(password)
253 return crypto_backend().hash_create(password)
254
254
255
255
256 def check_password(password, hashed):
256 def check_password(password, hashed):
257 """
257 """
258 Check if the value in `password` matches the hash in `hashed`.
258 Check if the value in `password` matches the hash in `hashed`.
259
259
260 :param password: The cleartext password.
260 :param password: The cleartext password.
261 :type password: unicode
261 :type password: unicode
262
262
263 :param hashed: The expected hashed version of the password.
263 :param hashed: The expected hashed version of the password.
264 :type hashed: The hash has to be passed in in text representation.
264 :type hashed: The hash has to be passed in in text representation.
265 """
265 """
266 password = safe_str(password)
266 password = safe_str(password)
267 return crypto_backend().hash_check(password, hashed)
267 return crypto_backend().hash_check(password, hashed)
268
268
269
269
270 def generate_auth_token(data, salt=None):
270 def generate_auth_token(data, salt=None):
271 """
271 """
272 Generates API KEY from given string
272 Generates API KEY from given string
273 """
273 """
274
274
275 if salt is None:
275 if salt is None:
276 salt = os.urandom(16)
276 salt = os.urandom(16)
277 return hashlib.sha1(safe_str(data) + salt).hexdigest()
277 return hashlib.sha1(safe_str(data) + salt).hexdigest()
278
278
279
279
280 def get_came_from(request):
280 def get_came_from(request):
281 """
281 """
282 get query_string+path from request sanitized after removing auth_token
282 get query_string+path from request sanitized after removing auth_token
283 """
283 """
284 _req = request
284 _req = request
285
285
286 path = _req.path
286 path = _req.path
287 if 'auth_token' in _req.GET:
287 if 'auth_token' in _req.GET:
288 # sanitize the request and remove auth_token for redirection
288 # sanitize the request and remove auth_token for redirection
289 _req.GET.pop('auth_token')
289 _req.GET.pop('auth_token')
290 qs = _req.query_string
290 qs = _req.query_string
291 if qs:
291 if qs:
292 path += '?' + qs
292 path += '?' + qs
293
293
294 return path
294 return path
295
295
296
296
297 class CookieStoreWrapper(object):
297 class CookieStoreWrapper(object):
298
298
299 def __init__(self, cookie_store):
299 def __init__(self, cookie_store):
300 self.cookie_store = cookie_store
300 self.cookie_store = cookie_store
301
301
302 def __repr__(self):
302 def __repr__(self):
303 return 'CookieStore<%s>' % (self.cookie_store)
303 return 'CookieStore<%s>' % (self.cookie_store)
304
304
305 def get(self, key, other=None):
305 def get(self, key, other=None):
306 if isinstance(self.cookie_store, dict):
306 if isinstance(self.cookie_store, dict):
307 return self.cookie_store.get(key, other)
307 return self.cookie_store.get(key, other)
308 elif isinstance(self.cookie_store, AuthUser):
308 elif isinstance(self.cookie_store, AuthUser):
309 return self.cookie_store.__dict__.get(key, other)
309 return self.cookie_store.__dict__.get(key, other)
310
310
311
311
312 def _cached_perms_data(user_id, scope, user_is_admin,
312 def _cached_perms_data(user_id, scope, user_is_admin,
313 user_inherit_default_permissions, explicit, algo,
313 user_inherit_default_permissions, explicit, algo,
314 calculate_super_admin):
314 calculate_super_admin):
315
315
316 permissions = PermissionCalculator(
316 permissions = PermissionCalculator(
317 user_id, scope, user_is_admin, user_inherit_default_permissions,
317 user_id, scope, user_is_admin, user_inherit_default_permissions,
318 explicit, algo, calculate_super_admin)
318 explicit, algo, calculate_super_admin)
319 return permissions.calculate()
319 return permissions.calculate()
320
320
321
321
322 class PermOrigin(object):
322 class PermOrigin(object):
323 SUPER_ADMIN = 'superadmin'
323 SUPER_ADMIN = 'superadmin'
324 ARCHIVED = 'archived'
324 ARCHIVED = 'archived'
325
325
326 REPO_USER = 'user:%s'
326 REPO_USER = 'user:%s'
327 REPO_USERGROUP = 'usergroup:%s'
327 REPO_USERGROUP = 'usergroup:%s'
328 REPO_OWNER = 'repo.owner'
328 REPO_OWNER = 'repo.owner'
329 REPO_DEFAULT = 'repo.default'
329 REPO_DEFAULT = 'repo.default'
330 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
330 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
331 REPO_PRIVATE = 'repo.private'
331 REPO_PRIVATE = 'repo.private'
332
332
333 REPOGROUP_USER = 'user:%s'
333 REPOGROUP_USER = 'user:%s'
334 REPOGROUP_USERGROUP = 'usergroup:%s'
334 REPOGROUP_USERGROUP = 'usergroup:%s'
335 REPOGROUP_OWNER = 'group.owner'
335 REPOGROUP_OWNER = 'group.owner'
336 REPOGROUP_DEFAULT = 'group.default'
336 REPOGROUP_DEFAULT = 'group.default'
337 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
337 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
338
338
339 USERGROUP_USER = 'user:%s'
339 USERGROUP_USER = 'user:%s'
340 USERGROUP_USERGROUP = 'usergroup:%s'
340 USERGROUP_USERGROUP = 'usergroup:%s'
341 USERGROUP_OWNER = 'usergroup.owner'
341 USERGROUP_OWNER = 'usergroup.owner'
342 USERGROUP_DEFAULT = 'usergroup.default'
342 USERGROUP_DEFAULT = 'usergroup.default'
343 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
343 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
344
344
345
345
346 class PermOriginDict(dict):
346 class PermOriginDict(dict):
347 """
347 """
348 A special dict used for tracking permissions along with their origins.
348 A special dict used for tracking permissions along with their origins.
349
349
350 `__setitem__` has been overridden to expect a tuple(perm, origin)
350 `__setitem__` has been overridden to expect a tuple(perm, origin)
351 `__getitem__` will return only the perm
351 `__getitem__` will return only the perm
352 `.perm_origin_stack` will return the stack of (perm, origin) set per key
352 `.perm_origin_stack` will return the stack of (perm, origin) set per key
353
353
354 >>> perms = PermOriginDict()
354 >>> perms = PermOriginDict()
355 >>> perms['resource'] = 'read', 'default'
355 >>> perms['resource'] = 'read', 'default'
356 >>> perms['resource']
356 >>> perms['resource']
357 'read'
357 'read'
358 >>> perms['resource'] = 'write', 'admin'
358 >>> perms['resource'] = 'write', 'admin'
359 >>> perms['resource']
359 >>> perms['resource']
360 'write'
360 'write'
361 >>> perms.perm_origin_stack
361 >>> perms.perm_origin_stack
362 {'resource': [('read', 'default'), ('write', 'admin')]}
362 {'resource': [('read', 'default'), ('write', 'admin')]}
363 """
363 """
364
364
365 def __init__(self, *args, **kw):
365 def __init__(self, *args, **kw):
366 dict.__init__(self, *args, **kw)
366 dict.__init__(self, *args, **kw)
367 self.perm_origin_stack = collections.OrderedDict()
367 self.perm_origin_stack = collections.OrderedDict()
368
368
369 def __setitem__(self, key, (perm, origin)):
369 def __setitem__(self, key, (perm, origin)):
370 self.perm_origin_stack.setdefault(key, []).append(
370 self.perm_origin_stack.setdefault(key, []).append(
371 (perm, origin))
371 (perm, origin))
372 dict.__setitem__(self, key, perm)
372 dict.__setitem__(self, key, perm)
373
373
374
374
375 class BranchPermOriginDict(PermOriginDict):
375 class BranchPermOriginDict(PermOriginDict):
376 """
376 """
377 Dedicated branch permissions dict, with tracking of patterns and origins.
377 Dedicated branch permissions dict, with tracking of patterns and origins.
378
378
379 >>> perms = BranchPermOriginDict()
379 >>> perms = BranchPermOriginDict()
380 >>> perms['resource'] = '*pattern', 'read', 'default'
380 >>> perms['resource'] = '*pattern', 'read', 'default'
381 >>> perms['resource']
381 >>> perms['resource']
382 {'*pattern': 'read'}
382 {'*pattern': 'read'}
383 >>> perms['resource'] = '*pattern', 'write', 'admin'
383 >>> perms['resource'] = '*pattern', 'write', 'admin'
384 >>> perms['resource']
384 >>> perms['resource']
385 {'*pattern': 'write'}
385 {'*pattern': 'write'}
386 >>> perms.perm_origin_stack
386 >>> perms.perm_origin_stack
387 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
387 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
388 """
388 """
389 def __setitem__(self, key, (pattern, perm, origin)):
389 def __setitem__(self, key, (pattern, perm, origin)):
390
390
391 self.perm_origin_stack.setdefault(key, {}) \
391 self.perm_origin_stack.setdefault(key, {}) \
392 .setdefault(pattern, []).append((perm, origin))
392 .setdefault(pattern, []).append((perm, origin))
393
393
394 if key in self:
394 if key in self:
395 self[key].__setitem__(pattern, perm)
395 self[key].__setitem__(pattern, perm)
396 else:
396 else:
397 patterns = collections.OrderedDict()
397 patterns = collections.OrderedDict()
398 patterns[pattern] = perm
398 patterns[pattern] = perm
399 dict.__setitem__(self, key, patterns)
399 dict.__setitem__(self, key, patterns)
400
400
401
401
402 class PermissionCalculator(object):
402 class PermissionCalculator(object):
403
403
404 def __init__(
404 def __init__(
405 self, user_id, scope, user_is_admin,
405 self, user_id, scope, user_is_admin,
406 user_inherit_default_permissions, explicit, algo,
406 user_inherit_default_permissions, explicit, algo,
407 calculate_super_admin_as_user=False):
407 calculate_super_admin_as_user=False):
408
408
409 self.user_id = user_id
409 self.user_id = user_id
410 self.user_is_admin = user_is_admin
410 self.user_is_admin = user_is_admin
411 self.inherit_default_permissions = user_inherit_default_permissions
411 self.inherit_default_permissions = user_inherit_default_permissions
412 self.explicit = explicit
412 self.explicit = explicit
413 self.algo = algo
413 self.algo = algo
414 self.calculate_super_admin_as_user = calculate_super_admin_as_user
414 self.calculate_super_admin_as_user = calculate_super_admin_as_user
415
415
416 scope = scope or {}
416 scope = scope or {}
417 self.scope_repo_id = scope.get('repo_id')
417 self.scope_repo_id = scope.get('repo_id')
418 self.scope_repo_group_id = scope.get('repo_group_id')
418 self.scope_repo_group_id = scope.get('repo_group_id')
419 self.scope_user_group_id = scope.get('user_group_id')
419 self.scope_user_group_id = scope.get('user_group_id')
420
420
421 self.default_user_id = User.get_default_user(cache=True).user_id
421 self.default_user_id = User.get_default_user(cache=True).user_id
422
422
423 self.permissions_repositories = PermOriginDict()
423 self.permissions_repositories = PermOriginDict()
424 self.permissions_repository_groups = PermOriginDict()
424 self.permissions_repository_groups = PermOriginDict()
425 self.permissions_user_groups = PermOriginDict()
425 self.permissions_user_groups = PermOriginDict()
426 self.permissions_repository_branches = BranchPermOriginDict()
426 self.permissions_repository_branches = BranchPermOriginDict()
427 self.permissions_global = set()
427 self.permissions_global = set()
428
428
429 self.default_repo_perms = Permission.get_default_repo_perms(
429 self.default_repo_perms = Permission.get_default_repo_perms(
430 self.default_user_id, self.scope_repo_id)
430 self.default_user_id, self.scope_repo_id)
431 self.default_repo_groups_perms = Permission.get_default_group_perms(
431 self.default_repo_groups_perms = Permission.get_default_group_perms(
432 self.default_user_id, self.scope_repo_group_id)
432 self.default_user_id, self.scope_repo_group_id)
433 self.default_user_group_perms = \
433 self.default_user_group_perms = \
434 Permission.get_default_user_group_perms(
434 Permission.get_default_user_group_perms(
435 self.default_user_id, self.scope_user_group_id)
435 self.default_user_id, self.scope_user_group_id)
436
436
437 # default branch perms
437 # default branch perms
438 self.default_branch_repo_perms = \
438 self.default_branch_repo_perms = \
439 Permission.get_default_repo_branch_perms(
439 Permission.get_default_repo_branch_perms(
440 self.default_user_id, self.scope_repo_id)
440 self.default_user_id, self.scope_repo_id)
441
441
442 def calculate(self):
442 def calculate(self):
443 if self.user_is_admin and not self.calculate_super_admin_as_user:
443 if self.user_is_admin and not self.calculate_super_admin_as_user:
444 return self._calculate_admin_permissions()
444 return self._calculate_admin_permissions()
445
445
446 self._calculate_global_default_permissions()
446 self._calculate_global_default_permissions()
447 self._calculate_global_permissions()
447 self._calculate_global_permissions()
448 self._calculate_default_permissions()
448 self._calculate_default_permissions()
449 self._calculate_repository_permissions()
449 self._calculate_repository_permissions()
450 self._calculate_repository_branch_permissions()
450 self._calculate_repository_branch_permissions()
451 self._calculate_repository_group_permissions()
451 self._calculate_repository_group_permissions()
452 self._calculate_user_group_permissions()
452 self._calculate_user_group_permissions()
453 return self._permission_structure()
453 return self._permission_structure()
454
454
455 def _calculate_admin_permissions(self):
455 def _calculate_admin_permissions(self):
456 """
456 """
457 admin user have all default rights for repositories
457 admin user have all default rights for repositories
458 and groups set to admin
458 and groups set to admin
459 """
459 """
460 self.permissions_global.add('hg.admin')
460 self.permissions_global.add('hg.admin')
461 self.permissions_global.add('hg.create.write_on_repogroup.true')
461 self.permissions_global.add('hg.create.write_on_repogroup.true')
462
462
463 # repositories
463 # repositories
464 for perm in self.default_repo_perms:
464 for perm in self.default_repo_perms:
465 r_k = perm.UserRepoToPerm.repository.repo_name
465 r_k = perm.UserRepoToPerm.repository.repo_name
466 archived = perm.UserRepoToPerm.repository.archived
466 archived = perm.UserRepoToPerm.repository.archived
467 p = 'repository.admin'
467 p = 'repository.admin'
468 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN
468 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN
469 # special case for archived repositories, which we block still even for
469 # special case for archived repositories, which we block still even for
470 # super admins
470 # super admins
471 if archived:
471 if archived:
472 p = 'repository.read'
472 p = 'repository.read'
473 self.permissions_repositories[r_k] = p, PermOrigin.ARCHIVED
473 self.permissions_repositories[r_k] = p, PermOrigin.ARCHIVED
474
474
475 # repository groups
475 # repository groups
476 for perm in self.default_repo_groups_perms:
476 for perm in self.default_repo_groups_perms:
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
478 p = 'group.admin'
478 p = 'group.admin'
479 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN
479 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN
480
480
481 # user groups
481 # user groups
482 for perm in self.default_user_group_perms:
482 for perm in self.default_user_group_perms:
483 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
483 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
484 p = 'usergroup.admin'
484 p = 'usergroup.admin'
485 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
485 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
486
486
487 # branch permissions
487 # branch permissions
488 # since super-admin also can have custom rule permissions
488 # since super-admin also can have custom rule permissions
489 # we *always* need to calculate those inherited from default, and also explicit
489 # we *always* need to calculate those inherited from default, and also explicit
490 self._calculate_default_permissions_repository_branches(
490 self._calculate_default_permissions_repository_branches(
491 user_inherit_object_permissions=False)
491 user_inherit_object_permissions=False)
492 self._calculate_repository_branch_permissions()
492 self._calculate_repository_branch_permissions()
493
493
494 return self._permission_structure()
494 return self._permission_structure()
495
495
496 def _calculate_global_default_permissions(self):
496 def _calculate_global_default_permissions(self):
497 """
497 """
498 global permissions taken from the default user
498 global permissions taken from the default user
499 """
499 """
500 default_global_perms = UserToPerm.query()\
500 default_global_perms = UserToPerm.query()\
501 .filter(UserToPerm.user_id == self.default_user_id)\
501 .filter(UserToPerm.user_id == self.default_user_id)\
502 .options(joinedload(UserToPerm.permission))
502 .options(joinedload(UserToPerm.permission))
503
503
504 for perm in default_global_perms:
504 for perm in default_global_perms:
505 self.permissions_global.add(perm.permission.permission_name)
505 self.permissions_global.add(perm.permission.permission_name)
506
506
507 if self.user_is_admin:
507 if self.user_is_admin:
508 self.permissions_global.add('hg.admin')
508 self.permissions_global.add('hg.admin')
509 self.permissions_global.add('hg.create.write_on_repogroup.true')
509 self.permissions_global.add('hg.create.write_on_repogroup.true')
510
510
511 def _calculate_global_permissions(self):
511 def _calculate_global_permissions(self):
512 """
512 """
513 Set global system permissions with user permissions or permissions
513 Set global system permissions with user permissions or permissions
514 taken from the user groups of the current user.
514 taken from the user groups of the current user.
515
515
516 The permissions include repo creating, repo group creating, forking
516 The permissions include repo creating, repo group creating, forking
517 etc.
517 etc.
518 """
518 """
519
519
520 # now we read the defined permissions and overwrite what we have set
520 # now we read the defined permissions and overwrite what we have set
521 # before those can be configured from groups or users explicitly.
521 # before those can be configured from groups or users explicitly.
522
522
523 # In case we want to extend this list we should make sure
523 # In case we want to extend this list we should make sure
524 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
524 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
525 _configurable = frozenset([
525 _configurable = frozenset([
526 'hg.fork.none', 'hg.fork.repository',
526 'hg.fork.none', 'hg.fork.repository',
527 'hg.create.none', 'hg.create.repository',
527 'hg.create.none', 'hg.create.repository',
528 'hg.usergroup.create.false', 'hg.usergroup.create.true',
528 'hg.usergroup.create.false', 'hg.usergroup.create.true',
529 'hg.repogroup.create.false', 'hg.repogroup.create.true',
529 'hg.repogroup.create.false', 'hg.repogroup.create.true',
530 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
530 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
531 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
531 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
532 ])
532 ])
533
533
534 # USER GROUPS comes first user group global permissions
534 # USER GROUPS comes first user group global permissions
535 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
535 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
536 .options(joinedload(UserGroupToPerm.permission))\
536 .options(joinedload(UserGroupToPerm.permission))\
537 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
537 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
538 UserGroupMember.users_group_id))\
538 UserGroupMember.users_group_id))\
539 .filter(UserGroupMember.user_id == self.user_id)\
539 .filter(UserGroupMember.user_id == self.user_id)\
540 .order_by(UserGroupToPerm.users_group_id)\
540 .order_by(UserGroupToPerm.users_group_id)\
541 .all()
541 .all()
542
542
543 # need to group here by groups since user can be in more than
543 # need to group here by groups since user can be in more than
544 # one group, so we get all groups
544 # one group, so we get all groups
545 _explicit_grouped_perms = [
545 _explicit_grouped_perms = [
546 [x, list(y)] for x, y in
546 [x, list(y)] for x, y in
547 itertools.groupby(user_perms_from_users_groups,
547 itertools.groupby(user_perms_from_users_groups,
548 lambda _x: _x.users_group)]
548 lambda _x: _x.users_group)]
549
549
550 for gr, perms in _explicit_grouped_perms:
550 for gr, perms in _explicit_grouped_perms:
551 # since user can be in multiple groups iterate over them and
551 # since user can be in multiple groups iterate over them and
552 # select the lowest permissions first (more explicit)
552 # select the lowest permissions first (more explicit)
553 # TODO(marcink): do this^^
553 # TODO(marcink): do this^^
554
554
555 # group doesn't inherit default permissions so we actually set them
555 # group doesn't inherit default permissions so we actually set them
556 if not gr.inherit_default_permissions:
556 if not gr.inherit_default_permissions:
557 # NEED TO IGNORE all previously set configurable permissions
557 # NEED TO IGNORE all previously set configurable permissions
558 # and replace them with explicitly set from this user
558 # and replace them with explicitly set from this user
559 # group permissions
559 # group permissions
560 self.permissions_global = self.permissions_global.difference(
560 self.permissions_global = self.permissions_global.difference(
561 _configurable)
561 _configurable)
562 for perm in perms:
562 for perm in perms:
563 self.permissions_global.add(perm.permission.permission_name)
563 self.permissions_global.add(perm.permission.permission_name)
564
564
565 # user explicit global permissions
565 # user explicit global permissions
566 user_perms = Session().query(UserToPerm)\
566 user_perms = Session().query(UserToPerm)\
567 .options(joinedload(UserToPerm.permission))\
567 .options(joinedload(UserToPerm.permission))\
568 .filter(UserToPerm.user_id == self.user_id).all()
568 .filter(UserToPerm.user_id == self.user_id).all()
569
569
570 if not self.inherit_default_permissions:
570 if not self.inherit_default_permissions:
571 # NEED TO IGNORE all configurable permissions and
571 # NEED TO IGNORE all configurable permissions and
572 # replace them with explicitly set from this user permissions
572 # replace them with explicitly set from this user permissions
573 self.permissions_global = self.permissions_global.difference(
573 self.permissions_global = self.permissions_global.difference(
574 _configurable)
574 _configurable)
575 for perm in user_perms:
575 for perm in user_perms:
576 self.permissions_global.add(perm.permission.permission_name)
576 self.permissions_global.add(perm.permission.permission_name)
577
577
578 def _calculate_default_permissions_repositories(self, user_inherit_object_permissions):
578 def _calculate_default_permissions_repositories(self, user_inherit_object_permissions):
579 for perm in self.default_repo_perms:
579 for perm in self.default_repo_perms:
580 r_k = perm.UserRepoToPerm.repository.repo_name
580 r_k = perm.UserRepoToPerm.repository.repo_name
581 archived = perm.UserRepoToPerm.repository.archived
581 archived = perm.UserRepoToPerm.repository.archived
582 p = perm.Permission.permission_name
582 p = perm.Permission.permission_name
583 o = PermOrigin.REPO_DEFAULT
583 o = PermOrigin.REPO_DEFAULT
584 self.permissions_repositories[r_k] = p, o
584 self.permissions_repositories[r_k] = p, o
585
585
586 # if we decide this user isn't inheriting permissions from
586 # if we decide this user isn't inheriting permissions from
587 # default user we set him to .none so only explicit
587 # default user we set him to .none so only explicit
588 # permissions work
588 # permissions work
589 if not user_inherit_object_permissions:
589 if not user_inherit_object_permissions:
590 p = 'repository.none'
590 p = 'repository.none'
591 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
591 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
592 self.permissions_repositories[r_k] = p, o
592 self.permissions_repositories[r_k] = p, o
593
593
594 if perm.Repository.private and not (
594 if perm.Repository.private and not (
595 perm.Repository.user_id == self.user_id):
595 perm.Repository.user_id == self.user_id):
596 # disable defaults for private repos,
596 # disable defaults for private repos,
597 p = 'repository.none'
597 p = 'repository.none'
598 o = PermOrigin.REPO_PRIVATE
598 o = PermOrigin.REPO_PRIVATE
599 self.permissions_repositories[r_k] = p, o
599 self.permissions_repositories[r_k] = p, o
600
600
601 elif perm.Repository.user_id == self.user_id:
601 elif perm.Repository.user_id == self.user_id:
602 # set admin if owner
602 # set admin if owner
603 p = 'repository.admin'
603 p = 'repository.admin'
604 o = PermOrigin.REPO_OWNER
604 o = PermOrigin.REPO_OWNER
605 self.permissions_repositories[r_k] = p, o
605 self.permissions_repositories[r_k] = p, o
606
606
607 if self.user_is_admin:
607 if self.user_is_admin:
608 p = 'repository.admin'
608 p = 'repository.admin'
609 o = PermOrigin.SUPER_ADMIN
609 o = PermOrigin.SUPER_ADMIN
610 self.permissions_repositories[r_k] = p, o
610 self.permissions_repositories[r_k] = p, o
611
611
612 # finally in case of archived repositories, we downgrade higher
612 # finally in case of archived repositories, we downgrade higher
613 # permissions to read
613 # permissions to read
614 if archived:
614 if archived:
615 current_perm = self.permissions_repositories[r_k]
615 current_perm = self.permissions_repositories[r_k]
616 if current_perm in ['repository.write', 'repository.admin']:
616 if current_perm in ['repository.write', 'repository.admin']:
617 p = 'repository.read'
617 p = 'repository.read'
618 o = PermOrigin.ARCHIVED
618 o = PermOrigin.ARCHIVED
619 self.permissions_repositories[r_k] = p, o
619 self.permissions_repositories[r_k] = p, o
620
620
621 def _calculate_default_permissions_repository_branches(self, user_inherit_object_permissions):
621 def _calculate_default_permissions_repository_branches(self, user_inherit_object_permissions):
622 for perm in self.default_branch_repo_perms:
622 for perm in self.default_branch_repo_perms:
623
623
624 r_k = perm.UserRepoToPerm.repository.repo_name
624 r_k = perm.UserRepoToPerm.repository.repo_name
625 p = perm.Permission.permission_name
625 p = perm.Permission.permission_name
626 pattern = perm.UserToRepoBranchPermission.branch_pattern
626 pattern = perm.UserToRepoBranchPermission.branch_pattern
627 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
627 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
628
628
629 if not self.explicit:
629 if not self.explicit:
630 cur_perm = self.permissions_repository_branches.get(r_k)
630 cur_perm = self.permissions_repository_branches.get(r_k)
631 if cur_perm:
631 if cur_perm:
632 cur_perm = cur_perm[pattern]
632 cur_perm = cur_perm[pattern]
633 cur_perm = cur_perm or 'branch.none'
633 cur_perm = cur_perm or 'branch.none'
634
634
635 p = self._choose_permission(p, cur_perm)
635 p = self._choose_permission(p, cur_perm)
636
636
637 # NOTE(marcink): register all pattern/perm instances in this
637 # NOTE(marcink): register all pattern/perm instances in this
638 # special dict that aggregates entries
638 # special dict that aggregates entries
639 self.permissions_repository_branches[r_k] = pattern, p, o
639 self.permissions_repository_branches[r_k] = pattern, p, o
640
640
641 def _calculate_default_permissions_repository_groups(self, user_inherit_object_permissions):
641 def _calculate_default_permissions_repository_groups(self, user_inherit_object_permissions):
642 for perm in self.default_repo_groups_perms:
642 for perm in self.default_repo_groups_perms:
643 rg_k = perm.UserRepoGroupToPerm.group.group_name
643 rg_k = perm.UserRepoGroupToPerm.group.group_name
644 p = perm.Permission.permission_name
644 p = perm.Permission.permission_name
645 o = PermOrigin.REPOGROUP_DEFAULT
645 o = PermOrigin.REPOGROUP_DEFAULT
646 self.permissions_repository_groups[rg_k] = p, o
646 self.permissions_repository_groups[rg_k] = p, o
647
647
648 # if we decide this user isn't inheriting permissions from default
648 # if we decide this user isn't inheriting permissions from default
649 # user we set him to .none so only explicit permissions work
649 # user we set him to .none so only explicit permissions work
650 if not user_inherit_object_permissions:
650 if not user_inherit_object_permissions:
651 p = 'group.none'
651 p = 'group.none'
652 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
652 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
653 self.permissions_repository_groups[rg_k] = p, o
653 self.permissions_repository_groups[rg_k] = p, o
654
654
655 if perm.RepoGroup.user_id == self.user_id:
655 if perm.RepoGroup.user_id == self.user_id:
656 # set admin if owner
656 # set admin if owner
657 p = 'group.admin'
657 p = 'group.admin'
658 o = PermOrigin.REPOGROUP_OWNER
658 o = PermOrigin.REPOGROUP_OWNER
659 self.permissions_repository_groups[rg_k] = p, o
659 self.permissions_repository_groups[rg_k] = p, o
660
660
661 if self.user_is_admin:
661 if self.user_is_admin:
662 p = 'group.admin'
662 p = 'group.admin'
663 o = PermOrigin.SUPER_ADMIN
663 o = PermOrigin.SUPER_ADMIN
664 self.permissions_repository_groups[rg_k] = p, o
664 self.permissions_repository_groups[rg_k] = p, o
665
665
666 def _calculate_default_permissions_user_groups(self, user_inherit_object_permissions):
666 def _calculate_default_permissions_user_groups(self, user_inherit_object_permissions):
667 for perm in self.default_user_group_perms:
667 for perm in self.default_user_group_perms:
668 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
668 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
669 p = perm.Permission.permission_name
669 p = perm.Permission.permission_name
670 o = PermOrigin.USERGROUP_DEFAULT
670 o = PermOrigin.USERGROUP_DEFAULT
671 self.permissions_user_groups[u_k] = p, o
671 self.permissions_user_groups[u_k] = p, o
672
672
673 # if we decide this user isn't inheriting permissions from default
673 # if we decide this user isn't inheriting permissions from default
674 # user we set him to .none so only explicit permissions work
674 # user we set him to .none so only explicit permissions work
675 if not user_inherit_object_permissions:
675 if not user_inherit_object_permissions:
676 p = 'usergroup.none'
676 p = 'usergroup.none'
677 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
677 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
678 self.permissions_user_groups[u_k] = p, o
678 self.permissions_user_groups[u_k] = p, o
679
679
680 if perm.UserGroup.user_id == self.user_id:
680 if perm.UserGroup.user_id == self.user_id:
681 # set admin if owner
681 # set admin if owner
682 p = 'usergroup.admin'
682 p = 'usergroup.admin'
683 o = PermOrigin.USERGROUP_OWNER
683 o = PermOrigin.USERGROUP_OWNER
684 self.permissions_user_groups[u_k] = p, o
684 self.permissions_user_groups[u_k] = p, o
685
685
686 if self.user_is_admin:
686 if self.user_is_admin:
687 p = 'usergroup.admin'
687 p = 'usergroup.admin'
688 o = PermOrigin.SUPER_ADMIN
688 o = PermOrigin.SUPER_ADMIN
689 self.permissions_user_groups[u_k] = p, o
689 self.permissions_user_groups[u_k] = p, o
690
690
691 def _calculate_default_permissions(self):
691 def _calculate_default_permissions(self):
692 """
692 """
693 Set default user permissions for repositories, repository branches,
693 Set default user permissions for repositories, repository branches,
694 repository groups, user groups taken from the default user.
694 repository groups, user groups taken from the default user.
695
695
696 Calculate inheritance of object permissions based on what we have now
696 Calculate inheritance of object permissions based on what we have now
697 in GLOBAL permissions. We check if .false is in GLOBAL since this is
697 in GLOBAL permissions. We check if .false is in GLOBAL since this is
698 explicitly set. Inherit is the opposite of .false being there.
698 explicitly set. Inherit is the opposite of .false being there.
699
699
700 .. note::
700 .. note::
701
701
702 the syntax is little bit odd but what we need to check here is
702 the syntax is little bit odd but what we need to check here is
703 the opposite of .false permission being in the list so even for
703 the opposite of .false permission being in the list so even for
704 inconsistent state when both .true/.false is there
704 inconsistent state when both .true/.false is there
705 .false is more important
705 .false is more important
706
706
707 """
707 """
708 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
708 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
709 in self.permissions_global)
709 in self.permissions_global)
710
710
711 # default permissions inherited from `default` user permissions
711 # default permissions inherited from `default` user permissions
712 self._calculate_default_permissions_repositories(
712 self._calculate_default_permissions_repositories(
713 user_inherit_object_permissions)
713 user_inherit_object_permissions)
714
714
715 self._calculate_default_permissions_repository_branches(
715 self._calculate_default_permissions_repository_branches(
716 user_inherit_object_permissions)
716 user_inherit_object_permissions)
717
717
718 self._calculate_default_permissions_repository_groups(
718 self._calculate_default_permissions_repository_groups(
719 user_inherit_object_permissions)
719 user_inherit_object_permissions)
720
720
721 self._calculate_default_permissions_user_groups(
721 self._calculate_default_permissions_user_groups(
722 user_inherit_object_permissions)
722 user_inherit_object_permissions)
723
723
724 def _calculate_repository_permissions(self):
724 def _calculate_repository_permissions(self):
725 """
725 """
726 Repository access permissions for the current user.
726 Repository access permissions for the current user.
727
727
728 Check if the user is part of user groups for this repository and
728 Check if the user is part of user groups for this repository and
729 fill in the permission from it. `_choose_permission` decides of which
729 fill in the permission from it. `_choose_permission` decides of which
730 permission should be selected based on selected method.
730 permission should be selected based on selected method.
731 """
731 """
732
732
733 # user group for repositories permissions
733 # user group for repositories permissions
734 user_repo_perms_from_user_group = Permission\
734 user_repo_perms_from_user_group = Permission\
735 .get_default_repo_perms_from_user_group(
735 .get_default_repo_perms_from_user_group(
736 self.user_id, self.scope_repo_id)
736 self.user_id, self.scope_repo_id)
737
737
738 multiple_counter = collections.defaultdict(int)
738 multiple_counter = collections.defaultdict(int)
739 for perm in user_repo_perms_from_user_group:
739 for perm in user_repo_perms_from_user_group:
740 r_k = perm.UserGroupRepoToPerm.repository.repo_name
740 r_k = perm.UserGroupRepoToPerm.repository.repo_name
741 multiple_counter[r_k] += 1
741 multiple_counter[r_k] += 1
742 p = perm.Permission.permission_name
742 p = perm.Permission.permission_name
743 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
743 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
744 .users_group.users_group_name
744 .users_group.users_group_name
745
745
746 if multiple_counter[r_k] > 1:
746 if multiple_counter[r_k] > 1:
747 cur_perm = self.permissions_repositories[r_k]
747 cur_perm = self.permissions_repositories[r_k]
748 p = self._choose_permission(p, cur_perm)
748 p = self._choose_permission(p, cur_perm)
749
749
750 self.permissions_repositories[r_k] = p, o
750 self.permissions_repositories[r_k] = p, o
751
751
752 if perm.Repository.user_id == self.user_id:
752 if perm.Repository.user_id == self.user_id:
753 # set admin if owner
753 # set admin if owner
754 p = 'repository.admin'
754 p = 'repository.admin'
755 o = PermOrigin.REPO_OWNER
755 o = PermOrigin.REPO_OWNER
756 self.permissions_repositories[r_k] = p, o
756 self.permissions_repositories[r_k] = p, o
757
757
758 if self.user_is_admin:
758 if self.user_is_admin:
759 p = 'repository.admin'
759 p = 'repository.admin'
760 o = PermOrigin.SUPER_ADMIN
760 o = PermOrigin.SUPER_ADMIN
761 self.permissions_repositories[r_k] = p, o
761 self.permissions_repositories[r_k] = p, o
762
762
763 # user explicit permissions for repositories, overrides any specified
763 # user explicit permissions for repositories, overrides any specified
764 # by the group permission
764 # by the group permission
765 user_repo_perms = Permission.get_default_repo_perms(
765 user_repo_perms = Permission.get_default_repo_perms(
766 self.user_id, self.scope_repo_id)
766 self.user_id, self.scope_repo_id)
767 for perm in user_repo_perms:
767 for perm in user_repo_perms:
768 r_k = perm.UserRepoToPerm.repository.repo_name
768 r_k = perm.UserRepoToPerm.repository.repo_name
769 p = perm.Permission.permission_name
769 p = perm.Permission.permission_name
770 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
770 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
771
771
772 if not self.explicit:
772 if not self.explicit:
773 cur_perm = self.permissions_repositories.get(
773 cur_perm = self.permissions_repositories.get(
774 r_k, 'repository.none')
774 r_k, 'repository.none')
775 p = self._choose_permission(p, cur_perm)
775 p = self._choose_permission(p, cur_perm)
776
776
777 self.permissions_repositories[r_k] = p, o
777 self.permissions_repositories[r_k] = p, o
778
778
779 if perm.Repository.user_id == self.user_id:
779 if perm.Repository.user_id == self.user_id:
780 # set admin if owner
780 # set admin if owner
781 p = 'repository.admin'
781 p = 'repository.admin'
782 o = PermOrigin.REPO_OWNER
782 o = PermOrigin.REPO_OWNER
783 self.permissions_repositories[r_k] = p, o
783 self.permissions_repositories[r_k] = p, o
784
784
785 if self.user_is_admin:
785 if self.user_is_admin:
786 p = 'repository.admin'
786 p = 'repository.admin'
787 o = PermOrigin.SUPER_ADMIN
787 o = PermOrigin.SUPER_ADMIN
788 self.permissions_repositories[r_k] = p, o
788 self.permissions_repositories[r_k] = p, o
789
789
790 def _calculate_repository_branch_permissions(self):
790 def _calculate_repository_branch_permissions(self):
791 # user group for repositories permissions
791 # user group for repositories permissions
792 user_repo_branch_perms_from_user_group = Permission\
792 user_repo_branch_perms_from_user_group = Permission\
793 .get_default_repo_branch_perms_from_user_group(
793 .get_default_repo_branch_perms_from_user_group(
794 self.user_id, self.scope_repo_id)
794 self.user_id, self.scope_repo_id)
795
795
796 multiple_counter = collections.defaultdict(int)
796 multiple_counter = collections.defaultdict(int)
797 for perm in user_repo_branch_perms_from_user_group:
797 for perm in user_repo_branch_perms_from_user_group:
798 r_k = perm.UserGroupRepoToPerm.repository.repo_name
798 r_k = perm.UserGroupRepoToPerm.repository.repo_name
799 p = perm.Permission.permission_name
799 p = perm.Permission.permission_name
800 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
800 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
801 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
801 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
802 .users_group.users_group_name
802 .users_group.users_group_name
803
803
804 multiple_counter[r_k] += 1
804 multiple_counter[r_k] += 1
805 if multiple_counter[r_k] > 1:
805 if multiple_counter[r_k] > 1:
806 cur_perm = self.permissions_repository_branches[r_k][pattern]
806 cur_perm = self.permissions_repository_branches[r_k][pattern]
807 p = self._choose_permission(p, cur_perm)
807 p = self._choose_permission(p, cur_perm)
808
808
809 self.permissions_repository_branches[r_k] = pattern, p, o
809 self.permissions_repository_branches[r_k] = pattern, p, o
810
810
811 # user explicit branch permissions for repositories, overrides
811 # user explicit branch permissions for repositories, overrides
812 # any specified by the group permission
812 # any specified by the group permission
813 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
813 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
814 self.user_id, self.scope_repo_id)
814 self.user_id, self.scope_repo_id)
815
815
816 for perm in user_repo_branch_perms:
816 for perm in user_repo_branch_perms:
817
817
818 r_k = perm.UserRepoToPerm.repository.repo_name
818 r_k = perm.UserRepoToPerm.repository.repo_name
819 p = perm.Permission.permission_name
819 p = perm.Permission.permission_name
820 pattern = perm.UserToRepoBranchPermission.branch_pattern
820 pattern = perm.UserToRepoBranchPermission.branch_pattern
821 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
821 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
822
822
823 if not self.explicit:
823 if not self.explicit:
824 cur_perm = self.permissions_repository_branches.get(r_k)
824 cur_perm = self.permissions_repository_branches.get(r_k)
825 if cur_perm:
825 if cur_perm:
826 cur_perm = cur_perm[pattern]
826 cur_perm = cur_perm[pattern]
827 cur_perm = cur_perm or 'branch.none'
827 cur_perm = cur_perm or 'branch.none'
828 p = self._choose_permission(p, cur_perm)
828 p = self._choose_permission(p, cur_perm)
829
829
830 # NOTE(marcink): register all pattern/perm instances in this
830 # NOTE(marcink): register all pattern/perm instances in this
831 # special dict that aggregates entries
831 # special dict that aggregates entries
832 self.permissions_repository_branches[r_k] = pattern, p, o
832 self.permissions_repository_branches[r_k] = pattern, p, o
833
833
834 def _calculate_repository_group_permissions(self):
834 def _calculate_repository_group_permissions(self):
835 """
835 """
836 Repository group permissions for the current user.
836 Repository group permissions for the current user.
837
837
838 Check if the user is part of user groups for repository groups and
838 Check if the user is part of user groups for repository groups and
839 fill in the permissions from it. `_choose_permission` decides of which
839 fill in the permissions from it. `_choose_permission` decides of which
840 permission should be selected based on selected method.
840 permission should be selected based on selected method.
841 """
841 """
842 # user group for repo groups permissions
842 # user group for repo groups permissions
843 user_repo_group_perms_from_user_group = Permission\
843 user_repo_group_perms_from_user_group = Permission\
844 .get_default_group_perms_from_user_group(
844 .get_default_group_perms_from_user_group(
845 self.user_id, self.scope_repo_group_id)
845 self.user_id, self.scope_repo_group_id)
846
846
847 multiple_counter = collections.defaultdict(int)
847 multiple_counter = collections.defaultdict(int)
848 for perm in user_repo_group_perms_from_user_group:
848 for perm in user_repo_group_perms_from_user_group:
849 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
849 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
850 multiple_counter[rg_k] += 1
850 multiple_counter[rg_k] += 1
851 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
851 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
852 .users_group.users_group_name
852 .users_group.users_group_name
853 p = perm.Permission.permission_name
853 p = perm.Permission.permission_name
854
854
855 if multiple_counter[rg_k] > 1:
855 if multiple_counter[rg_k] > 1:
856 cur_perm = self.permissions_repository_groups[rg_k]
856 cur_perm = self.permissions_repository_groups[rg_k]
857 p = self._choose_permission(p, cur_perm)
857 p = self._choose_permission(p, cur_perm)
858 self.permissions_repository_groups[rg_k] = p, o
858 self.permissions_repository_groups[rg_k] = p, o
859
859
860 if perm.RepoGroup.user_id == self.user_id:
860 if perm.RepoGroup.user_id == self.user_id:
861 # set admin if owner, even for member of other user group
861 # set admin if owner, even for member of other user group
862 p = 'group.admin'
862 p = 'group.admin'
863 o = PermOrigin.REPOGROUP_OWNER
863 o = PermOrigin.REPOGROUP_OWNER
864 self.permissions_repository_groups[rg_k] = p, o
864 self.permissions_repository_groups[rg_k] = p, o
865
865
866 if self.user_is_admin:
866 if self.user_is_admin:
867 p = 'group.admin'
867 p = 'group.admin'
868 o = PermOrigin.SUPER_ADMIN
868 o = PermOrigin.SUPER_ADMIN
869 self.permissions_repository_groups[rg_k] = p, o
869 self.permissions_repository_groups[rg_k] = p, o
870
870
871 # user explicit permissions for repository groups
871 # user explicit permissions for repository groups
872 user_repo_groups_perms = Permission.get_default_group_perms(
872 user_repo_groups_perms = Permission.get_default_group_perms(
873 self.user_id, self.scope_repo_group_id)
873 self.user_id, self.scope_repo_group_id)
874 for perm in user_repo_groups_perms:
874 for perm in user_repo_groups_perms:
875 rg_k = perm.UserRepoGroupToPerm.group.group_name
875 rg_k = perm.UserRepoGroupToPerm.group.group_name
876 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
876 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
877 .user.username
877 .user.username
878 p = perm.Permission.permission_name
878 p = perm.Permission.permission_name
879
879
880 if not self.explicit:
880 if not self.explicit:
881 cur_perm = self.permissions_repository_groups.get(rg_k, 'group.none')
881 cur_perm = self.permissions_repository_groups.get(rg_k, 'group.none')
882 p = self._choose_permission(p, cur_perm)
882 p = self._choose_permission(p, cur_perm)
883
883
884 self.permissions_repository_groups[rg_k] = p, o
884 self.permissions_repository_groups[rg_k] = p, o
885
885
886 if perm.RepoGroup.user_id == self.user_id:
886 if perm.RepoGroup.user_id == self.user_id:
887 # set admin if owner
887 # set admin if owner
888 p = 'group.admin'
888 p = 'group.admin'
889 o = PermOrigin.REPOGROUP_OWNER
889 o = PermOrigin.REPOGROUP_OWNER
890 self.permissions_repository_groups[rg_k] = p, o
890 self.permissions_repository_groups[rg_k] = p, o
891
891
892 if self.user_is_admin:
892 if self.user_is_admin:
893 p = 'group.admin'
893 p = 'group.admin'
894 o = PermOrigin.SUPER_ADMIN
894 o = PermOrigin.SUPER_ADMIN
895 self.permissions_repository_groups[rg_k] = p, o
895 self.permissions_repository_groups[rg_k] = p, o
896
896
897 def _calculate_user_group_permissions(self):
897 def _calculate_user_group_permissions(self):
898 """
898 """
899 User group permissions for the current user.
899 User group permissions for the current user.
900 """
900 """
901 # user group for user group permissions
901 # user group for user group permissions
902 user_group_from_user_group = Permission\
902 user_group_from_user_group = Permission\
903 .get_default_user_group_perms_from_user_group(
903 .get_default_user_group_perms_from_user_group(
904 self.user_id, self.scope_user_group_id)
904 self.user_id, self.scope_user_group_id)
905
905
906 multiple_counter = collections.defaultdict(int)
906 multiple_counter = collections.defaultdict(int)
907 for perm in user_group_from_user_group:
907 for perm in user_group_from_user_group:
908 ug_k = perm.UserGroupUserGroupToPerm\
908 ug_k = perm.UserGroupUserGroupToPerm\
909 .target_user_group.users_group_name
909 .target_user_group.users_group_name
910 multiple_counter[ug_k] += 1
910 multiple_counter[ug_k] += 1
911 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
911 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
912 .user_group.users_group_name
912 .user_group.users_group_name
913 p = perm.Permission.permission_name
913 p = perm.Permission.permission_name
914
914
915 if multiple_counter[ug_k] > 1:
915 if multiple_counter[ug_k] > 1:
916 cur_perm = self.permissions_user_groups[ug_k]
916 cur_perm = self.permissions_user_groups[ug_k]
917 p = self._choose_permission(p, cur_perm)
917 p = self._choose_permission(p, cur_perm)
918
918
919 self.permissions_user_groups[ug_k] = p, o
919 self.permissions_user_groups[ug_k] = p, o
920
920
921 if perm.UserGroup.user_id == self.user_id:
921 if perm.UserGroup.user_id == self.user_id:
922 # set admin if owner, even for member of other user group
922 # set admin if owner, even for member of other user group
923 p = 'usergroup.admin'
923 p = 'usergroup.admin'
924 o = PermOrigin.USERGROUP_OWNER
924 o = PermOrigin.USERGROUP_OWNER
925 self.permissions_user_groups[ug_k] = p, o
925 self.permissions_user_groups[ug_k] = p, o
926
926
927 if self.user_is_admin:
927 if self.user_is_admin:
928 p = 'usergroup.admin'
928 p = 'usergroup.admin'
929 o = PermOrigin.SUPER_ADMIN
929 o = PermOrigin.SUPER_ADMIN
930 self.permissions_user_groups[ug_k] = p, o
930 self.permissions_user_groups[ug_k] = p, o
931
931
932 # user explicit permission for user groups
932 # user explicit permission for user groups
933 user_user_groups_perms = Permission.get_default_user_group_perms(
933 user_user_groups_perms = Permission.get_default_user_group_perms(
934 self.user_id, self.scope_user_group_id)
934 self.user_id, self.scope_user_group_id)
935 for perm in user_user_groups_perms:
935 for perm in user_user_groups_perms:
936 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
936 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
937 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
937 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
938 .user.username
938 .user.username
939 p = perm.Permission.permission_name
939 p = perm.Permission.permission_name
940
940
941 if not self.explicit:
941 if not self.explicit:
942 cur_perm = self.permissions_user_groups.get(ug_k, 'usergroup.none')
942 cur_perm = self.permissions_user_groups.get(ug_k, 'usergroup.none')
943 p = self._choose_permission(p, cur_perm)
943 p = self._choose_permission(p, cur_perm)
944
944
945 self.permissions_user_groups[ug_k] = p, o
945 self.permissions_user_groups[ug_k] = p, o
946
946
947 if perm.UserGroup.user_id == self.user_id:
947 if perm.UserGroup.user_id == self.user_id:
948 # set admin if owner
948 # set admin if owner
949 p = 'usergroup.admin'
949 p = 'usergroup.admin'
950 o = PermOrigin.USERGROUP_OWNER
950 o = PermOrigin.USERGROUP_OWNER
951 self.permissions_user_groups[ug_k] = p, o
951 self.permissions_user_groups[ug_k] = p, o
952
952
953 if self.user_is_admin:
953 if self.user_is_admin:
954 p = 'usergroup.admin'
954 p = 'usergroup.admin'
955 o = PermOrigin.SUPER_ADMIN
955 o = PermOrigin.SUPER_ADMIN
956 self.permissions_user_groups[ug_k] = p, o
956 self.permissions_user_groups[ug_k] = p, o
957
957
958 def _choose_permission(self, new_perm, cur_perm):
958 def _choose_permission(self, new_perm, cur_perm):
959 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
959 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
960 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
960 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
961 if self.algo == 'higherwin':
961 if self.algo == 'higherwin':
962 if new_perm_val > cur_perm_val:
962 if new_perm_val > cur_perm_val:
963 return new_perm
963 return new_perm
964 return cur_perm
964 return cur_perm
965 elif self.algo == 'lowerwin':
965 elif self.algo == 'lowerwin':
966 if new_perm_val < cur_perm_val:
966 if new_perm_val < cur_perm_val:
967 return new_perm
967 return new_perm
968 return cur_perm
968 return cur_perm
969
969
970 def _permission_structure(self):
970 def _permission_structure(self):
971 return {
971 return {
972 'global': self.permissions_global,
972 'global': self.permissions_global,
973 'repositories': self.permissions_repositories,
973 'repositories': self.permissions_repositories,
974 'repository_branches': self.permissions_repository_branches,
974 'repository_branches': self.permissions_repository_branches,
975 'repositories_groups': self.permissions_repository_groups,
975 'repositories_groups': self.permissions_repository_groups,
976 'user_groups': self.permissions_user_groups,
976 'user_groups': self.permissions_user_groups,
977 }
977 }
978
978
979
979
980 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
980 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
981 """
981 """
982 Check if given controller_name is in whitelist of auth token access
982 Check if given controller_name is in whitelist of auth token access
983 """
983 """
984 if not whitelist:
984 if not whitelist:
985 from rhodecode import CONFIG
985 from rhodecode import CONFIG
986 whitelist = aslist(
986 whitelist = aslist(
987 CONFIG.get('api_access_controllers_whitelist'), sep=',')
987 CONFIG.get('api_access_controllers_whitelist'), sep=',')
988 # backward compat translation
988 # backward compat translation
989 compat = {
989 compat = {
990 # old controller, new VIEW
990 # old controller, new VIEW
991 'ChangesetController:*': 'RepoCommitsView:*',
991 'ChangesetController:*': 'RepoCommitsView:*',
992 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
992 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
993 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
993 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
994 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
994 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
995 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
995 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
996 'GistsController:*': 'GistView:*',
996 'GistsController:*': 'GistView:*',
997 }
997 }
998
998
999 log.debug(
999 log.debug(
1000 'Allowed views for AUTH TOKEN access: %s', whitelist)
1000 'Allowed views for AUTH TOKEN access: %s', whitelist)
1001 auth_token_access_valid = False
1001 auth_token_access_valid = False
1002
1002
1003 for entry in whitelist:
1003 for entry in whitelist:
1004 token_match = True
1004 token_match = True
1005 if entry in compat:
1005 if entry in compat:
1006 # translate from old Controllers to Pyramid Views
1006 # translate from old Controllers to Pyramid Views
1007 entry = compat[entry]
1007 entry = compat[entry]
1008
1008
1009 if '@' in entry:
1009 if '@' in entry:
1010 # specific AuthToken
1010 # specific AuthToken
1011 entry, allowed_token = entry.split('@', 1)
1011 entry, allowed_token = entry.split('@', 1)
1012 token_match = auth_token == allowed_token
1012 token_match = auth_token == allowed_token
1013
1013
1014 if fnmatch.fnmatch(view_name, entry) and token_match:
1014 if fnmatch.fnmatch(view_name, entry) and token_match:
1015 auth_token_access_valid = True
1015 auth_token_access_valid = True
1016 break
1016 break
1017
1017
1018 if auth_token_access_valid:
1018 if auth_token_access_valid:
1019 log.debug('view: `%s` matches entry in whitelist: %s',
1019 log.debug('view: `%s` matches entry in whitelist: %s',
1020 view_name, whitelist)
1020 view_name, whitelist)
1021
1021
1022 else:
1022 else:
1023 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
1023 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
1024 % (view_name, whitelist))
1024 % (view_name, whitelist))
1025 if auth_token:
1025 if auth_token:
1026 # if we use auth token key and don't have access it's a warning
1026 # if we use auth token key and don't have access it's a warning
1027 log.warning(msg)
1027 log.warning(msg)
1028 else:
1028 else:
1029 log.debug(msg)
1029 log.debug(msg)
1030
1030
1031 return auth_token_access_valid
1031 return auth_token_access_valid
1032
1032
1033
1033
1034 class AuthUser(object):
1034 class AuthUser(object):
1035 """
1035 """
1036 A simple object that handles all attributes of user in RhodeCode
1036 A simple object that handles all attributes of user in RhodeCode
1037
1037
1038 It does lookup based on API key,given user, or user present in session
1038 It does lookup based on API key,given user, or user present in session
1039 Then it fills all required information for such user. It also checks if
1039 Then it fills all required information for such user. It also checks if
1040 anonymous access is enabled and if so, it returns default user as logged in
1040 anonymous access is enabled and if so, it returns default user as logged in
1041 """
1041 """
1042 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
1042 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
1043
1043
1044 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
1044 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
1045
1045
1046 self.user_id = user_id
1046 self.user_id = user_id
1047 self._api_key = api_key
1047 self._api_key = api_key
1048
1048
1049 self.api_key = None
1049 self.api_key = None
1050 self.username = username
1050 self.username = username
1051 self.ip_addr = ip_addr
1051 self.ip_addr = ip_addr
1052 self.name = ''
1052 self.name = ''
1053 self.lastname = ''
1053 self.lastname = ''
1054 self.first_name = ''
1054 self.first_name = ''
1055 self.last_name = ''
1055 self.last_name = ''
1056 self.email = ''
1056 self.email = ''
1057 self.is_authenticated = False
1057 self.is_authenticated = False
1058 self.admin = False
1058 self.admin = False
1059 self.inherit_default_permissions = False
1059 self.inherit_default_permissions = False
1060 self.password = ''
1060 self.password = ''
1061
1061
1062 self.anonymous_user = None # propagated on propagate_data
1062 self.anonymous_user = None # propagated on propagate_data
1063 self.propagate_data()
1063 self.propagate_data()
1064 self._instance = None
1064 self._instance = None
1065 self._permissions_scoped_cache = {} # used to bind scoped calculation
1065 self._permissions_scoped_cache = {} # used to bind scoped calculation
1066
1066
1067 @LazyProperty
1067 @LazyProperty
1068 def permissions(self):
1068 def permissions(self):
1069 return self.get_perms(user=self, cache=None)
1069 return self.get_perms(user=self, cache=None)
1070
1070
1071 @LazyProperty
1071 @LazyProperty
1072 def permissions_safe(self):
1072 def permissions_safe(self):
1073 """
1073 """
1074 Filtered permissions excluding not allowed repositories
1074 Filtered permissions excluding not allowed repositories
1075 """
1075 """
1076 perms = self.get_perms(user=self, cache=None)
1076 perms = self.get_perms(user=self, cache=None)
1077
1077
1078 perms['repositories'] = {
1078 perms['repositories'] = {
1079 k: v for k, v in perms['repositories'].items()
1079 k: v for k, v in perms['repositories'].items()
1080 if v != 'repository.none'}
1080 if v != 'repository.none'}
1081 perms['repositories_groups'] = {
1081 perms['repositories_groups'] = {
1082 k: v for k, v in perms['repositories_groups'].items()
1082 k: v for k, v in perms['repositories_groups'].items()
1083 if v != 'group.none'}
1083 if v != 'group.none'}
1084 perms['user_groups'] = {
1084 perms['user_groups'] = {
1085 k: v for k, v in perms['user_groups'].items()
1085 k: v for k, v in perms['user_groups'].items()
1086 if v != 'usergroup.none'}
1086 if v != 'usergroup.none'}
1087 perms['repository_branches'] = {
1087 perms['repository_branches'] = {
1088 k: v for k, v in perms['repository_branches'].iteritems()
1088 k: v for k, v in perms['repository_branches'].iteritems()
1089 if v != 'branch.none'}
1089 if v != 'branch.none'}
1090 return perms
1090 return perms
1091
1091
1092 @LazyProperty
1092 @LazyProperty
1093 def permissions_full_details(self):
1093 def permissions_full_details(self):
1094 return self.get_perms(
1094 return self.get_perms(
1095 user=self, cache=None, calculate_super_admin=True)
1095 user=self, cache=None, calculate_super_admin=True)
1096
1096
1097 def permissions_with_scope(self, scope):
1097 def permissions_with_scope(self, scope):
1098 """
1098 """
1099 Call the get_perms function with scoped data. The scope in that function
1099 Call the get_perms function with scoped data. The scope in that function
1100 narrows the SQL calls to the given ID of objects resulting in fetching
1100 narrows the SQL calls to the given ID of objects resulting in fetching
1101 Just particular permission we want to obtain. If scope is an empty dict
1101 Just particular permission we want to obtain. If scope is an empty dict
1102 then it basically narrows the scope to GLOBAL permissions only.
1102 then it basically narrows the scope to GLOBAL permissions only.
1103
1103
1104 :param scope: dict
1104 :param scope: dict
1105 """
1105 """
1106 if 'repo_name' in scope:
1106 if 'repo_name' in scope:
1107 obj = Repository.get_by_repo_name(scope['repo_name'])
1107 obj = Repository.get_by_repo_name(scope['repo_name'])
1108 if obj:
1108 if obj:
1109 scope['repo_id'] = obj.repo_id
1109 scope['repo_id'] = obj.repo_id
1110 _scope = collections.OrderedDict()
1110 _scope = collections.OrderedDict()
1111 _scope['repo_id'] = -1
1111 _scope['repo_id'] = -1
1112 _scope['user_group_id'] = -1
1112 _scope['user_group_id'] = -1
1113 _scope['repo_group_id'] = -1
1113 _scope['repo_group_id'] = -1
1114
1114
1115 for k in sorted(scope.keys()):
1115 for k in sorted(scope.keys()):
1116 _scope[k] = scope[k]
1116 _scope[k] = scope[k]
1117
1117
1118 # store in cache to mimic how the @LazyProperty works,
1118 # store in cache to mimic how the @LazyProperty works,
1119 # the difference here is that we use the unique key calculated
1119 # the difference here is that we use the unique key calculated
1120 # from params and values
1120 # from params and values
1121 return self.get_perms(user=self, cache=None, scope=_scope)
1121 return self.get_perms(user=self, cache=None, scope=_scope)
1122
1122
1123 def get_instance(self):
1123 def get_instance(self):
1124 return User.get(self.user_id)
1124 return User.get(self.user_id)
1125
1125
1126 def propagate_data(self):
1126 def propagate_data(self):
1127 """
1127 """
1128 Fills in user data and propagates values to this instance. Maps fetched
1128 Fills in user data and propagates values to this instance. Maps fetched
1129 user attributes to this class instance attributes
1129 user attributes to this class instance attributes
1130 """
1130 """
1131 log.debug('AuthUser: starting data propagation for new potential user')
1131 log.debug('AuthUser: starting data propagation for new potential user')
1132 user_model = UserModel()
1132 user_model = UserModel()
1133 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1133 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1134 is_user_loaded = False
1134 is_user_loaded = False
1135
1135
1136 # lookup by userid
1136 # lookup by userid
1137 if self.user_id is not None and self.user_id != anon_user.user_id:
1137 if self.user_id is not None and self.user_id != anon_user.user_id:
1138 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1138 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1139 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1139 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1140
1140
1141 # try go get user by api key
1141 # try go get user by api key
1142 elif self._api_key and self._api_key != anon_user.api_key:
1142 elif self._api_key and self._api_key != anon_user.api_key:
1143 log.debug('Trying Auth User lookup by API KEY: `%s`', self._api_key)
1143 log.debug('Trying Auth User lookup by API KEY: `...%s`', self._api_key[-4:])
1144 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1144 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1145
1145
1146 # lookup by username
1146 # lookup by username
1147 elif self.username:
1147 elif self.username:
1148 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1148 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1149 is_user_loaded = user_model.fill_data(self, username=self.username)
1149 is_user_loaded = user_model.fill_data(self, username=self.username)
1150 else:
1150 else:
1151 log.debug('No data in %s that could been used to log in', self)
1151 log.debug('No data in %s that could been used to log in', self)
1152
1152
1153 if not is_user_loaded:
1153 if not is_user_loaded:
1154 log.debug(
1154 log.debug(
1155 'Failed to load user. Fallback to default user %s', anon_user)
1155 'Failed to load user. Fallback to default user %s', anon_user)
1156 # if we cannot authenticate user try anonymous
1156 # if we cannot authenticate user try anonymous
1157 if anon_user.active:
1157 if anon_user.active:
1158 log.debug('default user is active, using it as a session user')
1158 log.debug('default user is active, using it as a session user')
1159 user_model.fill_data(self, user_id=anon_user.user_id)
1159 user_model.fill_data(self, user_id=anon_user.user_id)
1160 # then we set this user is logged in
1160 # then we set this user is logged in
1161 self.is_authenticated = True
1161 self.is_authenticated = True
1162 else:
1162 else:
1163 log.debug('default user is NOT active')
1163 log.debug('default user is NOT active')
1164 # in case of disabled anonymous user we reset some of the
1164 # in case of disabled anonymous user we reset some of the
1165 # parameters so such user is "corrupted", skipping the fill_data
1165 # parameters so such user is "corrupted", skipping the fill_data
1166 for attr in ['user_id', 'username', 'admin', 'active']:
1166 for attr in ['user_id', 'username', 'admin', 'active']:
1167 setattr(self, attr, None)
1167 setattr(self, attr, None)
1168 self.is_authenticated = False
1168 self.is_authenticated = False
1169
1169
1170 if not self.username:
1170 if not self.username:
1171 self.username = 'None'
1171 self.username = 'None'
1172
1172
1173 log.debug('AuthUser: propagated user is now %s', self)
1173 log.debug('AuthUser: propagated user is now %s', self)
1174
1174
1175 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1175 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1176 calculate_super_admin=False, cache=None):
1176 calculate_super_admin=False, cache=None):
1177 """
1177 """
1178 Fills user permission attribute with permissions taken from database
1178 Fills user permission attribute with permissions taken from database
1179 works for permissions given for repositories, and for permissions that
1179 works for permissions given for repositories, and for permissions that
1180 are granted to groups
1180 are granted to groups
1181
1181
1182 :param user: instance of User object from database
1182 :param user: instance of User object from database
1183 :param explicit: In case there are permissions both for user and a group
1183 :param explicit: In case there are permissions both for user and a group
1184 that user is part of, explicit flag will defiine if user will
1184 that user is part of, explicit flag will defiine if user will
1185 explicitly override permissions from group, if it's False it will
1185 explicitly override permissions from group, if it's False it will
1186 make decision based on the algo
1186 make decision based on the algo
1187 :param algo: algorithm to decide what permission should be choose if
1187 :param algo: algorithm to decide what permission should be choose if
1188 it's multiple defined, eg user in two different groups. It also
1188 it's multiple defined, eg user in two different groups. It also
1189 decides if explicit flag is turned off how to specify the permission
1189 decides if explicit flag is turned off how to specify the permission
1190 for case when user is in a group + have defined separate permission
1190 for case when user is in a group + have defined separate permission
1191 :param calculate_super_admin: calculate permissions for super-admin in the
1191 :param calculate_super_admin: calculate permissions for super-admin in the
1192 same way as for regular user without speedups
1192 same way as for regular user without speedups
1193 :param cache: Use caching for calculation, None = let the cache backend decide
1193 :param cache: Use caching for calculation, None = let the cache backend decide
1194 """
1194 """
1195 user_id = user.user_id
1195 user_id = user.user_id
1196 user_is_admin = user.is_admin
1196 user_is_admin = user.is_admin
1197
1197
1198 # inheritance of global permissions like create repo/fork repo etc
1198 # inheritance of global permissions like create repo/fork repo etc
1199 user_inherit_default_permissions = user.inherit_default_permissions
1199 user_inherit_default_permissions = user.inherit_default_permissions
1200
1200
1201 cache_seconds = safe_int(
1201 cache_seconds = safe_int(
1202 rhodecode.CONFIG.get('rc_cache.cache_perms.expiration_time'))
1202 rhodecode.CONFIG.get('rc_cache.cache_perms.expiration_time'))
1203
1203
1204 if cache is None:
1204 if cache is None:
1205 # let the backend cache decide
1205 # let the backend cache decide
1206 cache_on = cache_seconds > 0
1206 cache_on = cache_seconds > 0
1207 else:
1207 else:
1208 cache_on = cache
1208 cache_on = cache
1209
1209
1210 log.debug(
1210 log.debug(
1211 'Computing PERMISSION tree for user %s scope `%s` '
1211 'Computing PERMISSION tree for user %s scope `%s` '
1212 'with caching: %s[TTL: %ss]', user, scope, cache_on, cache_seconds or 0)
1212 'with caching: %s[TTL: %ss]', user, scope, cache_on, cache_seconds or 0)
1213
1213
1214 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
1214 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
1215 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1215 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1216
1216
1217 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
1217 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
1218 condition=cache_on)
1218 condition=cache_on)
1219 def compute_perm_tree(cache_name,
1219 def compute_perm_tree(cache_name,
1220 user_id, scope, user_is_admin,user_inherit_default_permissions,
1220 user_id, scope, user_is_admin,user_inherit_default_permissions,
1221 explicit, algo, calculate_super_admin):
1221 explicit, algo, calculate_super_admin):
1222 return _cached_perms_data(
1222 return _cached_perms_data(
1223 user_id, scope, user_is_admin, user_inherit_default_permissions,
1223 user_id, scope, user_is_admin, user_inherit_default_permissions,
1224 explicit, algo, calculate_super_admin)
1224 explicit, algo, calculate_super_admin)
1225
1225
1226 start = time.time()
1226 start = time.time()
1227 result = compute_perm_tree(
1227 result = compute_perm_tree(
1228 'permissions', user_id, scope, user_is_admin,
1228 'permissions', user_id, scope, user_is_admin,
1229 user_inherit_default_permissions, explicit, algo,
1229 user_inherit_default_permissions, explicit, algo,
1230 calculate_super_admin)
1230 calculate_super_admin)
1231
1231
1232 result_repr = []
1232 result_repr = []
1233 for k in result:
1233 for k in result:
1234 result_repr.append((k, len(result[k])))
1234 result_repr.append((k, len(result[k])))
1235 total = time.time() - start
1235 total = time.time() - start
1236 log.debug('PERMISSION tree for user %s computed in %.4fs: %s',
1236 log.debug('PERMISSION tree for user %s computed in %.4fs: %s',
1237 user, total, result_repr)
1237 user, total, result_repr)
1238
1238
1239 return result
1239 return result
1240
1240
1241 @property
1241 @property
1242 def is_default(self):
1242 def is_default(self):
1243 return self.username == User.DEFAULT_USER
1243 return self.username == User.DEFAULT_USER
1244
1244
1245 @property
1245 @property
1246 def is_admin(self):
1246 def is_admin(self):
1247 return self.admin
1247 return self.admin
1248
1248
1249 @property
1249 @property
1250 def is_user_object(self):
1250 def is_user_object(self):
1251 return self.user_id is not None
1251 return self.user_id is not None
1252
1252
1253 @property
1253 @property
1254 def repositories_admin(self):
1254 def repositories_admin(self):
1255 """
1255 """
1256 Returns list of repositories you're an admin of
1256 Returns list of repositories you're an admin of
1257 """
1257 """
1258 return [
1258 return [
1259 x[0] for x in self.permissions['repositories'].items()
1259 x[0] for x in self.permissions['repositories'].items()
1260 if x[1] == 'repository.admin']
1260 if x[1] == 'repository.admin']
1261
1261
1262 @property
1262 @property
1263 def repository_groups_admin(self):
1263 def repository_groups_admin(self):
1264 """
1264 """
1265 Returns list of repository groups you're an admin of
1265 Returns list of repository groups you're an admin of
1266 """
1266 """
1267 return [
1267 return [
1268 x[0] for x in self.permissions['repositories_groups'].items()
1268 x[0] for x in self.permissions['repositories_groups'].items()
1269 if x[1] == 'group.admin']
1269 if x[1] == 'group.admin']
1270
1270
1271 @property
1271 @property
1272 def user_groups_admin(self):
1272 def user_groups_admin(self):
1273 """
1273 """
1274 Returns list of user groups you're an admin of
1274 Returns list of user groups you're an admin of
1275 """
1275 """
1276 return [
1276 return [
1277 x[0] for x in self.permissions['user_groups'].items()
1277 x[0] for x in self.permissions['user_groups'].items()
1278 if x[1] == 'usergroup.admin']
1278 if x[1] == 'usergroup.admin']
1279
1279
1280 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1280 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1281 """
1281 """
1282 Returns list of repository ids that user have access to based on given
1282 Returns list of repository ids that user have access to based on given
1283 perms. The cache flag should be only used in cases that are used for
1283 perms. The cache flag should be only used in cases that are used for
1284 display purposes, NOT IN ANY CASE for permission checks.
1284 display purposes, NOT IN ANY CASE for permission checks.
1285 """
1285 """
1286 from rhodecode.model.scm import RepoList
1286 from rhodecode.model.scm import RepoList
1287 if not perms:
1287 if not perms:
1288 perms = [
1288 perms = [
1289 'repository.read', 'repository.write', 'repository.admin']
1289 'repository.read', 'repository.write', 'repository.admin']
1290
1290
1291 def _cached_repo_acl(user_id, perm_def, _name_filter):
1291 def _cached_repo_acl(user_id, perm_def, _name_filter):
1292 qry = Repository.query()
1292 qry = Repository.query()
1293 if _name_filter:
1293 if _name_filter:
1294 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1294 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1295 qry = qry.filter(
1295 qry = qry.filter(
1296 Repository.repo_name.ilike(ilike_expression))
1296 Repository.repo_name.ilike(ilike_expression))
1297
1297
1298 return [x.repo_id for x in
1298 return [x.repo_id for x in
1299 RepoList(qry, perm_set=perm_def)]
1299 RepoList(qry, perm_set=perm_def)]
1300
1300
1301 return _cached_repo_acl(self.user_id, perms, name_filter)
1301 return _cached_repo_acl(self.user_id, perms, name_filter)
1302
1302
1303 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1303 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1304 """
1304 """
1305 Returns list of repository group ids that user have access to based on given
1305 Returns list of repository group ids that user have access to based on given
1306 perms. The cache flag should be only used in cases that are used for
1306 perms. The cache flag should be only used in cases that are used for
1307 display purposes, NOT IN ANY CASE for permission checks.
1307 display purposes, NOT IN ANY CASE for permission checks.
1308 """
1308 """
1309 from rhodecode.model.scm import RepoGroupList
1309 from rhodecode.model.scm import RepoGroupList
1310 if not perms:
1310 if not perms:
1311 perms = [
1311 perms = [
1312 'group.read', 'group.write', 'group.admin']
1312 'group.read', 'group.write', 'group.admin']
1313
1313
1314 def _cached_repo_group_acl(user_id, perm_def, _name_filter):
1314 def _cached_repo_group_acl(user_id, perm_def, _name_filter):
1315 qry = RepoGroup.query()
1315 qry = RepoGroup.query()
1316 if _name_filter:
1316 if _name_filter:
1317 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1317 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1318 qry = qry.filter(
1318 qry = qry.filter(
1319 RepoGroup.group_name.ilike(ilike_expression))
1319 RepoGroup.group_name.ilike(ilike_expression))
1320
1320
1321 return [x.group_id for x in
1321 return [x.group_id for x in
1322 RepoGroupList(qry, perm_set=perm_def)]
1322 RepoGroupList(qry, perm_set=perm_def)]
1323
1323
1324 return _cached_repo_group_acl(self.user_id, perms, name_filter)
1324 return _cached_repo_group_acl(self.user_id, perms, name_filter)
1325
1325
1326 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1326 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1327 """
1327 """
1328 Returns list of user group ids that user have access to based on given
1328 Returns list of user group ids that user have access to based on given
1329 perms. The cache flag should be only used in cases that are used for
1329 perms. The cache flag should be only used in cases that are used for
1330 display purposes, NOT IN ANY CASE for permission checks.
1330 display purposes, NOT IN ANY CASE for permission checks.
1331 """
1331 """
1332 from rhodecode.model.scm import UserGroupList
1332 from rhodecode.model.scm import UserGroupList
1333 if not perms:
1333 if not perms:
1334 perms = [
1334 perms = [
1335 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1335 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1336
1336
1337 def _cached_user_group_acl(user_id, perm_def, name_filter):
1337 def _cached_user_group_acl(user_id, perm_def, name_filter):
1338 qry = UserGroup.query()
1338 qry = UserGroup.query()
1339 if name_filter:
1339 if name_filter:
1340 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1340 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1341 qry = qry.filter(
1341 qry = qry.filter(
1342 UserGroup.users_group_name.ilike(ilike_expression))
1342 UserGroup.users_group_name.ilike(ilike_expression))
1343
1343
1344 return [x.users_group_id for x in
1344 return [x.users_group_id for x in
1345 UserGroupList(qry, perm_set=perm_def)]
1345 UserGroupList(qry, perm_set=perm_def)]
1346
1346
1347 return _cached_user_group_acl(self.user_id, perms, name_filter)
1347 return _cached_user_group_acl(self.user_id, perms, name_filter)
1348
1348
1349 @property
1349 @property
1350 def ip_allowed(self):
1350 def ip_allowed(self):
1351 """
1351 """
1352 Checks if ip_addr used in constructor is allowed from defined list of
1352 Checks if ip_addr used in constructor is allowed from defined list of
1353 allowed ip_addresses for user
1353 allowed ip_addresses for user
1354
1354
1355 :returns: boolean, True if ip is in allowed ip range
1355 :returns: boolean, True if ip is in allowed ip range
1356 """
1356 """
1357 # check IP
1357 # check IP
1358 inherit = self.inherit_default_permissions
1358 inherit = self.inherit_default_permissions
1359 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1359 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1360 inherit_from_default=inherit)
1360 inherit_from_default=inherit)
1361 @property
1361 @property
1362 def personal_repo_group(self):
1362 def personal_repo_group(self):
1363 return RepoGroup.get_user_personal_repo_group(self.user_id)
1363 return RepoGroup.get_user_personal_repo_group(self.user_id)
1364
1364
1365 @LazyProperty
1365 @LazyProperty
1366 def feed_token(self):
1366 def feed_token(self):
1367 return self.get_instance().feed_token
1367 return self.get_instance().feed_token
1368
1368
1369 @LazyProperty
1370 def artifact_token(self):
1371 return self.get_instance().artifact_token
1372
1369 @classmethod
1373 @classmethod
1370 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1374 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1371 allowed_ips = AuthUser.get_allowed_ips(
1375 allowed_ips = AuthUser.get_allowed_ips(
1372 user_id, cache=True, inherit_from_default=inherit_from_default)
1376 user_id, cache=True, inherit_from_default=inherit_from_default)
1373 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1377 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1374 log.debug('IP:%s for user %s is in range of %s',
1378 log.debug('IP:%s for user %s is in range of %s',
1375 ip_addr, user_id, allowed_ips)
1379 ip_addr, user_id, allowed_ips)
1376 return True
1380 return True
1377 else:
1381 else:
1378 log.info('Access for IP:%s forbidden for user %s, '
1382 log.info('Access for IP:%s forbidden for user %s, '
1379 'not in %s', ip_addr, user_id, allowed_ips)
1383 'not in %s', ip_addr, user_id, allowed_ips)
1380 return False
1384 return False
1381
1385
1382 def get_branch_permissions(self, repo_name, perms=None):
1386 def get_branch_permissions(self, repo_name, perms=None):
1383 perms = perms or self.permissions_with_scope({'repo_name': repo_name})
1387 perms = perms or self.permissions_with_scope({'repo_name': repo_name})
1384 branch_perms = perms.get('repository_branches', {})
1388 branch_perms = perms.get('repository_branches', {})
1385 if not branch_perms:
1389 if not branch_perms:
1386 return {}
1390 return {}
1387 repo_branch_perms = branch_perms.get(repo_name)
1391 repo_branch_perms = branch_perms.get(repo_name)
1388 return repo_branch_perms or {}
1392 return repo_branch_perms or {}
1389
1393
1390 def get_rule_and_branch_permission(self, repo_name, branch_name):
1394 def get_rule_and_branch_permission(self, repo_name, branch_name):
1391 """
1395 """
1392 Check if this AuthUser has defined any permissions for branches. If any of
1396 Check if this AuthUser has defined any permissions for branches. If any of
1393 the rules match in order, we return the matching permissions
1397 the rules match in order, we return the matching permissions
1394 """
1398 """
1395
1399
1396 rule = default_perm = ''
1400 rule = default_perm = ''
1397
1401
1398 repo_branch_perms = self.get_branch_permissions(repo_name=repo_name)
1402 repo_branch_perms = self.get_branch_permissions(repo_name=repo_name)
1399 if not repo_branch_perms:
1403 if not repo_branch_perms:
1400 return rule, default_perm
1404 return rule, default_perm
1401
1405
1402 # now calculate the permissions
1406 # now calculate the permissions
1403 for pattern, branch_perm in repo_branch_perms.items():
1407 for pattern, branch_perm in repo_branch_perms.items():
1404 if fnmatch.fnmatch(branch_name, pattern):
1408 if fnmatch.fnmatch(branch_name, pattern):
1405 rule = '`{}`=>{}'.format(pattern, branch_perm)
1409 rule = '`{}`=>{}'.format(pattern, branch_perm)
1406 return rule, branch_perm
1410 return rule, branch_perm
1407
1411
1408 return rule, default_perm
1412 return rule, default_perm
1409
1413
1410 def __repr__(self):
1414 def __repr__(self):
1411 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1415 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1412 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1416 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1413
1417
1414 def set_authenticated(self, authenticated=True):
1418 def set_authenticated(self, authenticated=True):
1415 if self.user_id != self.anonymous_user.user_id:
1419 if self.user_id != self.anonymous_user.user_id:
1416 self.is_authenticated = authenticated
1420 self.is_authenticated = authenticated
1417
1421
1418 def get_cookie_store(self):
1422 def get_cookie_store(self):
1419 return {
1423 return {
1420 'username': self.username,
1424 'username': self.username,
1421 'password': md5(self.password or ''),
1425 'password': md5(self.password or ''),
1422 'user_id': self.user_id,
1426 'user_id': self.user_id,
1423 'is_authenticated': self.is_authenticated
1427 'is_authenticated': self.is_authenticated
1424 }
1428 }
1425
1429
1426 @classmethod
1430 @classmethod
1427 def from_cookie_store(cls, cookie_store):
1431 def from_cookie_store(cls, cookie_store):
1428 """
1432 """
1429 Creates AuthUser from a cookie store
1433 Creates AuthUser from a cookie store
1430
1434
1431 :param cls:
1435 :param cls:
1432 :param cookie_store:
1436 :param cookie_store:
1433 """
1437 """
1434 user_id = cookie_store.get('user_id')
1438 user_id = cookie_store.get('user_id')
1435 username = cookie_store.get('username')
1439 username = cookie_store.get('username')
1436 api_key = cookie_store.get('api_key')
1440 api_key = cookie_store.get('api_key')
1437 return AuthUser(user_id, api_key, username)
1441 return AuthUser(user_id, api_key, username)
1438
1442
1439 @classmethod
1443 @classmethod
1440 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1444 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1441 _set = set()
1445 _set = set()
1442
1446
1443 if inherit_from_default:
1447 if inherit_from_default:
1444 def_user_id = User.get_default_user(cache=True).user_id
1448 def_user_id = User.get_default_user(cache=True).user_id
1445 default_ips = UserIpMap.query().filter(UserIpMap.user_id == def_user_id)
1449 default_ips = UserIpMap.query().filter(UserIpMap.user_id == def_user_id)
1446 if cache:
1450 if cache:
1447 default_ips = default_ips.options(
1451 default_ips = default_ips.options(
1448 FromCache("sql_cache_short", "get_user_ips_default"))
1452 FromCache("sql_cache_short", "get_user_ips_default"))
1449
1453
1450 # populate from default user
1454 # populate from default user
1451 for ip in default_ips:
1455 for ip in default_ips:
1452 try:
1456 try:
1453 _set.add(ip.ip_addr)
1457 _set.add(ip.ip_addr)
1454 except ObjectDeletedError:
1458 except ObjectDeletedError:
1455 # since we use heavy caching sometimes it happens that
1459 # since we use heavy caching sometimes it happens that
1456 # we get deleted objects here, we just skip them
1460 # we get deleted objects here, we just skip them
1457 pass
1461 pass
1458
1462
1459 # NOTE:(marcink) we don't want to load any rules for empty
1463 # NOTE:(marcink) we don't want to load any rules for empty
1460 # user_id which is the case of access of non logged users when anonymous
1464 # user_id which is the case of access of non logged users when anonymous
1461 # access is disabled
1465 # access is disabled
1462 user_ips = []
1466 user_ips = []
1463 if user_id:
1467 if user_id:
1464 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1468 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1465 if cache:
1469 if cache:
1466 user_ips = user_ips.options(
1470 user_ips = user_ips.options(
1467 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1471 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1468
1472
1469 for ip in user_ips:
1473 for ip in user_ips:
1470 try:
1474 try:
1471 _set.add(ip.ip_addr)
1475 _set.add(ip.ip_addr)
1472 except ObjectDeletedError:
1476 except ObjectDeletedError:
1473 # since we use heavy caching sometimes it happens that we get
1477 # since we use heavy caching sometimes it happens that we get
1474 # deleted objects here, we just skip them
1478 # deleted objects here, we just skip them
1475 pass
1479 pass
1476 return _set or {ip for ip in ['0.0.0.0/0', '::/0']}
1480 return _set or {ip for ip in ['0.0.0.0/0', '::/0']}
1477
1481
1478
1482
1479 def set_available_permissions(settings):
1483 def set_available_permissions(settings):
1480 """
1484 """
1481 This function will propagate pyramid settings with all available defined
1485 This function will propagate pyramid settings with all available defined
1482 permission given in db. We don't want to check each time from db for new
1486 permission given in db. We don't want to check each time from db for new
1483 permissions since adding a new permission also requires application restart
1487 permissions since adding a new permission also requires application restart
1484 ie. to decorate new views with the newly created permission
1488 ie. to decorate new views with the newly created permission
1485
1489
1486 :param settings: current pyramid registry.settings
1490 :param settings: current pyramid registry.settings
1487
1491
1488 """
1492 """
1489 log.debug('auth: getting information about all available permissions')
1493 log.debug('auth: getting information about all available permissions')
1490 try:
1494 try:
1491 sa = meta.Session
1495 sa = meta.Session
1492 all_perms = sa.query(Permission).all()
1496 all_perms = sa.query(Permission).all()
1493 settings.setdefault('available_permissions',
1497 settings.setdefault('available_permissions',
1494 [x.permission_name for x in all_perms])
1498 [x.permission_name for x in all_perms])
1495 log.debug('auth: set available permissions')
1499 log.debug('auth: set available permissions')
1496 except Exception:
1500 except Exception:
1497 log.exception('Failed to fetch permissions from the database.')
1501 log.exception('Failed to fetch permissions from the database.')
1498 raise
1502 raise
1499
1503
1500
1504
1501 def get_csrf_token(session, force_new=False, save_if_missing=True):
1505 def get_csrf_token(session, force_new=False, save_if_missing=True):
1502 """
1506 """
1503 Return the current authentication token, creating one if one doesn't
1507 Return the current authentication token, creating one if one doesn't
1504 already exist and the save_if_missing flag is present.
1508 already exist and the save_if_missing flag is present.
1505
1509
1506 :param session: pass in the pyramid session, else we use the global ones
1510 :param session: pass in the pyramid session, else we use the global ones
1507 :param force_new: force to re-generate the token and store it in session
1511 :param force_new: force to re-generate the token and store it in session
1508 :param save_if_missing: save the newly generated token if it's missing in
1512 :param save_if_missing: save the newly generated token if it's missing in
1509 session
1513 session
1510 """
1514 """
1511 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1515 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1512 # from pyramid.csrf import get_csrf_token
1516 # from pyramid.csrf import get_csrf_token
1513
1517
1514 if (csrf_token_key not in session and save_if_missing) or force_new:
1518 if (csrf_token_key not in session and save_if_missing) or force_new:
1515 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1519 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1516 session[csrf_token_key] = token
1520 session[csrf_token_key] = token
1517 if hasattr(session, 'save'):
1521 if hasattr(session, 'save'):
1518 session.save()
1522 session.save()
1519 return session.get(csrf_token_key)
1523 return session.get(csrf_token_key)
1520
1524
1521
1525
1522 def get_request(perm_class_instance):
1526 def get_request(perm_class_instance):
1523 from pyramid.threadlocal import get_current_request
1527 from pyramid.threadlocal import get_current_request
1524 pyramid_request = get_current_request()
1528 pyramid_request = get_current_request()
1525 return pyramid_request
1529 return pyramid_request
1526
1530
1527
1531
1528 # CHECK DECORATORS
1532 # CHECK DECORATORS
1529 class CSRFRequired(object):
1533 class CSRFRequired(object):
1530 """
1534 """
1531 Decorator for authenticating a form
1535 Decorator for authenticating a form
1532
1536
1533 This decorator uses an authorization token stored in the client's
1537 This decorator uses an authorization token stored in the client's
1534 session for prevention of certain Cross-site request forgery (CSRF)
1538 session for prevention of certain Cross-site request forgery (CSRF)
1535 attacks (See
1539 attacks (See
1536 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1540 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1537 information).
1541 information).
1538
1542
1539 For use with the ``webhelpers.secure_form`` helper functions.
1543 For use with the ``webhelpers.secure_form`` helper functions.
1540
1544
1541 """
1545 """
1542 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1546 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1543 except_methods=None):
1547 except_methods=None):
1544 self.token = token
1548 self.token = token
1545 self.header = header
1549 self.header = header
1546 self.except_methods = except_methods or []
1550 self.except_methods = except_methods or []
1547
1551
1548 def __call__(self, func):
1552 def __call__(self, func):
1549 return get_cython_compat_decorator(self.__wrapper, func)
1553 return get_cython_compat_decorator(self.__wrapper, func)
1550
1554
1551 def _get_csrf(self, _request):
1555 def _get_csrf(self, _request):
1552 return _request.POST.get(self.token, _request.headers.get(self.header))
1556 return _request.POST.get(self.token, _request.headers.get(self.header))
1553
1557
1554 def check_csrf(self, _request, cur_token):
1558 def check_csrf(self, _request, cur_token):
1555 supplied_token = self._get_csrf(_request)
1559 supplied_token = self._get_csrf(_request)
1556 return supplied_token and supplied_token == cur_token
1560 return supplied_token and supplied_token == cur_token
1557
1561
1558 def _get_request(self):
1562 def _get_request(self):
1559 return get_request(self)
1563 return get_request(self)
1560
1564
1561 def __wrapper(self, func, *fargs, **fkwargs):
1565 def __wrapper(self, func, *fargs, **fkwargs):
1562 request = self._get_request()
1566 request = self._get_request()
1563
1567
1564 if request.method in self.except_methods:
1568 if request.method in self.except_methods:
1565 return func(*fargs, **fkwargs)
1569 return func(*fargs, **fkwargs)
1566
1570
1567 cur_token = get_csrf_token(request.session, save_if_missing=False)
1571 cur_token = get_csrf_token(request.session, save_if_missing=False)
1568 if self.check_csrf(request, cur_token):
1572 if self.check_csrf(request, cur_token):
1569 if request.POST.get(self.token):
1573 if request.POST.get(self.token):
1570 del request.POST[self.token]
1574 del request.POST[self.token]
1571 return func(*fargs, **fkwargs)
1575 return func(*fargs, **fkwargs)
1572 else:
1576 else:
1573 reason = 'token-missing'
1577 reason = 'token-missing'
1574 supplied_token = self._get_csrf(request)
1578 supplied_token = self._get_csrf(request)
1575 if supplied_token and cur_token != supplied_token:
1579 if supplied_token and cur_token != supplied_token:
1576 reason = 'token-mismatch [%s:%s]' % (
1580 reason = 'token-mismatch [%s:%s]' % (
1577 cur_token or ''[:6], supplied_token or ''[:6])
1581 cur_token or ''[:6], supplied_token or ''[:6])
1578
1582
1579 csrf_message = \
1583 csrf_message = \
1580 ("Cross-site request forgery detected, request denied. See "
1584 ("Cross-site request forgery detected, request denied. See "
1581 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1585 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1582 "more information.")
1586 "more information.")
1583 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1587 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1584 'REMOTE_ADDR:%s, HEADERS:%s' % (
1588 'REMOTE_ADDR:%s, HEADERS:%s' % (
1585 request, reason, request.remote_addr, request.headers))
1589 request, reason, request.remote_addr, request.headers))
1586
1590
1587 raise HTTPForbidden(explanation=csrf_message)
1591 raise HTTPForbidden(explanation=csrf_message)
1588
1592
1589
1593
1590 class LoginRequired(object):
1594 class LoginRequired(object):
1591 """
1595 """
1592 Must be logged in to execute this function else
1596 Must be logged in to execute this function else
1593 redirect to login page
1597 redirect to login page
1594
1598
1595 :param api_access: if enabled this checks only for valid auth token
1599 :param api_access: if enabled this checks only for valid auth token
1596 and grants access based on valid token
1600 and grants access based on valid token
1597 """
1601 """
1598 def __init__(self, auth_token_access=None):
1602 def __init__(self, auth_token_access=None):
1599 self.auth_token_access = auth_token_access
1603 self.auth_token_access = auth_token_access
1604 if self.auth_token_access:
1605 valid_type = set(auth_token_access).intersection(set(UserApiKeys.ROLES))
1606 if not valid_type:
1607 raise ValueError('auth_token_access must be on of {}, got {}'.format(
1608 UserApiKeys.ROLES, auth_token_access))
1600
1609
1601 def __call__(self, func):
1610 def __call__(self, func):
1602 return get_cython_compat_decorator(self.__wrapper, func)
1611 return get_cython_compat_decorator(self.__wrapper, func)
1603
1612
1604 def _get_request(self):
1613 def _get_request(self):
1605 return get_request(self)
1614 return get_request(self)
1606
1615
1607 def __wrapper(self, func, *fargs, **fkwargs):
1616 def __wrapper(self, func, *fargs, **fkwargs):
1608 from rhodecode.lib import helpers as h
1617 from rhodecode.lib import helpers as h
1609 cls = fargs[0]
1618 cls = fargs[0]
1610 user = cls._rhodecode_user
1619 user = cls._rhodecode_user
1611 request = self._get_request()
1620 request = self._get_request()
1612 _ = request.translate
1621 _ = request.translate
1613
1622
1614 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1623 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1615 log.debug('Starting login restriction checks for user: %s', user)
1624 log.debug('Starting login restriction checks for user: %s', user)
1616 # check if our IP is allowed
1625 # check if our IP is allowed
1617 ip_access_valid = True
1626 ip_access_valid = True
1618 if not user.ip_allowed:
1627 if not user.ip_allowed:
1619 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1628 h.flash(h.literal(_('IP {} not allowed'.format(user.ip_addr))),
1620 category='warning')
1629 category='warning')
1621 ip_access_valid = False
1630 ip_access_valid = False
1622
1631
1623 # check if we used an APIKEY and it's a valid one
1632 # we used stored token that is extract from GET or URL param (if any)
1633 _auth_token = request.user_auth_token
1634
1635 # check if we used an AUTH_TOKEN and it's a valid one
1624 # defined white-list of controllers which API access will be enabled
1636 # defined white-list of controllers which API access will be enabled
1625 _auth_token = request.GET.get(
1637 whitelist = None
1626 'auth_token', '') or request.GET.get('api_key', '')
1638 if self.auth_token_access:
1639 # since this location is allowed by @LoginRequired decorator it's our
1640 # only whitelist
1641 whitelist = [loc]
1627 auth_token_access_valid = allowed_auth_token_access(
1642 auth_token_access_valid = allowed_auth_token_access(
1628 loc, auth_token=_auth_token)
1643 loc, whitelist=whitelist, auth_token=_auth_token)
1629
1644
1630 # explicit controller is enabled or API is in our whitelist
1645 # explicit controller is enabled or API is in our whitelist
1631 if self.auth_token_access or auth_token_access_valid:
1646 if auth_token_access_valid:
1632 log.debug('Checking AUTH TOKEN access for %s', cls)
1647 log.debug('Checking AUTH TOKEN access for %s', cls)
1633 db_user = user.get_instance()
1648 db_user = user.get_instance()
1634
1649
1635 if db_user:
1650 if db_user:
1636 if self.auth_token_access:
1651 if self.auth_token_access:
1637 roles = self.auth_token_access
1652 roles = self.auth_token_access
1638 else:
1653 else:
1639 roles = [UserApiKeys.ROLE_HTTP]
1654 roles = [UserApiKeys.ROLE_HTTP]
1655 log.debug('AUTH TOKEN: checking auth for user %s and roles %s',
1656 db_user, roles)
1640 token_match = db_user.authenticate_by_token(
1657 token_match = db_user.authenticate_by_token(
1641 _auth_token, roles=roles)
1658 _auth_token, roles=roles)
1642 else:
1659 else:
1643 log.debug('Unable to fetch db instance for auth user: %s', user)
1660 log.debug('Unable to fetch db instance for auth user: %s', user)
1644 token_match = False
1661 token_match = False
1645
1662
1646 if _auth_token and token_match:
1663 if _auth_token and token_match:
1647 auth_token_access_valid = True
1664 auth_token_access_valid = True
1648 log.debug('AUTH TOKEN ****%s is VALID', _auth_token[-4:])
1665 log.debug('AUTH TOKEN ****%s is VALID', _auth_token[-4:])
1649 else:
1666 else:
1650 auth_token_access_valid = False
1667 auth_token_access_valid = False
1651 if not _auth_token:
1668 if not _auth_token:
1652 log.debug("AUTH TOKEN *NOT* present in request")
1669 log.debug("AUTH TOKEN *NOT* present in request")
1653 else:
1670 else:
1654 log.warning("AUTH TOKEN ****%s *NOT* valid", _auth_token[-4:])
1671 log.warning("AUTH TOKEN ****%s *NOT* valid", _auth_token[-4:])
1655
1672
1656 log.debug('Checking if %s is authenticated @ %s', user.username, loc)
1673 log.debug('Checking if %s is authenticated @ %s', user.username, loc)
1657 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1674 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1658 else 'AUTH_TOKEN_AUTH'
1675 else 'AUTH_TOKEN_AUTH'
1659
1676
1660 if ip_access_valid and (
1677 if ip_access_valid and (
1661 user.is_authenticated or auth_token_access_valid):
1678 user.is_authenticated or auth_token_access_valid):
1662 log.info('user %s authenticating with:%s IS authenticated on func %s',
1679 log.info('user %s authenticating with:%s IS authenticated on func %s',
1663 user, reason, loc)
1680 user, reason, loc)
1664
1681
1665 return func(*fargs, **fkwargs)
1682 return func(*fargs, **fkwargs)
1666 else:
1683 else:
1667 log.warning(
1684 log.warning(
1668 'user %s authenticating with:%s NOT authenticated on '
1685 'user %s authenticating with:%s NOT authenticated on '
1669 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s',
1686 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s',
1670 user, reason, loc, ip_access_valid, auth_token_access_valid)
1687 user, reason, loc, ip_access_valid, auth_token_access_valid)
1671 # we preserve the get PARAM
1688 # we preserve the get PARAM
1672 came_from = get_came_from(request)
1689 came_from = get_came_from(request)
1673
1690
1674 log.debug('redirecting to login page with %s', came_from)
1691 log.debug('redirecting to login page with %s', came_from)
1675 raise HTTPFound(
1692 raise HTTPFound(
1676 h.route_path('login', _query={'came_from': came_from}))
1693 h.route_path('login', _query={'came_from': came_from}))
1677
1694
1678
1695
1679 class NotAnonymous(object):
1696 class NotAnonymous(object):
1680 """
1697 """
1681 Must be logged in to execute this function else
1698 Must be logged in to execute this function else
1682 redirect to login page
1699 redirect to login page
1683 """
1700 """
1684
1701
1685 def __call__(self, func):
1702 def __call__(self, func):
1686 return get_cython_compat_decorator(self.__wrapper, func)
1703 return get_cython_compat_decorator(self.__wrapper, func)
1687
1704
1688 def _get_request(self):
1705 def _get_request(self):
1689 return get_request(self)
1706 return get_request(self)
1690
1707
1691 def __wrapper(self, func, *fargs, **fkwargs):
1708 def __wrapper(self, func, *fargs, **fkwargs):
1692 import rhodecode.lib.helpers as h
1709 import rhodecode.lib.helpers as h
1693 cls = fargs[0]
1710 cls = fargs[0]
1694 self.user = cls._rhodecode_user
1711 self.user = cls._rhodecode_user
1695 request = self._get_request()
1712 request = self._get_request()
1696 _ = request.translate
1713 _ = request.translate
1697 log.debug('Checking if user is not anonymous @%s', cls)
1714 log.debug('Checking if user is not anonymous @%s', cls)
1698
1715
1699 anonymous = self.user.username == User.DEFAULT_USER
1716 anonymous = self.user.username == User.DEFAULT_USER
1700
1717
1701 if anonymous:
1718 if anonymous:
1702 came_from = get_came_from(request)
1719 came_from = get_came_from(request)
1703 h.flash(_('You need to be a registered user to '
1720 h.flash(_('You need to be a registered user to '
1704 'perform this action'),
1721 'perform this action'),
1705 category='warning')
1722 category='warning')
1706 raise HTTPFound(
1723 raise HTTPFound(
1707 h.route_path('login', _query={'came_from': came_from}))
1724 h.route_path('login', _query={'came_from': came_from}))
1708 else:
1725 else:
1709 return func(*fargs, **fkwargs)
1726 return func(*fargs, **fkwargs)
1710
1727
1711
1728
1712 class PermsDecorator(object):
1729 class PermsDecorator(object):
1713 """
1730 """
1714 Base class for controller decorators, we extract the current user from
1731 Base class for controller decorators, we extract the current user from
1715 the class itself, which has it stored in base controllers
1732 the class itself, which has it stored in base controllers
1716 """
1733 """
1717
1734
1718 def __init__(self, *required_perms):
1735 def __init__(self, *required_perms):
1719 self.required_perms = set(required_perms)
1736 self.required_perms = set(required_perms)
1720
1737
1721 def __call__(self, func):
1738 def __call__(self, func):
1722 return get_cython_compat_decorator(self.__wrapper, func)
1739 return get_cython_compat_decorator(self.__wrapper, func)
1723
1740
1724 def _get_request(self):
1741 def _get_request(self):
1725 return get_request(self)
1742 return get_request(self)
1726
1743
1727 def __wrapper(self, func, *fargs, **fkwargs):
1744 def __wrapper(self, func, *fargs, **fkwargs):
1728 import rhodecode.lib.helpers as h
1745 import rhodecode.lib.helpers as h
1729 cls = fargs[0]
1746 cls = fargs[0]
1730 _user = cls._rhodecode_user
1747 _user = cls._rhodecode_user
1731 request = self._get_request()
1748 request = self._get_request()
1732 _ = request.translate
1749 _ = request.translate
1733
1750
1734 log.debug('checking %s permissions %s for %s %s',
1751 log.debug('checking %s permissions %s for %s %s',
1735 self.__class__.__name__, self.required_perms, cls, _user)
1752 self.__class__.__name__, self.required_perms, cls, _user)
1736
1753
1737 if self.check_permissions(_user):
1754 if self.check_permissions(_user):
1738 log.debug('Permission granted for %s %s', cls, _user)
1755 log.debug('Permission granted for %s %s', cls, _user)
1739 return func(*fargs, **fkwargs)
1756 return func(*fargs, **fkwargs)
1740
1757
1741 else:
1758 else:
1742 log.debug('Permission denied for %s %s', cls, _user)
1759 log.debug('Permission denied for %s %s', cls, _user)
1743 anonymous = _user.username == User.DEFAULT_USER
1760 anonymous = _user.username == User.DEFAULT_USER
1744
1761
1745 if anonymous:
1762 if anonymous:
1746 came_from = get_came_from(self._get_request())
1763 came_from = get_came_from(self._get_request())
1747 h.flash(_('You need to be signed in to view this page'),
1764 h.flash(_('You need to be signed in to view this page'),
1748 category='warning')
1765 category='warning')
1749 raise HTTPFound(
1766 raise HTTPFound(
1750 h.route_path('login', _query={'came_from': came_from}))
1767 h.route_path('login', _query={'came_from': came_from}))
1751
1768
1752 else:
1769 else:
1753 # redirect with 404 to prevent resource discovery
1770 # redirect with 404 to prevent resource discovery
1754 raise HTTPNotFound()
1771 raise HTTPNotFound()
1755
1772
1756 def check_permissions(self, user):
1773 def check_permissions(self, user):
1757 """Dummy function for overriding"""
1774 """Dummy function for overriding"""
1758 raise NotImplementedError(
1775 raise NotImplementedError(
1759 'You have to write this function in child class')
1776 'You have to write this function in child class')
1760
1777
1761
1778
1762 class HasPermissionAllDecorator(PermsDecorator):
1779 class HasPermissionAllDecorator(PermsDecorator):
1763 """
1780 """
1764 Checks for access permission for all given predicates. All of them
1781 Checks for access permission for all given predicates. All of them
1765 have to be meet in order to fulfill the request
1782 have to be meet in order to fulfill the request
1766 """
1783 """
1767
1784
1768 def check_permissions(self, user):
1785 def check_permissions(self, user):
1769 perms = user.permissions_with_scope({})
1786 perms = user.permissions_with_scope({})
1770 if self.required_perms.issubset(perms['global']):
1787 if self.required_perms.issubset(perms['global']):
1771 return True
1788 return True
1772 return False
1789 return False
1773
1790
1774
1791
1775 class HasPermissionAnyDecorator(PermsDecorator):
1792 class HasPermissionAnyDecorator(PermsDecorator):
1776 """
1793 """
1777 Checks for access permission for any of given predicates. In order to
1794 Checks for access permission for any of given predicates. In order to
1778 fulfill the request any of predicates must be meet
1795 fulfill the request any of predicates must be meet
1779 """
1796 """
1780
1797
1781 def check_permissions(self, user):
1798 def check_permissions(self, user):
1782 perms = user.permissions_with_scope({})
1799 perms = user.permissions_with_scope({})
1783 if self.required_perms.intersection(perms['global']):
1800 if self.required_perms.intersection(perms['global']):
1784 return True
1801 return True
1785 return False
1802 return False
1786
1803
1787
1804
1788 class HasRepoPermissionAllDecorator(PermsDecorator):
1805 class HasRepoPermissionAllDecorator(PermsDecorator):
1789 """
1806 """
1790 Checks for access permission for all given predicates for specific
1807 Checks for access permission for all given predicates for specific
1791 repository. All of them have to be meet in order to fulfill the request
1808 repository. All of them have to be meet in order to fulfill the request
1792 """
1809 """
1793 def _get_repo_name(self):
1810 def _get_repo_name(self):
1794 _request = self._get_request()
1811 _request = self._get_request()
1795 return get_repo_slug(_request)
1812 return get_repo_slug(_request)
1796
1813
1797 def check_permissions(self, user):
1814 def check_permissions(self, user):
1798 perms = user.permissions
1815 perms = user.permissions
1799 repo_name = self._get_repo_name()
1816 repo_name = self._get_repo_name()
1800
1817
1801 try:
1818 try:
1802 user_perms = {perms['repositories'][repo_name]}
1819 user_perms = {perms['repositories'][repo_name]}
1803 except KeyError:
1820 except KeyError:
1804 log.debug('cannot locate repo with name: `%s` in permissions defs',
1821 log.debug('cannot locate repo with name: `%s` in permissions defs',
1805 repo_name)
1822 repo_name)
1806 return False
1823 return False
1807
1824
1808 log.debug('checking `%s` permissions for repo `%s`',
1825 log.debug('checking `%s` permissions for repo `%s`',
1809 user_perms, repo_name)
1826 user_perms, repo_name)
1810 if self.required_perms.issubset(user_perms):
1827 if self.required_perms.issubset(user_perms):
1811 return True
1828 return True
1812 return False
1829 return False
1813
1830
1814
1831
1815 class HasRepoPermissionAnyDecorator(PermsDecorator):
1832 class HasRepoPermissionAnyDecorator(PermsDecorator):
1816 """
1833 """
1817 Checks for access permission for any of given predicates for specific
1834 Checks for access permission for any of given predicates for specific
1818 repository. In order to fulfill the request any of predicates must be meet
1835 repository. In order to fulfill the request any of predicates must be meet
1819 """
1836 """
1820 def _get_repo_name(self):
1837 def _get_repo_name(self):
1821 _request = self._get_request()
1838 _request = self._get_request()
1822 return get_repo_slug(_request)
1839 return get_repo_slug(_request)
1823
1840
1824 def check_permissions(self, user):
1841 def check_permissions(self, user):
1825 perms = user.permissions
1842 perms = user.permissions
1826 repo_name = self._get_repo_name()
1843 repo_name = self._get_repo_name()
1827
1844
1828 try:
1845 try:
1829 user_perms = {perms['repositories'][repo_name]}
1846 user_perms = {perms['repositories'][repo_name]}
1830 except KeyError:
1847 except KeyError:
1831 log.debug(
1848 log.debug(
1832 'cannot locate repo with name: `%s` in permissions defs',
1849 'cannot locate repo with name: `%s` in permissions defs',
1833 repo_name)
1850 repo_name)
1834 return False
1851 return False
1835
1852
1836 log.debug('checking `%s` permissions for repo `%s`',
1853 log.debug('checking `%s` permissions for repo `%s`',
1837 user_perms, repo_name)
1854 user_perms, repo_name)
1838 if self.required_perms.intersection(user_perms):
1855 if self.required_perms.intersection(user_perms):
1839 return True
1856 return True
1840 return False
1857 return False
1841
1858
1842
1859
1843 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1860 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1844 """
1861 """
1845 Checks for access permission for all given predicates for specific
1862 Checks for access permission for all given predicates for specific
1846 repository group. All of them have to be meet in order to
1863 repository group. All of them have to be meet in order to
1847 fulfill the request
1864 fulfill the request
1848 """
1865 """
1849 def _get_repo_group_name(self):
1866 def _get_repo_group_name(self):
1850 _request = self._get_request()
1867 _request = self._get_request()
1851 return get_repo_group_slug(_request)
1868 return get_repo_group_slug(_request)
1852
1869
1853 def check_permissions(self, user):
1870 def check_permissions(self, user):
1854 perms = user.permissions
1871 perms = user.permissions
1855 group_name = self._get_repo_group_name()
1872 group_name = self._get_repo_group_name()
1856 try:
1873 try:
1857 user_perms = {perms['repositories_groups'][group_name]}
1874 user_perms = {perms['repositories_groups'][group_name]}
1858 except KeyError:
1875 except KeyError:
1859 log.debug(
1876 log.debug(
1860 'cannot locate repo group with name: `%s` in permissions defs',
1877 'cannot locate repo group with name: `%s` in permissions defs',
1861 group_name)
1878 group_name)
1862 return False
1879 return False
1863
1880
1864 log.debug('checking `%s` permissions for repo group `%s`',
1881 log.debug('checking `%s` permissions for repo group `%s`',
1865 user_perms, group_name)
1882 user_perms, group_name)
1866 if self.required_perms.issubset(user_perms):
1883 if self.required_perms.issubset(user_perms):
1867 return True
1884 return True
1868 return False
1885 return False
1869
1886
1870
1887
1871 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1888 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1872 """
1889 """
1873 Checks for access permission for any of given predicates for specific
1890 Checks for access permission for any of given predicates for specific
1874 repository group. In order to fulfill the request any
1891 repository group. In order to fulfill the request any
1875 of predicates must be met
1892 of predicates must be met
1876 """
1893 """
1877 def _get_repo_group_name(self):
1894 def _get_repo_group_name(self):
1878 _request = self._get_request()
1895 _request = self._get_request()
1879 return get_repo_group_slug(_request)
1896 return get_repo_group_slug(_request)
1880
1897
1881 def check_permissions(self, user):
1898 def check_permissions(self, user):
1882 perms = user.permissions
1899 perms = user.permissions
1883 group_name = self._get_repo_group_name()
1900 group_name = self._get_repo_group_name()
1884
1901
1885 try:
1902 try:
1886 user_perms = {perms['repositories_groups'][group_name]}
1903 user_perms = {perms['repositories_groups'][group_name]}
1887 except KeyError:
1904 except KeyError:
1888 log.debug(
1905 log.debug(
1889 'cannot locate repo group with name: `%s` in permissions defs',
1906 'cannot locate repo group with name: `%s` in permissions defs',
1890 group_name)
1907 group_name)
1891 return False
1908 return False
1892
1909
1893 log.debug('checking `%s` permissions for repo group `%s`',
1910 log.debug('checking `%s` permissions for repo group `%s`',
1894 user_perms, group_name)
1911 user_perms, group_name)
1895 if self.required_perms.intersection(user_perms):
1912 if self.required_perms.intersection(user_perms):
1896 return True
1913 return True
1897 return False
1914 return False
1898
1915
1899
1916
1900 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1917 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1901 """
1918 """
1902 Checks for access permission for all given predicates for specific
1919 Checks for access permission for all given predicates for specific
1903 user group. All of them have to be meet in order to fulfill the request
1920 user group. All of them have to be meet in order to fulfill the request
1904 """
1921 """
1905 def _get_user_group_name(self):
1922 def _get_user_group_name(self):
1906 _request = self._get_request()
1923 _request = self._get_request()
1907 return get_user_group_slug(_request)
1924 return get_user_group_slug(_request)
1908
1925
1909 def check_permissions(self, user):
1926 def check_permissions(self, user):
1910 perms = user.permissions
1927 perms = user.permissions
1911 group_name = self._get_user_group_name()
1928 group_name = self._get_user_group_name()
1912 try:
1929 try:
1913 user_perms = {perms['user_groups'][group_name]}
1930 user_perms = {perms['user_groups'][group_name]}
1914 except KeyError:
1931 except KeyError:
1915 return False
1932 return False
1916
1933
1917 if self.required_perms.issubset(user_perms):
1934 if self.required_perms.issubset(user_perms):
1918 return True
1935 return True
1919 return False
1936 return False
1920
1937
1921
1938
1922 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1939 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1923 """
1940 """
1924 Checks for access permission for any of given predicates for specific
1941 Checks for access permission for any of given predicates for specific
1925 user group. In order to fulfill the request any of predicates must be meet
1942 user group. In order to fulfill the request any of predicates must be meet
1926 """
1943 """
1927 def _get_user_group_name(self):
1944 def _get_user_group_name(self):
1928 _request = self._get_request()
1945 _request = self._get_request()
1929 return get_user_group_slug(_request)
1946 return get_user_group_slug(_request)
1930
1947
1931 def check_permissions(self, user):
1948 def check_permissions(self, user):
1932 perms = user.permissions
1949 perms = user.permissions
1933 group_name = self._get_user_group_name()
1950 group_name = self._get_user_group_name()
1934 try:
1951 try:
1935 user_perms = {perms['user_groups'][group_name]}
1952 user_perms = {perms['user_groups'][group_name]}
1936 except KeyError:
1953 except KeyError:
1937 return False
1954 return False
1938
1955
1939 if self.required_perms.intersection(user_perms):
1956 if self.required_perms.intersection(user_perms):
1940 return True
1957 return True
1941 return False
1958 return False
1942
1959
1943
1960
1944 # CHECK FUNCTIONS
1961 # CHECK FUNCTIONS
1945 class PermsFunction(object):
1962 class PermsFunction(object):
1946 """Base function for other check functions"""
1963 """Base function for other check functions"""
1947
1964
1948 def __init__(self, *perms):
1965 def __init__(self, *perms):
1949 self.required_perms = set(perms)
1966 self.required_perms = set(perms)
1950 self.repo_name = None
1967 self.repo_name = None
1951 self.repo_group_name = None
1968 self.repo_group_name = None
1952 self.user_group_name = None
1969 self.user_group_name = None
1953
1970
1954 def __bool__(self):
1971 def __bool__(self):
1955 frame = inspect.currentframe()
1972 frame = inspect.currentframe()
1956 stack_trace = traceback.format_stack(frame)
1973 stack_trace = traceback.format_stack(frame)
1957 log.error('Checking bool value on a class instance of perm '
1974 log.error('Checking bool value on a class instance of perm '
1958 'function is not allowed: %s', ''.join(stack_trace))
1975 'function is not allowed: %s', ''.join(stack_trace))
1959 # rather than throwing errors, here we always return False so if by
1976 # rather than throwing errors, here we always return False so if by
1960 # accident someone checks truth for just an instance it will always end
1977 # accident someone checks truth for just an instance it will always end
1961 # up in returning False
1978 # up in returning False
1962 return False
1979 return False
1963 __nonzero__ = __bool__
1980 __nonzero__ = __bool__
1964
1981
1965 def __call__(self, check_location='', user=None):
1982 def __call__(self, check_location='', user=None):
1966 if not user:
1983 if not user:
1967 log.debug('Using user attribute from global request')
1984 log.debug('Using user attribute from global request')
1968 request = self._get_request()
1985 request = self._get_request()
1969 user = request.user
1986 user = request.user
1970
1987
1971 # init auth user if not already given
1988 # init auth user if not already given
1972 if not isinstance(user, AuthUser):
1989 if not isinstance(user, AuthUser):
1973 log.debug('Wrapping user %s into AuthUser', user)
1990 log.debug('Wrapping user %s into AuthUser', user)
1974 user = AuthUser(user.user_id)
1991 user = AuthUser(user.user_id)
1975
1992
1976 cls_name = self.__class__.__name__
1993 cls_name = self.__class__.__name__
1977 check_scope = self._get_check_scope(cls_name)
1994 check_scope = self._get_check_scope(cls_name)
1978 check_location = check_location or 'unspecified location'
1995 check_location = check_location or 'unspecified location'
1979
1996
1980 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1997 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1981 self.required_perms, user, check_scope, check_location)
1998 self.required_perms, user, check_scope, check_location)
1982 if not user:
1999 if not user:
1983 log.warning('Empty user given for permission check')
2000 log.warning('Empty user given for permission check')
1984 return False
2001 return False
1985
2002
1986 if self.check_permissions(user):
2003 if self.check_permissions(user):
1987 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2004 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1988 check_scope, user, check_location)
2005 check_scope, user, check_location)
1989 return True
2006 return True
1990
2007
1991 else:
2008 else:
1992 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2009 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1993 check_scope, user, check_location)
2010 check_scope, user, check_location)
1994 return False
2011 return False
1995
2012
1996 def _get_request(self):
2013 def _get_request(self):
1997 return get_request(self)
2014 return get_request(self)
1998
2015
1999 def _get_check_scope(self, cls_name):
2016 def _get_check_scope(self, cls_name):
2000 return {
2017 return {
2001 'HasPermissionAll': 'GLOBAL',
2018 'HasPermissionAll': 'GLOBAL',
2002 'HasPermissionAny': 'GLOBAL',
2019 'HasPermissionAny': 'GLOBAL',
2003 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
2020 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
2004 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
2021 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
2005 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
2022 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
2006 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
2023 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
2007 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
2024 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
2008 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
2025 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
2009 }.get(cls_name, '?:%s' % cls_name)
2026 }.get(cls_name, '?:%s' % cls_name)
2010
2027
2011 def check_permissions(self, user):
2028 def check_permissions(self, user):
2012 """Dummy function for overriding"""
2029 """Dummy function for overriding"""
2013 raise Exception('You have to write this function in child class')
2030 raise Exception('You have to write this function in child class')
2014
2031
2015
2032
2016 class HasPermissionAll(PermsFunction):
2033 class HasPermissionAll(PermsFunction):
2017 def check_permissions(self, user):
2034 def check_permissions(self, user):
2018 perms = user.permissions_with_scope({})
2035 perms = user.permissions_with_scope({})
2019 if self.required_perms.issubset(perms.get('global')):
2036 if self.required_perms.issubset(perms.get('global')):
2020 return True
2037 return True
2021 return False
2038 return False
2022
2039
2023
2040
2024 class HasPermissionAny(PermsFunction):
2041 class HasPermissionAny(PermsFunction):
2025 def check_permissions(self, user):
2042 def check_permissions(self, user):
2026 perms = user.permissions_with_scope({})
2043 perms = user.permissions_with_scope({})
2027 if self.required_perms.intersection(perms.get('global')):
2044 if self.required_perms.intersection(perms.get('global')):
2028 return True
2045 return True
2029 return False
2046 return False
2030
2047
2031
2048
2032 class HasRepoPermissionAll(PermsFunction):
2049 class HasRepoPermissionAll(PermsFunction):
2033 def __call__(self, repo_name=None, check_location='', user=None):
2050 def __call__(self, repo_name=None, check_location='', user=None):
2034 self.repo_name = repo_name
2051 self.repo_name = repo_name
2035 return super(HasRepoPermissionAll, self).__call__(check_location, user)
2052 return super(HasRepoPermissionAll, self).__call__(check_location, user)
2036
2053
2037 def _get_repo_name(self):
2054 def _get_repo_name(self):
2038 if not self.repo_name:
2055 if not self.repo_name:
2039 _request = self._get_request()
2056 _request = self._get_request()
2040 self.repo_name = get_repo_slug(_request)
2057 self.repo_name = get_repo_slug(_request)
2041 return self.repo_name
2058 return self.repo_name
2042
2059
2043 def check_permissions(self, user):
2060 def check_permissions(self, user):
2044 self.repo_name = self._get_repo_name()
2061 self.repo_name = self._get_repo_name()
2045 perms = user.permissions
2062 perms = user.permissions
2046 try:
2063 try:
2047 user_perms = {perms['repositories'][self.repo_name]}
2064 user_perms = {perms['repositories'][self.repo_name]}
2048 except KeyError:
2065 except KeyError:
2049 return False
2066 return False
2050 if self.required_perms.issubset(user_perms):
2067 if self.required_perms.issubset(user_perms):
2051 return True
2068 return True
2052 return False
2069 return False
2053
2070
2054
2071
2055 class HasRepoPermissionAny(PermsFunction):
2072 class HasRepoPermissionAny(PermsFunction):
2056 def __call__(self, repo_name=None, check_location='', user=None):
2073 def __call__(self, repo_name=None, check_location='', user=None):
2057 self.repo_name = repo_name
2074 self.repo_name = repo_name
2058 return super(HasRepoPermissionAny, self).__call__(check_location, user)
2075 return super(HasRepoPermissionAny, self).__call__(check_location, user)
2059
2076
2060 def _get_repo_name(self):
2077 def _get_repo_name(self):
2061 if not self.repo_name:
2078 if not self.repo_name:
2062 _request = self._get_request()
2079 _request = self._get_request()
2063 self.repo_name = get_repo_slug(_request)
2080 self.repo_name = get_repo_slug(_request)
2064 return self.repo_name
2081 return self.repo_name
2065
2082
2066 def check_permissions(self, user):
2083 def check_permissions(self, user):
2067 self.repo_name = self._get_repo_name()
2084 self.repo_name = self._get_repo_name()
2068 perms = user.permissions
2085 perms = user.permissions
2069 try:
2086 try:
2070 user_perms = {perms['repositories'][self.repo_name]}
2087 user_perms = {perms['repositories'][self.repo_name]}
2071 except KeyError:
2088 except KeyError:
2072 return False
2089 return False
2073 if self.required_perms.intersection(user_perms):
2090 if self.required_perms.intersection(user_perms):
2074 return True
2091 return True
2075 return False
2092 return False
2076
2093
2077
2094
2078 class HasRepoGroupPermissionAny(PermsFunction):
2095 class HasRepoGroupPermissionAny(PermsFunction):
2079 def __call__(self, group_name=None, check_location='', user=None):
2096 def __call__(self, group_name=None, check_location='', user=None):
2080 self.repo_group_name = group_name
2097 self.repo_group_name = group_name
2081 return super(HasRepoGroupPermissionAny, self).__call__(check_location, user)
2098 return super(HasRepoGroupPermissionAny, self).__call__(check_location, user)
2082
2099
2083 def check_permissions(self, user):
2100 def check_permissions(self, user):
2084 perms = user.permissions
2101 perms = user.permissions
2085 try:
2102 try:
2086 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2103 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2087 except KeyError:
2104 except KeyError:
2088 return False
2105 return False
2089 if self.required_perms.intersection(user_perms):
2106 if self.required_perms.intersection(user_perms):
2090 return True
2107 return True
2091 return False
2108 return False
2092
2109
2093
2110
2094 class HasRepoGroupPermissionAll(PermsFunction):
2111 class HasRepoGroupPermissionAll(PermsFunction):
2095 def __call__(self, group_name=None, check_location='', user=None):
2112 def __call__(self, group_name=None, check_location='', user=None):
2096 self.repo_group_name = group_name
2113 self.repo_group_name = group_name
2097 return super(HasRepoGroupPermissionAll, self).__call__(check_location, user)
2114 return super(HasRepoGroupPermissionAll, self).__call__(check_location, user)
2098
2115
2099 def check_permissions(self, user):
2116 def check_permissions(self, user):
2100 perms = user.permissions
2117 perms = user.permissions
2101 try:
2118 try:
2102 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2119 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2103 except KeyError:
2120 except KeyError:
2104 return False
2121 return False
2105 if self.required_perms.issubset(user_perms):
2122 if self.required_perms.issubset(user_perms):
2106 return True
2123 return True
2107 return False
2124 return False
2108
2125
2109
2126
2110 class HasUserGroupPermissionAny(PermsFunction):
2127 class HasUserGroupPermissionAny(PermsFunction):
2111 def __call__(self, user_group_name=None, check_location='', user=None):
2128 def __call__(self, user_group_name=None, check_location='', user=None):
2112 self.user_group_name = user_group_name
2129 self.user_group_name = user_group_name
2113 return super(HasUserGroupPermissionAny, self).__call__(check_location, user)
2130 return super(HasUserGroupPermissionAny, self).__call__(check_location, user)
2114
2131
2115 def check_permissions(self, user):
2132 def check_permissions(self, user):
2116 perms = user.permissions
2133 perms = user.permissions
2117 try:
2134 try:
2118 user_perms = {perms['user_groups'][self.user_group_name]}
2135 user_perms = {perms['user_groups'][self.user_group_name]}
2119 except KeyError:
2136 except KeyError:
2120 return False
2137 return False
2121 if self.required_perms.intersection(user_perms):
2138 if self.required_perms.intersection(user_perms):
2122 return True
2139 return True
2123 return False
2140 return False
2124
2141
2125
2142
2126 class HasUserGroupPermissionAll(PermsFunction):
2143 class HasUserGroupPermissionAll(PermsFunction):
2127 def __call__(self, user_group_name=None, check_location='', user=None):
2144 def __call__(self, user_group_name=None, check_location='', user=None):
2128 self.user_group_name = user_group_name
2145 self.user_group_name = user_group_name
2129 return super(HasUserGroupPermissionAll, self).__call__(check_location, user)
2146 return super(HasUserGroupPermissionAll, self).__call__(check_location, user)
2130
2147
2131 def check_permissions(self, user):
2148 def check_permissions(self, user):
2132 perms = user.permissions
2149 perms = user.permissions
2133 try:
2150 try:
2134 user_perms = {perms['user_groups'][self.user_group_name]}
2151 user_perms = {perms['user_groups'][self.user_group_name]}
2135 except KeyError:
2152 except KeyError:
2136 return False
2153 return False
2137 if self.required_perms.issubset(user_perms):
2154 if self.required_perms.issubset(user_perms):
2138 return True
2155 return True
2139 return False
2156 return False
2140
2157
2141
2158
2142 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
2159 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
2143 class HasPermissionAnyMiddleware(object):
2160 class HasPermissionAnyMiddleware(object):
2144 def __init__(self, *perms):
2161 def __init__(self, *perms):
2145 self.required_perms = set(perms)
2162 self.required_perms = set(perms)
2146
2163
2147 def __call__(self, auth_user, repo_name):
2164 def __call__(self, auth_user, repo_name):
2148 # repo_name MUST be unicode, since we handle keys in permission
2165 # repo_name MUST be unicode, since we handle keys in permission
2149 # dict by unicode
2166 # dict by unicode
2150 repo_name = safe_unicode(repo_name)
2167 repo_name = safe_unicode(repo_name)
2151 log.debug(
2168 log.debug(
2152 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
2169 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
2153 self.required_perms, auth_user, repo_name)
2170 self.required_perms, auth_user, repo_name)
2154
2171
2155 if self.check_permissions(auth_user, repo_name):
2172 if self.check_permissions(auth_user, repo_name):
2156 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
2173 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
2157 repo_name, auth_user, 'PermissionMiddleware')
2174 repo_name, auth_user, 'PermissionMiddleware')
2158 return True
2175 return True
2159
2176
2160 else:
2177 else:
2161 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
2178 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
2162 repo_name, auth_user, 'PermissionMiddleware')
2179 repo_name, auth_user, 'PermissionMiddleware')
2163 return False
2180 return False
2164
2181
2165 def check_permissions(self, user, repo_name):
2182 def check_permissions(self, user, repo_name):
2166 perms = user.permissions_with_scope({'repo_name': repo_name})
2183 perms = user.permissions_with_scope({'repo_name': repo_name})
2167
2184
2168 try:
2185 try:
2169 user_perms = {perms['repositories'][repo_name]}
2186 user_perms = {perms['repositories'][repo_name]}
2170 except Exception:
2187 except Exception:
2171 log.exception('Error while accessing user permissions')
2188 log.exception('Error while accessing user permissions')
2172 return False
2189 return False
2173
2190
2174 if self.required_perms.intersection(user_perms):
2191 if self.required_perms.intersection(user_perms):
2175 return True
2192 return True
2176 return False
2193 return False
2177
2194
2178
2195
2179 # SPECIAL VERSION TO HANDLE API AUTH
2196 # SPECIAL VERSION TO HANDLE API AUTH
2180 class _BaseApiPerm(object):
2197 class _BaseApiPerm(object):
2181 def __init__(self, *perms):
2198 def __init__(self, *perms):
2182 self.required_perms = set(perms)
2199 self.required_perms = set(perms)
2183
2200
2184 def __call__(self, check_location=None, user=None, repo_name=None,
2201 def __call__(self, check_location=None, user=None, repo_name=None,
2185 group_name=None, user_group_name=None):
2202 group_name=None, user_group_name=None):
2186 cls_name = self.__class__.__name__
2203 cls_name = self.__class__.__name__
2187 check_scope = 'global:%s' % (self.required_perms,)
2204 check_scope = 'global:%s' % (self.required_perms,)
2188 if repo_name:
2205 if repo_name:
2189 check_scope += ', repo_name:%s' % (repo_name,)
2206 check_scope += ', repo_name:%s' % (repo_name,)
2190
2207
2191 if group_name:
2208 if group_name:
2192 check_scope += ', repo_group_name:%s' % (group_name,)
2209 check_scope += ', repo_group_name:%s' % (group_name,)
2193
2210
2194 if user_group_name:
2211 if user_group_name:
2195 check_scope += ', user_group_name:%s' % (user_group_name,)
2212 check_scope += ', user_group_name:%s' % (user_group_name,)
2196
2213
2197 log.debug('checking cls:%s %s %s @ %s',
2214 log.debug('checking cls:%s %s %s @ %s',
2198 cls_name, self.required_perms, check_scope, check_location)
2215 cls_name, self.required_perms, check_scope, check_location)
2199 if not user:
2216 if not user:
2200 log.debug('Empty User passed into arguments')
2217 log.debug('Empty User passed into arguments')
2201 return False
2218 return False
2202
2219
2203 # process user
2220 # process user
2204 if not isinstance(user, AuthUser):
2221 if not isinstance(user, AuthUser):
2205 user = AuthUser(user.user_id)
2222 user = AuthUser(user.user_id)
2206 if not check_location:
2223 if not check_location:
2207 check_location = 'unspecified'
2224 check_location = 'unspecified'
2208 if self.check_permissions(user.permissions, repo_name, group_name,
2225 if self.check_permissions(user.permissions, repo_name, group_name,
2209 user_group_name):
2226 user_group_name):
2210 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2227 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2211 check_scope, user, check_location)
2228 check_scope, user, check_location)
2212 return True
2229 return True
2213
2230
2214 else:
2231 else:
2215 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2232 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2216 check_scope, user, check_location)
2233 check_scope, user, check_location)
2217 return False
2234 return False
2218
2235
2219 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2236 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2220 user_group_name=None):
2237 user_group_name=None):
2221 """
2238 """
2222 implement in child class should return True if permissions are ok,
2239 implement in child class should return True if permissions are ok,
2223 False otherwise
2240 False otherwise
2224
2241
2225 :param perm_defs: dict with permission definitions
2242 :param perm_defs: dict with permission definitions
2226 :param repo_name: repo name
2243 :param repo_name: repo name
2227 """
2244 """
2228 raise NotImplementedError()
2245 raise NotImplementedError()
2229
2246
2230
2247
2231 class HasPermissionAllApi(_BaseApiPerm):
2248 class HasPermissionAllApi(_BaseApiPerm):
2232 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2249 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2233 user_group_name=None):
2250 user_group_name=None):
2234 if self.required_perms.issubset(perm_defs.get('global')):
2251 if self.required_perms.issubset(perm_defs.get('global')):
2235 return True
2252 return True
2236 return False
2253 return False
2237
2254
2238
2255
2239 class HasPermissionAnyApi(_BaseApiPerm):
2256 class HasPermissionAnyApi(_BaseApiPerm):
2240 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2257 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2241 user_group_name=None):
2258 user_group_name=None):
2242 if self.required_perms.intersection(perm_defs.get('global')):
2259 if self.required_perms.intersection(perm_defs.get('global')):
2243 return True
2260 return True
2244 return False
2261 return False
2245
2262
2246
2263
2247 class HasRepoPermissionAllApi(_BaseApiPerm):
2264 class HasRepoPermissionAllApi(_BaseApiPerm):
2248 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2265 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2249 user_group_name=None):
2266 user_group_name=None):
2250 try:
2267 try:
2251 _user_perms = {perm_defs['repositories'][repo_name]}
2268 _user_perms = {perm_defs['repositories'][repo_name]}
2252 except KeyError:
2269 except KeyError:
2253 log.warning(traceback.format_exc())
2270 log.warning(traceback.format_exc())
2254 return False
2271 return False
2255 if self.required_perms.issubset(_user_perms):
2272 if self.required_perms.issubset(_user_perms):
2256 return True
2273 return True
2257 return False
2274 return False
2258
2275
2259
2276
2260 class HasRepoPermissionAnyApi(_BaseApiPerm):
2277 class HasRepoPermissionAnyApi(_BaseApiPerm):
2261 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2278 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2262 user_group_name=None):
2279 user_group_name=None):
2263 try:
2280 try:
2264 _user_perms = {perm_defs['repositories'][repo_name]}
2281 _user_perms = {perm_defs['repositories'][repo_name]}
2265 except KeyError:
2282 except KeyError:
2266 log.warning(traceback.format_exc())
2283 log.warning(traceback.format_exc())
2267 return False
2284 return False
2268 if self.required_perms.intersection(_user_perms):
2285 if self.required_perms.intersection(_user_perms):
2269 return True
2286 return True
2270 return False
2287 return False
2271
2288
2272
2289
2273 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2290 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2274 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2291 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2275 user_group_name=None):
2292 user_group_name=None):
2276 try:
2293 try:
2277 _user_perms = {perm_defs['repositories_groups'][group_name]}
2294 _user_perms = {perm_defs['repositories_groups'][group_name]}
2278 except KeyError:
2295 except KeyError:
2279 log.warning(traceback.format_exc())
2296 log.warning(traceback.format_exc())
2280 return False
2297 return False
2281 if self.required_perms.intersection(_user_perms):
2298 if self.required_perms.intersection(_user_perms):
2282 return True
2299 return True
2283 return False
2300 return False
2284
2301
2285
2302
2286 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2303 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2287 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2304 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2288 user_group_name=None):
2305 user_group_name=None):
2289 try:
2306 try:
2290 _user_perms = {perm_defs['repositories_groups'][group_name]}
2307 _user_perms = {perm_defs['repositories_groups'][group_name]}
2291 except KeyError:
2308 except KeyError:
2292 log.warning(traceback.format_exc())
2309 log.warning(traceback.format_exc())
2293 return False
2310 return False
2294 if self.required_perms.issubset(_user_perms):
2311 if self.required_perms.issubset(_user_perms):
2295 return True
2312 return True
2296 return False
2313 return False
2297
2314
2298
2315
2299 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2316 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2300 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2317 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2301 user_group_name=None):
2318 user_group_name=None):
2302 try:
2319 try:
2303 _user_perms = {perm_defs['user_groups'][user_group_name]}
2320 _user_perms = {perm_defs['user_groups'][user_group_name]}
2304 except KeyError:
2321 except KeyError:
2305 log.warning(traceback.format_exc())
2322 log.warning(traceback.format_exc())
2306 return False
2323 return False
2307 if self.required_perms.intersection(_user_perms):
2324 if self.required_perms.intersection(_user_perms):
2308 return True
2325 return True
2309 return False
2326 return False
2310
2327
2311
2328
2312 def check_ip_access(source_ip, allowed_ips=None):
2329 def check_ip_access(source_ip, allowed_ips=None):
2313 """
2330 """
2314 Checks if source_ip is a subnet of any of allowed_ips.
2331 Checks if source_ip is a subnet of any of allowed_ips.
2315
2332
2316 :param source_ip:
2333 :param source_ip:
2317 :param allowed_ips: list of allowed ips together with mask
2334 :param allowed_ips: list of allowed ips together with mask
2318 """
2335 """
2319 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
2336 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
2320 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2337 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2321 if isinstance(allowed_ips, (tuple, list, set)):
2338 if isinstance(allowed_ips, (tuple, list, set)):
2322 for ip in allowed_ips:
2339 for ip in allowed_ips:
2323 ip = safe_unicode(ip)
2340 ip = safe_unicode(ip)
2324 try:
2341 try:
2325 network_address = ipaddress.ip_network(ip, strict=False)
2342 network_address = ipaddress.ip_network(ip, strict=False)
2326 if source_ip_address in network_address:
2343 if source_ip_address in network_address:
2327 log.debug('IP %s is network %s', source_ip_address, network_address)
2344 log.debug('IP %s is network %s', source_ip_address, network_address)
2328 return True
2345 return True
2329 # for any case we cannot determine the IP, don't crash just
2346 # for any case we cannot determine the IP, don't crash just
2330 # skip it and log as error, we want to say forbidden still when
2347 # skip it and log as error, we want to say forbidden still when
2331 # sending bad IP
2348 # sending bad IP
2332 except Exception:
2349 except Exception:
2333 log.error(traceback.format_exc())
2350 log.error(traceback.format_exc())
2334 continue
2351 continue
2335 return False
2352 return False
2336
2353
2337
2354
2338 def get_cython_compat_decorator(wrapper, func):
2355 def get_cython_compat_decorator(wrapper, func):
2339 """
2356 """
2340 Creates a cython compatible decorator. The previously used
2357 Creates a cython compatible decorator. The previously used
2341 decorator.decorator() function seems to be incompatible with cython.
2358 decorator.decorator() function seems to be incompatible with cython.
2342
2359
2343 :param wrapper: __wrapper method of the decorator class
2360 :param wrapper: __wrapper method of the decorator class
2344 :param func: decorated function
2361 :param func: decorated function
2345 """
2362 """
2346 @wraps(func)
2363 @wraps(func)
2347 def local_wrapper(*args, **kwds):
2364 def local_wrapper(*args, **kwds):
2348 return wrapper(func, *args, **kwds)
2365 return wrapper(func, *args, **kwds)
2349 local_wrapper.__wrapped__ = func
2366 local_wrapper.__wrapped__ = func
2350 return local_wrapper
2367 return local_wrapper
2351
2368
2352
2369
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,381 +1,382 b''
1
1
2 /******************************************************************************
2 /******************************************************************************
3 * *
3 * *
4 * DO NOT CHANGE THIS FILE MANUALLY *
4 * DO NOT CHANGE THIS FILE MANUALLY *
5 * *
5 * *
6 * *
6 * *
7 * This file is automatically generated when the app starts up with *
7 * This file is automatically generated when the app starts up with *
8 * generate_js_files = true *
8 * generate_js_files = true *
9 * *
9 * *
10 * To add a route here pass jsroute=True to the route definition in the app *
10 * To add a route here pass jsroute=True to the route definition in the app *
11 * *
11 * *
12 ******************************************************************************/
12 ******************************************************************************/
13 function registerRCRoutes() {
13 function registerRCRoutes() {
14 // routes registration
14 // routes registration
15 pyroutes.register('favicon', '/favicon.ico', []);
15 pyroutes.register('favicon', '/favicon.ico', []);
16 pyroutes.register('robots', '/robots.txt', []);
16 pyroutes.register('robots', '/robots.txt', []);
17 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
17 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
18 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
18 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
19 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
19 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
20 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
20 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
21 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
21 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
22 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
22 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
23 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
24 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
24 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
25 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
26 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
26 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
27 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
27 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
28 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
28 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
29 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
29 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
30 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
32 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
32 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
38 pyroutes.register('admin_home', '/_admin', []);
38 pyroutes.register('admin_home', '/_admin', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
95 pyroutes.register('users', '/_admin/users', []);
95 pyroutes.register('users', '/_admin/users', []);
96 pyroutes.register('users_data', '/_admin/users_data', []);
96 pyroutes.register('users_data', '/_admin/users_data', []);
97 pyroutes.register('users_create', '/_admin/users/create', []);
97 pyroutes.register('users_create', '/_admin/users/create', []);
98 pyroutes.register('users_new', '/_admin/users/new', []);
98 pyroutes.register('users_new', '/_admin/users/new', []);
99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
105 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
105 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
106 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
106 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
107 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
107 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
108 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
108 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
109 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
109 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
110 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
110 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
111 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
111 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
112 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
112 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
113 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
113 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
114 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
114 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
115 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
115 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
116 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
116 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
117 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
117 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
118 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
118 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
119 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
119 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
120 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
120 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
121 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
121 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
122 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
122 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
123 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
123 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
124 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
124 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
125 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
125 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
126 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
126 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
127 pyroutes.register('user_groups', '/_admin/user_groups', []);
127 pyroutes.register('user_groups', '/_admin/user_groups', []);
128 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
128 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
129 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
129 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
130 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
130 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
131 pyroutes.register('repos', '/_admin/repos', []);
131 pyroutes.register('repos', '/_admin/repos', []);
132 pyroutes.register('repo_new', '/_admin/repos/new', []);
132 pyroutes.register('repo_new', '/_admin/repos/new', []);
133 pyroutes.register('repo_create', '/_admin/repos/create', []);
133 pyroutes.register('repo_create', '/_admin/repos/create', []);
134 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
134 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
135 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
135 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
136 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
136 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
137 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
137 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
138 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
138 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
139 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
139 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
140 pyroutes.register('channelstream_proxy', '/_channelstream', []);
140 pyroutes.register('channelstream_proxy', '/_channelstream', []);
141 pyroutes.register('upload_file', '/_file_store/upload', []);
141 pyroutes.register('upload_file', '/_file_store/upload', []);
142 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
142 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
143 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
143 pyroutes.register('logout', '/_admin/logout', []);
144 pyroutes.register('logout', '/_admin/logout', []);
144 pyroutes.register('reset_password', '/_admin/password_reset', []);
145 pyroutes.register('reset_password', '/_admin/password_reset', []);
145 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
146 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
146 pyroutes.register('home', '/', []);
147 pyroutes.register('home', '/', []);
147 pyroutes.register('user_autocomplete_data', '/_users', []);
148 pyroutes.register('user_autocomplete_data', '/_users', []);
148 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
149 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
149 pyroutes.register('repo_list_data', '/_repos', []);
150 pyroutes.register('repo_list_data', '/_repos', []);
150 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
151 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
151 pyroutes.register('goto_switcher_data', '/_goto_data', []);
152 pyroutes.register('goto_switcher_data', '/_goto_data', []);
152 pyroutes.register('markup_preview', '/_markup_preview', []);
153 pyroutes.register('markup_preview', '/_markup_preview', []);
153 pyroutes.register('file_preview', '/_file_preview', []);
154 pyroutes.register('file_preview', '/_file_preview', []);
154 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
155 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
155 pyroutes.register('journal', '/_admin/journal', []);
156 pyroutes.register('journal', '/_admin/journal', []);
156 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
157 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
157 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
158 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
158 pyroutes.register('journal_public', '/_admin/public_journal', []);
159 pyroutes.register('journal_public', '/_admin/public_journal', []);
159 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
160 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
160 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
161 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
161 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
162 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
162 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
163 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
163 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
164 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
164 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
165 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
165 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
166 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
166 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
167 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
167 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
168 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
168 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
170 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
170 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
171 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
171 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
172 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
172 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
173 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
173 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
174 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
174 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
175 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
175 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
176 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
176 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
177 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
177 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
178 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
178 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
179 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
179 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
180 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
180 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
181 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
181 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
182 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
182 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
183 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
183 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
184 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
184 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
185 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
185 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
186 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
186 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
189 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
189 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
191 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
191 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
199 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
199 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
201 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
201 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
203 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
203 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
204 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
204 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
205 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
205 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
206 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
206 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
207 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
207 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
208 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
208 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
209 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
209 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
210 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
210 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
211 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
211 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
212 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
212 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
213 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
213 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
214 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
214 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
215 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
215 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
216 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
216 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
217 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
217 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
218 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
218 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
219 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
219 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
220 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
220 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
221 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
221 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
222 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
222 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
223 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
223 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
224 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
224 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
225 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
225 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
226 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
226 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
227 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
227 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
228 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
228 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
229 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
229 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
230 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
230 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
231 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
231 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
232 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
232 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
233 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
233 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
234 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
234 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
235 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
235 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
236 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
236 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
237 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
237 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
238 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
238 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
239 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
239 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
240 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
240 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
241 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
241 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
242 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
242 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
243 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
243 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
244 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
244 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
245 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
245 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
246 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
246 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
247 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
247 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
248 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
248 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
249 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
249 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
250 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
250 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
251 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
251 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
252 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
252 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
253 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
253 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
254 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
254 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
255 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
255 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
256 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
256 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
257 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
257 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
258 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
258 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
259 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
259 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
260 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
260 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
261 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
261 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
262 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
262 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
263 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
263 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
264 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
264 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
265 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
265 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
266 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
266 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
267 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
267 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
268 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
268 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
269 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
269 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
270 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
270 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
271 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
271 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
272 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
272 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
273 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
273 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
274 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
274 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
275 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
275 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
276 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
276 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
277 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
277 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
278 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
278 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
279 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
279 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
280 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
280 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
281 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
281 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
282 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
282 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
283 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
283 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
284 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
284 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
285 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
285 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
286 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
286 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
287 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
287 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
288 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
288 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
289 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
289 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
290 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
290 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
291 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
291 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
292 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
292 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
293 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
293 pyroutes.register('search', '/_admin/search', []);
294 pyroutes.register('search', '/_admin/search', []);
294 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
295 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
295 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
296 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
296 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
297 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
297 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
298 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
298 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
299 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
299 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
300 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
300 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
301 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
301 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
302 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
302 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
303 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
303 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
304 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
304 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
305 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
305 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
306 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
306 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
307 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
307 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
308 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
308 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
309 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
309 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
310 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
310 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
311 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
311 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
312 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
312 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
313 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
313 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
314 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
314 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
315 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
315 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
316 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
316 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
317 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
317 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
318 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
318 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
319 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
319 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
320 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
320 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
321 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
321 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
322 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
322 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
323 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
323 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
324 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
324 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
325 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
325 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
326 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
326 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
327 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
327 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
328 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
328 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
329 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
329 pyroutes.register('gists_show', '/_admin/gists', []);
330 pyroutes.register('gists_show', '/_admin/gists', []);
330 pyroutes.register('gists_new', '/_admin/gists/new', []);
331 pyroutes.register('gists_new', '/_admin/gists/new', []);
331 pyroutes.register('gists_create', '/_admin/gists/create', []);
332 pyroutes.register('gists_create', '/_admin/gists/create', []);
332 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
333 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
333 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
334 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
334 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
335 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
335 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
336 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
336 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
337 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
337 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
338 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
338 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
339 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
339 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
340 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
340 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
341 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
341 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
342 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
342 pyroutes.register('apiv2', '/_admin/api', []);
343 pyroutes.register('apiv2', '/_admin/api', []);
343 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
344 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
344 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
345 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
345 pyroutes.register('login', '/_admin/login', []);
346 pyroutes.register('login', '/_admin/login', []);
346 pyroutes.register('register', '/_admin/register', []);
347 pyroutes.register('register', '/_admin/register', []);
347 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
348 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
348 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
349 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
349 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
350 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
350 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
351 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
351 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
352 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
352 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
353 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
353 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
354 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
354 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
355 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
355 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
356 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
356 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
357 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
357 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
358 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
358 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
359 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
359 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
360 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
360 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
361 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
361 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
362 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
362 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
363 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
363 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
364 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
364 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
365 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
365 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
366 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
366 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
367 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
367 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
368 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
368 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
369 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
369 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
370 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
370 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
371 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
371 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
372 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
372 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
373 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
373 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
374 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
374 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
375 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
375 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
376 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
376 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
377 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
377 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
378 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
378 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
379 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
379 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
380 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
380 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
381 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
381 }
382 }
General Comments 0
You need to be logged in to leave comments. Login now