fix(core.gbapp): #387 adding /setupSecurity multiple tokens. Refresh token fix. @othonlima.

This commit is contained in:
Rodrigo Rodriguez 2023-11-20 11:29:36 -03:00
parent 6483f589ea
commit 42a9a8c402
4 changed files with 89 additions and 33 deletions

View file

@ -425,14 +425,14 @@ export class AdminDialog extends IGBDialog {
if (!tokenName) { if (!tokenName) {
min.instance.authenticatorAuthorityHostUrl = step.activeDialog.state.authenticatorAuthorityHostUrl; min.instance.authenticatorAuthorityHostUrl = step.activeDialog.state.authenticatorAuthorityHostUrl;
min.instance.authenticatorTenant = step.activeDialog.state.authenticatorTenant; min.instance.authenticatorTenant = step.activeDialog.state.authenticatorTenant;
}
await min.adminService.updateSecurityInfo( await min.adminService.updateSecurityInfo(
min.instance.instanceId, min.instance.instanceId,
tokenName ? step.activeDialog.state.tenant : step.activeDialog.state.authenticatorTenant, tokenName ? step.activeDialog.state.tenant : step.activeDialog.state.authenticatorTenant,
tokenName ? step.activeDialog.state.host : step.activeDialog.state.authenticatorAuthorityHostUrl tokenName ? step.activeDialog.state.host : step.activeDialog.state.authenticatorAuthorityHostUrl
); );
}
const locale = step.context.activity.locale; const locale = step.context.activity.locale;
const buf = Buffer.alloc(16); const buf = Buffer.alloc(16);
const state = `${min.instance.instanceId}${crypto.randomFillSync(buf).toString('hex')}`; const state = `${min.instance.instanceId}${crypto.randomFillSync(buf).toString('hex')}`;

View file

@ -238,6 +238,7 @@ export class GBAdminService implements IGBAdminService {
tenant: string = null tenant: string = null
): Promise<string> { ): Promise<string> {
if (root) { if (root) {
const minBoot = GBServer.globals.minBoot; const minBoot = GBServer.globals.minBoot;
instanceId = minBoot.instance.instanceId; instanceId = minBoot.instance.instanceId;
@ -251,6 +252,7 @@ export class GBAdminService implements IGBAdminService {
throw new Error(`/setupSecurity is required before running /publish.`); throw new Error(`/setupSecurity is required before running /publish.`);
} }
return new Promise<string>(async (resolve, reject) => { return new Promise<string>(async (resolve, reject) => {
const instance = await this.core.loadInstanceById(instanceId); const instance = await this.core.loadInstanceById(instanceId);
@ -259,38 +261,84 @@ export class GBAdminService implements IGBAdminService {
const accessToken = await this.getValue(instanceId, `${tokenName}accessToken`); const accessToken = await this.getValue(instanceId, `${tokenName}accessToken`);
resolve(accessToken); resolve(accessToken);
} else { } else {
const oauth2 = tokenName ? 'oauth' : 'oauth2';
const authorizationUrl = urlJoin(
tokenName ? host : instance.authenticatorAuthorityHostUrl,
tokenName ? tenant : instance.authenticatorTenant,
`/${oauth2}/authorize`
);
const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`); if (tokenName && !root) {
const resource = tokenName ? '' : 'https://graph.microsoft.com';
const authenticationContext = new AuthenticationContext(authorizationUrl);
authenticationContext.acquireTokenWithRefreshToken( const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`);
refreshToken,
tokenName ? clientId : instance.marketplaceId, let url = urlJoin(
tokenName ? clientSecret : instance.marketplacePassword, host,
resource, tenant, 'oauth/token');
async (err, res) => { let buff = new Buffer(`${clientId}:${clientSecret}`);
if (err !== null) { const base64 = buff.toString('base64');
reject(err);
} else { const options = {
const token = res as TokenResponse; method: 'POST',
try { headers: {
await this.setValue(instanceId, `${tokenName}accessToken`, token.accessToken); Accept: '1.0',
await this.setValue(instanceId, `${tokenName}refreshToken`, token.refreshToken); Authorization: `Basic ${base64}`,
await this.setValue(instanceId, `${tokenName}expiresOn`, token.expiresOn.toString()); 'Content-Type': 'application/x-www-form-urlencoded'
resolve(token.accessToken); },
} catch (error) { body: new URLSearchParams({
'grant_type': 'refresh_token',
'refresh_token': refreshToken
})
};
const result = await fetch(url, options);
if (result.status != 200) {
throw new Error(`acquireElevatedToken error: ${result.status}: ${result.statusText}.`)
}
const text = await result.text();
const token = JSON.parse(text);
// Saves token to the database.
await this.setValue(instanceId, `${tokenName}accessToken`, token['access_token']);
await this.setValue(instanceId, `${tokenName}refreshToken`, token['refresh_token']);
await this.setValue(instanceId, `${tokenName}expiresOn`,
new Date(Date.now() + token['expires_in']).toString());
await this.setValue(instanceId, `${tokenName}AntiCSRFAttackState`, null);
resolve(token['access_token']);
}
else {
const oauth2 = tokenName ? 'oauth' : 'oauth2';
const authorizationUrl = urlJoin(
tokenName ? host : instance.authenticatorAuthorityHostUrl,
tokenName ? tenant : instance.authenticatorTenant,
`/${oauth2}/authorize`
);
const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`);
const resource = tokenName ? '' : 'https://graph.microsoft.com';
const authenticationContext = new AuthenticationContext(authorizationUrl);
authenticationContext.acquireTokenWithRefreshToken(
refreshToken,
tokenName ? clientId : instance.marketplaceId,
tokenName ? clientSecret : instance.marketplacePassword,
resource,
async (err, res) => {
if (err !== null) {
reject(err); reject(err);
} else {
const token = res as TokenResponse;
try {
await this.setValue(instanceId, `${tokenName}accessToken`, token.accessToken);
await this.setValue(instanceId, `${tokenName}refreshToken`, token.refreshToken);
await this.setValue(instanceId, `${tokenName}expiresOn`, token.expiresOn.toString());
resolve(token.accessToken);
} catch (error) {
reject(err);
}
} }
} }
} );
); }
} }
}); });
} }

View file

@ -212,10 +212,14 @@ export class GBVMService extends GBService {
return { key: 'UUID' }; return { key: 'UUID' };
case 'key': case 'key':
return { key: 'STRING' }; // Assuming key is a string data type return { key: 'STRING' }; // Assuming key is a string data type
case 'number':
return { key: 'INTEGER' };
case 'integer': case 'integer':
return { key: 'INTEGER' }; return { key: 'INTEGER' };
case 'double': case 'double':
return { key: 'FLOAT' }; return { key: 'FLOAT' };
case 'float':
return { key: 'FLOAT' };
case 'date': case 'date':
return { key: 'DATE' }; return { key: 'DATE' };
case 'boolean': case 'boolean':
@ -525,9 +529,10 @@ export class GBVMService extends GBService {
} }
public static normalizeQuotes(text: any) { public static normalizeQuotes(text: any) {
text = text.replace(/\¨/gm, '"'); text = text.replace(/\"/gm, '`');
text = text.replace(/\“/gm, '"'); text = text.replace(/\¨/gm, '`');
text = text.replace(/\”/gm, '"'); text = text.replace(/\“/gm, '`');
text = text.replace(/\”/gm, '`');
text = text.replace(/\/gm, "'"); text = text.replace(/\/gm, "'");
text = text.replace(/\/gm, "'"); text = text.replace(/\/gm, "'");

View file

@ -548,8 +548,11 @@ export class GBMinService {
`${tokenName}accessToken`, token['accessToken']?token['accessToken']:token['access_token']); `${tokenName}accessToken`, token['accessToken']?token['accessToken']:token['access_token']);
await this.adminService.setValue(instance.instanceId, await this.adminService.setValue(instance.instanceId,
`${tokenName}refreshToken`, token['refreshToken']?token['refreshToken']:token['refresh_token']); `${tokenName}refreshToken`, token['refreshToken']?token['refreshToken']:token['refresh_token']);
await this.adminService.setValue(instance.instanceId, await this.adminService.setValue(instance.instanceId,
`${tokenName}expiresOn`, token['expiresOn']?token['expiresOn'].toString():token['expires_in'].toString()); `${tokenName}expiresOn`, token['expiresOn'] ?
token['expiresOn'].toString():
new Date (Date.now() + token['expires_in']));
await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null); await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null);