You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

ckanext-dcor-schemas

Package Overview
Dependencies
Maintainers
2
Versions
87
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ckanext-dcor-schemas - pypi Package Compare versions

Comparing version
1.0.1
to
1.0.2
+4
-0
CHANGELOG

@@ -0,1 +1,5 @@

1.0.2
- fix: only group admins and editors may add or remove datasets
- fix: only group admins may add or remove users
- fix: do not allow listing users details for `group_list`
1.0.1

@@ -2,0 +6,0 @@ - fix: deny user listing for non-admins

+1
-1
Metadata-Version: 2.4
Name: ckanext-dcor_schemas
Version: 1.0.1
Version: 1.0.2
Summary: Introduces or lifts restrictions (authorization) for managing data and metadata on DCOR

@@ -5,0 +5,0 @@ Author: Paul Müller

@@ -31,5 +31,5 @@ # file generated by setuptools-scm

__version__ = version = '1.0.1'
__version_tuple__ = version_tuple = (1, 0, 1)
__version__ = version = '1.0.2'
__version_tuple__ = version_tuple = (1, 0, 2)
__commit_id__ = commit_id = 'gd5d8ace35'
__commit_id__ = commit_id = 'geba8d4429'

@@ -67,2 +67,39 @@ from email.utils import parseaddr

@logic.auth_allow_anonymous_access
def group_list(context, data_dict):
"""Check whether access to individual group details is authorised"""
if data_dict.get('include_users', False):
return {'success': False,
'msg': "Fetching user info via 'group_list' is not allowed."}
return content_listing(context, data_dict)
def member_create(context, data_dict):
"""In contrast to CKAN defaults, only editors of groups may add datasets"""
group = logic.auth.get_group_object(context, data_dict)
user = context["user"]
if not group.is_organization:
if data_dict.get("object_type") == "package":
permission = "create_dataset"
elif data_dict.get("object_type") == "user":
permission = "membership"
else:
raise ValueError(f"`object_type` should be 'package' or 'user',"
f"got '{data_dict.get('object_type')}'. "
f"The application logic did not check this case.")
authorized = authz.has_user_permission_for_group_or_org(group.id,
user,
permission)
if not authorized:
return {"success": False,
"msg": f'User {user} not authorized to '
f'edit collection {group.id}'
}
# Run the original auth function
return logic.auth.create.member_create(context, data_dict)
def package_create(context, data_dict):

@@ -583,22 +620,1 @@ # Note that we did not decorate this function with

'msg': "Users may only view their own details"}
@logic.auth_allow_anonymous_access
def group_show(context, data_dict):
"""Check whether access to a group is authorised.
If it's just the group metadata, this requires no privileges,
but if user details have been requested, it requires a group admin.
"""
user = context.get('user')
group = logic.auth.get_group_object(context, data_dict)
if group.state == 'active' and \
not asbool(data_dict.get('include_users', False)) and \
data_dict.get('object_type', None) != 'user':
return {'success': True}
authorized = authz.has_user_permission_for_group_or_org(
group.id, user, 'update')
if authorized:
return {'success': True}
else:
return {'success': False,
'msg': f'User {user} not authorized to read group {group.id}'}

@@ -9,3 +9,3 @@ import logging

import ckan.lib.signals
from ckan import config, common, logic
from ckan import authz, config, common, logic, model
import ckan.plugins as plugins

@@ -45,2 +45,9 @@ import ckan.plugins.toolkit as toolkit

