Internal api key gql #181
This commit is contained in:
@@ -1,20 +1,21 @@
|
|||||||
|
import socket
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Self
|
from typing import Self
|
||||||
|
|
||||||
from cpl.api.application import WebApp
|
from cpl.api.application import WebApp
|
||||||
from cpl.api.model.validation_match import ValidationMatch
|
from cpl.api.model.validation_match import ValidationMatch
|
||||||
|
from cpl.auth.schema import UserDao
|
||||||
|
from cpl.core.configuration import Configuration
|
||||||
|
from cpl.core.environment import Environment
|
||||||
from cpl.dependency.service_provider import ServiceProvider
|
from cpl.dependency.service_provider import ServiceProvider
|
||||||
from cpl.dependency.typing import Modules
|
from cpl.dependency.typing import Modules
|
||||||
from queries.user import UserGraphType, UserFilter, UserSort
|
from queries.user import UserGraphType, UserFilter, UserSort
|
||||||
from .._endpoints.graphiql import graphiql_endpoint
|
from cpl.graphql._endpoints.graphiql import graphiql_endpoint
|
||||||
from .._endpoints.graphql import graphql_endpoint
|
from cpl.graphql._endpoints.graphql import graphql_endpoint
|
||||||
from .._endpoints.playground import playground_endpoint
|
from cpl.graphql._endpoints.playground import playground_endpoint
|
||||||
from ..auth.administration.user.user_mutation import UserMutation
|
from cpl.graphql.auth.administration.user.user_mutation import UserMutation
|
||||||
from ..graphql_module import GraphQLModule
|
from cpl.graphql.graphql_module import GraphQLModule
|
||||||
from ..service.schema import Schema
|
from cpl.graphql.service.schema import Schema
|
||||||
from ...application.abc.application_abc import __not_implemented__
|
|
||||||
from ...auth.schema import UserDao
|
|
||||||
from ...core.configuration import Configuration
|
|
||||||
|
|
||||||
|
|
||||||
class GraphQLApp(WebApp):
|
class GraphQLApp(WebApp):
|
||||||
@@ -104,8 +105,14 @@ class GraphQLApp(WebApp):
|
|||||||
schema.mutation.with_mutation("user", UserMutation).with_public(public)
|
schema.mutation.with_mutation("user", UserMutation).with_public(public)
|
||||||
|
|
||||||
async def _log_before_startup(self):
|
async def _log_before_startup(self):
|
||||||
self._logger.info(f"Start API on {self._api_settings.host}:{self._api_settings.port}")
|
host = self._api_settings.host
|
||||||
|
if host == "0.0.0.0" and Environment.get_environment() == "development":
|
||||||
|
host = "localhost"
|
||||||
|
elif host == "0.0.0.0":
|
||||||
|
host = socket.gethostbyname(socket.gethostname())
|
||||||
|
|
||||||
|
self._logger.info(f"Start API on {host}:{self._api_settings.port}")
|
||||||
if self._with_graphiql:
|
if self._with_graphiql:
|
||||||
self._logger.warning(f"GraphiQL available at http://{self._api_settings.host}:{self._api_settings.port}/api/graphiql")
|
self._logger.warning(f"GraphiQL available at http://{host}:{self._api_settings.port}/api/graphiql")
|
||||||
if self._with_playground:
|
if self._with_playground:
|
||||||
self._logger.warning(f"GraphQL Playground available at http://{self._api_settings.host}:{self._api_settings.port}/api/playground")
|
self._logger.warning(f"GraphQL Playground available at http://{host}:{self._api_settings.port}/api/playground")
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
from cpl.auth.schema import ApiKey
|
||||||
|
from cpl.graphql.schema.filter.db_model_filter import DbModelFilter
|
||||||
|
from cpl.graphql.schema.filter.string_filter import StringFilter
|
||||||
|
|
||||||
|
|
||||||
|
class ApiKeyFilter(DbModelFilter[ApiKey]):
|
||||||
|
def __init__(self, public: bool = False):
|
||||||
|
DbModelFilter.__init__(self, public)
|
||||||
|
|
||||||
|
self.field("identifier", StringFilter).with_public(public)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from cpl.auth.schema import ApiKey, RolePermissionDao
|
||||||
|
from cpl.graphql.schema.db_model_graph_type import DbModelGraphType
|
||||||
|
|
||||||
|
|
||||||
|
class ApiKeyGraphType(DbModelGraphType):
|
||||||
|
|
||||||
|
def __init__(self, role_permission_dao: RolePermissionDao):
|
||||||
|
DbModelGraphType.__init__(self)
|
||||||
|
|
||||||
|
self.string_field(ApiKey.identifier, lambda root: root.identifier)
|
||||||
|
self.string_field(ApiKey.key, lambda root: root.key)
|
||||||
|
self.string_field(ApiKey.permissions, lambda root: root.permissions)
|
||||||
|
|
||||||
|
self.set_history_reference_dao(role_permission_dao, "apikeyid")
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from cpl.auth.schema import ApiKey
|
||||||
|
from cpl.core.typing import SerialId
|
||||||
|
from cpl.graphql.schema.input import Input
|
||||||
|
|
||||||
|
|
||||||
|
class ApiKeyCreateInput(Input[ApiKey]):
|
||||||
|
identifier: str
|
||||||
|
permissions: list[SerialId]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Input.__init__(self)
|
||||||
|
self.string_field("identifier").with_required()
|
||||||
|
self.list_field("permissions", SerialId)
|
||||||
|
|
||||||
|
|
||||||
|
class ApiKeyUpdateInput(Input[ApiKey]):
|
||||||
|
id: SerialId
|
||||||
|
identifier: str | None
|
||||||
|
permissions: list[SerialId] | None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Input.__init__(self)
|
||||||
|
self.int_field("id").with_required()
|
||||||
|
self.string_field("identifier").with_required()
|
||||||
|
self.list_field("permissions", SerialId)
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
from cpl.api import APILogger
|
||||||
|
from cpl.auth.keycloak import KeycloakAdmin
|
||||||
|
from cpl.auth.permission import Permissions
|
||||||
|
from cpl.auth.schema import ApiKey, ApiKeyDao, ApiKeyPermissionDao, ApiKeyPermission
|
||||||
|
from cpl.graphql.auth.administration.api_key.api_key_input import ApiKeyUpdateInput, ApiKeyCreateInput
|
||||||
|
from cpl.graphql.schema.mutation import Mutation
|
||||||
|
|
||||||
|
|
||||||
|
class ApiKeyMutation(Mutation):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
|
||||||
|
logger: APILogger,
|
||||||
|
api_key_dao: ApiKeyDao,
|
||||||
|
api_key_permission_dao: ApiKeyPermissionDao,
|
||||||
|
permission_dao: ApiKeyPermissionDao,
|
||||||
|
keycloak_admin: KeycloakAdmin,
|
||||||
|
):
|
||||||
|
Mutation.__init__(self)
|
||||||
|
self._logger = logger
|
||||||
|
self._api_key_dao = api_key_dao
|
||||||
|
self._api_key_permission_dao = api_key_permission_dao
|
||||||
|
self._permission_dao = permission_dao
|
||||||
|
self._keycloak_admin = keycloak_admin
|
||||||
|
|
||||||
|
self.int_field(
|
||||||
|
"create",
|
||||||
|
self.resolve_create,
|
||||||
|
).with_require_any_permission(Permissions.users_create).with_argument(
|
||||||
|
"input",
|
||||||
|
ApiKeyCreateInput,
|
||||||
|
).with_required()
|
||||||
|
|
||||||
|
self.bool_field(
|
||||||
|
"update",
|
||||||
|
self.resolve_update,
|
||||||
|
).with_require_any_permission(Permissions.users_update).with_argument(
|
||||||
|
"input",
|
||||||
|
ApiKeyUpdateInput,
|
||||||
|
).with_required()
|
||||||
|
|
||||||
|
self.bool_field(
|
||||||
|
"delete",
|
||||||
|
self.resolve_delete,
|
||||||
|
).with_require_any_permission(Permissions.users_delete).with_argument(
|
||||||
|
"id",
|
||||||
|
int,
|
||||||
|
).with_required()
|
||||||
|
|
||||||
|
self.bool_field(
|
||||||
|
"restore",
|
||||||
|
self.resolve_restore,
|
||||||
|
).with_require_any_permission(Permissions.users_delete).with_argument(
|
||||||
|
"id",
|
||||||
|
int,
|
||||||
|
).with_required()
|
||||||
|
|
||||||
|
async def resolve_create(self, obj: ApiKeyCreateInput):
|
||||||
|
self._logger.debug(f"create api key: {obj.__dict__}")
|
||||||
|
|
||||||
|
api_key = ApiKey.new(obj.identifier)
|
||||||
|
await self._api_key_dao.create(api_key)
|
||||||
|
api_key = await self._api_key_dao.get_single_by([{ApiKey.identifier: obj.identifier}])
|
||||||
|
await self._api_key_permission_dao.create_many(
|
||||||
|
[ApiKeyPermission(0, api_key.id, x) for x in obj.permissions]
|
||||||
|
)
|
||||||
|
return api_key
|
||||||
|
|
||||||
|
async def resolve_update(self, input: ApiKeyUpdateInput):
|
||||||
|
self._logger.debug(f"update api key: {input}")
|
||||||
|
api_key = await self._api_key_dao.get_by_id(input.id)
|
||||||
|
|
||||||
|
await self._resolve_assignments(
|
||||||
|
input.permissions or [],
|
||||||
|
api_key,
|
||||||
|
ApiKeyPermission.api_key_id,
|
||||||
|
ApiKeyPermission.permission_id,
|
||||||
|
self._api_key_dao,
|
||||||
|
self._api_key_permission_dao,
|
||||||
|
ApiKeyPermission,
|
||||||
|
self._permission_dao,
|
||||||
|
)
|
||||||
|
|
||||||
|
return api_key
|
||||||
|
|
||||||
|
async def resolve_delete(self, id: str):
|
||||||
|
self._logger.debug(f"delete api key: {id}")
|
||||||
|
api_key = await self._api_key_dao.get_by_id(id)
|
||||||
|
await self._api_key_dao.delete(api_key)
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def resolve_restore(self, id: str):
|
||||||
|
self._logger.debug(f"restore api key: {id}")
|
||||||
|
api_key = await self._api_key_dao.get_by_id(id)
|
||||||
|
await self._api_key_dao.restore(api_key)
|
||||||
|
return True
|
||||||
@@ -5,7 +5,7 @@ from cpl.graphql.schema.input import Input
|
|||||||
|
|
||||||
class UserCreateInput(Input[User]):
|
class UserCreateInput(Input[User]):
|
||||||
keycloak_id: str
|
keycloak_id: str
|
||||||
roles: list[SerialId]
|
roles: list[SerialId] | None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Input.__init__(self)
|
Input.__init__(self)
|
||||||
@@ -15,7 +15,7 @@ class UserCreateInput(Input[User]):
|
|||||||
|
|
||||||
class UserUpdateInput(Input[User]):
|
class UserUpdateInput(Input[User]):
|
||||||
id: SerialId
|
id: SerialId
|
||||||
roles: list[SerialId]
|
roles: list[SerialId] | None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Input.__init__(self)
|
Input.__init__(self)
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ from cpl.core.configuration import Configuration
|
|||||||
from cpl.dependency import ServiceProvider
|
from cpl.dependency import ServiceProvider
|
||||||
from cpl.dependency.module.module import Module
|
from cpl.dependency.module.module import Module
|
||||||
from cpl.dependency.service_collection import ServiceCollection
|
from cpl.dependency.service_collection import ServiceCollection
|
||||||
|
from cpl.graphql.auth.administration.api_key.api_key_filter import ApiKeyFilter
|
||||||
|
from cpl.graphql.auth.administration.api_key.api_key_graph_type import ApiKeyGraphType
|
||||||
|
from cpl.graphql.auth.administration.api_key.api_key_mutation import ApiKeyMutation
|
||||||
from cpl.graphql.auth.administration.user.user_filter import UserFilter
|
from cpl.graphql.auth.administration.user.user_filter import UserFilter
|
||||||
from cpl.graphql.auth.administration.user.user_graph_type import UserGraphType
|
from cpl.graphql.auth.administration.user.user_graph_type import UserGraphType
|
||||||
from cpl.graphql.auth.administration.user.user_mutation import UserMutation
|
from cpl.graphql.auth.administration.user.user_mutation import UserMutation
|
||||||
@@ -11,7 +14,7 @@ from cpl.graphql.service.schema import Schema
|
|||||||
|
|
||||||
class GraphQLAuthModule(Module):
|
class GraphQLAuthModule(Module):
|
||||||
dependencies = [GraphQLModule]
|
dependencies = [GraphQLModule]
|
||||||
transient = [UserGraphType, UserMutation, UserFilter]
|
transient = [UserGraphType, UserMutation, UserFilter, ApiKeyGraphType, ApiKeyMutation, ApiKeyFilter]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def register(collection: ServiceCollection):
|
def register(collection: ServiceCollection):
|
||||||
@@ -21,5 +24,3 @@ class GraphQLAuthModule(Module):
|
|||||||
def configure(provider: ServiceProvider):
|
def configure(provider: ServiceProvider):
|
||||||
schema = provider.get_service(Schema)
|
schema = provider.get_service(Schema)
|
||||||
schema.with_type(UserGraphType)
|
schema.with_type(UserGraphType)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user