tangled
alpha
login
or
join now
futur.blue
/
pegasus
56
fork
atom
objective categorical abstract machine language personal data server
56
fork
atom
overview
issues
2
pulls
pipelines
Use more accurate auth error names
futur.blue
2 months ago
c43ec295
7e1604c6
verified
This commit was signed with the committer's
known signature
.
futur.blue
SSH Key Fingerprint:
SHA256:QHGqHWNpqYyw9bt8KmPuJIyeZX9SZewBZ0PR1COtKQ0=
+77
-59
1 changed file
expand all
collapse all
unified
split
pegasus
lib
auth.ml
+77
-59
pegasus/lib/auth.ml
···
34
34
else if jwt.sub = "" then Lwt.return_error "missing sub"
35
35
else if now_s < jwt.iat then
36
36
Lwt.return_error "token issued in the future"
37
37
-
else if now_s > jwt.exp then Lwt.return_error "expired token"
37
37
+
else if now_s > jwt.exp then Lwt.return_error "ExpiredToken"
38
38
else if jwt.scope <> expected_scope then
39
39
Lwt.return_error "invalid scope"
40
40
else if jwt.jti = "" then Lwt.return_error "missing jti"
···
42
42
let%lwt revoked_at =
43
43
Data_store.is_token_revoked t ~did:jwt.sub ~jti:jwt.jti
44
44
in
45
45
-
if revoked_at <> None then Lwt.return_error "token revoked"
45
45
+
if revoked_at <> None then Lwt.return_error "ExpiredToken"
46
46
else Lwt.return_ok jwt
47
47
with _ -> Lwt.return_error "invalid token format" )
48
48
···
219
219
| "admin", p when p = Env.admin_password ->
220
220
Lwt.return_ok Admin
221
221
| _ ->
222
222
-
Lwt.return_error @@ Errors.auth_required "invalid credentials" )
222
222
+
Lwt.return_error @@ Errors.invalid_request "invalid credentials" )
223
223
| Error _ ->
224
224
Lwt.return_error @@ Errors.auth_required "invalid authorization header"
225
225
···
234
234
Lwt.return_ok (Access {did})
235
235
| Some {deactivated_at= Some _; _} ->
236
236
Lwt.return_error
237
237
-
@@ Errors.auth_required ~name:"AccountDeactivated"
237
237
+
@@ Errors.invalid_request ~name:"AccountDeactivated"
238
238
"account is deactivated"
239
239
| None ->
240
240
-
Lwt.return_error @@ Errors.auth_required "invalid credentials" )
240
240
+
Lwt.return_error
241
241
+
@@ Errors.internal_error ~msg:"invalid credentials" () )
242
242
+
| Error "ExpiredToken" ->
243
243
+
Lwt.return_error
244
244
+
@@ Errors.invalid_request ~name:"ExpiredToken" "token expired"
241
245
| Error _ ->
242
242
-
Lwt.return_error @@ Errors.auth_required "invalid credentials" )
246
246
+
Lwt.return_error
247
247
+
@@ Errors.invalid_request ~name:"InvalidToken" "invalid credentials" )
243
248
| Error _ ->
244
249
Lwt.return_error @@ Errors.auth_required "invalid authorization header"
245
250
···
297
302
let scopes = Oauth.Scopes.of_string scope_str in
298
303
let now = int_of_float (Unix.gettimeofday ()) in
299
304
if jkt_claim <> proof.jkt then
300
300
-
Lwt.return_error @@ Errors.auth_required "dpop key mismatch"
305
305
+
Lwt.return_error @@ Errors.invalid_request "dpop key mismatch"
301
306
else if exp < now then
302
302
-
Lwt.return_error @@ Errors.auth_required "token expired"
307
307
+
Lwt.return_error
308
308
+
@@ Errors.invalid_request ~name:"ExpiredToken" "token expired"
303
309
else if not (Oauth.Scopes.has_atproto scopes) then
304
310
Lwt.return_error
305
305
-
@@ Errors.auth_required ~name:"InvalidToken"
311
311
+
@@ Errors.invalid_request ~name:"InvalidToken"
306
312
"oauth token missing 'atproto' scope"
307
313
else
308
314
let%lwt session =
···
311
317
Lwt.return_ok sess
312
318
with _ ->
313
319
Lwt.return_error
314
314
-
@@ Errors.auth_required "invalid credentials"
320
320
+
@@ Errors.internal_error ~msg:"invalid credentials" ()
315
321
in
316
322
match session with
317
323
| Ok {active= Some true; _} ->
318
324
Lwt.return_ok (OAuth {did; proof; scopes})
319
325
| Ok _ ->
320
326
Lwt.return_error
321
321
-
@@ Errors.auth_required ~name:"AccountDeactivated"
327
327
+
@@ Errors.invalid_request ~name:"AccountDeactivated"
322
328
"account is deactivated"
323
329
| Error _ ->
324
330
Lwt.return_error
325
325
-
@@ Errors.auth_required "invalid credentials"
331
331
+
@@ Errors.internal_error ~msg:"invalid credentials" ()
326
332
with _ ->
327
333
Lwt.return_error @@ Errors.auth_required "malformed JWT claims" )
328
334
) )
···
341
347
raise (Errors.Redirect "/account")
342
348
| Some {deactivated_at= Some _; _} ->
343
349
Lwt.return_error
344
344
-
@@ Errors.auth_required ~name:"AccountDeactivated"
350
350
+
@@ Errors.invalid_request ~name:"AccountDeactivated"
345
351
"account is deactivated"
346
352
| None ->
347
353
let%lwt () = Session.Raw.clear_session req in
348
348
-
Lwt.return_error @@ Errors.auth_required "no active session" )
354
354
+
Lwt.return_error @@ Errors.internal_error ~msg:"no active session" ()
355
355
+
)
349
356
| None ->
350
357
Lwt.return_error @@ Errors.auth_required "no active session"
351
358
···
360
367
Lwt.return_ok (Refresh {did; jti})
361
368
| Some {deactivated_at= Some _; _} ->
362
369
Lwt.return_error
363
363
-
@@ Errors.auth_required ~name:"AccountDeactivated"
370
370
+
@@ Errors.invalid_request ~name:"AccountDeactivated"
364
371
"account is deactivated"
365
372
| None ->
366
366
-
Lwt.return_error @@ Errors.auth_required "invalid credentials" )
367
367
-
| Error "" | Error _ ->
368
368
-
Lwt.return_error @@ Errors.auth_required "invalid credentials" )
373
373
+
Lwt.return_error
374
374
+
@@ Errors.internal_error ~msg:"invalid credentials" () )
375
375
+
| Error "ExpiredToken" ->
376
376
+
Lwt.return_error
377
377
+
@@ Errors.invalid_request ~name:"ExpiredToken" "token expired"
378
378
+
| Error _ ->
379
379
+
Lwt.return_error
380
380
+
@@ Errors.invalid_request ~name:"InvalidToken" "invalid credentials" )
369
381
| Error _ ->
370
382
Lwt.return_error @@ Errors.auth_required "invalid authorization header"
371
383
···
376
388
Lwt.return_ok (Access {did})
377
389
| Some {deactivated_at= Some _; _} ->
378
390
Lwt.return_error
379
379
-
@@ Errors.auth_required ~name:"AccountDeactivated"
391
391
+
@@ Errors.invalid_request ~name:"AccountDeactivated"
380
392
"account is deactivated"
381
393
| None ->
382
382
-
Lwt.return_error @@ Errors.auth_required "invalid credentials"
394
394
+
Lwt.return_error
395
395
+
@@ Errors.internal_error ~msg:"invalid credentials" ()
383
396
in
384
397
let verify_with_key token pubkey_multibase did db =
385
385
-
let pubkey =
386
386
-
Kleidos.parse_multikey_str pubkey_multibase
387
387
-
in
398
398
+
let pubkey = Kleidos.parse_multikey_str pubkey_multibase in
388
399
match Jwt.verify_jwt token ~pubkey with
389
400
| Ok _ ->
390
401
check_actor_status did db
391
402
| Error e ->
392
403
Dream.debug (fun log -> log "service jwt verification failed: %s" e) ;
393
404
Lwt.return_error
394
394
-
@@ Errors.auth_required "jwt signature does not match jwt issuer"
405
405
+
@@ Errors.invalid_request ~name:"InvalidToken"
406
406
+
"jwt signature does not match jwt issuer"
395
407
in
396
408
fun {req; db} ->
397
409
match parse_bearer req with
···
410
422
let lxm = payload |> member "lxm" |> to_string_option in
411
423
let now = int_of_float (Unix.gettimeofday ()) in
412
424
if exp < now then
413
413
-
Lwt.return_error @@ Errors.auth_required "jwt expired"
425
425
+
Lwt.return_error
426
426
+
@@ Errors.invalid_request ~name:"ExpiredToken" "token expired"
414
427
else if aud <> Env.did then
415
428
Lwt.return_error
416
416
-
@@ Errors.auth_required "jwt audience does not match service did"
429
429
+
@@ Errors.invalid_request ~name:"InvalidToken"
430
430
+
"jwt audience does not match service did"
417
431
else
418
432
let nsid =
419
433
(Dream.path [@warning "-3"]) req |> List.rev |> List.hd
420
434
in
421
421
-
( match lxm with
435
435
+
match lxm with
422
436
| Some l when l <> nsid && l <> "*" ->
423
437
Lwt.return_error
424
424
-
@@ Errors.auth_required
438
438
+
@@ Errors.invalid_request ~name:"InvalidToken"
425
439
("jwt lxm " ^ l ^ " does not match " ^ nsid)
426
426
-
| _ ->
440
440
+
| _ -> (
427
441
let did =
428
442
match String.split_on_char '#' iss with
429
443
| did :: _ ->
···
431
445
| [] ->
432
446
iss
433
447
in
434
434
-
( match%lwt Id_resolver.Did.resolve did with
448
448
+
match%lwt Id_resolver.Did.resolve did with
435
449
| Error e ->
436
450
Dream.debug (fun log ->
437
451
log "failed to resolve did %s: %s" did e ) ;
438
452
Lwt.return_error
439
439
-
@@ Errors.auth_required "could not resolve issuer did"
453
453
+
@@ Errors.internal_error
454
454
+
~msg:"could not resolve jwt issuer did" ()
440
455
| Ok did_doc -> (
441
456
match
442
457
Id_resolver.Did.Document.get_verification_key did_doc
···
444
459
with
445
460
| None ->
446
461
Lwt.return_error
447
447
-
@@ Errors.auth_required
448
448
-
"missing or bad key in issuer did doc"
462
462
+
@@ Errors.internal_error
463
463
+
~msg:"missing or bad key in issuer did doc" ()
449
464
| Some pubkey_multibase -> (
450
450
-
match%lwt verify_with_key token pubkey_multibase did db with
465
465
+
match%lwt
466
466
+
verify_with_key token pubkey_multibase did db
467
467
+
with
451
468
| Ok creds ->
452
469
Lwt.return_ok creds
453
453
-
| Error _ ->
454
454
-
(* try again, skipping cache in case of key rotation *)
455
455
-
( match%lwt
456
456
-
Id_resolver.Did.resolve ~skip_cache:true did
457
457
-
with
458
458
-
| Error _ ->
470
470
+
| Error _ -> (
471
471
+
(* try again, skipping cache in case of key rotation *)
472
472
+
match%lwt
473
473
+
Id_resolver.Did.resolve ~skip_cache:true did
474
474
+
with
475
475
+
| Error _ ->
476
476
+
Lwt.return_error
477
477
+
@@ Errors.invalid_request ~name:"InvalidToken"
478
478
+
"jwt signature does not match jwt issuer"
479
479
+
| Ok fresh_doc -> (
480
480
+
match
481
481
+
Id_resolver.Did.Document.get_verification_key
482
482
+
fresh_doc "#atproto"
483
483
+
with
484
484
+
| None ->
459
485
Lwt.return_error
460
460
-
@@ Errors.auth_required
486
486
+
@@ Errors.invalid_request ~name:"InvalidToken"
461
487
"jwt signature does not match jwt issuer"
462
462
-
| Ok fresh_doc -> (
463
463
-
match
464
464
-
Id_resolver.Did.Document.get_verification_key
465
465
-
fresh_doc "#atproto"
466
466
-
with
467
467
-
| None ->
468
468
-
Lwt.return_error
469
469
-
@@ Errors.auth_required
470
470
-
"jwt signature does not match jwt issuer"
471
471
-
| Some fresh_pubkey_multibase
472
472
-
when fresh_pubkey_multibase = pubkey_multibase ->
473
473
-
Lwt.return_error
474
474
-
@@ Errors.auth_required
475
475
-
"jwt signature does not match jwt issuer"
476
476
-
| Some fresh_pubkey_multibase ->
477
477
-
verify_with_key token fresh_pubkey_multibase did
478
478
-
db ) ) ) ) ) )
488
488
+
| Some fresh_pubkey_multibase
489
489
+
when fresh_pubkey_multibase = pubkey_multibase ->
490
490
+
Lwt.return_error
491
491
+
@@ Errors.invalid_request ~name:"InvalidToken"
492
492
+
"jwt signature does not match jwt issuer"
493
493
+
| Some fresh_pubkey_multibase ->
494
494
+
verify_with_key token fresh_pubkey_multibase did
495
495
+
db ) ) ) ) )
479
496
with _ ->
480
480
-
Lwt.return_error @@ Errors.auth_required "malformed service jwt" ) )
497
497
+
Lwt.return_error @@ Errors.invalid_request "malformed service jwt" )
498
498
+
)
481
499
482
500
let authorization : verifier =
483
501
fun ctx ->