Skip to content

Commit

Permalink
HCK-8554: extended errors processing to handle Entra grant consent is…
Browse files Browse the repository at this point in the history
…sues (#113)

* HCK-8554: extended errors processing to handle Entra grant c
onsent issues

* HCk-8554: removed redundant variables and escape characters

---------

Co-authored-by: Vitalii Yarmus <[email protected]>
Co-authored-by: Thomas Jakemeyn <[email protected]>
  • Loading branch information
3 people authored Oct 30, 2024
1 parent ef09b9d commit 1c7e2f4
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 4 deletions.
23 changes: 19 additions & 4 deletions reverse_engineering/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const { adaptJsonSchema } = require('./helpers/adaptJsonSchema');
const crypto = require('crypto');
const randomstring = require('randomstring');
const base64url = require('base64url');
const { prepareError } = require('./databaseService/helpers/errorService');

module.exports = {
async connect(connectionInfo, logger, callback, app) {
Expand Down Expand Up @@ -47,8 +48,17 @@ module.exports = {
}
callback(null);
} catch (error) {
logger.log('error', { message: error.message, stack: error.stack, error }, 'Test connection');
callback({ message: error.message, stack: error.stack });
const errorWithUpdatedInfo = prepareError({ error });
logger.log(
'error',
{
message: errorWithUpdatedInfo.message,
stack: errorWithUpdatedInfo.stack,
error: errorWithUpdatedInfo,
},
'Test connection',
);
callback({ message: errorWithUpdatedInfo.message, stack: errorWithUpdatedInfo.stack });
}
},

Expand Down Expand Up @@ -91,12 +101,17 @@ module.exports = {
logger.log('info', { collation: collationData[0] }, 'Database collation');
callback(null, objects);
} catch (error) {
const errorWithUpdatedInfo = prepareError({ error });
logger.log(
'error',
{ message: error.message, stack: error.stack, error },
{
message: errorWithUpdatedInfo.message,
stack: errorWithUpdatedInfo.stack,
error: errorWithUpdatedInfo,
},
'Retrieving databases and tables information',
);
callback({ message: error.message, stack: error.stack });
callback({ message: errorWithUpdatedInfo.message, stack: errorWithUpdatedInfo.stack });
}
},

Expand Down
99 changes: 99 additions & 0 deletions reverse_engineering/databaseService/helpers/errorService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
*
* @param {{message: string}} param
* @returns {boolean}
*/
const isDisabledPublicClientFlowsError = ({ message }) => {
const DISABLED_PUBLIC_CLIENT_FLOWS_ERROR_ID = 'AADSTS7000218';

return message.includes(DISABLED_PUBLIC_CLIENT_FLOWS_ERROR_ID);
};

/**
*
* @param {{message: string}} param
* @returns {boolean}
*/
const isConsentRequiredError = ({ message }) => {
const CONSENT_REQUIRED_ERROR_ID = 'AADSTS65001';

return message.includes(CONSENT_REQUIRED_ERROR_ID);
};

/**
*
* @param {{error: object, newMessage: string, newStackTrace: string}} param
* @returns {object}
*/
const updateErrorMessageAndStack = ({ error, newMessage, newStackTrace }) => ({
code: error.code,
name: error.name,
message: newMessage,
stack: newStackTrace,
});

/**
*
* @param {{clientId: string}} param
* @returns {string}
*/
const getConsentRequiredErrorMessage = ({ clientId }) => {
const consentLink = `https://login.microsoftonline.com/organizations/adminconsent?client_id=${clientId}`;

return `Your Azure administrator needs to grant tenant-wide consent to the Hackolade application using the link below: ${consentLink}`;
};

/**
*
* @param {{match: string}} param
* @returns {string}
*/
const getClientIdFromErrorMessage = ({ message }) => {
const clientIdRegularExpression = new RegExp(/'[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}'/gim);
const clientIdMatches = message.match(clientIdRegularExpression);

if (clientIdMatches.length === 0) {
return 'Unknown';
}

const [clientId] = clientIdMatches;
const clientIdWithoutQuotes = clientId.slice(1, clientId.length - 1);

return clientIdWithoutQuotes;
};

/**
*
* @param {{error: object}} param
* @returns {object}
*/
const prepareError = ({ error }) => {
const originalErrors = error?.originalError?.errors;
if (!originalErrors || originalErrors?.length === 0) {
return error;
}

const initialErrorDataIndex = originalErrors.length - 1;
const initialError = originalErrors[initialErrorDataIndex];

const isInitialErrorConsentRequiredError = isConsentRequiredError(initialError);
if (isInitialErrorConsentRequiredError) {
const clientId = getClientIdFromErrorMessage({ message: initialError.message });
const newErrorMessage = getConsentRequiredErrorMessage({ clientId });

return updateErrorMessageAndStack({ error, newMessage: newErrorMessage, newStackTrace: initialError.stack });
}

const isInitialErrorDisabledPublicClientFlowsError = isDisabledPublicClientFlowsError(initialError);
if (isInitialErrorDisabledPublicClientFlowsError) {
const newErrorMessage = 'You need to allow Public client flows for the Entra ID application';

return updateErrorMessageAndStack({ error, newMessage: newErrorMessage, newStackTrace: initialError.stack });
}

return error;
};

module.exports = {
prepareError,
};

0 comments on commit 1c7e2f4

Please sign in to comment.