Works almost

This commit is contained in:
2023-09-28 17:29:30 +02:00
parent 175e13da4f
commit 92546024d8
147 changed files with 31229 additions and 70 deletions

19
abac/forms.py Normal file
View File

@@ -0,0 +1,19 @@
from django import forms
from .models import File, RuleAttribute, AttributeType
class FileUploadForm(forms.ModelForm):
class Meta:
model = File
fields = ['name', 'file']
class UploadCertificateForm(forms.Form):
certificate = forms.FileField()
class RuleAttributeForm(forms.ModelForm):
class Meta:
model = RuleAttribute
fields = ['attribute_type', 'operator', 'value']
attribute_type = forms.ModelChoiceField(queryset=AttributeType.objects.all())

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.5 on 2023-09-21 17:15
# Generated by Django 4.2.5 on 2023-09-28 12:45
from django.conf import settings
import django.contrib.auth.models
@@ -43,49 +43,61 @@ class Migration(migrations.Migration):
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='Attribute',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('value', models.IntegerField()),
],
),
migrations.CreateModel(
name='AttributeType',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_secret', models.BooleanField(default=False)),
('is_private', models.BooleanField(default=False)),
('datatype', models.CharField(max_length=15)),
('significant_digits', models.PositiveIntegerField(blank=True, null=True)),
('name', models.CharField(max_length=40)),
],
),
migrations.CreateModel(
name='Rule',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('rule_type', models.CharField(choices=[('and', 'AND'), ('or', 'OR')], max_length=3)),
('attributes', models.ManyToManyField(to='abac.attribute')),
],
),
migrations.CreateModel(
name='File',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('file', models.FileField(upload_to='uploads/')),
('created_at', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('rules', models.ManyToManyField(to='abac.rule')),
],
options={
'ordering': ['name', 'created_at'],
},
),
migrations.CreateModel(
name='Rule',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abac.file')),
],
),
migrations.AddField(
model_name='attribute',
name='attribute_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abac.attributetype'),
migrations.CreateModel(
name='Attribute',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('value', models.IntegerField()),
('last_modified', models.DateTimeField(auto_now=True)),
('attribute_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abac.attributetype')),
],
),
migrations.AddField(
model_name='attribute',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
migrations.CreateModel(
name='UserAttribute',
fields=[
('attribute_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='abac.attribute')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
bases=('abac.attribute',),
),
migrations.CreateModel(
name='RuleAttribute',
fields=[
('attribute_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='abac.attribute')),
('rule', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abac.rule')),
],
bases=('abac.attribute',),
),
]

View File

@@ -0,0 +1,42 @@
# Generated by Django 4.2.5 on 2023-09-28 13:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('abac', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='attribute',
name='last_modified',
),
migrations.AddField(
model_name='rule',
name='delete',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='rule',
name='read',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='rule',
name='write',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='ruleattribute',
name='option',
field=models.CharField(choices=[('EQ', 'Equals'), ('NEQ', "Doesn't Equal"), ('GT', 'Greater Than'), ('LT', 'Less Than')], default='EQ', max_length=3),
),
migrations.AddField(
model_name='userattribute',
name='last_modified',
field=models.DateTimeField(auto_now=True),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2023-09-28 14:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('abac', '0002_remove_attribute_last_modified_rule_delete_rule_read_and_more'),
]
operations = [
migrations.RenameField(
model_name='ruleattribute',
old_name='option',
new_name='operator',
),
]

View File

@@ -2,6 +2,7 @@ import pickle
from base64 import b64encode, b64decode
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
class User(AbstractUser):
@@ -37,7 +38,7 @@ class AttributeType(models.Model):
('integer', 'Integer'),
]
is_secret = models.BooleanField(default=False)
is_private = models.BooleanField(default=False)
datatype = models.CharField(max_length=15)
significant_digits = models.PositiveIntegerField(null=True, blank=True)
name = models.CharField(max_length=40)
@@ -51,24 +52,52 @@ class AttributeType(models.Model):
raise ValueError('significant_digits must be None for non-float datatype')
super().save(*args, **kwargs)
def __str__(self) -> str:
return self.name
class Attribute(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
attribute_type = models.ForeignKey(AttributeType, on_delete=models.CASCADE)
value = models.IntegerField() # assuming value is always stored as an integer
value = models.IntegerField()
class Rule(models.Model):
TYPE_CHOICES = [
('and', 'AND'),
('or', 'OR'),
]
rule_type = models.CharField(max_length=3, choices=TYPE_CHOICES)
attributes = models.ManyToManyField(Attribute)
class UserAttribute(Attribute):
user = models.ForeignKey(User, on_delete=models.CASCADE)
last_modified = models.DateTimeField(auto_now=True)
class File(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
file = models.FileField(upload_to='uploads/') # assuming you are using FileField to store the file
rules = models.ManyToManyField(Rule)
file = models.FileField(upload_to='uploads/')
created_at = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Meta:
ordering = ['name', 'created_at']
class Rule(models.Model):
name = models.CharField(max_length=255)
file = models.ForeignKey(File, on_delete=models.CASCADE)
read = models.BooleanField(default=False)
write = models.BooleanField(default=False)
delete = models.BooleanField(default=False)
class RuleAttribute(Attribute):
OPTION_EQUALS = 'EQ'
OPTION_DOES_NOT_EQUAL = 'NEQ'
OPTION_GREATER_THAN = 'GT'
OPTION_LESS_THAN = 'LT'
OPTION_CHOICES = [
('EQ', 'Equals'),
('NEQ', "Doesn't Equal"),
('GT', 'Greater Than'),
('LT', 'Less Than'),
]
rule = models.ForeignKey(Rule, on_delete=models.CASCADE)
operator = models.CharField(max_length=3, choices=OPTION_CHOICES, default=OPTION_EQUALS)

7
abac/static/abac/main.js Normal file
View File

@@ -0,0 +1,7 @@
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('tr[data-url]').forEach(row => {
row.addEventListener('click', function() {
window.location.href = row.dataset.url;
});
});
});

View File

@@ -0,0 +1,4 @@
tr[data-url]:hover {
cursor: pointer;
background-color: #e8e8e8; /* Or any other color you prefer */
}

View File

@@ -1,4 +1,4 @@
<!-- abac/templates/base.html -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
@@ -8,29 +8,32 @@
<title>{% block title %}Privacy Preserving ABAC{% endblock %}</title>
<!-- Bootstrap CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<link rel="stylesheet" href="{% static 'abac/styles.css' %}"> <!-- Include CSS file -->
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="{% url 'home' %}">Privacy Preserving ABAC</a>
<a class="navbar-brand" href="{% url 'abac:home' %}">Privacy Preserving ABAC</a>
<span class="navbar-text ml-auto">
{% if user.is_authenticated %}
{{ user.username }}
<a class="btn btn-outline-light ml-3" href="{% url 'logout' %}">Logout</a>
<a href="{% url 'abac:user_details' username=user.username %}"> {{ user.username }}</a>
<a class="btn btn-outline-light ml-3" href="{% url 'abac:logout' %}">Logout</a>
{% else %}
<a class="btn btn-outline-light" href="{% url 'login' %}">Login</a>
<a class="btn btn-outline-light" href="{% url 'abac:login' %}">Login</a>
{% endif %}
</span>
</nav>
{% if user.is_authenticated %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<button class="btn btn-primary">Upload File</button>
<button class="btn btn-primary" onclick="window.location.href='{% url 'abac:upload_file' %}'">Upload File</button>
{% if perms.abac.can_create_users %}
<button class="btn btn-primary ml-2">Create User</button>
<button class="btn btn-primary ml-2">User Management</button>
{% endif %}
<span class="ml-auto">
<button class="btn btn-primary">Upload Certificate</button>
<button class="btn btn-primary" onclick="window.location.href='{% url 'abac:upload_certificate' %}'">Upload Certificate</button>
</span>
</nav>
{% endif %}
@@ -44,7 +47,7 @@
<footer class="footer mt-auto py-3 bg-dark text-white">
<div class="container text-center">
<span>© 2023 Privacy Preserving ABAC</span>
<span>© 2023 Masterthesis Malte Kerl Applications of Homomorphic Encryption in Attribute Based Access Control (ABAC) Systems </span>
</div>
</footer>

View File

@@ -0,0 +1,26 @@
{% extends 'base.html' %}
{% block content %}
<div class="container mt-3">
<h2>{{ file.name }}</h2>
<p>Created At: {{ file.created_at|date:"F d, Y H:i" }}</p>
<p>Last Modified: {{ file.last_modified|date:"F d, Y H:i" }}</p>
<form method="post" action="{% url 'abac:create_rule' file.id %}">
{% csrf_token %}
<label for="rule_name">Rule Name:</label>
<input type="text" name="rule_name" required>
<button type="submit" class="btn btn-primary">Add Rule</button>
</form>
{% for rule in rules %}
<div class="bg-light p-3 my-2">
<h4>{{ rule.name }}</h4>
<a href="{% url 'abac:rule_detail' file_id=file.id rule_id=rule.id %}">View Details</a>
</div>
{% empty %}
<p>No rules have been added yet.</p>
{% endfor %}
</div>
{% endblock %}

View File

@@ -0,0 +1,12 @@
{% extends 'base.html' %}
{% block content %}
<div class="container">
<h2>Upload File</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Upload</button>
</form>
</div>
{% endblock %}

View File

@@ -1,14 +1,42 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}ABAC Home{% endblock %}
{% block title %}Landing Page{% endblock %}
{% block content %}
<h2>All Files</h2>
<ul>
{% for file in files %}
<li>{{ file.name }}</li>
{% empty %}
<li>No files have been uploaded yet.</li>
{% endfor %}
</ul>
{% endblock %}
<div class="container mt-3">
<table class="table">
<thead>
<tr>
<th scope="col">File Name</th>
<th scope="col">Owner</th>
<th scope="col">Created At</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{% for file in files %}
<tr data-url="{% url 'abac:file_detail' file_id=file.id %}"> <!-- Add data-url attribute here -->
<td>{{ file.name }}</td>
<td>{{ file.owner.username }}</td>
<td>{{ file.created_at|date:"F d, Y H:i" }}</td>
<td>
<a href="{{ file.file.url }}" download="{{ file.name }}" class="btn btn-outline-primary btn-sm">
<i class="bi bi-download"></i> Download
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" class="text-center">No files have been uploaded yet.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script src="{% static 'abac/main.js' %}"></script>
{% endblock %}

View File

@@ -0,0 +1,48 @@
{% extends 'base.html' %}
{% block content %}
<header>
<h1>{{ rule.name }}</h1>
<p>File Owner: {{ rule.file.owner.username }}</p>
<a href="{% url 'abac:file_detail' file_id=rule.file.id %}">Back to {{ rule.file.name }}</a>
</header>
<div class="container">
<h2>{{ rule.name }} Details</h2>
<table class="table">
<thead>
<tr>
<th>Attribute Name</th>
<th>Operator</th>
<th>Value</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for rule_attribute in rule_attributes %}
<tr>
<td>{{ rule_attribute.attribute_type.name }}</td>
<td>{{ rule_attribute.operator }}</td>
<td>{{ rule_attribute.value }}</td>
<td>
<a href="{% url 'abac:delete_rule_attribute' file_id=file.id rule_id=rule.id rule_attribute_id=rule_attribute.id %}" class="btn btn-danger">Delete</a>
</td>
</tr>
{% endfor %}
<tr>
<!-- Form to add new RuleAttribute -->
<form method="post" action="{% url 'abac:rule_detail' file_id=file.id rule_id=rule.id %}">
{% csrf_token %}
<td>{{ form.attribute_type }}</td>
<td>{{ form.operator }}</td>
<td>{{ form.value }}</td>
<td><input type="submit" class="btn btn-success" value="Add"></td>
</form>
</tr>
</tbody>
</table>
</div>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends 'base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
{% endblock %}

View File

@@ -0,0 +1,33 @@
{% extends 'base.html' %}
{% block content %}
<h2>{{ user.username }}'s Attributes</h2>
<table class="table">
<thead>
<tr>
<th scope="col">Attribute Name</th>
<th scope="col">Last Modified</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
{% for attribute in attributes %}
<tr>
<td>{{ attribute.attribute_type.name }}</td>
<td>{{ attribute.last_modified|date:"F d, Y H:i" }}</td>
<td>
{% if not attribute.attribute_type.is_private %}
{{ attribute.value }}
{% else %}
<i>Private</i>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="3">This user has no attributes.</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -3,9 +3,32 @@
from django.contrib.auth import views as auth_views
from django.urls import path
from .views import landing_page
from .views import (
landing_page,
login_view,
logout_view,
upload_file_view,
create_user_view,
upload_certificate_view,
file_detail,
create_rule,
rule_detail,
user_detail_view,
delete_rule_attribute,
)
app_name = 'abac'
urlpatterns = [
path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
path('', landing_page, name='home'),
]
path('login/', auth_views.LoginView.as_view(template_name='login.html', success_url='/'), name='login'),
path('logout/', logout_view, name='logout'),
path('upload-file/', upload_file_view, name='upload_file'),
path('create-user/', create_user_view, name='create_user'),
path('upload-certificate/', upload_certificate_view, name='upload_certificate'),
path('files/<int:file_id>/', file_detail, name='file_detail'),
path('files/<int:file_id>/create_rule/', create_rule, name='create_rule'),
path('rules/<int:file_id>/<int:rule_id>/',rule_detail, name='rule_detail'),
path('user/<str:username>/', user_detail_view, name='user_details'),
path('rules/<int:file_id>/<int:rule_id>/delete/<int:rule_attribute_id>/', delete_rule_attribute, name='delete_rule_attribute'),
]

