@@ -230,6 +230,12 @@ def utcnow():
230230 return datetime .datetime .now (datetime .timezone .utc )
231231
232232
233+ def b64_decode_padding (s ):
234+ N = 4
235+ extra = (N - (len (s ) % N )) % N
236+ return base64 .b64decode (s + '=' * extra )
237+
238+
233239SIGNING_KEY = 'a' * 32
234240GITHUB_SECRET = 'b' * 32
235241GOOGLE_SECRET = 'c' * 32
@@ -3399,6 +3405,15 @@ async def test_http_auth_ext_token_01(self):
33993405 refresh_token = "a_refresh_token" ,
34003406 id_token = "an_id_token" ,
34013407 )
3408+ # Some other user
3409+ other_user = await self .con .query_single (
3410+ """
3411+ insert ext::auth::Identity {
3412+ issuer := "https://example.com",
3413+ subject := "foobaz",
3414+ }
3415+ """
3416+ )
34023417
34033418 # Correct code, random verifier
34043419 (_ , _ , wrong_verifier_status ) = self .http_con_request (
@@ -3429,16 +3444,73 @@ async def test_http_auth_ext_token_01(self):
34293444
34303445 self .assertEqual (status , 200 , body )
34313446 body_json = json .loads (body )
3447+ auth_token = body_json ["auth_token" ]
3448+
34323449 self .assertEqual (
34333450 body_json ,
34343451 {
3435- "auth_token" : body_json [ " auth_token" ] ,
3452+ "auth_token" : auth_token ,
34363453 "identity_id" : str (pkce .identity_id ),
34373454 "provider_token" : "a_provider_token" ,
34383455 "provider_refresh_token" : "a_refresh_token" ,
34393456 "provider_id_token" : "an_id_token" ,
34403457 },
34413458 )
3459+
3460+ # Check that the client_token and ClientTokenIdentity
3461+ # works! I'm not sure if this is the simplest/best
3462+ # place to do these checks, but it seems to work
3463+ # (-sully)
3464+ await self .con .execute (
3465+ '''
3466+ set global ext::auth::client_token := <str>$0;
3467+ ''' ,
3468+ auth_token ,
3469+ )
3470+ user = await self .con .query_single ('''
3471+ select global ext::auth::ClientTokenIdentity { ** }
3472+ ''' )
3473+ await self .con .execute (
3474+ '''
3475+ reset global ext::auth::client_token
3476+ ''' ,
3477+ )
3478+
3479+ self .assertEqual (user .subject , "abcdefg" )
3480+
3481+ # Turn the real auth token into a fake auth token for
3482+ # a different user.
3483+ parts = auth_token .split ('.' )
3484+ claims_bytes = b64_decode_padding (parts [1 ])
3485+ claims = json .loads (claims_bytes )
3486+ claims ['sub' ] = str (other_user .id )
3487+ fake_claim_str = base64 .urlsafe_b64encode (
3488+ json .dumps (claims ).encode ('utf-8' )
3489+ ).decode ('ascii' )
3490+ parts [1 ] = fake_claim_str
3491+ fake_auth_token = '.' .join (parts )
3492+
3493+ # Try to use the fake auth token and make sure it fails!
3494+ await self .con .execute (
3495+ '''
3496+ set global ext::auth::client_token := <str>$0;
3497+ ''' ,
3498+ fake_auth_token ,
3499+ )
3500+ with self .assertRaisesRegex (
3501+ QueryAssertionError ,
3502+ "signature mismatch" ,
3503+ ):
3504+ await self .con .query_single ('''
3505+ select global ext::auth::ClientTokenIdentity { ** }
3506+ ''' )
3507+ await self .con .execute (
3508+ '''
3509+ reset global ext::auth::client_token
3510+ ''' ,
3511+ )
3512+
3513+ # Check the webhooks
34423514 async for tr in self .try_until_succeeds (
34433515 delay = 2 , timeout = 120 , ignore = (KeyError , AssertionError )
34443516 ):
0 commit comments