112 lines
3.4 KiB
JavaScript
112 lines
3.4 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const JwksReplica = require('./JwksReplica.js');
|
||
|
const XsuaaService = require('../service/XsuaaService.js');
|
||
|
const IdentityService = require('../service/IdentityService.js');
|
||
|
|
||
|
class JwksManager {
|
||
|
#replicas;
|
||
|
|
||
|
constructor() {
|
||
|
this.#replicas = new Map();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the expirationTime of any future JwksReplica objects created by this manager. Does not affect already created (and therefore cached) objects.
|
||
|
* @param expirationTime in ms
|
||
|
* @returns this
|
||
|
*/
|
||
|
withExpirationTime(expirationTime) {
|
||
|
if (expirationTime > 0) {
|
||
|
this.expirationTime = expirationTime;
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the refreshPeriod of any future JwksReplica objects created by this manager. Does not affect already created (and therefore cached) objects.
|
||
|
* @param refreshPeriod in ms
|
||
|
* @returns this
|
||
|
*/
|
||
|
withRefreshPeriod(refreshPeriod) {
|
||
|
if (refreshPeriod > 0) {
|
||
|
this.refreshPeriod = refreshPeriod;
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
getXsuaaJwks(uaaDomain, zid, attributes = {}) {
|
||
|
if (!uaaDomain) {
|
||
|
throw new Error("Cannot get JWKS from empty uaaDomain.");
|
||
|
}
|
||
|
|
||
|
const jwksParams = { zid };
|
||
|
|
||
|
let jwksReplica, replicaKey;
|
||
|
if (!attributes.disableCache) {
|
||
|
const keyParts = {domain: uaaDomain, ...jwksParams};
|
||
|
replicaKey = this.createCacheKey(keyParts);
|
||
|
|
||
|
jwksReplica = this.#replicas.get(replicaKey);
|
||
|
}
|
||
|
|
||
|
if (!jwksReplica) {
|
||
|
const xsuaaService = new XsuaaService(uaaDomain, zid);
|
||
|
jwksReplica = new JwksReplica(xsuaaService, this.expirationTime, this.refreshPeriod).withParams(jwksParams);
|
||
|
|
||
|
!attributes.disableCache && this.#replicas.set(replicaKey, jwksReplica);
|
||
|
}
|
||
|
|
||
|
return jwksReplica;
|
||
|
}
|
||
|
|
||
|
getIdentityJwks(issuerDomain, serviceCredentials, token, attributes = {}) {
|
||
|
if (!issuerDomain) {
|
||
|
throw new Error("Cannot get JWKS from empty domain.");
|
||
|
}
|
||
|
|
||
|
const jwksParams = {
|
||
|
client_id: serviceCredentials.clientid,
|
||
|
app_tid: token.getAppTID(),
|
||
|
azp: token.getAzp()
|
||
|
}
|
||
|
|
||
|
let jwksReplica, replicaKey;
|
||
|
if (!attributes.disableCache) {
|
||
|
const keyParts = {domain: issuerDomain, ...jwksParams};
|
||
|
replicaKey = this.createCacheKey(keyParts);
|
||
|
|
||
|
jwksReplica = this.#replicas.get(replicaKey);
|
||
|
}
|
||
|
|
||
|
if (!jwksReplica) {
|
||
|
const service = new IdentityService(serviceCredentials).withCustomDomain(issuerDomain);
|
||
|
jwksReplica = new JwksReplica(service, this.expirationTime, this.refreshPeriod).withParams(jwksParams);
|
||
|
|
||
|
!attributes.disableCache && this.#replicas.set(replicaKey, jwksReplica);
|
||
|
}
|
||
|
|
||
|
return jwksReplica;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a string cache key from the given key-value pairs, ignoring keys with null or undefined values.
|
||
|
* @param {object} parts
|
||
|
* @returns a cache key in string format, e.g. app_tid:foo:client_id:bar:azp:baz
|
||
|
*/
|
||
|
createCacheKey(parts) {
|
||
|
if (!parts || Object.entries(parts).length < 1) {
|
||
|
throw new Error("Could not create JwksManager key. Key parts must contain at least one element.");
|
||
|
}
|
||
|
|
||
|
return Object.entries(parts)
|
||
|
.filter(([value]) => value != null)
|
||
|
.map(([key, value]) => `${key}:${value}`)
|
||
|
.join(":");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = JwksManager;
|