Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3: Drop some of the deprecated features #1001

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions docs/user-guide/9-Sharing-objects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,6 @@ Each capability has its own name and scope:

Allows to access all users and groups in MWDB. Rules described in *Who is who?* don't apply to users with that permission. Enables user to create new user accounts, new groups and change their capabilities and membership. Allows to manage attribute keys, define new ones, delete and set the group permissions for them.

*
**share_queried_objects - Query for all objects in system**

That one is a bit tricky and will be possibly deprecated. MWDB will automatically share object and all descendants with group if member directly accessed it via identifier (knows the hash e.g. have direct link to the object). It can be used for bot accounts, so they have access only to these objects that are intended to be processed by them. Internally, we abandoned that idea, so that capability may not be stable.

*
**access_all_objects - Has access to all uploaded objects into system**

Expand Down
33 changes: 0 additions & 33 deletions mwdb/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

from mwdb.core.app import api, app
from mwdb.core.config import app_config
from mwdb.core.deprecated import DeprecatedFeature, uses_deprecated_api
from mwdb.core.log import getLogger, setup_logger
from mwdb.core.metrics import metric_api_requests, metrics_enabled
from mwdb.core.plugins import PluginAppContext, load_plugins
Expand Down Expand Up @@ -42,7 +41,6 @@
ConfigResource,
ConfigStatsResource,
)
from mwdb.resources.download import DownloadResource, RequestSampleDownloadResource
from mwdb.resources.file import (
FileDownloadResource,
FileDownloadZipResource,
Expand All @@ -51,13 +49,6 @@
)
from mwdb.resources.group import GroupListResource, GroupMemberResource, GroupResource
from mwdb.resources.karton import KartonAnalysisResource, KartonObjectResource
from mwdb.resources.metakey import (
MetakeyDefinitionManageResource,
MetakeyListDefinitionManageResource,
MetakeyListDefinitionResource,
MetakeyPermissionResource,
MetakeyResource,
)
from mwdb.resources.metrics import MetricsResource
from mwdb.resources.oauth import (
OpenIDAccountIdentitiesResource,
Expand Down Expand Up @@ -88,7 +79,6 @@
RemoteTextBlobPullResource,
RemoteTextBlobPushResource,
)
from mwdb.resources.search import SearchResource
from mwdb.resources.server import (
PingResource,
ServerAdminInfoResource,
Expand Down Expand Up @@ -204,11 +194,6 @@ def require_auth():
# Not a session token? Maybe APIKey token
if g.auth_user is None:
g.auth_user = APIKey.verify_token(token)
# Still nothing? Maybe legacy API key
if g.auth_user is None:
g.auth_user = User.verify_legacy_token(token)
if g.auth_user is not None:
uses_deprecated_api(DeprecatedFeature.legacy_api_key_v1)

if g.auth_user:
if (
Expand Down Expand Up @@ -307,13 +292,6 @@ def apply_rate_limit():
api.add_resource(TextBlobResource, "/blob")
api.add_resource(TextBlobItemResource, "/blob/<hash64:identifier>")

# Download endpoints
api.add_resource(RequestSampleDownloadResource, "/request/sample/<identifier>")
api.add_resource(DownloadResource, "/download/<access_token>")

# Search endpoints
api.add_resource(SearchResource, "/search")

# Quick query endpoints
api.add_resource(
QuickQueryResource, "/<any(file, config, blob, object):type>/quick_query"
Expand All @@ -334,17 +312,6 @@ def apply_rate_limit():
api.add_resource(AttributeDefinitionResource, "/attribute/<key>")
api.add_resource(AttributePermissionResource, "/attribute/<key>/permissions")

# Attribute (metakey) deprecated endpoints
api.add_resource(MetakeyListDefinitionResource, "/meta/list/<any(read, set):access>")
api.add_resource(
MetakeyResource, "/<any(file, config, blob, object):type>/<hash64:identifier>/meta"
)
api.add_resource(MetakeyListDefinitionManageResource, "/meta/manage")
api.add_resource(MetakeyDefinitionManageResource, "/meta/manage/<key>")
api.add_resource(
MetakeyPermissionResource, "/meta/manage/<key>/permissions/<group_name>"
)

# Karton endpoints
api.add_resource(
KartonObjectResource,
Expand Down
6 changes: 3 additions & 3 deletions mwdb/core/auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import datetime
from enum import Enum
from typing import Any, Set
from typing import Any

import jwt

Expand Down Expand Up @@ -52,14 +52,14 @@ def verify_token(token: str, scope: AuthScope) -> Any:
return data


def verify_legacy_token(token: str, required_fields: Set[str]) -> Any:
def verify_legacy_api_key(token: str) -> Any:
try:
data = jwt.decode(
token,
key=app_config.mwdb.secret_key,
algorithms=["HS512"],
)
if set(data.keys()) != required_fields:
if set(data.keys()) != {"login", "api_key_id"}:
return None

except jwt.InvalidTokenError:
Expand Down
2 changes: 0 additions & 2 deletions mwdb/core/capabilities.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
class Capabilities(object):
# Can create/update users and groups
manage_users = "manage_users"
# Queried objects by members are automatically shared with this group
share_queried_objects = "share_queried_objects"
# All new uploaded objects are automatically shared with this group
access_all_objects = "access_all_objects"
# Can share objects with all groups, have access to complete list of groups
Expand Down
26 changes: 0 additions & 26 deletions mwdb/core/deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,9 @@


class DeprecatedFeature(Enum):
# Unmanageable API keys, deprecated in v2.0.0
legacy_api_key_v1 = "legacy_api_key_v1"
# API keys non-complaint with RFC7519
# Deprecated in v2.7.0
legacy_api_key_v2 = "legacy_api_key_v2"
# Legacy PUT/POST /api/<object_type>/<parent>
# Use POST /api/<object_type> instead
# Deprecated in v2.0.0
legacy_object_upload = "legacy_file_upload"
# Legacy /request/sample/<token>
# Use /file/<id>/download instead
# Deprecated in v2.2.0
legacy_file_download = "legacy_file_download"
# Legacy /search
# Use GET /<object_type> instead
# Deprecated in v2.0.0
legacy_search = "legacy_search"
# Legacy ?page parameter in object listing endpoints
# Use "?older_than" instead
# Deprecated in v2.0.0
legacy_page_parameter = "legacy_page_parameter"
# Legacy Metakey API
# Use Attribute API instead
# Deprecated in v2.6.0
legacy_metakey_api = "legacy_metakey_api"
# Legacy Metakey API
# Use Attribute API instead
# Deprecated in v2.6.0
legacy_metakeys_upload_option = "legacy_metakeys_upload_option"


def uses_deprecated_api(
Expand Down
9 changes: 7 additions & 2 deletions mwdb/model/api_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm.exc import NoResultFound

from mwdb.core.auth import AuthScope, generate_token, verify_legacy_token, verify_token
from mwdb.core.auth import (
AuthScope,
generate_token,
verify_legacy_api_key,
verify_token,
)
from mwdb.core.deprecated import DeprecatedFeature, uses_deprecated_api

from . import db
Expand Down Expand Up @@ -35,7 +40,7 @@ def verify_token(token):

if data is None:
# check for legacy API Token
data = verify_legacy_token(token, required_fields={"login", "api_key_id"})
data = verify_legacy_api_key(token)
if data is None:
return None
else:
Expand Down
10 changes: 0 additions & 10 deletions mwdb/model/attribute.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from string import Template

from flask import g
from sqlalchemy import cast, func
from sqlalchemy.dialects.postgresql import JSONB
Expand Down Expand Up @@ -35,14 +33,6 @@ class Attribute(db.Model):
value = db.Column(JSONB, nullable=False)
template = db.relationship("AttributeDefinition", lazy="joined")

@property
def url(self):
# deprecated, left for metakey compatibility
if self.template.url_template:
s = Template(self.template.url_template)
return s.safe_substitute(value=self.value)
return None

@property
def label(self):
return self.template.label
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Remove share_queried_objects from groups

Revision ID: 465b589d0362
Revises: 56adf974831e
Create Date: 2024-12-12 14:39:21.117379

"""
from alembic import op

# revision identifiers, used by Alembic.
revision = "465b589d0362"
down_revision = "56adf974831e"
branch_labels = None
depends_on = None


def upgrade():
op.execute(
"UPDATE \"group\" SET capabilities = array_remove(capabilities, 'share_queried_objects');"
)
pass


def downgrade():
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Removed User.version_uid column

Revision ID: 56adf974831e
Revises: 52bb55f76ef3
Create Date: 2024-12-11 18:21:42.442984

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "56adf974831e"
down_revision = "52bb55f76ef3"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("user", "version_uid")
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"user",
sa.Column(
"version_uid", sa.VARCHAR(length=16), autoincrement=False, nullable=True
),
)
# ### end Alembic commands ###
56 changes: 5 additions & 51 deletions mwdb/model/object.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import datetime
from collections import namedtuple
from typing import Any, Dict, Optional
from uuid import UUID

Expand Down Expand Up @@ -475,8 +474,6 @@ def access(cls, identifier, requestor=None):
(default: currently authenticated user)
:return: Object instance or None
"""
from .group import Group

if requestor is None:
requestor = g.auth_user

Expand All @@ -489,23 +486,6 @@ def access(cls, identifier, requestor=None):
if obj.has_explicit_access(requestor):
return obj

# If not, but has "share_queried_objects" rights: give_access
if requestor.has_rights(Capabilities.share_queried_objects):
share_queried_groups = (
db.session.query(Group)
.filter(
and_(
Group.capabilities.contains(
[Capabilities.share_queried_objects]
),
requestor.is_member(Group.id),
)
)
.all()
)
for group in share_queried_groups:
obj.give_access(group.id, AccessType.QUERIED, obj, requestor)
return obj
# Well.. I've tried
return None

Expand Down Expand Up @@ -596,7 +576,6 @@ def get_attributes(
as_dict=False,
check_permissions=True,
show_hidden=False,
show_karton=False,
):
"""
Gets all object attributes
Expand All @@ -606,7 +585,6 @@ def get_attributes(
:param check_permissions: |
Filter results including current user permissions (default: True)
:param show_hidden: Show hidden attributes
:param show_karton: Show Karton attributes (for compatibility)
"""
attributes = (
db.session.query(Attribute)
Expand All @@ -630,19 +608,6 @@ def get_attributes(

attributes = attributes.order_by(Attribute.id).all()

if show_karton:
KartonAttribute = namedtuple("KartonAttribute", ["key", "value"])

attributes += [
KartonAttribute(key="karton", value=str(analysis.id))
for analysis in (
db.session.query(KartonAnalysis)
.filter(KartonAnalysis.objects.any(id=self.id))
.order_by(KartonAnalysis.creation_time)
.all()
)
]

if not as_dict:
return attributes

Expand All @@ -654,23 +619,12 @@ def get_attributes(
return dict_attributes

def add_attribute(
self, key, value, commit=True, check_permissions=True, include_karton=True
self,
key,
value,
commit=True,
check_permissions=True,
):
if include_karton and key == "karton":
karton_id = UUID(value)

if check_permissions and not g.auth_user.has_rights(
Capabilities.karton_assign
):
# User doesn't have permissions to assign analysis
return None

_, is_new = self.assign_analysis(karton_id, commit=False)

if commit:
db.session.commit()
return is_new

if check_permissions:
attribute_definition = AttributeDefinition.query_for_set(key).first()
else:
Expand Down
Loading
Loading