Skip to content

Commit 9d65757

Browse files
Merge pull request #63 from ivan-borovets/fixes
2 parents d8d143b + 203264a commit 9d65757

9 files changed

Lines changed: 93 additions & 92 deletions

File tree

Makefile

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@ PYTHON := python
33
CONFIGS_DIG := config
44
TOML_CONFIG_MANAGER := $(CONFIGS_DIG)/toml_config_manager.py
55

6+
.PHONY: guard-APP_ENV
7+
guard-APP_ENV:
8+
@if [ -z "$$APP_ENV" ]; then \
9+
echo "APP_ENV is not set. Set APP_ENV before running this command."; \
10+
exit 1; \
11+
fi
12+
613
.PHONY: env dotenv
714
env:
815
@echo APP_ENV=$(APP_ENV)
916

10-
dotenv:
11-
@$(PYTHON) $(TOML_CONFIG_MANAGER) ${APP_ENV}
17+
dotenv: guard-APP_ENV
18+
@$(PYTHON) $(TOML_CONFIG_MANAGER) $(APP_ENV)
1219

1320
# Docker compose
1421
DOCKER_COMPOSE := docker compose
1522
DOCKER_COMPOSE_PRUNE := scripts/makefile/docker_prune.sh
1623

17-
.PHONY: guard-APP_ENV up.db up.db-echo up up.echo down down.total logs.db shell.db prune
18-
guard-APP_ENV:
19-
ifndef APP_ENV
20-
$(error "APP_ENV is not set. Set APP_ENV before running this command.")
21-
endif
22-
24+
.PHONY: up.db up.db-echo up up.echo down down.total logs.db shell.db prune
2325
up.db: guard-APP_ENV
2426
@echo "APP_ENV=$(APP_ENV)"
2527
@cd $(CONFIGS_DIG)/$(APP_ENV) && $(DOCKER_COMPOSE) --env-file .env.$(APP_ENV) up -d web_app_db_pg --build
@@ -28,11 +30,11 @@ up.db-echo: guard-APP_ENV
2830
@echo "APP_ENV=$(APP_ENV)"
2931
@cd $(CONFIGS_DIG)/$(APP_ENV) && $(DOCKER_COMPOSE) --env-file .env.$(APP_ENV) up web_app_db_pg --build
3032

31-
up:
33+
up: guard-APP_ENV
3234
@echo "APP_ENV=$(APP_ENV)"
3335
@cd $(CONFIGS_DIG)/$(APP_ENV) && $(DOCKER_COMPOSE) --env-file .env.$(APP_ENV) up -d --build
3436

35-
up.echo:
37+
up.echo: guard-APP_ENV
3638
@echo "APP_ENV=$(APP_ENV)"
3739
@cd $(CONFIGS_DIG)/$(APP_ENV) && $(DOCKER_COMPOSE) --env-file .env.$(APP_ENV) up --build
3840

@@ -42,10 +44,10 @@ down: guard-APP_ENV
4244
down.total: guard-APP_ENV
4345
@cd $(CONFIGS_DIG)/$(APP_ENV) && $(DOCKER_COMPOSE) --env-file .env.$(APP_ENV) down -v
4446

45-
logs.db:
47+
logs.db: guard-APP_ENV
4648
@cd $(CONFIGS_DIG)/$(APP_ENV) && $(DOCKER_COMPOSE) --env-file .env.$(APP_ENV) logs -f web_app_db_pg
4749

48-
shell.db:
50+
shell.db: guard-APP_ENV
4951
@cd $(CONFIGS_DIG)/$(APP_ENV) && $(DOCKER_COMPOSE) --env-file .env.$(APP_ENV) exec web_app_db_pg sh
5052

5153
prune:
@@ -90,4 +92,4 @@ tree: pycache-del
9092

9193
# Dishka
9294
plot-data:
93-
python $(DISHKA_PLOT_DATA)
95+
@$(PYTHON) $(DISHKA_PLOT_DATA)

