|
|
|
@ -1,17 +1,23 @@
|
|
|
|
|
from django.shortcuts import render, redirect, get_object_or_404
|
|
|
|
|
from django.http.response import HttpResponseNotAllowed
|
|
|
|
|
from django.contrib.auth.decorators import permission_required, login_required, user_passes_test
|
|
|
|
|
from django.http import HttpResponse, FileResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotAllowed
|
|
|
|
|
from django.http import HttpResponse, FileResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotAllowed, JsonResponse
|
|
|
|
|
from django.contrib.auth import logout
|
|
|
|
|
from django.urls import reverse
|
|
|
|
|
from django.contrib import messages
|
|
|
|
|
from django.core.exceptions import ValidationError
|
|
|
|
|
from django.utils import timezone
|
|
|
|
|
|
|
|
|
|
import hashlib
|
|
|
|
|
import json
|
|
|
|
|
from phe import paillier
|
|
|
|
|
from cryptography.hazmat.primitives import serialization, hashes
|
|
|
|
|
from cryptography.hazmat.primitives.asymmetric import padding
|
|
|
|
|
from cryptography.hazmat.backends import default_backend
|
|
|
|
|
|
|
|
|
|
from .forms import FileUploadForm, UploadCertificateForm, RuleAttributeForm
|
|
|
|
|
from .models import File, Rule, UserAttribute, RuleAttribute, AttributeType, User
|
|
|
|
|
|
|
|
|
|
from .forms import FileUploadForm, UploadCertificateForm, RuleAttributeForm, TrustedAuthorityForm
|
|
|
|
|
from .models import File, Rule, UserAttribute, RuleAttribute, AttributeType, User, TrustedAuthority
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@ -42,26 +48,62 @@ def create_user_view(request):
|
|
|
|
|
@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')
|
|
|
|
|
attribute_type = get_or_create_attribute_type(name, value, private=True)
|
|
|
|
|
form = UploadCertificateForm(request.POST, request.FILES)
|
|
|
|
|
if form.is_valid():
|
|
|
|
|
certificate = form.cleaned_data['certificate']
|
|
|
|
|
signature = form.cleaned_data['signature'].read()
|
|
|
|
|
|
|
|
|
|
is_verified = False
|
|
|
|
|
for authority in TrustedAuthority.objects.all():
|
|
|
|
|
pub_key = serialization.load_pem_public_key(
|
|
|
|
|
authority.public_key.encode(),
|
|
|
|
|
backend=default_backend()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
pub_key.verify(
|
|
|
|
|
signature,
|
|
|
|
|
certificate.read(),
|
|
|
|
|
padding.PSS(
|
|
|
|
|
mgf=padding.MGF1(hashes.SHA256()),
|
|
|
|
|
salt_length=padding.PSS.MAX_LENGTH
|
|
|
|
|
),
|
|
|
|
|
hashes.SHA256()
|
|
|
|
|
)
|
|
|
|
|
is_verified = True
|
|
|
|
|
break
|
|
|
|
|
except:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if is_verified:
|
|
|
|
|
|
|
|
|
|
certificate_data = json.load(certificate)
|
|
|
|
|
|
|
|
|
|
if not request.user.public_key:
|
|
|
|
|
messages.warning(request, 'Please upload your public key first.')
|
|
|
|
|
return redirect(reverse('abac:upload_public_key', args=[request.user.username]))
|
|
|
|
|
|
|
|
|
|
public_key_native = paillier.PaillierPublicKey(n=int(request.user.public_key))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for attribute_data in certificate_data:
|
|
|
|
|
name = attribute_data.get('name')
|
|
|
|
|
value = attribute_data.get('value')
|
|
|
|
|
attribute_type = get_or_create_attribute_type(name, value, private=True)
|
|
|
|
|
encrypted_value = str(public_key_native.encrypt(value).ciphertext())
|
|
|
|
|
|
|
|
|
|
attribute, created = UserAttribute.objects.update_or_create(
|
|
|
|
|
user=request.user,
|
|
|
|
|
attribute_type=attribute_type,
|
|
|
|
|
defaults={'value': encrypted_value, 'last_modified': timezone.now()}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
messages.success(request, 'Certificate uploaded successfully.')
|
|
|
|
|
return redirect('abac:user_details', username=request.user.username)
|
|
|
|
|
else:
|
|
|
|
|
messages.error(request, 'Certificate verification failed.')
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
@ -69,9 +111,14 @@ def upload_certificate_view(request):
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
def file_detail(request, file_id):
|
|
|
|
|
user = request.user
|
|
|
|
|
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})
|
|
|
|
|
if check_permission(user, file):
|
|
|
|
|
rules = Rule.objects.filter(file=file)
|
|
|
|
|
return render(request, 'file_detail.html', {'file': file, 'rules': rules})
|
|
|
|
|
else:
|
|
|
|
|
return HttpResponseForbidden("You don't have the permission to access this file")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
def create_rule(request, file_id):
|
|
|
|
@ -123,7 +170,7 @@ 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'):
|
|
|
|
|
if user != request.user and not request.user.is_superuser:
|
|
|
|
|
return HttpResponseForbidden('You do not have permission to view this page.')
|
|
|
|
|
|
|
|
|
|
attributes = UserAttribute.objects.filter(user=user)
|
|
|
|
@ -165,30 +212,36 @@ def download_file(request, file_id):
|
|
|
|
|
|
|
|
|
|
user = request.user
|
|
|
|
|
|
|
|
|
|
# a) Check if the user is the owner of the file.
|
|
|
|
|
if user == file.owner:
|
|
|
|
|
print("User is Owner")
|
|
|
|
|
return serve_file(file)
|
|
|
|
|
|
|
|
|
|
# b) Check if the user is a superuser.
|
|
|
|
|
if user.is_superuser:
|
|
|
|
|
print("User is superuser")
|
|
|
|
|
return serve_file(file)
|
|
|
|
|
|
|
|
|
|
# c) Check the user's attributes against the file's rules.
|
|
|
|
|
for rule in file.rule_set.all():
|
|
|
|
|
if rule.is_satisfied_by(user):
|
|
|
|
|
print(f"user satisfies rule {rule.name}")
|
|
|
|
|
return serve_file(file)
|
|
|
|
|
|
|
|
|
|
return HttpResponseForbidden('You do not have permission to download this file.')
|
|
|
|
|
|
|
|
|
|
def check_permission(user, file, mode = None):
|
|
|
|
|
if mode:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
# a) Check if the user is the owner of the file.
|
|
|
|
|
if user == file.owner:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# b) Check if the user is a superuser.
|
|
|
|
|
if user.is_superuser:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# c) Check the user's attributes against the file's rules.
|
|
|
|
|
for rule in file.rule_set.all():
|
|
|
|
|
if rule.is_satisfied_by(user):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def serve_file(file):
|
|
|
|
|
# Serve the file using FileResponse.
|
|
|
|
|
response = FileResponse(file.file.open('rb'))
|
|
|
|
|
response['Content-Disposition'] = f'attachment; filename="{file.name}"'
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
@user_passes_test(lambda u: u.is_superuser)
|
|
|
|
|
def user_management(request):
|
|
|
|
@ -207,3 +260,97 @@ def user_management(request):
|
|
|
|
|
|
|
|
|
|
users = User.objects.all().order_by('-is_superuser', 'username')
|
|
|
|
|
return render(request, 'user_management.html', {'users': users})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
def upload_public_key(request, username):
|
|
|
|
|
if request.method == 'POST':
|
|
|
|
|
public_key = request.POST.get('public_key')
|
|
|
|
|
request.user.public_key = public_key
|
|
|
|
|
request.user.save()
|
|
|
|
|
messages.success(request, 'Public key uploaded successfully.')
|
|
|
|
|
return redirect(reverse('abac:user_details', args=[username]))
|
|
|
|
|
|
|
|
|
|
return render(request, 'upload_public_key.html')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_hierarchy_data():
|
|
|
|
|
users = User.objects.all()
|
|
|
|
|
data = {
|
|
|
|
|
"name": "Users",
|
|
|
|
|
"children": []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for user in users:
|
|
|
|
|
user_data = {
|
|
|
|
|
'name': user.username,
|
|
|
|
|
'children': []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for file in user.file_set.all():
|
|
|
|
|
file_data = {
|
|
|
|
|
'name': file.name,
|
|
|
|
|
'children': []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for rule in file.rule_set.all():
|
|
|
|
|
rule_data = {
|
|
|
|
|
'name': rule.name,
|
|
|
|
|
'children': []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for rule_attribute in rule.ruleattribute_set.all():
|
|
|
|
|
rule_data['children'].append({
|
|
|
|
|
'name': f"{rule_attribute.attribute_type.name}; {rule_attribute.operator}; {rule_attribute.value}",
|
|
|
|
|
'children': []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
file_data['children'].append(rule_data)
|
|
|
|
|
|
|
|
|
|
user_data['children'].append(file_data)
|
|
|
|
|
|
|
|
|
|
data['children'].append(user_data)
|
|
|
|
|
|
|
|
|
|
return json.dumps(data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
@user_passes_test(lambda u: u.is_superuser)
|
|
|
|
|
def hierarchy_view(request):
|
|
|
|
|
context = {'data': get_hierarchy_data()}
|
|
|
|
|
return render(request, 'vis_tree.html', context=context)
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
@user_passes_test(lambda u: u.is_superuser)
|
|
|
|
|
def trusted_authorities(request):
|
|
|
|
|
if request.method == "POST":
|
|
|
|
|
form = TrustedAuthorityForm(request.POST)
|
|
|
|
|
if form.is_valid():
|
|
|
|
|
form.save()
|
|
|
|
|
messages.success(request, 'Authority successfully added!')
|
|
|
|
|
return redirect(reverse('abac:trusted_authorities'))
|
|
|
|
|
else:
|
|
|
|
|
messages.warning(request, 'Invalid RSA Key')
|
|
|
|
|
return redirect(reverse('abac:trusted_authorities'))
|
|
|
|
|
|
|
|
|
|
authorities = TrustedAuthority.objects.all()
|
|
|
|
|
authorities_with_hashes = [(authority, hashlib.sha256(authority.public_key.encode()).hexdigest()) for authority in authorities]
|
|
|
|
|
|
|
|
|
|
form = TrustedAuthorityForm()
|
|
|
|
|
context = {
|
|
|
|
|
'authorities_with_hashes': authorities_with_hashes,
|
|
|
|
|
'form': form
|
|
|
|
|
}
|
|
|
|
|
return render(request, 'trusted_authorities.html', context)
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
@user_passes_test(lambda u: u.is_superuser)
|
|
|
|
|
def delete_authority(request, authority_id):
|
|
|
|
|
authority = get_object_or_404(TrustedAuthority, id=authority_id)
|
|
|
|
|
if request.method == 'POST':
|
|
|
|
|
authority.delete()
|
|
|
|
|
messages.success(request, 'Authority successfully deleted!')
|
|
|
|
|
return redirect(reverse('abac:trusted_authorities'))
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
return redirect(reverse('abac:trusted_authorities'))
|