From b354896dc8073a3265fca1101ab24f2aa2d1a36c Mon Sep 17 00:00:00 2001 From: elisamerida Date: Mon, 13 Apr 2020 19:14:44 +0200 Subject: [PATCH 1/2] Support OpenID Connect --- oauth2.js | 24 ++++++++++++--------- server.js | 64 +++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 26 deletions(-) diff --git a/oauth2.js b/oauth2.js index 3f6324f..d3c3da3 100644 --- a/oauth2.js +++ b/oauth2.js @@ -1,9 +1,9 @@ const querystring= require('querystring'); const https= require('https'); -const http= require('http'); +const http= require('http'); const URL= require('url'); -exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, accessTokenPath, callbackURL, customHeaders) { +exports.OAuth2= function(scope, clientId, clientSecret, baseSite, authorizePath, accessTokenPath, callbackURL, customHeaders) { this._clientId= clientId; this._clientSecret= clientSecret; this._baseSite= baseSite; @@ -13,6 +13,8 @@ exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, access this._accessTokenName= "access_token"; this._authMethod= "Basic"; this._customHeaders = customHeaders || {}; + this._scope = scope; + console.log(this._scope); } // This 'hack' method is required for sites that don't use @@ -67,6 +69,7 @@ exports.OAuth2.prototype._request= function(method, url, headers, postBody, acce } let queryStr= querystring.stringify(parsedUrl.query); + console.log(queryStr); if( queryStr ) {queryStr= "?" + queryStr;} const options = { host:parsedUrl.hostname, @@ -118,14 +121,15 @@ exports.OAuth2.prototype._executeRequest= function( httpLibrary, options, postBo if(options.method === 'POST' && postBody) { request.write(postBody); } - request.end(); + request.end(); } exports.OAuth2.prototype.getAuthorizeUrl= function(responseType) { - + responseType = responseType || 'code'; + console.log(this._baseSite + this._authorizeUrl + '?response_type=' + responseType + '&client_id=' + this._clientId + '&state=xyz&scope='+this._scope+'&redirect_uri=' + this._callbackURL); - return this._baseSite + this._authorizeUrl + '?response_type=' + responseType + '&client_id=' + this._clientId + '&state=xyz&redirect_uri=' + this._callbackURL; + return this._baseSite + this._authorizeUrl + '?response_type=' + responseType + '&client_id=' + this._clientId + '&state=xyz&scope='+this._scope+'&redirect_uri=' + this._callbackURL; } @@ -140,11 +144,11 @@ function getResults(data){ return results; } -exports.OAuth2.prototype.getOAuthAccessToken= function(code) { +exports.OAuth2.prototype.getOAuthAccessToken= function(code, grant_type) { const that = this; - - return new Promise((resolve, reject) => { - const postData = 'grant_type=authorization_code&code=' + code + '&redirect_uri=' + that._callbackURL; + console.log(grant_type); + return new Promise((resolve, reject) => { + const postData = 'grant_type='+grant_type+'&code=' + code + '&redirect_uri=' + that._callbackURL; const postHeaders= { 'Authorization': that.buildAuthHeader(), @@ -199,4 +203,4 @@ exports.OAuth2.prototype.get= function(url, accessToken) { return error ? reject(error) : resolve(data); }); }); -} \ No newline at end of file +} diff --git a/server.js b/server.js index c898d88..a874037 100644 --- a/server.js +++ b/server.js @@ -6,7 +6,7 @@ const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const session = require('express-session'); const http = require('http'); -const port = 80; +const port = 8080; // Express configuration @@ -30,9 +30,12 @@ const client_secret = config.client_secret; const idmURL = config.idmURL; const response_type = config.response_type; const callbackURL = config.callbackURL; - +const scope = config.scope; +console.log(scope); +const grant_type = config.grant_type; +console.log(grant_type); // Creates oauth library object with the config data -const oa = new OAuth2(client_id, +const oa = new OAuth2(scope, client_id, client_secret, idmURL, '/oauth2/authorize', @@ -40,36 +43,67 @@ const oa = new OAuth2(client_id, callbackURL); // Handles requests to the main page -app.get('/', function(req, res){ - - // If auth_token is not stored in a session cookie it sends a button to redirect to IDM authentication portal - if(!req.session.access_token) { - res.send("Oauth2 IDM Demo.

"); +app.get('/login', function(req, res){ + //console.log(req); + // If auth_token is not stored in a session cookie it sends a button to redirect to IDM authentication portal + if(!req.session.access_token && !req.session.id_token) { + res.send("OpenID Connect IDM Demo.

"); // If auth_token is stored in a session cookie it sends a button to get user info } else { - res.send("Successfully authenticated.

Your oauth access_token: " +req.session.access_token + "

"); + var response = "Successfully authenticated. "; + if (req.session.id_token){ + response += "

Your id_token: "+req.session.id_token; + } + if(req.session.access_token){ + response +="

Your access_token: " +req.session.access_token; + response += "

"; + } + + res.send(response); } }); // Handles requests from IDM with the access code -app.get('/login', function(req, res){ - +app.get('/', function(req, res){ + console.log(req.query); + if(grant_type=='authorization_code'){ // Using the access code goes again to the IDM to obtain the access_token - oa.getOAuthAccessToken(req.query.code) + oa.getOAuthAccessToken(req.query.code, grant_type) + .then (results => { + + // Stores the access_token in a session cookie + req.session.access_token = results.access_token; + req.session.id_token = results.id_token; + + res.redirect('/login'); + + }); + }else if (grant_type=='implicit'){ + req.session.id_token = req.query.id_token; + req.session.access_token = req.query.access_token; + + res.redirect('/login'); + }else if (grant_type=='hybrid'){ + console.log("ID_TOKEN Authorization endpoint: "+req.query.id_token); + + oa.getOAuthAccessToken(req.query.code, grant_type) .then (results => { // Stores the access_token in a session cookie req.session.access_token = results.access_token; + req.session.id_token = results.id_token; - res.redirect('/'); + res.redirect('/login'); }); + + } }); // Redirection to IDM authentication portal app.get('/auth', function(req, res){ - const path = oa.getAuthorizeUrl(response_type); + const path = oa.getAuthorizeUrl(response_type, grant_type); res.redirect(path); }); @@ -140,5 +174,3 @@ const server = http.createServer(app); server.listen(port); server.on('error', onError); server.on('listening', onListeningServer); - - From ee093da28d1abb9613f889344148415ef50b4b0f Mon Sep 17 00:00:00 2001 From: elisamerida Date: Sat, 16 May 2020 13:53:06 +0200 Subject: [PATCH 2/2] Decoding JWT button --- oauth2.js | 24 +++++++++-------- server.js | 77 +++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/oauth2.js b/oauth2.js index 3f6324f..d3c3da3 100644 --- a/oauth2.js +++ b/oauth2.js @@ -1,9 +1,9 @@ const querystring= require('querystring'); const https= require('https'); -const http= require('http'); +const http= require('http'); const URL= require('url'); -exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, accessTokenPath, callbackURL, customHeaders) { +exports.OAuth2= function(scope, clientId, clientSecret, baseSite, authorizePath, accessTokenPath, callbackURL, customHeaders) { this._clientId= clientId; this._clientSecret= clientSecret; this._baseSite= baseSite; @@ -13,6 +13,8 @@ exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, access this._accessTokenName= "access_token"; this._authMethod= "Basic"; this._customHeaders = customHeaders || {}; + this._scope = scope; + console.log(this._scope); } // This 'hack' method is required for sites that don't use @@ -67,6 +69,7 @@ exports.OAuth2.prototype._request= function(method, url, headers, postBody, acce } let queryStr= querystring.stringify(parsedUrl.query); + console.log(queryStr); if( queryStr ) {queryStr= "?" + queryStr;} const options = { host:parsedUrl.hostname, @@ -118,14 +121,15 @@ exports.OAuth2.prototype._executeRequest= function( httpLibrary, options, postBo if(options.method === 'POST' && postBody) { request.write(postBody); } - request.end(); + request.end(); } exports.OAuth2.prototype.getAuthorizeUrl= function(responseType) { - + responseType = responseType || 'code'; + console.log(this._baseSite + this._authorizeUrl + '?response_type=' + responseType + '&client_id=' + this._clientId + '&state=xyz&scope='+this._scope+'&redirect_uri=' + this._callbackURL); - return this._baseSite + this._authorizeUrl + '?response_type=' + responseType + '&client_id=' + this._clientId + '&state=xyz&redirect_uri=' + this._callbackURL; + return this._baseSite + this._authorizeUrl + '?response_type=' + responseType + '&client_id=' + this._clientId + '&state=xyz&scope='+this._scope+'&redirect_uri=' + this._callbackURL; } @@ -140,11 +144,11 @@ function getResults(data){ return results; } -exports.OAuth2.prototype.getOAuthAccessToken= function(code) { +exports.OAuth2.prototype.getOAuthAccessToken= function(code, grant_type) { const that = this; - - return new Promise((resolve, reject) => { - const postData = 'grant_type=authorization_code&code=' + code + '&redirect_uri=' + that._callbackURL; + console.log(grant_type); + return new Promise((resolve, reject) => { + const postData = 'grant_type='+grant_type+'&code=' + code + '&redirect_uri=' + that._callbackURL; const postHeaders= { 'Authorization': that.buildAuthHeader(), @@ -199,4 +203,4 @@ exports.OAuth2.prototype.get= function(url, accessToken) { return error ? reject(error) : resolve(data); }); }); -} \ No newline at end of file +} diff --git a/server.js b/server.js index c898d88..068a37c 100644 --- a/server.js +++ b/server.js @@ -6,7 +6,7 @@ const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const session = require('express-session'); const http = require('http'); -const port = 80; +const port = 8080; // Express configuration @@ -30,9 +30,12 @@ const client_secret = config.client_secret; const idmURL = config.idmURL; const response_type = config.response_type; const callbackURL = config.callbackURL; - +const scope = config.scope; +console.log(scope); +const grant_type = config.grant_type; +console.log(grant_type); // Creates oauth library object with the config data -const oa = new OAuth2(client_id, +const oa = new OAuth2(scope, client_id, client_secret, idmURL, '/oauth2/authorize', @@ -40,36 +43,68 @@ const oa = new OAuth2(client_id, callbackURL); // Handles requests to the main page -app.get('/', function(req, res){ - - // If auth_token is not stored in a session cookie it sends a button to redirect to IDM authentication portal - if(!req.session.access_token) { - res.send("Oauth2 IDM Demo.

"); +app.get('/login', function(req, res){ + //console.log(req); + // If auth_token is not stored in a session cookie it sends a button to redirect to IDM authentication portal + if(!req.session.access_token && !req.session.id_token) { + res.send("OpenID Connect IDM Demo.

"); // If auth_token is stored in a session cookie it sends a button to get user info } else { - res.send("Successfully authenticated.

Your oauth access_token: " +req.session.access_token + "

"); + var response = "Successfully authenticated. "; + if (req.session.id_token){ + response += "

Your id_token: "+req.session.id_token; + response += "

"; + } + if(req.session.access_token){ + response +="

Your access_token: " +req.session.access_token; + response += "

"; + } + + res.send(response); } }); // Handles requests from IDM with the access code -app.get('/login', function(req, res){ - +app.get('/', function(req, res){ + console.log(req.query); + if(grant_type=='authorization_code'){ // Using the access code goes again to the IDM to obtain the access_token - oa.getOAuthAccessToken(req.query.code) + oa.getOAuthAccessToken(req.query.code, grant_type) + .then (results => { + + // Stores the access_token in a session cookie + req.session.access_token = results.access_token; + req.session.id_token = results.id_token; + + res.redirect('/login'); + + }); + }else if (grant_type=='implicit'){ + req.session.id_token = req.query.id_token; + req.session.access_token = req.query.access_token; + + res.redirect('/login'); + }else if (grant_type=='hybrid'){ + console.log("ID_TOKEN Authorization endpoint: "+req.query.id_token); + + oa.getOAuthAccessToken(req.query.code, grant_type) .then (results => { // Stores the access_token in a session cookie req.session.access_token = results.access_token; + req.session.id_token = results.id_token; - res.redirect('/'); + res.redirect('/login'); }); + + } }); // Redirection to IDM authentication portal app.get('/auth', function(req, res){ - const path = oa.getAuthorizeUrl(response_type); + const path = oa.getAuthorizeUrl(response_type, grant_type); res.redirect(path); }); @@ -86,6 +121,18 @@ app.get('/user_info', function(req, res){ }); }); +app.get('/decode_jwt', function(req, res){ +    const url = config.idmURL + '/user'; +    var jwtDecoded = req.session.id_token.split('.'); +    var header = Buffer.from(jwtDecoded[0], 'base64').toString(); +var headerParsed = JSON.stringify(JSON.parse(header), null, 2); +    var payload = Buffer.from(jwtDecoded[1], 'base64').toString(); +var payloadParsed = JSON.stringify(JSON.parse(payload), null, 2); + +    +    res.send("This is the DECODED JSON WEB TOKEN

HEADER:
" + headerParsed + "

PAYLOAD
" + payloadParsed +"

"); +}); + // Handles logout requests to remove access_token from the session cookie app.get('/logout', function(req, res){ @@ -140,5 +187,3 @@ const server = http.createServer(app); server.listen(port); server.on('error', onError); server.on('listening', onListeningServer); - -