def owner_org_validator(key, data, errors, context): value = data.get(key) if value is missing or value is None: if not authz.check_config_permission('create_unowned_dataset'): raise Invalid(_('An organization must be provided')) data.pop(key, None) raise df.StopOnError model = context['model'] user = context['user'] user = model.User.get(user) if value == '': if not authz.check_config_permission('create_unowned_dataset'): raise Invalid(_('An organization must be provided')) return group = model.Group.get(value) if not group: raise Invalid(_('Organization does not exist')) group_id = group.id if not context.get(u'ignore_auth', False) and not ( user.sysadmin or authz.has_user_permission_for_group_or_org( group_id, user.name, 'create_dataset')): raise Invalid(_('You cannot add a dataset to this organization')) data[key] = group_id
def package_create(context, data_dict=None): user = context['user'] if authz.auth_is_anon_user(context): check1 = all(authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = all(authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') if not check1: return {'success': False, 'msg': _('User %s not authorized to create packages') % user} check2 = _check_group_auth(context,data_dict) if not check2: return {'success': False, 'msg': _('User %s not authorized to edit these groups') % user} # If an organization is given are we able to add a dataset to it? data_dict = data_dict or {} org_id = data_dict.get('owner_org') if org_id and not authz.has_user_permission_for_group_or_org( org_id, user, 'create_dataset'): return {'success': False, 'msg': _('User %s not authorized to add dataset to this organization') % user} return {'success': True}
def owner_org_validator(key, data, errors, context): value = data.get(key) if value is missing or value is None: if not authz.check_config_permission('create_unowned_dataset'): raise Invalid(_('An organization must be provided')) data.pop(key, None) raise df.StopOnError model = context['model'] user = context['user'] user = model.User.get(user) if value == '': if not authz.check_config_permission('create_unowned_dataset'): raise Invalid(_('An organization must be provided')) return group = model.Group.get(value) if not group: raise Invalid(_('Organization does not exist')) group_id = group.id if not context.get(u'ignore_auth', False) and not(user.sysadmin or authz.has_user_permission_for_group_or_org( group_id, user.name, 'create_dataset')): raise Invalid(_('You cannot add a dataset to this organization')) data[key] = group_id
def owner_org_validator(key, data, errors, context): value = data.get(key) if value is missing or value is None: if not authz.check_config_permission('create_unowned_dataset'): raise Invalid(_('An organization must be provided')) data.pop(key, None) raise df.StopOnError model = context['model'] user = context['user'] user = model.User.get(user) package = context.get('package') if value == '': if not authz.check_config_permission('create_unowned_dataset'): raise Invalid(_('An organization must be provided')) return if (authz.check_config_permission('allow_dataset_collaborators') and not authz.check_config_permission( 'allow_collaborators_to_change_owner_org')): if package and user and not user.sysadmin: is_collaborator = authz.user_is_collaborator_on_dataset( user.id, package.id, ['admin', 'editor']) if is_collaborator: # User is a collaborator, check if it's also a member with # edit rights of the current organization (redundant, but possible) user_orgs = logic.get_action('organization_list_for_user')( { 'ignore_auth': True }, { 'id': user.id, 'permission': 'update_dataset' }) user_is_org_member = package.owner_org in [ org['id'] for org in user_orgs ] if data.get( key) != package.owner_org and not user_is_org_member: raise Invalid( _('You cannot move this dataset to another organization' )) group = model.Group.get(value) if not group: raise Invalid(_('Organization does not exist')) group_id = group.id if not package or (package and package.owner_org != group_id): # This is a new dataset or we are changing the organization if not context.get(u'ignore_auth', False) and not ( user.sysadmin or authz.has_user_permission_for_group_or_org( group_id, user.name, 'create_dataset')): raise Invalid(_('You cannot add a dataset to this organization')) data[key] = group_id
def managing_users_package_update(context, data_dict): user = context.get('user') package = logic_auth.get_package_object(context, data_dict) extras = dict([(key, value) for key, value in package.extras.items()]) if package.owner_org: # if there is an owner org then we must have update_dataset # permission for that organization check1 = authz.has_user_permission_for_group_or_org( package.owner_org, user, 'update_dataset') #Managing users have to be specified for datasets within an organization managing_users = extras.get('managing_users', '') managing_users = managing_users.split(',') check1 = check1 and context['auth_user_obj'].name in managing_users else: # If dataset is not owned then we can edit if config permissions allow if authz.auth_is_anon_user(context): check1 = all( authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = all( authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') #Managing users have to be specified for datasets without owner #Else only creator can edit the dataset managing_users = extras.get('managing_users', '') managing_users = managing_users.split(',') check1 = check1 and context['auth_user_obj'].name in managing_users if context['auth_user_obj'].id == package.creator_user_id: #If user is the creator of the package, he can edit it regardless check1 = True if not check1: return { 'success': False, 'msg': _('User %s not authorized to edit package %s') % (str(user), package.id) } else: check2 = _check_group_auth(context, data_dict) if not check2: return { 'success': False, 'msg': _('User %s not authorized to edit these groups') % (str(user)) } return {'success': True}
def package_update(context, data_dict): model = context['model'] user = context.get('user') package = logic_auth.get_package_object(context, data_dict) if package.owner_org: # if there is an owner org then we must have update_dataset # permission for that organization check1 = authz.has_user_permission_for_group_or_org( package.owner_org, user, 'update_dataset') else: # If dataset is not owned then we can edit if config permissions allow if authz.auth_is_anon_user(context): check1 = all( authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = all( authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') if not check1: success = False if authz.check_config_permission('allow_dataset_collaborators'): # if org-level auth failed, check dataset-level auth # (ie if user is a collaborator) user_obj = model.User.get(user) if user_obj: success = authz.user_is_collaborator_on_dataset( user_obj.id, package.id, ['admin', 'editor']) if not success: return { 'success': False, 'msg': _('User %s not authorized to edit package %s') % (str(user), package.id) } else: check2 = _check_group_auth(context, data_dict) if not check2: return { 'success': False, 'msg': _('User %s not authorized to edit these groups') % (str(user)) } return {'success': True}
def managing_users_package_update(context, data_dict): user = context.get('user') package = logic_auth.get_package_object(context, data_dict) extras = dict([(key, value) for key, value in package.extras.items()]) if package.owner_org: # if there is an owner org then we must have update_dataset # permission for that organization check1 = authz.has_user_permission_for_group_or_org( package.owner_org, user, 'update_dataset' ) #Managing users have to be specified for datasets within an organization managing_users = extras.get('managing_users', '') managing_users = managing_users.split(',') check1 = check1 and context['auth_user_obj'].name in managing_users else: # If dataset is not owned then we can edit if config permissions allow if authz.auth_is_anon_user(context): check1 = all(authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = all(authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') #Managing users have to be specified for datasets without owner #Else only creator can edit the dataset managing_users = extras.get('managing_users', '') managing_users = managing_users.split(',') check1 = check1 and context['auth_user_obj'].name in managing_users if context['auth_user_obj'].id == package.creator_user_id: #If user is the creator of the package, he can edit it regardless check1 = True if not check1: return {'success': False, 'msg': _('User %s not authorized to edit package %s') % (str(user), package.id)} else: check2 = _check_group_auth(context, data_dict) if not check2: return {'success': False, 'msg': _('User %s not authorized to edit these groups') % (str(user))} return {'success': True}
def user_create(context, data_dict=None): using_api = 'api_version' in context create_user_via_api = authz.check_config_permission( 'create_user_via_api') create_user_via_web = authz.check_config_permission( 'create_user_via_web') if using_api and not create_user_via_api: return {'success': False, 'msg': _('User {user} not authorized to ' 'create users via the API').format(user=context.get('user'))} if not using_api and not create_user_via_web: return {'success': False, 'msg': _('Not authorized to ' 'create users')} return {'success': True}
def activity_list(context, data_dict): ''' :param id: the id or name of the object (e.g. package id) :type id: string :param object_type: The type of the object (e.g. 'package', 'organization', 'group', 'user') :type object_type: string :param include_data: include the data field, containing a full object dict (otherwise the data field is only returned with the object's title) :type include_data: boolean ''' if data_dict['object_type'] not in ('package', 'organization', 'group', 'user'): return {'success': False, 'msg': 'object_type not recognized'} if (data_dict.get('include_data') and not authz.check_config_permission('public_activity_stream_detail') ): # The 'data' field of the activity is restricted to users who are # allowed to edit the object show_or_update = 'update' else: # the activity for an object (i.e. the activity metadata) can be viewed # if the user can see the object show_or_update = 'show' action_on_which_to_base_auth = '{}_{}'.format( data_dict['object_type'], show_or_update) # e.g. 'package_update' return authz.is_authorized(action_on_which_to_base_auth, context, {'id': data_dict['id']})
def package_create(context, data_dict=None): user = context['user'] user_object = context.get('auth_user_obj') #Sysadmin user has all the previliges if user_object and user_object.sysadmin : {'success': True} #Do not authorize anonymous users if authz.auth_is_anon_user(context): return {'success': False, 'msg': _('User %s not authorized to create packages') % user} #Check if the user has the editor or admin role in some org/suborg check1 = all(authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') if not check1: return {'success': False, 'msg': _('User %s not authorized to create packages') % user} check2 = _check_group_auth(context,data_dict) if not check2: return {'success': False, 'msg': _('User %s not authorized to edit these groups') % user} # If an organization is given are we able to add a dataset to it? data_dict = data_dict or {} org_id = data_dict.get('owner_org') if org_id and not authz.has_user_permission_for_group_or_org( org_id, user, 'create_dataset'): return {'success': False, 'msg': _('User %s not authorized to add dataset to this organization') % user} return {'success': True}
def activity_list(context: Context, data_dict: DataDict) -> AuthResult: """ :param id: the id or name of the object (e.g. package id) :type id: string :param object_type: The type of the object (e.g. 'package', 'organization', 'group', 'user') :type object_type: string :param include_data: include the data field, containing a full object dict (otherwise the data field is only returned with the object's title) :type include_data: boolean """ if data_dict["object_type"] not in ( "package", "organization", "group", "user", ): return {"success": False, "msg": "object_type not recognized"} is_public = authz.check_config_permission("public_activity_stream_detail") if data_dict.get("include_data") and not is_public: # The 'data' field of the activity is restricted to users who are # allowed to edit the object show_or_update = "update" else: # the activity for an object (i.e. the activity metadata) can be viewed # if the user can see the object show_or_update = "show" action_on_which_to_base_auth = "{}_{}".format( data_dict["object_type"], show_or_update) # e.g. 'package_update' return authz.is_authorized(action_on_which_to_base_auth, context, {"id": data_dict["id"]})
def related_update(context, data_dict): ''' Override default related_update so; - Users must be logged-in to create related items - User can update if they are able to create datasets for housed package ''' user = context['user'] check1 = all(authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') if user and check1: related = logic_auth.get_related_object(context, data_dict) if related.datasets: for package in related.datasets: pkg_dict = {'id': package.id} authorised = authz.is_authorized( 'package_update', context, pkg_dict).get('success') if authorised: return {'success': True} return {'success': False, 'msg': _('''You do not have permission to update this related item''')} return {'success': False, 'msg': _('''You must be logged in and have permission to create datasets to update a related item''')}
def organization_create(context, data_dict): """ This overrides CKAN's auth function to make sure that user has permission to use a specific parent organization. """ if not c.userobj: return {'success': False, 'msg': _('Only registered users can create organizations')} # Check that user has admin permissions in selected parent organizations if data_dict and data_dict.get('groups'): admin_in_orgs = (model.Session.query(model.Member).filter(model.Member.state == 'active') .filter(model.Member.table_name == 'user') .filter(model.Member.capacity == 'admin') .filter(model.Member.table_id == c.userobj.id)) for group in data_dict['groups']: if any(group['name'] == admin_org.group.name for admin_org in admin_in_orgs): break else: return {'success': False, 'msg': _('User %s is not administrator in the selected parent organization') % context['user']} check = _check_public_adminstration_flag(context, data_dict) if check: return check if authz.check_config_permission('user_create_organizations'): return {'success': True} return {'success': False, 'msg': _('User %s not authorized to create organizations') % context['user']}
def test_roles_that_cascade_to_sub_groups_is_a_list(self): assert_equals( sorted( auth.check_config_permission( 'roles_that_cascade_to_sub_groups')), sorted(['admin', 'editor']))
def package_update(context, data_dict): user = context.get('user') package = logic_auth.get_package_object(context, data_dict) if package.owner_org: # if there is an owner org then we must have update_dataset # permission for that organization check1 = authz.has_user_permission_for_group_or_org( package.owner_org, user, 'update_dataset') else: # If dataset is not owned then we can edit if config permissions allow if authz.auth_is_anon_user(context): check1 = all( authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = all( authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') if not check1: return { 'success': False, 'msg': _('User %s not authorized to edit package %s') % (str(user), package.id) } else: check2 = _check_group_auth(context, data_dict) if not check2: return { 'success': False, 'msg': _('User %s not authorized to edit these groups') % (str(user)) } if authz.config.get('ckan.gov_theme.is_back'): return {'success': True} else: return {'success': False}
def organization2_create(context, data_dict=None): user = context['user'] user = authz.get_user_id_for_username(user, allow_none=True) if user and authz.check_config_permission('user_create_organizations2'): return {'success': True} return {'success': False, 'msg': _('User %s not authorized to create organizations2') % user}
def organization_create(context, data_dict=None): user = context['user'] user = authz.get_user_id_for_username(user, allow_none=True) if user and authz.check_config_permission('user_create_organizations'): return {'success': True} return {'success': False, 'msg': _('User %s not authorized to create organizations') % user}
def group_create(context: Context, data_dict: Optional[DataDict] = None) -> AuthResult: user = context['user'] user = authz.get_user_id_for_username(user, allow_none=True) if user and authz.check_config_permission('user_create_groups'): return {'success': True} return {'success': False, 'msg': _('User %s not authorized to create groups') % user}
def related_create(context, data_dict=None): ''' Override default related_create so; - Users must be logged-in to create related items - Related item must be created for an associated dataset - User must be able to create datasets (proves privilege) Note: This function is used both to gain entry to the 'Create' form and to validate the 'Create' form ''' context_model = context['model'] user = context['user'] userobj = context_model.User.get(user) check1 = all( authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org(user, 'create_dataset') if userobj and check1: if data_dict: dataset_id = data_dict.get('dataset_id', None) if dataset_id is None or dataset_id == '': return { 'success': False, 'msg': _('''Related item must have an associated dataset''') } # check authentication against package pkg = context_model.Package.get(dataset_id) if not pkg: return { 'success': False, 'msg': _('No package found, cannot check auth.') } pkg_dict = {'id': dataset_id} authorised = authz.is_authorized('package_update', context, pkg_dict).get('success') if not authorised: return { 'success': False, 'msg': _('''Not authorised to add a related item to this package.''') } return {'success': True} return { 'success': False, 'msg': _('You must be logged in to add a related item') }
def register_dataset_plugin_rules(blueprint): blueprint.add_url_rule(u'/', view_func=search, strict_slashes=False) blueprint.add_url_rule(u'/new', view_func=CreateView.as_view(str(u'new'))) blueprint.add_url_rule(u'/<id>', view_func=read) blueprint.add_url_rule(u'/resources/<id>', view_func=resources) blueprint.add_url_rule(u'/edit/<id>', view_func=EditView.as_view(str(u'edit'))) blueprint.add_url_rule(u'/delete/<id>', view_func=DeleteView.as_view(str(u'delete'))) blueprint.add_url_rule(u'/follow/<id>', view_func=follow, methods=(u'POST', )) blueprint.add_url_rule(u'/unfollow/<id>', view_func=unfollow, methods=(u'POST', )) blueprint.add_url_rule(u'/followers/<id>', view_func=followers) blueprint.add_url_rule(u'/groups/<id>', view_func=GroupView.as_view(str(u'groups'))) blueprint.add_url_rule(u'/activity/<id>', view_func=activity) blueprint.add_url_rule(u'/changes/<id>', view_func=changes) blueprint.add_url_rule(u'/<id>/history', view_func=history) blueprint.add_url_rule(u'/changes_multiple', view_func=changes_multiple) # Duplicate resource create and edit for backward compatibility. Note, # we cannot use resource.CreateView directly here, because of # circular imports blueprint.add_url_rule(u'/new_resource/<id>', view_func=LazyView( u'ckan.views.resource.CreateView', str(u'new_resource'))) blueprint.add_url_rule(u'/<id>/resource_edit/<resource_id>', view_func=LazyView(u'ckan.views.resource.EditView', str(u'edit_resource'))) if authz.check_config_permission(u'allow_dataset_collaborators'): blueprint.add_url_rule(rule=u'/collaborators/<id>', view_func=collaborators_read, methods=[ 'GET', ]) blueprint.add_url_rule(rule=u'/collaborators/<id>/new', view_func=CollaboratorEditView.as_view( str(u'new_collaborator')), methods=[ u'GET', u'POST', ]) blueprint.add_url_rule(rule=u'/collaborators/<id>/delete/<user_id>', view_func=collaborator_delete, methods=[ 'POST', ])
def group_delete(context, data_dict): group = get_group_object(context, data_dict) user = context["user"] if not authz.check_config_permission("user_delete_groups"): return {"success": False, "msg": _("User %s not authorized to delete groups") % user} authorized = authz.has_user_permission_for_group_or_org(group.id, user, "delete") if not authorized: return {"success": False, "msg": _("User %s not authorized to delete group %s") % (user, group.id)} else: return {"success": True}
def group_create(context, data_dict=None): user = context['user'] user = authz.get_user_id_for_username(user, allow_none=True) if user and authz.check_config_permission('user_create_groups'): if authz.config.get('ckan.gov_theme.is_back'): return {'success': True} else: return {'success': False} return {'success': False, 'msg': _('User %s not authorized to create groups') % user}
def app_create(context, data_dict=None): user = context['user'] user = authz.get_user_id_for_username(user, allow_none=True) if user and authz.check_config_permission('user_create_apps'): return {'success': True} return { 'success': False, 'msg': _(u'Usuário %s não autorizado para criar um app') % user }
def organization_delete(context, data_dict): group = get_group_object(context, data_dict) user = context['user'] if not authz.check_config_permission('user_delete_organizations'): return {'success': False, 'msg': _('User %s not authorized to delete organizations') % user} authorized = authz.has_user_permission_for_group_or_org( group.id, user, 'delete') if not authorized: return {'success': False, 'msg': _('User %s not authorized to delete organization %s') % (user ,group.id)} else: return {'success': True}
def package_create(context, data_dict=None): ''' Modified from CKAN's original check. Any logged in user can add a dataset to any organisation. Packages owner check is done when adding a resource. :param context: context :param data_dict: data_dict :return: dictionary with 'success': True|False ''' user = context['user'] # Needed in metadata supplements if context.get('package', False): return is_owner(context, context.get('package').get('id')) # If an organization is given are we able to add a dataset to it? data_dict = data_dict or {} org_id = data_dict.get('owner_org', False) if org_id and not kata_has_user_permission_for_org( org_id, user, 'create_dataset'): return {'success': False, 'msg': _('User %s not authorized to add a dataset') % user} elif org_id and kata_has_user_permission_for_org(org_id, user, 'create_dataset'): return {'success': True} # Below is copy-pasted from CKAN auth.create.package_create # to allow dataset creation without explicit organization permissions. if authz.auth_is_anon_user(context): check1 = all(authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = True # Registered users may create datasets if not check1: return {'success': False, 'msg': _('User %s not authorized to create packages') % user} check2 = _check_group_auth(context, data_dict) if not check2: return {'success': False, 'msg': _('User %s not authorized to edit these groups') % user} # If an organization is given are we able to add a dataset to it? data_dict = data_dict or {} org_id = data_dict.get('owner_org') if org_id and not authz.has_user_permission_for_group_or_org( org_id, user, 'create_dataset'): return {'success': False, 'msg': _('User %s not authorized to add dataset to this organization') % user} return {'success': True}
def inventory_entry_list_for_user(context, data_dict): # TODO @palcu: DRY the code below from organization_list_for_user model = context['model'] user = context['user'] check_access('organization_list_for_user', context, data_dict) sysadmin = authz.is_sysadmin(user) orgs_q = model.Session.query(InventoryEntry).join(model.Group) \ .filter(model.Group.is_organization == True) \ .filter(model.Group.state == 'active') if not sysadmin: # for non-Sysadmins check they have the required permission # NB 'edit_group' doesn't exist so by default this action returns just # orgs with admin role permission = data_dict.get('permission', 'edit_group') roles = authz.get_roles_with_permission(permission) if not roles: return [] user_id = authz.get_user_id_for_username(user, allow_none=True) if not user_id: return [] q = model.Session.query(model.Member, model.Group) \ .filter(model.Member.table_name == 'user') \ .filter(model.Member.capacity.in_(roles)) \ .filter(model.Member.table_id == user_id) \ .filter(model.Member.state == 'active') \ .join(model.Group) group_ids = set() roles_that_cascade = \ authz.check_config_permission('roles_that_cascade_to_sub_groups') for member, group in q.all(): if member.capacity in roles_that_cascade: group_ids |= set([ grp_tuple[0] for grp_tuple in group.get_children_group_hierarchy( type='organization') ]) group_ids.add(group.id) if not group_ids: return [] orgs_q = orgs_q.filter(model.Group.id.in_(group_ids)) return [table_dictize(obj, context) for obj in orgs_q.all()]
def group_delete(context: Context, data_dict: DataDict) -> AuthResult: group = get_group_object(context, data_dict) user = context['user'] if not authz.check_config_permission('user_delete_groups'): return {'success': False, 'msg': _('User %s not authorized to delete groups') % user} authorized = authz.has_user_permission_for_group_or_org( group.id, user, 'delete') if not authorized: return {'success': False, 'msg': _( 'User %s not authorized to delete group %s') % (user ,group.id)} else: return {'success': True}
def inventory_entry_list_for_user(context, data_dict): # TODO @palcu: DRY the code below from organization_list_for_user model = context['model'] user = context['user'] check_access('organization_list_for_user', context, data_dict) sysadmin = authz.is_sysadmin(user) orgs_q = model.Session.query(InventoryEntry).join(model.Group) \ .filter(model.Group.is_organization == True) \ .filter(model.Group.state == 'active') if not sysadmin: # for non-Sysadmins check they have the required permission # NB 'edit_group' doesn't exist so by default this action returns just # orgs with admin role permission = data_dict.get('permission', 'edit_group') roles = authz.get_roles_with_permission(permission) if not roles: return [] user_id = authz.get_user_id_for_username(user, allow_none=True) if not user_id: return [] q = model.Session.query(model.Member, model.Group) \ .filter(model.Member.table_name == 'user') \ .filter(model.Member.capacity.in_(roles)) \ .filter(model.Member.table_id == user_id) \ .filter(model.Member.state == 'active') \ .join(model.Group) group_ids = set() roles_that_cascade = \ authz.check_config_permission('roles_that_cascade_to_sub_groups') for member, group in q.all(): if member.capacity in roles_that_cascade: group_ids |= set([ grp_tuple[0] for grp_tuple in group.get_children_group_hierarchy(type='organization') ]) group_ids.add(group.id) if not group_ids: return [] orgs_q = orgs_q.filter(model.Group.id.in_(group_ids)) return [table_dictize(obj, context) for obj in orgs_q.all()]
def package_create(context, data_dict=None): user = context['user'] user_object = context.get('auth_user_obj') #Sysadmin user has all the previliges if user_object and user_object.sysadmin: {'success': True} #Do not authorize anonymous users if authz.auth_is_anon_user(context): return { 'success': False, 'msg': _('User %s not authorized to create packages') % user } #Check if the user has the editor or admin role in some org/suborg check1 = all( authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org(user, 'create_dataset') if not check1: return { 'success': False, 'msg': _('User %s not authorized to create packages') % user } check2 = _check_group_auth(context, data_dict) if not check2: return { 'success': False, 'msg': _('User %s not authorized to edit these groups') % user } # If an organization is given are we able to add a dataset to it? data_dict = data_dict or {} org_id = data_dict.get('owner_org') if org_id and not authz.has_user_permission_for_group_or_org( org_id, user, 'create_dataset'): return { 'success': False, 'msg': _('User %s not authorized to add dataset to this organization') % user } return {'success': True}
def auth_resource_show(context, data_dict): """ if the grace period is set and the user does not belong to collaborators --> do not allow access :return: """ resource = data_dict.get('resource', context.get('resource', {})) if not resource: resource = logic_auth.get_resource_object(context, data_dict) if type(resource) is not dict: resource = resource.as_dict() pkg_id = resource.get('package_id') # Basic check: # Ensure user who can edit the package can see the resource if authz.is_authorized('package_update', context, { 'id': pkg_id }).get('success'): return {'success': True} # If the user is not authorized, deny access auth = authz.is_authorized('package_show', context, {'id': pkg_id}) if not auth.get('success', False): return { 'success': False, 'msg': _('User {} not authorized to read resource').format(g.user) } # The user is authorized so far: now check for grace period # If there are not grace period constraints, the resource is allowed if is_allowed_by_grace_period(resource): return {'success': True} # We are within grace period. # Owner and admins have already been granted access (because they can update the package) # Allow read-only collaborators to access the resource if g.userobj and \ authz.check_config_permission('allow_dataset_collaborators') and \ authz.user_is_collaborator_on_dataset(g.userobj.id, pkg_id): return {'success': True} return { 'success': False, 'msg': _('User {} not authorized to read resource in its grace period'). format(g.userobj.name if g.userobj else '-Anonymous-') }
def group_delete(context, data_dict): group = get_group_object(context, data_dict) user = context['user'] if not authz.check_config_permission('user_delete_groups'): return {'success': False, 'msg': _('User %s not authorized to delete groups') % user} authorized = authz.has_user_permission_for_group_or_org( group.id, user, 'delete') if not authorized: return {'success': False, 'msg': _('User %s not authorized to delete group %s') % (user ,group.id)} else: if authz.config.get('ckan.gov_theme.is_back'): return {'success': True} else: return {'success': False}
def package_update(context, data_dict): user = context.get('user') package = logic_auth.get_package_object(context, data_dict) if package.owner_org: # if there is an owner org then we must have update_dataset # permission for that organization check1 = authz.has_user_permission_for_group_or_org( package.owner_org, user, 'update_dataset' ) else: # If dataset is not owned then we can edit if config permissions allow if authz.auth_is_anon_user(context): check1 = all(authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = all(authz.check_config_permission(p) for p in ( 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) or authz.has_user_permission_for_some_org( user, 'create_dataset') if not check1: return {'success': False, 'msg': _('User %s not authorized to edit package %s') % (str(user), package.id)} else: check2 = _check_group_auth(context, data_dict) if not check2: return {'success': False, 'msg': _('User %s not authorized to edit these groups') % (str(user))} return {'success': True}
def package_collaborator_delete(context, data_dict): '''Remove a collaborator from a dataset. Currently you must be an Admin on the dataset owner organization to manage collaborators. Note: This action requires the collaborators feature to be enabled with the :ref:`ckan.auth.allow_dataset_collaborators` configuration option. :param id: the id or name of the dataset :type id: string :param user_id: the id or name of the user to remove :type user_id: string ''' model = context['model'] package_id, user_id = _get_or_bust( data_dict, ['id', 'user_id'] ) _check_access('package_collaborator_delete', context, data_dict) if not authz.check_config_permission('allow_dataset_collaborators'): raise ValidationError(_('Dataset collaborators not enabled')) package = model.Package.get(package_id) if not package: raise NotFound(_('Package not found')) user = model.User.get(user_id) if not user: raise NotFound(_('User not found')) collaborator = model.Session.query(model.PackageMember).\ filter(model.PackageMember.package_id == package.id).\ filter(model.PackageMember.user_id == user.id).one_or_none() if not collaborator: raise NotFound( 'User {} is not a collaborator on this package'.format(user_id)) model.Session.delete(collaborator) model.repo.commit() log.info('User {} removed as collaborator from package {}'.format( user_id, package.id))
def _is_resource_available(self, pkg, res): if 'available_since' in res: try: dt = datetime.strptime(res['available_since'], '%Y.%m.%d') except ValueError: is_available = False else: is_available = dt > datetime.now() # https://docs.ckan.org/en/2.9/maintaining/authorization.html#dataset-collaborators if is_available and \ authz.check_config_permission('allow_dataset_collaborators'): is_available = authz.user_is_collaborator_on_dataset( g.userobj.id, pkg['id']) else: is_available = True return is_available
def get(self, package_type, id): context = {u'model': model, u'user': g.user} data_dict = {u'id': id} try: check_access(u'package_collaborator_list', context, data_dict) # needed to ckan_extend package/edit_base.html pkg_dict = get_action(u'package_show')(context, data_dict) except NotAuthorized: message = u'Unauthorized to read collaborators {}'.format(id) return base.abort(401, _(message)) except NotFound: return base.abort(404, _(u'Resource not found')) user = request.params.get(u'user_id') user_capacity = u'member' if user: collaborators = get_action(u'package_collaborator_list')(context, data_dict) for c in collaborators: if c[u'user_id'] == user: user_capacity = c[u'capacity'] user = get_action(u'user_show')(context, {u'id': user}) capacities = [] if authz.check_config_permission(u'allow_admin_collaborators'): capacities.append({u'name': u'admin', u'value': u'admin'}) capacities.extend([{ u'name': u'editor', u'value': u'editor' }, { u'name': u'member', u'value': u'member' }]) extra_vars = { u'capacities': capacities, u'user_capacity': user_capacity, u'user': user, u'pkg_dict': pkg_dict, } return base.render(u'package/collaborators/collaborator_new.html', extra_vars)
def register_dataset_plugin_rules(blueprint): blueprint.add_url_rule(u'/', view_func=search, strict_slashes=False) blueprint.add_url_rule(u'/new', view_func=CreateView.as_view(str(u'new'))) blueprint.add_url_rule(u'/<id>', view_func=read) blueprint.add_url_rule(u'/resources/<id>', view_func=resources) blueprint.add_url_rule(u'/edit/<id>', view_func=EditView.as_view(str(u'edit'))) blueprint.add_url_rule(u'/delete/<id>', view_func=DeleteView.as_view(str(u'delete'))) blueprint.add_url_rule(u'/follow/<id>', view_func=follow, methods=(u'POST', )) blueprint.add_url_rule(u'/unfollow/<id>', view_func=unfollow, methods=(u'POST', )) blueprint.add_url_rule(u'/followers/<id>', view_func=followers) blueprint.add_url_rule(u'/groups/<id>', view_func=GroupView.as_view(str(u'groups'))) blueprint.add_url_rule(u'/activity/<id>', view_func=activity) blueprint.add_url_rule(u'/changes/<id>', view_func=changes) blueprint.add_url_rule(u'/<id>/history', view_func=history) blueprint.add_url_rule(u'/changes_multiple', view_func=changes_multiple) if authz.check_config_permission(u'allow_dataset_collaborators'): blueprint.add_url_rule(rule=u'/collaborators/<id>', view_func=collaborators_read, methods=[ 'GET', ]) blueprint.add_url_rule(rule=u'/collaborators/<id>/new', view_func=CollaboratorEditView.as_view( str(u'new_collaborator')), methods=[ u'GET', u'POST', ]) blueprint.add_url_rule(rule=u'/collaborators/<id>/delete/<user_id>', view_func=collaborator_delete, methods=[ 'POST', ])
def organization_create(context, data_dict): """ This overrides CKAN's auth function to make sure that user has permission to use a specific parent organization. """ if not c.userobj: return { 'success': False, 'msg': _('Only registered users can create organizations') } # Check that user has admin permissions in selected parent organizations if data_dict and data_dict.get('groups'): admin_in_orgs = (model.Session.query( model.Member).filter(model.Member.state == 'active').filter( model.Member.table_name == 'user').filter( model.Member.capacity == 'admin').filter( model.Member.table_id == c.userobj.id)) for group in data_dict['groups']: if any(group['name'] == admin_org.group.name for admin_org in admin_in_orgs): break else: return { 'success': False, 'msg': _('User %s is not administrator in the selected parent organization' ) % context['user'] } check = _check_public_adminstration_flag(context, data_dict) if check: return check if authz.check_config_permission('user_create_organizations'): return {'success': True} return { 'success': False, 'msg': _('User %s not authorized to create organizations') % context['user'] }
def test_roles_that_cascade_to_sub_groups_is_a_list(self): assert_equals(sorted(auth.check_config_permission( 'roles_that_cascade_to_sub_groups')), sorted(['admin', 'editor']))
def test_default_roles_that_cascade_to_sub_groups_is_a_list(self): assert isinstance(auth.check_config_permission( 'roles_that_cascade_to_sub_groups'), list)
def test_unknown_permission_not_in_config_returns_false(self): assert_equals(auth.check_config_permission( 'unknown_permission'), False)
def test_config_override_also_works_with_prefix(self): assert_equals(auth.check_config_permission( 'ckan.auth.anon_create_dataset'), True)
def test_config_overrides_default(self): assert_equals(auth.check_config_permission( 'anon_create_dataset'), True)
def test_get_default_value_also_works_with_prefix(self): assert_equals(auth.check_config_permission( 'ckan.auth.anon_create_dataset'), auth.CONFIG_PERMISSIONS_DEFAULTS['anon_create_dataset'])
def test_get_default_value_if_not_set_in_config(self): assert_equals(auth.check_config_permission( 'anon_create_dataset'), auth.CONFIG_PERMISSIONS_DEFAULTS['anon_create_dataset'])
def _group_or_org_purge(context, data_dict, is_org=False): '''Purge a group or organization. The group or organization will be completely removed from the database. This cannot be undone! Only sysadmins can purge groups or organizations. :param id: the name or id of the group or organization to be purged :type id: string :param is_org: you should pass is_org=True if purging an organization, otherwise False (optional, default: False) :type is_org: bool ''' model = context['model'] id = _get_or_bust(data_dict, 'id') group = model.Group.get(id) context['group'] = group if group is None: if is_org: raise NotFound('Organization was not found') else: raise NotFound('Group was not found') if is_org: _check_access('organization_purge', context, data_dict) else: _check_access('group_purge', context, data_dict) if is_org: # Clear the owner_org field datasets = model.Session.query(model.Package) \ .filter_by(owner_org=group.id) \ .filter(model.Package.state != 'deleted') \ .count() if datasets: if not authz.check_config_permission('ckan.auth.create_unowned_dataset'): raise ValidationError('Organization cannot be purged while it ' 'still has datasets') pkg_table = model.package_table # using Core SQLA instead of the ORM should be faster model.Session.execute( pkg_table.update().where( sqla.and_(pkg_table.c.owner_org == group.id, pkg_table.c.state != 'deleted') ).values(owner_org=None) ) # Delete related Memberships members = model.Session.query(model.Member) \ .filter(sqla.or_(model.Member.group_id == group.id, model.Member.table_id == group.id)) if members.count() > 0: # no need to do new_revision() because Member is not revisioned, nor # does it cascade delete any revisioned objects for m in members.all(): m.purge() model.repo.commit_and_remove() group = model.Group.get(id) model.repo.new_revision() group.purge() model.repo.commit_and_remove()
def _group_or_org_delete(context, data_dict, is_org=False): '''Delete a group. You must be authorized to delete the group. :param id: the name or id of the group :type id: string ''' from sqlalchemy import or_ model = context['model'] user = context['user'] id = _get_or_bust(data_dict, 'id') group = model.Group.get(id) context['group'] = group if group is None: raise NotFound('Group was not found.') revisioned_details = 'Group: %s' % group.name if is_org: _check_access('organization_delete', context, data_dict) else: _check_access('group_delete', context, data_dict) # organization delete will not occure whilke all datasets for that org are # not deleted if is_org: datasets = model.Session.query(model.Package) \ .filter_by(owner_org=group.id) \ .filter(model.Package.state != 'deleted') \ .count() if datasets: if not authz.check_config_permission('ckan.auth.create_unowned_dataset'): raise ValidationError(_('Organization cannot be deleted while it ' 'still has datasets')) pkg_table = model.package_table # using Core SQLA instead of the ORM should be faster model.Session.execute( pkg_table.update().where( sqla.and_(pkg_table.c.owner_org == group.id, pkg_table.c.state != 'deleted') ).values(owner_org=None) ) rev = model.repo.new_revision() rev.author = user rev.message = _(u'REST API: Delete %s') % revisioned_details # The group's Member objects are deleted # (including hierarchy connections to parent and children groups) for member in model.Session.query(model.Member).\ filter(or_(model.Member.table_id == id, model.Member.group_id == id)).\ filter(model.Member.state == 'active').all(): member.delete() group.delete() if is_org: plugin_type = plugins.IOrganizationController else: plugin_type = plugins.IGroupController for item in plugins.PluginImplementations(plugin_type): item.delete(group) model.repo.commit()
def package_create(context, data_dict=None): ''' Modified from CKAN's original check. Any logged in user can add a dataset to any organisation. Packages owner check is done when adding a resource. :param context: context :param data_dict: data_dict :return: dictionary with 'success': True|False ''' user = context['user'] # Needed in metadata supplements if context.get('package', False): return is_owner(context, context.get('package').get('id')) # If an organization is given are we able to add a dataset to it? data_dict = data_dict or {} org_id = data_dict.get('owner_org', False) if org_id and not kata_has_user_permission_for_org(org_id, user, 'create_dataset'): return { 'success': False, 'msg': _('User %s not authorized to add a dataset') % user } elif org_id and kata_has_user_permission_for_org(org_id, user, 'create_dataset'): return {'success': True} # Below is copy-pasted from CKAN auth.create.package_create # to allow dataset creation without explicit organization permissions. if authz.auth_is_anon_user(context): check1 = all( authz.check_config_permission(p) for p in ( 'anon_create_dataset', 'create_dataset_if_not_in_organization', 'create_unowned_dataset', )) else: check1 = True # Registered users may create datasets if not check1: return { 'success': False, 'msg': _('User %s not authorized to create packages') % user } check2 = _check_group_auth(context, data_dict) if not check2: return { 'success': False, 'msg': _('User %s not authorized to edit these groups') % user } # If an organization is given are we able to add a dataset to it? data_dict = data_dict or {} org_id = data_dict.get('owner_org') if org_id and not authz.has_user_permission_for_group_or_org( org_id, user, 'create_dataset'): return { 'success': False, 'msg': _('User %s not authorized to add dataset to this organization') % user } return {'success': True}
def test_roles_that_cascade_to_sub_groups_is_a_list(self): assert_equals( sorted(auth.check_config_permission("roles_that_cascade_to_sub_groups")), sorted(["admin", "editor"]) )
def test_unknown_permission_returns_false(self): assert_equals(auth.check_config_permission("unknown_permission"), False)
def _group_or_org_purge(context, data_dict, is_org=False): '''Purge a group or organization. The group or organization will be completely removed from the database. This cannot be undone! Only sysadmins can purge groups or organizations. :param id: the name or id of the group or organization to be purged :type id: string :param is_org: you should pass is_org=True if purging an organization, otherwise False (optional, default: False) :type is_org: boolean ''' model = context['model'] id = _get_or_bust(data_dict, 'id') group = model.Group.get(id) context['group'] = group if group is None: if is_org: raise NotFound('Organization was not found') else: raise NotFound('Group was not found') if is_org: _check_access('organization_purge', context, data_dict) else: _check_access('group_purge', context, data_dict) if is_org: # Clear the owner_org field datasets = model.Session.query(model.Package) \ .filter_by(owner_org=group.id) \ .filter(model.Package.state != 'deleted') \ .count() if datasets: if not authz.check_config_permission( 'ckan.auth.create_unowned_dataset'): raise ValidationError('Organization cannot be purged while it ' 'still has datasets') pkg_table = model.package_table # using Core SQLA instead of the ORM should be faster model.Session.execute(pkg_table.update().where( sqla.and_( pkg_table.c.owner_org == group.id, pkg_table.c.state != 'deleted')).values(owner_org=None)) # Delete related Memberships members = model.Session.query(model.Member) \ .filter(sqla.or_(model.Member.group_id == group.id, model.Member.table_id == group.id)) if members.count() > 0: # no need to do new_revision() because Member is not revisioned, nor # does it cascade delete any revisioned objects for m in members.all(): m.purge() model.repo.commit_and_remove() group = model.Group.get(id) model.repo.new_revision() group.purge() model.repo.commit_and_remove()