Skip to content
This repository has been archived by the owner on Mar 17, 2024. It is now read-only.

Commit

Permalink
Feature/SK-290 | Varify form input for security (#52)
Browse files Browse the repository at this point in the history
Co-authored-by: Fredrik Wrede <fredrik@scaleoutsystems.com>
  • Loading branch information
niklastheman and Wrede committed Feb 23, 2023
1 parent d064c52 commit 18a4e78
Show file tree
Hide file tree
Showing 11 changed files with 604 additions and 286 deletions.
9 changes: 3 additions & 6 deletions generate_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ def get_form_apps(aset, project, myapp, user, appinstance=[]):
print(app_obj)
print(">>>>>")
# TODO: Only get app instances that we have permission to list.

app_instances = AppInstance.objects.filter(
Q(owner=user)
| Q(permission__projects__slug=project.slug)
| Q(permission__public=True),
~Q(state="Deleted"),
Q(owner=user) | Q(access__in=["project", "public"]),
project=project,
app__name=app_name,
)
Expand All @@ -78,10 +77,8 @@ def get_form_apps(aset, project, myapp, user, appinstance=[]):
# '"appobj.app_slug":"true"'
if app_name == "Environment":
app_instances = AppInstance.objects.filter(
Q(owner=user)
| Q(permission__projects__slug=project.slug)
| Q(permission__public=True),
~Q(state="Deleted"),
Q(owner=user) | Q(access__in=["project", "public"]),
project=project,
app__name=app_name,
parameters__contains={"appobj": {myapp.slug: True}},
Expand Down
68 changes: 68 additions & 0 deletions helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,71 @@ def create_instance_params(instance, action="create"):
instance.parameters["project"].update(
{"name": instance.project.name, "slug": instance.project.slug}
)


def can_access_app_instance(app_instance, user, project):
"""Checks if a user has access to an app instance
Args:
app_instance (AppInstance): app instance object
user (User): user object
project (Project): project object
Returns:
Boolean: returns False if user lack permission to provided app instance
"""
authorized = False

if app_instance.access == "public":
authorized = True
elif app_instance.access == "project":
if user.has_perm("can_view_project", project):
authorized = True
else:
if user.has_perm("can_access_app", app_instance):
authorized = True

return authorized


def can_access_app_instances(app_instances, user, project):
"""Checks if user has access to all app instances provided
Args:
app_instances (Queryset<AppInstace>): list of app instances
user (User): user object
project (Project): project object
Returns:
Boolean: returns False if user lacks
permission to any of the app instances provided
"""
for app_instance in app_instances:
authorized = can_access_app_instance(app_instance, user, project)

if not authorized:
return False

return True


def handle_permissions(parameters, project):
access = ""

if parameters["permissions"]["public"]:
access = "public"
elif parameters["permissions"]["project"]:
access = "project"

if "project" not in parameters:
parameters["project"] = dict()

parameters["project"]["client_id"] = project.slug
parameters["project"]["client_secret"] = project.slug
parameters["project"]["slug"] = project.slug
parameters["project"]["name"] = project.name

elif parameters["permissions"]["private"]:
access = "private"

return access
20 changes: 20 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from django.contrib.auth import get_user_model
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from guardian.shortcuts import assign_perm, remove_perm
from tagulous.models import TagField


Expand Down Expand Up @@ -105,6 +108,23 @@ def __str__(self):
)


@receiver(
post_save,
sender=AppInstance,
dispatch_uid="app_instance_update_permission",
)
def update_permission(sender, instance, created, **kwargs):
owner = instance.owner

if instance.access == "private":
if created or not owner.has_perm("can_access_app", instance):
assign_perm("can_access_app", owner, instance)

else:
if owner.has_perm("can_access_app", instance):
remove_perm("can_access_app", owner, instance)


class AppStatus(models.Model):
appinstance = models.ForeignKey(
"AppInstance", on_delete=models.CASCADE, related_name="status"
Expand Down
2 changes: 0 additions & 2 deletions serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ def serialize_S3(form_selection, project):
print("SERIALIZING S3")
s3_json = dict()
if "S3" in form_selection:

s3_id = form_selection.get("S3", None)
try:
obj = S3.objects.filter(pk=s3_id)
Expand Down Expand Up @@ -164,7 +163,6 @@ def serialize_apps(form_selection, project):
app_deps = []
for key in form_selection.keys():
if "app:" in key and key[0:4] == "app:":

app_name = key[4:]
try:
app = (
Expand Down
6 changes: 0 additions & 6 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ def deploy_resource(instance_pk, action="create"):
status = AppStatus(appinstance=app_instance)

if action == "create":

parameters = app_instance.parameters
status.status_type = "Created"
status.info = parameters["release"]
Expand Down Expand Up @@ -279,7 +278,6 @@ def delete_resource(pk):
@shared_task
@transaction.atomic
def delete_resource_permanently(appinstance):

parameters = appinstance.parameters

# Invoke chart controller
Expand Down Expand Up @@ -448,7 +446,6 @@ def check_status():

@app.task
def get_resource_usage():

timestamp = time.time()

args = ["kubectl", "get", "--raw", "/apis/metrics.k8s.io/v1beta1/pods"]
Expand Down Expand Up @@ -485,7 +482,6 @@ def get_resource_usage():

try:
for pod in pods:

podname = pod["metadata"]["name"]
if podname in resources:
containers = pod["containers"]
Expand Down Expand Up @@ -543,7 +539,6 @@ def sync_mlflow_models():
~Q(state="Deleted"), project__status="active", app__slug="mlflow"
)
for mlflow_app in mlflow_apps:

url = "http://{}/{}".format(
mlflow_app.project.mlflow.host,
"api/2.0/preview/mlflow/model-versions/search",
Expand Down Expand Up @@ -615,7 +610,6 @@ def sync_mlflow_models():

@app.task
def clean_resource_usage():

curr_timestamp = time.time()
ResourceData.objects.filter(time__lte=curr_timestamp - 48 * 3600).delete()

Expand Down
2 changes: 1 addition & 1 deletion templates/app_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<i class="align-middle me-1" data-feather="activity"></i> Logs (disabled)
</a>

{% if appinstance.app.settings.publishable == "true" %}
{% if appinstance.app.settings.publishable == "true" and appinstance.owner.id == request.user.id %}
{% if appinstance.access == "public" %}
<a class="dropdown-item" href="{% url 'apps:unpublish' request.user project.slug category appinstance.pk %}">
<i class="align-middle me-1" data-feather="slash"></i> Unpublish
Expand Down
78 changes: 2 additions & 76 deletions templates/create.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
{% load custom_tags %}

{% block content %}
<h1 class="h3 mb-3">{{ app_action }} {{ app.name }}</h1>
<h1 class="h3 mb-3">Create {{ app.name }}</h1>
<div class="row">
<div class="col-12 col-xl-6">
<div class="card">
<!-- <div class="card-header">
<h5 class="card-title">Basic form</h5>
<h6 class="card-subtitle text-muted">Default Bootstrap form layout.</h6>
</div> -->
<div class="card-body">
<form action="{% url 'apps:create' request.user project.slug app.slug %}?from={{ from_page }}" method="post">
{% csrf_token %}
Expand All @@ -31,7 +27,7 @@ <h6 class="card-subtitle text-muted">Default Bootstrap form layout.</h6>
{% endfor %}
</select>
</div>

{% if form.dep_permissions %}
<div class="mb-3">
<label class="form-label">Permissions</label>
Expand Down Expand Up @@ -97,7 +93,6 @@ <h6 class="card-subtitle text-muted">Default Bootstrap form layout.</h6>
</div>
{% endif %}


{% if form.dep_volumes %}
<div class="mb-3">
<label class="form-label">Volumes</label>
Expand All @@ -109,7 +104,6 @@ <h6 class="card-subtitle text-muted">Default Bootstrap form layout.</h6>
</div>
{% endif %}


{% if form.dep_apps %}
{% for app_name, appinstances in form.app_deps.items %}
<div class="mb-3">
Expand All @@ -123,10 +117,8 @@ <h6 class="card-subtitle text-muted">Default Bootstrap form layout.</h6>
{% endfor %}
{% endif %}


{% for key, vals in form.primitives.items %}

<!-- <label class="form-label">{{ key }}</label> -->
<h6> {{ vals.meta_title }}</h6>
{% for subkey, subval in vals.items %}
<div class="mb-3">
Expand Down Expand Up @@ -173,11 +165,7 @@ <h6> {{ vals.meta_title }}</h6>
</div>
{% endif %}

{% if app_action == "Create" %}
<button class="btn btn-primary" type="submit">Create</button>
{% else %}
<button class="btn btn-primary" type="submit">Update</button>
{% endif %}
<button class="btn btn-secondary float-end" type="submit" onclick="window.location='{{ request.headers.referer }}' ; return false;">
Cancel
</button>
Expand All @@ -186,66 +174,4 @@ <h6> {{ vals.meta_title }}</h6>
</div>
</div>
</div>
{% if app_action == "Settings" %}
<div class="row">
<div class="col-12 col-xl-6">
<div class="card">
<!-- <div class="card-header">
<h5 class="card-title">Basic form</h5>
<h6 class="card-subtitle text-muted">Default Bootstrap form layout.</h6>
</div> -->
<div class="card-body">
<form method="POST" autocomplete="off" action="{% url 'apps:add_tag' request.user project.slug appinstance.pk %}">
{% csrf_token %}

<div class="mb-3 row">
<dt class="col-4 col-xxl-3 mb-0">Add Tag</dt>
<dd class="col-4 col-xxl-9 mb-0">
{% if request.user.is_superuser %}
<input id="id_access" placeholder="Add Tag ..." type="text" name="tag" required class="form-control tag-form" list="add_tags" style="width: 50%;" />
<datalist id="add_tags">
{% for tag in all_tags %}
<option value="{{ tag }}">{{ tag }}</option>
{% endfor %}
</datalist>
{% else %}
<select id="id_access_add" type="text" name="tag" required class="search-select-tag form-select tag-form" style="width: 50%;">
<option></option>
{% for tag in all_tags %}
<option value="{{ tag }}">{{ tag }}</option>
{% endfor %}
</select>
{% endif %}
<button type="submit" class="btn btn-info btn-sm">
<i class="fas fa-save"></i>
Add
</button>
</dd>
</div>
</form>
<dl class="row">
<dt class="col-4 col-xxl-3 mb-0">Tags</dt>
<dd class="col-8 col-xxl-9 mb-0">
<div>
{% with appinstance.tags|split:"," as tags %}
{% for tag in tags %}
<!-- <span class="tag tag-model-details">{{ tag }}</span> -->
<form style="display: inline-flex;" method="POST" action="{% url 'apps:remove_tag' request.user project.slug appinstance.pk %}">
{% csrf_token %}
<div class="tag tag-list tag-model-details"><button class="tag-list-ico fas fa-times" style="color: #fffafa;" type="submit" name="tag" value="{{ tag }}"></button><span style="font-weight: 500;">{{ tag }}</span></div>
</form>
{% endfor %}
{% endwith %}

{% if appinstance.tags.count == 0 %}
<span>None</span>
{% endif %}
</div>
</dd>
</dl>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %}
Loading

0 comments on commit 18a4e78

Please sign in to comment.