src/app/application/common/services/current_user.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,18 @@ def __init__(
2323
self._identity_provider = identity_provider
2424
self._user_command_gateway = user_command_gateway
2525
self._access_revoker = access_revoker
26-
self._cached_current_user: User | None = None
2726

2827
async def get_current_user(self) -> User:
2928
"""
3029
:raises AuthenticationError:
3130
:raises DataMapperError:
3231
:raises AuthorizationError:
3332
"""
34-
if self._cached_current_user is not None:
35-
return self._cached_current_user
36-
3733
current_user_id = await self._identity_provider.get_current_user_id()
3834
user: User | None = await self._user_command_gateway.read_by_id(current_user_id)
39-
if user is None:
35+
if user is None or not user.is_active:
4036
log.warning("%s ID: %s.", AUTHZ_NO_CURRENT_USER, current_user_id)
4137
await self._access_revoker.remove_all_user_access(current_user_id)
4238
raise AuthorizationError(AUTHZ_NOT_AUTHORIZED)
4339

44-
self._cached_current_user = user
4540
return user

src/app/infrastructure/auth/adapters/access_revoker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ async def remove_all_user_access(self, user_id: UserId) -> None:
1414
"""
1515
:raises DataMapperError:
1616
"""
17-
await self._auth_session_service.invalidate_all_sessions_for_user(user_id)
17+
await self._auth_session_service.terminate_all_sessions_for_user(user_id)

src/app/infrastructure/auth/adapters/transaction_manager_sqla.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ async def commit(self) -> None:
2626
"""
2727
try:
2828
await self._session.commit()
29-
log.debug("%s. Auth session.", DB_COMMIT_DONE)
29+
log.debug("%s Auth session.", DB_COMMIT_DONE)
3030

3131
except SQLAlchemyError as error:
3232
raise DataMapperError(f"{DB_QUERY_FAILED} {DB_COMMIT_FAILED}") from error

src/app/infrastructure/auth/handlers/log_in.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ async def execute(self, request_data: LogInRequest) -> None:
6161
:raises DataMapperError:
6262
:raises DomainFieldError:
6363
:raises UserNotFoundByUsernameError:
64+
:raises AuthenticationError:
6465
"""
6566
log.info("Log in: started. Username: '%s'.", request_data.username)
6667

@@ -83,7 +84,7 @@ async def execute(self, request_data: LogInRequest) -> None:
8384
if not user.is_active:
8485
raise AuthenticationError(AUTH_ACCOUNT_INACTIVE)
8586

86-
await self._auth_session_service.create_session(user.id_)
87+
await self._auth_session_service.issue_session(user.id_)
8788

8889
log.info(
8990
"Log in: done. User, ID: '%s', username '%s', role '%s'.",

src/app/infrastructure/auth/handlers/log_out.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ async def execute(self) -> None:
3333

3434
log.info("Log out: user identified. User ID: '%s'.", current_user.id_)
3535

36-
await self._auth_session_service.invalidate_current_session()
36+
await self._auth_session_service.terminate_current_session()
3737

3838
log.info("Log out: done. User ID: '%s'.", current_user.id_)

src/app/infrastructure/auth/session/service.py

Lines changed: 63 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ def __init__(
4444
self._auth_session_timer = auth_session_timer
4545
self._cached_auth_session: AuthSession | None = None
4646

47-
async def create_session(self, user_id: UserId) -> None:
47+
async def issue_session(self, user_id: UserId) -> None:
4848
"""
4949
:raises AuthenticationError:
5050
"""
51-
log.debug("Create auth session: started. User ID: '%s'.", user_id.value)
51+
log.debug("Issue auth session: started. User ID: '%s'.", user_id.value)
5252

5353
auth_session_id: str = self._auth_session_id_generator()
5454
expiration: datetime = self._auth_session_timer.auth_session_expiration
@@ -68,7 +68,7 @@ async def create_session(self, user_id: UserId) -> None:
6868
self._auth_session_transport.deliver(auth_session)
6969

7070
log.debug(
71-
"Create auth session: done. User ID: '%s', Auth session id: '%s'.",
71+
"Issue auth session: done. User ID: '%s', Auth session ID: '%s'.",
7272
user_id.value,
7373
auth_session.id_,
7474
)
@@ -79,111 +79,113 @@ async def get_authenticated_user_id(self) -> UserId:
7979
"""
8080
log.debug("Get authenticated user ID: started.")
8181

82-
raw_auth_session = await self._load_current_session()
82+
raw_auth_session = await self._get_current_auth_session()
8383
valid_auth_session = await self._validate_and_extend_session(raw_auth_session)
84+
self._cached_auth_session = valid_auth_session
8485

8586
log.debug(
86-
"Get authenticated user ID: done. Auth session ID: %s. User ID: %s.",
87+
"Get authenticated user ID: done. Auth session ID: '%s'. User ID: '%s'.",
8788
valid_auth_session.id_,
8889
valid_auth_session.user_id.value,
8990
)
9091
return valid_auth_session.user_id
9192

92-
async def invalidate_current_session(self) -> None:
93-
log.debug("Invalidate current session: started. Auth session ID: unknown.")
93+
async def terminate_current_session(self) -> None:
94+
log.debug("Terminate current session: started. Auth session ID: unknown.")
9495

95-
auth_session_id: str | None = self._auth_session_transport.extract_id()
96-
if auth_session_id is None:
97-
log.warning(
98-
"Invalidate current session failed: partially failed. "
99-
"Session ID can't be extracted from transport. "
100-
"Auth session can't be identified.",
96+
auth_session_id: str | None
97+
if self._cached_auth_session is not None:
98+
auth_session_id = self._cached_auth_session.id_
99+
log.debug(
100+
"Terminate current session: using ID from cache. "
101+
"Auth session ID: '%s'.",
102+
auth_session_id,
103+
)
104+
else:
105+
auth_session_id = self._auth_session_transport.extract_id()
106+
if auth_session_id is None:
107+
log.warning(
108+
"Terminate current session failed: partially failed. "
109+
"Session ID can't be extracted from transport. "
110+
"Auth session can't be identified.",
111+
)
112+
return
113+
log.debug(
114+
"Terminate current session: using ID from transport. "
115+
"Auth session ID: '%s'.",
116+
auth_session_id,
101117
)
102-
return
103-
104-
log.debug(
105-
"Invalidate current session: in progress. Auth session id: %s.",
106-
auth_session_id,
107-
)
108118

109119
self._auth_session_transport.remove_current()
110120

111-
auth_session: AuthSession | None = None
112-
try:
113-
auth_session = await self._auth_session_gateway.read_by_id(auth_session_id)
114-
115-
except DataMapperError as error:
116-
log.error("%s: '%s'", AUTH_SESSION_EXTRACTION_FAILED, error)
117-
118-
if auth_session is None:
119-
log.warning(
120-
"Invalidate current session failed: partially failed. "
121-
"Session ID was removed from transport, "
122-
"but auth session was not found in storage.",
123-
)
124-
return
125-
126121
try:
127-
await self._auth_session_gateway.delete(auth_session.id_)
122+
await self._auth_session_gateway.delete(auth_session_id)
128123
await self._auth_transaction_manager.commit()
124+
log.debug(
125+
"Terminate current session: done (transport cleared, storage deleted). "
126+
"Auth session ID: '%s'.",
127+
auth_session_id,
128+
)
129129

130130
except DataMapperError:
131131
log.warning(
132-
(
133-
"Invalidate current session failed: partially failed. "
134-
"Session ID was removed from transport, "
135-
"but auth session was not deleted from storage. "
136-
"Auth session ID: '%s'."
137-
),
138-
auth_session.id_,
132+
"Terminate current session: partially failed "
133+
"(transport cleared, storage delete failed). "
134+
"Auth session ID: '%s'.",
135+
auth_session_id,
139136
)
140137

141-
async def invalidate_all_sessions_for_user(self, user_id: UserId) -> None:
138+
self._cached_auth_session = None
139+
140+
async def terminate_all_sessions_for_user(self, user_id: UserId) -> None:
142141
"""
143142
:raises DataMapperError:
144143
"""
145144
log.debug(
146-
"Invalidate all sessions for user: started. User id: '%s'.",
145+
"Terminate all sessions for user: started. User ID: '%s'.",
147146
user_id.value,
148147
)
149148

150149
await self._auth_session_gateway.delete_all_for_user(user_id)
151150
await self._auth_transaction_manager.commit()
152151

152+
if self._cached_auth_session and self._cached_auth_session.user_id == user_id:
153+
self._auth_session_transport.remove_current()
154+
self._cached_auth_session = None
155+
153156
log.debug(
154-
"Invalidate all sessions for user: done. User id: '%s'.",
157+
"Terminate all sessions for user: done. User ID: '%s'.",
155158
user_id.value,
156159
)
157160

158-
async def _load_current_session(self) -> AuthSession:
161+
async def _get_current_auth_session(self) -> AuthSession:
159162
"""
160163
:raises AuthenticationError:
161164
"""
162-
log.debug("Load current auth session: started. Auth session id: unknown.")
165+
log.debug("Get current auth session: started. Auth session ID: unknown.")
166+
163167
if self._cached_auth_session is not None:
164-
cached_auth_session = self._cached_auth_session
165168
log.debug(
166-
"Load current auth session: done (from cache). Auth session id: %s.",
167-
cached_auth_session.id_,
169+
"Get current auth session: done (from cache). Auth session ID: '%s'.",
170+
self._cached_auth_session.id_,
168171
)
169-
return cached_auth_session
172+
return self._cached_auth_session
170173

171174
auth_session_id: str | None = self._auth_session_transport.extract_id()
172175
if auth_session_id is None:
173176
log.debug(AUTH_SESSION_NOT_FOUND)
174177
raise AuthenticationError(AUTH_NOT_AUTHENTICATED)
175178

176179
log.debug(
177-
"Load current auth session: in progress. Auth session id: %s.",
180+
"Get current auth session: reading from storage. Auth session ID: '%s'.",
178181
auth_session_id,
179182
)
180183

181184
try:
182185
auth_session: (
183186
AuthSession | None
184-
) = await self._auth_session_gateway.read_by_id(
185-
auth_session_id,
186-
)
187+
) = await self._auth_session_gateway.read_by_id(auth_session_id)
188+
187189
except DataMapperError as error:
188190
log.error("%s: '%s'", AUTH_SESSION_EXTRACTION_FAILED, error)
189191
raise AuthenticationError(AUTH_NOT_AUTHENTICATED) from error
@@ -192,11 +194,8 @@ async def _load_current_session(self) -> AuthSession:
192194
log.debug(AUTH_SESSION_NOT_FOUND)
193195
raise AuthenticationError(AUTH_NOT_AUTHENTICATED)
194196

195-
self._cached_auth_session = auth_session
196-
197197
log.debug(
198-
"Load current auth session: done. Auth session id: %s.",
199-
auth_session.id_,
198+
"Get current auth session: done. Auth session ID: '%s'.", auth_session.id_
200199
)
201200
return auth_session
202201

@@ -208,7 +207,7 @@ async def _validate_and_extend_session(
208207
:raises AuthenticationError:
209208
"""
210209
log.debug(
211-
"Validate and extend auth session: started. Auth session id: %s.",
210+
"Validate and extend auth session: started. Auth session ID: '%s'.",
212211
auth_session.id_,
213212
)
214213

@@ -223,7 +222,7 @@ async def _validate_and_extend_session(
223222
):
224223
log.debug(
225224
"Validate and extend auth session: validated without extension. "
226-
"Auth session id: %s.",
225+
"Auth session ID: '%s'.",
227226
auth_session.id_,
228227
)
229228
return auth_session
@@ -242,10 +241,10 @@ async def _validate_and_extend_session(
242241

243242
self._auth_session_transport.deliver(auth_session)
244243

245-
self._cached_auth_session = auth_session
246-
247244
log.debug(
248-
"Validate and extend auth session: done. Auth session id: %s.",
245+
"Validate and extend auth session: done. "
246+
"Auth session ID: '%s'. New expiration: '%s'.",
249247
auth_session.id_,
248+
auth_session.expiration.isoformat(),
250249
)
251250
return auth_session

src/app/infrastructure/persistence_sqla/provider.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ async def get_main_async_session(
5959
async with async_session_factory() as session:
6060
log.debug("Main async session started.")
6161
yield cast(MainAsyncSession, session)
62-
log.debug("Closing async session.")
62+
log.debug("Closing Main async session.")
6363
log.debug("Main async session closed.")
6464

6565

@@ -69,7 +69,7 @@ async def get_auth_async_session(
6969
"""Provides UoW (AsyncSession) for the auth context."""
7070
log.debug("Starting Auth async session...")
7171
async with async_session_factory() as session:
72-
log.debug("Async session started for Auth.")
72+
log.debug("Auth async session started.")
7373
yield cast(AuthAsyncSession, session)
74-
log.debug("Closing async session.")
75-
log.debug("Async session closed for Auth.")
74+
log.debug("Closing Auth async session.")
75+
log.debug("Auth async session closed.")

0 commit comments

Comments
 (0)