FastAPI-UI-Auth 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: FastAPI-UI-Auth
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Python module to add username and password authentication to specific FastAPI routes
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -10,11 +10,12 @@ Requires-Dist: jinja2==3.1.*
10
10
  Requires-Dist: pydantic==2.11.*
11
11
  Requires-Dist: python-dotenv==1.1.*
12
12
  Provides-Extra: dev
13
+ Requires-Dist: websockets==15.0.*; extra == "dev"
13
14
  Requires-Dist: pre-commit==4.2.*; extra == "dev"
14
15
  Requires-Dist: uvicorn==0.34.*; extra == "dev"
15
16
  Dynamic: license-file
16
17
 
17
- # FastAPIAuthenticator
18
+ # FastAPIUIAuth
18
19
 
19
20
  Python module to add username and password authentication to specific FastAPI routes
20
21
 
@@ -24,38 +25,48 @@ Python module to add username and password authentication to specific FastAPI ro
24
25
 
25
26
  ![Platform][label-platform]
26
27
 
27
- ## Installation
28
+ **Deployments**
28
29
 
29
- ```shell
30
- repo="thevickypedia/FastAPIAuthenticator"
30
+ [![pypi][label-actions-pypi]][gha_pypi]
31
31
 
32
- latest=$(curl -s https://api.github.com/repos/${repo}/tags | jq -r '.[0].name')
32
+ [![Pypi][label-pypi]][pypi]
33
+ [![Pypi-format][label-pypi-format]][pypi-files]
34
+ [![Pypi-status][label-pypi-status]][pypi]
35
+
36
+ ## Installation
33
37
 
34
- pip install "git+https://github.com/${repo}.git@${latest}"
38
+ ```shell
39
+ pip install FastAPI-UI-Auth
35
40
  ```
36
41
 
37
42
  ## Usage
38
43
 
39
44
  ```python
40
- import fastapiauthenticator
45
+ import uiauth
41
46
 
42
47
  from fastapi import FastAPI
43
48
 
44
49
  app = FastAPI()
45
50
 
46
-
47
51
  @app.get("/public")
48
- def public_route():
52
+ async def public_route():
49
53
  return {"message": "This is a public route"}
50
54
 
51
-
52
- def private_route():
55
+ async def private_route():
53
56
  return {"message": "This is a private route"}
54
57
 
55
-
56
- fastapiauthenticator.Authenticator(app=app, secure_function=private_route)
58
+ uiauth.protect(
59
+ app=app,
60
+ params=uiauth.Parameters(
61
+ path="/private",
62
+ function=private_route
63
+ )
64
+ )
57
65
  ```
58
66
 
67
+ > `FastAPI-UI-Auth` supports both `APIRoute` and `APIWebSocketRoute` routes.<br>
68
+ > Refer [samples] directory for different use-cases.
69
+
59
70
  ## Coding Standards
60
71
  Docstring format: [`Google`][google-docs] <br>
61
72
  Styling conventions: [`PEP 8`][pep8] and [`isort`][isort]
@@ -83,6 +94,11 @@ python -m pip install sphinx==5.1.1 pre-commit recommonmark
83
94
  pre-commit run --all-files
84
95
  ```
85
96
 