# Monkey-patch away the `manage_group` permission for group members.
# We need this to prevent simple group members (non-editors and non-admins)
# from adding or removing datasets to a group.
if "manage_group" in authz.ROLE_PERMISSIONS["member"]:
authz.ROLE_PERMISSIONS["member"].remove("manage_group")
class DCORDatasetFormPlugin(plugins.SingletonPlugin,

@@ -85,4 +92,5 @@ toolkit.DefaultDatasetForm,

'dataset_purge': dcor_auth.dataset_purge,
'group_show': dcor_auth.group_show,
'group_list': dcor_auth.content_listing,
'group_list': dcor_auth.group_list,
'group_show': dcor_auth.content_listing,
'member_create': dcor_auth.member_create,
'member_roles_list': dcor_auth.content_listing,

@@ -427,5 +435,15 @@ 'organization_list': dcor_auth.content_listing,

if user_obj and not user_obj.is_anonymous and hasattr(user_obj, "id"):
grps = logic.get_action("group_list_authz")(
{u'user': user_obj.id}, {})
labels.extend(u'group-%s' % o['id'] for o in grps)
# I initially meant to use `group_authz_list` for this, but
# this one checks for `manage_group` while regular members only
# have the `read` permission. Thus, directly ask the DB:
q = (model.Session.query(model.Member.group_id)
.filter(model.Member.table_name == 'user')
.filter(model.Member.capacity.in_(["member"]))
.filter(model.Member.table_id == user_obj.id)
.filter(model.Member.state == 'active')
)
grps = []
for row in q:
grps.append(row.group_id)
labels.extend(u'group-%s' % g for g in grps)
return labels

@@ -432,0 +450,0 @@

@@ -17,2 +17,75 @@ import pathlib

@pytest.mark.usefixtures('clean_db', 'with_plugins', 'with_request_context')
def test_group_dataset_create():
"""Only admins and editors of a group are allowed to add datasets"""
user1 = factories.User()
user2 = factories.User()
user3 = factories.User()
user4 = factories.User()
owner_org = factories.Organization(users=[
{'name': user1['id'], 'capacity': 'editor'},
{'name': user2['id'], 'capacity': 'member'},
])
# create a datasets
create_context1 = {'ignore_auth': False,
'user': user1['name'],
'api_version': 3}
ds_dict_1, _ = make_dataset_via_s3(
create_context=create_context1,
owner_org=owner_org,
resource_path=data_path / "calibration_beads_47.rtdc",
activate=True)
# create group for user1
group_dict = helpers.call_action(
"group_create",
name=f"test_group-{uuid.uuid4()}",
title="Tests for group permissions",
packages=[ds_dict_1],
context=create_context1,
)
# add users 2 and 3 to the group in different capacities
for user, capacity in [
[user2, "editor"],
[user3, "member"],
]:
helpers.call_action("member_create",
id=group_dict["id"],
object=user["id"],
object_type='user',
capacity=capacity)
# admin and editor of the group should be able to create a dataset
for user in [user1, user2]:
context = {'ignore_auth': False,
'user': user['name'],
'api_version': 3}
helpers.call_auth("member_create",
context,
object_type="package",
id=group_dict["id"])
# This must also be reflected in group_list_authz
groups = helpers.call_action("group_list_authz", context)
assert len(groups) == 1
assert groups[0]["id"] == group_dict["id"]
# A member, random user, or anon may not add dataset
for user in [user3, user4, {"name": None}]:
context = {'ignore_auth': False,
'user': user['name'],
'api_version': 3}
with pytest.raises(logic.NotAuthorized):
helpers.call_auth("member_create",
context,
object_type="package",
id=group_dict["id"])
# This must also be reflected in group_list_authz
groups = helpers.call_action("group_list_authz", context)
assert len(groups) == 0
@pytest.mark.ckan_config('ckan.plugins', 'dcor_schemas')
@pytest.mark.usefixtures('clean_db', 'with_plugins', 'with_request_context')
def test_group_delete():

@@ -132,1 +205,159 @@ """Make sure users can delete their groups"""

id=group_dict["id"])
@pytest.mark.ckan_config('ckan.plugins', 'dcor_schemas')
@pytest.mark.ckan_config('ckanext.dcor_schemas.allow_content_listing_for_anon',
'false')
@pytest.mark.usefixtures('clean_db', 'with_plugins', 'with_request_context')
def test_group_show_by_user():
"""
Only members of a group are allowed to show it
"""
user1 = factories.User()
user2 = factories.User()
user3 = factories.User()
user4 = factories.User()
owner_org = factories.Organization(users=[
{'name': user1['id'], 'capacity': 'editor'},
{'name': user2['id'], 'capacity': 'member'},
])
# create a datasets
create_context1 = {'ignore_auth': False,
'user': user1['name'],
'api_version': 3}
ds_dict_1, _ = make_dataset_via_s3(
create_context=create_context1,
owner_org=owner_org,
resource_path=data_path / "calibration_beads_47.rtdc",
activate=True)
# create group for user1
group_dict = helpers.call_action(
"group_create",
name=f"test_group-{uuid.uuid4()}",
title="Tests for group permissions",
packages=[ds_dict_1],
context=create_context1,
)
# add users 2 and 3 to the group in different capacities
for user, capacity in [
[user2, "editor"],
[user3, "member"],
]:
helpers.call_action("member_create",
id=group_dict["id"],
object=user["id"],
object_type='user',
capacity=capacity)
# The admin, editor, and member should be able to view the group
for user in [user1, user2, user3]:
helpers.call_auth("group_show",
{'ignore_auth': False,
'user': user['name'],
'api_version': 3},
id=group_dict["id"])
# A random user is allowed to view it. But we need this
# functionality so that users can list all groups!
helpers.call_auth("group_show",
{'ignore_auth': False,
'user': user4['name'],
'api_version': 3},
id=group_dict["id"])
# An anonymous user is also not allowed
with pytest.raises(logic.NotAuthorized):
helpers.call_auth("group_show",
{'ignore_auth': False,
'user': None,
'api_version': 3},
id=group_dict["id"])
@pytest.mark.ckan_config('ckan.plugins', 'dcor_schemas')
@pytest.mark.usefixtures('clean_db', 'with_plugins', 'with_request_context')
def test_group_user_add():
"""Only admins of a group are allowed to add users to it"""
user1 = factories.User()
user2 = factories.User()
user3 = factories.User()
user4 = factories.User()
owner_org = factories.Organization(users=[
{'name': user1['id'], 'capacity': 'editor'},
{'name': user2['id'], 'capacity': 'member'},
])
# create a datasets
create_context1 = {'ignore_auth': False,
'user': user1['name'],
'api_version': 3}
ds_dict_1, _ = make_dataset_via_s3(
create_context=create_context1,
owner_org=owner_org,
resource_path=data_path / "calibration_beads_47.rtdc",
activate=True)
# create group for user1
group_dict = helpers.call_action(
"group_create",
name=f"test_group-{uuid.uuid4()}",
title="Tests for group permissions",
packages=[ds_dict_1],
context=create_context1,
)
# add users 2 and 3 to the group in different capacities
for user, capacity in [
[user2, "editor"],
[user3, "member"],
]:
helpers.call_action("member_create",
id=group_dict["id"],
object=user["id"],
object_type='user',
capacity=capacity)
# The admin of the group should be able to add a user
helpers.call_auth("member_create",
{'ignore_auth': False,
'user': user1['name'],
'api_version': 3},
object_type="user",
id=group_dict["id"])
# An editor of a group should not be able to add a user
with pytest.raises(logic.NotAuthorized):
helpers.call_auth("member_create",
{'ignore_auth': False,
'user': user2['name'],
'api_version': 3},
object_type="user",
id=group_dict["id"])
# A simple member of a group is not allowed to add another member
with pytest.raises(logic.NotAuthorized):
helpers.call_auth("member_create",
{'ignore_auth': False,
'user': user3['name'],
'api_version': 3},
object_type="user",
id=group_dict["id"])
# A random user is not allowed to add another member
with pytest.raises(logic.NotAuthorized):
helpers.call_auth("member_create",
{'ignore_auth': False,
'user': user4['name'],
'api_version': 3},
object_type="user",
id=group_dict["id"])
# An anonymous user is also not allowed
with pytest.raises(logic.NotAuthorized):
helpers.call_auth("member_create",
{'ignore_auth': False,
'user': None,
'api_version': 3},
object_type="package",
id=group_dict["id"])

@@ -11,2 +11,4 @@ import pytest

@pytest.mark.usefixtures('clean_db', 'with_plugins', 'with_request_context')
@pytest.mark.ckan_config('ckanext.dcor_schemas.allow_content_listing_for_anon',
'false')
def test_auth_group_show():

@@ -13,0 +15,0 @@ """Anonymous user not allowed to list group with users"""

Metadata-Version: 2.4
Name: ckanext-dcor_schemas
Version: 1.0.1
Version: 1.0.2
Summary: Introduces or lifts restrictions (authorization) for managing data and metadata on DCOR

@@ -5,0 +5,0 @@ Author: Paul Müller