Skip to content

Commit

Permalink
Auto refresh implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
na-stewart committed Jun 21, 2024
1 parent 8aae20a commit e8cf716
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 12 deletions.
16 changes: 11 additions & 5 deletions sanic_security/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
NotFoundError,
CredentialsError,
DeactivatedError,
SecondFactorFulfilledError,
SecondFactorFulfilledError, ExpiredError, RequiredRefreshError,
)
from sanic_security.models import Account, AuthenticationSession, Role, TwoStepSession
from sanic_security.utils import get_ip
Expand Down Expand Up @@ -268,10 +268,16 @@ async def authenticate(request: Request) -> AuthenticationSession:
SecondFactorRequiredError
"""
authentication_session = await AuthenticationSession.decode(request)
authentication_session.validate()
# Automatic refresh?
if not authentication_session.is_anonymous:
authentication_session.bearer.validate()
try:
authentication_session.validate()
if not authentication_session.is_anonymous:
authentication_session.bearer.validate()
except ExpiredError as e:
if security_config.AUTHENTICATION_REFRESH_AUTO:
authentication_session = await authentication_session.refresh(request)
logger.debug("Authentication session has been auto-refreshed.")
else:
raise e
return authentication_session


Expand Down
9 changes: 6 additions & 3 deletions sanic_security/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"CAPTCHA_FONT": "captcha-font.ttf",
"TWO_STEP_SESSION_EXPIRATION": 300,
"AUTHENTICATION_SESSION_EXPIRATION": 86400,
"AUTHENTICATION_SESSION_REFRESH": 2592000,
"AUTHENTICATION_REFRESH_EXPIRATION": 2592000,
"AUTHENTICATION_REFRESH_AUTO": True,
"ALLOW_LOGIN_WITH_USERNAME": False,
"INITIAL_ADMIN_EMAIL": "[email protected]",
"INITIAL_ADMIN_PASSWORD": "admin123",
Expand All @@ -65,8 +66,9 @@ class Config(dict):
CAPTCHA_SESSION_EXPIRATION (int): The amount of seconds till captcha session expiration on creation. Setting to 0 will disable expiration.
CAPTCHA_FONT (str): The file path to the font being used for captcha generation.
TWO_STEP_SESSION_EXPIRATION (int): The amount of seconds till two-step session expiration on creation. Setting to 0 will disable expiration.
AUTHENTICATION_SESSION_EXPIRATION (bool): The amount of seconds till authentication session expiration on creation. Setting to 0 will disable expiration.
AUTHENTICATION_REFRESH_EXPIRATION (bool): The amount of seconds till authentication session refresh expiration.
AUTHENTICATION_SESSION_EXPIRATION (int): The amount of seconds till authentication session expiration on creation. Setting to 0 will disable expiration.
AUTHENTICATION_REFRESH_EXPIRATION (int): The amount of seconds till authentication session refresh expiration.
AUTHENTICATION_REFRESH_AUTO (bool): Expired sessions will be automatically refreshed and passed into endpoint on authentication attempt, requires session to be re-encoded.
ALLOW_LOGIN_WITH_USERNAME (bool): Allows login via username and email.
INITIAL_ADMIN_EMAIL (str): Email used when creating the initial admin account.
INITIAL_ADMIN_PASSWORD (str): Password used when creating the initial admin account.
Expand All @@ -87,6 +89,7 @@ class Config(dict):
TWO_STEP_SESSION_EXPIRATION: int
AUTHENTICATION_SESSION_EXPIRATION: int
AUTHENTICATION_REFRESH_EXPIRATION: int
AUTHENTICATION_REFRESH_AUTO: bool
ALLOW_LOGIN_WITH_USERNAME: bool
INITIAL_ADMIN_EMAIL: str
INITIAL_ADMIN_PASSWORD: str
Expand Down
11 changes: 7 additions & 4 deletions sanic_security/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,11 +543,13 @@ class AuthenticationSession(Session):
Used to authenticate and identify a client.
Attributes:
refreshed (bool): Determines if session has been refreshed.
requires_second_factor (bool): Determines if session requires a second factor.
refresh_expiration_date (bool): Date and time the session can no longer be refreshed.
"""

refreshed: bool = fields.BooleanField(default=False)
requires_second_factor: bool = fields.BooleanField(default=False)
refresh_date: datetime.datetime = fields.DatetimeField(null=True)
refresh_expiration_date: datetime.datetime = fields.DatetimeField(null=True)

def validate(self) -> None:
"""
Expand Down Expand Up @@ -578,9 +580,10 @@ async def refresh(self, request: Request):
self.validate()
raise NotExpiredError()
except ExpiredError as e:
if datetime.datetime.now(datetime.timezone.utc) <= self.refresh_date:
if datetime.datetime.now(datetime.timezone.utc) <= self.refresh_expiration_date:
self.active = False
await self.save(update_fields=["active"])
self.refreshed = True
await self.save(update_fields=["active", "refreshed"])
return self.new(request, self.bearer)
else:
raise e
Expand Down

0 comments on commit e8cf716

Please sign in to comment.