Skip to content

Commit

Permalink
API key generation mechanism added
Browse files Browse the repository at this point in the history
  • Loading branch information
adityasinght committed Oct 20, 2024
1 parent 3b2afdd commit 94d2d18
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 74 deletions.
1 change: 0 additions & 1 deletion paig-server/backend/paig/alembic_db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ def get_bind(self, mapper=None, clause=None, **kwargs):
name=ai_application.get("name"),
description=ai_application.get("description"),
application_key=generate_unique_identifier_key(),
application_api_key=generate_unique_identifier_key(),
vector_dbs=''
)
session.add(default_app)
Expand Down
1 change: 1 addition & 0 deletions paig-server/backend/paig/alembic_db/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from api.governance.database.db_models import ai_app_config_model
from api.governance.database.db_models import metadata_key_model, metadata_value_model
from api.governance.database.db_models import tag_model
from api.governance.database.db_models import ai_app_apikey_model
from api.user.database.db_models import user_model, groups_model
from api.audit.RDS_service.db_models import access_audit_model
from api.encryption.database.db_models import encryption_master_key_model, encryption_key_model
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from typing import List

from api.user.utils.acc_service_validation_util import AccServiceValidationUtil
from core.controllers.paginated_response import Pageable
from core.db_session import Transactional, Propagation
from api.governance.api_schemas.ai_app_policy import AIApplicationPolicyView, AIApplicationPolicyFilter
from api.governance.services.ai_app_policy_service import AIAppPolicyService
from api.governance.utils.gov_service_validation_util import GovServiceValidationUtil
from core.utils import SingletonDepends


class AIAppAPIKeyController:
"""
Controller class specifically for handling AI application policies.
Args:
ai_app_policy_service (AIAppPolicyService): The service class for AI application policies.
"""

def __init__(self,
ai_app_policy_service: AIAppPolicyService = SingletonDepends(AIAppPolicyService),
gov_service_validation_util: GovServiceValidationUtil = SingletonDepends(GovServiceValidationUtil),
acc_service_validation_util: AccServiceValidationUtil = SingletonDepends(AccServiceValidationUtil)):
self.ai_app_policy_service = ai_app_policy_service
self.gov_service_validation_util = gov_service_validation_util
self.acc_service_validation_util = acc_service_validation_util


