From e9f4636a28b13bc324ede3645a61ad5fe830a8cd Mon Sep 17 00:00:00 2001 From: rleon Date: Tue, 3 Mar 2020 18:48:32 -0500 Subject: [PATCH] feature #7 : support refresh tokens --- .gitignore | 1 + HorusOauthSecurityStrategy.js | 93 ++++++++++++++++++++++++++++++----- client/HorusRestClient.js | 63 ++++++++++++++++++++++-- 3 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/HorusOauthSecurityStrategy.js b/HorusOauthSecurityStrategy.js index 2a7417a..9fd0233 100644 --- a/HorusOauthSecurityStrategy.js +++ b/HorusOauthSecurityStrategy.js @@ -1,7 +1,7 @@ const HorusRestClient = require('./client/HorusRestClient.js'); function HorusOauthSecurityStrategy(expressServer, options) { - logger.info(options); + logger.debug(options); var _this = this; var horusRestClient = new HorusRestClient(options.horusBaseUrl); @@ -16,24 +16,41 @@ function HorusOauthSecurityStrategy(expressServer, options) { return; } - logger.info("Authorization new user with code: "+authorizationCode); + logger.info("Authorizing new user with google oauth code: "+authorizationCode); options.horusOptions.authenticate.authorizationCode = authorizationCode; - horusRestClient.authenticate(options.horusOptions.authenticate, function(getAuthorizeUrlErr, userConfig) { - if (getAuthorizeUrlErr) { - logger.error("Error in auth transaction: "+getAuthorizeUrlErr); + var params = { + "grantType":options.horusOptions.authenticate.grantType, + "clientId":options.horusOptions.authenticate.clientId, + "authorizationCode":authorizationCode, + "applicationId":options.horusOptions.authenticate.applicationId + } + + horusRestClient.authenticate(params, function(horusAuthError, horusAuthResponse) { + if (horusAuthError) { + logger.error("Error in auth transaction: "+horusAuthError); res.redirect(options.express.failureRedirectRoute); return; } if(options.overrideResponse === true){ - logger.info("Modifying default response"); - userConfig.options = mapMenuReferences(userConfig.options, options); + logger.info("Modifying oauth default response"); + horusAuthResponse.options = mapMenuReferences(horusAuthResponse.options, options); }else{ - logger.info("default response will be returned"); + logger.info("default oauth response will be returned"); } - req.session.connectedUserInformation = userConfig; + req.session.tokenInformation = {}; + + req.session.tokenInformation.acquisitionTime = new Date().getTime(); + req.session.tokenInformation.refreshTokenV1 = horusAuthResponse.refreshTokenV1; + req.session.tokenInformation.refreshTokenV2 = horusAuthResponse.refreshTokenV2; + + //delete unnecesary values + delete horusAuthResponse.refreshTokenV1; + delete horusAuthResponse.refreshTokenV2; + + req.session.connectedUserInformation = horusAuthResponse; req.session.save(); if (req.session.originalUrl) { @@ -55,12 +72,55 @@ function HorusOauthSecurityStrategy(expressServer, options) { if (req.session.connectedUserInformation) { //User is already logged in - return next(); + if(isHorusTokenExpired(req)){ + //refresh tokens + logger.debug("Horus token is expired"); + + var params = { + "grantType":"refresh_token", + "refreshTokenV1":req.session.tokenInformation.refreshTokenV1, + "refreshTokenV2":req.session.tokenInformation.refreshTokenV2 + } + + horusRestClient.refreshTokens(params, function(refreshTokensError, refreshTokensResponse){ + if(refreshTokensError){ + logger.debug("token renewal failure:"+refreshTokensError); + if(req.path.endsWith("/settings.json")){ + var settings = {}; + settings.session = {}; + settings.session.expiredSession = true; + responseUtil.createJsonResponse(settings, req, res); + return; + }else{ + res.redirect(options.express.failureRedirectRoute); + return; + } + } + + //no errors, update tokens + req.session.connectedUserInformation.tokenV1 = refreshTokensResponse.tokenV1; + req.session.connectedUserInformation.tokenV2 = refreshTokensResponse.tokenV2; + + //upate refresh tokens + req.session.tokenInformation.refreshTokenV1 = refreshTokensResponse.refreshTokenV1; + req.session.tokenInformation.refreshTokenV2 = refreshTokensResponse.refreshTokenV2; + req.session.tokenInformation.acquisitionTime = new Date().getTime(); + + return next(); + }); + }else{ + return next(); + } } else { logger.info("User not logged in"); - logger.info(options.horusOptions.authorizeUrl); - horusRestClient.getAuthorizeUrl(options.horusOptions.authorizeUrl, function(getAuthorizeUrlErr, authorizeUrl) { + var params = { + "clientId":options.horusOptions.authenticate.clientId, + "clientType":options.horusOptions.authenticate.clientType, + "applicationId":options.horusOptions.authenticate.applicationId + } + + horusRestClient.getAuthorizeUrl(params, function(getAuthorizeUrlErr, authorizeUrl) { if (getAuthorizeUrlErr) { logger.error(getAuthorizeUrlErr); res.redirect(options.express.failureRedirectRoute); @@ -73,6 +133,15 @@ function HorusOauthSecurityStrategy(expressServer, options) { }); } } + + + function isHorusTokenExpired(req){ + var acquisitionTime = req.session.tokenInformation.acquisitionTime; + var now = new Date().getTime(); + var expirationTime = options.horusOptions.expirationTime; + return now > (acquisitionTime + expirationTime*1000); + } + } function mapMenuReferences(menuOptions, appOptions) { diff --git a/client/HorusRestClient.js b/client/HorusRestClient.js index dc99608..ae62158 100644 --- a/client/HorusRestClient.js +++ b/client/HorusRestClient.js @@ -5,6 +5,7 @@ function HorusRestClient(horusBaseUrl) { var horusAuthenticateEndpoint = horusBaseUrl + '/v1/nonspec/oauth2/auth'; var horusGetAuthorizeUrlEndpoint = horusBaseUrl + '/v1/nonspec/oauth2/auth/url'; + var horusRefreshTokensEndpoint = horusBaseUrl + '/v1/nonspec/oauth2/token/refresh'; this.authenticate = function(params, callback) { try { @@ -36,7 +37,10 @@ function HorusRestClient(horusBaseUrl) { }) .catch(function(err) { - logger.error(err.response); + logger.error(err.stack); + if(err.response && err.response.data && err.response.status && err.response.data.message){ + logger.error("Error: "+err.response.data.status+", message:"+err.response.data.message); + } return callback("Horus is down or " + horusAuthenticateEndpoint + " does not respond: " + err.message, null); }); } catch (globalErr) { @@ -81,9 +85,60 @@ function HorusRestClient(horusBaseUrl) { }) .catch(function(err) { - logger.error(err.response); - logger.error("Error: "+err.response.data.status+", message:"+err.response.data.message); - return callback("Horus is down or " + horusGetAuthorizeUrlEndpoint + " does not respond: " + err.message, null); + logger.error(err.stack); + if(err.response && err.response.data && err.response.status && err.response.data.message){ + logger.error("Error: "+err.response.data.status+", message:"+err.response.data.message); + } + return callback("Horus is down or " + horusGetAuthorizeUrlEndpoint + " does not respond: " + err, null); + }); + } catch (globalErr) { + logger.error(globalErr.stack); + return callback("Error when consuming Horus service:" + globalErr.message, null); + } + + } + + this.refreshTokens = function(params, callback) { + + try { + axios({ + method: 'POST', + headers: { + 'content-type': 'application/json' + }, + url: horusRefreshTokensEndpoint, + data: params + }) + .then(function(horusResponse) { + if (!horusResponse || (typeof horusResponse === 'undefined')) { + return callback("Horus " + horusRefreshTokensEndpoint + " http response is wrong.", null) + } + + if (!horusResponse.data || (typeof horusResponse.data === 'undefined')) { + return callback("Horus " + horusRefreshTokensEndpoint + " http response.data is wrong.", null); + } + + if (!horusResponse.data.status || (typeof horusResponse.data.status === 'undefined')) { + return callback("Horus " + horusRefreshTokensEndpoint + " http response status is undefined.", null); + } + + if (horusResponse.data.status != "200") { + return callback("Horus " + horusRefreshTokensEndpoint + " http response status " + horusResponse.data.status + " is different to 200:" + JSON.stringify(horusResponse.data), null); + } + + if (!horusResponse.data.content || (typeof horusResponse.data.content === 'undefined')) { + return callback("Horus " + horusRefreshTokensEndpoint + " http response content is undefined. Redirect url was expected :" + horusResponse.data.content, null); + } + + return callback(null, horusResponse.data.content); + + }) + .catch(function(err) { + logger.error(err.stack); + if(err.response && err.response.data && err.response.status && err.response.data.message){ + logger.error("Error: "+err.response.data.status+", message:"+err.response.data.message); + } + return callback("Horus is down or " + horusRefreshTokensEndpoint + " does not respond: " + err.message, null); }); } catch (globalErr) { logger.error(globalErr.stack);