Skip to content

[WIP] Access Control Enhancements #644

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

Draft
wants to merge 23 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
802a875
Merge pull request #1 from amber-vale/add-devcontainer
lowlandghost Jun 29, 2024
875b748
Merge branch 'dfir-iris:develop' into develop
lowlandghost Jul 4, 2024
54af989
rbac: start of new models & bizlogic
lowlandghost Jul 4, 2024
fbfd0a1
app: do not run post-init unless the app is actually starting
lowlandghost Jul 4, 2024
93f160e
alembic: start of rbac table migration
lowlandghost Jul 4, 2024
e24e4b4
gitignore: add `.devcontainer`
lowlandghost Jul 4, 2024
5b29920
remove devcontainer config
lowlandghost Jul 4, 2024
349840e
[ADD] Authz Resources schema & config file
lowlandghost Nov 30, 2024
d445357
[ADD] `Authorization` class stub
lowlandghost Nov 30, 2024
dbfaee8
[ADD] New `UnauthorizedException` to handle authz denied
lowlandghost Nov 30, 2024
a6c72cd
[ADD] Root v2 API blueprint + unauthz & biz error handling
lowlandghost Nov 30, 2024
e5b27de
[IMP] Rework cases v2 api to use more BPs & less error handling
lowlandghost Nov 30, 2024
a123f28
[FIX] bad imports containing `source` path
lowlandghost Nov 30, 2024
2b1667e
[IMP] Hook error handlers better
lowlandghost Nov 30, 2024
fc329f8
[IMP] Update views to use API V2 root BP
lowlandghost Nov 30, 2024
d8e5ebc
[ADD] Watch option to the dev compose for the webapp
lowlandghost Nov 30, 2024
c5e0e8f
[IMP] Register the case with ID BP too
lowlandghost Nov 30, 2024
f809c90
[WIP] First attempt at adding additional tests, harness seems broken
lowlandghost Nov 30, 2024
aebe995
[FIX] deepsource PYL-W0102 for `perform_request` in tests
lowlandghost Nov 30, 2024
d89bfe1
[IMP] apply pep8 formatting to all changed files so far
lowlandghost Nov 30, 2024
f2f916f
[IMP] Modify how the flask app is built when testing
lowlandghost Nov 30, 2024
f796f1d
[IMP] Fix broken type and usage of `url_for()`
lowlandghost Nov 30, 2024
e3b1c5b
Merge branch 'access-control-enhancements' of https://github.com/ambe…
lowlandghost Jan 26, 2025
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
15 changes: 0 additions & 15 deletions .devcontainer/Dockerfile

This file was deleted.

48 changes: 0 additions & 48 deletions .devcontainer/devcontainer.json

This file was deleted.

62 changes: 0 additions & 62 deletions .devcontainer/docker-compose.yml

This file was deleted.

12 changes: 0 additions & 12 deletions .devcontainer/post-create.sh

This file was deleted.

11 changes: 0 additions & 11 deletions .devcontainer/pre-create.sh

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ venv1/
.env*
.venv/
.vscode/
.devcontainer/
*.code-workspace
nohup.out
celerybeat-schedule.db
Expand Down
9 changes: 6 additions & 3 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

services:

rabbitmq:
extends:
file: docker-compose.base.yml
Expand All @@ -43,11 +42,16 @@ services:
ports:
- "127.0.0.1:8000:8000"
volumes:
- ./source/app:/iriswebapp/app
# - ./source/app:/iriswebapp/app
- ./ui/dist:/iriswebapp/static
healthcheck:
test: curl --head --fail http://localhost:8000 || exit 1
start_period: 60s
develop:
watch:
- action: sync+restart
path: ./source/app
target: /iriswebapp/app

worker:
extends:
Expand All @@ -71,7 +75,6 @@ services:
NGINX_CONF_FILE: nginx.conf
image: iriswebapp_nginx:develop


volumes:
iris-downloads:
user_templates:
Expand Down
7 changes: 5 additions & 2 deletions source/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import json
import logging as logger
import os
import sys
import urllib.parse
from flask import Flask
from flask import session
Expand Down Expand Up @@ -111,7 +112,7 @@ def ac_current_user_has_manage_perms():
lm = LoginManager() # flask-loginmanager
lm.init_app(app) # init the login manager

ma = Marshmallow(app) # Init marshmallow
ma = Marshmallow(app) # Init marshmallow

dropzone = Dropzone(app)

Expand Down Expand Up @@ -139,4 +140,6 @@ def shutdown_session(exception=None):
db.session.remove()


