diff --git a/README.md b/README.md
index fc712e63..6417bf7a 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,10 @@ CyberArk's Official SDK and CLI for different services operations
- [x] DPA K8S Service
- [x] DPA DB Service
- [x] Session Monitoring Service
+ - [x] Identity Users Service
+ - [x] Identity Roles Service
+ - [x] Identity Policies Service
+ - [x] Identity Directories Service
- [x] All services contains CRUD and Statistics per respective service
- [x] Ready to use SDK in Python
- [x] CLI and SDK Examples
@@ -211,6 +215,12 @@ The following services and commands are supported:
- db - DPA DB Enduser Operations
- sso - DPA SSO Enduser Operations
- k8s - DPA kubernetes service
+- sm - Session Monitoring Service
+- identity - Identity Service
+ - users - Identity Users Management
+ - roles - Identity Roles Management
+ - policies - Identity Policies Management
+ - directories - Identity Directories Reading
Any command has its own subcommands, with respective arguments
diff --git a/ark_sdk_python/ark_api.py b/ark_sdk_python/ark_api.py
index de64e579..37fed323 100644
--- a/ark_sdk_python/ark_api.py
+++ b/ark_sdk_python/ark_api.py
@@ -80,6 +80,54 @@ def profile(self) -> ArkProfile:
"""
return self.__profile
+ @property
+ def identity_directories(self) -> "ArkIdentityDirectoriesService":
+ """
+ Returns the Identity Directories Service if the appropriate authenticators were given
+
+ Returns:
+ ArkIdentityDirectoriesService: _description_
+ """
+ from ark_sdk_python.services.identity.directories import ArkIdentityDirectoriesService
+
+ return cast(ArkIdentityDirectoriesService, self.service(ArkIdentityDirectoriesService))
+
+ @property
+ def identity_policies(self) -> "ArkIdentityPoliciesService":
+ """
+ Returns the Identity Policies Service if the appropriate authenticators were given
+
+ Returns:
+ ArkIdentityPoliciesService: _description_
+ """
+ from ark_sdk_python.services.identity.policies import ArkIdentityPoliciesService
+
+ return cast(ArkIdentityPoliciesService, self.service(ArkIdentityPoliciesService))
+
+ @property
+ def identity_roles(self) -> "ArkIdentityRolesService":
+ """
+ Returns the Identity Roles Service if the appropriate authenticators were given
+
+ Returns:
+ ArkIdentityRolesService: _description_
+ """
+ from ark_sdk_python.services.identity.roles import ArkIdentityRolesService
+
+ return cast(ArkIdentityRolesService, self.service(ArkIdentityRolesService))
+
+ @property
+ def identity_users(self) -> "ArkIdentityUsersService":
+ """
+ Returns the Identity Users Service if the appropriate authenticators were given
+
+ Returns:
+ ArkIdentityUsersService: _description_
+ """
+ from ark_sdk_python.services.identity.users import ArkIdentityUsersService
+
+ return cast(ArkIdentityUsersService, self.service(ArkIdentityUsersService))
+
@property
def dpa_workspaces_db(self) -> "ArkDPADBWorkspaceService":
"""
diff --git a/ark_sdk_python/examples/create_identity_resources.py b/ark_sdk_python/examples/create_identity_resources.py
new file mode 100644
index 00000000..8635b8f5
--- /dev/null
+++ b/ark_sdk_python/examples/create_identity_resources.py
@@ -0,0 +1,20 @@
+from ark_sdk_python.auth import ArkISPAuth
+from ark_sdk_python.models.auth import ArkAuthMethod, ArkAuthProfile, ArkSecret, IdentityArkAuthMethodSettings
+from ark_sdk_python.models.services.identity.roles import ArkIdentityCreateRole
+from ark_sdk_python.models.services.identity.users import ArkIdentityCreateUser
+from ark_sdk_python.services.identity import ArkIdentityAPI
+
+if __name__ == "__main__":
+ isp_auth = ArkISPAuth()
+ isp_auth.authenticate(
+ auth_profile=ArkAuthProfile(
+ username='CoolUser', auth_method=ArkAuthMethod.Identity, auth_method_settings=IdentityArkAuthMethodSettings()
+ ),
+ secret=ArkSecret(secret='CoolPassword'),
+ )
+
+ # Create an identity service to create some users and roles
+ print('Creating identity roles and users')
+ identity_api = ArkIdentityAPI(isp_auth)
+ identity_api.identity_roles.create_role(ArkIdentityCreateRole(role_name='IT'))
+ identity_api.identity_users.create_user(ArkIdentityCreateUser(username='it_user', password='CoolPassword', roles=['IT']))
diff --git a/ark_sdk_python/examples/default_suffix.py b/ark_sdk_python/examples/default_suffix.py
new file mode 100644
index 00000000..91920863
--- /dev/null
+++ b/ark_sdk_python/examples/default_suffix.py
@@ -0,0 +1,12 @@
+from ark_sdk_python.auth import ArkISPAuth
+from ark_sdk_python.models.ark_profile import ArkProfileLoader
+from ark_sdk_python.models.services.identity.directories import ArkIdentityListDirectoriesEntities
+from ark_sdk_python.services.identity import ArkIdentityAPI
+
+if __name__ == "__main__":
+ isp_auth = ArkISPAuth()
+ isp_auth.authenticate(ArkProfileLoader().load_default_profile())
+ identity_api = ArkIdentityAPI(isp_auth)
+ print(identity_api.identity_directories.tenant_default_suffix())
+ for page in identity_api.identity_directories.list_directories_entities(ArkIdentityListDirectoriesEntities()):
+ print([i.name for i in page.items])
diff --git a/ark_sdk_python/models/actions/services/__init__.py b/ark_sdk_python/models/actions/services/__init__.py
index 11f77a61..c7779252 100644
--- a/ark_sdk_python/models/actions/services/__init__.py
+++ b/ark_sdk_python/models/actions/services/__init__.py
@@ -1,14 +1,17 @@
from typing import Any, List
from ark_sdk_python.models.actions.services.ark_dpa_exec_action_consts import DPA_ACTIONS
+from ark_sdk_python.models.actions.services.ark_identity_exec_action_consts import IDENTITY_ACTIONS
from ark_sdk_python.models.actions.services.ark_sm_exec_action_consts import SM_ACTIONS
SUPPORTED_SERVICE_ACTIONS: List[Any] = [
+ IDENTITY_ACTIONS,
DPA_ACTIONS,
SM_ACTIONS,
]
__all__ = [
+ 'IDENTITY_ACTIONS',
'DPA_ACTIONS',
'SM_ACTIONS',
'SUPPORTED_SERVICE_ACTIONS',
diff --git a/ark_sdk_python/models/actions/services/ark_identity_exec_action_consts.py b/ark_sdk_python/models/actions/services/ark_identity_exec_action_consts.py
new file mode 100644
index 00000000..3c1ccf8b
--- /dev/null
+++ b/ark_sdk_python/models/actions/services/ark_identity_exec_action_consts.py
@@ -0,0 +1,114 @@
+from typing import Dict, Final, Optional, Type
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.actions.ark_service_action_definition import ArkServiceActionDefinition
+from ark_sdk_python.models.services.identity.directories import ArkIdentityListDirectories, ArkIdentityListDirectoriesEntities
+from ark_sdk_python.models.services.identity.policies import (
+ ArkIdentityAddAuthenticationProfile,
+ ArkIdentityAddPolicy,
+ ArkIdentityDisablePolicy,
+ ArkIdentityEnablePolicy,
+ ArkIdentityGetAuthenticationProfile,
+ ArkIdentityGetPolicy,
+ ArkIdentityRemoveAuthenticationProfile,
+ ArkIdentityRemovePolicy,
+)
+from ark_sdk_python.models.services.identity.roles import (
+ ArkIdentityAddAdminRightsToRole,
+ ArkIdentityAddGroupToRole,
+ ArkIdentityAddRoleToRole,
+ ArkIdentityAddUserToRole,
+ ArkIdentityCreateRole,
+ ArkIdentityDeleteRole,
+ ArkIdentityListRoleMembers,
+ ArkIdentityRemoveGroupFromRole,
+ ArkIdentityRemoveRoleFromRole,
+ ArkIdentityRemoveUserFromRole,
+ ArkIdentityRoleIdByName,
+ ArkIdentityUpdateRole,
+)
+from ark_sdk_python.models.services.identity.users import (
+ ArkIdentityCreateUser,
+ ArkIdentityDeleteUser,
+ ArkIdentityResetUserPassword,
+ ArkIdentityUpdateUser,
+ ArkIdentityUserByName,
+ ArkIdentityUserIdByName,
+)
+
+# Identity Definitions
+# Directories
+IDENTITY_DIRECTORIES_ACTION_TO_SCHEMA_MAP: Final[Dict[str, Optional[Type[ArkModel]]]] = {
+ 'list-directories': ArkIdentityListDirectories,
+ 'list-directories-entities': ArkIdentityListDirectoriesEntities,
+ 'tenant-default-suffix': None,
+}
+IDENTITY_DIRECTORIES_ACTIONS: Final[ArkServiceActionDefinition] = ArkServiceActionDefinition(
+ action_name='directories',
+ schemas=IDENTITY_DIRECTORIES_ACTION_TO_SCHEMA_MAP,
+)
+
+# Policies
+IDENTITY_POLICIES_ACTION_TO_SCHEMA_MAP: Final[Dict[str, Optional[Type[ArkModel]]]] = {
+ 'add-authentication-profile': ArkIdentityAddAuthenticationProfile,
+ 'remove-authentication-profile': ArkIdentityRemoveAuthenticationProfile,
+ 'list-authentication-profiles': None,
+ 'authentication-profile': ArkIdentityGetAuthenticationProfile,
+ 'add-policy': ArkIdentityAddPolicy,
+ 'remove-policy': ArkIdentityRemovePolicy,
+ 'list-policies': None,
+ 'policy': ArkIdentityGetPolicy,
+ 'enable-policy': ArkIdentityEnablePolicy,
+ 'disable-policy': ArkIdentityDisablePolicy,
+ 'enable-default-policy': None,
+ 'disable-default-policy': None,
+}
+IDENTITY_POLICIES_ACTIONS: Final[ArkServiceActionDefinition] = ArkServiceActionDefinition(
+ action_name='policies',
+ schemas=IDENTITY_POLICIES_ACTION_TO_SCHEMA_MAP,
+)
+
+# Roles
+IDENTITY_ROLES_ACTION_TO_SCHEMA_MAP: Final[Dict[str, Optional[Type[ArkModel]]]] = {
+ 'add-user-to-role': ArkIdentityAddUserToRole,
+ 'add-group-to-role': ArkIdentityAddGroupToRole,
+ 'add-role-to-role': ArkIdentityAddRoleToRole,
+ 'remove-user-from-role': ArkIdentityRemoveUserFromRole,
+ 'remove-group-from-role': ArkIdentityRemoveGroupFromRole,
+ 'remove-role-from-role': ArkIdentityRemoveRoleFromRole,
+ 'create-role': ArkIdentityCreateRole,
+ 'update-role': ArkIdentityUpdateRole,
+ 'delete-role': ArkIdentityDeleteRole,
+ 'list-role-members': ArkIdentityListRoleMembers,
+ 'add-admin-rights-to-role': ArkIdentityAddAdminRightsToRole,
+ 'role-id-by-name': ArkIdentityRoleIdByName,
+}
+IDENTITY_ROLES_ACTIONS: Final[ArkServiceActionDefinition] = ArkServiceActionDefinition(
+ action_name='roles',
+ schemas=IDENTITY_ROLES_ACTION_TO_SCHEMA_MAP,
+)
+
+# Users
+IDENTITY_USERS_ACTION_TO_SCHEMA_MAP: Final[Dict[str, Optional[Type[ArkModel]]]] = {
+ 'create-user': ArkIdentityCreateUser,
+ 'update-user': ArkIdentityUpdateUser,
+ 'delete-user': ArkIdentityDeleteUser,
+ 'user-by-name': ArkIdentityUserByName,
+ 'user-id-by-name': ArkIdentityUserIdByName,
+ 'reset-user-password': ArkIdentityResetUserPassword,
+}
+IDENTITY_USERS_ACTIONS: Final[ArkServiceActionDefinition] = ArkServiceActionDefinition(
+ action_name='users',
+ schemas=IDENTITY_USERS_ACTION_TO_SCHEMA_MAP,
+)
+
+# Service Actions Definition
+IDENTITY_ACTIONS: Final[ArkServiceActionDefinition] = ArkServiceActionDefinition(
+ action_name='identity',
+ subactions=[
+ IDENTITY_DIRECTORIES_ACTIONS,
+ IDENTITY_POLICIES_ACTIONS,
+ IDENTITY_ROLES_ACTIONS,
+ IDENTITY_USERS_ACTIONS,
+ ],
+)
diff --git a/ark_sdk_python/models/common/identity/ark_identity_directory_schemas.py b/ark_sdk_python/models/common/identity/ark_identity_directory_schemas.py
index 87420b91..65820f7b 100644
--- a/ark_sdk_python/models/common/identity/ark_identity_directory_schemas.py
+++ b/ark_sdk_python/models/common/identity/ark_identity_directory_schemas.py
@@ -94,6 +94,7 @@ class RoleRow(ArkModel):
id: str = Field(alias='_ID')
admin_rights: Optional[List[RoleAdminRight]] = Field(alias='AdministrativeRights')
is_hidden: Optional[bool] = Field(alias='IsHidden')
+ description: Optional[str] = Field(alias='Description')
class RoleResult(ArkModel):
@@ -113,6 +114,7 @@ class UserRow(ArkModel):
directory_service_type: DirectoryService = Field(alias='ServiceType')
email: Optional[str] = Field(alias='EMail')
internal_id: Optional[str] = Field(alias='InternalName')
+ description: Optional[str] = Field(alias='Description')
class UserResult(ArkModel):
diff --git a/ark_sdk_python/models/services/dpa/policies/db/ark_dpa_db_connection_data.py b/ark_sdk_python/models/services/dpa/policies/db/ark_dpa_db_connection_data.py
index 8ea5b760..8ad49847 100644
--- a/ark_sdk_python/models/services/dpa/policies/db/ark_dpa_db_connection_data.py
+++ b/ark_sdk_python/models/services/dpa/policies/db/ark_dpa_db_connection_data.py
@@ -40,9 +40,13 @@ class ArkDPADBOracleDBAuth(ArkDPADBBaseAuth):
class ArkDPADBMongoDBAuth(ArkDPADBBaseAuth):
- global_builtin_roles: List[ArkDPADBMongoGlobalBuiltinRole] = Field(description='Global builtin roles across all databases')
- database_builtin_roles: Dict[str, List[ArkDPADBMongoDatabaseBuiltinRole]] = Field(description='Per database builtin roles')
- database_custom_roles: Dict[str, List[str]] = Field(description='Custom per database roles')
+ global_builtin_roles: List[ArkDPADBMongoGlobalBuiltinRole] = Field(
+ description='Global builtin roles across all databases', default_factory=list
+ )
+ database_builtin_roles: Dict[str, List[ArkDPADBMongoDatabaseBuiltinRole]] = Field(
+ description='Per database builtin roles', default_factory=dict
+ )
+ database_custom_roles: Dict[str, List[str]] = Field(description='Custom per database roles', default_factory=dict)
applied_to: Optional[List[ArkDPADBAppliedTo]] = Field(description='Which resources to apply to')
diff --git a/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_add_database.py b/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_add_database.py
index bd1589c1..743a265f 100644
--- a/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_add_database.py
+++ b/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_add_database.py
@@ -14,6 +14,7 @@ class ArkDPADBAddDatabase(ArkCamelizedModel):
platform: ArkWorkspaceType = Field(
description='Platform of the database, as in, where it resides, defaulted to on premises', default=ArkWorkspaceType.ONPREM
)
+ auth_database: str = Field(description='Authentication database used, most commonly used with mongodb', default='admin')
services: Optional[List[str]] = Field(description='Services related to the database, most commonly used with oracle')
domain: Optional[str] = Field(description='The domain the DB resides in')
domain_controller_name: Optional[str] = Field(description='Domain controller name associated to this database')
diff --git a/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_database.py b/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_database.py
index dbf14fe4..eed450d5 100644
--- a/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_database.py
+++ b/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_database.py
@@ -13,6 +13,7 @@ class ArkDPADBDatabase(ArkCamelizedModel):
name: str = Field(description='Name of the database, often referenced in policies and other APIs')
network_name: str = Field(description='Name of the network the database resides in', default='OnPrem')
platform: Optional[ArkWorkspaceType] = Field(description='Platform of the database, as in, where it resides')
+ auth_database: str = Field(description='Authentication database used, most commonly used with mongodb', default='admin')
services: List[str] = Field(description='Services related to the database, most commonly used with oracle', default_factory=list)
domain: Optional[str] = Field(description='The domain the DB resides in')
domain_controller_name: Optional[str] = Field(description='Domain controller name associated to this database')
diff --git a/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_update_database.py b/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_update_database.py
index 6a1b878a..4ed19ea9 100644
--- a/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_update_database.py
+++ b/ark_sdk_python/models/services/dpa/workspaces/db/ark_dpa_db_update_database.py
@@ -14,6 +14,7 @@ class ArkDPADBUpdateDatabase(ArkCamelizedModel):
new_name: Optional[str] = Field(description='New name for the database')
network_name: Optional[str] = Field(description='Name of the network the database resides in', default='ON-PREMISE')
platform: Optional[ArkWorkspaceType] = Field(description='Platform of the database, as in, where it resides')
+ auth_database: str = Field(description='Authentication database used, most commonly used with mongodb', default='admin')
services: Optional[List[str]] = Field(description='Services related to the database, most commonly used with oracle')
domain: Optional[str] = Field(description='The domain the DB resides in')
domain_controller_name: Optional[str] = Field(description='Domain controller name associated to this database')
diff --git a/ark_sdk_python/models/services/identity/__init__.py b/ark_sdk_python/models/services/identity/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/ark_sdk_python/models/services/identity/directories/__init__.py b/ark_sdk_python/models/services/identity/directories/__init__.py
new file mode 100644
index 00000000..34c2f5da
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/directories/__init__.py
@@ -0,0 +1,21 @@
+from ark_sdk_python.models.services.identity.directories.ark_identity_directory import ArkIdentityDirectory
+from ark_sdk_python.models.services.identity.directories.ark_identity_entity import (
+ ArkIdentityEntity,
+ ArkIdentityEntityType,
+ ArkIdentityGroupEntity,
+ ArkIdentityRoleEntity,
+ ArkIdentityUserEntity,
+)
+from ark_sdk_python.models.services.identity.directories.ark_identity_list_directories import ArkIdentityListDirectories
+from ark_sdk_python.models.services.identity.directories.ark_identity_list_directories_entities import ArkIdentityListDirectoriesEntities
+
+__all__ = [
+ 'ArkIdentityListDirectoriesEntities',
+ 'ArkIdentityEntity',
+ 'ArkIdentityEntityType',
+ 'ArkIdentityGroupEntity',
+ 'ArkIdentityRoleEntity',
+ 'ArkIdentityUserEntity',
+ 'ArkIdentityListDirectories',
+ 'ArkIdentityDirectory',
+]
diff --git a/ark_sdk_python/models/services/identity/directories/ark_identity_directory.py b/ark_sdk_python/models/services/identity/directories/ark_identity_directory.py
new file mode 100644
index 00000000..75422a2f
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/directories/ark_identity_directory.py
@@ -0,0 +1,9 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.common.identity import DirectoryService
+
+
+class ArkIdentityDirectory(ArkModel):
+ directory: DirectoryService = Field(description='Name of the directory')
+ directory_service_uuid: str = Field(description='ID of the directory')
diff --git a/ark_sdk_python/models/services/identity/directories/ark_identity_entity.py b/ark_sdk_python/models/services/identity/directories/ark_identity_entity.py
new file mode 100644
index 00000000..97211865
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/directories/ark_identity_entity.py
@@ -0,0 +1,37 @@
+from enum import Enum
+from typing import List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.common.identity import DirectoryService, RoleAdminRight
+
+
+class ArkIdentityEntityType(str, Enum):
+ Role = 'ROLE'
+ User = 'USER'
+ Group = 'GROUP'
+
+
+class ArkIdentityEntity(ArkModel):
+ id: str = Field(description='ID of the entity')
+ name: str = Field(description='Name of the entity')
+ entity_type: ArkIdentityEntityType = Field(description='Type of the entity')
+ directory_service_type: DirectoryService = Field(description='Directory type of the entity')
+ display_name: Optional[str] = Field(description='Display name of the entity')
+ service_instance_localized: str = Field(description='Display directory service name')
+
+
+class ArkIdentityUserEntity(ArkIdentityEntity):
+ email: Optional[str] = Field(description='Email of the user')
+ description: Optional[str] = Field(description='Description of the user')
+
+
+class ArkIdentityGroupEntity(ArkIdentityEntity):
+ pass
+
+
+class ArkIdentityRoleEntity(ArkIdentityEntity):
+ admin_rights: Optional[List[RoleAdminRight]] = Field(description='Admin rights of the role')
+ is_hidden: bool = Field(description='Whwether this role is hidden or not')
+ description: Optional[str] = Field(description='Description of the role')
diff --git a/ark_sdk_python/models/services/identity/directories/ark_identity_list_directories.py b/ark_sdk_python/models/services/identity/directories/ark_identity_list_directories.py
new file mode 100644
index 00000000..01b59f71
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/directories/ark_identity_list_directories.py
@@ -0,0 +1,10 @@
+from typing import List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.common.identity import DirectoryService
+
+
+class ArkIdentityListDirectories(ArkModel):
+ directories: Optional[List[DirectoryService]] = Field(description='Directories types to list')
diff --git a/ark_sdk_python/models/services/identity/directories/ark_identity_list_directories_entities.py b/ark_sdk_python/models/services/identity/directories/ark_identity_list_directories_entities.py
new file mode 100644
index 00000000..9311e7b4
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/directories/ark_identity_list_directories_entities.py
@@ -0,0 +1,22 @@
+from typing import Final, List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.common.identity import DirectoryService
+from ark_sdk_python.models.services.identity.directories.ark_identity_entity import ArkIdentityEntityType
+
+DEFAULT_ENTITIES_PAGE_SIZE: Final[int] = 10000
+DEFAULT_ENTITIES_LIMIT: Final[int] = 10000
+DEFAULT_MAX_PAGE_SIZE: Final[int] = -1
+
+
+class ArkIdentityListDirectoriesEntities(ArkModel):
+ directories: Optional[List[DirectoryService]] = Field(description='Directories to search on')
+ entity_types: Optional[List[ArkIdentityEntityType]] = Field(
+ description='Member types to search in the format of X,Y,Z, possible values are ROLE,USER,GROUP'
+ )
+ search: Optional[str] = Field(description='Search string to use')
+ page_size: int = Field(description='Page size to emit', default=DEFAULT_ENTITIES_PAGE_SIZE)
+ limit: int = Field(description='Limit amount to list', default=DEFAULT_ENTITIES_LIMIT)
+ max_page_count: int = Field(description='Max page count to reach to', default=DEFAULT_MAX_PAGE_SIZE)
diff --git a/ark_sdk_python/models/services/identity/policies/__init__.py b/ark_sdk_python/models/services/identity/policies/__init__.py
new file mode 100644
index 00000000..88c02fc9
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/__init__.py
@@ -0,0 +1,31 @@
+from ark_sdk_python.models.services.identity.policies.ark_identity_add_authentication_profile import ArkIdentityAddAuthenticationProfile
+from ark_sdk_python.models.services.identity.policies.ark_identity_add_policy import ArkIdentityAddPolicy
+from ark_sdk_python.models.services.identity.policies.ark_identity_authentication_profile import ArkIdentityAuthenticationProfile
+from ark_sdk_python.models.services.identity.policies.ark_identity_disable_policy import ArkIdentityDisablePolicy
+from ark_sdk_python.models.services.identity.policies.ark_identity_enable_policy import ArkIdentityEnablePolicy
+from ark_sdk_python.models.services.identity.policies.ark_identity_get_authentication_profile import ArkIdentityGetAuthenticationProfile
+from ark_sdk_python.models.services.identity.policies.ark_identity_get_policy import ArkIdentityGetPolicy
+from ark_sdk_python.models.services.identity.policies.ark_identity_policy import ArkIdentityPolicy
+from ark_sdk_python.models.services.identity.policies.ark_identity_policy_info import ArkIdentityPolicyInfo
+from ark_sdk_python.models.services.identity.policies.ark_identity_policy_operation import ArkIdentityPolicyOperation
+from ark_sdk_python.models.services.identity.policies.ark_identity_policy_operation_type import ArkIdentityPolicyOperationType
+from ark_sdk_python.models.services.identity.policies.ark_identity_remove_authentication_profile import (
+ ArkIdentityRemoveAuthenticationProfile,
+)
+from ark_sdk_python.models.services.identity.policies.ark_identity_remove_policy import ArkIdentityRemovePolicy
+
+__all__ = [
+ 'ArkIdentityPolicy',
+ 'ArkIdentityPolicyInfo',
+ 'ArkIdentityDisablePolicy',
+ 'ArkIdentityEnablePolicy',
+ 'ArkIdentityPolicyOperationType',
+ 'ArkIdentityPolicyOperation',
+ 'ArkIdentityAddPolicy',
+ 'ArkIdentityGetPolicy',
+ 'ArkIdentityRemovePolicy',
+ 'ArkIdentityAddAuthenticationProfile',
+ 'ArkIdentityAuthenticationProfile',
+ 'ArkIdentityGetAuthenticationProfile',
+ 'ArkIdentityRemoveAuthenticationProfile',
+]
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_add_authentication_profile.py b/ark_sdk_python/models/services/identity/policies/ark_identity_add_authentication_profile.py
new file mode 100644
index 00000000..d0b3ded9
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_add_authentication_profile.py
@@ -0,0 +1,13 @@
+from typing import Any, Dict, List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityAddAuthenticationProfile(ArkModel):
+ auth_profile_name: str = Field(description='Name of the profile')
+ first_challenges: List[str] = Field(description='List of first challenges for the profile, i,e "UP,SMS"')
+ second_challenges: Optional[List[str]] = Field(description='List of second challenges for the profile, i,e "UP,SMS"')
+ additional_data: Optional[Dict[str, Any]] = Field(description='Additional auth profile data')
+ duration_in_minutes: int = Field(description='Duration of auth profile', default=30)
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_add_policy.py b/ark_sdk_python/models/services/identity/policies/ark_identity_add_policy.py
new file mode 100644
index 00000000..a47082b4
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_add_policy.py
@@ -0,0 +1,13 @@
+from typing import Any, Dict, List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityAddPolicy(ArkModel):
+ policy_name: str = Field(description='Name of the policy to create')
+ description: str = Field(description='Description of the policy', default="")
+ role_names: List[str] = Field(description='Roles to associate to the policy')
+ auth_profile_name: str = Field(description='Authentication profile to assoicate to the policy')
+ settings: Optional[Dict[str, Any]] = Field(description='Settings of the policy')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_authentication_profile.py b/ark_sdk_python/models/services/identity/policies/ark_identity_authentication_profile.py
new file mode 100644
index 00000000..17aab9b7
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_authentication_profile.py
@@ -0,0 +1,14 @@
+from typing import Any, Dict, List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkTitleizedModel
+
+
+class ArkIdentityAuthenticationProfile(ArkTitleizedModel):
+ challenges: List[str] = Field(description='List of challenges for the profile')
+ id: Optional[str] = Field(description='Identifier of the profile', alias='ID')
+ name: str = Field(description='Name of the profile')
+ single_challenge_mechanisms: Optional[str] = Field(description='Single challenge mechanisms used')
+ uuid: str = Field(description='UUID of the profile')
+ additional_data: Dict[str, Any] = Field(description='Additional profile data')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_disable_policy.py b/ark_sdk_python/models/services/identity/policies/ark_identity_disable_policy.py
new file mode 100644
index 00000000..18fc4d2e
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_disable_policy.py
@@ -0,0 +1,7 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityDisablePolicy(ArkModel):
+ policy_name: str = Field(description='Policy to disable')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_enable_policy.py b/ark_sdk_python/models/services/identity/policies/ark_identity_enable_policy.py
new file mode 100644
index 00000000..bc7263ce
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_enable_policy.py
@@ -0,0 +1,7 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityEnablePolicy(ArkModel):
+ policy_name: str = Field(description='Policy to enable')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_get_authentication_profile.py b/ark_sdk_python/models/services/identity/policies/ark_identity_get_authentication_profile.py
new file mode 100644
index 00000000..a1155d99
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_get_authentication_profile.py
@@ -0,0 +1,10 @@
+from typing import Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityGetAuthenticationProfile(ArkModel):
+ auth_profile_id: Optional[str] = Field(description='Gets the profile by id')
+ auth_profile_name: Optional[str] = Field(description='Gets the profile by name')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_get_policy.py b/ark_sdk_python/models/services/identity/policies/ark_identity_get_policy.py
new file mode 100644
index 00000000..990b0683
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_get_policy.py
@@ -0,0 +1,7 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityGetPolicy(ArkModel):
+ policy_name: str = Field(description='Policy name to get')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_policy.py b/ark_sdk_python/models/services/identity/policies/ark_identity_policy.py
new file mode 100644
index 00000000..15c90d1e
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_policy.py
@@ -0,0 +1,25 @@
+from typing import Any, Dict, List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkTitleizedModel
+from ark_sdk_python.models.services.identity.policies.ark_identity_authentication_profile import ArkIdentityAuthenticationProfile
+
+
+class ArkIdentityPolicyDirectoryService(ArkTitleizedModel):
+ display_name_short: str = Field(description='Display name of the directory service')
+ directory_service_uuid: str = Field(description='UUID of the directory', alias='directoryServiceUuid')
+
+
+class ArkIdentityPolicy(ArkTitleizedModel):
+ auth_profiles: List[ArkIdentityAuthenticationProfile] = Field(description="Auth profiles set for the policy")
+ description: str = Field(description='Description of the policy')
+ directory_services: List[ArkIdentityPolicyDirectoryService] = Field(description='Directory services of the policy')
+ path: str = Field(description='Path of the policy')
+ policy_modifiers: List[str] = Field(description='Modifiers of the policy')
+ radius_client_list: Optional[List[str]] = Field(description='Client list integrated with radius on the policy')
+ radius_server_list: Optional[List[str]] = Field(description='Server list integrated with radius on the policy')
+ rev_stamp: str = Field(description='Timestamp of the revision')
+ risk_analysis_levels: Dict[str, Any] = Field(description='Risk analysis info')
+ settings: Dict[str, Any] = Field(description='Settings of the policy')
+ version: int = Field(description='Version of the policy')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_policy_info.py b/ark_sdk_python/models/services/identity/policies/ark_identity_policy_info.py
new file mode 100644
index 00000000..a9fc2b97
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_policy_info.py
@@ -0,0 +1,11 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkTitleizedModel
+
+
+class ArkIdentityPolicyInfo(ArkTitleizedModel):
+ id: str = Field(description='ID of the policy', alias='ID')
+ description: str = Field(description='Description of the policy')
+ enable_compliant: bool = Field(description='Enable policy compliant')
+ link_type: str = Field(description='Type of policy link')
+ policy_set: str = Field(description="Policy set name")
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_policy_operation.py b/ark_sdk_python/models/services/identity/policies/ark_identity_policy_operation.py
new file mode 100644
index 00000000..07af6998
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_policy_operation.py
@@ -0,0 +1,9 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.services.identity.policies.ark_identity_policy_operation_type import ArkIdentityPolicyOperationType
+
+
+class ArkIdentityPolicyOperation(ArkModel):
+ policy_name: str = Field(description='Policy name')
+ operation_type: ArkIdentityPolicyOperationType = Field(description='Operation to perform on the policy')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_policy_operation_type.py b/ark_sdk_python/models/services/identity/policies/ark_identity_policy_operation_type.py
new file mode 100644
index 00000000..7609451a
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_policy_operation_type.py
@@ -0,0 +1,6 @@
+from enum import Enum
+
+
+class ArkIdentityPolicyOperationType(str, Enum):
+ ENABLE = 'Global'
+ DISABLE = 'Inactive'
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_remove_authentication_profile.py b/ark_sdk_python/models/services/identity/policies/ark_identity_remove_authentication_profile.py
new file mode 100644
index 00000000..7e5305d2
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_remove_authentication_profile.py
@@ -0,0 +1,10 @@
+from typing import Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityRemoveAuthenticationProfile(ArkModel):
+ auth_profile_id: Optional[str] = Field(description='Remove the profile by id')
+ auth_profile_name: Optional[str] = Field(description='Remove the profile by name')
diff --git a/ark_sdk_python/models/services/identity/policies/ark_identity_remove_policy.py b/ark_sdk_python/models/services/identity/policies/ark_identity_remove_policy.py
new file mode 100644
index 00000000..967ea318
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/policies/ark_identity_remove_policy.py
@@ -0,0 +1,7 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityRemovePolicy(ArkModel):
+ policy_name: str = Field(description='Policy name to remove')
diff --git a/ark_sdk_python/models/services/identity/roles/__init__.py b/ark_sdk_python/models/services/identity/roles/__init__.py
new file mode 100644
index 00000000..86fbb52e
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/__init__.py
@@ -0,0 +1,33 @@
+from ark_sdk_python.models.services.identity.roles.ark_identity_add_admin_right_to_role import ArkIdentityAddAdminRightsToRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_add_group_to_role import ArkIdentityAddGroupToRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_add_role_to_role import ArkIdentityAddRoleToRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_add_user_to_role import ArkIdentityAddUserToRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_admin_right import ArkIdentityAdminRights
+from ark_sdk_python.models.services.identity.roles.ark_identity_create_role import ArkIdentityCreateRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_delete_role import ArkIdentityDeleteRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_list_role_members import ArkIdentityListRoleMembers
+from ark_sdk_python.models.services.identity.roles.ark_identity_remove_group_from_role import ArkIdentityRemoveGroupFromRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_remove_role_from_role import ArkIdentityRemoveRoleFromRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_remove_user_from_role import ArkIdentityRemoveUserFromRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_role import ArkIdentityRole
+from ark_sdk_python.models.services.identity.roles.ark_identity_role_id_by_name import ArkIdentityRoleIdByName
+from ark_sdk_python.models.services.identity.roles.ark_identity_role_member import ArkIdentityRoleMember
+from ark_sdk_python.models.services.identity.roles.ark_identity_update_role import ArkIdentityUpdateRole
+
+__all__ = [
+ 'ArkIdentityAddAdminRightsToRole',
+ 'ArkIdentityAddUserToRole',
+ 'ArkIdentityAddGroupToRole',
+ 'ArkIdentityAddRoleToRole',
+ 'ArkIdentityAdminRights',
+ 'ArkIdentityCreateRole',
+ 'ArkIdentityDeleteRole',
+ 'ArkIdentityRemoveUserFromRole',
+ 'ArkIdentityRemoveGroupFromRole',
+ 'ArkIdentityRemoveRoleFromRole',
+ 'ArkIdentityRole',
+ 'ArkIdentityRoleIdByName',
+ 'ArkIdentityUpdateRole',
+ 'ArkIdentityListRoleMembers',
+ 'ArkIdentityRoleMember',
+]
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_add_admin_right_to_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_add_admin_right_to_role.py
new file mode 100644
index 00000000..3f5979c9
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_add_admin_right_to_role.py
@@ -0,0 +1,12 @@
+from typing import Optional
+
+from pydantic import Field, conlist
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.services.identity.roles.ark_identity_admin_right import ArkIdentityAdminRights
+
+
+class ArkIdentityAddAdminRightsToRole(ArkModel):
+ role_id: Optional[str] = Field(description='Role id to add admin rights to')
+ role_name: Optional[str] = Field(description='Role name to add admin rights to')
+ admin_rights: conlist(ArkIdentityAdminRights, min_items=1) = Field(description='Admin rights to add to the role')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_add_group_to_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_add_group_to_role.py
new file mode 100644
index 00000000..14b41575
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_add_group_to_role.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityAddGroupToRole(ArkModel):
+ group_name: str = Field(description='Group name to add to the role')
+ role_name: str = Field(description='Name of the role to add the group to')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_add_role_to_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_add_role_to_role.py
new file mode 100644
index 00000000..27453e84
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_add_role_to_role.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityAddRoleToRole(ArkModel):
+ role_name_to_add: str = Field(description='Role name to add to the role')
+ role_name: str = Field(description='Name of the role to add the role to')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_add_user_to_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_add_user_to_role.py
new file mode 100644
index 00000000..573ca7a6
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_add_user_to_role.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityAddUserToRole(ArkModel):
+ username: str = Field(description='Username to add to the role')
+ role_name: str = Field(description='Name of the role to add the user to')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_admin_right.py b/ark_sdk_python/models/services/identity/roles/ark_identity_admin_right.py
new file mode 100644
index 00000000..163a93ed
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_admin_right.py
@@ -0,0 +1,10 @@
+from enum import Enum
+
+
+class ArkIdentityAdminRights(str, Enum):
+ AdminPortalLogin = '/lib/rights/adminportallogin.json'
+ RoleManagement = '/lib/rights/roleman.json'
+ ReadOnlyRoleManagement = '/lib/rights/roroleman.json'
+ UserManagement = '/lib/rights/dsman.json'
+ Audit = 'ServiceRight/auditShowTile'
+ JIT = 'ServiceRight/dpaShowTile'
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_create_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_create_role.py
new file mode 100644
index 00000000..36956f25
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_create_role.py
@@ -0,0 +1,12 @@
+from typing import List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.services.identity.roles.ark_identity_admin_right import ArkIdentityAdminRights
+
+
+class ArkIdentityCreateRole(ArkModel):
+ role_name: str = Field(description='Role name to create')
+ description: Optional[str] = Field(description='Description of the role')
+ admin_rights: List[ArkIdentityAdminRights] = Field(description='Admin rights to add to the role', default_factory=list)
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_delete_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_delete_role.py
new file mode 100644
index 00000000..d300a267
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_delete_role.py
@@ -0,0 +1,10 @@
+from typing import Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityDeleteRole(ArkModel):
+ role_name: Optional[str] = Field(description='Role name to delete')
+ role_id: Optional[str] = Field(description='Role id to delete')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_list_role_members.py b/ark_sdk_python/models/services/identity/roles/ark_identity_list_role_members.py
new file mode 100644
index 00000000..7f26eec5
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_list_role_members.py
@@ -0,0 +1,10 @@
+from typing import Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityListRoleMembers(ArkModel):
+ role_name: Optional[str] = Field(description='Name of the role to get members of')
+ role_id: Optional[str] = Field(description='ID of the role to get members of')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_remove_group_from_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_remove_group_from_role.py
new file mode 100644
index 00000000..0833abeb
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_remove_group_from_role.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityRemoveGroupFromRole(ArkModel):
+ group_name: str = Field(description='Group name to remove from the role')
+ role_name: str = Field(description='Name of the role to remove the group from')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_remove_role_from_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_remove_role_from_role.py
new file mode 100644
index 00000000..b1f3584a
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_remove_role_from_role.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityRemoveRoleFromRole(ArkModel):
+ role_name_to_remove: str = Field(description='Role name to remove from the role')
+ role_name: str = Field(description='Name of the role to remove the role from')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_remove_user_from_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_remove_user_from_role.py
new file mode 100644
index 00000000..2ec8f5ac
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_remove_user_from_role.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityRemoveUserFromRole(ArkModel):
+ username: str = Field(description='Username to remove from the role')
+ role_name: str = Field(description='Name of the role to remove the user from')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_role.py
new file mode 100644
index 00000000..3a3507c7
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_role.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityRole(ArkModel):
+ role_id: str = Field(description='Identifier of the role')
+ role_name: str = Field(description='Name of the role')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_role_id_by_name.py b/ark_sdk_python/models/services/identity/roles/ark_identity_role_id_by_name.py
new file mode 100644
index 00000000..7958a8c9
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_role_id_by_name.py
@@ -0,0 +1,7 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityRoleIdByName(ArkModel):
+ role_name: str = Field(description='Role name to find the id for')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_role_member.py b/ark_sdk_python/models/services/identity/roles/ark_identity_role_member.py
new file mode 100644
index 00000000..9295ac36
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_role_member.py
@@ -0,0 +1,10 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+from ark_sdk_python.models.services.identity.directories.ark_identity_entity import ArkIdentityEntityType
+
+
+class ArkIdentityRoleMember(ArkModel):
+ member_id: str = Field(description='ID of the mmeber')
+ member_name: str = Field(description='Name of the member')
+ member_type: ArkIdentityEntityType = Field(description='Type of the member')
diff --git a/ark_sdk_python/models/services/identity/roles/ark_identity_update_role.py b/ark_sdk_python/models/services/identity/roles/ark_identity_update_role.py
new file mode 100644
index 00000000..d1942c86
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/roles/ark_identity_update_role.py
@@ -0,0 +1,12 @@
+from typing import Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityUpdateRole(ArkModel):
+ role_name: Optional[str] = Field(description='Role name to update')
+ role_id: Optional[str] = Field(description='Role id to update')
+ new_role_name: Optional[str] = Field(description='New role name to update to')
+ description: Optional[str] = Field(description='New description of the role')
diff --git a/ark_sdk_python/models/services/identity/users/__init__.py b/ark_sdk_python/models/services/identity/users/__init__.py
new file mode 100644
index 00000000..c08afb04
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/__init__.py
@@ -0,0 +1,19 @@
+from ark_sdk_python.models.services.identity.users.ark_identity_create_user import ArkIdentityCreateUser
+from ark_sdk_python.models.services.identity.users.ark_identity_delete_user import ArkIdentityDeleteUser
+from ark_sdk_python.models.services.identity.users.ark_identity_reset_user_password import ArkIdentityResetUserPassword
+from ark_sdk_python.models.services.identity.users.ark_identity_update_user import ArkIdentityUpdateUser
+from ark_sdk_python.models.services.identity.users.ark_identity_user import ArkIdentityUser
+from ark_sdk_python.models.services.identity.users.ark_identity_user_by_name import ArkIdentityUserByName
+from ark_sdk_python.models.services.identity.users.ark_identity_user_id_by_name import ArkIdentityUserIdByName
+from ark_sdk_python.models.services.identity.users.ark_identity_user_info import ArkIdentityUserInfo
+
+__all__ = [
+ 'ArkIdentityCreateUser',
+ 'ArkIdentityUser',
+ 'ArkIdentityResetUserPassword',
+ 'ArkIdentityDeleteUser',
+ 'ArkIdentityUserIdByName',
+ 'ArkIdentityUserByName',
+ 'ArkIdentityUpdateUser',
+ 'ArkIdentityUserInfo',
+]
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_create_user.py b/ark_sdk_python/models/services/identity/users/ark_identity_create_user.py
new file mode 100644
index 00000000..0657bbce
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_create_user.py
@@ -0,0 +1,29 @@
+import random
+import string
+from typing import Final, List, Optional
+
+from pydantic import Field, SecretStr
+
+from ark_sdk_python.common import ArkRandomUtils
+from ark_sdk_python.models import ArkModel
+
+DEFAULT_ADMIN_ROLES: Final[List[str]] = ["DpaAdmin", 'global auditor', "System Administrator"]
+
+
+class ArkIdentityCreateUser(ArkModel):
+ username: str = Field(
+ description='Name of the user to create', default_factory=lambda: f"ark_user_{ArkRandomUtils.random_string(n=10)}"
+ )
+ display_name: Optional[str] = Field(
+ description='Display name of the user',
+ default_factory=lambda: f'{ArkRandomUtils.random_string(5).capitalize()} {ArkRandomUtils.random_string(7).capitalize()}',
+ )
+ email: Optional[str] = Field(
+ description='Email of the user', default_factory=lambda: f'{ArkRandomUtils.random_string(6).lower()}@email.com'
+ )
+ mobile_number: Optional[str] = Field(
+ description='Mobile number of the user', default_factory=lambda: f'+44-987-654-{"".join(random.choices(string.digits, k=4))}'
+ )
+ suffix: Optional[str] = Field(description='Suffix to use for the username')
+ password: SecretStr = Field(description='Password of the user', default_factory=lambda: SecretStr(ArkRandomUtils.random_password(n=25)))
+ roles: List[str] = Field(description='Roles to add the user to', default_factory=DEFAULT_ADMIN_ROLES.copy)
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_delete_user.py b/ark_sdk_python/models/services/identity/users/ark_identity_delete_user.py
new file mode 100644
index 00000000..42a0f75a
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_delete_user.py
@@ -0,0 +1,10 @@
+from typing import Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityDeleteUser(ArkModel):
+ user_id: Optional[str] = Field(description='User ID to delete')
+ username: Optional[str] = Field(description='Username to delete')
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_reset_user_password.py b/ark_sdk_python/models/services/identity/users/ark_identity_reset_user_password.py
new file mode 100644
index 00000000..3d58f0af
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_reset_user_password.py
@@ -0,0 +1,8 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityResetUserPassword(ArkModel):
+ username: str = Field(description='Username to reset the password for')
+ new_password: str = Field(description='New password to reset to')
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_update_user.py b/ark_sdk_python/models/services/identity/users/ark_identity_update_user.py
new file mode 100644
index 00000000..c8d24220
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_update_user.py
@@ -0,0 +1,14 @@
+from typing import Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityUpdateUser(ArkModel):
+ user_id: Optional[str] = Field(description='Users id that we change the details for')
+ username: Optional[str] = Field(description='Username that we change the details for')
+ new_username: Optional[str] = Field(description='Name of the user to change')
+ display_name: Optional[str] = Field(description='Display name of the user to change')
+ email: Optional[str] = Field(description='Email of the user to change')
+ mobile_number: Optional[str] = Field(description='Mobile number of the user to change')
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_user.py b/ark_sdk_python/models/services/identity/users/ark_identity_user.py
new file mode 100644
index 00000000..6cf89660
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_user.py
@@ -0,0 +1,16 @@
+from datetime import datetime
+from typing import List, Optional
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkPresentableModel
+
+
+class ArkIdentityUser(ArkPresentableModel):
+ user_id: str = Field(description='User identifier')
+ username: str = Field(description='Name of the user')
+ display_name: str = Field(description='Display name of the user')
+ email: Optional[str] = Field(description='Email of the user')
+ mobile_number: Optional[str] = Field(description='Mobile number of the user')
+ roles: Optional[List[str]] = Field(description='Roles of the user')
+ last_login: Optional[datetime] = Field(description='Last login of the user')
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_user_by_name.py b/ark_sdk_python/models/services/identity/users/ark_identity_user_by_name.py
new file mode 100644
index 00000000..377033e6
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_user_by_name.py
@@ -0,0 +1,7 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityUserByName(ArkModel):
+ username: str = Field(description='User name to find the id for')
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_user_id_by_name.py b/ark_sdk_python/models/services/identity/users/ark_identity_user_id_by_name.py
new file mode 100644
index 00000000..fe56d669
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_user_id_by_name.py
@@ -0,0 +1,7 @@
+from pydantic import Field
+
+from ark_sdk_python.models import ArkModel
+
+
+class ArkIdentityUserIdByName(ArkModel):
+ username: str = Field(description='User name to find the id for')
diff --git a/ark_sdk_python/models/services/identity/users/ark_identity_user_info.py b/ark_sdk_python/models/services/identity/users/ark_identity_user_info.py
new file mode 100644
index 00000000..98808d66
--- /dev/null
+++ b/ark_sdk_python/models/services/identity/users/ark_identity_user_info.py
@@ -0,0 +1,16 @@
+from typing import Any, List
+
+from pydantic import Field
+
+from ark_sdk_python.models import ArkTitleizedModel
+
+
+class ArkIdentityUserInfo(ArkTitleizedModel):
+ first_name: str = Field(description='First name of the user')
+ last_name: str = Field(description='Last name of the user')
+ home_number: str = Field(description='Home number of the user')
+ manager: str = Field(description='Manager of the user')
+ username: str = Field(description='Username info')
+ groups: List[Any] = Field(description='AD groups of the user', default_factory=list)
+ rights: List[str] = Field(description='Administrative rights of the user', default_factory=list)
+ roles: List[Any] = Field(description='Roles of the user', default_factory=list)
diff --git a/ark_sdk_python/services/dpa/sso/ark_dpa_sso_service.py b/ark_sdk_python/services/dpa/sso/ark_dpa_sso_service.py
index 601ca64d..8b02f753 100644
--- a/ark_sdk_python/services/dpa/sso/ark_dpa_sso_service.py
+++ b/ark_sdk_python/services/dpa/sso/ark_dpa_sso_service.py
@@ -77,6 +77,7 @@ def __output_client_certificate(
) -> None:
folder_path = self.__expand_folder(folder)
claims = get_unverified_claims(self.__client.session_token)
+ base_name = claims["unique_name"].split('@')[0]
client_certificate = result.token['client_certificate']
private_key = result.token['private_key']
@@ -95,9 +96,9 @@ def __output_client_certificate(
)
if not os.path.exists(folder_path):
os.makedirs(folder_path)
- with open(f'{folder_path}{os.path.sep}{claims["unique_name"]}client_cert.crt', 'w', encoding='utf-8') as file_handle:
+ with open(f'{folder_path}{os.path.sep}{base_name}_client_cert.crt', 'w', encoding='utf-8') as file_handle:
file_handle.write(client_certificate)
- with open(f'{folder_path}{os.path.sep}{claims["unique_name"]}client_key.pem', 'w', encoding='utf-8') as file_handle:
+ with open(f'{folder_path}{os.path.sep}{base_name}_client_key.pem', 'w', encoding='utf-8') as file_handle:
file_handle.write(private_key)
elif output_format == ArkDPASSOShortLiveClientCertificateFormat.SINGLE_FILE:
if not folder:
@@ -106,7 +107,7 @@ def __output_client_certificate(
)
if not os.path.exists(folder_path):
os.makedirs(folder_path)
- with open(f'{folder_path}{os.path.sep}{claims["unique_name"]}client_cert.pem', 'w', encoding='utf-8') as file_handle:
+ with open(f'{folder_path}{os.path.sep}{base_name}_client_cert.pem', 'w', encoding='utf-8') as file_handle:
file_handle.write(client_certificate)
file_handle.write('\n')
file_handle.write(private_key)
@@ -119,7 +120,9 @@ def __save_oracle_sso_wallet(self, folder: str, unzip_wallet: bool, result: ArkD
if not os.path.exists(folder_path):
os.makedirs(folder_path)
if not unzip_wallet:
- with open(f'{folder_path}{os.path.sep}wallet.zip', 'wb') as file_handle:
+ claims = get_unverified_claims(self.__client.session_token)
+ base_name = claims["unique_name"].split('@')[0]
+ with open(f'{folder_path}{os.path.sep}{base_name}_wallet.zip', 'wb') as file_handle:
file_handle.write(result.token['wallet'])
else:
wallet_bytes = BytesIO(result.token['wallet'])
@@ -129,10 +132,11 @@ def __save_oracle_sso_wallet(self, folder: str, unzip_wallet: bool, result: ArkD
def __save_oracle_pem_wallet(self, folder: str, result: ArkDPASSOAcquireTokenResponse) -> None:
folder_path = self.__expand_folder(folder)
claims = get_unverified_claims(self.__client.session_token)
+ base_name = claims["unique_name"].split('@')[0]
pem_wallet = base64.b64decode(result.token['pem_wallet']).decode('utf-8')
if not os.path.exists(folder_path):
os.makedirs(folder_path)
- with open(f'{folder_path}{os.path.sep}{claims["unique_name"]}ewallet.pem', 'w', encoding='utf-8') as file_handle:
+ with open(f'{folder_path}{os.path.sep}{base_name}_ewallet.pem', 'w', encoding='utf-8') as file_handle:
file_handle.write(pem_wallet)
def __save_rdp_file(self, get_short_lived_rdp_file: ArkDPASSOGetShortLivedRDPFile, result: ArkDPASSOAcquireTokenResponse) -> None:
diff --git a/ark_sdk_python/services/identity/__init__.py b/ark_sdk_python/services/identity/__init__.py
new file mode 100644
index 00000000..1217600c
--- /dev/null
+++ b/ark_sdk_python/services/identity/__init__.py
@@ -0,0 +1,3 @@
+from ark_sdk_python.services.identity.ark_identity_api import ArkIdentityAPI
+
+__all__ = ['ArkIdentityAPI']
diff --git a/ark_sdk_python/services/identity/ark_identity_api.py b/ark_sdk_python/services/identity/ark_identity_api.py
new file mode 100644
index 00000000..4d6ca087
--- /dev/null
+++ b/ark_sdk_python/services/identity/ark_identity_api.py
@@ -0,0 +1,53 @@
+from ark_sdk_python.auth import ArkISPAuth
+from ark_sdk_python.services.identity.directories import ArkIdentityDirectoriesService
+from ark_sdk_python.services.identity.policies import ArkIdentityPoliciesService
+from ark_sdk_python.services.identity.roles import ArkIdentityRolesService
+from ark_sdk_python.services.identity.users import ArkIdentityUsersService
+
+
+class ArkIdentityAPI:
+ def __init__(self, isp_auth: ArkISPAuth) -> None:
+ self.__identity_directories = ArkIdentityDirectoriesService(isp_auth)
+ self.__identity_policies = ArkIdentityPoliciesService(isp_auth)
+ self.__identity_roles = ArkIdentityRolesService(isp_auth)
+ self.__identity_users = ArkIdentityUsersService(isp_auth)
+
+ @property
+ def identity_directories(self) -> ArkIdentityDirectoriesService:
+ """
+ Getter for the identity directories service
+
+ Returns:
+ ArkIdentityDirectoriesService: _description_
+ """
+ return self.__identity_directories
+
+ @property
+ def identity_policies(self) -> ArkIdentityPoliciesService:
+ """
+ Getter for the identity policies service
+
+ Returns:
+ ArkIdentityPoliciesService: _description_
+ """
+ return self.__identity_policies
+
+ @property
+ def identity_roles(self) -> ArkIdentityRolesService:
+ """
+ Getter for the identity roles service
+
+ Returns:
+ ArkIdentityRolesService: _description_
+ """
+ return self.__identity_roles
+
+ @property
+ def identity_users(self) -> ArkIdentityUsersService:
+ """
+ Getter for the identity users service
+
+ Returns:
+ ArkIdentityUsersService: _description_
+ """
+ return self.__identity_users
diff --git a/ark_sdk_python/services/identity/common/__init__.py b/ark_sdk_python/services/identity/common/__init__.py
new file mode 100644
index 00000000..bb0d7f11
--- /dev/null
+++ b/ark_sdk_python/services/identity/common/__init__.py
@@ -0,0 +1,3 @@
+from ark_sdk_python.services.identity.common.ark_identity_base_service import ArkIdentityBaseService
+
+__all__ = ['ArkIdentityBaseService']
diff --git a/ark_sdk_python/services/identity/common/ark_identity_base_service.py b/ark_sdk_python/services/identity/common/ark_identity_base_service.py
new file mode 100644
index 00000000..8fd0efb3
--- /dev/null
+++ b/ark_sdk_python/services/identity/common/ark_identity_base_service.py
@@ -0,0 +1,38 @@
+import os
+
+from ark_sdk_python.auth.ark_isp_auth import ArkISPAuth
+from ark_sdk_python.common.ark_client import ArkClient
+from ark_sdk_python.common.env import ROOT_DOMAIN, AwsEnv
+from ark_sdk_python.common.isp import ArkISPServiceClient
+from ark_sdk_python.services.ark_service import ArkService
+
+
+class ArkIdentityBaseService(ArkService):
+ def __init__(self, isp_auth: ArkISPAuth) -> None:
+ super().__init__(isp_auth)
+ self._isp_auth = isp_auth
+ self._idp_client = ArkClient(
+ isp_auth.token.endpoint,
+ isp_auth.token.token.get_secret_value(),
+ )
+ self._idp_client.add_headers(
+ {
+ 'Content-Type': 'application/json',
+ 'X-IDAP-NATIVE-CLIENT': 'true',
+ 'Authorization': f'Bearer {isp_auth.token.token.get_secret_value()}',
+ }
+ )
+ self._client = None
+ self._url_prefix = 'api/idadmin/'
+ self._env = None
+ if 'env' in isp_auth.token.metadata.keys():
+ self._env = AwsEnv(isp_auth.token.metadata['env'])
+ else:
+ self._env = AwsEnv(os.environ.get('DEPLOY_ENV', AwsEnv.PROD.value))
+ try:
+ self._client: ArkISPServiceClient = ArkISPServiceClient.from_isp_auth(self._isp_auth)
+ self._env = self._client.tenant_env
+ except Exception:
+ self._client = self._idp_client
+ if any(f'id.{d}' in self._idp_client.base_url for d in ROOT_DOMAIN.values()):
+ self._url_prefix = ''
diff --git a/ark_sdk_python/services/identity/directories/__init__.py b/ark_sdk_python/services/identity/directories/__init__.py
new file mode 100644
index 00000000..6c86c237
--- /dev/null
+++ b/ark_sdk_python/services/identity/directories/__init__.py
@@ -0,0 +1,3 @@
+from ark_sdk_python.services.identity.directories.ark_identity_directories_service import ArkIdentityDirectoriesService
+
+__all__ = ['ArkIdentityDirectoriesService']
diff --git a/ark_sdk_python/services/identity/directories/ark_identity_directories_service.py b/ark_sdk_python/services/identity/directories/ark_identity_directories_service.py
new file mode 100644
index 00000000..9f62ea74
--- /dev/null
+++ b/ark_sdk_python/services/identity/directories/ark_identity_directories_service.py
@@ -0,0 +1,216 @@
+from http import HTTPStatus
+from typing import Final, Iterator, List
+
+from overrides import overrides
+from pydantic.error_wrappers import ValidationError
+from requests import Response
+from requests.exceptions import JSONDecodeError
+
+from ark_sdk_python.common import ArkPage
+from ark_sdk_python.common.env import SHELL_DOMAIN, check_if_identity_generated_suffix
+from ark_sdk_python.models.ark_exceptions import ArkServiceException
+from ark_sdk_python.models.common.identity import (
+ DirectorySearchArgs,
+ DirectoryService,
+ DirectoryServiceQueryResponse,
+ GetDirectoryServicesResponse,
+ GetTenantSuffixResult,
+)
+from ark_sdk_python.models.common.identity.ark_identity_directory_schemas import DirectoryServiceQueryRequest
+from ark_sdk_python.models.services import ArkServiceConfig
+from ark_sdk_python.models.services.identity.directories import (
+ ArkIdentityDirectory,
+ ArkIdentityEntity,
+ ArkIdentityEntityType,
+ ArkIdentityGroupEntity,
+ ArkIdentityListDirectories,
+ ArkIdentityListDirectoriesEntities,
+ ArkIdentityRoleEntity,
+ ArkIdentityUserEntity,
+)
+from ark_sdk_python.services.identity.common import ArkIdentityBaseService
+
+SERVICE_CONFIG: Final[ArkServiceConfig] = ArkServiceConfig(
+ service_name='identity-directories', required_authenticator_names=['isp'], optional_authenticator_names=[]
+)
+
+TENANT_SUFFIX_URL: Final[str] = 'Core/GetCdsAliasesForTenant'
+GET_DIRECTORY_SERVICES_URL: Final[str] = 'Core/GetDirectoryServices'
+DIRECTORY_SERVICE_QUERY_URL: Final[str] = 'UserMgmt/DirectoryServiceQuery'
+
+ArkIdentityEntitiesPage = ArkPage[ArkIdentityEntity]
+
+
+class ArkIdentityDirectoriesService(ArkIdentityBaseService):
+ def list_directories(self, list_directories: ArkIdentityListDirectories) -> List[ArkIdentityDirectory]:
+ """
+ Get directories for given types
+
+ Args:
+ list_directories (ArkIdentityListDirectories): _description_
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ List[ArkIdentityDirectory]: _description_
+ """
+ if not list_directories.directories:
+ list_directories.directories = [d for d in DirectoryService]
+ self._logger.info(f'Retrieving directory services for directories [{list_directories}] [{self._url_prefix}]')
+ response: Response = self._client.get(f'{self._url_prefix}{GET_DIRECTORY_SERVICES_URL}', data={})
+ try:
+ directory_services_result = GetDirectoryServicesResponse.parse_raw(response.text)
+ requested_directories = set(item.value for item in list_directories.directories)
+ requested_services = list(
+ filter(lambda service: service.row.service in requested_directories, directory_services_result.result.results)
+ )
+ if len(requested_services) == 0:
+ raise ArkServiceException(f'Could not find any directory services matching {requested_directories}')
+ directories = list(
+ map(
+ lambda service: ArkIdentityDirectory(
+ directory=DirectoryService(service.row.service), directory_service_uuid=service.row.directory_service_uuid
+ ),
+ requested_services,
+ )
+ )
+ return directories
+ except (ValidationError, JSONDecodeError) as ex:
+ self._logger.exception(f'Failed to parse directory services response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse directory services response [{str(ex)}]') from ex
+
+ def list_directories_entities(self, list_directories_entities: ArkIdentityListDirectoriesEntities) -> Iterator[ArkIdentityEntitiesPage]:
+ """
+ Lists given directories entities by filters of search and type and directories
+ Yields pages of entities
+
+ Args:
+ list_directories_entities (ArkIdentityListDirectoriesEntities): _description_
+
+ Raises:
+ ArkServiceException: _description_
+
+ Yields:
+ Iterator[ArkIdentityEntitiesPage]: _description_
+ """
+ self._logger.info('Listing directories entities')
+ directories = [
+ d.directory_service_uuid
+ for d in self.list_directories(
+ ArkIdentityListDirectories(directories=list_directories_entities.directories or [d for d in DirectoryService])
+ )
+ ]
+ exclusion_list = set()
+ if list_directories_entities.entity_types:
+ if ArkIdentityEntityType.User not in list_directories_entities.entity_types:
+ exclusion_list.add('user')
+ if ArkIdentityEntityType.Group not in list_directories_entities.entity_types:
+ exclusion_list.add('group')
+ if ArkIdentityEntityType.Role not in list_directories_entities.entity_types:
+ exclusion_list.add('roles')
+ response: Response = self._idp_client.post(
+ DIRECTORY_SERVICE_QUERY_URL,
+ data=DirectoryServiceQueryRequest(
+ directory_services=directories,
+ search_string=list_directories_entities.search,
+ args=DirectorySearchArgs(
+ limit=list_directories_entities.limit, page_number=1, page_size=list_directories_entities.page_size
+ ),
+ ).json(by_alias=True, exclude=exclusion_list),
+ )
+ if response.status_code != HTTPStatus.OK:
+ raise ArkServiceException(f'Failed to query for directory services entities [{response.text}] - [{response.status_code}]')
+ try:
+ result = DirectoryServiceQueryResponse.parse_raw(response.text)
+ entities: List[ArkIdentityEntity] = []
+ if result.result.users and result.result.users.results:
+ for user in result.result.users.results:
+ entities.append(
+ ArkIdentityUserEntity(
+ id=user.row.internal_id,
+ name=user.row.system_name,
+ entity_type=ArkIdentityEntityType.User,
+ directory_service_type=user.row.directory_service_type,
+ display_name=user.row.display_name,
+ service_instance_localized=user.row.service_instance_localized,
+ email=user.row.email,
+ description=user.row.description,
+ )
+ )
+ if result.result.groups and result.result.groups.results:
+ for group in result.result.groups.results:
+ entities.append(
+ ArkIdentityGroupEntity(
+ id=group.row.internal_id,
+ name=group.row.system_name,
+ entity_type=ArkIdentityEntityType.Group,
+ directory_service_type=group.row.directory_service_type,
+ display_name=group.row.display_name,
+ service_instance_localized=group.row.service_instance_localized,
+ )
+ )
+ if result.result.roles and result.result.roles.results:
+ for role in result.result.roles.results:
+ entities.append(
+ ArkIdentityRoleEntity(
+ id=role.row.id,
+ name=role.row.name,
+ entity_type=ArkIdentityEntityType.Role,
+ directory_service_type=DirectoryService.Identity,
+ display_name=role.row.name,
+ service_instance_localized=DirectoryService.Identity.value,
+ admin_rights=role.row.admin_rights,
+ is_hidden=role.row.is_hidden or False,
+ description=role.row.description,
+ )
+ )
+ while entities:
+ if len(entities) <= list_directories_entities.page_size:
+ yield ArkIdentityEntitiesPage(entities)
+ break
+ else:
+ page = entities[: list_directories_entities.page_size]
+ entities = entities[list_directories_entities.page_size :]
+ yield ArkIdentityEntitiesPage(page)
+ except (ValidationError, JSONDecodeError) as ex:
+ self._logger.exception(f'Failed to parse list directories entities response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse list directories entities response [{str(ex)}]') from ex
+
+ def tenant_default_suffix(self) -> str:
+ """
+ Retrieves the tenant default suffix found in identity
+ The suffix is used when creating users based on whats configured on the tenant
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ str: _description_
+ """
+ self._logger.info('Discovering default tenant suffix')
+ response: Response = self._client.post(f'{self._url_prefix}{TENANT_SUFFIX_URL}')
+ if response.status_code != HTTPStatus.OK:
+ raise ArkServiceException(f'Failed to get directory services [{response.text}]')
+ try:
+ tenant_suffixes_result: GetTenantSuffixResult = GetTenantSuffixResult.parse_raw(response.text)
+ tenant_suffixes_list: List[str] = [result['Entities'][0]['Key'] for result in tenant_suffixes_result.result['Results']]
+ if len(tenant_suffixes_list) == 0:
+ raise ArkServiceException('No tenant suffix has been found')
+ filtered_urls = list(
+ filter(
+ lambda suffix: check_if_identity_generated_suffix(suffix, self._env) or SHELL_DOMAIN[self._env] in suffix,
+ tenant_suffixes_list,
+ )
+ )
+ if filtered_urls:
+ return filtered_urls[0]
+ return tenant_suffixes_list[0]
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse tenant default suffix response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse tenant default suffix response [{str(ex)}]') from ex
+
+ @staticmethod
+ @overrides
+ def service_config() -> ArkServiceConfig:
+ return SERVICE_CONFIG
diff --git a/ark_sdk_python/services/identity/policies/__init__.py b/ark_sdk_python/services/identity/policies/__init__.py
new file mode 100644
index 00000000..bce09032
--- /dev/null
+++ b/ark_sdk_python/services/identity/policies/__init__.py
@@ -0,0 +1,3 @@
+from ark_sdk_python.services.identity.policies.ark_identity_policies_service import ArkIdentityPoliciesService
+
+__all__ = ['ArkIdentityPoliciesService']
diff --git a/ark_sdk_python/services/identity/policies/ark_identity_policies_service.py b/ark_sdk_python/services/identity/policies/ark_identity_policies_service.py
new file mode 100644
index 00000000..e031e0e9
--- /dev/null
+++ b/ark_sdk_python/services/identity/policies/ark_identity_policies_service.py
@@ -0,0 +1,366 @@
+from http import HTTPStatus
+from typing import Final, List
+
+from overrides import overrides
+from pydantic import parse_obj_as
+from pydantic.error_wrappers import ValidationError
+from requests import Response
+from requests.exceptions import JSONDecodeError
+
+from ark_sdk_python.models.ark_exceptions import ArkServiceException
+from ark_sdk_python.models.services import ArkServiceConfig
+from ark_sdk_python.models.services.identity.policies import (
+ ArkIdentityAddAuthenticationProfile,
+ ArkIdentityAddPolicy,
+ ArkIdentityAuthenticationProfile,
+ ArkIdentityDisablePolicy,
+ ArkIdentityEnablePolicy,
+ ArkIdentityGetAuthenticationProfile,
+ ArkIdentityGetPolicy,
+ ArkIdentityPolicy,
+ ArkIdentityPolicyInfo,
+ ArkIdentityPolicyOperation,
+ ArkIdentityPolicyOperationType,
+ ArkIdentityRemoveAuthenticationProfile,
+ ArkIdentityRemovePolicy,
+)
+from ark_sdk_python.models.services.identity.roles import ArkIdentityRoleIdByName
+from ark_sdk_python.services.identity.common import ArkIdentityBaseService
+from ark_sdk_python.services.identity.roles import ArkIdentityRolesService
+
+SERVICE_CONFIG: Final[ArkServiceConfig] = ArkServiceConfig(
+ service_name='identity-policies', required_authenticator_names=['isp'], optional_authenticator_names=[]
+)
+
+SAVE_PROFILE_URL: Final[str] = 'AuthProfile/SaveProfile'
+DELETE_PROFILE_URL: Final[str] = 'AuthProfile/DeleteProfile'
+GET_PROFILES_URL: Final[str] = 'AuthProfile/GetDecoratedProfileList'
+SAVE_POLICY_URL: Final[str] = 'Policy/SavePolicyBlock3'
+DELETE_POLICY_URL: Final[str] = 'Policy/DeletePolicyBlock'
+LIST_POLICIES_URL: Final[str] = 'Policy/GetNicePlinks'
+GET_POLICY_URL: Final[str] = 'Policy/GetPolicyBlock'
+
+
+class ArkIdentityPoliciesService(ArkIdentityBaseService):
+ def add_authentication_profile(
+ self, add_authentication_profile: ArkIdentityAddAuthenticationProfile
+ ) -> ArkIdentityAuthenticationProfile:
+ """
+ Adds a new authentication profile
+
+ Args:
+ add_authentication_profile (ArkIdentityAddAuthenticationProfile): _description_
+
+ Returns:
+ ArkIdentityAuthenticationProfile: _description_
+ """
+ self._logger.info(f'Adding authentication profile [{add_authentication_profile.auth_profile_name}]')
+ data = {
+ 'settings': {
+ 'Name': add_authentication_profile.auth_profile_name,
+ 'Challenges': [','.join(add_authentication_profile.first_challenges)],
+ 'DurationInMinutes': add_authentication_profile.duration_in_minutes,
+ }
+ }
+ if add_authentication_profile.second_challenges:
+ data['settings']['Challenges'].append(','.join(add_authentication_profile.second_challenges))
+ if add_authentication_profile.additional_data:
+ data['settings']['AdditionalData'] = add_authentication_profile.additional_data
+ response: Response = self._client.post(f'{self._url_prefix}{SAVE_PROFILE_URL}', json=data)
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to add authentication profile [{response.text}] - [{response.status_code}]')
+ return ArkIdentityAuthenticationProfile.parse_obj(result['Result'])
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse add authentication profile response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse add authentication profile response [{str(ex)}]') from ex
+
+ def remove_authentication_profile(self, remove_authentication_profile: ArkIdentityRemoveAuthenticationProfile) -> None:
+ """
+ Removes an authentication profile by name or id
+
+ Args:
+ remove_authentication_profile (ArkIdentityRemoveAuthenticationProfile): _description_
+ """
+ if remove_authentication_profile.auth_profile_name and not remove_authentication_profile.auth_profile_id:
+ remove_authentication_profile.auth_profile_id = self.authentication_profile(
+ ArkIdentityGetAuthenticationProfile(auth_profile_name=remove_authentication_profile.auth_profile_name)
+ ).uuid
+ self._logger.info(f'Removing authentication profile [{remove_authentication_profile.auth_profile_id}]')
+ response: Response = self._client.post(
+ f'{self._url_prefix}{DELETE_PROFILE_URL}', json={'uuid': remove_authentication_profile.auth_profile_id}
+ )
+ try:
+ if response.status_code != HTTPStatus.OK or not response.json()['success']:
+ raise ArkServiceException(f'Failed to remove authentication profile [{response.text}] - [{response.status_code}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse remove authentication profile response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse remove authentication profile response [{str(ex)}]') from ex
+
+ def list_authentication_profiles(self) -> List[ArkIdentityAuthenticationProfile]:
+ """
+ List available authentication profiles
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ List[ArkIdentityAuthenticationProfile]: _description_
+ """
+ self._logger.info('Listing authentication profiles')
+ response: Response = self._client.post(f'{self._url_prefix}{GET_PROFILES_URL}')
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to list authentication profiles [{response.text}] - [{response.status_code}]')
+ return parse_obj_as(List[ArkIdentityAuthenticationProfile], [r['Row'] for r in result['Result']['Results']])
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse list authentication profiles response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse list authentication profiles response [{str(ex)}]') from ex
+
+ def authentication_profile(self, get_authentication_profile: ArkIdentityGetAuthenticationProfile) -> ArkIdentityAuthenticationProfile:
+ """
+ Retrieve an authentication profile by id or name
+
+ Args:
+ get_authentication_profile (ArkIdentityGetAuthenticationProfile): _description_
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ ArkIdentityAuthenticationProfile: _description_
+ """
+ self._logger.info('Retrieving authentication profile')
+ auth_profiles = self.list_authentication_profiles()
+ if get_authentication_profile.auth_profile_id:
+ auth_profiles = [p for p in auth_profiles if p.uuid == get_authentication_profile.auth_profile_id]
+ if get_authentication_profile.auth_profile_name:
+ auth_profiles = [p for p in auth_profiles if p.name == get_authentication_profile.auth_profile_name]
+ if len(auth_profiles) == 0:
+ raise ArkServiceException('Failed to find authentication profile')
+ return auth_profiles[0]
+
+ def add_policy(self, add_policy: ArkIdentityAddPolicy) -> ArkIdentityPolicy:
+ """
+ Adds a new policy
+
+ Args:
+ add_policy (ArkIdentityAddPolicy): _description_
+
+ Returns:
+ ArkIdentityPolicy: _description_
+ """
+ self._logger.info(f'Adding policy [{add_policy.policy_name}]')
+ roles_service = ArkIdentityRolesService(self._isp_auth)
+ policies_list = [p.dict(by_alias=True) for p in self.list_policies()]
+ policy_name = f'/Policy/{add_policy.policy_name}'
+ policy_link = {
+ "Description": add_policy.description,
+ "PolicySet": policy_name,
+ "LinkType": "Role",
+ "Priority": 1,
+ "Params": [roles_service.role_id_by_name(ArkIdentityRoleIdByName(role_name=role_name)) for role_name in add_policy.role_names],
+ "Filters": [],
+ "Allowedpolicies": [],
+ }
+ policies_list.insert(0, policy_link)
+ data = {
+ "plinks": policies_list,
+ "policy": {
+ "Path": policy_name,
+ "Version": 1,
+ "Description": add_policy.description,
+ "Settings": {
+ "AuthenticationEnabled": 'true',
+ "/Core/Authentication/AuthenticationRulesDefaultProfileId": self.authentication_profile(
+ ArkIdentityGetAuthenticationProfile(auth_profile_name=add_policy.auth_profile_name)
+ ).uuid,
+ "/Core/Authentication/CookieAllowPersist": 'false',
+ "/Core/Authentication/AuthSessionMaxConcurrent": 0,
+ "/Core/Authentication/AllowIwa": 'true',
+ "/Core/Authentication/IwaSetKnownEndpoint": 'false',
+ "/Core/Authentication/IwaSatisfiesAllMechs": 'false',
+ "/Core/Authentication/AllowZso": 'true',
+ "/Core/Authentication/ZsoSkipChallenge": 'true',
+ "/Core/Authentication/ZsoSetKnownEndpoint": 'false',
+ "/Core/Authentication/ZsoSatisfiesAllMechs": 'false',
+ "/Core/Authentication/NoMfaMechLogin": 'false',
+ "/Core/Authentication/FederatedLoginAllowsMfa": 'false',
+ "/Core/Authentication/FederatedLoginSatisfiesAllMechs": 'false',
+ "/Core/MfaRestrictions/BlockMobileMechsOnMobileLogin": 'false',
+ "/Core/Authentication/ContinueFailedSessions": 'true',
+ "/Core/Authentication/SkipMechsInFalseAdvance": 'true',
+ "/Core/Authentication/AllowLoginMfaCache": 'false',
+ },
+ "Newpolicy": 'true',
+ },
+ }
+ if add_policy.settings:
+ data['policy']['Settings'].update(add_policy.settings)
+ response: Response = self._client.post(f'{self._url_prefix}{SAVE_POLICY_URL}', json=data)
+ try:
+ if response.status_code != HTTPStatus.OK or not response.json()['success']:
+ raise ArkServiceException(f'Failed to add policy [{response.text}] - [{response.status_code}]')
+ return self.policy(ArkIdentityGetPolicy(policy_name=add_policy.policy_name))
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse add policy response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse add policy response [{str(ex)}]') from ex
+
+ def disable_default_policy(self) -> None:
+ """
+ Disables the default policy (makes it inactive)
+ """
+ self.disable_policy(
+ disable_policy=ArkIdentityDisablePolicy(
+ policy_name='/Policy/Default Policy',
+ ),
+ )
+
+ def enable_default_policy(self) -> None:
+ """
+ Enables the default policy (makes it active)
+ """
+ self.enable_policy(
+ enable_policy=ArkIdentityEnablePolicy(
+ policy_name='/Policy/Default Policy',
+ ),
+ )
+
+ def perform_action_on_policy(self, policy_operation: ArkIdentityPolicyOperation) -> None:
+ """
+ Performs operation on policy (enable/disable)
+
+ Args:
+ policy_operation (ArkIdentityPolicyOperation): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ policy_name = policy_operation.policy_name
+ policy = self.policy(get_policy=ArkIdentityGetPolicy(policy_name=policy_name))
+
+ policies_list = [p.dict(by_alias=True) for p in self.list_policies()]
+ for elem in policies_list:
+ if elem['ID'] == policy_name:
+ elem['LinkType'] = policy_operation.operation_type.value
+ data = {
+ "plinks": policies_list,
+ "policy": {
+ "Path": policy_name,
+ "Version": 1,
+ "Description": policy.description,
+ "RevStamp": policy.rev_stamp,
+ "Settings": policy.settings,
+ "Newpolicy": False,
+ },
+ }
+ response: Response = self._client.post(f'{self._url_prefix}{SAVE_POLICY_URL}', json=data)
+ try:
+ if response.status_code != HTTPStatus.OK or not response.json()['success']:
+ raise ArkServiceException(f'Failed to add policy [{response.text}] - [{response.status_code}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse perform policy action response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse perform policy action response [{str(ex)}]') from ex
+
+ def enable_policy(self, enable_policy: ArkIdentityEnablePolicy) -> None:
+ """
+ Enables a policy by name
+
+ Args:
+ enable_policy (ArkIdentityEnablePolicy): _description_
+
+ """
+ self._logger.info(f'Making Policy [{enable_policy.policy_name}] active')
+ self.perform_action_on_policy(
+ policy_operation=ArkIdentityPolicyOperation(
+ policy_name=enable_policy.policy_name,
+ operation_type=ArkIdentityPolicyOperationType.ENABLE,
+ ),
+ )
+
+ def disable_policy(self, disable_policy: ArkIdentityDisablePolicy) -> None:
+ """
+ Disables a policy by name
+
+ Args:
+ disable_policy (ArkIdentityDisablePolicy): _description_
+
+ """
+ self._logger.info(f'Making Policy [{disable_policy.policy_name}] inactive')
+ self.perform_action_on_policy(
+ policy_operation=ArkIdentityPolicyOperation(
+ policy_name=disable_policy.policy_name,
+ operation_type=ArkIdentityPolicyOperationType.DISABLE,
+ ),
+ )
+
+ def remove_policy(self, remove_policy: ArkIdentityRemovePolicy) -> None:
+ """
+ Removes a policy by name
+
+ Args:
+ remove_policy (ArkIdentityRemovePolicy): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Removing policy [{remove_policy.policy_name}]')
+ policy_name = remove_policy.policy_name
+ if not policy_name.startswith('/Policy/'):
+ policy_name = f'/Policy/{policy_name}'
+ response: Response = self._client.post(f'{self._url_prefix}{DELETE_POLICY_URL}', json={'path': policy_name})
+ try:
+ if response.status_code != HTTPStatus.OK or not response.json()['success']:
+ raise ArkServiceException(f'Failed to remove policy [{response.text}] - [{response.status_code}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse remove policy response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse remove policy response [{str(ex)}]') from ex
+
+ def list_policies(self) -> List[ArkIdentityPolicyInfo]:
+ """
+ Lists all policies short info
+
+ Returns:
+ List[ArkIdentityPolicyInfo]: _description_
+ """
+ self._logger.info('Listing all policies')
+ response: Response = self._client.post(f'{self._url_prefix}{LIST_POLICIES_URL}')
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to list policies [{response.text}] - [{response.status_code}]')
+ return parse_obj_as(List[ArkIdentityPolicyInfo], [p['Row'] for p in result['Result']['Results']])
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse list policies response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse list policies response [{str(ex)}]') from ex
+
+ def policy(self, get_policy: ArkIdentityGetPolicy) -> ArkIdentityPolicy:
+ """
+ Retrieves a policy full info by name
+
+ Args:
+ get_policy (ArkIdentityGetPolicy): _description_
+
+ Returns:
+ ArkIdentityPolicy: _description_
+ """
+ self._logger.info(f'Retrieving policy [{get_policy.policy_name}]')
+ policy_name = get_policy.policy_name
+ if not policy_name.startswith('/Policy/'):
+ policy_name = f'/Policy/{policy_name}'
+ response: Response = self._client.post(f'{self._url_prefix}{GET_POLICY_URL}', json={'name': policy_name})
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to list policies [{response.text}] - [{response.status_code}]')
+ return ArkIdentityPolicy.parse_obj(result['Result'])
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse policy response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse policy response [{str(ex)}]') from ex
+
+ @staticmethod
+ @overrides
+ def service_config() -> ArkServiceConfig:
+ return SERVICE_CONFIG
diff --git a/ark_sdk_python/services/identity/roles/__init__.py b/ark_sdk_python/services/identity/roles/__init__.py
new file mode 100644
index 00000000..1f65f1e4
--- /dev/null
+++ b/ark_sdk_python/services/identity/roles/__init__.py
@@ -0,0 +1,3 @@
+from ark_sdk_python.services.identity.roles.ark_identity_roles_service import ArkIdentityRolesService
+
+__all__ = ['ArkIdentityRolesService']
diff --git a/ark_sdk_python/services/identity/roles/ark_identity_roles_service.py b/ark_sdk_python/services/identity/roles/ark_identity_roles_service.py
new file mode 100644
index 00000000..7d93a006
--- /dev/null
+++ b/ark_sdk_python/services/identity/roles/ark_identity_roles_service.py
@@ -0,0 +1,402 @@
+from http import HTTPStatus
+from typing import Final, List
+
+from overrides import overrides
+from pydantic.error_wrappers import ValidationError
+from requests import Response
+from requests.exceptions import JSONDecodeError
+
+from ark_sdk_python.models.ark_exceptions import ArkServiceException
+from ark_sdk_python.models.common.identity import (
+ DirectorySearchArgs,
+ DirectoryService,
+ DirectoryServiceQueryResponse,
+ DirectoryServiceQuerySpecificRoleRequest,
+)
+from ark_sdk_python.models.services import ArkServiceConfig
+from ark_sdk_python.models.services.identity.directories import ArkIdentityEntityType, ArkIdentityListDirectories
+from ark_sdk_python.models.services.identity.roles import (
+ ArkIdentityAddAdminRightsToRole,
+ ArkIdentityAddGroupToRole,
+ ArkIdentityAddRoleToRole,
+ ArkIdentityAddUserToRole,
+ ArkIdentityCreateRole,
+ ArkIdentityDeleteRole,
+ ArkIdentityListRoleMembers,
+ ArkIdentityRemoveGroupFromRole,
+ ArkIdentityRemoveRoleFromRole,
+ ArkIdentityRemoveUserFromRole,
+ ArkIdentityRole,
+ ArkIdentityRoleIdByName,
+ ArkIdentityRoleMember,
+ ArkIdentityUpdateRole,
+)
+from ark_sdk_python.services.identity.common import ArkIdentityBaseService
+from ark_sdk_python.services.identity.directories import ArkIdentityDirectoriesService
+
+SERVICE_CONFIG: Final[ArkServiceConfig] = ArkServiceConfig(
+ service_name='identity-roles', required_authenticator_names=['isp'], optional_authenticator_names=[]
+)
+
+ADD_USER_TO_ROLE_URL: Final[str] = 'SaasManage/AddUsersAndGroupsToRole'
+CREATE_ROLE_URL: Final[str] = 'Roles/StoreRole'
+UPDATE_ROLE_URL: Final[str] = 'Roles/UpdateRole'
+ROLE_MEMBERS_URL: Final[str] = 'Roles/GetRoleMembers'
+ADD_ADMIN_RIGHTS_TO_ROLE_URL: Final[str] = 'SaasManage/AssignSuperRights'
+REMOVE_USER_FROM_ROLE_URL: Final[str] = 'SaasManage/RemoveUsersAndGroupsFromRole'
+DELETE_ROLE_URL: Final[str] = 'SaasManage/DeleteRole'
+DIRECTORY_SERVICE_QUERY_URL: Final[str] = 'UserMgmt/DirectoryServiceQuery'
+REDROCK_QUERY: Final[str] = 'Redrock/query'
+
+
+class ArkIdentityRolesService(ArkIdentityBaseService):
+ def create_role(self, create_role: ArkIdentityCreateRole) -> ArkIdentityRole:
+ """
+ Creates a role by given name and adds admin rights to it
+ If the role exists, will only alter admin rights and return it
+
+ Args:
+ create_role (ArkIdentityCreateRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ ArkIdentityRole: _description_
+ """
+ role_details = None
+ self._logger.info(f'Trying to create role [{create_role.role_name}]')
+ try:
+ # Role exists
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=create_role.role_name))
+ role_details = ArkIdentityRole(role_name=create_role.role_name, role_id=role_id)
+ self._logger.info(f'Role already exists with id [{role_id}]')
+ except (ValidationError, Exception) as ex:
+ # Create the role
+ create_dict = {'Name': create_role.role_name}
+ if create_role.description:
+ create_dict['Description'] = create_role.description
+ response: Response = self._client.post(f'{self._url_prefix}{CREATE_ROLE_URL}', json=create_dict)
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to create role [{response.text}]') from ex
+ role_id = result['Result']['_RowKey']
+ role_details = ArkIdentityRole(role_name=create_role.role_name, role_id=role_id)
+ self._logger.info(f'Role created with id [{role_id}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse create role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse create role response [{str(ex)}]') from ex
+ # Add admin rights
+ if create_role.admin_rights:
+ self.add_admin_rights_to_role(
+ ArkIdentityAddAdminRightsToRole(role_id=role_details.role_id, admin_rights=create_role.admin_rights)
+ )
+ return role_details
+
+ def update_role(self, update_role: ArkIdentityUpdateRole) -> None:
+ """
+ Updates a role details
+
+ Args:
+ update_role (ArkIdentityUpdateRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ if update_role.role_name and not update_role.role_id:
+ update_role.role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=update_role.role_name))
+ self._logger.info(f'Updating identity role [{update_role.role_id}]')
+ update_dict = {'Name': update_role.role_id}
+ if update_role.new_role_name:
+ update_dict['NewName'] = update_role.new_role_name
+ if update_role.description:
+ update_role['Description'] = update_role.description
+ response: Response = self._client.post(f'{self._url_prefix}{UPDATE_ROLE_URL}', json=update_dict)
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to update role [{response.text}]')
+ self._logger.info('Role updated successfully')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse update role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse update role response [{str(ex)}]') from ex
+
+ def list_role_members(self, list_role_members: ArkIdentityListRoleMembers) -> List[ArkIdentityRoleMember]:
+ """
+ Lists a role members
+
+ Args:
+ list_role_members (ArkIdentityListRoleMembers): _description_
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ List[ArkIdentityRoleMember]: _description_
+ """
+ if list_role_members.role_name and not list_role_members.role_id:
+ list_role_members.role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=list_role_members.role_name))
+ self._logger.info(f'Listing identity role [{list_role_members.role_id}] members')
+ response: Response = self._client.post(f'{self._url_prefix}{ROLE_MEMBERS_URL}', json={'Name': list_role_members.role_id})
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to list role members [{response.text}]')
+ members = []
+ if 'Result' in result and 'Results' in result['Result'] and len(result['Result']['Results']) > 0:
+ members = [
+ ArkIdentityRoleMember(
+ member_id=r['Row']['Guid'],
+ member_name=r['Row']['Name'],
+ member_type=ArkIdentityEntityType(r['Row']['Type'].upper()),
+ )
+ for r in result['Result']['Results']
+ ]
+ self._logger.info('Listed role members successfully successfully')
+ return members
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse list role members response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse list role members response [{str(ex)}]') from ex
+
+ def add_admin_rights_to_role(self, add_admin_rights_to_role: ArkIdentityAddAdminRightsToRole) -> None:
+ """
+ Adds given admin rights to the role assuming it exists
+
+ Args:
+ add_admin_rights_to_role (ArkIdentityAddAdminRightsToRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Adding admin rights [{add_admin_rights_to_role.admin_rights}] to role [{add_admin_rights_to_role.role_name}]')
+ if not add_admin_rights_to_role.role_id and not add_admin_rights_to_role.role_name:
+ raise ArkServiceException('Either role id or role name must be given')
+ if add_admin_rights_to_role.role_id:
+ role_id = add_admin_rights_to_role.role_id
+ else:
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=add_admin_rights_to_role.role_name))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{ADD_ADMIN_RIGHTS_TO_ROLE_URL}',
+ json=[{'Role': role_id, 'Path': admin_right.value} for admin_right in add_admin_rights_to_role.admin_rights],
+ )
+ try:
+ if response.status_code != HTTPStatus.OK or not response.json()['success']:
+ raise ArkServiceException(f'Failed to add admin rights to role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse add admin rights to role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse add admin rights to role response [{str(ex)}]') from ex
+
+ def role_id_by_name(self, role_id_by_name: ArkIdentityRoleIdByName) -> str:
+ """
+ For a given role name, find its identifier on identity
+
+ Args:
+ role_id_by_name (ArkIdentityRoleIdByName): _description_
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ str: _description_
+ """
+ self._logger.info(f'Retrieving role id for name [{role_id_by_name.role_name}]')
+ directories_service = ArkIdentityDirectoriesService(self._isp_auth)
+ directories = [
+ d.directory_service_uuid
+ for d in directories_service.list_directories(ArkIdentityListDirectories(directories=[DirectoryService.Identity]))
+ ]
+ response: Response = self._client.post(
+ f'{self._url_prefix}{DIRECTORY_SERVICE_QUERY_URL}',
+ data=DirectoryServiceQuerySpecificRoleRequest(
+ role_name=role_id_by_name.role_name, directory_services=directories, args=DirectorySearchArgs(limit=1)
+ ).json(by_alias=True, exclude={'users'}),
+ )
+ if response.status_code != HTTPStatus.OK:
+ raise ArkServiceException(f'Failed to query for directory services role [{response.text}]')
+ try:
+ result = DirectoryServiceQueryResponse.parse_raw(response.text)
+ all_roles = result.result.roles.results
+ if not len(all_roles):
+ raise ArkServiceException('No role found for given name')
+ return all_roles[0].row.id
+ except (ValidationError, JSONDecodeError) as ex:
+ self._logger.exception(f'Failed to parse role id by name response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse role id by name response [{str(ex)}]') from ex
+
+ def add_user_to_role(self, add_user_to_role: ArkIdentityAddUserToRole) -> None:
+ """
+ Adds a given user to the role
+
+ Args:
+ add_user_to_role (ArkIdentityAddUserToRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Adding user [{add_user_to_role.username}] to role [{add_user_to_role.role_name}]')
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=add_user_to_role.role_name))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{ADD_USER_TO_ROLE_URL}',
+ json={
+ 'Name': role_id,
+ 'Users': [add_user_to_role.username],
+ },
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to add user to role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse add user to role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse add user to role response [{str(ex)}]') from ex
+
+ def add_group_to_role(self, add_group_to_role: ArkIdentityAddGroupToRole) -> None:
+ """
+ Adds a given group to the role
+
+ Args:
+ add_group_to_role (ArkIdentityAddGroupToRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Adding group [{add_group_to_role.group_name}] to role [{add_group_to_role.role_name}]')
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=add_group_to_role.role_name))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{ADD_USER_TO_ROLE_URL}',
+ json={
+ 'Name': role_id,
+ 'Groups': [add_group_to_role.group_name],
+ },
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to add group to role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse add group to role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse add group to role response [{str(ex)}]') from ex
+
+ def add_role_to_role(self, add_role_to_role: ArkIdentityAddRoleToRole) -> None:
+ """
+ Adds a given group to the role
+
+ Args:
+ add_role_to_role (ArkIdentityAddRoleToRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Adding role [{add_role_to_role.role_name_to_add}] to role [{add_role_to_role.role_name}]')
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=add_role_to_role.role_name))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{ADD_USER_TO_ROLE_URL}',
+ json={
+ 'Name': role_id,
+ 'Roles': [add_role_to_role.role_name_to_add],
+ },
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to add role to role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse add role to role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse add role to role response [{str(ex)}]') from ex
+
+ def remove_user_from_role(self, remove_user_from_role: ArkIdentityRemoveUserFromRole) -> None:
+ """
+ Removes a given user from the given role
+
+ Args:
+ remove_user_from_role (ArkIdentityRemoveUserFromRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Removing user [{remove_user_from_role.username}] from role [{remove_user_from_role.role_name}]')
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=remove_user_from_role.role_name))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{REMOVE_USER_FROM_ROLE_URL}', json={'Name': role_id, 'Users': [remove_user_from_role.username]}
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to remove user to role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse remove user to role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse remove user to role response [{str(ex)}]') from ex
+
+ def remove_group_from_role(self, remove_group_from_role: ArkIdentityRemoveGroupFromRole) -> None:
+ """
+ Removes a given group from the given role
+
+ Args:
+ remove_group_from_role (ArkIdentityRemoveGroupFromRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Removing group [{remove_group_from_role.group_name}] from role [{remove_group_from_role.role_name}]')
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=remove_group_from_role.role_name))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{REMOVE_USER_FROM_ROLE_URL}', json={'Name': role_id, 'Groups': [remove_group_from_role.group_name]}
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to remove group to role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse remove group to role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse remove group to role response [{str(ex)}]') from ex
+
+ def remove_role_from_role(self, remove_role_from_role: ArkIdentityRemoveRoleFromRole) -> None:
+ """
+ Removes a given role from the given role
+
+ Args:
+ remove_role_from_role (ArkIdentityRemoveRoleFromRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Removing group [{remove_role_from_role.role_name}] from role [{remove_role_from_role.role_name_to_remove}]')
+ role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=remove_role_from_role.role_name))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{REMOVE_USER_FROM_ROLE_URL}', json={'Name': role_id, 'Roles': [remove_role_from_role.role_name_to_remove]}
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to remove role to role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse remove role to role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse remove role to role response [{str(ex)}]') from ex
+
+ def delete_role(self, delete_role: ArkIdentityDeleteRole) -> None:
+ """
+ Deletes a given role by name
+
+ Args:
+ delete_role (ArkIdentityDeleteRole): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ self._logger.info(f'Deleting role [{delete_role.role_name}]')
+ if delete_role.role_name and not delete_role.role_id:
+ delete_role.role_id = self.role_id_by_name(ArkIdentityRoleIdByName(role_name=delete_role.role_name))
+ response: Response = self._client.post(f'{self._url_prefix}{DELETE_ROLE_URL}', json={'Name': delete_role.role_id})
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to delete role [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse delete role response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse delete role response [{str(ex)}]') from ex
+
+ @staticmethod
+ @overrides
+ def service_config() -> ArkServiceConfig:
+ return SERVICE_CONFIG
diff --git a/ark_sdk_python/services/identity/users/__init__.py b/ark_sdk_python/services/identity/users/__init__.py
new file mode 100644
index 00000000..f9573045
--- /dev/null
+++ b/ark_sdk_python/services/identity/users/__init__.py
@@ -0,0 +1,3 @@
+from ark_sdk_python.services.identity.users.ark_identity_users_service import ArkIdentityUsersService
+
+__all__ = ['ArkIdentityUsersService']
diff --git a/ark_sdk_python/services/identity/users/ark_identity_users_service.py b/ark_sdk_python/services/identity/users/ark_identity_users_service.py
new file mode 100644
index 00000000..5a874c18
--- /dev/null
+++ b/ark_sdk_python/services/identity/users/ark_identity_users_service.py
@@ -0,0 +1,267 @@
+from datetime import datetime, timezone
+from http import HTTPStatus
+from typing import Final
+
+from overrides import overrides
+from pydantic.error_wrappers import ValidationError
+from requests import Response
+from requests.exceptions import JSONDecodeError
+
+from ark_sdk_python.models.ark_exceptions import ArkServiceException
+from ark_sdk_python.models.services import ArkServiceConfig
+from ark_sdk_python.models.services.identity.roles import ArkIdentityAddUserToRole
+from ark_sdk_python.models.services.identity.users import (
+ ArkIdentityCreateUser,
+ ArkIdentityDeleteUser,
+ ArkIdentityResetUserPassword,
+ ArkIdentityUpdateUser,
+ ArkIdentityUser,
+ ArkIdentityUserByName,
+ ArkIdentityUserIdByName,
+ ArkIdentityUserInfo,
+)
+from ark_sdk_python.services.identity.common import ArkIdentityBaseService
+from ark_sdk_python.services.identity.directories import ArkIdentityDirectoriesService
+from ark_sdk_python.services.identity.roles import ArkIdentityRolesService
+
+SERVICE_CONFIG: Final[ArkServiceConfig] = ArkServiceConfig(
+ service_name='identity-users', required_authenticator_names=['isp'], optional_authenticator_names=[]
+)
+
+TENANT_SUFFIX_URL: Final[str] = 'Core/GetCdsAliasesForTenant'
+CREATE_USER_URL: Final[str] = 'CDirectoryService/CreateUser'
+UPDATE_USER_URL: Final[str] = 'CDirectoryService/ChangeUser'
+DELETE_USER_URL: Final[str] = 'UserMgmt/RemoveUsers'
+RESET_USER_PASSWORD_URL: Final[str] = 'UserMgmt/ResetUserPassword'
+REDROCK_QUERY: Final[str] = 'Redrock/query'
+USER_INFO_URL: Final[str] = 'OAuth2/UserInfo/__idaptive_cybr_user_oidc'
+
+
+class ArkIdentityUsersService(ArkIdentityBaseService):
+ def create_user(self, create_user: ArkIdentityCreateUser) -> ArkIdentityUser:
+ """
+ Creates a user with the given details, and returns its finalized details and id
+
+ Args:
+ create_user (ArkIdentityCreateUser): _description_
+
+ Raises:
+ ArkServiceException: _description_
+
+ Returns:
+ ArkIdentityUser: _description_
+ """
+ self._logger.info(f'Creating identity user [{create_user.username}]')
+ directories_service = ArkIdentityDirectoriesService(self._isp_auth)
+ tenant_suffix = create_user.suffix or directories_service.tenant_default_suffix()
+ response: Response = self._client.post(
+ f'{self._url_prefix}{CREATE_USER_URL}',
+ json={
+ "DisplayName": create_user.display_name,
+ "Name": f'{create_user.username}@{tenant_suffix}',
+ "Mail": create_user.email,
+ "Password": create_user.password.get_secret_value(),
+ "MobileNumber": create_user.mobile_number,
+ "InEverybodyRole": 'true',
+ "InSysAdminRole": 'false',
+ "ForcePasswordChangeNext": 'false',
+ "SendEmailInvite": 'false',
+ "SendSmsInvite": 'false',
+ },
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to create user [{response.text}]')
+ if create_user.roles:
+ roles_service = ArkIdentityRolesService(self._isp_auth)
+ for role in create_user.roles:
+ roles_service.add_user_to_role(
+ ArkIdentityAddUserToRole(username=f'{create_user.username}@{tenant_suffix}', role_name=role)
+ )
+ self._logger.info(f'User created successfully with id [{result["Result"]}]')
+ return ArkIdentityUser(
+ user_id=result['Result'],
+ username=f'{create_user.username}@{tenant_suffix}',
+ display_name=create_user.display_name,
+ email=create_user.email,
+ mobile_number=create_user.mobile_number,
+ roles=create_user.roles,
+ )
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse create user response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse create user response [{str(ex)}]') from ex
+
+ def update_user(self, update_user: ArkIdentityUpdateUser) -> None:
+ """
+ Updates the user information
+
+ Args:
+ update_user (ArkIdentityUpdateUser): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ if update_user.username and not update_user.user_id:
+ update_user.user_id = self.user_id_by_name(ArkIdentityUserIdByName(username=update_user.username))
+ self._logger.info(f'Updating identity user [{update_user.user_id}]')
+ update_dict = {}
+ if update_user.new_username:
+ if '@' not in update_user.new_username:
+ tenant_suffix = update_user.username.split('@')[1]
+ update_user.new_username = f'{update_user.new_username}@{tenant_suffix}'
+ update_dict['Name'] = update_user.new_username
+ if update_user.display_name:
+ update_dict['DisplayName'] = update_user.display_name
+ if update_user.email:
+ update_dict['Mail'] = update_user.email
+ if update_user.mobile_number:
+ update_dict['MobileNumber'] = update_user.mobile_number
+ update_dict['ID'] = update_user.user_id
+ response: Response = self._client.post(f'{self._url_prefix}{UPDATE_USER_URL}', json=update_dict)
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to update user [{response.text}]')
+ self._logger.info('User updated successfully')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse update user response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse update user response [{str(ex)}]') from ex
+
+ def delete_user(self, delete_user: ArkIdentityDeleteUser) -> None:
+ """
+ Deletes a user by given name
+
+ Args:
+ delete_user (ArkIdentityDeleteUser): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ if delete_user.username and not delete_user.user_id:
+ delete_user.user_id = self.user_id_by_name(ArkIdentityUserIdByName(username=delete_user.username))
+ self._logger.info(f'Deleting user [{delete_user.user_id}]')
+ response: Response = self._client.post(f'{self._url_prefix}{DELETE_USER_URL}', json={'Users': [delete_user.user_id]})
+ try:
+ if response.status_code != HTTPStatus.OK or not response.json()['success']:
+ raise ArkServiceException(f'Failed to delete user [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse delete user response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse delete user response [{str(ex)}]') from ex
+
+ def user_id_by_name(self, user_id_by_name: ArkIdentityUserIdByName) -> str:
+ """
+ Finds the identifier of the given username
+
+ Args:
+ user_id_by_name (ArkIdentityUserIdByName): _description_
+
+ Returns:
+ str: _description_
+ """
+ response: Response = self._client.post(
+ f'{self._url_prefix}{REDROCK_QUERY}',
+ json={"Script": f"Select ID, Username from User WHERE Username='{user_id_by_name.username}'"},
+ )
+ if response.status_code != HTTPStatus.OK:
+ raise ArkServiceException(f'Failed to retrieve user id by name [{response.text}] - [{response.status_code}]')
+ try:
+ query_result = response.json()
+ if not query_result['success'] or len(query_result['Result']["Results"]) == 0:
+ raise ArkServiceException('Failed to retrieve user id by name')
+ return query_result['Result']["Results"][0]["Row"]["ID"]
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse user id by name response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse user id by name response [{str(ex)}]') from ex
+
+ def user_by_name(self, user_id_by_name: ArkIdentityUserByName) -> ArkIdentityUser:
+ """
+ Finds the identifier of the given username
+
+ Args:
+ user_id_by_name (ArkIdentityUserIdByName): _description_
+
+ Returns:
+ str: _description_
+ """
+ response: Response = self._client.post(
+ f'{self._url_prefix}{REDROCK_QUERY}',
+ json={
+ "Script": f"Select ID, Username, DisplayName, Email, MobileNumber, LastLogin from User WHERE Username='{user_id_by_name.username}'"
+ },
+ )
+ if response.status_code != HTTPStatus.OK:
+ raise ArkServiceException(f'Failed to retrieve user id by name [{response.text}] - [{response.status_code}]')
+ try:
+ query_result = response.json()
+ if not query_result['success'] or len(query_result['Result']["Results"]) == 0:
+ raise ArkServiceException('Failed to retrieve user id by name')
+ user_row = query_result['Result']["Results"][0]["Row"]
+ last_login = None
+ if last_login := user_row.get('LastLogin'):
+ try:
+ last_login = last_login.split('(')[1].split(')')[0]
+ last_login = f'{last_login[:10]}.{last_login[10:]}' # for milliseconds
+ last_login = datetime.fromtimestamp(float(last_login), timezone.utc)
+ except Exception as ex:
+ self._logger.debug(f'Failed to parse last login [{user_row.get("LastLogin")}] [{str(ex)}]')
+
+ return ArkIdentityUser(
+ user_id=user_row["ID"],
+ username=user_row["Username"],
+ display_name=user_row["DisplayName"],
+ email=user_row["Email"],
+ mobile_number=user_row["MobileNumber"],
+ last_login=last_login,
+ )
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse user id by name response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse user id by name response [{str(ex)}]') from ex
+
+ def reset_user_password(self, reset_user_password: ArkIdentityResetUserPassword) -> None:
+ """
+ Resets a given username's password to the new given one
+ Assumes the logged in user has permissions to do so
+
+ Args:
+ reset_user_password (ArkIdentityResetUserPassword): _description_
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ user_id = self.user_id_by_name(ArkIdentityUserIdByName(username=reset_user_password.username))
+ response: Response = self._client.post(
+ f'{self._url_prefix}{RESET_USER_PASSWORD_URL}', json={'ID': user_id, 'newPassword': reset_user_password.new_password}
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK or not result['success']:
+ raise ArkServiceException(f'Failed to reset user password [{response.text}]')
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to parse reset user password response [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to parse reset user password response [{str(ex)}]') from ex
+
+ def user_info(self) -> ArkIdentityUserInfo:
+ """
+ Retrieves the current user info
+
+ Raises:
+ ArkServiceException: _description_
+ """
+ response: Response = self._client.post(
+ f'{self._url_prefix}{USER_INFO_URL}',
+ json={'Scopes': ['userInfo']},
+ )
+ try:
+ result = response.json()
+ if response.status_code != HTTPStatus.OK:
+ raise ArkServiceException(f'Failed to get user info [{response.text}]')
+ return ArkIdentityUserInfo.parse_obj(result)
+ except (ValidationError, JSONDecodeError, KeyError) as ex:
+ self._logger.exception(f'Failed to get user info [{str(ex)}] - [{response.text}]')
+ raise ArkServiceException(f'Failed to get user info [{str(ex)}]') from ex
+
+ @staticmethod
+ @overrides
+ def service_config() -> ArkServiceConfig:
+ return SERVICE_CONFIG
diff --git a/docs/commands/exec.md b/docs/commands/exec.md
index ddb5df6b..f9b0e213 100644
--- a/docs/commands/exec.md
+++ b/docs/commands/exec.md
@@ -11,7 +11,7 @@ You use the `exec` command is used to run commands on available services (the av
The following DPA commands are supported:
-- `ark exec dpa`: Root command for the DBA service
+- `ark exec dpa`: Root command for the DPA service
- `policies` - Policy management
- `db` - DB policies
- `editor` - DB policies interactive editor
@@ -25,6 +25,12 @@ The following DPA commands are supported:
- `workspaces` - Workspaces management
- `db` - DB workspace management
- `k8s` - Kubernetes service
+- `ark exec sm`: Root command for Session Monitoring service
+- `ark exec identity`: Root command for Identity service
+ - `roles` - Roles management
+ - `users` - Users management
+ - `policies` - Policies management
+ - `directories` - Directories reading
All commands have their own subcommands and respective arguments.
@@ -38,10 +44,10 @@ ark exec
usage: ark exec [-h] [-r] [-s] [-ao] [-v] [-ls {default}] [-ll {DEBUG,INFO,WARN,ERROR,CRITICAL}]
[-dcv] [-tc TRUSTED_CERT] [-pn PROFILE_NAME] [-op OUTPUT_PATH] [-rf REQUEST_FILE]
[-rc RETRY_COUNT] [-ra]
- {dpa} ...
+ {identity,dpa,sm} ...
positional arguments:
- {dpa}
+ {identity,dpa,sm}
optional arguments:
-h, --help show this help message and exit
diff --git a/docs/examples/commands_examples.md b/docs/examples/commands_examples.md
index bc45faa4..e4eff3f6 100644
--- a/docs/examples/commands_examples.md
+++ b/docs/examples/commands_examples.md
@@ -164,3 +164,43 @@ ark exec sm count-session-activities-by --session-id 5e62bdb8-cd81-42b8-ac72-1e0
```shell
ark exec sm sessions-stats
```
+
+### List all identity entities, including roles users and groups
+```shell
+ark exec identity directories list-directories-entities
+```
+
+### List only identity roles
+```shell
+ark exec identity directories list-directories-entities --entity-types ROLE
+```
+
+### Create a role with DPA show tile admin right
+```shell
+ark exec identity roles create-role --role-name RoleName --admin-rights "ServiceRight/dpaShowTile"
+```
+
+### Delete a role by name
+```shell
+ark exec identity roles delete-role --role-name RoleName
+```
+
+### Create a new user
+```shell
+ark exec identity users create-user --username myname --email email@email.com --password MyPassword
+```
+
+### Delete a user by name
+```shell
+ark exec identity users delete-user --username myname
+```
+
+### Add an authentication profile
+```shell
+ark exec identity policies add-authentication-profile --auth-profile-name myprofile --first-challenges UP --second-challenges EMAIL
+```
+
+### Add a policy
+```shell
+ark exec identity policies add-policy --policy-name mypolicy --role-names RoleName --auth-profile-name myprofile
+```
diff --git a/docs/examples/sdk_examples.md b/docs/examples/sdk_examples.md
index e8a05c77..bc230d5d 100644
--- a/docs/examples/sdk_examples.md
+++ b/docs/examples/sdk_examples.md
@@ -102,77 +102,126 @@ if __name__ == '__main__':
## Authenticate and provision DPA VM policies
```python
+isp_auth = ArkISPAuth()
+isp_auth.authenticate(
+ auth_profile=ArkAuthProfile(
+ username=username, auth_method=ArkAuthMethod.Identity, auth_method_settings=IdentityArkAuthMethodSettings()
+ ),
+ secret=ArkSecret(secret='CoolPassword'),
+)
+print('Adding DPA Policy')
+dpa_service.policies.add_policy(
+ ArkDPAVMAddPolicy(
+ policy_name='IT Policy',
+ description='IT Policy',
+ status=ArkDPARuleStatus.Enabled,
+ providers_data={
+ ArkWorkspaceType.AWS: ArkDPAVMAWSProviderData(
+ account_ids=['965428623928'], tags=[{'key': 'team', 'value': 'IT'}], regions=[], vpc_ids=[]
+ )
+ },
+ user_access_rules=[
+ ArkDPAVMAuthorizationRule(
+ rule_name='IT Rule',
+ user_data=ArkDPAUserData(roles=['IT']),
+ connection_information=ArkDPAVMConnectionInformation(
+ full_days=True,
+ days_of_week=[],
+ time_zone='Asia/Jerusalem',
+ connect_as={
+ ArkWorkspaceType.AWS: {
+ ArkProtocolType.SSH: 'root',
+ ArkProtocolType.RDP: ArkDPAVMRDPLocalEphemeralUserConnectionData(
+ local_ephemeral_user=ArkDPAVMLocalEphemeralUserConnectionMethodData(assign_groups={'Administrators'})
+ ),
+ }
+ },
+ ),
+ )
+ ],
+ )
+)
+```
+
+## View Session Monitoring Sessions And Activities Per Session
+
+```python
+from ark_sdk_python.services.sm import ArkSMService
+from ark_sdk_python.models.services.sm import ArkSMSessionsFilter, ArkSMGetSession, ArkSMGetSessionActivities
+from ark_sdk_python.models.ark_profile import ArkProfileLoader
+from ark_sdk_python.models.common import ArkProtocolType
+from ark_sdk_python.auth import ArkISPAuth
+from datetime import datetime, timedelta
+
+if __name__ == "__main__":
isp_auth = ArkISPAuth()
isp_auth.authenticate(
- auth_profile=ArkAuthProfile(
- username=username, auth_method=ArkAuthMethod.Identity, auth_method_settings=IdentityArkAuthMethodSettings()
- ),
- secret=ArkSecret(secret='CoolPassword'),
+ profile=ArkProfileLoader().load_default_profile()
)
- print('Adding DPA Policy')
- dpa_service.policies.add_policy(
- ArkDPAVMAddPolicy(
- policy_name='IT Policy',
- description='IT Policy',
- status=ArkDPARuleStatus.Enabled,
- providers_data={
- ArkWorkspaceType.AWS: ArkDPAVMAWSProviderData(
- account_ids=['965428623928'], tags=[{'key': 'team', 'value': 'IT'}], regions=[], vpc_ids=[]
- )
- },
- user_access_rules=[
- ArkDPAVMAuthorizationRule(
- rule_name='IT Rule',
- user_data=ArkDPAUserData(roles=['IT']),
- connection_information=ArkDPAVMConnectionInformation(
- full_days=True,
- days_of_week=[],
- time_zone='Asia/Jerusalem',
- connect_as={
- ArkWorkspaceType.AWS: {
- ArkProtocolType.SSH: 'root',
- ArkProtocolType.RDP: ArkDPAVMRDPLocalEphemeralUserConnectionData(
- local_ephemeral_user=ArkDPAVMLocalEphemeralUserConnectionMethodData(assign_groups={'Administrators'})
- ),
- }
- },
- ),
- )
- ],
- )
+ sm: ArkSMService = ArkSMService(isp_auth)
+ search_by = 'startTime ge {start_time_from} AND sessionDuration GE {min_duration} AND protocol IN {protocols}'
+ search_by = search_by.format(
+ start_time_from=(datetime.utcnow() - timedelta(days=30)).isoformat(timespec='seconds'),
+ min_duration='00:00:01',
+ protocols=','.join([ArkProtocolType.DB[0], ArkProtocolType.SSH[0], ArkProtocolType.RDP[0]]),
+ )
+ sessions_filter = ArkSMSessionsFilter(
+ search=search_by,
)
+ print(f'session_count = {sm.count_sessions_by(sessions_filter)}')
+ for s_page in sm.list_sessions_by(sessions_filter):
+ for session in s_page.items:
+ session = sm.session(ArkSMGetSession(session_id=session.session_id))
+ get_session_activities = ArkSMGetSessionActivities(session_id=session.session_id)
+ print(f'session = {session}, activities_count = {sm.count_session_activities(get_session_activities)}')
+ session_activities = [activity for page in sm.list_session_activities(get_session_activities) for activity in page.items]
+ print(session_activities)
```
-## View Session Monitoring Sessions And Activities Per Session
+## Get current tenant default suffix
```python
- from ark_sdk_python.services.sm import ArkSMService
- from ark_sdk_python.models.services.sm import ArkSMSessionsFilter, ArkSMGetSession, ArkSMGetSessionActivities
- from ark_sdk_python.models.ark_profile import ArkProfileLoader
- from ark_sdk_python.models.common import ArkProtocolType
- from ark_sdk_python.auth import ArkISPAuth
- from datetime import datetime, timedelta
- if __name__ == "__main__":
- isp_auth = ArkISPAuth()
- isp_auth.authenticate(
- profile=ArkProfileLoader().load_default_profile()
- )
- sm: ArkSMService = ArkSMService(isp_auth)
- search_by = 'startTime ge {start_time_from} AND sessionDuration GE {min_duration} AND protocol IN {protocols}'
- search_by = search_by.format(
- start_time_from=(datetime.utcnow() - timedelta(days=30)).isoformat(timespec='seconds'),
- min_duration='00:00:01',
- protocols=','.join([ArkProtocolType.DB[0], ArkProtocolType.SSH[0], ArkProtocolType.RDP[0]]),
- )
- sessions_filter = ArkSMSessionsFilter(
- search=search_by,
- )
- print(f'session_count = {sm.count_sessions_by(sessions_filter)}')
- for s_page in sm.list_sessions_by(sessions_filter):
- for session in s_page.items:
- session = sm.session(ArkSMGetSession(session_id=session.session_id))
- get_session_activities = ArkSMGetSessionActivities(session_id=session.session_id)
- print(f'session = {session}, activities_count = {sm.count_session_activities(get_session_activities)}')
- session_activities = [activity for page in sm.list_session_activities(get_session_activities) for activity in page.items]
- print(session_activities)
+from ark_sdk_python.auth import ArkISPAuth
+from ark_sdk_python.models.ark_profile import ArkProfileLoader
+from ark_sdk_python.models.services.identity.directories import ArkIdentityListDirectoriesEntities
+from ark_sdk_python.services.identity import ArkIdentityAPI
+
+if __name__ == "__main__":
+ isp_auth = ArkISPAuth()
+ isp_auth.authenticate(ArkProfileLoader().load_default_profile())
+ identity_api = ArkIdentityAPI(isp_auth)
+ print(identity_api.identity_directories.tenant_default_suffix())
+ for page in identity_api.identity_directories.list_directories_entities(ArkIdentityListDirectoriesEntities()):
+ print([i.name for i in page.items])
+```
+
+
+## Add identity role and user
+
+```python
+from ark_sdk_python.models.auth import (
+ ArkAuthMethod,
+ ArkAuthProfile,
+ ArkSecret,
+ IdentityArkAuthMethodSettings,
+)
+from ark_sdk_python.auth import ArkISPAuth
+from ark_sdk_python.services.identity import ArkIdentityAPI
+from ark_sdk_python.models.services.identity.roles import ArkIdentityCreateRole
+from ark_sdk_python.models.services.identity.users import ArkIdentityCreateUser
+
+if __name__ == "__main__":
+ isp_auth = ArkISPAuth()
+ isp_auth.authenticate(
+ auth_profile=ArkAuthProfile(
+ username='CoolUser', auth_method=ArkAuthMethod.Identity, auth_method_settings=IdentityArkAuthMethodSettings()
+ ),
+ secret=ArkSecret(secret='CoolPassword'),
+ )
+
+ # Create an identity service to create some users and roles
+ print('Creating identity roles and users')
+ identity_api = ArkIdentityAPI(isp_auth)
+ identity_api.identity_roles.create_role(ArkIdentityCreateRole(role_name='IT'))
+ identity_api.identity_users.create_user(ArkIdentityCreateUser(username='it_user', password='CoolPassword', roles=['IT']))
```
diff --git a/pyproject.toml b/pyproject.toml
index 9e73d909..054e2b00 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ark-sdk-python"
-version = "1.0.7"
+version = "1.1.0"
description='Official Ark SDK / CLI for CyberArk Identity Security Platform'
authors = ["CyberArk ", "Ofir Iluz