e28babb0b8
* rename consent permission Signed-off-by: Jens Langhammer <jens@goauthentik.io> * the user version Signed-off-by: Jens Langhammer <jens@goauthentik.io> t Signed-off-by: Jens Langhammer <jens@goauthentik.io> * initial role Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * some minor table refactoring Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix user, add assign Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add roles ui Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix backend Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add assign API for roles Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start adding toggle buttons Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start view page Signed-off-by: Jens Langhammer <jens@goauthentik.io> * exclude add_ permission for per-object perms Signed-off-by: Jens Langhammer <jens@goauthentik.io> * small cleanup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add permission list for roles Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make sidebar update Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix page header not re-rendering? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fixup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add search Signed-off-by: Jens Langhammer <jens@goauthentik.io> * show first category in table groupBy except when its empty Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make model and object PK optional but required together Signed-off-by: Jens Langhammer <jens@goauthentik.io> * allow for setting global perms Signed-off-by: Jens Langhammer <jens@goauthentik.io> * exclude non-authentik permissions Signed-off-by: Jens Langhammer <jens@goauthentik.io> * exclude models which aren't allowed (base models etc) Signed-off-by: Jens Langhammer <jens@goauthentik.io> * ensure all models have verbose_name set, exclude some more internal objects Signed-off-by: Jens Langhammer <jens@goauthentik.io> * lint fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix role perm assign Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add unasign for global perms Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add meta changes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * clear modal state after submit Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add roles to our group Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix duplicate url names Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make recursive group query more usable Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add name field to role itself and move group creation to signal Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start sync Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move rbac stuff to separate django app Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint and such Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix go Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start API changes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add more API tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make admin interface not require superuser for now, improve error handling Signed-off-by: Jens Langhammer <jens@goauthentik.io> * replace some IsAdminUser where applicable Signed-off-by: Jens Langhammer <jens@goauthentik.io> * migrate flow inspector perms to actual permission Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix license not being a serializermodel Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add permission modal to models without view page Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add additional permissions to assign/unassign permissions Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add action to unassign user permissions Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add permissions tab to remaining view pages Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix flow inspector permission check Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix codecov config? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add more API tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * ensure viewsets have an order set Signed-off-by: Jens Langhammer <jens@goauthentik.io> * hopefully the last api name change Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make perm modal less confusing Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start user view permission page Signed-off-by: Jens Langhammer <jens@goauthentik.io> * only make delete bulk form expandable if usedBy is set Signed-off-by: Jens Langhammer <jens@goauthentik.io> * expand permission tables Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add more things Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add user global permission table Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests' url names Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add tests for assign perms Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add unassign tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rebuild permissions Signed-off-by: Jens Langhammer <jens@goauthentik.io> * prevent assigning/unassigning permissions to internal service accounts Signed-off-by: Jens Langhammer <jens@goauthentik.io> * only enable default api browser in debug Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix role object permissions showing duplicate Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix role link on role object permissions table Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix object permission modal having duplicate close buttons Signed-off-by: Jens Langhammer <jens@goauthentik.io> * return error if user has no global perm and no object perms also improve error display on table Signed-off-by: Jens Langhammer <jens@goauthentik.io> * small optimisation Signed-off-by: Jens Langhammer <jens@goauthentik.io> * optimise even more Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update locale Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add system permission for non-object permissions Signed-off-by: Jens Langhammer <jens@goauthentik.io> * allow access to admin interface based on perm Signed-off-by: Jens Langhammer <jens@goauthentik.io> * clean Signed-off-by: Jens Langhammer <jens@goauthentik.io> * don't exclude base models Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
155 lines
5.5 KiB
Python
155 lines
5.5 KiB
Python
"""Enterprise API Views"""
|
|
from datetime import datetime, timedelta
|
|
|
|
from django.utils.timezone import now
|
|
from drf_spectacular.types import OpenApiTypes
|
|
from drf_spectacular.utils import extend_schema, inline_serializer
|
|
from rest_framework.decorators import action
|
|
from rest_framework.fields import BooleanField, CharField, DateTimeField, IntegerField
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.request import Request
|
|
from rest_framework.response import Response
|
|
from rest_framework.serializers import ModelSerializer
|
|
from rest_framework.viewsets import ModelViewSet
|
|
|
|
from authentik.api.decorators import permission_required
|
|
from authentik.core.api.used_by import UsedByMixin
|
|
from authentik.core.api.utils import PassiveSerializer
|
|
from authentik.core.models import User, UserTypes
|
|
from authentik.enterprise.models import License, LicenseKey
|
|
from authentik.root.install_id import get_install_id
|
|
|
|
|
|
class LicenseSerializer(ModelSerializer):
|
|
"""License Serializer"""
|
|
|
|
def validate_key(self, key: str) -> str:
|
|
"""Validate the license key (install_id and signature)"""
|
|
LicenseKey.validate(key)
|
|
return key
|
|
|
|
class Meta:
|
|
model = License
|
|
fields = [
|
|
"license_uuid",
|
|
"name",
|
|
"key",
|
|
"expiry",
|
|
"internal_users",
|
|
"external_users",
|
|
]
|
|
extra_kwargs = {
|
|
"name": {"read_only": True},
|
|
"expiry": {"read_only": True},
|
|
"internal_users": {"read_only": True},
|
|
"external_users": {"read_only": True},
|
|
}
|
|
|
|
|
|
class LicenseSummary(PassiveSerializer):
|
|
"""Serializer for license status"""
|
|
|
|
internal_users = IntegerField(required=True)
|
|
external_users = IntegerField(required=True)
|
|
valid = BooleanField()
|
|
show_admin_warning = BooleanField()
|
|
show_user_warning = BooleanField()
|
|
read_only = BooleanField()
|
|
latest_valid = DateTimeField()
|
|
has_license = BooleanField()
|
|
|
|
|
|
class LicenseForecastSerializer(PassiveSerializer):
|
|
"""Serializer for license forecast"""
|
|
|
|
internal_users = IntegerField(required=True)
|
|
external_users = IntegerField(required=True)
|
|
forecasted_internal_users = IntegerField(required=True)
|
|
forecasted_external_users = IntegerField(required=True)
|
|
|
|
|
|
class LicenseViewSet(UsedByMixin, ModelViewSet):
|
|
"""License Viewset"""
|
|
|
|
queryset = License.objects.all()
|
|
serializer_class = LicenseSerializer
|
|
search_fields = ["name"]
|
|
ordering = ["name"]
|
|
filterset_fields = ["name"]
|
|
|
|
@permission_required(None, ["authentik_enterprise.view_license"])
|
|
@extend_schema(
|
|
request=OpenApiTypes.NONE,
|
|
responses={
|
|
200: inline_serializer("InstallIDSerializer", {"install_id": CharField(required=True)}),
|
|
},
|
|
)
|
|
@action(detail=False, methods=["GET"])
|
|
def get_install_id(self, request: Request) -> Response:
|
|
"""Get install_id"""
|
|
return Response(
|
|
data={
|
|
"install_id": get_install_id(),
|
|
}
|
|
)
|
|
|
|
@extend_schema(
|
|
request=OpenApiTypes.NONE,
|
|
responses={
|
|
200: LicenseSummary(),
|
|
},
|
|
)
|
|
@action(detail=False, methods=["GET"], permission_classes=[IsAuthenticated])
|
|
def summary(self, request: Request) -> Response:
|
|
"""Get the total license status"""
|
|
total = LicenseKey.get_total()
|
|
last_valid = LicenseKey.last_valid_date()
|
|
# TODO: move this to a different place?
|
|
show_admin_warning = last_valid < now() - timedelta(weeks=2)
|
|
show_user_warning = last_valid < now() - timedelta(weeks=4)
|
|
read_only = last_valid < now() - timedelta(weeks=6)
|
|
latest_valid = datetime.fromtimestamp(total.exp)
|
|
response = LicenseSummary(
|
|
data={
|
|
"internal_users": total.internal_users,
|
|
"external_users": total.external_users,
|
|
"valid": total.is_valid(),
|
|
"show_admin_warning": show_admin_warning,
|
|
"show_user_warning": show_user_warning,
|
|
"read_only": read_only,
|
|
"latest_valid": latest_valid,
|
|
"has_license": License.objects.all().count() > 0,
|
|
}
|
|
)
|
|
response.is_valid(raise_exception=True)
|
|
return Response(response.data)
|
|
|
|
@permission_required(None, ["authentik_enterprise.view_license"])
|
|
@extend_schema(
|
|
request=OpenApiTypes.NONE,
|
|
responses={
|
|
200: LicenseForecastSerializer(),
|
|
},
|
|
)
|
|
@action(detail=False, methods=["GET"])
|
|
def forecast(self, request: Request) -> Response:
|
|
"""Forecast how many users will be required in a year"""
|
|
last_month = now() - timedelta(days=30)
|
|
# Forecast for internal users
|
|
internal_in_last_month = User.objects.filter(
|
|
type=UserTypes.INTERNAL, date_joined__gte=last_month
|
|
).count()
|
|
# Forecast for external users
|
|
external_in_last_month = LicenseKey.get_external_user_count()
|
|
forecast_for_months = 12
|
|
response = LicenseForecastSerializer(
|
|
data={
|
|
"internal_users": LicenseKey.get_default_user_count(),
|
|
"external_users": LicenseKey.get_external_user_count(),
|
|
"forecasted_internal_users": (internal_in_last_month * forecast_for_months),
|
|
"forecasted_external_users": (external_in_last_month * forecast_for_months),
|
|
}
|
|
)
|
|
response.is_valid(raise_exception=True)
|
|
return Response(response.data)
|