2021-03-09 13:30:30 -06:00
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Views for organization api key management.
|
2021-03-09 13:30:30 -06:00
|
|
|
"""
|
|
|
|
from django.contrib.auth.decorators import login_required
|
2021-11-12 11:16:25 -06:00
|
|
|
from django.db import transaction
|
2021-03-09 13:30:30 -06:00
|
|
|
from django.http import JsonResponse
|
2021-07-10 10:12:35 -05:00
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from django.views.decorators.csrf import csrf_protect
|
|
|
|
from grainy.const import PERM_READ
|
2021-03-09 13:30:30 -06:00
|
|
|
|
2021-07-10 10:12:35 -05:00
|
|
|
from peeringdb_server.forms import OrgAdminUserPermissionForm, OrganizationAPIKeyForm
|
2021-03-09 13:30:30 -06:00
|
|
|
from peeringdb_server.models import (
|
|
|
|
OrganizationAPIKey,
|
|
|
|
OrganizationAPIPermission,
|
2021-07-10 10:12:35 -05:00
|
|
|
UserAPIKey,
|
2021-03-09 13:30:30 -06:00
|
|
|
)
|
2021-07-10 10:12:35 -05:00
|
|
|
from peeringdb_server.org_admin_views import load_entity_permissions, org_admin_required
|
2021-03-09 13:30:30 -06:00
|
|
|
|
|
|
|
|
|
|
|
def save_key_permissions(org, key, perms):
|
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Save key permissions for the specified org and key.
|
2021-03-09 13:30:30 -06:00
|
|
|
|
2021-10-15 03:25:38 -05:00
|
|
|
Perms should be a dict of permissioning ids and permission levels.
|
2021-03-09 13:30:30 -06:00
|
|
|
"""
|
|
|
|
|
|
|
|
# wipe all the key's perms for the targeted org
|
|
|
|
|
|
|
|
key.grainy_permissions.filter(namespace__startswith=org.grainy_namespace).delete()
|
|
|
|
|
|
|
|
# collect permissioning namespaces from the provided permissioning ids
|
|
|
|
|
|
|
|
grainy_perms = {}
|
|
|
|
|
|
|
|
for id, permissions in list(perms.items()):
|
|
|
|
|
|
|
|
if not permissions & PERM_READ:
|
|
|
|
permissions = permissions | PERM_READ
|
|
|
|
|
|
|
|
if id == "org.%d" % org.id:
|
|
|
|
grainy_perms[org.grainy_namespace] = permissions
|
|
|
|
grainy_perms[
|
|
|
|
f"{org.grainy_namespace}.network.*.poc_set.private"
|
|
|
|
] = permissions
|
|
|
|
elif id == "net":
|
|
|
|
grainy_perms[f"{org.grainy_namespace}.network"] = permissions
|
|
|
|
grainy_perms[
|
|
|
|
f"{org.grainy_namespace}.network.*.poc_set.private"
|
|
|
|
] = permissions
|
|
|
|
elif id == "ix":
|
|
|
|
grainy_perms[f"{org.grainy_namespace}.internetexchange"] = permissions
|
|
|
|
elif id == "fac":
|
|
|
|
grainy_perms[f"{org.grainy_namespace}.facility"] = permissions
|
|
|
|
elif id.find(".") > -1:
|
|
|
|
id = id.split(".")
|
|
|
|
if id[0] == "net":
|
|
|
|
grainy_perms[f"{org.grainy_namespace}.network.{id[1]}"] = permissions
|
|
|
|
grainy_perms[
|
|
|
|
f"{org.grainy_namespace}.network.{id[1]}.poc_set.private"
|
|
|
|
] = permissions
|
|
|
|
elif id[0] == "ix":
|
|
|
|
grainy_perms[
|
|
|
|
f"{org.grainy_namespace}.internetexchange.{id[1]}"
|
|
|
|
] = permissions
|
|
|
|
elif id[0] == "fac":
|
|
|
|
grainy_perms[f"{org.grainy_namespace}.facility.{id[1]}"] = permissions
|
|
|
|
|
|
|
|
# save
|
|
|
|
for ns, p in list(grainy_perms.items()):
|
|
|
|
OrganizationAPIPermission.objects.create(
|
|
|
|
namespace=ns, permission=p, org_api_key=key
|
|
|
|
)
|
|
|
|
|
|
|
|
return grainy_perms
|
|
|
|
|
|
|
|
|
|
|
|
def load_all_key_permissions(org):
|
|
|
|
"""
|
|
|
|
Returns dict of all users with all their permissions for
|
2021-10-15 03:25:38 -05:00
|
|
|
the given org.
|
2021-03-09 13:30:30 -06:00
|
|
|
"""
|
|
|
|
|
|
|
|
rv = {}
|
|
|
|
for key in org.api_keys.filter(revoked=False):
|
|
|
|
kperms, perms = load_entity_permissions(org, key)
|
|
|
|
rv[key.prefix] = {
|
|
|
|
"prefix": key.prefix,
|
|
|
|
"perms": perms,
|
|
|
|
"name": key.name,
|
|
|
|
}
|
|
|
|
return rv
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
2021-11-12 11:16:25 -06:00
|
|
|
@transaction.atomic
|
2021-03-09 13:30:30 -06:00
|
|
|
@org_admin_required
|
|
|
|
def manage_key_add(request, **kwargs):
|
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Create a new Organization API key.
|
2021-03-09 13:30:30 -06:00
|
|
|
|
|
|
|
Requires a name for the key.
|
|
|
|
"""
|
|
|
|
|
|
|
|
api_key_form = OrganizationAPIKeyForm(request.POST)
|
|
|
|
|
|
|
|
if api_key_form.is_valid():
|
|
|
|
name = api_key_form.cleaned_data.get("name")
|
|
|
|
org_id = api_key_form.cleaned_data.get("org_id")
|
|
|
|
email = api_key_form.cleaned_data.get("email")
|
|
|
|
|
|
|
|
api_key, key = OrganizationAPIKey.objects.create_key(
|
|
|
|
org_id=org_id, name=name, email=email
|
|
|
|
)
|
|
|
|
|
|
|
|
return JsonResponse(
|
|
|
|
{
|
|
|
|
"status": "ok",
|
|
|
|
"name": api_key.name,
|
|
|
|
"email": api_key.email,
|
|
|
|
"prefix": api_key.prefix,
|
|
|
|
"org_id": api_key.org_id,
|
|
|
|
"key": key,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
else:
|
|
|
|
return JsonResponse(api_key_form.errors, status=400)
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
2021-11-12 11:16:25 -06:00
|
|
|
@transaction.atomic
|
2021-03-09 13:30:30 -06:00
|
|
|
@org_admin_required
|
|
|
|
def manage_key_update(request, **kwargs):
|
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Updated existing Organization API key.
|
2021-03-09 13:30:30 -06:00
|
|
|
"""
|
|
|
|
|
|
|
|
prefix = request.POST.get("prefix")
|
|
|
|
org = kwargs.get("org")
|
|
|
|
|
|
|
|
api_key_form = OrganizationAPIKeyForm(request.POST)
|
|
|
|
|
|
|
|
if api_key_form.is_valid():
|
|
|
|
name = api_key_form.cleaned_data.get("name")
|
|
|
|
email = api_key_form.cleaned_data.get("email")
|
|
|
|
|
|
|
|
# attempt to retrieve api for key prefix + org combination
|
|
|
|
|
|
|
|
try:
|
|
|
|
api_key = OrganizationAPIKey.objects.get(prefix=prefix, org=org)
|
|
|
|
except OrganizationAPIKey.DoesNotExist:
|
|
|
|
return JsonResponse({"non_field_errors": [_("Key not found")]}, status=404)
|
|
|
|
|
|
|
|
# update name and email fields of key
|
|
|
|
|
|
|
|
api_key.name = name
|
|
|
|
api_key.email = email
|
|
|
|
api_key.save()
|
|
|
|
|
|
|
|
return JsonResponse(
|
|
|
|
{
|
|
|
|
"status": "ok",
|
|
|
|
"name": api_key.name,
|
|
|
|
"email": api_key.email,
|
|
|
|
"prefix": api_key.prefix,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
else:
|
|
|
|
return JsonResponse(api_key_form.errors, status=400)
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
2021-11-12 11:16:25 -06:00
|
|
|
@transaction.atomic
|
2021-03-09 13:30:30 -06:00
|
|
|
@org_admin_required
|
|
|
|
def manage_key_revoke(request, **kwargs):
|
|
|
|
"""
|
|
|
|
Revoke an existing API key.
|
|
|
|
"""
|
|
|
|
|
|
|
|
org = kwargs.get("org")
|
|
|
|
prefix = request.POST.get("prefix")
|
|
|
|
|
|
|
|
try:
|
|
|
|
api_key = OrganizationAPIKey.objects.get(org=org, prefix=prefix)
|
|
|
|
except OrganizationAPIKey.DoesNotExist:
|
|
|
|
return JsonResponse({"non_field_errors": [_("Key not found")]}, status=404)
|
|
|
|
|
|
|
|
api_key.revoked = True
|
|
|
|
api_key.save()
|
|
|
|
|
|
|
|
return JsonResponse(
|
|
|
|
{
|
|
|
|
"status": "ok",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@org_admin_required
|
|
|
|
def key_permissions(request, **kwargs):
|
|
|
|
"""
|
|
|
|
Returns JsonResponse with list of key permissions for the targeted
|
2021-10-15 03:25:38 -05:00
|
|
|
org an entities under it.
|
2021-03-09 13:30:30 -06:00
|
|
|
|
|
|
|
Permisions are returned as a dict of permissioning ids and permission
|
|
|
|
levels.
|
|
|
|
|
|
|
|
Permissioning ids serve as a wrapper for actual permissioning namespaces
|
2021-10-15 03:25:38 -05:00
|
|
|
so they can be exposed to the organization admins for changes without allowing
|
2021-03-09 13:30:30 -06:00
|
|
|
them to set permissioning namespaces directly.
|
|
|
|
"""
|
|
|
|
|
|
|
|
org = kwargs.get("org")
|
|
|
|
perms_rv = {}
|
|
|
|
for key in org.api_keys.filter(revoked=False).all():
|
|
|
|
kperms, perms = load_entity_permissions(org, key)
|
|
|
|
perms_rv[key.prefix] = perms
|
|
|
|
|
|
|
|
return JsonResponse({"status": "ok", "key_permissions": perms_rv})
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@csrf_protect
|
2021-11-12 11:16:25 -06:00
|
|
|
@transaction.atomic
|
2021-03-09 13:30:30 -06:00
|
|
|
@org_admin_required
|
|
|
|
def key_permission_update(request, **kwargs):
|
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Update/Add a user's permission.
|
2021-03-09 13:30:30 -06:00
|
|
|
|
|
|
|
perms = permission level
|
|
|
|
entity = permission id
|
|
|
|
"""
|
|
|
|
|
|
|
|
org = kwargs.get("org")
|
|
|
|
prefix = request.POST.get("key_prefix")
|
|
|
|
key = OrganizationAPIKey.objects.get(prefix=prefix)
|
|
|
|
kperms, perms = load_entity_permissions(org, key)
|
|
|
|
form = OrgAdminUserPermissionForm(request.POST)
|
|
|
|
if not form.is_valid():
|
|
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
|
|
|
|
level = form.cleaned_data.get("perms")
|
|
|
|
entity = form.cleaned_data.get("entity")
|
|
|
|
perms[entity] = level
|
|
|
|
save_key_permissions(org, key, perms)
|
|
|
|
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@csrf_protect
|
2021-11-12 11:16:25 -06:00
|
|
|
@transaction.atomic
|
2021-03-09 13:30:30 -06:00
|
|
|
@org_admin_required
|
|
|
|
def key_permission_remove(request, **kwargs):
|
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Remove a keys permission.
|
2021-03-09 13:30:30 -06:00
|
|
|
|
|
|
|
entity = permission id
|
|
|
|
"""
|
|
|
|
|
|
|
|
org = kwargs.get("org")
|
|
|
|
prefix = request.POST.get("key_prefix")
|
|
|
|
key = OrganizationAPIKey.objects.get(prefix=prefix)
|
|
|
|
|
|
|
|
entity = request.POST.get("entity")
|
|
|
|
kperms, perms = load_entity_permissions(org, key)
|
|
|
|
if entity in perms:
|
|
|
|
del perms[entity]
|
|
|
|
save_key_permissions(org, key, perms)
|
|
|
|
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
USER API KEY MANAGEMENT
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def convert_to_bool(data):
|
|
|
|
if data is None:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return data.lower() == "true"
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
2021-11-12 11:16:25 -06:00
|
|
|
@transaction.atomic
|
2021-03-09 13:30:30 -06:00
|
|
|
def add_user_key(request, **kwargs):
|
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Create a new User API key.
|
2021-03-09 13:30:30 -06:00
|
|
|
|
|
|
|
Requires a name and a readonly boolean.
|
|
|
|
"""
|
|
|
|
|
|
|
|
user = request.user
|
|
|
|
name = request.POST.get("name")
|
|
|
|
readonly = convert_to_bool(request.POST.get("readonly"))
|
|
|
|
|
2022-01-11 08:56:47 -06:00
|
|
|
if not name:
|
|
|
|
return JsonResponse({"name": [_("This field is required.")]}, status=400)
|
|
|
|
|
2021-03-09 13:30:30 -06:00
|
|
|
api_key, key = UserAPIKey.objects.create_key(
|
|
|
|
name=name,
|
|
|
|
user=user,
|
|
|
|
readonly=readonly,
|
|
|
|
)
|
|
|
|
|
|
|
|
return JsonResponse(
|
|
|
|
{
|
|
|
|
"status": "ok",
|
|
|
|
"name": api_key.name,
|
|
|
|
"prefix": api_key.prefix,
|
|
|
|
"readonly": api_key.readonly,
|
|
|
|
"key": key,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
2021-11-12 11:16:25 -06:00
|
|
|
@transaction.atomic
|
2021-03-09 13:30:30 -06:00
|
|
|
def remove_user_key(request, **kwargs):
|
|
|
|
"""
|
2021-10-15 03:25:38 -05:00
|
|
|
Revoke user api key.
|
2021-03-09 13:30:30 -06:00
|
|
|
"""
|
|
|
|
|
|
|
|
user = request.user
|
|
|
|
prefix = request.POST.get("prefix")
|
|
|
|
|
|
|
|
try:
|
|
|
|
api_key = UserAPIKey.objects.get(user=user, prefix=prefix)
|
|
|
|
except UserAPIKey.DoesNotExist:
|
|
|
|
return JsonResponse({"non_field_errors": [_("Key not found")]}, status=404)
|
|
|
|
api_key.revoked = True
|
|
|
|
api_key.save()
|
|
|
|
|
|
|
|
return JsonResponse(
|
|
|
|
{
|
|
|
|
"status": "ok",
|
|
|
|
}
|
|
|
|
)
|