Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions authentik/enterprise/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.urls import resolve
from structlog.stdlib import BoundLogger, get_logger

from authentik.core.api.users import UserViewSet
from authentik.enterprise.api import LicenseViewSet
from authentik.enterprise.license import LicenseKey
from authentik.enterprise.models import LicenseUsageStatus
Expand Down Expand Up @@ -59,6 +60,9 @@ def is_request_always_allowed(self, request: HttpRequest):
# Flow executor is mounted as an API path but explicitly allowed
if request.resolver_match._func_path == class_to_path(FlowExecutorView):
return True
# Always allow making changes to users, even in case the license has ben exceeded
if request.resolver_match._func_path == class_to_path(UserViewSet):
return True
# Only apply these restrictions to the API
if "authentik_api" not in request.resolver_match.app_names:
return True
Expand Down
46 changes: 46 additions & 0 deletions authentik/enterprise/tests/test_read_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,49 @@ def test_manage_flows(self):
{"detail": "Request denied due to expired/invalid license.", "code": "denied_license"},
)
self.assertEqual(response.status_code, 400)

@patch(
"authentik.enterprise.license.LicenseKey.validate",
MagicMock(
return_value=LicenseKey(
aud="",
exp=expiry_valid,
name=generate_id(),
internal_users=100,
external_users=100,
)
),
)
@patch(
"authentik.enterprise.license.LicenseKey.get_internal_user_count",
MagicMock(return_value=1000),
)
@patch(
"authentik.enterprise.license.LicenseKey.get_external_user_count",
MagicMock(return_value=1000),
)
@patch(
"authentik.enterprise.license.LicenseKey.record_usage",
MagicMock(),
)
def test_manage_users(self):
"""Test that managing users is still possible"""
License.objects.create(key=generate_id())
usage = LicenseUsage.objects.create(
internal_user_count=100,
external_user_count=100,
status=LicenseUsageStatus.VALID,
)
usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
usage.save(update_fields=["record_date"])

admin = create_test_admin_user()
self.client.force_login(admin)

# Reading is always allowed
response = self.client.get(reverse("authentik_api:user-list"))
self.assertEqual(response.status_code, 200)

# Writing should also be allowed
response = self.client.patch(reverse("authentik_api:user-detail", kwargs={"pk": admin.pk}))
self.assertEqual(response.status_code, 200)
10 changes: 9 additions & 1 deletion website/docs/enterprise/manage-enterprise.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,15 @@ The following events occur when a license expires or the internal/external user

- After another 2 weeks, users get a warning banner

- After another 2 weeks, the authentik Enterprise instance becomes “read-only”
- After another 2 weeks, the authentik Enterprise instance becomes "read-only"

@tanberry tanberry Dec 9, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- After another 2 weeks, the authentik Enterprise instance becomes "read-only"
- After another 2 weeks (six weeks after the initial violation), the authentik Enterprise instance becomes "read-only".


When an authentik instance has gone into read-only mode, the following actions can still be done:
Comment thread
BeryJu marked this conversation as resolved.
Outdated

- Users can authenticate and authorize applications
- Licenses can be modified
- Users can be modified/deleted <span class="badge badge--version">authentik 2024.10.5+</span>

Once the user count returns to be within the limits of the license, authentik will return to the standard read-write mode and the notification will disappear.

@tanberry tanberry Dec 9, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I thought the problem was that the license had expired, not the number of users...? This is a bit confusing... Do we mean both, that either the license has expired AND/OR the number of users has exceeded the licensed amount?

Comment thread
BeryJu marked this conversation as resolved.
Outdated

### About users and licenses

Expand Down