0001-manager-allow-importing-roles-from-different-OUs-588.patch
src/authentic2/data_transfer.py | ||
---|---|---|
158 | 158 |
role_attributes_update=True, |
159 | 159 |
ou_delete_orphans=False, |
160 | 160 |
set_ou=None, |
161 |
allowed_ous=None, |
|
161 | 162 |
): |
162 | 163 |
self.import_roles = import_roles |
163 | 164 |
self.import_ous = import_ous |
... | ... | |
167 | 168 |
self.role_permissions_update = role_permissions_update |
168 | 169 |
self.role_attributes_update = role_attributes_update |
169 | 170 |
self.set_ou = set_ou |
171 |
self.allowed_ous = allowed_ous |
|
170 | 172 | |
171 | 173 | |
172 | 174 |
def wraps_validationerror(func): |
... | ... | |
210 | 212 |
if self._import_context.set_ou: |
211 | 213 |
ou = self._import_context.set_ou |
212 | 214 |
has_ou = True |
213 |
else:
|
|
215 |
elif 'ou' in self._role_d:
|
|
214 | 216 |
ou_d = self._role_d['ou'] |
215 | 217 |
has_ou = bool(ou_d) |
216 | 218 |
ou = None if not has_ou else search_ou(ou_d) |
217 | 219 |
if has_ou and not ou: |
218 | 220 |
raise ValidationError(_("Can't import role because missing Organizational Unit: %s") % ou_d) |
221 |
if self._import_context.allowed_ous and ou not in self._import_context.allowed_ous: |
|
222 |
raise ValidationError( |
|
223 |
_("Can't import role because missing permissions on Organizational Unit: %s") % ou_d |
|
224 |
) |
|
225 |
else: |
|
226 |
name = self._role_d.get('name') or self._role_d.get('slug') or self._role_d.get('uuid') |
|
227 |
raise ValidationError(_("Missing Organizational Unit for role: %s") % name) |
|
219 | 228 | |
220 | 229 |
obj = search_role(self._role_d, ou=self._import_context.set_ou) |
221 | 230 |
src/authentic2/manager/forms.py | ||
---|---|---|
691 | 691 |
class RolesImportForm(LimitQuerysetFormMixin, SiteImportForm): |
692 | 692 |
file_field_label = _('Roles Export File') |
693 | 693 | |
694 |
def __init__(self, *args, **kwargs): |
|
695 |
super().__init__(*args, **kwargs) |
|
696 |
if utils.get_ou_count() < 2: |
|
697 |
self.fields['ou'].widget = forms.HiddenInput() |
|
698 | ||
699 | 694 |
ou = forms.ModelChoiceField( |
700 |
label=_('Organizational unit'), |
|
695 |
required=False, |
|
696 |
label=_('Force organizational unit'), |
|
701 | 697 |
queryset=OrganizationalUnit.objects, |
702 |
initial=lambda: get_default_ou().pk, |
|
703 | 698 |
) |
704 | 699 | |
705 | 700 |
src/authentic2/manager/role_views.py | ||
---|---|---|
664 | 664 |
def form_valid(self, form): |
665 | 665 |
self.ou = form.cleaned_data['ou'] |
666 | 666 |
try: |
667 |
context = data_transfer.ImportContext(import_ous=False, set_ou=self.ou) |
|
667 |
context = data_transfer.ImportContext( |
|
668 |
import_ous=False, set_ou=self.ou, allowed_ous=set(form.fields['ou'].queryset) |
|
669 |
) |
|
668 | 670 |
with transaction.atomic(): |
669 | 671 |
data_transfer.import_site(form.cleaned_data['site_json'], context) |
670 | 672 |
except ValidationError as e: |
... | ... | |
674 | 676 |
return super().form_valid(form) |
675 | 677 | |
676 | 678 |
def get_success_url(self): |
677 |
messages.success( |
|
678 |
self.request, |
|
679 |
_('Roles have been successfully imported inside "%s" organizational unit.') % self.ou, |
|
680 |
) |
|
681 |
return reverse('a2-manager-roles') + '?search-ou=%s' % self.ou.pk |
|
679 |
if self.ou: |
|
680 |
message = _('Roles have been successfully imported inside "%s" organizational unit.') % self.ou |
|
681 |
querystring = '?search-ou=%s' % self.ou.pk |
|
682 |
else: |
|
683 |
message = _('Roles have been successfully imported.') |
|
684 |
querystring = '' |
|
685 | ||
686 |
messages.success(self.request, message) |
|
687 |
return reverse('a2-manager-roles') + querystring |
|
682 | 688 | |
683 | 689 | |
684 | 690 |
roles_import = RolesImportView.as_view() |
tests/test_role_manager.py | ||
---|---|---|
138 | 138 |
assert not 'ous' in export |
139 | 139 |
Role.objects.filter(ou__in=[ou1, ou2]).delete() |
140 | 140 | |
141 |
# import in OUs specified in export file |
|
141 | 142 |
resp = app.get('/manage/roles/') |
142 | 143 |
resp = resp.click('Import') |
143 | 144 |
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') |
144 | 145 |
resp = resp.form.submit().follow() |
145 | 146 | |
147 |
assert Role.objects.filter(name=role_ou1.name, ou=ou1).exists() |
|
148 |
assert Role.objects.filter(name=role_ou2.name, ou=ou2).exists() |
|
149 |
Role.objects.filter(ou__in=[ou1, ou2]).delete() |
|
150 | ||
151 |
# import in custom OU |
|
152 |
resp = app.get('/manage/roles/') |
|
153 |
resp = resp.click('Import') |
|
154 |
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') |
|
155 |
resp.form['ou'] = get_default_ou().pk |
|
156 |
resp = resp.form.submit().follow() |
|
157 | ||
146 | 158 |
assert Role.objects.filter(name=role_ou1.name, ou=get_default_ou()).exists() |
147 | 159 |
assert Role.objects.filter(name=role_ou2.name, ou=get_default_ou()).exists() |
148 | 160 | |
... | ... | |
155 | 167 |
assert new_export['roles'][0]['uuid'] == export['roles'][0]['uuid'] |
156 | 168 |
assert new_export['roles'][1]['uuid'] == export['roles'][1]['uuid'] |
157 | 169 | |
170 |
# import in custom OU while roles exist in another OU |
|
158 | 171 |
resp = app.get('/manage/roles/') |
159 | 172 |
resp = resp.click('Import') |
160 | 173 |
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') |
... | ... | |
176 | 189 |
resp = app.get('/manage/roles/') # unselect ou1 |
177 | 190 |
resp = resp.click('Import') |
178 | 191 |
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') |
192 |
resp.form['ou'] = get_default_ou().pk |
|
179 | 193 |
resp = resp.form.submit().follow() |
180 | 194 | |
181 | 195 |
assert not OrganizationalUnit.objects.filter(slug="should_not_exist").exists() |
182 | 196 | |
183 | ||
184 |
def test_manager_role_import_single_ou(app, admin, simple_role): |
|
185 |
assert OrganizationalUnit.objects.count() == 1 |
|
186 |
response = login(app, admin, 'a2-manager-roles') |
|
187 | ||
188 |
export_response = response.click('Export') |
|
189 |
export = export_response.json |
|
190 | ||
191 |
assert len(export['roles']) == 1 |
|
192 |
simple_role.delete() |
|
193 | ||
197 |
# missing ou in export file |
|
198 |
export = {"roles": [{"slug": "agent", "name": "Agent"}]} |
|
194 | 199 |
resp = app.get('/manage/roles/') |
195 | 200 |
resp = resp.click('Import') |
196 |
assert not 'Organizational unit' in resp.text |
|
197 |
assert resp.form['ou'].attrs['type'] == 'hidden' |
|
201 |
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') |
|
202 |
resp = resp.form.submit() |
|
203 |
assert 'Missing Organizational Unit for role: Agent' in resp.text |
|
198 | 204 | |
205 |
resp.form['ou'] = get_default_ou().pk |
|
199 | 206 |
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') |
200 | 207 |
resp = resp.form.submit().follow() |
201 | ||
202 |
imported_role = Role.objects.get(slug=simple_role.slug) |
|
203 |
assert imported_role.ou == simple_role.ou |
|
208 |
assert Role.objects.get(slug='agent') |
|
204 | 209 | |
205 | 210 | |
206 | 211 |
def test_manager_role_import_selected_ou(app, admin, ou1, ou2): |
... | ... | |
211 | 216 |
assert response.pyquery.find('select#id_ou option[selected]')[0].text == 'OU2' |
212 | 217 | |
213 | 218 | |
219 |
def test_manager_role_import_ou_permission(app, admin, ou1, role_ou1, ou2, role_ou2, admin_ou1): |
|
220 |
resp = login(app, admin, 'a2-manager-roles') |
|
221 |
resp = resp.click('Export') |
|
222 |
export = resp.json |
|
223 |
assert len(export['roles']) == 2 |
|
224 |
role_ou1.delete() |
|
225 |
role_ou2.delete() |
|
226 |
app.session.flush() # logout |
|
227 | ||
228 |
resp = login(app, admin_ou1, 'a2-manager-roles') |
|
229 |
resp = resp.click('Import') |
|
230 |
resp.form['ou'] = '' |
|
231 |
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') |
|
232 |
resp = resp.form.submit() |
|
233 | ||
234 |
# importing fails because user has no permission on ou2 |
|
235 |
assert 'missing permissions on Organizational Unit' in resp.text |
|
236 | ||
237 | ||
214 | 238 |
def test_manager_role_add_selected_ou(app, admin, ou1, ou2): |
215 | 239 |
response = login(app, admin, '/manage/roles/') |
216 | 240 |
response = response.click('Add role') |
217 |
- |