maleo-foundation 0.2.7__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/PKG-INFO +1 -1
  2. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/authentication.py +5 -4
  3. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/service.py +2 -4
  4. maleo_foundation-0.2.8/maleo_foundation/middlewares/authentication.py +99 -0
  5. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/middlewares/base.py +29 -6
  6. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation.egg-info/PKG-INFO +1 -1
  7. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/pyproject.toml +1 -1
  8. maleo_foundation-0.2.7/maleo_foundation/middlewares/authentication.py +0 -80
  9. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/README.md +0 -0
  10. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/__init__.py +0 -0
  11. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/__init__.py +0 -0
  12. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/manager.py +0 -0
  13. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/__init__.py +0 -0
  14. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/encryption/__init__.py +0 -0
  15. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/encryption/aes.py +0 -0
  16. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/encryption/rsa.py +0 -0
  17. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/hash/__init__.py +0 -0
  18. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/hash/bcrypt.py +0 -0
  19. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/hash/hmac.py +0 -0
  20. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/hash/sha256.py +0 -0
  21. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/key.py +0 -0
  22. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/signature.py +0 -0
  23. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/client/services/token.py +0 -0
  24. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/constants.py +0 -0
  25. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/enums.py +0 -0
  26. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/__init__.py +0 -0
  27. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/client.py +0 -0
  28. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/encryption/__init__.py +0 -0
  29. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/encryption/aes.py +0 -0
  30. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/encryption/rsa.py +0 -0
  31. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/general.py +0 -0
  32. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/hash.py +0 -0
  33. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/key.py +0 -0
  34. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/query.py +0 -0
  35. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/service.py +0 -0
  36. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/signature.py +0 -0
  37. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/expanded_types/token.py +0 -0
  38. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/extended_types.py +0 -0
  39. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/__init__.py +0 -0
  40. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/client/__init__.py +0 -0
  41. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/client/base.py +0 -0
  42. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/client/google/__init__.py +0 -0
  43. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/client/google/base.py +0 -0
  44. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/client/google/secret.py +0 -0
  45. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/client/google/storage.py +0 -0
  46. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/client/maleo.py +0 -0
  47. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/db.py +0 -0
  48. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/managers/middleware.py +0 -0
  49. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/middlewares/cors.py +0 -0
  50. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/__init__.py +0 -0
  51. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/responses.py +0 -0
  52. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/__init__.py +0 -0
  53. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/encryption.py +0 -0
  54. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/general.py +0 -0
  55. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/hash.py +0 -0
  56. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/key.py +0 -0
  57. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/parameter.py +0 -0
  58. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/result.py +0 -0
  59. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/signature.py +0 -0
  60. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/schemas/token.py +0 -0
  61. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/table.py +0 -0
  62. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/__init__.py +0 -0
  63. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/general/__init__.py +0 -0
  64. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/general/key.py +0 -0
  65. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/general/signature.py +0 -0
  66. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/general/token.py +0 -0
  67. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/__init__.py +0 -0
  68. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/client.py +0 -0
  69. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/encryption/__init__.py +0 -0
  70. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/encryption/aes.py +0 -0
  71. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/encryption/rsa.py +0 -0
  72. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/general.py +0 -0
  73. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/hash/__init__.py +0 -0
  74. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/hash/bcrypt.py +0 -0
  75. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/hash/hmac.py +0 -0
  76. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/hash/sha256.py +0 -0
  77. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/key.py +0 -0
  78. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/service.py +0 -0
  79. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/signature.py +0 -0
  80. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/parameters/token.py +0 -0
  81. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/__init__.py +0 -0
  82. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/client/__init__.py +0 -0
  83. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/client/controllers/__init__.py +0 -0
  84. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/client/controllers/http.py +0 -0
  85. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/client/service.py +0 -0
  86. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/encryption/__init__.py +0 -0
  87. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/encryption/aes.py +0 -0
  88. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/encryption/rsa.py +0 -0
  89. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/hash.py +0 -0
  90. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/key.py +0 -0
  91. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/service/__init__.py +0 -0
  92. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/service/controllers/__init__.py +0 -0
  93. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/service/controllers/rest.py +0 -0
  94. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/service/general.py +0 -0
  95. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/service/query.py +0 -0
  96. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/signature.py +0 -0
  97. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/models/transfers/results/token.py +0 -0
  98. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/types.py +0 -0
  99. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/__init__.py +0 -0
  100. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/controller.py +0 -0
  101. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/exceptions.py +0 -0
  102. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/extractor.py +0 -0
  103. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/formatter/__init__.py +0 -0
  104. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/formatter/case.py +0 -0
  105. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/loaders/__init__.py +0 -0
  106. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/loaders/credential/__init__.py +0 -0
  107. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/loaders/credential/google.py +0 -0
  108. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/loaders/json.py +0 -0
  109. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/loaders/key/__init__.py +0 -0
  110. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/loaders/key/rsa.py +0 -0
  111. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/loaders/yaml.py +0 -0
  112. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/logging.py +0 -0
  113. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/mergers.py +0 -0
  114. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation/utils/query.py +0 -0
  115. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation.egg-info/SOURCES.txt +0 -0
  116. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation.egg-info/dependency_links.txt +0 -0
  117. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation.egg-info/requires.txt +0 -0
  118. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/maleo_foundation.egg-info/top_level.txt +0 -0
  119. {maleo_foundation-0.2.7 → maleo_foundation-0.2.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -1,25 +1,26 @@
1
1
  from pydantic import BaseModel, Field
2
2
  from starlette.authentication import AuthCredentials, BaseUser
3
3
  from typing import Optional, Sequence
4
+ from maleo_foundation.enums import BaseEnums
4
5
  from maleo_foundation.models.transfers.general.token import MaleoFoundationTokenGeneralTransfers
5
6
  from maleo_foundation.types import BaseTypes
6
7
 
7
8
  class Credentials(AuthCredentials):
8
9
  def __init__(
9
10
  self,
10
- key:BaseTypes.OptionalString = None,
11
+ token_type:Optional[BaseEnums.TokenType] = None,
11
12
  token:BaseTypes.OptionalString = None,
12
13
  payload:Optional[MaleoFoundationTokenGeneralTransfers.DecodePayload] = None,
13
14
  scopes:Optional[Sequence[str]] = None
14
15
  ) -> None:
15
- self._key = key
16
+ self._token_type = token_type
16
17
  self._token = token
17
18
  self._payload = payload
18
19
  super().__init__(scopes)
19
20
 
20
21
  @property
21
- def key(self) -> BaseTypes.OptionalString:
22
- return self._key
22
+ def token_type(self) -> Optional[BaseEnums.TokenType]:
23
+ return self._token_type
23
24
 
24
25
  @property
25
26
  def token(self) -> BaseTypes.OptionalString:
@@ -261,7 +261,7 @@ class ServiceManager:
261
261
  raise NotImplementedError()
262
262
 
263
263
  @property
264
- def token(self) -> str:
264
+ def token(self) -> BaseTypes.OptionalString:
265
265
  payload = MaleoFoundationTokenGeneralTransfers.BaseEncodePayload(
266
266
  iss=None,
267
267
  sub=str(self._maleo_credentials.id),
@@ -272,9 +272,7 @@ class ServiceManager:
272
272
  )
273
273
  parameters = MaleoFoundationTokenParametersTransfers.Encode(key=self._keys.private, password=self._keys.password, payload=payload)
274
274
  result = self._foundation.services.token.encode(parameters=parameters)
275
- if not result.success:
276
- raise RuntimeError("Failed encoding payload into token")
277
- return result.data.token
275
+ return result.data.token if result.success else None
278
276
 
279
277
  def create_app(self, router:APIRouter, lifespan:Optional[Lifespan[AppType]] = None) -> FastAPI:
280
278
  self._loggers.application.info("Creating FastAPI application")
@@ -0,0 +1,99 @@
1
+ from fastapi import FastAPI
2
+ from starlette.authentication import AuthenticationBackend, AuthenticationError
3
+ from starlette.middleware.authentication import AuthenticationMiddleware
4
+ from starlette.requests import HTTPConnection
5
+ from typing import Tuple
6
+ from maleo_foundation.authentication import Credentials, User
7
+ from maleo_foundation.enums import BaseEnums
8
+ from maleo_foundation.client.manager import MaleoFoundationClientManager
9
+ from maleo_foundation.models.schemas import BaseGeneralSchemas
10
+ from maleo_foundation.models.transfers.parameters.token import MaleoFoundationTokenParametersTransfers
11
+ from maleo_foundation.utils.exceptions import BaseExceptions
12
+ from maleo_foundation.utils.logging import MiddlewareLogger
13
+
14
+ class Backend(AuthenticationBackend):
15
+ def __init__(self, keys:BaseGeneralSchemas.RSAKeys, logger:MiddlewareLogger, maleo_foundation:MaleoFoundationClientManager):
16
+ super().__init__()
17
+ self._keys = keys
18
+ self._logger = logger
19
+ self._maleo_foundation = maleo_foundation
20
+
21
+ async def authenticate(self, conn:HTTPConnection) -> Tuple[Credentials, User]:
22
+ if "Authorization" in conn.headers:
23
+ auth = conn.headers["Authorization"]
24
+ parts = auth.split()
25
+ if len(parts) != 2 or parts[0] != "Bearer":
26
+ raise AuthenticationError("Invalid Authorization header format")
27
+ scheme, token = parts
28
+ if scheme != 'Bearer':
29
+ raise AuthenticationError("Authorization scheme must be Bearer token")
30
+
31
+ #* Decode token
32
+ decode_token_parameters = MaleoFoundationTokenParametersTransfers.Decode(key=self._keys.public, token=token)
33
+ decode_token_result = self._maleo_foundation.services.token.decode(parameters=decode_token_parameters)
34
+ if decode_token_result.success:
35
+ payload = decode_token_result.data
36
+ return (
37
+ Credentials(
38
+ token_type=BaseEnums.TokenType.ACCESS,
39
+ token=token,
40
+ payload=payload,
41
+ scopes=["authenticated", payload.sr]
42
+ ),
43
+ User(
44
+ authenticated=True,
45
+ username=payload.u_u,
46
+ email=payload.u_e
47
+ )
48
+ )
49
+
50
+ if "token" in conn.cookies:
51
+ token = conn.cookies["token"]
52
+ #* Decode token
53
+ decode_token_parameters = MaleoFoundationTokenParametersTransfers.Decode(key=self._keys.public, token=token)
54
+ decode_token_result = self._maleo_foundation.services.token.decode(parameters=decode_token_parameters)
55
+ if decode_token_result.success:
56
+ payload = decode_token_result.data
57
+ return (
58
+ Credentials(
59
+ token_type=BaseEnums.TokenType.REFRESH,
60
+ token=token,
61
+ payload=payload,
62
+ scopes=["authenticated", payload.sr]
63
+ ),
64
+ User(
65
+ authenticated=True,
66
+ username=payload.u_u,
67
+ email=payload.u_e
68
+ )
69
+ )
70
+
71
+ return Credentials(), User(authenticated=False)
72
+
73
+ def add_authentication_middleware(app:FastAPI, keys:BaseGeneralSchemas.RSAKeys, logger:MiddlewareLogger, maleo_foundation:MaleoFoundationClientManager) -> None:
74
+ """
75
+ Adds Authentication middleware to the FastAPI application.
76
+
77
+ Args:
78
+ app: FastAPI
79
+ The FastAPI application instance to which the middleware will be added.
80
+
81
+ logger: MiddlewareLogger
82
+ Authentication middleware logger to be used.
83
+
84
+ key: str
85
+ Public key to be used for token decoding.
86
+
87
+ Returns:
88
+ None: The function modifies the FastAPI app by adding Base middleware.
89
+
90
+ Note:
91
+ FastAPI applies middleware in reverse order of registration, so this middleware
92
+ will execute after any middleware added subsequently.
93
+
94
+ Example:
95
+ ```python
96
+ add_authentication_middleware(app=app, limit=10, window=1, cleanup_interval=60, ip_timeout=300)
97
+ ```
98
+ """
99
+ app.add_middleware(AuthenticationMiddleware, backend=Backend(keys, logger, maleo_foundation), on_error=BaseExceptions.authentication_error_handler)
@@ -8,10 +8,13 @@ from fastapi import FastAPI, Request, Response, status
8
8
  from fastapi.responses import JSONResponse
9
9
  from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
10
10
  from typing import Awaitable, Callable, Optional, Sequence
11
- from maleo_foundation.authentication import Credentials, User
11
+ from maleo_foundation.authentication import Authentication
12
+ from maleo_foundation.enums import BaseEnums
12
13
  from maleo_foundation.client.manager import MaleoFoundationClientManager
13
14
  from maleo_foundation.models.schemas import BaseGeneralSchemas
14
15
  from maleo_foundation.models.responses import BaseResponses
16
+ from maleo_foundation.models.transfers.general.token import MaleoFoundationTokenGeneralTransfers
17
+ from maleo_foundation.models.transfers.parameters.token import MaleoFoundationTokenParametersTransfers
15
18
  from maleo_foundation.models.transfers.parameters.signature import MaleoFoundationSignatureParametersTransfers
16
19
  from maleo_foundation.utils.extractor import BaseExtractors
17
20
  from maleo_foundation.utils.logging import MiddlewareLogger
@@ -117,6 +120,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
117
120
  def _add_response_headers(
118
121
  self,
119
122
  request:Request,
123
+ authentication:Authentication,
120
124
  response:Response,
121
125
  request_timestamp:datetime,
122
126
  response_timestamp:datetime,
@@ -132,11 +136,22 @@ class BaseMiddleware(BaseHTTPMiddleware):
132
136
  if sign_result.success:
133
137
  response.headers["X-Signature"] = sign_result.data.signature
134
138
  response = self._append_cors_headers(request=request, response=response) #* Re-append CORS headers
139
+ if authentication.user.is_authenticated \
140
+ and authentication.credentials.token_type == BaseEnums.TokenType.REFRESH \
141
+ and authentication.credentials.payload is not None \
142
+ and (response.status_code >= 200 and response.status_code < 300):
143
+ #* Regenerate new authorization
144
+ payload = MaleoFoundationTokenGeneralTransfers.BaseEncodePayload.model_validate(authentication.credentials.payload.model_dump())
145
+ parameters = MaleoFoundationTokenParametersTransfers.Encode(key=self._keys.private, password=self._keys.password, payload=payload)
146
+ result = self._maleo_foundation.services.token.encode(parameters=parameters)
147
+ if result.success:
148
+ response.headers["X-New-Authorization"] = result.data.token
135
149
  return response
136
150
 
137
151
  def _build_response(
138
152
  self,
139
153
  request:Request,
154
+ authentication:Authentication,
140
155
  authentication_info:str,
141
156
  response:Response,
142
157
  request_timestamp:datetime,
@@ -145,7 +160,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
145
160
  log_level:str = "info",
146
161
  client_ip:str = "unknown"
147
162
  ) -> Response:
148
- response = self._add_response_headers(request, response, request_timestamp, response_timestamp, process_time)
163
+ response = self._add_response_headers(request, authentication, response, request_timestamp, response_timestamp, process_time)
149
164
  log_func = getattr(self._logger, log_level)
150
165
  log_func(
151
166
  f"Request {authentication_info} | IP: {client_ip} | Host: {request.client.host} | Port: {request.client.port} | Method: {request.method} | URL: {request.url.path} | "
@@ -156,6 +171,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
156
171
  def _handle_exception(
157
172
  self,
158
173
  request:Request,
174
+ authentication:Authentication,
159
175
  authentication_info:str,
160
176
  error,
161
177
  request_timestamp:datetime,
@@ -183,7 +199,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
183
199
  f"Headers: {dict(request.headers)} - Response | Status: 500 | Exception:\n{json.dumps(error_details, indent=4)}"
184
200
  )
185
201
 
186
- return self._add_response_headers(request, response, request_timestamp, response_timestamp, process_time)
202
+ return self._add_response_headers(request, authentication, response, request_timestamp, response_timestamp, process_time)
187
203
 
188
204
  async def _request_processor(self, request:Request) -> Optional[Response]:
189
205
  return None
@@ -193,17 +209,21 @@ class BaseMiddleware(BaseHTTPMiddleware):
193
209
  request_timestamp = datetime.now(tz=timezone.utc) #* Record the request timestamp
194
210
  start_time = time.perf_counter() #* Record the start time
195
211
  client_ip = BaseExtractors.extract_client_ip(request) #* Get request IP with improved extraction
196
- user:User = request.user
197
- if not user.is_authenticated:
212
+ authentication = Authentication(
213
+ credentials=request.auth,
214
+ user=request.user
215
+ )
216
+ if not authentication.user.is_authenticated:
198
217
  authentication_info = "| Unauthenticated"
199
218
  else:
200
- authentication_info = f"| Username: {user.display_name} | Email:{user.identity}"
219
+ authentication_info = f"| Username: {authentication.user.display_name} | Email:{authentication.user.identity}"
201
220
 
202
221
  try:
203
222
  #* 1. Rate limit check
204
223
  if self._check_rate_limit(client_ip):
205
224
  return self._build_response(
206
225
  request=request,
226
+ authentication=authentication,
207
227
  authentication_info=authentication_info,
208
228
  response=JSONResponse(
209
229
  content=BaseResponses.RateLimitExceeded().model_dump(),
@@ -221,6 +241,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
221
241
  if pre_response is not None:
222
242
  return self._build_response(
223
243
  request=request,
244
+ authentication=authentication,
224
245
  authentication_info=authentication_info,
225
246
  response=pre_response,
226
247
  request_timestamp=request_timestamp,
@@ -234,6 +255,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
234
255
  response = await call_next(request)
235
256
  response = self._build_response(
236
257
  request=request,
258
+ authentication=authentication,
237
259
  authentication_info=authentication_info,
238
260
  response=response,
239
261
  request_timestamp=request_timestamp,
@@ -248,6 +270,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
248
270
  except Exception as e:
249
271
  return self._handle_exception(
250
272
  request=request,
273
+ authentication=authentication,
251
274
  authentication_info=authentication_info,
252
275
  error=e,
253
276
  request_timestamp=request_timestamp,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maleo_foundation"
7
- version = "0.2.7"
7
+ version = "0.2.8"
8
8
  description = "Foundation package for Maleo"
9
9
  authors = [
10
10
  { name = "Agra Bima Yuda", email = "agra@nexmedis.com" }
@@ -1,80 +0,0 @@
1
- from datetime import datetime, timezone
2
- from fastapi import FastAPI
3
- from starlette.authentication import AuthenticationBackend, AuthenticationError
4
- from starlette.middleware.authentication import AuthenticationMiddleware
5
- from starlette.requests import HTTPConnection
6
- from typing import Tuple
7
- from maleo_foundation.authentication import Credentials, User
8
- from maleo_foundation.client.manager import MaleoFoundationClientManager
9
- from maleo_foundation.models.schemas import BaseGeneralSchemas
10
- from maleo_foundation.models.transfers.parameters.token import MaleoFoundationTokenParametersTransfers
11
- from maleo_foundation.utils.exceptions import BaseExceptions
12
- from maleo_foundation.utils.logging import MiddlewareLogger
13
-
14
- class Backend(AuthenticationBackend):
15
- def __init__(self, keys:BaseGeneralSchemas.RSAKeys, logger:MiddlewareLogger, maleo_foundation:MaleoFoundationClientManager):
16
- super().__init__()
17
- self._keys = keys
18
- self._logger = logger
19
- self._maleo_foundation = maleo_foundation
20
-
21
- async def authenticate(self, conn:HTTPConnection) -> Tuple[Credentials, User]:
22
- if "Authorization" not in conn.headers:
23
- return Credentials(), User(authenticated=False)
24
-
25
- auth = conn.headers["Authorization"]
26
- scheme, token = auth.split()
27
- if scheme != 'Bearer':
28
- # raise AuthenticationError("Authorization scheme must be Bearer token")
29
- return Credentials(), User(authenticated=False)
30
-
31
- decode_token_parameters = MaleoFoundationTokenParametersTransfers.Decode(key=self._keys.public, token=token)
32
- decode_token_result = self._maleo_foundation.services.token.decode(parameters=decode_token_parameters)
33
- if not decode_token_result.success:
34
- # raise AuthenticationError("Invalid Bearer token, unable to decode token")
35
- return Credentials(), User(authenticated=False)
36
- if decode_token_result.data.exp_dt <= datetime.now(tz=timezone.utc):
37
- # raise AuthenticationError("Expired Bearer token, request new or refresh token")
38
- return Credentials(), User(authenticated=False)
39
-
40
- payload = decode_token_result.data
41
- return (
42
- Credentials(
43
- token=token,
44
- payload=payload,
45
- scopes=["authenticated", payload.sr]
46
- ),
47
- User(
48
- authenticated=True,
49
- username=payload.u_u,
50
- email=payload.u_e
51
- )
52
- )
53
-
54
- def add_authentication_middleware(app:FastAPI, keys:BaseGeneralSchemas.RSAKeys, logger:MiddlewareLogger, maleo_foundation:MaleoFoundationClientManager) -> None:
55
- """
56
- Adds Authentication middleware to the FastAPI application.
57
-
58
- Args:
59
- app: FastAPI
60
- The FastAPI application instance to which the middleware will be added.
61
-
62
- logger: MiddlewareLogger
63
- Authentication middleware logger to be used.
64
-
65
- key: str
66
- Public key to be used for token decoding.
67
-
68
- Returns:
69
- None: The function modifies the FastAPI app by adding Base middleware.
70
-
71
- Note:
72
- FastAPI applies middleware in reverse order of registration, so this middleware
73
- will execute after any middleware added subsequently.
74
-
75
- Example:
76
- ```python
77
- add_authentication_middleware(app=app, limit=10, window=1, cleanup_interval=60, ip_timeout=300)
78
- ```
79
- """
80
- app.add_middleware(AuthenticationMiddleware, backend=Backend(keys, logger, maleo_foundation), on_error=BaseExceptions.authentication_error_handler)