Skip to content

Commit 52241f7

Browse files
committed
fix(cloud_auth): Properly set/check session duration
Fixes a bug where the session token was not being updated with the correct session duration.
1 parent e62c585 commit 52241f7

26 files changed

+6145
-121
lines changed

services/celest_cloud_auth/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.2
2+
3+
- fix: Properly set/check session duration
4+
15
## 0.3.1
26

37
- fix: Allow dashes in routes

services/celest_cloud_auth/drift_schema/auth_database/drift_schema_v5.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

services/celest_cloud_auth/lib/celest_cloud_auth.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ final class CelestCloudAuth {
104104
issuer: context.rootEntity,
105105
routeMap: routeMap,
106106
corks: corks,
107+
cryptoKeys: cryptoKeys,
108+
users: users,
107109
db: db,
108110
authorizer: authorizer,
109111
);
@@ -162,6 +164,8 @@ final class CelestCloudAuth {
162164
routeMap: routeMap,
163165
authorizer: authorizer,
164166
corks: corks,
167+
cryptoKeys: cryptoKeys,
168+
users: users,
165169
db: db,
166170
);
167171

services/celest_cloud_auth/lib/src/authentication/authentication_model.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,13 @@ final class SessionStateSuccess extends SessionState {
177177

178178
factory SessionStateSuccess.fromProto(pb.AuthenticationSuccess success) {
179179
return SessionStateSuccess(
180-
cork: Cork.parse(success.identityToken),
180+
cork: CedarCork.parse(success.identityToken),
181181
user: success.user.toModel(),
182182
isNewUser: success.isNewUser,
183183
);
184184
}
185185

186-
final Cork cork;
186+
final CedarCork cork;
187187
String get identityToken => cork.toString();
188188

189189
final User user;

services/celest_cloud_auth/lib/src/authentication/authentication_service.dart

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:celest_ast/celest_ast.dart';
55
import 'package:celest_cloud/src/proto.dart' as pb;
66
import 'package:celest_cloud_auth/src/authorization/authorization_middleware.dart';
77
import 'package:celest_cloud_auth/src/authorization/authorizer.dart';
8+
import 'package:celest_cloud_auth/src/authorization/celest_role.dart';
89
import 'package:celest_cloud_auth/src/authorization/corks_repository.dart';
910
import 'package:celest_cloud_auth/src/context.dart';
1011
import 'package:celest_cloud_auth/src/crypto/crypto_key_repository.dart';
@@ -16,6 +17,7 @@ import 'package:celest_cloud_auth/src/sessions/sessions_repository.dart';
1617
import 'package:celest_cloud_auth/src/users/users_repository.dart';
1718
import 'package:celest_cloud_auth/src/util/typeid.dart';
1819
import 'package:celest_core/celest_core.dart';
20+
import 'package:clock/clock.dart';
1921
import 'package:corks_cedar/corks_cedar.dart';
2022
import 'package:meta/meta.dart';
2123
import 'package:shelf/shelf.dart';
@@ -137,6 +139,8 @@ extension type AuthenticationService._(_Deps _deps) implements Object {
137139
final requestAuthorizer = AuthorizationMiddleware(
138140
routeMap: _deps.routeMap,
139141
corks: _deps.corks,
142+
cryptoKeys: _deps.cryptoKeys,
143+
users: _deps.users,
140144
db: _deps.db,
141145
authorizer: _deps.authorizer,
142146
issuer: _deps.issuer,
@@ -275,19 +279,19 @@ extension type AuthenticationService._(_Deps _deps) implements Object {
275279
throw InternalServerError('Unknown user: ${session.userId}');
276280
}
277281

278-
final isNewUser = user.roles.contains(
279-
const EntityUid.of('Celest::Role', 'anonymous'),
280-
);
282+
final isNewUser = user.roles.contains(CelestRole.anonymous);
281283
if (isNewUser) {
282284
user = await _users.updateUser(
283285
userId: session.userId,
284286
factor: factor,
285-
roles: const [EntityUid.of('Celest::Role', 'authenticated')],
287+
roles: const [CelestRole.authenticated],
286288
);
287289
}
288290
final cork = await _corks.createCork(
291+
session: session.copyWith(
292+
expireTime: clock.now().add(SessionsRepository.postAuthSessionDuration),
293+
),
289294
user: user,
290-
session: session,
291295
);
292296
return SessionStateSuccess(
293297
cork: cork,
@@ -317,7 +321,7 @@ extension type AuthenticationService._(_Deps _deps) implements Object {
317321
'Failed to send OTP. Please restart the authentication flow.',
318322
);
319323
}
320-
final resendIn = nextResend.difference(DateTime.timestamp());
324+
final resendIn = nextResend.difference(clock.now());
321325
throw ResourceExhaustedException(
322326
'Failed to send OTP. Try again in ${resendIn.inSeconds} seconds',
323327
);
@@ -334,7 +338,7 @@ extension type AuthenticationService._(_Deps _deps) implements Object {
334338
// 'Failed to send OTP. Please restart the authentication flow.',
335339
// );
336340
// }
337-
// final resendIn = nextResend.difference(DateTime.timestamp());
341+
// final resendIn = nextResend.difference(clock.now());
338342
// throw ResourceExhaustedException(
339343
// 'Failed to send OTP. Try again in ${resendIn.inSeconds} seconds',
340344
// );
@@ -358,7 +362,7 @@ extension type AuthenticationService._(_Deps _deps) implements Object {
358362
SessionStatePendingConfirmation? confirmation,
359363
AuthenticationFactor? resend,
360364
}) async {
361-
var session = await _db.cloudAuthCoreDrift
365+
final session = await _db.cloudAuthCoreDrift
362366
.getSession(sessionId: sessionId.encoded)
363367
.getSingleOrNull();
364368
if (session == null) {
@@ -386,11 +390,14 @@ extension type AuthenticationService._(_Deps _deps) implements Object {
386390
null => throw StateError('Unexpected state'),
387391
};
388392

389-
session = await _sessions.updateSession(
393+
return _sessions.updateSession(
390394
session: session,
391395
state: updatedState,
396+
sessionDuration: switch (updatedState) {
397+
SessionStateSuccess() => SessionsRepository.postAuthSessionDuration,
398+
_ => SessionsRepository.preAuthSessionDuration,
399+
},
392400
);
393-
return session.copyWith(sessionToken: sessionToken);
394401
}
395402

396403
Future<Response> handleContinueSession(Request request) async {

services/celest_cloud_auth/lib/src/authorization/authorization_middleware.dart

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import 'package:celest/http.dart';
33
import 'package:celest_cloud_auth/src/authorization/authorizer.dart';
44
import 'package:celest_cloud_auth/src/authorization/corks_repository.dart';
55
import 'package:celest_cloud_auth/src/context.dart';
6+
import 'package:celest_cloud_auth/src/crypto/crypto_key_repository.dart';
67
import 'package:celest_cloud_auth/src/database/auth_database_accessors.dart';
78
import 'package:celest_cloud_auth/src/http/http_helpers.dart';
89
import 'package:celest_cloud_auth/src/model/interop.dart';
910
import 'package:celest_cloud_auth/src/model/route_map.dart';
11+
import 'package:celest_cloud_auth/src/sessions/sessions_repository.dart';
12+
import 'package:celest_cloud_auth/src/users/users_repository.dart';
13+
import 'package:celest_cloud_auth/src/util/typeid.dart';
1014
import 'package:celest_core/celest_core.dart' as core;
1115
import 'package:celest_core/celest_core.dart';
1216
import 'package:collection/collection.dart';
@@ -17,6 +21,8 @@ import 'package:shelf/shelf.dart' show Handler, Request;
1721
typedef _Deps = ({
1822
RouteMap routeMap,
1923
CorksRepository corks,
24+
CryptoKeyRepository cryptoKeys,
25+
UsersRepository users,
2026
CloudAuthDatabaseMixin db,
2127
Authorizer authorizer,
2228
EntityUid issuer,
@@ -30,13 +36,17 @@ extension type AuthorizationMiddleware._(_Deps _deps) implements Object {
3036
AuthorizationMiddleware({
3137
required RouteMap routeMap,
3238
required CorksRepository corks,
39+
required CryptoKeyRepository cryptoKeys,
40+
required UsersRepository users,
3341
required CloudAuthDatabaseMixin db,
3442
required Authorizer authorizer,
3543
required EntityUid issuer,
3644
}) : this._(
3745
(
3846
routeMap: routeMap,
3947
corks: corks,
48+
cryptoKeys: cryptoKeys,
49+
users: users,
4050
db: db,
4151
authorizer: authorizer,
4252
issuer: issuer,
@@ -47,6 +57,12 @@ extension type AuthorizationMiddleware._(_Deps _deps) implements Object {
4757
CorksRepository get _corks => _deps.corks;
4858
CloudAuthDatabaseAccessors get _db => _deps.db.cloudAuth;
4959
Authorizer get _authorizer => _deps.authorizer;
60+
SessionsRepository get _sessions => SessionsRepository(
61+
corks: _corks,
62+
db: _deps.db,
63+
cryptoKeys: _deps.cryptoKeys,
64+
users: _deps.users,
65+
);
5066

5167
Handler call(Handler inner) {
5268
return (request) async {
@@ -129,13 +145,20 @@ extension type AuthorizationMiddleware._(_Deps _deps) implements Object {
129145
context.put(contextKeyCork, cork);
130146
switch (cork.bearer) {
131147
case EntityUid(type: 'Celest::Session', id: final sessionId):
132-
final session = await _db.getSession(sessionId: sessionId);
148+
final sessionTid = TypeId.tryDecode<Session>(sessionId);
149+
if (sessionTid == null) {
150+
context.logger.severe('Invalid session ID: $sessionId');
151+
throw const UnauthorizedException('Invalid session ID');
152+
}
153+
final session = await _sessions.getSession(
154+
sessionId: sessionTid,
155+
);
133156
if (session == null) {
134-
throw const UnauthorizedException('Invalid session');
157+
throw UnauthorizedException('Invalid session: $sessionId');
135158
}
136159
final user = await _db.getUser(userId: session.userId);
137160
if (user == null) {
138-
throw const UnauthorizedException('Invalid user');
161+
throw UnauthorizedException('Invalid user: ${session.userId}');
139162
}
140163
context.logger.finest('Found user for cork: $user');
141164
return (user, user.toEntity());

services/celest_cloud_auth/lib/src/authorization/corks_repository.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:celest_cloud_auth/src/database/schema/cloud_auth_core.drift.dart
88
as drift;
99
import 'package:celest_cloud_auth/src/model/interop.dart';
1010
import 'package:celest_core/celest_core.dart';
11+
import 'package:clock/clock.dart';
1112
import 'package:corks_cedar/corks_cedar.dart';
1213
import 'package:drift/drift.dart' as drift;
1314

@@ -41,7 +42,7 @@ extension type CorksRepository._(_Dependencies _deps) implements Object {
4142
}
4243

4344
/// Creates a new cork for the given [user].
44-
Future<Cork> createCork({
45+
Future<CedarCork> createCork({
4546
required Session session,
4647
required User user,
4748
EntityUid? audience,
@@ -88,7 +89,7 @@ extension type CorksRepository._(_Dependencies _deps) implements Object {
8889
expireTime: expireTime,
8990
);
9091
});
91-
return cork;
92+
return CedarCork(cork);
9293
}
9394

9495
/// Verifies the given [cork].
@@ -115,7 +116,7 @@ extension type CorksRepository._(_Dependencies _deps) implements Object {
115116
..where((tbl) => tbl.corkId.equals(cork.id));
116117
await query.write(
117118
drift.CloudAuthCorksCompanion(
118-
lastUseTime: drift.Value(DateTime.timestamp()),
119+
lastUseTime: drift.Value(clock.now()),
119120
),
120121
);
121122
} on Object catch (e, st) {

services/celest_cloud_auth/lib/src/database/auth_database.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class CloudAuthDatabase extends $CloudAuthDatabase with CloudAuthDatabaseMixin {
5757
final ResolvedProject? _project;
5858

5959
@override
60-
int get schemaVersion => 4;
60+
int get schemaVersion => 5;
6161

6262
@override
6363
MigrationStrategy get migration {

0 commit comments

Comments
 (0)