mirror of
https://github.com/hexolan/panels.git
synced 2026-03-26 12:40:21 +00:00
init auth-service
This commit is contained in:
75
services/auth-service/auth_service/models/config.py
Normal file
75
services/auth-service/auth_service/models/config.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import base64
|
||||
from typing import Any, List
|
||||
|
||||
from pydantic import computed_field
|
||||
from pydantic.fields import FieldInfo
|
||||
from pydantic_settings import BaseSettings, EnvSettingsSource
|
||||
from pydantic_settings.main import BaseSettings
|
||||
from pydantic_settings.sources import PydanticBaseSettingsSource
|
||||
|
||||
|
||||
class ConfigSource(EnvSettingsSource):
|
||||
"""Responsible for loading config options from environment variables."""
|
||||
def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any:
|
||||
if field_name == "kafka_brokers":
|
||||
# Comma delimit the kafka brokers.
|
||||
if value == None:
|
||||
return None
|
||||
return value.split(",")
|
||||
elif field_name == "jwt_public_key" or field_name == "jwt_private_key":
|
||||
# Decode the JWT public and private keys from base64.
|
||||
if value == None:
|
||||
return None
|
||||
return base64.standard_b64decode(value).decode(encoding="utf-8")
|
||||
|
||||
return super().prepare_field_value(field_name, field, value, value_is_complex)
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
"""The service configuration loaded from environment
|
||||
variables.
|
||||
|
||||
Attributes:
|
||||
postgres_user (str): Loaded from the 'POSTGRES_USER' envvar.
|
||||
postgres_pass (str): Loaded from the 'POSTGRES_PASS' envvar.
|
||||
postgres_host (str): Loaded from the 'POSTGRES_HOST' envvar.
|
||||
postgres_database (str): Loaded from the 'POSTGRES_DATABASE' envvar.
|
||||
kafka_brokers (list[str]): Loaded and comma delmited from the 'KAFKA_BROKERS' envvar.
|
||||
jwt_public_key (str): Loaded and decoded, from base64, from the 'JWT_PUBLIC_KEY' envvar.
|
||||
jwt_private_key (str): Loaded and decoded, from base64, from the 'JWT_PRIVATE_KEY' envvar.
|
||||
password_pepper (str): Loaded from the 'PASSWORD_PEPPER' envvar.
|
||||
postgres_dsn (str): Computed when accessed the first time. (@property)
|
||||
|
||||
"""
|
||||
postgres_user: str
|
||||
postgres_pass: str
|
||||
postgres_host: str
|
||||
postgres_database: str
|
||||
|
||||
kafka_brokers: List[str]
|
||||
|
||||
jwt_public_key: str
|
||||
jwt_private_key: str
|
||||
|
||||
password_pepper: str
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def postgres_dsn(self) -> str:
|
||||
"""Uses the postgres_user, postgres_pass, postgres_host,
|
||||
and postgres_database options to assemble a DSN.
|
||||
|
||||
Returns:
|
||||
str: DSN for connecting to the database.
|
||||
|
||||
"""
|
||||
return "postgresql+asyncpg://{user}:{password}@{host}/{db}".format(
|
||||
user=self.postgres_user,
|
||||
password=self.postgres_pass,
|
||||
host=self.postgres_host,
|
||||
db=self.postgres_database
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def settings_customise_sources(cls, settings_cls: type[BaseSettings], *args, **kwargs) -> tuple[PydanticBaseSettingsSource, ...]:
|
||||
return (ConfigSource(settings_cls), )
|
||||
59
services/auth-service/auth_service/models/exceptions.py
Normal file
59
services/auth-service/auth_service/models/exceptions.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from enum import Enum, auto
|
||||
|
||||
from grpc import RpcContext, StatusCode
|
||||
|
||||
|
||||
class ServiceErrorCode(Enum):
|
||||
"""Error codes used for classifying ServiceExceptions."""
|
||||
INVALID_ARGUMENT = auto()
|
||||
CONFLICT = auto()
|
||||
NOT_FOUND = auto()
|
||||
INVALID_CREDENTIALS = auto()
|
||||
SERVICE_ERROR = auto()
|
||||
|
||||
__RPC_CODE_MAP__ = {
|
||||
INVALID_ARGUMENT: StatusCode.INVALID_ARGUMENT,
|
||||
CONFLICT: StatusCode.ALREADY_EXISTS,
|
||||
NOT_FOUND: StatusCode.NOT_FOUND,
|
||||
INVALID_CREDENTIALS: StatusCode.UNAUTHENTICATED,
|
||||
SERVICE_ERROR: StatusCode.INTERNAL
|
||||
}
|
||||
|
||||
def to_rpc_code(self) -> StatusCode:
|
||||
"""Convert a service error code to a gRPC status code.
|
||||
|
||||
Returns:
|
||||
The mapped RPC status code, if found, otherwise gRPC Unknown status code.
|
||||
|
||||
"""
|
||||
return self.__class__.__RPC_CODE_MAP__.get(self.value, StatusCode.UNKNOWN)
|
||||
|
||||
|
||||
class ServiceException(Exception):
|
||||
"""This exception provides an interface to convert service errors
|
||||
into gRPC errors, which can then be returned to the caller.
|
||||
|
||||
Args:
|
||||
msg (str): Error message.
|
||||
error_code (ServiceErrorCode): Categorisation code for the error.
|
||||
|
||||
Attributes:
|
||||
msg (str): The error message.
|
||||
error_code (ServiceErrorCode): Categorisation code for the error.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, msg: str, error_code: ServiceErrorCode) -> None:
|
||||
super().__init__(msg)
|
||||
self.msg = msg
|
||||
self.error_code = error_code
|
||||
|
||||
def apply_to_rpc(self, context: RpcContext) -> None:
|
||||
"""Apply the exception to an RPC context.
|
||||
|
||||
Args:
|
||||
context (grpc.RpcContext): The context to apply to.
|
||||
|
||||
"""
|
||||
context.set_code(self.error_code.to_rpc_code())
|
||||
context.set_details(self.msg)
|
||||
23
services/auth-service/auth_service/models/proto/auth_pb2.py
Normal file
23
services/auth-service/auth_service/models/proto/auth_pb2.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_sym_db = _symbol_database.Default()
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nauth.proto\x12\x0epanels.auth.v1\x1a\x1bgoogle/protobuf/empty.proto":\n\x15SetPasswordAuthMethod\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t"+\n\x18DeletePasswordAuthMethod\x12\x0f\n\x07user_id\x18\x01 \x01(\t"8\n\x13PasswordAuthRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t"`\n\tAuthToken\x12\x12\n\ntoken_type\x18\x01 \x01(\t\x12\x14\n\x0caccess_token\x18\x02 \x01(\t\x12\x15\n\rrefresh_token\x18\x03 \x01(\t\x12\x12\n\nexpires_in\x18\x04 \x01(\x032\x91\x02\n\x0bAuthService\x12T\n\x10AuthWithPassword\x12#.panels.auth.v1.PasswordAuthRequest\x1a\x19.panels.auth.v1.AuthToken"\x00\x12R\n\x0fSetPasswordAuth\x12%.panels.auth.v1.SetPasswordAuthMethod\x1a\x16.google.protobuf.Empty"\x00\x12X\n\x12DeletePasswordAuth\x12(.panels.auth.v1.DeletePasswordAuthMethod\x1a\x16.google.protobuf.Empty"\x00b\x06proto3')
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'auth_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_SETPASSWORDAUTHMETHOD']._serialized_start = 59
|
||||
_globals['_SETPASSWORDAUTHMETHOD']._serialized_end = 117
|
||||
_globals['_DELETEPASSWORDAUTHMETHOD']._serialized_start = 119
|
||||
_globals['_DELETEPASSWORDAUTHMETHOD']._serialized_end = 162
|
||||
_globals['_PASSWORDAUTHREQUEST']._serialized_start = 164
|
||||
_globals['_PASSWORDAUTHREQUEST']._serialized_end = 220
|
||||
_globals['_AUTHTOKEN']._serialized_start = 222
|
||||
_globals['_AUTHTOKEN']._serialized_end = 318
|
||||
_globals['_AUTHSERVICE']._serialized_start = 321
|
||||
_globals['_AUTHSERVICE']._serialized_end = 594
|
||||
47
services/auth-service/auth_service/models/proto/auth_pb2.pyi
Normal file
47
services/auth-service/auth_service/models/proto/auth_pb2.pyi
Normal file
@@ -0,0 +1,47 @@
|
||||
from google.protobuf import empty_pb2 as _empty_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Optional as _Optional
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class SetPasswordAuthMethod(_message.Message):
|
||||
__slots__ = ['user_id', 'password']
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
PASSWORD_FIELD_NUMBER: _ClassVar[int]
|
||||
user_id: str
|
||||
password: str
|
||||
|
||||
def __init__(self, user_id: _Optional[str]=..., password: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class DeletePasswordAuthMethod(_message.Message):
|
||||
__slots__ = ['user_id']
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
user_id: str
|
||||
|
||||
def __init__(self, user_id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class PasswordAuthRequest(_message.Message):
|
||||
__slots__ = ['user_id', 'password']
|
||||
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
PASSWORD_FIELD_NUMBER: _ClassVar[int]
|
||||
user_id: str
|
||||
password: str
|
||||
|
||||
def __init__(self, user_id: _Optional[str]=..., password: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class AuthToken(_message.Message):
|
||||
__slots__ = ['token_type', 'access_token', 'refresh_token', 'expires_in']
|
||||
TOKEN_TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
ACCESS_TOKEN_FIELD_NUMBER: _ClassVar[int]
|
||||
REFRESH_TOKEN_FIELD_NUMBER: _ClassVar[int]
|
||||
EXPIRES_IN_FIELD_NUMBER: _ClassVar[int]
|
||||
token_type: str
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
expires_in: int
|
||||
|
||||
def __init__(self, token_type: _Optional[str]=..., access_token: _Optional[str]=..., refresh_token: _Optional[str]=..., expires_in: _Optional[int]=...) -> None:
|
||||
...
|
||||
@@ -0,0 +1,58 @@
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
from . import auth_pb2 as auth__pb2
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
|
||||
class AuthServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.AuthWithPassword = channel.unary_unary('/panels.auth.v1.AuthService/AuthWithPassword', request_serializer=auth__pb2.PasswordAuthRequest.SerializeToString, response_deserializer=auth__pb2.AuthToken.FromString)
|
||||
self.SetPasswordAuth = channel.unary_unary('/panels.auth.v1.AuthService/SetPasswordAuth', request_serializer=auth__pb2.SetPasswordAuthMethod.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
self.DeletePasswordAuth = channel.unary_unary('/panels.auth.v1.AuthService/DeletePasswordAuth', request_serializer=auth__pb2.DeletePasswordAuthMethod.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
|
||||
class AuthServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def AuthWithPassword(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def SetPasswordAuth(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeletePasswordAuth(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def add_AuthServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {'AuthWithPassword': grpc.unary_unary_rpc_method_handler(servicer.AuthWithPassword, request_deserializer=auth__pb2.PasswordAuthRequest.FromString, response_serializer=auth__pb2.AuthToken.SerializeToString), 'SetPasswordAuth': grpc.unary_unary_rpc_method_handler(servicer.SetPasswordAuth, request_deserializer=auth__pb2.SetPasswordAuthMethod.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString), 'DeletePasswordAuth': grpc.unary_unary_rpc_method_handler(servicer.DeletePasswordAuth, request_deserializer=auth__pb2.DeletePasswordAuthMethod.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString)}
|
||||
generic_handler = grpc.method_handlers_generic_handler('panels.auth.v1.AuthService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
class AuthService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def AuthWithPassword(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.auth.v1.AuthService/AuthWithPassword', auth__pb2.PasswordAuthRequest.SerializeToString, auth__pb2.AuthToken.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def SetPasswordAuth(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.auth.v1.AuthService/SetPasswordAuth', auth__pb2.SetPasswordAuthMethod.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeletePasswordAuth(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.auth.v1.AuthService/DeletePasswordAuth', auth__pb2.DeletePasswordAuthMethod.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
36
services/auth-service/auth_service/models/proto/user_pb2.py
Normal file
36
services/auth-service/auth_service/models/proto/user_pb2.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_sym_db = _symbol_database.Default()
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nuser.proto\x12\x0epanels.user.v1\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto"\x96\x01\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x10\n\x08is_admin\x18\x03 \x01(\x08\x12.\n\ncreated_at\x18\x04 \x01(\x0b2\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x05 \x01(\x0b2\x1a.google.protobuf.Timestamp"1\n\x0bUserMutable\x12\x15\n\x08username\x18\x01 \x01(\tH\x00\x88\x01\x01B\x0b\n\t_username">\n\x11CreateUserRequest\x12)\n\x04data\x18\x01 \x01(\x0b2\x1b.panels.user.v1.UserMutable" \n\x12GetUserByIdRequest\x12\n\n\x02id\x18\x01 \x01(\t"(\n\x14GetUserByNameRequest\x12\x10\n\x08username\x18\x01 \x01(\t"N\n\x15UpdateUserByIdRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12)\n\x04data\x18\x02 \x01(\x0b2\x1b.panels.user.v1.UserMutable"V\n\x17UpdateUserByNameRequest\x12\x10\n\x08username\x18\x01 \x01(\t\x12)\n\x04data\x18\x02 \x01(\x0b2\x1b.panels.user.v1.UserMutable"#\n\x15DeleteUserByIdRequest\x12\n\n\x02id\x18\x01 \x01(\t"+\n\x17DeleteUserByNameRequest\x12\x10\n\x08username\x18\x01 \x01(\t"=\n\tUserEvent\x12\x0c\n\x04type\x18\x01 \x01(\t\x12"\n\x04data\x18\x02 \x01(\x0b2\x14.panels.user.v1.User2\xb4\x04\n\x0bUserService\x12G\n\nCreateUser\x12!.panels.user.v1.CreateUserRequest\x1a\x14.panels.user.v1.User"\x00\x12E\n\x07GetUser\x12".panels.user.v1.GetUserByIdRequest\x1a\x14.panels.user.v1.User"\x00\x12M\n\rGetUserByName\x12$.panels.user.v1.GetUserByNameRequest\x1a\x14.panels.user.v1.User"\x00\x12K\n\nUpdateUser\x12%.panels.user.v1.UpdateUserByIdRequest\x1a\x14.panels.user.v1.User"\x00\x12S\n\x10UpdateUserByName\x12\'.panels.user.v1.UpdateUserByNameRequest\x1a\x14.panels.user.v1.User"\x00\x12M\n\nDeleteUser\x12%.panels.user.v1.DeleteUserByIdRequest\x1a\x16.google.protobuf.Empty"\x00\x12U\n\x10DeleteUserByName\x12\'.panels.user.v1.DeleteUserByNameRequest\x1a\x16.google.protobuf.Empty"\x00b\x06proto3')
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'user_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
_globals['_USER']._serialized_start = 93
|
||||
_globals['_USER']._serialized_end = 243
|
||||
_globals['_USERMUTABLE']._serialized_start = 245
|
||||
_globals['_USERMUTABLE']._serialized_end = 294
|
||||
_globals['_CREATEUSERREQUEST']._serialized_start = 296
|
||||
_globals['_CREATEUSERREQUEST']._serialized_end = 358
|
||||
_globals['_GETUSERBYIDREQUEST']._serialized_start = 360
|
||||
_globals['_GETUSERBYIDREQUEST']._serialized_end = 392
|
||||
_globals['_GETUSERBYNAMEREQUEST']._serialized_start = 394
|
||||
_globals['_GETUSERBYNAMEREQUEST']._serialized_end = 434
|
||||
_globals['_UPDATEUSERBYIDREQUEST']._serialized_start = 436
|
||||
_globals['_UPDATEUSERBYIDREQUEST']._serialized_end = 514
|
||||
_globals['_UPDATEUSERBYNAMEREQUEST']._serialized_start = 516
|
||||
_globals['_UPDATEUSERBYNAMEREQUEST']._serialized_end = 602
|
||||
_globals['_DELETEUSERBYIDREQUEST']._serialized_start = 604
|
||||
_globals['_DELETEUSERBYIDREQUEST']._serialized_end = 639
|
||||
_globals['_DELETEUSERBYNAMEREQUEST']._serialized_start = 641
|
||||
_globals['_DELETEUSERBYNAMEREQUEST']._serialized_end = 684
|
||||
_globals['_USEREVENT']._serialized_start = 686
|
||||
_globals['_USEREVENT']._serialized_end = 747
|
||||
_globals['_USERSERVICE']._serialized_start = 750
|
||||
_globals['_USERSERVICE']._serialized_end = 1314
|
||||
100
services/auth-service/auth_service/models/proto/user_pb2.pyi
Normal file
100
services/auth-service/auth_service/models/proto/user_pb2.pyi
Normal file
@@ -0,0 +1,100 @@
|
||||
from google.protobuf import empty_pb2 as _empty_pb2
|
||||
from google.protobuf import timestamp_pb2 as _timestamp_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class User(_message.Message):
|
||||
__slots__ = ['id', 'username', 'is_admin', 'created_at', 'updated_at']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
IS_ADMIN_FIELD_NUMBER: _ClassVar[int]
|
||||
CREATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
username: str
|
||||
is_admin: bool
|
||||
created_at: _timestamp_pb2.Timestamp
|
||||
updated_at: _timestamp_pb2.Timestamp
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., username: _Optional[str]=..., is_admin: bool=..., created_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=..., updated_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class UserMutable(_message.Message):
|
||||
__slots__ = ['username']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
|
||||
def __init__(self, username: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class CreateUserRequest(_message.Message):
|
||||
__slots__ = ['data']
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
data: UserMutable
|
||||
|
||||
def __init__(self, data: _Optional[_Union[UserMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class GetUserByIdRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class GetUserByNameRequest(_message.Message):
|
||||
__slots__ = ['username']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
|
||||
def __init__(self, username: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class UpdateUserByIdRequest(_message.Message):
|
||||
__slots__ = ['id', 'data']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
data: UserMutable
|
||||
|
||||
def __init__(self, id: _Optional[str]=..., data: _Optional[_Union[UserMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class UpdateUserByNameRequest(_message.Message):
|
||||
__slots__ = ['username', 'data']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
data: UserMutable
|
||||
|
||||
def __init__(self, username: _Optional[str]=..., data: _Optional[_Union[UserMutable, _Mapping]]=...) -> None:
|
||||
...
|
||||
|
||||
class DeleteUserByIdRequest(_message.Message):
|
||||
__slots__ = ['id']
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
|
||||
def __init__(self, id: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class DeleteUserByNameRequest(_message.Message):
|
||||
__slots__ = ['username']
|
||||
USERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
username: str
|
||||
|
||||
def __init__(self, username: _Optional[str]=...) -> None:
|
||||
...
|
||||
|
||||
class UserEvent(_message.Message):
|
||||
__slots__ = ['type', 'data']
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
type: str
|
||||
data: User
|
||||
|
||||
def __init__(self, type: _Optional[str]=..., data: _Optional[_Union[User, _Mapping]]=...) -> None:
|
||||
...
|
||||
102
services/auth-service/auth_service/models/proto/user_pb2_grpc.py
Normal file
102
services/auth-service/auth_service/models/proto/user_pb2_grpc.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
||||
from . import user_pb2 as user__pb2
|
||||
|
||||
class UserServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.CreateUser = channel.unary_unary('/panels.user.v1.UserService/CreateUser', request_serializer=user__pb2.CreateUserRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.GetUser = channel.unary_unary('/panels.user.v1.UserService/GetUser', request_serializer=user__pb2.GetUserByIdRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.GetUserByName = channel.unary_unary('/panels.user.v1.UserService/GetUserByName', request_serializer=user__pb2.GetUserByNameRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.UpdateUser = channel.unary_unary('/panels.user.v1.UserService/UpdateUser', request_serializer=user__pb2.UpdateUserByIdRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.UpdateUserByName = channel.unary_unary('/panels.user.v1.UserService/UpdateUserByName', request_serializer=user__pb2.UpdateUserByNameRequest.SerializeToString, response_deserializer=user__pb2.User.FromString)
|
||||
self.DeleteUser = channel.unary_unary('/panels.user.v1.UserService/DeleteUser', request_serializer=user__pb2.DeleteUserByIdRequest.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
self.DeleteUserByName = channel.unary_unary('/panels.user.v1.UserService/DeleteUserByName', request_serializer=user__pb2.DeleteUserByNameRequest.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString)
|
||||
|
||||
class UserServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def CreateUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetUserByName(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateUserByName(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteUser(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteUserByName(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def add_UserServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {'CreateUser': grpc.unary_unary_rpc_method_handler(servicer.CreateUser, request_deserializer=user__pb2.CreateUserRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'GetUser': grpc.unary_unary_rpc_method_handler(servicer.GetUser, request_deserializer=user__pb2.GetUserByIdRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'GetUserByName': grpc.unary_unary_rpc_method_handler(servicer.GetUserByName, request_deserializer=user__pb2.GetUserByNameRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'UpdateUser': grpc.unary_unary_rpc_method_handler(servicer.UpdateUser, request_deserializer=user__pb2.UpdateUserByIdRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'UpdateUserByName': grpc.unary_unary_rpc_method_handler(servicer.UpdateUserByName, request_deserializer=user__pb2.UpdateUserByNameRequest.FromString, response_serializer=user__pb2.User.SerializeToString), 'DeleteUser': grpc.unary_unary_rpc_method_handler(servicer.DeleteUser, request_deserializer=user__pb2.DeleteUserByIdRequest.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString), 'DeleteUserByName': grpc.unary_unary_rpc_method_handler(servicer.DeleteUserByName, request_deserializer=user__pb2.DeleteUserByNameRequest.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString)}
|
||||
generic_handler = grpc.method_handlers_generic_handler('panels.user.v1.UserService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
class UserService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def CreateUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/CreateUser', user__pb2.CreateUserRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/GetUser', user__pb2.GetUserByIdRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def GetUserByName(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/GetUserByName', user__pb2.GetUserByNameRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdateUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/UpdateUser', user__pb2.UpdateUserByIdRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def UpdateUserByName(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/UpdateUserByName', user__pb2.UpdateUserByNameRequest.SerializeToString, user__pb2.User.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeleteUser(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/DeleteUser', user__pb2.DeleteUserByIdRequest.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
|
||||
@staticmethod
|
||||
def DeleteUserByName(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None):
|
||||
return grpc.experimental.unary_unary(request, target, '/panels.user.v1.UserService/DeleteUserByName', user__pb2.DeleteUserByNameRequest.SerializeToString, google_dot_protobuf_dot_empty__pb2.Empty.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
55
services/auth-service/auth_service/models/service.py
Normal file
55
services/auth-service/auth_service/models/service.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from time import time
|
||||
from typing import Optional
|
||||
from datetime import timedelta
|
||||
|
||||
from pydantic import BaseModel, Field, SecretStr
|
||||
|
||||
from auth_service.models.proto import auth_pb2
|
||||
from auth_service.models.exceptions import ServiceException, ServiceErrorCode
|
||||
|
||||
|
||||
class AuthRecord(BaseModel):
|
||||
user_id: str
|
||||
password: SecretStr # Hashed Password
|
||||
|
||||
|
||||
class AuthToken(BaseModel):
|
||||
token_type: str = "Bearer"
|
||||
access_token: str
|
||||
expires_in: int = Field(default=int(timedelta(minutes=30).total_seconds()))
|
||||
# refresh_token: str # todo: implement functionality in the future
|
||||
|
||||
@classmethod
|
||||
def to_protobuf(cls, auth_token: "AuthToken") -> auth_pb2.AuthToken:
|
||||
return auth_pb2.AuthToken(**auth_token.model_dump())
|
||||
|
||||
|
||||
class AccessTokenClaims(BaseModel):
|
||||
sub: str
|
||||
iat: int = Field(default_factory=lambda: int(time()))
|
||||
exp: int = Field(default_factory=lambda: int(time() + timedelta(minutes=30).total_seconds()))
|
||||
|
||||
|
||||
class AuthRepository:
|
||||
"""Abstract repository interface"""
|
||||
async def auth_with_password(self, user_id: str, password: str) -> AuthToken:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def set_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def delete_password_auth_method(self, user_id: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
|
||||
class AuthDBRepository(AuthRepository):
|
||||
"""Abstract database repository interface"""
|
||||
async def get_auth_record(self, user_id: str) -> Optional[AuthRecord]:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def create_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
async def update_password_auth_method(self, user_id: str, password: str) -> None:
|
||||
raise ServiceException("unimplemented internal repository method", ServiceErrorCode.SERVICE_ERROR)
|
||||
|
||||
Reference in New Issue
Block a user