View File

@@ -1,9 +1,19 @@
from django.shortcuts import render
from django.shortcuts import render, redirect, get_object_or_404
from django.http.response import HttpResponseNotAllowed
from django.contrib.auth.decorators import permission_required
from django.http import HttpResponse
from django.contrib.auth.decorators import permission_required, login_required
from django.http import HttpResponse, JsonResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotAllowed
from django.contrib.auth import logout
from django.urls import reverse
from django.views.generic.detail import SingleObjectMixin, DetailView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.utils import timezone
from .models import File
import json
from .forms import FileUploadForm, UploadCertificateForm, RuleAttributeForm
from .models import File, Rule, UserAttribute, RuleAttribute, AttributeType, User
def create_user(request):
special_user = request.user
@@ -18,7 +28,150 @@ def create_user_view(request):
# Your view logic here
return HttpResponse('New user created')
@login_required
def landing_page(request):
files = File.objects.all()
return render(request, 'landing_page.html', {'files': files})
return render(request, 'landing_page.html', {'files': files})
def login_view(request):
return HttpResponse('Login View')
def logout_view(request):
logout(request)
return redirect('abac:login')
@login_required
def upload_file_view(request):
if request.method == 'POST':
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
file_instance = form.save(commit=False)
file_instance.owner = request.user # Assign the logged-in user as the owner of the uploaded file.
file_instance.save()
return redirect('abac:home') # Redirect to the landing page after a successful file upload.
else:
form = FileUploadForm()
return render(request, 'file_upload.html', {'form': form})
def create_user_view(request):
return HttpResponse('Create User View')
@login_required
def upload_certificate_view(request):
if request.method == 'POST':
uploaded_file = request.FILES.get('certificate')
if not uploaded_file:
return HttpResponseBadRequest('No file uploaded.')
certificate_data = json.load(uploaded_file)
for attribute_data in certificate_data:
name = attribute_data.get('name')
value = attribute_data.get('value')
# Assuming you have a method to get or create AttributeType
attribute_type = get_or_create_attribute_type(name, value, private=True)
attribute, created = UserAttribute.objects.update_or_create(
user=request.user,
attribute_type=attribute_type,
defaults={'value': value, 'last_modified': timezone.now()}
)
messages.success(request, 'Certificate uploaded successfully.')
return redirect('abac:user_details', username=request.user.username)
else:
form = UploadCertificateForm()
return render(request, 'upload_certificate.html', {'form': form})
@login_required
def file_detail(request, file_id):
file = get_object_or_404(File, id=file_id)
rules = Rule.objects.filter(file=file)
return render(request, 'file_detail.html', {'file': file, 'rules': rules})
@login_required
def create_rule(request, file_id):
file = get_object_or_404(File, id=file_id)
if request.method == "POST":
rule_name = request.POST.get('rule_name')
if rule_name:
rule = Rule.objects.create(name=rule_name, file=file)
url = reverse('abac:rule_detail', args=[file_id, rule.id])
return redirect(url)
# If the rule_name is not provided or if the method is GET, redirect to file_detail view.
return redirect('abac:file_detail', file_id=file_id)
@login_required
def rule_detail(request, file_id, rule_id=None):
file = get_object_or_404(File, id=file_id)
rule = get_object_or_404(Rule, id=rule_id) if rule_id else None
if request.method == "POST":
form = RuleAttributeForm(request.POST)
if form.is_valid():
rule_attribute = form.save(commit=False)
rule_attribute.rule = rule
rule_attribute.save()
return redirect('abac:rule_detail', file_id=file_id, rule_id=rule_id)
else:
form = RuleAttributeForm()
rule_attributes = RuleAttribute.objects.filter(rule=rule) if rule else []
return render(request, 'rule_detail.html', {
'file': file,
'rule': rule,
'form': form,
'rule_attributes': rule_attributes
})
@login_required
def delete_rule_attribute(request, file_id, rule_id, rule_attribute_id):
rule_attribute = get_object_or_404(RuleAttribute, id=rule_attribute_id)
rule_attribute.delete()
return redirect('abac:rule_detail', file_id=file_id, rule_id=rule_id)
@login_required
def user_detail_view(request, username):
user = get_object_or_404(User, username=username)
# Check if the requested user is the same as the logged-in user or the logged-in user has the required permission
if user != request.user and not request.user.has_perm('abac.can_create_users'):
return HttpResponseForbidden('You do not have permission to view this page.')
attributes = UserAttribute.objects.filter(user=user)
return render(request, 'user_detail.html', {'user': user, 'attributes': attributes})
def get_or_create_attribute_type(name, value, private=False):
# Determine the datatype from the value
if isinstance(value, int):
datatype = 'INTEGER'
elif isinstance(value, float):
datatype = 'FLOAT'
elif isinstance(value, bool):
datatype = 'BOOLEAN'
elif isinstance(value, str):
datatype = 'STRING'
else:
raise ValidationError('Invalid data type in certificate for attribute: {}'.format(name))
# Try to get the existing AttributeType object with matching name and datatype.
attribute_type, created = AttributeType.objects.get_or_create(
name=name,
datatype=datatype
)
if not created and attribute_type.datatype != datatype:
# If an AttributeType with the same name but different datatype exists, create a new one.
attribute_type = AttributeType.objects.create(name=name, datatype=datatype, is_private=private)
return attribute_type