feat: Support OIDC signed UserInfo responses

Some OIDC providers support signed UserInfo response, to enhance
security. The OIDC client should be free to ask for the user info
sgnature, however in certain situations (e.g egov applications)
where security matters, the OIDC providers might chose to enforce
this sugnature.

Planka was not supported signed UserInfo response, which resulted
in an misleading exception 'invalidCodeOrNonce'.

Introduce the proper configurations to parametrize the OIDC client,
and a dedicated exception to improve the developer experience.

Specifications:

"The UserInfo Claims MUST be returned as the members of a JSON
object unless a signed or encrypted response was requested
during Client Registration."
pull/824/head
lebaudantoine 1 year ago
parent a6c8f1bc23
commit 9aaaca1b8d

@ -13,6 +13,9 @@ const Errors = {
MISSING_VALUES: {
missingValues: 'Unable to retrieve required values (email, name)',
},
INVALID_USERINFO_SIGNATURE: {
invalidUserInfoSignature: "Invalid signature on userInfo due to client misconfiguration"
}
};
module.exports = {
@ -40,6 +43,9 @@ module.exports = {
missingValues: {
responseType: 'unprocessableEntity',
},
invalidUserInfoSignature: {
responseType: 'unauthorized',
},
},
async fn(inputs) {
@ -51,6 +57,7 @@ module.exports = {
sails.log.warn(`Invalid code or nonce! (IP: ${remoteAddress})`);
return Errors.INVALID_CODE_OR_NONCE;
})
.intercept('invalidUserInfoSignature', () => Errors.INVALID_USERINFO_SIGNATURE)
.intercept('emailAlreadyInUse', () => Errors.EMAIL_ALREADY_IN_USE)
.intercept('usernameAlreadyInUse', () => Errors.USERNAME_ALREADY_IN_USE)
.intercept('missingValues', () => Errors.MISSING_VALUES);

@ -11,6 +11,7 @@ module.exports = {
},
exits: {
invalidUserInfoSignature: {},
invalidCodeOrNonce: {},
missingValues: {},
emailAlreadyInUse: {},
@ -34,6 +35,10 @@ module.exports = {
);
userInfo = await client.userinfo(tokenSet);
} catch (e) {
if (e instanceof SyntaxError && e.message.includes('Unexpected token e in JSON at position 0')) {
sails.log.warn('Error while exchanging OIDC code: userInfo response is signed.');
throw 'invalidUserInfoSignature';
}
sails.log.warn(`Error while exchanging OIDC code: ${e}`);
throw 'invalidCodeOrNonce';
}

@ -30,6 +30,7 @@ module.exports = function defineOidcHook(sails) {
client_secret: sails.config.custom.oidcClientSecret,
redirect_uris: [sails.config.custom.oidcRedirectUri],
response_types: ['code'],
userinfo_signed_response_alg: sails.config.custom.oidcUserinfoSignedResponseAlg,
});
},

@ -39,6 +39,7 @@ module.exports.custom = {
oidcIssuer: process.env.OIDC_ISSUER,
oidcClientId: process.env.OIDC_CLIENT_ID,
oidcClientSecret: process.env.OIDC_CLIENT_SECRET,
oidcUserinfoSignedResponseAlg: process.env.OIDC_USERINFO_SIGNED_RESPONSE_ALG,
oidcScopes: process.env.OIDC_SCOPES || 'openid email profile',
oidcResponseMode: process.env.OIDC_RESPONSE_MODE || 'fragment',
oidcDefaultResponseMode: process.env.OIDC_DEFAULT_RESPONSE_MODE === 'true',

Loading…
Cancel
Save