@sap/xssec
Advanced tools
Comparing version 3.3.0 to 3.3.2
# Change Log | ||
All notable changes to this project will be documented in this file. | ||
## 3.3.2 - 2023-07-28 | ||
- restore backward-compatibility feature: use cleanUpPemKey function on verification keys to support PEM with missing line breaks- | ||
- restore backward-compatible behaviour: use verificationKey as fallback if KID is not found in JWKS but throw error about missing KID if it fails | ||
- fix error handling for cert endpoint | ||
## 3.3.0 - 2023-07-24 | ||
@@ -5,0 +10,0 @@ - add app_tid to formular for token exchanges |
@@ -58,3 +58,5 @@ 'use strict'; | ||
if (jwk === undefined) { | ||
throw new Error("JWKS does not contain JWK with this kid."); | ||
const err = new Error(`JWKS does not contain JWK with kid ${kid}.`); | ||
err.kidMissingInJwks = true; | ||
throw err; | ||
} | ||
@@ -61,0 +63,0 @@ |
@@ -13,5 +13,3 @@ 'use strict'; | ||
#app_tid; // optional zone id | ||
#correlationId; // optional | ||
#oidcInfo; | ||
#clientId; | ||
@@ -21,6 +19,5 @@ | ||
get app_tid() { return this.#app_tid; } | ||
get correlationId() { return this.#correlationId; } | ||
get clientId() { return this.#clientId; } | ||
constructor(url, app_tid, correlationId, client_id) { | ||
constructor(url, app_tid, client_id) { | ||
if (url === undefined) { | ||
@@ -32,3 +29,2 @@ throw new Error("IdentityService requires a url."); | ||
this.#app_tid = app_tid; | ||
this.#correlationId = correlationId; | ||
this.#clientId = client_id; | ||
@@ -40,11 +36,11 @@ } | ||
try { | ||
requests.requestOpenIDConfiguration(this.url, { correlationId: this.correlationId, clientId: this.clientId }, (err, oidcInfo) => { | ||
requests.requestOpenIDConfiguration(this.url, { clientId: this.clientId }, (err, oidcInfo) => { | ||
if (err) { | ||
rej(err); | ||
return rej(err); | ||
} | ||
res(oidcInfo); | ||
return res(oidcInfo); | ||
}); | ||
} catch (e) { | ||
rej(e); | ||
return rej(e); | ||
} | ||
@@ -60,3 +56,3 @@ }); | ||
} catch (e) { | ||
rej(e); | ||
return rej(e); | ||
} | ||
@@ -68,5 +64,5 @@ } | ||
try { | ||
requests.fetchOIDCKey(jwksEndpoint, this.app_tid, { correlationId: this.correlationId, clientId: this.clientId }, (err, json) => { | ||
requests.fetchOIDCKey(jwksEndpoint, this.app_tid, { clientId: this.clientId }, (err, json) => { | ||
if (err) { | ||
rej(err); | ||
return rej(err); | ||
} | ||
@@ -86,6 +82,6 @@ | ||
.filter(key => key.value !== undefined); | ||
res(jwks); | ||
return res(jwks); | ||
}); | ||
} catch (e) { | ||
rej(e); | ||
return rej(e); | ||
} | ||
@@ -92,0 +88,0 @@ }); |
@@ -8,9 +8,7 @@ 'use strict'; | ||
#zid; // optional zone id | ||
#correlationId; // optional | ||
get jku() { return this.#jku; } | ||
get zid() { return this.#zid; } | ||
get correlationId() { return this.#correlationId; } | ||
constructor(jku, zid, correlationId) { | ||
constructor(jku, zid) { | ||
if(jku === undefined) { | ||
@@ -22,3 +20,2 @@ throw new Error("XsuaaService requires a jku to fetch JWKS from."); | ||
this.#zid = zid; | ||
this.#correlationId = correlationId; | ||
} | ||
@@ -29,3 +26,3 @@ | ||
try { | ||
requests.fetchKeyFromXSUAA(this.jku, this.zid, { correlationId: this.correlationId }, function (err, json) { | ||
requests.fetchKeyFromXSUAA(this.jku, this.zid, null, function (err, json) { | ||
if (err) { | ||
@@ -35,6 +32,6 @@ return rej(err); | ||
res(json.keys); | ||
return res(json.keys); | ||
}); | ||
} catch (e) { | ||
rej(e); | ||
return rej(e); | ||
} | ||
@@ -41,0 +38,0 @@ }); |
@@ -289,2 +289,24 @@ 'use strict'; | ||
/* Adds missing line breaks to malformed PEM keys. | ||
* For backward-compatibility, a specific kind of malformed PEM needs to be supported that is lacking line breaks around the header and footer. | ||
* This kind of PEM input can occur, for example, in old service bindings of XSA and is not always fixable by consumers of this library. | ||
*/ | ||
function cleanUpPemKey(pem) { | ||
if(!pem) { | ||
return null; | ||
} | ||
const header = "-----BEGIN PUBLIC KEY-----"; | ||
if(!pem.includes(`${header}\n`)) { | ||
pem = pem.replace(header, `${header}\n`); | ||
} | ||
const footer = "-----END PUBLIC KEY-----"; | ||
if(!pem.includes(`\n${footer}`)) { | ||
pem = pem.replace(footer, `\n${footer}`); | ||
} | ||
return pem; | ||
} | ||
function JwtTokenValidatorXSUAA(configArray, serviceCredentials) { | ||
@@ -319,4 +341,5 @@ if(!jwksManager) { | ||
let kidNotInJwksErr = null; | ||
const verificationKeySupplier = async (header, callback) => { | ||
let keyFromConfig = serviceCredentials.verificationkey; | ||
let keyFromConfig = cleanUpPemKey(serviceCredentials.verificationkey); | ||
@@ -335,3 +358,3 @@ if(!header.jku || !header.kid || header.kid == 'legacy-token-key') { | ||
let err, jwk; | ||
let jwk; | ||
try { | ||
@@ -341,6 +364,12 @@ const jwks = jwksManager.getXsuaaJwks(header.jku, token.getZoneId()); | ||
} catch(e) { | ||
err = e; | ||
if(e.kidMissingInJwks) { | ||
// try validation with keyFromConfig but remember KID was not in JWKS for error logging | ||
kidNotInJwksErr = e; | ||
jwk = keyFromConfig; | ||
} else { | ||
return callback(e); | ||
} | ||
} | ||
return callback(err, jwk ? jwk.value : null); | ||
return callback(null, jwk ? cleanUpPemKey(jwk.value) : keyFromConfig); | ||
} | ||
@@ -351,2 +380,8 @@ | ||
if (err) { | ||
if(kidNotInJwksErr) { | ||
// verification with keyFromConfig as fallback failed after key with KID was not in JWKS | ||
debugError(kidNotInJwksErr); | ||
return cb(kidNotInJwksErr, token); | ||
} | ||
debugError(err.statuscode); | ||
@@ -429,4 +464,5 @@ debugError(err.message); | ||
let kidNotInJwksErr = null; | ||
const verificationKeySupplier = async (header, callback) => { | ||
let keyFromConfig = serviceCredentials.verificationkey; | ||
let keyFromConfig = cleanUpPemKey(serviceCredentials.verificationkey); | ||
@@ -445,3 +481,3 @@ if(!header.jku || !header.kid || header.kid == 'legacy-token-key') { | ||
let err, jwk; | ||
let jwk; | ||
try { | ||
@@ -451,11 +487,23 @@ const jwks = jwksManager.getXsuaaJwks(header.jku, token.getZoneId()); | ||
} catch(e) { | ||
err = e; | ||
if(e.kidMissingInJwks) { | ||
// try validation with keyFromConfig but remember KID was not in JWKS for error logging | ||
kidNotInJwksErr = e; | ||
jwk = keyFromConfig; | ||
} else { | ||
return callback(e); | ||
} | ||
} | ||
return callback(err, jwk ? jwk.value : null); | ||
return callback(null, jwk ? cleanUpPemKey(jwk.value) : keyFromConfig); | ||
} | ||
return token.verify(verificationKeySupplier, | ||
function (err, token) { | ||
function (err, token) { | ||
if (err) { | ||
if(kidNotInJwksErr) { | ||
// verification with keyFromConfig as fallback failed after key with KID was not in JWKS | ||
debugError(kidNotInJwksErr); | ||
return cb(kidNotInJwksErr, token); | ||
} | ||
debugError(err.statuscode); | ||
@@ -462,0 +510,0 @@ debugError(err.message); |
{ | ||
"name": "@sap/xssec", | ||
"version": "3.3.0", | ||
"version": "3.3.2", | ||
"description": "XS Advanced Container Security API for node.js", | ||
@@ -5,0 +5,0 @@ "main": "./lib", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
149324
2320