def generate_api_key(self):
pass
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,23 @@ def __init__(self,
self.ai_app_service = ai_app_service
self.encryption_key_service = encryption_key_service

async def get_ai_app_config_json_data(self, id: int = None, application_api_key=None) -> Tuple[str, dict]:
async def get_ai_app_config_json_data(self, id: int = None) -> Tuple[str, dict]:
"""
Get the configuration of an AI application in JSON format.
Args:
id (int): The ID of the AI application.
application_api_key (str, optional): The API key of the AI application.
Returns:
Tuple[str, dict]: A tuple containing the name of the AI application and its configuration in JSON format.
"""
if application_api_key:
ai_application = await self.ai_app_service.get_ai_application_by_application_api_key(application_api_key)
else:
ai_application = await self.ai_app_service.get_ai_application_by_id(id)
ai_application = await self.ai_app_service.get_ai_application_by_id(id)
shield_server_key: EncryptionKeyView = await self.encryption_key_service.get_active_encryption_key_by_type(EncryptionKeyType.MSG_PROTECT_SHIELD)
shield_plugin_key: EncryptionKeyView = await self.encryption_key_service.get_active_encryption_key_by_type(EncryptionKeyType.MSG_PROTECT_PLUGIN)
shield_server_url = await self.ai_app_service.get_shield_server_url()
# Simulating retrieval of data from a database or other source
return ai_application.name, {
"applicationId": ai_application.id,
"applicationKey": ai_application.application_key,
"applicationAPIKey": ai_application.application_api_key,
"tenantId": DEFAULT_TENANT_ID,
"apiServerUrl": "",
"apiKey": "none",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from api.governance.services.ai_app_config_service import AIAppConfigService
from api.governance.services.ai_app_policy_service import AIAppPolicyService
from api.governance.services.ai_app_service import AIAppService
from api.governance.services.ai_app_apikey_service import AIAppAPIKeyService
from core.utils import format_to_root_path, SingletonDepends


Expand All @@ -23,10 +24,13 @@ class AIAppController:
def __init__(self,
ai_app_service: AIAppService = SingletonDepends(AIAppService),
ai_app_policy_service: AIAppPolicyService = SingletonDepends(AIAppPolicyService),
ai_app_config_service: AIAppConfigService = SingletonDepends(AIAppConfigService)):
ai_app_config_service: AIAppConfigService = SingletonDepends(AIAppConfigService),
ai_app_apikey_service: AIAppAPIKeyService = SingletonDepends(AIAppAPIKeyService)
):
self.ai_app_service = ai_app_service
self.ai_app_policy_service = ai_app_policy_service
self.ai_app_config_service = ai_app_config_service
self.ai_app_apikey_service = ai_app_apikey_service

ai_app_defaults_file_path = format_to_root_path("api/governance/configs/ai_application_defaults.json")
application_defaults = self.get_application_defaults(ai_app_defaults_file_path)
Expand Down Expand Up @@ -76,6 +80,9 @@ async def create_ai_application(self, request: AIApplicationView) -> AIApplicati
"""
created_app = await self.ai_app_service.create_ai_application(request)

# Create master encryption key per application
self.ai_app_apikey_service.create_app_encryption_key(created_app.id)

app_config_create_model = AIApplicationConfigView(**self.ai_app_default_config.model_dump())
await self.ai_app_config_service.update_ai_app_config(created_app.id, app_config_create_model)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime
from sqlalchemy.orm import relationship

from core.db_models.BaseSQLModel import BaseSQLModel


class AIApplicationEncryptionKeyModel(BaseSQLModel):
"""
SQLAlchemy model representing AI application encryption keys.
Attributes:
__tablename__ (str): Name of the database table.
key (str): Encryption key
application_id (int): The application ID.
"""

__tablename__ = "ai_application_encryption_key"

key = Column(String(255), nullable=False)
application_id = Column(Integer, ForeignKey('ai_application.id', ondelete='CASCADE', name='fk_ai_application_policy_application_id'), nullable=False)
ai_app = relationship("AIApplicationModel", back_populates="app_encryption_keys")


class AIApplicationAPIKeyModel(BaseSQLModel):
"""
SQLAlchemy model representing AI application API keys.
scope: 1 - All access, 0 - No access
api_key: API key
expiry_time: Expiry time of the API key
application_id: The AI application ID.
"""
__tablename__ = "ai_application_api_key"
scope = Column(Integer, nullable=False, default=1)
api_key = Column(String(255), nullable=False)
expiry_time = Column(DateTime, index=True, nullable=True)
application_id = Column(Integer, ForeignKey('ai_application.id', ondelete='CASCADE', name='fk_ai_application_policy_application_id'), nullable=False)

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class AIApplicationModel(BaseSQLModel):
name = Column(String(255), nullable=False)
description = Column(String(4000), nullable=True)
application_key = Column(String(255), nullable=False)
application_api_key = Column(String(255), nullable=True)
vector_dbs = Column(CommaSeparatedList(255), nullable=True)

app_config = relationship("AIApplicationConfigModel", back_populates="ai_app", uselist=False, cascade="all, delete-orphan")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import os

from core.factory.database_initiator import BaseOperations
from api.governance.database.db_models.ai_app_apikey_model import AIApplicationEncryptionKeyModel, AIApplicationAPIKeyModel


class AIAppEncryptionKeyRepository(BaseOperations[AIApplicationEncryptionKeyModel]):
"""
Repository class for handling database operations related to AI application encryption key models.
Inherits from BaseOperations[AIAppEncryptionKeyRepository], providing generic CRUD operations.
This class inherits all methods from BaseOperations[AIAppEncryptionKeyRepository].
"""

def __init__(self):
"""
Initialize the AIAppEncryptionKeyRepository.
Args:
db_session (Session): The database session to use for operations.
"""
super().__init__(AIApplicationEncryptionKeyModel)

def create_encryption_key(self, app_id):
key = os.urandom(32)
self.create_record(AIApplicationEncryptionKeyModel(application_id=app_id, key=key))

class AIAppAPIKeyRepository(BaseOperations[AIApplicationAPIKeyModel]):
"""
Repository class for handling database operations related to AI application api key models.
Inherits from BaseOperations[AIApplicationAPIKeyModel], providing generic CRUD operations.
This class inherits all methods from BaseOperations[AIApplicationAPIKeyModel].
"""

def __init__(self):
"""
Initialize the AIAppRepository.
Args:
db_session (Session): The database session to use for operations.
"""
super().__init__(AIApplicationAPIKeyModel)
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,3 @@ async def get_ai_application_by_application_key(self, application_key: str) -> A
return await self.get_by(filters={"application_key": application_key}, unique=True)
except NoResultFound as e:
raise NotFoundException(get_error_message(ERROR_RESOURCE_NOT_FOUND, "AI Application", "applicationKey", application_key))

async def get_ai_application_by_application_api_key(self, application_api_key: str) -> AIApplicationModel:
"""
Retrieve an AI application by its application API key.
Args:
application_api_key (str): The application API key to search for.
Returns:
AIApplicationModel: The AI application with the specified application API key.
Raises:
NoResultFound: If no AI application with the specified application API key is found.
"""
try:
return await self.get_by(filters={"application_api_key": application_api_key}, unique=True)
except NoResultFound as e:
raise NotFoundException(get_error_message(ERROR_RESOURCE_NOT_FOUND, "AI Application", "applicationApiKey", application_api_key))
2 changes: 2 additions & 0 deletions paig-server/backend/paig/api/governance/routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
from api.governance.routes.ai_app_router import ai_app_router
from api.governance.routes.vector_db_policy_router import vector_db_policy_router
from api.governance.routes.vector_db_router import vector_db_router
from api.governance.routes.ai_app_apikey_router import ai_app_apikey_router

governance_router = APIRouter(dependencies=[Depends(get_auth_user)])
governance_router.include_router(ai_app_router, prefix="/ai/application", tags=["AI Application Management"])
governance_router.include_router(ai_app_config_router, prefix="/ai/application/{id}", tags=["AI Application Config Management"])
governance_router.include_router(ai_app_config_download_router, prefix="/ai/application/{id}", tags=["AI Application Config Downloader"])
governance_router.include_router(ai_app_policy_router, prefix="/ai/application/{app_id}/policy", tags=["AI Application Policy Management"])
governance_router.include_router(ai_app_apikey_router, prefix="/ai/application/{app_id}/apikey", tags=["AI Application API Key Management"])
governance_router.include_router(vector_db_router, prefix="/ai/vectordb", tags=["AI Vector DB Management"])
governance_router.include_router(vector_db_policy_router, prefix="/ai/vectordb/{vector_db_id}/policy", tags=["AI Vector DB Policy Management"])
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from fastapi import APIRouter, Depends

from api.governance.controllers.ai_app_apikey_controller import AIAPPAPIKeyController
from core.utils import SingletonDepends

ai_app_apikey_router = APIRouter()

ai_app_apikey_controller_instance = Depends(SingletonDepends(AIAPPAPIKeyController, called_inside_fastapi_depends=True))


@ai_app_apikey_router.post("generate")
async def generate_api_key(
app_id: int,
ai_app_apikey_controller: AIAPPAPIKeyController = ai_app_apikey_controller_instance
):
"""
Generated Application API Key
"""
return await ai_app_apikey_controller.generate_api_key(app_id)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from api.governance.database.db_operations.ai_app_apikey_repository import AIAppAPIKeyRepository, \
AIAppEncryptionKeyRepository
from core.utils import SingletonDepends


class AIAppAPIKeyService:

def __init__(self, ai_app_apikey_repository: AIAppAPIKeyRepository = SingletonDepends(AIAppAPIKeyRepository),
ai_app_encryptionkey_repository: AIAppEncryptionKeyRepository = SingletonDepends(
AIAppEncryptionKeyRepository)
):
self.ai_app_apikey_repository = ai_app_apikey_repository
self.ai_app_encryptionkey_repository = ai_app_encryptionkey_repository

def create_app_encryption_key(self, app_id):
return self.ai_app_encryptionkey_repository.create_encryption_key(app_id)
14 changes: 0 additions & 14 deletions paig-server/backend/paig/api/governance/services/ai_app_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,6 @@ async def create_ai_application(self, request: AIApplicationView) -> AIApplicati
"""
await self.ai_app_request_validator.validate_create_request(request)
request.application_key = generate_unique_identifier_key()
request.application_api_key = generate_unique_identifier_key()
return await self.create_record(request)

async def get_ai_application_by_id(self, id: int) -> AIApplicationView:
Expand Down Expand Up @@ -287,19 +286,6 @@ async def get_ai_application_by_application_key(self, application_key: str) -> A
repository = self.get_repository()
return await repository.get_ai_application_by_application_key(application_key)

async def get_ai_application_by_application_api_key(self, application_api_key: str) -> AIApplicationView:
"""
Retrieve an AI application by its application key.
Args:
application_api_key (str): The application api key of the AI application to retrieve.
Returns:
AIApplicationView: The AI application view object corresponding to the application key.
"""
repository = self.get_repository()
return await repository.get_ai_application_by_application_api_key(application_api_key)

async def update_ai_application(self, id: int, request: AIApplicationView) -> AIApplicationView:
"""
Update an AI application identified by its ID.
Expand Down

0 comments on commit 94d2d18

Please sign in to comment.