#6434 - signIn_issue #1892

Merged
jsegarra merged 20 commits from 6434-signIn_issue into dev 2023-12-22 09:36:33 +00:00
14 changed files with 99 additions and 58 deletions
Showing only changes of commit c3b91e1719 - Show all commits

View File

@ -1,5 +1,14 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const {models} = require('vn-loopback/server/server');
const handlePromiseLogout = (Self, {id}, courtesyTime) => {
new Promise(res => {
setTimeout(() => {
res(Self.logout(id));
}
, courtesyTime * 1000);
});
};
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('renewToken', { Self.remoteMethodCtx('renewToken', {
description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it', description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it',
@ -16,23 +25,32 @@ module.exports = Self => {
}); });
Self.renewToken = async function(ctx) { Self.renewToken = async function(ctx) {
const models = Self.app.models; const {accessToken: token} = ctx.req;
const token = ctx.req.accessToken;
const now = new Date(); // Check if current token is valid
const differenceMilliseconds = now - token.created; const isValid = await validateToken(token);
const differenceSeconds = Math.floor(differenceMilliseconds / 1000); if (isValid)
return token;
const fields = ['renewPeriod', 'courtesyTime']; const {courtesyTime} = await models.AccessTokenConfig.findOne({fields: ['courtesyTime']});
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields});
if (differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime) // Schedule to remove current token
throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded'); handlePromiseLogout(Self, token, courtesyTime);
await Self.logout(token.id); // Create new accessToken
const user = await Self.findById(token.userId); const user = await Self.findById(token.userId);
const accessToken = await user.createAccessToken(); const accessToken = await user.createAccessToken();
return {id: accessToken.id, ttl: accessToken.ttl}; return {id: accessToken.id, ttl: accessToken.ttl};
}; };
async function validateToken(token) {
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields: ['renewPeriod', 'courtesyTime']});
const now = Date.now();
const differenceMilliseconds = now - token.created;
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
const isValid = differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime;
return isValid;
}
}; };

View File

