Skip to content

Commit

Permalink
feat: adding capture for 2fa enforcements at org level (#26660)
Browse files Browse the repository at this point in the history
  • Loading branch information
surbhi-posthog authored Dec 5, 2024
1 parent dc3cdef commit 2919e27
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
25 changes: 24 additions & 1 deletion posthog/api/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
from django.shortcuts import get_object_or_404
from rest_framework import exceptions, permissions, serializers, viewsets
from rest_framework.request import Request
from rest_framework.response import Response
import posthoganalytics

from posthog import settings
from posthog.api.routing import TeamAndOrgViewSetMixin
from posthog.api.shared import ProjectBasicSerializer, TeamBasicSerializer
from posthog.auth import PersonalAPIKeyAuthentication
from posthog.cloud_utils import is_cloud
from posthog.constants import INTERNAL_BOT_EMAIL_SUFFIX, AvailableFeature
from posthog.event_usage import report_organization_deleted
from posthog.event_usage import report_organization_deleted, groups
from posthog.models import Organization, User
from posthog.models.async_deletion import AsyncDeletion, DeletionType
from posthog.rbac.user_access_control import UserAccessControlSerializerMixin
Expand Down Expand Up @@ -240,3 +242,24 @@ def get_serializer_context(self) -> dict[str, Any]:
**super().get_serializer_context(),
"user_permissions": UserPermissions(cast(User, self.request.user)),
}

def update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
if "enforce_2fa" in request.data:
enforce_2fa_value = request.data["enforce_2fa"]
organization = self.get_object()
user = cast(User, request.user)

# Add capture event for 2FA enforcement change
posthoganalytics.capture(
str(user.distinct_id),
"organization 2fa enforcement toggled",
properties={
"enabled": enforce_2fa_value,
"organization_id": str(organization.id),
"organization_name": organization.name,
"user_role": user.organization_memberships.get(organization=organization).level,
},
groups=groups(organization),
)

return super().update(request, *args, **kwargs)
17 changes: 16 additions & 1 deletion posthog/api/test/test_organization.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from rest_framework import status
from unittest.mock import patch, ANY

from posthog.models import Organization, OrganizationMembership, Team
from posthog.models.personal_api_key import PersonalAPIKey, hash_key_value
Expand Down Expand Up @@ -128,7 +129,8 @@ def test_cant_update_plugins_access_level(self):
self.organization.refresh_from_db()
self.assertEqual(self.organization.plugins_access_level, 3)

def test_enforce_2fa_for_everyone(self):
@patch("posthoganalytics.capture")
def test_enforce_2fa_for_everyone(self, mock_capture):
# Only admins should be able to enforce 2fa
response = self.client.patch(f"/api/organizations/{self.organization.id}/", {"enforce_2fa": True})
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
Expand All @@ -142,6 +144,19 @@ def test_enforce_2fa_for_everyone(self):
self.organization.refresh_from_db()
self.assertEqual(self.organization.enforce_2fa, True)

# Verify the capture event was called correctly
mock_capture.assert_any_call(
self.user.distinct_id,
"organization 2fa enforcement toggled",
properties={
"enabled": True,
"organization_id": str(self.organization.id),
"organization_name": self.organization.name,
"user_role": OrganizationMembership.Level.ADMIN,
},
groups={"instance": ANY, "organization": str(self.organization.id)},
)

def test_projects_outside_personal_api_key_scoped_organizations_not_listed(self):
other_org, _, _ = Organization.objects.bootstrap(self.user)
personal_api_key = generate_random_token_personal()
Expand Down

0 comments on commit 2919e27

Please sign in to comment.