from app import views
# Only import the remainder of the app if we are actually launching the app
if ".py" in sys.argv[0]:
from app import views
7 changes: 4 additions & 3 deletions source/app/alembic/env.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from app.configuration import SQLALCHEMY_BASE_ADMIN_URI, PG_DB_
import os
from alembic import context
from logging.config import fileConfig
from sqlalchemy import engine_from_config
Expand All @@ -11,13 +13,12 @@
# This line sets up loggers basically.
fileConfig(config.config_file_name)

import os
os.environ["ALEMBIC"] = "1"

from app.configuration import SQLALCHEMY_BASE_ADMIN_URI, PG_DB_

config.set_main_option('sqlalchemy.url', SQLALCHEMY_BASE_ADMIN_URI + PG_DB_)


# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
Expand Down Expand Up @@ -72,7 +73,7 @@ def run_migrations_online():
connection=connection, target_metadata=target_metadata
)

#with context.begin_transaction(): -- Fixes stuck transaction. Need more info on that
# with context.begin_transaction(): -- Fixes stuck transaction. Need more info on that
context.run_migrations()


Expand Down
69 changes: 69 additions & 0 deletions source/app/alembic/versions/c7a7606e930c_add_rbac_role_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Add RBAC Role tables

Revision ID: c7a7606e930c
Revises: 11aa5b725b8e
Create Date: 2024-07-04 12:26:01.299980

"""
from alembic import op
import sqlalchemy as sa
from app.alembic.alembic_utils import _has_table

# revision identifiers, used by Alembic.
revision = 'c7a7606e930c'
down_revision = '11aa5b725b8e'
branch_labels = None
depends_on = None


def upgrade():
"""Apply this upgrade by creating all the new RBAC tables"""

bind = op.get_bind()

# Create `role` table
if not _has_table("role"):
role_table = sa.Table(
'role', sa.MetaData(),
sa.Column('role_id', sa.BigInteger, primary_key=True),
sa.Column('name', sa.String(64)),
sa.Column('description', sa.Text),
sa.Column('entitlements', sa.JSON)
)
role_table.create(bind)

# Create `organisation_role` table
if not _has_table("organisation_role"):
organisation_role_table = sa.Table(
'organisation_role', sa.MetaData(),
sa.Column('role_id', sa.BigInteger, sa.ForeignKey(
'role.role_id'), primary_key=True),
sa.Column('org_id', sa.BigInteger, sa.ForeignKey(
'organisations.org_id'), primary_key=True),
sa.UniqueConstraint('role_id', 'org_id')
)
organisation_role_table.create(bind)

# Create `case_role` table
if not _has_table("case_role"):
case_role_table = sa.Table(
'case_role', sa.MetaData(),
sa.Column('role_id', sa.BigInteger, sa.ForeignKey(
'role.role_id'), primary_key=True),
sa.Column('case_id', sa.BigInteger, sa.ForeignKey(
'cases.case_id'), primary_key=True),
sa.UniqueConstraint('role_id', 'case_id')
)
case_role_table.create(bind)

bind.commit()


def downgrade():
"""
Downgrade this migration by dropping all the newly created tables
"""

op.drop_table('role')
op.drop_table('organisation_role')
op.drop_table('case_role')
5 changes: 5 additions & 0 deletions source/app/blueprints/authorization/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Authorization:
"""`Authorization` class is responsible for handling permission validation, access checks, and more for blueprints."""

def __init__(self) -> None:
pass
29 changes: 29 additions & 0 deletions source/app/blueprints/authorization/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import Optional
from flask_login import current_user
import werkzeug.exceptions


class UnauthorizedException(werkzeug.exceptions.Forbidden):
"""`UnauthorizedException` will be raised when an access control check fails.

Args:
resource (str): The resource type
action (str): The type of action performed
resource_id (str, optional): The resource ID that was the action attempt was for

Returns:
`UnauthorizedException` with args:
0, user_id, optional
1, resource
2, action
3, resource_id, optional
"""

def __init__(self, resource, action, resource_id: Optional[str] = None) -> None:
# Get current user ID
user_id = current_user.id if current_user.is_authenticated else None

# Set exception args
self.args = (user_id, resource, action, resource_id)

super().__init__()
33 changes: 33 additions & 0 deletions source/app/blueprints/authorization/resources.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Resources",
"type": "object",
"required": [],
"additionalProperties": {
"type": "object",
"$ref": "#/definitions/resource"
},
"definitions": {
"resource": {
"type": "object",
"properties": {
"actions": {
"$comment": "The allowed type of actions to take against a resource, multiple allowed.",
"description": "What actions are allowed to be performed against this resource? Options: create, read, update, delete.",
"type": "array",
"items": {
"type": "string",
"enum": ["create", "read", "update", "delete"]
},
"minItems": 1
},
"description": {
"$comment": "Friendly description of the resource, used for UI.",
"description": "Describe what this resource is for.",
"type": "string"
}
},
"required": ["actions", "description"]
}
}
}
Loading