@ -0,0 +1,49 @@
const {models} = require('vn-loopback/server/server');
describe('Renew Token', () => {
const startingTime = Date.now();
let ctx = null;
beforeAll(async() => {
const unAuthCtx = {
req: {
headers: {},
connection: {
remoteAddress: '127.0.0.1'
},
getLocale: () => 'en'
},
args: {}
};
let login = await models.VnUser.signIn(unAuthCtx, 'salesAssistant', 'nightmare');
let accessToken = await models.AccessToken.findById(login.token);
ctx = {req: {accessToken: accessToken}};
});
beforeEach(() => {
jasmine.clock().install();
jasmine.clock().mockDate(new Date(startingTime));
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('should renew process', async() => {
jasmine.clock().mockDate(new Date(startingTime + 21600000));
const {id} = await models.VnUser.renewToken(ctx);
Review

Console.log.
Lo he visto una vez mergeado en dev. Lo quito directamente de la rama

Console.log. Lo he visto una vez mergeado en dev. Lo quito directamente de la rama
expect(id).not.toEqual(ctx.req.accessToken.id);
});
it('NOT should renew', async() => {
let error;
let response;
try {
response = await models.VnUser.renewToken(ctx);
} catch (e) {
error = e;
}
expect(error).toBeUndefined();
expect(response.id).toEqual(ctx.req.accessToken.id);
});
});

View File

@ -1,17 +0,0 @@
module.exports = Self => {
Self.remoteMethod('validateToken', {
description: 'Validates the current logged user token',
returns: {
type: 'Boolean',
root: true
},
http: {
path: `/validateToken`,
verb: 'GET'
}
});
Self.validateToken = async function() {
return true;
};
};

View File

@ -10,7 +10,6 @@ module.exports = function(Self) {
require('../methods/vn-user/sign-in')(Self); require('../methods/vn-user/sign-in')(Self);
require('../methods/vn-user/acl')(Self); require('../methods/vn-user/acl')(Self);
require('../methods/vn-user/recover-password')(Self); require('../methods/vn-user/recover-password')(Self);
require('../methods/vn-user/validate-token')(Self);
require('../methods/vn-user/privileges')(Self); require('../methods/vn-user/privileges')(Self);
require('../methods/vn-user/validate-auth')(Self); require('../methods/vn-user/validate-auth')(Self);
require('../methods/vn-user/renew-token')(Self); require('../methods/vn-user/renew-token')(Self);

View File

@ -104,13 +104,6 @@
"permission": "ALLOW" "permission": "ALLOW"
}, },
{ {
"property": "validateToken",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{
"property": "validateAuth", "property": "validateAuth",
"accessType": "EXECUTE", "accessType": "EXECUTE",
"principalType": "ROLE", "principalType": "ROLE",

View File

@ -0,0 +1,4 @@
-- Auto-generated SQL script #202311061003
UPDATE salix.accessTokenConfig
SET courtesyTime=60
WHERE id=1;

View File

@ -3,7 +3,7 @@ CREATE OR REPLACE DEFINER=`root`@`localhost`
VIEW `vn`.`ticketState` VIEW `vn`.`ticketState`
AS SELECT `tt`.`created` AS `updated`, AS SELECT `tt`.`created` AS `updated`,
`tt`.`stateFk` AS `stateFk`, `tt`.`stateFk` AS `stateFk`,
`tt`.`userFk` AS `userFk`, `tt`.`userFk` AS `workerFk`,
`tls`.`ticketFk` AS `ticketFk`, `tls`.`ticketFk` AS `ticketFk`,
`s`.`id` AS `state`, `s`.`id` AS `state`,
`s`.`order` AS `productionOrder`, `s`.`order` AS `productionOrder`,
@ -40,7 +40,7 @@ SELECT
`ts`.`state` AS `state`, `ts`.`state` AS `state`,
`ts`.`productionOrder` AS `productionOrder`, `ts`.`productionOrder` AS `productionOrder`,
`ts`.`alertLevel` AS `alertLevel`, `ts`.`alertLevel` AS `alertLevel`,
`ts`.`userFk` AS `userFk`, `ts`.`worker` AS `worker`,
`ts`.`code` AS `code`, `ts`.`code` AS `code`,
`ts`.`updated` AS `updated`, `ts`.`updated` AS `updated`,
`ts`.`isPicked` AS `isPicked` `ts`.`isPicked` AS `isPicked`

View File

@ -2967,9 +2967,9 @@ INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`)
(2, 1, 50, 2), (2, 1, 50, 2),
(3, 1, 0, 3); (3, 1, 0, 3);
INSERT INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `renewInterval`) INSERT INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `courtesyTime`, `renewInterval`)
VALUES VALUES
(1, 21600, 300); (1, 21600, 60, 300);
INSERT INTO `vn`.`travelConfig` (`id`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `companyFk`) INSERT INTO `vn`.`travelConfig` (`id`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `companyFk`)
VALUES VALUES

View File

@ -82,7 +82,7 @@ export default class Token {
if (!data) return; if (!data) return;
this.renewPeriod = data.renewPeriod; this.renewPeriod = data.renewPeriod;
this.stopRenewer(); this.stopRenewer();
this.inservalId = setInterval(() => this.checkValidity(), data.renewInterval * 1000); this.intervalId = setInterval(() => this.checkValidity(), data.renewInterval * 1000);
}); });
} }
@ -103,17 +103,13 @@ export default class Token {
const token = res.data; const token = res.data;
this.set(token.id, now, token.ttl, this.remember); this.set(token.id, now, token.ttl, this.remember);
}) })
.catch(res => {
if (res.data?.error?.code !== 'periodNotExceeded')
throw res;
})
.finally(() => { .finally(() => {
this.checking = false; this.checking = false;
}); });
} }
stopRenewer() { stopRenewer() {
clearInterval(this.inservalId); clearInterval(this.intervalId);
} }
} }
Token.$inject = ['vnInterceptor', '$http', '$rootScope']; Token.$inject = ['vnInterceptor', '$http', '$rootScope'];

View File

@ -1,6 +1,5 @@
module.exports = () => { module.exports = () => {
Date.vnUTC = () => { Date.vnUTC = (env = process.env.NODE_ENV) => {
const env = process.env.NODE_ENV;
if (!env || env === 'development') if (!env || env === 'development')
return new Date(Date.UTC(2001, 0, 1, 11)); return new Date(Date.UTC(2001, 0, 1, 11));

View File

@ -39,7 +39,7 @@
"./middleware/salix-version": {} "./middleware/salix-version": {}
}, },
"parse": { "parse": {
"body-parser#json":{} "body-parser#json":{}
}, },
"routes": { "routes": {
"loopback#rest": { "loopback#rest": {

View File

@ -2,7 +2,7 @@ const {models} = require('vn-loopback/server/server');
describe('account changePassword()', () => { describe('account changePassword()', () => {
const userId = 70; const userId = 70;
const unauthCtx = { const unAuthCtx = {
req: { req: {
headers: {}, headers: {},
connection: { connection: {
@ -79,7 +79,7 @@ describe('account changePassword()', () => {
passExpired: yesterday passExpired: yesterday
} }
, options); , options);
await models.VnUser.signIn(unauthCtx, 'trainee', 'nightmare', options); await models.VnUser.signIn(unAuthCtx, 'trainee', 'nightmare', options);
} catch (e) { } catch (e) {
if (e.message != 'Pass expired') if (e.message != 'Pass expired')
throw e; throw e;

View File

@ -34,9 +34,9 @@
"foreignKey": "stateFk" "foreignKey": "stateFk"
}, },
"user": { "user": {
"type": "belongsTo", "type": "belongsTo",
"model": "VnUser", "model": "VnUser",
"foreignKey": "userFk" "foreignKey": "workerFk"
} }
} }
} }

View File

@ -37,9 +37,9 @@
"foreignKey": "stateFk" "foreignKey": "stateFk"
}, },
"user": { "user": {
"type": "belongsTo", "type": "belongsTo",
"model": "VnUser", "model": "VnUser",
"foreignKey": "userFk" "foreignKey": "userFk"
} }
} }
} }