@@ -57,6 +57,7 @@ interface TokenResponse {
5757export type UmaVerificationOptions = Omit < JWTVerifyOptions , 'iss' | 'aud' | 'sub' | 'iat' > ;
5858
5959const UMA_DISCOVERY = '/.well-known/uma2-configuration' ;
60+ const PAT_EVENT = 'PAT_EVENT' ;
6061
6162const REQUIRED_METADATA = [
6263 'issuer' ,
@@ -75,10 +76,12 @@ const REQUIRED_METADATA = [
7576export class UmaClient implements SingleThreaded {
7677 protected readonly logger = getLoggerFor ( this ) ;
7778
78- // Keeps track of resources that are being registered to prevent duplicate registration calls.
79- protected readonly inProgressResources : Set < string > = new Set ( ) ;
80- // Used to notify when registration finished for a resource. The event will be the identifier of the resource.
81- protected readonly registerEmitter : EventEmitter = new EventEmitter ( ) ;
79+ /* Keeps track of resources that are being registered to prevent duplicate registration calls.
80+ * Also keeps track if a PAT registration is going on. */
81+ protected readonly inProgress : Set < string > = new Set ( ) ;
82+ /* Used to notify when registration finished for a resource. The event will be the identifier of the resource.
83+ * Also used to notify when a PAT was acquired. */
84+ protected readonly emitter : EventEmitter = new EventEmitter ( ) ;
8285
8386 protected readonly configCache : NodeJS . Dict < { config : UmaConfig , expiration : number } > = { } ;
8487 protected readonly patStorage : NodeJS . Dict < { pat : string , expiration : number } > = { } ;
@@ -101,14 +104,19 @@ export class UmaClient implements SingleThreaded {
101104 ) {
102105 // This number can potentially get very big when seeding a bunch of pods.
103106 // This is not really an issue, but it is still preferable to not have a warning printed.
104- this . registerEmitter . setMaxListeners ( 20 ) ;
107+ this . emitter . setMaxListeners ( 20 ) ;
105108 }
106109
107110 public async getPat ( issuer : string , credentials : string ) : Promise < string > {
108111 const cached = this . patStorage [ credentials ] ;
109112 if ( cached && cached . expiration > Date . now ( ) ) {
110113 return cached . pat ;
111114 }
115+ if ( this . inProgress . has ( PAT_EVENT ) ) {
116+ await once ( this . emitter , PAT_EVENT ) ;
117+ return this . getPat ( issuer , credentials ) ;
118+ }
119+ this . inProgress . add ( PAT_EVENT ) ;
112120
113121 const config = await this . fetchUmaConfig ( issuer ) ;
114122 const response = await this . fetcher . fetch ( config . token_endpoint , {
@@ -129,6 +137,9 @@ export class UmaClient implements SingleThreaded {
129137 const expiration = Date . now ( ) + expires_in * 1000 ;
130138 this . patStorage [ credentials ] = { pat, expiration } ;
131139
140+ this . inProgress . delete ( PAT_EVENT ) ;
141+ this . emitter . emit ( PAT_EVENT ) ;
142+
132143 return pat ;
133144 }
134145
@@ -170,13 +181,13 @@ export class UmaClient implements SingleThreaded {
170181 const body = [ ] ;
171182 for ( const [ target , modes ] of permissions . entrySets ( ) ) {
172183 let umaId = await this . umaIdStore . get ( target . path ) ;
173- if ( ! umaId && this . inProgressResources . has ( target . path ) ) {
184+ if ( ! umaId && this . inProgress . has ( target . path ) ) {
174185 // Wait for the resource to finish registration if it is still being registered, and there is no UMA ID yet.
175186 // Time out after 2s to prevent getting stuck in case something goes wrong during registration.
176187 const timeoutPromise = promises . setTimeout ( 2000 , '' ) . then ( ( ) => {
177188 throw new InternalServerError ( `Unable to finish registration for ${ target . path } .` )
178189 } ) ;
179- await Promise . race ( [ timeoutPromise , once ( this . registerEmitter , target . path ) ] ) ;
190+ await Promise . race ( [ timeoutPromise , once ( this . emitter , target . path ) ] ) ;
180191 umaId = await this . umaIdStore . get ( target . path ) ;
181192 }
182193 if ( ! umaId ) {
@@ -350,14 +361,14 @@ export class UmaClient implements SingleThreaded {
350361 * and updated with the relations once the parent registration is finished.
351362 */
352363 public async registerResource ( resource : ResourceIdentifier , issuer : string , credentials : string ) : Promise < void > {
353- if ( this . inProgressResources . has ( resource . path ) ) {
364+ if ( this . inProgress . has ( resource . path ) ) {
354365 // It is possible a resource is still being registered when an updated registration is already requested.
355366 // To prevent duplicate registrations of the same resource,
356367 // the next call will only happen when the first one is finished.
357- await once ( this . registerEmitter , resource . path ) ;
368+ await once ( this . emitter , resource . path ) ;
358369 return this . registerResource ( resource , issuer , credentials ) ;
359370 }
360- this . inProgressResources . add ( resource . path ) ;
371+ this . inProgress . add ( resource . path ) ;
361372 let { resource_registration_endpoint : endpoint } = await this . fetchUmaConfig ( issuer ) ;
362373 const knownUmaId = await this . umaIdStore . get ( resource . path ) ;
363374 if ( knownUmaId ) {
@@ -394,12 +405,12 @@ export class UmaClient implements SingleThreaded {
394405 resource . path } due to missing parent ID. Waiting for parent registration.`) ;
395406
396407 promises . push (
397- once ( this . registerEmitter , parentIdentifier . path )
408+ once ( this . emitter , parentIdentifier . path )
398409 . then ( ( ) => this . registerResource ( resource , issuer , credentials ) ) ,
399410 ) ;
400411 // It is possible the parent is not yet being registered.
401412 // We need to force a registration in such a case, otherwise the above event will never be fired.
402- if ( ! this . inProgressResources . has ( parentIdentifier . path ) ) {
413+ if ( ! this . inProgress . has ( parentIdentifier . path ) ) {
403414 promises . push ( this . registerResource ( parentIdentifier , issuer , credentials ) ) ;
404415 }
405416 }
@@ -439,8 +450,8 @@ export class UmaClient implements SingleThreaded {
439450 this . logger . info ( `Registered resource ${ resource . path } with UMA ID ${ umaId } ` ) ;
440451 }
441452 // Indicate this resource finished registration
442- this . inProgressResources . delete ( resource . path ) ;
443- this . registerEmitter . emit ( resource . path ) ;
453+ this . inProgress . delete ( resource . path ) ;
454+ this . emitter . emit ( resource . path ) ;
444455 } ) ;
445456
446457 // Execute all the required promises.
0 commit comments