97
+ ## Pypi Package
98
+ [![pypi-module][label-pypi-package]][pypi-repo]
99
+
100
+ [https://pypi.org/project/FastAPI-UI-Auth/][pypi]
101
+
86
102
  ## License & copyright
87
103
 
88
104
  &copy; Vignesh Rao
@@ -92,11 +108,23 @@ Licensed under the [MIT License][license]
92
108
  [//]: # (Labels)
93
109
 
94
110
  [3.11]: https://docs.python.org/3/whatsnew/3.11.html
95
- [license]: https://github.com/thevickypedia/FastAPIAuthenticator/blob/main/LICENSE
111
+ [license]: https://github.com/thevickypedia/FastAPI-UI-Auth/blob/main/LICENSE
96
112
  [google-docs]: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings
97
113
  [pep8]: https://www.python.org/dev/peps/pep-0008/
98
114
  [isort]: https://pycqa.github.io/isort/
115
+ [samples]: https://github.com/thevickypedia/FastAPI-UI-Auth/tree/main/samples
99
116
 
117
+ [label-actions-pypi]: https://github.com/thevickypedia/FastAPI-UI-Auth/actions/workflows/python-publish.yml/badge.svg
118
+ [label-pypi]: https://img.shields.io/pypi/v/FastAPI-UI-Auth
119
+ [label-pypi-format]: https://img.shields.io/pypi/format/FastAPI-UI-Auth
120
+ [label-pypi-status]: https://img.shields.io/pypi/status/FastAPI_UI_Auth
121
+ [label-pypi-package]: https://img.shields.io/badge/Pypi%20Package-FastAPI_UI_Auth-blue?style=for-the-badge&logo=Python
100
122
  [label-pyversion]: https://img.shields.io/badge/python-3.11%20%7C%203.12-blue
101
123
  [label-platform]: https://img.shields.io/badge/Platform-Linux|macOS|Windows-1f425f.svg
102
- [release-notes]: https://github.com/thevickypedia/FastAPIAuthenticator/blob/main/release_notes.rst
124
+ [release-notes]: https://github.com/thevickypedia/FastAPI-UI-Auth/blob/main/release_notes.rst
125
+
126
+ [gha_pypi]: https://github.com/thevickypedia/FastAPI-UI-Auth/actions/workflows/python-publish.yml
127
+
128
+ [pypi]: https://pypi.org/project/FastAPI-UI-Auth
129
+ [pypi-files]: https://pypi.org/project/FastAPI-UI-Auth/#files
130
+ [pypi-repo]: https://packaging.python.org/tutorials/packaging-projects/
@@ -0,0 +1,17 @@
1
+ fastapi_ui_auth-0.2.0.dist-info/licenses/LICENSE,sha256=_sOIKJWdD2o1WwwDIwYB2qTP2nlSWqT5Tyg9jr1Xa4w,1070
2
+ uiauth/__init__.py,sha256=s8r2Z0O9w3cuw7GcmRTOWY0NZC0KJXzBS9QsG9wUWsk,264
3
+ uiauth/endpoints.py,sha256=4RtabYwlNSHAqpU89zfRH8RD_ATH1AAf-lJKg4HA1RQ,2076
4
+ uiauth/enums.py,sha256=WO0eBv3l9HHr1I_ZXtAifCgdL-db_tZj9ka7jnjiS5k,547
5
+ uiauth/logger.py,sha256=z67PBMs4zWOfy-Gfm_41dj5Uulm-ChvZxB_jmYKKXeI,391
6
+ uiauth/models.py,sha256=lcJyy99c-VeSeUj3LahXisQZ4g3wRqdGtBVdL1oyaZI,4255
7
+ uiauth/secure.py,sha256=ZOH6kT4BD56VqwaKdKocX7eSE8tqZcu-tK0QOmjY58k,1089
8
+ uiauth/service.py,sha256=6CN3Rg8m3f83sJuLdswVzwkxkwkjptHgWa5uugxIccE,6460
9
+ uiauth/utils.py,sha256=DzXqxLpKHUDy1bxffg1cw0izqxcgmnCybSytywiPgbQ,6625
10
+ uiauth/version.py,sha256=XQVhijSHeIVMVzY2S4fY9BKxV2XHSTr9VVHsYltGPvQ,18
11
+ uiauth/templates/index.html,sha256=8vbONgCdhBmwe12ITeuBSjwwjp309kDS9cu2lRrrG88,9080
12
+ uiauth/templates/session.html,sha256=EL4gajOED3IcOnrALMiJ2SzJl2at8GFfruTuExhgOVI,3040
13
+ uiauth/templates/unauthorized.html,sha256=ahv78zLM04_Lu83LdX0Ua_toKeP5JZkYsTCWCrfCvHA,3002
14
+ fastapi_ui_auth-0.2.0.dist-info/METADATA,sha256=L10c3aWSYOwNnAQIcbVO4SzBVH7Xa6DhueQViFlmW_o,3553
15
+ fastapi_ui_auth-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ fastapi_ui_auth-0.2.0.dist-info/top_level.txt,sha256=ra3nGTbDTgQ7eChlkngJ7xGXhSCeFTWMvb_b6q8uPVA,7
17
+ fastapi_ui_auth-0.2.0.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ uiauth
uiauth/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ from uiauth.enums import APIEndpoints, APIMethods # noqa: F401,E402
2
+ from uiauth.models import Parameters # noqa: F401,E402
3
+ from uiauth.service import FastAPIUIAuth # noqa: F401,E402
4
+ from uiauth.version import version # noqa: F401,E402
5
+
6
+ protect = FastAPIUIAuth
@@ -1,8 +1,8 @@
1
1
  from fastapi.requests import Request
2
2
  from fastapi.responses import HTMLResponse
3
3
 
4
- from fastapiauthenticator import enums, models, utils
5
- from fastapiauthenticator.version import version
4
+ from uiauth import enums, models, utils
5
+ from uiauth.version import version
6
6
 
7
7
 
8
8
  def session(request: Request) -> HTMLResponse:
uiauth/logger.py ADDED
@@ -0,0 +1,13 @@
1
+ """Default logger for FastAPI-UI-Auth package."""
2
+
3
+ import logging
4
+ import sys
5
+
6
+ CUSTOM_LOGGER = logging.getLogger(__name__)
7
+ CUSTOM_LOGGER.setLevel(logging.DEBUG)
8
+ CONSOLE_HANDLER = logging.StreamHandler(sys.stdout)
9
+ CONSOLE_FORMATTER = logging.Formatter(
10
+ fmt="%(levelname)-9s %(message)s",
11
+ )
12
+ CONSOLE_HANDLER.setFormatter(fmt=CONSOLE_FORMATTER)
13
+ CUSTOM_LOGGER.addHandler(hdlr=CONSOLE_HANDLER)
@@ -1,15 +1,66 @@
1
+ import os
1
2
  import pathlib
2
3
  from typing import Callable, Dict, List, Optional, Type
3
4
 
4
5
  from fastapi.routing import APIRoute, APIWebSocketRoute
5
6
  from fastapi.templating import Jinja2Templates
6
- from pydantic import BaseModel, Field
7
+ from pydantic import BaseModel, Field, ValidationInfo, field_validator
7
8
 
8
- from fastapiauthenticator.enums import APIMethods
9
+ from uiauth.enums import APIMethods
9
10
 
10
11
  templates = Jinja2Templates(directory=pathlib.Path(__file__).parent / "templates")
11
12
 
12
13
 
14
+ def get_env(keys: List[str], default: Optional[str] = None) -> Optional[str]:
15
+ """Get environment variable value.
16
+
17
+ Args:
18
+ keys: List of environment variable names to check.
19
+ default: Default value if the environment variable is not set.
20
+
21
+ Returns:
22
+ Value of the environment variable or default value.
23
+ """
24
+ for key in keys:
25
+ if value := os.getenv(key):
26
+ return value
27
+ if value := os.getenv(key.upper()):
28
+ return value
29
+ if value := os.getenv(key.lower()):
30
+ return value
31
+ return default
32
+
33
+
34
+ class EnvConfig(BaseModel):
35
+ """Configuration for environment variables."""
36
+
37
+ username: str
38
+ password: str
39
+
40
+ # noinspection PyMethodParameters
41
+ @field_validator("username", "password", mode="before")
42
+ def load_user(cls, key: str, field: ValidationInfo) -> str | None:
43
+ """Load environment variables into the configuration.
44
+
45
+ Args:
46
+ key: Environment variable key to check.
47
+ field: Field information for validation.
48
+
49
+ See Also:
50
+ - This method checks if the environment variable is set and returns its value.
51
+ - If the key is not set, it attempts to get the value from the environment using a helper function.
52
+
53
+ Returns:
54
+ str | None:
55
+ Value of the environment variable or None if not set.
56
+ """
57
+ if not key:
58
+ return get_env([field.field_name, field.field_name[:4]])
59
+
60
+
61
+ env = EnvConfig
62
+
63
+
13
64
  class Parameters(BaseModel):
14
65
  """Parameters for the Authenticator class.
15
66
 
@@ -1,5 +1,4 @@
1
1
  import logging
2
- import os
3
2
  from threading import Timer
4
3
  from typing import Dict, List
5
4
 
@@ -13,18 +12,17 @@ from fastapi.responses import Response
13
12
  from fastapi.routing import APIRoute, APIWebSocketRoute
14
13
  from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
15
14
 
16
- from fastapiauthenticator import endpoints, enums, models, utils
15
+ from uiauth import endpoints, enums, logger, models, utils
17
16
 
18
17
  dotenv.load_dotenv(dotenv_path=dotenv.find_dotenv(), override=True)
19
- LOGGER = logging.getLogger("uvicorn.default")
20
18
  BEARER_AUTH = HTTPBearer()
21
19
 
22
20
 
23
21
  # noinspection PyDefaultArgument
24
- class Authenticator:
25
- """Authenticator is a FastAPI integration that provides authentication for secure routes.
22
+ class FastAPIUIAuth:
23
+ """FastAPIUIAuth is a FastAPI integration that provides authentication for secure routes.
26
24
 
27
- >>> Authenticator
25
+ >>> FastAPIUIAuth
28
26
 
29
27
  """
30
28
 
@@ -33,23 +31,25 @@ class Authenticator:
33
31
  app: FastAPI,
34
32
  params: models.Parameters | List[models.Parameters],
35
33
  timeout: int = 300,
36
- username: str = os.environ.get("USERNAME"),
37
- password: str = os.environ.get("PASSWORD"),
34
+ username: str = None,
35
+ password: str = None,
38
36
  fallback_button: str = models.fallback.button,
39
37
  fallback_path: str = models.fallback.path,
38
+ custom_logger: logging.Logger = None,
40
39
  ):
41
40
  """Initialize the APIAuthenticator with the FastAPI app and secure function.
42
41
 
43
42
  Args:
44
43
  app: FastAPI application instance to which the authenticator will be added.
45
- params: Parameters for the secure routes, can be a single `Parameters` object or a list of `Parameters`.
44
+ params: Parameters for the secure routes can be a single `Parameters` object or a list of `Parameters`.
46
45
  timeout: Session timeout in seconds, default is 300 seconds (5 minutes).
47
46
  username: Username for authentication, can be set via environment variable 'USERNAME'.
48
47
  password: Password for authentication, can be set via environment variable 'PASSWORD'.
49
48
  fallback_button: Title for the fallback button, defaults to "LOGIN".
50
49
  fallback_path: Fallback path to redirect to in case of session timeout or invalid session.
50
+ custom_logger: Custom logger instance, defaults to the custom logger.
51
51
  """
52
- assert all((username, password)), "'username' and 'password' are mandatory."
52
+ models.env = models.EnvConfig(username=username, password=password)
53
53
  assert fallback_path.startswith("/"), "Fallback path must start with '/'"
54
54
 
55
55
  self.app = app
@@ -59,10 +59,6 @@ class Authenticator:
59
59
  elif isinstance(params, models.Parameters):
60
60
  self.params = [params]
61
61
 
62
- self.route_map: Dict[str, models.Parameters] = {
63
- param.path: param for param in self.params if param.route is APIRoute
64
- }
65
-
66
62
  models.fallback.path = fallback_path
67
63
  models.fallback.button = fallback_button
68
64
 
@@ -72,11 +68,15 @@ class Authenticator:
72
68
  handler=utils.redirect_exception_handler,
73
69
  )
