mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-21 13:39:22 +01:00
feat: rbac initial set up (#25745)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
447a18930f
commit
8d01d5ef54
@ -1,10 +1,10 @@
|
||||
from rest_framework import exceptions, mixins, serializers, viewsets
|
||||
from rest_framework.permissions import SAFE_METHODS, BasePermission
|
||||
|
||||
from ee.api.role import RoleSerializer
|
||||
from ee.api.rbac.role import RoleSerializer
|
||||
from ee.models.feature_flag_role_access import FeatureFlagRoleAccess
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.role import Role
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.role import Role
|
||||
from posthog.api.feature_flag import FeatureFlagSerializer
|
||||
from posthog.api.routing import TeamAndOrgViewSetMixin
|
||||
from posthog.models import FeatureFlag
|
||||
|
@ -1,7 +1,7 @@
|
||||
from rest_framework import mixins, serializers, viewsets
|
||||
|
||||
from ee.api.role import RolePermissions
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.api.rbac.role import RolePermissions
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from posthog.api.routing import TeamAndOrgViewSetMixin
|
||||
|
||||
|
@ -5,8 +5,8 @@ from rest_framework import mixins, serializers, viewsets
|
||||
from rest_framework.permissions import SAFE_METHODS, BasePermission
|
||||
|
||||
from ee.models.feature_flag_role_access import FeatureFlagRoleAccess
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.role import Role, RoleMembership
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.role import Role, RoleMembership
|
||||
from posthog.api.organization_member import OrganizationMemberSerializer
|
||||
from posthog.api.routing import TeamAndOrgViewSetMixin
|
||||
from posthog.api.shared import UserBasicSerializer
|
@ -1,6 +1,6 @@
|
||||
from ee.api.test.base import APILicensedTest
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.role import Role, RoleMembership
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.role import Role, RoleMembership
|
||||
from posthog.models.feature_flag import FeatureFlag
|
||||
from posthog.models.organization import OrganizationMembership
|
||||
|
||||
|
@ -2,8 +2,8 @@ from rest_framework import status
|
||||
|
||||
from ee.api.test.base import APILicensedTest
|
||||
from ee.models.feature_flag_role_access import FeatureFlagRoleAccess
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.role import Role
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.role import Role
|
||||
from posthog.models.feature_flag import FeatureFlag
|
||||
from posthog.models.organization import OrganizationMembership
|
||||
from posthog.models.user import User
|
||||
|
@ -2,7 +2,7 @@ from django.db import IntegrityError
|
||||
from rest_framework import status
|
||||
|
||||
from ee.api.test.base import APILicensedTest
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from posthog.models.organization import Organization, OrganizationMembership
|
||||
from posthog.test.base import QueryMatchingTest, snapshot_postgres_queries, FuzzyInt
|
||||
|
||||
|
@ -2,8 +2,8 @@ from django.db import IntegrityError
|
||||
from rest_framework import status
|
||||
|
||||
from ee.api.test.base import APILicensedTest
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.role import Role
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.role import Role
|
||||
from posthog.models.organization import Organization, OrganizationMembership
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
from rest_framework import status
|
||||
|
||||
from ee.api.test.base import APILicensedTest
|
||||
from ee.models.role import Role, RoleMembership
|
||||
from ee.models.rbac.role import Role, RoleMembership
|
||||
from posthog.models.organization import Organization, OrganizationMembership
|
||||
from posthog.models.user import User
|
||||
|
||||
|
@ -5,7 +5,7 @@ from .feature_flag_role_access import FeatureFlagRoleAccess
|
||||
from .hook import Hook
|
||||
from .license import License
|
||||
from .property_definition import EnterprisePropertyDefinition
|
||||
from .role import Role, RoleMembership
|
||||
from .rbac.role import Role, RoleMembership
|
||||
|
||||
__all__ = [
|
||||
"EnterpriseEventDefinition",
|
||||
|
@ -2,6 +2,8 @@ from django.db import models
|
||||
|
||||
from posthog.models.organization import Organization
|
||||
|
||||
# NOTE: This will be deprecated in favour of the AccessControl model
|
||||
|
||||
|
||||
class OrganizationResourceAccess(models.Model):
|
||||
class AccessLevel(models.IntegerChoices):
|
@ -1,6 +1,6 @@
|
||||
from django.db import models
|
||||
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from posthog.models.utils import UUIDModel
|
||||
|
||||
|
@ -6,6 +6,7 @@ from django.urls import include
|
||||
from django.urls.conf import path
|
||||
|
||||
from ee.api import integration
|
||||
from .api.rbac import organization_resource_access, role
|
||||
|
||||
from .api import (
|
||||
authentication,
|
||||
@ -15,8 +16,6 @@ from .api import (
|
||||
feature_flag_role_access,
|
||||
hooks,
|
||||
license,
|
||||
organization_resource_access,
|
||||
role,
|
||||
sentry_stats,
|
||||
subscription,
|
||||
)
|
||||
@ -49,6 +48,7 @@ def extend_api_router() -> None:
|
||||
"organization_role_memberships",
|
||||
["organization_id", "role_id"],
|
||||
)
|
||||
# Start: routes to be deprecated
|
||||
project_feature_flags_router.register(
|
||||
r"role_access",
|
||||
feature_flag_role_access.FeatureFlagRoleAccessViewSet,
|
||||
@ -61,6 +61,7 @@ def extend_api_router() -> None:
|
||||
"organization_resource_access",
|
||||
["organization_id"],
|
||||
)
|
||||
# End: routes to be deprecated
|
||||
register_grandfathered_environment_nested_viewset(r"hooks", hooks.HookViewSet, "environment_hooks", ["team_id"])
|
||||
register_grandfathered_environment_nested_viewset(
|
||||
r"explicit_members",
|
||||
|
@ -220,6 +220,7 @@ export const FEATURE_FLAGS = {
|
||||
LEGACY_ACTION_WEBHOOKS: 'legacy-action-webhooks', // owner: @mariusandra #team-cdp
|
||||
SESSION_REPLAY_URL_TRIGGER: 'session-replay-url-trigger', // owner: @richard-better #team-replay
|
||||
REPLAY_TEMPLATES: 'replay-templates', // owner: @raquelmsmith #team-replay
|
||||
ROLE_BASED_ACCESS_CONTROL: 'role-based-access-control', // owner: @zach
|
||||
EXPERIMENTS_HOLDOUTS: 'experiments-holdouts', // owner: @jurajmajerik #team-experiments
|
||||
MESSAGING: 'messaging', // owner @mariusandra #team-cdp
|
||||
SESSION_REPLAY_URL_BLOCKLIST: 'session-replay-url-blocklist', // owner: @richard-better #team-replay
|
||||
|
@ -9,7 +9,7 @@ import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast'
|
||||
import { urls } from 'scenes/urls'
|
||||
import { userLogic } from 'scenes/userLogic'
|
||||
|
||||
import { OrganizationBasicType, PersonalAPIKeyType, TeamBasicType } from '~/types'
|
||||
import { APIScopeObject, OrganizationBasicType, PersonalAPIKeyType, TeamBasicType } from '~/types'
|
||||
|
||||
import type { personalAPIKeysLogicType } from './personalAPIKeysLogicType'
|
||||
|
||||
@ -32,7 +32,7 @@ export const API_KEY_SCOPE_PRESETS = [
|
||||
]
|
||||
|
||||
export type APIScope = {
|
||||
key: string
|
||||
key: APIScopeObject
|
||||
info?: string | JSX.Element
|
||||
disabledActions?: ('read' | 'write')[]
|
||||
disabledWhenProjectScoped?: boolean
|
||||
|
@ -3821,6 +3821,37 @@ export interface RoleMemberType {
|
||||
user_uuid: string
|
||||
}
|
||||
|
||||
export type APIScopeObject =
|
||||
| 'action'
|
||||
| 'activity_log'
|
||||
| 'annotation'
|
||||
| 'batch_export'
|
||||
| 'cohort'
|
||||
| 'dashboard'
|
||||
| 'dashboard_template'
|
||||
| 'early_access_feature'
|
||||
| 'event_definition'
|
||||
| 'experiment'
|
||||
| 'export'
|
||||
| 'feature_flag'
|
||||
| 'group'
|
||||
| 'insight'
|
||||
| 'query'
|
||||
| 'notebook'
|
||||
| 'organization'
|
||||
| 'organization_member'
|
||||
| 'person'
|
||||
| 'plugin'
|
||||
| 'project'
|
||||
| 'property_definition'
|
||||
| 'session_recording'
|
||||
| 'session_recording_playlist'
|
||||
| 'sharing_configuration'
|
||||
| 'subscription'
|
||||
| 'survey'
|
||||
| 'user'
|
||||
| 'webhook'
|
||||
|
||||
export interface OrganizationResourcePermissionType {
|
||||
id: string
|
||||
resource: Resource
|
||||
|
@ -5,7 +5,8 @@ from rest_framework import response, serializers, viewsets
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from posthog.models import PersonalAPIKey, User
|
||||
from posthog.models.personal_api_key import API_SCOPE_ACTIONS, API_SCOPE_OBJECTS, hash_key_value, mask_key_value
|
||||
from posthog.models.personal_api_key import hash_key_value, mask_key_value
|
||||
from posthog.models.scopes import API_SCOPE_ACTIONS, API_SCOPE_OBJECTS
|
||||
from posthog.models.team.team import Team
|
||||
from posthog.models.utils import generate_random_token_personal
|
||||
from posthog.permissions import TimeSensitiveActionPermission
|
||||
|
@ -30,7 +30,7 @@ from posthog.models.activity_logging.activity_page import activity_page_response
|
||||
from posthog.models.async_deletion import AsyncDeletion, DeletionType
|
||||
from posthog.models.group_type_mapping import GroupTypeMapping
|
||||
from posthog.models.organization import OrganizationMembership
|
||||
from posthog.models.personal_api_key import APIScopeObjectOrNotSupported
|
||||
from posthog.models.scopes import APIScopeObjectOrNotSupported
|
||||
from posthog.models.product_intent.product_intent import ProductIntent
|
||||
from posthog.models.project import Project
|
||||
from posthog.models.signals import mute_selected_signals
|
||||
|
@ -18,7 +18,7 @@ from posthog.auth import (
|
||||
SharingAccessTokenAuthentication,
|
||||
)
|
||||
from posthog.models.organization import Organization
|
||||
from posthog.models.personal_api_key import APIScopeObjectOrNotSupported
|
||||
from posthog.models.scopes import APIScopeObjectOrNotSupported
|
||||
from posthog.models.project import Project
|
||||
from posthog.models.team import Team
|
||||
from posthog.models.user import User
|
||||
|
@ -28,7 +28,7 @@ from posthog.models.activity_logging.activity_page import activity_page_response
|
||||
from posthog.models.async_deletion import AsyncDeletion, DeletionType
|
||||
from posthog.models.group_type_mapping import GroupTypeMapping
|
||||
from posthog.models.organization import OrganizationMembership
|
||||
from posthog.models.personal_api_key import APIScopeObjectOrNotSupported
|
||||
from posthog.models.scopes import APIScopeObjectOrNotSupported
|
||||
from posthog.models.project import Project
|
||||
from posthog.models.signals import mute_selected_signals
|
||||
from posthog.models.team.util import delete_batch_exports, delete_bulky_postgres_data
|
||||
|
@ -70,9 +70,9 @@
|
||||
'/home/runner/work/posthog/posthog/posthog/api/project.py: Warning [ProjectViewSet > ProjectBackwardCompatSerializer]: unable to resolve type hint for function "get_product_intents". Consider using a type hint or @extend_schema_field. Defaulting to string.',
|
||||
'/home/runner/work/posthog/posthog/posthog/api/proxy_record.py: Warning [ProxyRecordViewset]: could not derive type of path parameter "organization_id" because it is untyped and obtaining queryset from the viewset failed. Consider adding a type to the path (e.g. <int:organization_id>) or annotating the parameter type with @extend_schema. Defaulting to "string".',
|
||||
'/home/runner/work/posthog/posthog/posthog/api/proxy_record.py: Warning [ProxyRecordViewset]: could not derive type of path parameter "id" because it is untyped and obtaining queryset from the viewset failed. Consider adding a type to the path (e.g. <int:id>) or annotating the parameter type with @extend_schema. Defaulting to "string".',
|
||||
'/home/runner/work/posthog/posthog/ee/api/role.py: Warning [RoleViewSet > RoleSerializer]: unable to resolve type hint for function "get_members". Consider using a type hint or @extend_schema_field. Defaulting to string.',
|
||||
'/home/runner/work/posthog/posthog/ee/api/role.py: Warning [RoleViewSet > RoleSerializer]: unable to resolve type hint for function "get_associated_flags". Consider using a type hint or @extend_schema_field. Defaulting to string.',
|
||||
'/home/runner/work/posthog/posthog/ee/api/role.py: Warning [RoleMembershipViewSet]: could not derive type of path parameter "organization_id" because model "ee.models.role.RoleMembership" contained no such field. Consider annotating parameter with @extend_schema. Defaulting to "string".',
|
||||
'/home/runner/work/posthog/posthog/ee/api/rbac/role.py: Warning [RoleViewSet > RoleSerializer]: unable to resolve type hint for function "get_members". Consider using a type hint or @extend_schema_field. Defaulting to string.',
|
||||
'/home/runner/work/posthog/posthog/ee/api/rbac/role.py: Warning [RoleViewSet > RoleSerializer]: unable to resolve type hint for function "get_associated_flags". Consider using a type hint or @extend_schema_field. Defaulting to string.',
|
||||
'/home/runner/work/posthog/posthog/ee/api/rbac/role.py: Warning [RoleMembershipViewSet]: could not derive type of path parameter "organization_id" because model "ee.models.rbac.role.RoleMembership" contained no such field. Consider annotating parameter with @extend_schema. Defaulting to "string".',
|
||||
'/home/runner/work/posthog/posthog/posthog/api/action.py: Warning [ActionViewSet]: could not derive type of path parameter "project_id" because model "posthog.models.action.action.Action" contained no such field. Consider annotating parameter with @extend_schema. Defaulting to "string".',
|
||||
'/home/runner/work/posthog/posthog/posthog/api/action.py: Warning [ActionViewSet > ActionSerializer]: unable to resolve type hint for function "get_creation_context". Consider using a type hint or @extend_schema_field. Defaulting to string.',
|
||||
'/home/runner/work/posthog/posthog/posthog/api/activity_log.py: Warning [ActivityLogViewSet]: could not derive type of path parameter "project_id" because model "posthog.models.activity_logging.activity_log.ActivityLog" contained no such field. Consider annotating parameter with @extend_schema. Defaulting to "string".',
|
||||
|
@ -3,7 +3,7 @@ from unittest.mock import ANY
|
||||
|
||||
from rest_framework import status
|
||||
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
from posthog.api.dashboards.dashboard import Dashboard
|
||||
from posthog.constants import AvailableFeature
|
||||
from posthog.models import FeatureFlag
|
||||
|
@ -6,7 +6,7 @@ def can_user_edit_feature_flag(request, feature_flag):
|
||||
# self hosted check for enterprise models that may not exist
|
||||
try:
|
||||
from ee.models.feature_flag_role_access import FeatureFlagRoleAccess
|
||||
from ee.models.organization_resource_access import OrganizationResourceAccess
|
||||
from ee.models.rbac.organization_resource_access import OrganizationResourceAccess
|
||||
except:
|
||||
return True
|
||||
else:
|
||||
|
@ -1,4 +1,4 @@
|
||||
from typing import Optional, Literal, get_args
|
||||
from typing import Optional, Literal
|
||||
import hashlib
|
||||
|
||||
from django.contrib.auth.hashers import PBKDF2PasswordHasher
|
||||
@ -66,56 +66,3 @@ class PersonalAPIKey(models.Model):
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
|
||||
## API Scopes
|
||||
# These are the scopes that are used to define the permissions of the API tokens.
|
||||
# Not every model needs a scope - it should more be for top-level things
|
||||
# Typically each object should have `read` and `write` scopes, but some objects may have more specific scopes
|
||||
|
||||
# WARNING: Make sure to keep in sync with the frontend!
|
||||
APIScopeObject = Literal[
|
||||
"action",
|
||||
"activity_log",
|
||||
"annotation",
|
||||
"batch_export",
|
||||
"cohort",
|
||||
"dashboard",
|
||||
"dashboard_template",
|
||||
"early_access_feature",
|
||||
"event_definition",
|
||||
"experiment",
|
||||
"export",
|
||||
"feature_flag",
|
||||
"group",
|
||||
"insight",
|
||||
"query", # Covers query and events endpoints
|
||||
"notebook",
|
||||
"organization",
|
||||
"organization_member",
|
||||
"person",
|
||||
"plugin",
|
||||
"project",
|
||||
"property_definition",
|
||||
"session_recording",
|
||||
"session_recording_playlist",
|
||||
"sharing_configuration",
|
||||
"subscription",
|
||||
"survey",
|
||||
"user",
|
||||
"webhook",
|
||||
]
|
||||
|
||||
APIScopeActions = Literal[
|
||||
"read",
|
||||
"write",
|
||||
]
|
||||
|
||||
APIScopeObjectOrNotSupported = Literal[
|
||||
APIScopeObject,
|
||||
"INTERNAL",
|
||||
]
|
||||
|
||||
|
||||
API_SCOPE_OBJECTS: tuple[APIScopeObject, ...] = get_args(APIScopeObject)
|
||||
API_SCOPE_ACTIONS: tuple[APIScopeActions, ...] = get_args(APIScopeActions)
|
||||
|
60
posthog/models/scopes.py
Normal file
60
posthog/models/scopes.py
Normal file
@ -0,0 +1,60 @@
|
||||
## API Scopes
|
||||
# These are the scopes that are used to define the permissions of the API tokens.
|
||||
# Not every model needs a scope - it should more be for top-level things
|
||||
# Typically each object should have `read` and `write` scopes, but some objects may have more specific scopes
|
||||
|
||||
# WARNING: Make sure to keep in sync with the frontend!
|
||||
from typing import Literal, get_args
|
||||
|
||||
|
||||
## API Scopes
|
||||
# These are the scopes that are used to define the permissions of the API tokens.
|
||||
# Not every model needs a scope - it should more be for top-level things
|
||||
# Typically each object should have `read` and `write` scopes, but some objects may have more specific scopes
|
||||
|
||||
# WARNING: Make sure to keep in sync with the frontend!
|
||||
APIScopeObject = Literal[
|
||||
"action",
|
||||
"activity_log",
|
||||
"annotation",
|
||||
"batch_export",
|
||||
"cohort",
|
||||
"dashboard",
|
||||
"dashboard_template",
|
||||
"early_access_feature",
|
||||
"event_definition",
|
||||
"experiment",
|
||||
"export",
|
||||
"feature_flag",
|
||||
"group",
|
||||
"insight",
|
||||
"query", # Covers query and events endpoints
|
||||
"notebook",
|
||||
"organization",
|
||||
"organization_member",
|
||||
"person",
|
||||
"plugin",
|
||||
"project",
|
||||
"property_definition",
|
||||
"session_recording",
|
||||
"session_recording_playlist",
|
||||
"sharing_configuration",
|
||||
"subscription",
|
||||
"survey",
|
||||
"user",
|
||||
"webhook",
|
||||
]
|
||||
|
||||
APIScopeActions = Literal[
|
||||
"read",
|
||||
"write",
|
||||
]
|
||||
|
||||
APIScopeObjectOrNotSupported = Literal[
|
||||
APIScopeObject,
|
||||
"INTERNAL",
|
||||
]
|
||||
|
||||
|
||||
API_SCOPE_OBJECTS: tuple[APIScopeObject, ...] = get_args(APIScopeObject)
|
||||
API_SCOPE_ACTIONS: tuple[APIScopeActions, ...] = get_args(APIScopeActions)
|
@ -19,7 +19,7 @@ from posthog.auth import (
|
||||
from posthog.cloud_utils import is_cloud
|
||||
from posthog.exceptions import EnterpriseFeatureException
|
||||
from posthog.models import Organization, OrganizationMembership, Team, User
|
||||
from posthog.models.personal_api_key import APIScopeObjectOrNotSupported
|
||||
from posthog.models.scopes import APIScopeObjectOrNotSupported
|
||||
from posthog.utils import get_can_create_org
|
||||
|
||||
CREATE_METHODS = ["POST", "PUT"]
|
||||
|
Loading…
Reference in New Issue
Block a user