74
70
 
75
- self.username = username
76
- self.password = password
71
+ if custom_logger:
72
+ assert isinstance(
73
+ custom_logger, logging.Logger
74
+ ), "Custom logger must be an instance of logging.Logger"
75
+ logger.CUSTOM_LOGGER = custom_logger
77
76
  self.timeout = timeout
78
77
 
79
78
  self._secure()
79
+ logger.CUSTOM_LOGGER.debug("Endpoints registered: %s", len(self.params))
80
80
 
81
81
  def _verify_auth(
82
82
  self,
@@ -95,19 +95,18 @@ class Authenticator:
95
95
  Dict[str, str]:
96
96
  A dictionary containing the redirect URL to the secure path.
97
97
  """
98
- utils.verify_login(
98
+ session_token = utils.verify_login(
99
99
  authorization=authorization,
100
100
  request=request,
101
- env_username=self.username,
102
- env_password=self.password,
103
101
  )
104
- destination = request.cookies.get("X-Requested-By")
105
- if parameter := self.route_map.get(destination):
106
- LOGGER.info("Setting session timeout for %s seconds", self.timeout)
102
+ if destination := request.cookies.get("X-Requested-By"):
103
+ logger.CUSTOM_LOGGER.info(
104
+ "Setting session timeout for %s seconds", self.timeout
105
+ )
107
106
  # Set session_token cookie with a timeout, to be used for session validation when redirected
108
107
  response.set_cookie(
109
108
  key="session_token",
110
- value=models.ws_session.client_auth[request.client.host].get("token"),
109
+ value=session_token,
111
110
  httponly=True,
112
111
  samesite="strict",
113
112
  max_age=self.timeout,
@@ -118,7 +117,7 @@ class Authenticator:
118
117
  args=(request.client.host,),
119
118
  interval=self.timeout,
120
119
  ).start()
121
- return {"redirect_url": parameter.path}
120
+ return {"redirect_url": destination}
122
121
  raise HTTPException(
123
122
  status_code=status.HTTP_417_EXPECTATION_FAILED,
124
123
  detail="Unable to find secure route for the requested path.\n"
@@ -154,14 +153,14 @@ class Authenticator:
154
153
  secure_route = APIWebSocketRoute(
155
154
  path=param.path,
156
155
  endpoint=param.function,
157
- dependencies=[Depends(utils.session_check)],
156
+ dependencies=[Depends(utils.verify_session)],
158
157
  )
159
158
  else:
160
159
  secure_route = APIRoute(
161
160
  path=param.path,
162
161
  endpoint=param.function,
163
162
  methods=["GET"],
164
- dependencies=[Depends(utils.session_check)],
163
+ dependencies=[Depends(utils.verify_session)],
165
164
  )
166
165
  self.app.routes.append(secure_route)
167
166
  self.app.routes.extend([login_route, session_route, verify_route, error_route])
@@ -3,7 +3,7 @@
3
3
  <html lang="en">
4
4
  <head>
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
- <title>FastAPI - Authenticator</title>
6
+ <title>FastAPI UI Authentication</title>
7
7
  <meta property="og:type" content="Authenticator">
8
8
  <meta name="keywords" content="Python, fastapi, JavaScript, HTML, CSS">
9
9
  <meta name="author" content="Vignesh Rao">
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5
- <title>FastAPI - Authenticator</title>
5
+ <title>FastAPI UI Authentication</title>
6
6
  <meta property="og:type" content="Authenticator">
7
7
  <meta name="keywords" content="Python, fastapi, JavaScript, HTML, CSS">
8
8
  <meta name="author" content="Vignesh Rao">
@@ -79,8 +79,8 @@
79
79
  </body>
80
80
  <footer>
81
81
  <div class="footer">
82
- FastAPIAuthenticator - {{ version }}<br>
83
- <a href="https://github.com/thevickypedia/FastAPIAuthenticator">https://github.com/thevickypedia/FastAPIAuthenticator</a>
82
+ FastAPI-UI-Auth - {{ version }}<br>
83
+ <a href="https://github.com/thevickypedia/FastAPI-UI-Auth">https://github.com/thevickypedia/FastAPI-UI-Auth</a>
84
84
  </div>
85
85
  </footer>
86
86
  </html>
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5
- <title>FastAPI - Authenticator</title>
5
+ <title>FastAPI UI Authentication</title>
6
6
  <meta property="og:type" content="Authenticator">
7
7
  <meta name="keywords" content="Python, fastapi, JavaScript, HTML, CSS">
8
8
  <meta name="author" content="Vignesh Rao">
@@ -79,8 +79,8 @@
79
79
  </body>
80
80
  <footer>
81
81
  <div class="footer">
82
- FastAPIAuthenticator - {{ version }}<br>
83
- <a href="https://github.com/thevickypedia/FastAPIAuthenticator">https://github.com/thevickypedia/FastAPIAuthenticator</a>
82
+ FastAPI-UI-Auth - {{ version }}<br>
83
+ <a href="https://github.com/thevickypedia/FastAPI-UI-Auth">https://github.com/thevickypedia/FastAPI-UI-Auth</a>
84
84
  </div>
85
85
  </footer>
86
86
  </html>
@@ -1,6 +1,5 @@
1
- import logging
2
1
  import secrets
3
- from typing import Dict, List, NoReturn, Union
2
+ from typing import List, NoReturn
4
3
 
5
4
  from fastapi import status
6
5
  from fastapi.exceptions import HTTPException
@@ -9,9 +8,7 @@ from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
9
8
  from fastapi.security import HTTPAuthorizationCredentials
10
9
  from fastapi.websockets import WebSocket
11
10
 
12
- from fastapiauthenticator import enums, models, secure
13
-
14
- LOGGER = logging.getLogger("uvicorn.default")
11
+ from uiauth import enums, logger, models, secure
15
12
 
16
13
 
17
14
  def failed_auth_counter(request: Request) -> None:
@@ -62,7 +59,7 @@ def raise_error(request: Request) -> NoReturn:
62
59
  request: Request object containing client information.
63
60
  """
64
61
  failed_auth_counter(request)
65
- LOGGER.error(
62
+ logger.CUSTOM_LOGGER.error(
66
63
  "Incorrect username or password: %d",
67
64
  models.ws_session.invalid[request.client.host],
68
65
  )
@@ -73,17 +70,12 @@ def raise_error(request: Request) -> NoReturn:
73
70
  )
74
71
 
75
72
 
76
- def extract_credentials(
77
- authorization: HTTPAuthorizationCredentials, host: str
78
- ) -> List[str]:
73
+ def extract_credentials(authorization: HTTPAuthorizationCredentials) -> List[str]:
79
74
  """Extract the credentials from ``Authorization`` headers and decode it before returning as a list of strings.
80
75
 
81
76
  Args:
82
77
  authorization: Authorization header from the request.
83
- host: Host header from the request.
84
78
  """
85
- if not authorization:
86
- raise_error(host)
87
79
  decoded_auth = secure.base64_decode(authorization.credentials)
88
80
  # convert hex to a string
89
81
  auth = secure.hex_decode(decoded_auth)
@@ -93,44 +85,40 @@ def extract_credentials(
93
85
  def verify_login(
94
86
  authorization: HTTPAuthorizationCredentials,
95
87
  request: Request,
96
- env_username: str,
97
- env_password: str,
98
- ) -> Dict[str, Union[str, int]]:
88
+ ) -> str | NoReturn:
99
89
  """Verifies authentication and generates session token for each user.
100
90
 
101
91
  Args:
102
92
  authorization: Authorization header from the request.
103
93
  request: Request object containing client information.
104
- env_username: Environment variable for the username.
105
- env_password: Environment variable for the password.
106
94
 
107
95
  Returns:
108
- Dict[str, str]:
109
- Returns a dictionary with the payload required to create the session token.
96
+ str:
97
+ Returns the session token.
110
98
  """
111
- username, signature, timestamp = extract_credentials(
112
- authorization, request.client.host
113
- )
114
- if secrets.compare_digest(username, env_username):
115
- hex_user = secure.hex_encode(env_username)
116
- hex_pass = secure.hex_encode(env_password)
99
+ if authorization:
100
+ username, signature, timestamp = extract_credentials(authorization)
117
101
  else:
118
- LOGGER.warning("User '%s' not allowed", username)
102
+ raise_error(request)
103
+ if secrets.compare_digest(username, models.env.username):
104
+ hex_user = secure.hex_encode(models.env.username)
105
+ hex_pass = secure.hex_encode(models.env.password)
106
+ else:
107
+ logger.CUSTOM_LOGGER.warning("User '%s' not allowed", models.env.username)
119
108
  raise_error(request)
120
109
  message = f"{hex_user}{hex_pass}{timestamp}"
121
110
  expected_signature = secure.calculate_hash(message)
122
111
  if secrets.compare_digest(signature, expected_signature):
123
112
  models.ws_session.invalid[request.client.host] = 0
124
113
  key = secrets.token_urlsafe(64)
125
- # fixme: By setting a path instead of timestamp, this can handle path specific sessions
126
- models.ws_session.client_auth[request.client.host] = dict(
127
- username=username, token=key, timestamp=int(timestamp)
128
- )
129
- return models.ws_session.client_auth[request.client.host]
114
+ models.ws_session.client_auth[request.client.host] = key
115
+ return key
130
116
  raise_error(request)
131
117
 
132
118
 
133
- def session_check(api_request: Request = None, api_websocket: WebSocket = None) -> None:
119
+ def verify_session(
120
+ api_request: Request = None, api_websocket: WebSocket = None
121
+ ) -> None:
134
122
  """Check if the session is still valid.
135
123
 
136
124
  Args:
@@ -150,18 +138,16 @@ def session_check(api_request: Request = None, api_websocket: WebSocket = None)
150
138
  detail="Request or WebSocket connection is required for session check.",
151
139
  )
152
140
  session_token = request.cookies.get("session_token")
153
- stored_token = models.ws_session.client_auth.get(request.client.host, {}).get(
154
- "token"
155
- )
141
+ stored_token = models.ws_session.client_auth.get(request.client.host)
156
142
  if (
157
143
  stored_token
158
144
  and session_token
159
145
  and secrets.compare_digest(session_token, stored_token)
160
146
  ):
161
- LOGGER.info("Session is valid for host: %s", request.client.host)
147
+ logger.CUSTOM_LOGGER.info("Session is valid for host: %s", request.client.host)
162
148
  return
163
149
  elif not session_token:
164
- LOGGER.warning(
150
+ logger.CUSTOM_LOGGER.warning(
165
151
  "Session is invalid or expired for host: %s", request.client.host
166
152
  )
167
153
  raise models.RedirectException(
@@ -169,7 +155,7 @@ def session_check(api_request: Request = None, api_websocket: WebSocket = None)
169
155
  destination=enums.APIEndpoints.fastapi_login,
170
156
  )
171
157
  else:
172
- LOGGER.warning(
158
+ logger.CUSTOM_LOGGER.warning(
173
159
  "Session token mismatch for host: %s. Expected: %s, Received: %s",
174
160
  request.client.host,
175
161
  stored_token,
@@ -205,6 +191,6 @@ def clear_session(host: str) -> None:
205
191
  """
206
192
  if models.ws_session.client_auth.get(host):
207
193
  models.ws_session.client_auth.pop(host)
208
- LOGGER.info("Session cleared for host: %s", host)
194
+ logger.CUSTOM_LOGGER.info("Session cleared for host: %s", host)
209
195
  else:
210
- LOGGER.warning("No session found for host: %s", host)
196
+ logger.CUSTOM_LOGGER.warning("No session found for host: %s", host)
uiauth/version.py ADDED
@@ -0,0 +1 @@
1
+ version = "0.2.0"
@@ -1,16 +0,0 @@
1
- fastapi_ui_auth-0.1.0.dist-info/licenses/LICENSE,sha256=_sOIKJWdD2o1WwwDIwYB2qTP2nlSWqT5Tyg9jr1Xa4w,1070
2
- fastapiauthenticator/__init__.py,sha256=H1tJUJp4FWweEu2JeMw5vmqjtMhMwR4kUd11ek8UmwQ,320
3
- fastapiauthenticator/endpoints.py,sha256=PF2qu6XQ3MQStFEprRYYxiS6Dl6ukYaMqEkSlO-F3Ls,2104
4
- fastapiauthenticator/enums.py,sha256=WO0eBv3l9HHr1I_ZXtAifCgdL-db_tZj9ka7jnjiS5k,547
5
- fastapiauthenticator/models.py,sha256=GxmQfSvg70OTsvswJ3QFq_lxq-Yz1fIfzW6x8d4Sj40,2726
6
- fastapiauthenticator/secure.py,sha256=ZOH6kT4BD56VqwaKdKocX7eSE8tqZcu-tK0QOmjY58k,1089
7
- fastapiauthenticator/service.py,sha256=1UCCUf7yaH11BHB2vlaNYehVn5YyWbGK6bnrN7wJlDM,6485
8
- fastapiauthenticator/utils.py,sha256=geO78AL-nqv4EANQzQaWI2mGkkZiLZY8wm2LH_EDye0,7145
9
- fastapiauthenticator/version.py,sha256=aOHawL1zuHMfBWKXqwUkXcW96oXLNCY-CXdHDqkz4g4,18
10
- fastapiauthenticator/templates/index.html,sha256=mA2R6gk6lvibq_AmPgGHBFQijYtNUD7IIfeBSJWQrM4,9078
11
- fastapiauthenticator/templates/session.html,sha256=LUCvcEdQOjfIXjRZ2gPx2s5wyzNuCve4OMge0hXaBLM,3053
12
- fastapiauthenticator/templates/unauthorized.html,sha256=UZo1Jt64-CFfjwWTGicUMdHVWkYkXCJBRxvit4QTiQM,3015
13
- fastapi_ui_auth-0.1.0.dist-info/METADATA,sha256=taS1d_w3xCMVJB5ymIbhjlM7GpWIfCPEf8PyR9u4pRQ,2402
14
- fastapi_ui_auth-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- fastapi_ui_auth-0.1.0.dist-info/top_level.txt,sha256=EpDRP7uLM0f-Vd5rUtLBh4MTMAnpXzw1pr0DSknW_Ds,21
16
- fastapi_ui_auth-0.1.0.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- fastapiauthenticator
@@ -1,6 +0,0 @@
1
- from fastapiauthenticator.enums import APIEndpoints, APIMethods # noqa: F401,E402
2
- from fastapiauthenticator.models import Parameters # noqa: F401,E402
3
- from fastapiauthenticator.service import Authenticator # noqa: F401,E402
4
- from fastapiauthenticator.version import version # noqa: F401,E402
5
-
6
- protect = Authenticator
@@ -1 +0,0 @@
1
- version = "0.1.0"
File without changes
File without changes