mirror of
https://github.com/HackPlan/google-auth-library-nodejs.git
synced 2026-04-28 19:55:40 +08:00
Merge pull request #39 from tbetbetbe/node-auth-correct-jwt-get-request-metadata
Node auth correct jwt get request metadata
This commit is contained in:
@@ -49,10 +49,10 @@ JWTAccess.prototype.createScopedRequired = function() {
|
||||
* Get a non-expired access token, after refreshing if necessary
|
||||
*
|
||||
* @param {string} authURI the URI being authorized
|
||||
* @param {function} accessTokenFn a callback invoked with the access
|
||||
* token.
|
||||
* @param {function} metadataCb a callback invoked with the jwt
|
||||
* request metadata.
|
||||
*/
|
||||
JWTAccess.prototype.getRequestMetadata = function(authURI, accessTokenFn) {
|
||||
JWTAccess.prototype.getRequestMetadata = function(authURI, metadataCb) {
|
||||
var iat = Math.floor(new Date().getTime() / 1000);
|
||||
var exp = iat + 3600; // 3600 seconds = 1 hour
|
||||
|
||||
@@ -75,12 +75,12 @@ JWTAccess.prototype.getRequestMetadata = function(authURI, accessTokenFn) {
|
||||
secret: this.key
|
||||
};
|
||||
|
||||
// Sign the jwt and invoke accessTokenFn with it.
|
||||
this._signJWT(assertion, function(err, signedJWT) {
|
||||
// Sign the jwt and invoke metadataCb with it.
|
||||
return this._signJWT(assertion, function(err, signedJWT) {
|
||||
if (!err) {
|
||||
accessTokenFn(null, {'Authorization': 'Bearer ' + signedJWT});
|
||||
return metadataCb(null, {'Authorization': 'Bearer ' + signedJWT});
|
||||
} else {
|
||||
accessTokenFn(err, null);
|
||||
return metadataCb(err, null);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -92,26 +92,26 @@ JWTAccess.prototype.getRequestMetadata = function(authURI, accessTokenFn) {
|
||||
*/
|
||||
JWTAccess.prototype.fromJSON = function(json, opt_callback) {
|
||||
var that = this;
|
||||
var callback = opt_callback || noop;
|
||||
var done = opt_callback || noop;
|
||||
if (!json) {
|
||||
callback(new Error(
|
||||
done(new Error(
|
||||
'Must pass in a JSON object containing the service account auth settings.'));
|
||||
return;
|
||||
}
|
||||
if (!json.client_email) {
|
||||
callback(new Error(
|
||||
done(new Error(
|
||||
'The incoming JSON object does not contain a client_email field'));
|
||||
return;
|
||||
}
|
||||
if (!json.private_key) {
|
||||
callback(new Error(
|
||||
done(new Error(
|
||||
'The incoming JSON object does not contain a private_key field'));
|
||||
return;
|
||||
}
|
||||
// Extract the relevant information from the json key file.
|
||||
that.email = json.client_email;
|
||||
that.key = json.private_key;
|
||||
callback();
|
||||
done();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -121,10 +121,10 @@ JWTAccess.prototype.fromJSON = function(json, opt_callback) {
|
||||
*/
|
||||
JWTAccess.prototype.fromStream = function(stream, opt_callback) {
|
||||
var that = this;
|
||||
var callback = opt_callback || noop;
|
||||
var done = opt_callback || noop;
|
||||
if (!stream) {
|
||||
process.nextTick(function() {
|
||||
callback(
|
||||
done(
|
||||
new Error('Must pass in a stream containing the service account auth settings.'));
|
||||
});
|
||||
return;
|
||||
@@ -139,7 +139,7 @@ JWTAccess.prototype.fromStream = function(stream, opt_callback) {
|
||||
var data = JSON.parse(s);
|
||||
that.fromJSON(data, opt_callback);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -155,9 +155,9 @@ JWTAccess.prototype.fromStream = function(stream, opt_callback) {
|
||||
*/
|
||||
JWTAccess.prototype._signJWT = function(assertion, signedJwtFn) {
|
||||
try {
|
||||
signedJwtFn(null, jws.sign(assertion));
|
||||
return signedJwtFn(null, jws.sign(assertion));
|
||||
} catch (err) {
|
||||
signedJwtFn(err);
|
||||
return signedJwtFn(err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
var Auth2Client = require('./oauth2client.js');
|
||||
var gToken = require('gtoken');
|
||||
var JWTAccess = require('./jwtaccess.js');
|
||||
var noop = require('lodash.noop');
|
||||
var util = require('util');
|
||||
|
||||
|
||||
/**
|
||||
* JWT service account credentials.
|
||||
*
|
||||
@@ -53,13 +55,6 @@ function JWT(email, keyFile, key, scopes, subject) {
|
||||
*/
|
||||
util.inherits(JWT, Auth2Client);
|
||||
|
||||
// Executes the given callback if it is not null.
|
||||
function callback(c, err, res) {
|
||||
if (c) {
|
||||
c(err, res);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the credential with the specified scopes.
|
||||
* @param {(string|array)=} scopes List of requested scopes or a single scope.
|
||||
@@ -73,16 +68,16 @@ JWT.prototype.createScoped = function(scopes) {
|
||||
* Obtains the metadata to be sent with the request.
|
||||
*
|
||||
* @param {string} opt_uri the URI being authorized.
|
||||
* @param {function} cb_with_metadata
|
||||
* @param {function} metadataCb
|
||||
*/
|
||||
JWT.prototype.getRequestMetadata = function(opt_uri, cb_with_metadata) {
|
||||
JWT.prototype.getRequestMetadata = function(opt_uri, metadataCb) {
|
||||
if (this.createScopedRequired() && opt_uri) {
|
||||
// no scopes have been set, but a uri has been provided. Use JWTAccess credentials.
|
||||
var alt = new JWTAccess(this.email, this.key);
|
||||
alt.getRequestMetadata(opt_uri, cb_with_metadata);
|
||||
return alt.getRequestMetadata(opt_uri, metadataCb);
|
||||
} else {
|
||||
JWT.super_.prototype.getRequestMetadata.call(
|
||||
this, opt_uri, cb_with_metadata);
|
||||
return JWT.super_.prototype.getRequestMetadata.call(
|
||||
this, opt_uri, metadataCb);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,6 +107,7 @@ JWT.prototype.createScopedRequired = function() {
|
||||
*/
|
||||
JWT.prototype.authorize = function(opt_callback) {
|
||||
var that = this;
|
||||
var done = opt_callback || noop;
|
||||
|
||||
that.refreshToken_(null, function(err, result) {
|
||||
if (!err) {
|
||||
@@ -120,7 +116,7 @@ JWT.prototype.authorize = function(opt_callback) {
|
||||
that.key = that.gtoken.key;
|
||||
that.email = that.gtoken.iss;
|
||||
}
|
||||
callback(opt_callback, err, result);
|
||||
done(err, result);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -132,12 +128,14 @@ JWT.prototype.authorize = function(opt_callback) {
|
||||
* @private
|
||||
*/
|
||||
JWT.prototype.refreshToken_ = function(ignored_, opt_callback) {
|
||||
this._createGToken(function(err, gToken) {
|
||||
var done = opt_callback || noop;
|
||||
|
||||
return this._createGToken(function(err, gToken) {
|
||||
if (err) {
|
||||
callback(opt_callback, err);
|
||||
return done(err);
|
||||
} else {
|
||||
gToken.getToken(function (err, token) {
|
||||
callback(opt_callback, err, {
|
||||
return gToken.getToken(function (err, token) {
|
||||
return done(err, {
|
||||
access_token: token,
|
||||
token_type: 'Bearer',
|
||||
expiry_date: gToken.expires_at
|
||||
@@ -155,25 +153,26 @@ JWT.prototype.refreshToken_ = function(ignored_, opt_callback) {
|
||||
*/
|
||||
JWT.prototype.fromJSON = function(json, opt_callback) {
|
||||
var that = this;
|
||||
var done = opt_callback || noop;
|
||||
if (!json) {
|
||||
callback(opt_callback, new Error(
|
||||
done(new Error(
|
||||
'Must pass in a JSON object containing the service account auth settings.'));
|
||||
return;
|
||||
}
|
||||
if (!json.client_email) {
|
||||
callback(opt_callback, new Error(
|
||||
done(new Error(
|
||||
'The incoming JSON object does not contain a client_email field'));
|
||||
return;
|
||||
}
|
||||
if (!json.private_key) {
|
||||
callback(opt_callback, new Error(
|
||||
done(new Error(
|
||||
'The incoming JSON object does not contain a private_key field'));
|
||||
return;
|
||||
}
|
||||
// Extract the relevant information from the json key file.
|
||||
that.email = json.client_email;
|
||||
that.key = json.private_key;
|
||||
callback(opt_callback);
|
||||
done();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -183,10 +182,11 @@ JWT.prototype.fromJSON = function(json, opt_callback) {
|
||||
*/
|
||||
JWT.prototype.fromStream = function(stream, opt_callback) {
|
||||
var that = this;
|
||||
var done = opt_callback || noop;
|
||||
|
||||
if (!stream) {
|
||||
process.nextTick(function() {
|
||||
callback(
|
||||
opt_callback,
|
||||
done(
|
||||
new Error('Must pass in a stream containing the service account auth settings.'));
|
||||
});
|
||||
return;
|
||||
@@ -201,7 +201,7 @@ JWT.prototype.fromStream = function(stream, opt_callback) {
|
||||
var data = JSON.parse(s);
|
||||
that.fromJSON(data, opt_callback);
|
||||
} catch (err) {
|
||||
callback(opt_callback, err);
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -213,7 +213,7 @@ JWT.prototype.fromStream = function(stream, opt_callback) {
|
||||
*/
|
||||
JWT.prototype._createGToken = function(callback) {
|
||||
if (this.gtoken) {
|
||||
callback(null, this.gtoken);
|
||||
return callback(null, this.gtoken);
|
||||
} else {
|
||||
this.gtoken = this.gToken({
|
||||
iss: this.email,
|
||||
@@ -222,7 +222,7 @@ JWT.prototype._createGToken = function(callback) {
|
||||
keyFile: this.keyFile,
|
||||
key: this.key
|
||||
});
|
||||
callback(null, this.gtoken);
|
||||
return callback(null, this.gtoken);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var querystring = require('querystring');
|
||||
var AuthClient = require('./authclient.js');
|
||||
var util = require('util');
|
||||
var PemVerifier = require('./../pemverifier.js');
|
||||
var LoginTicket = require('./loginticket.js');
|
||||
var noop = require('lodash.noop');
|
||||
var PemVerifier = require('./../pemverifier.js');
|
||||
var querystring = require('querystring');
|
||||
var util = require('util');
|
||||
|
||||
var certificateCache = null;
|
||||
var certificateExpiry = null;
|
||||
@@ -149,9 +150,8 @@ OAuth2Client.prototype.getToken = function(code, opt_callback) {
|
||||
tokens.expiry_date = ((new Date()).getTime() + (tokens.expires_in * 1000));
|
||||
delete tokens.expires_in;
|
||||
}
|
||||
if (opt_callback) {
|
||||
opt_callback(err, tokens, response);
|
||||
}
|
||||
var done = opt_callback || noop;
|
||||
done(err, tokens, response);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -171,7 +171,7 @@ OAuth2Client.prototype.refreshToken_ = function(refresh_token, opt_callback) {
|
||||
};
|
||||
|
||||
// request for new token
|
||||
this.transporter.request({
|
||||
return this.transporter.request({
|
||||
method: 'POST',
|
||||
uri: uri,
|
||||
form: values,
|
||||
@@ -181,9 +181,8 @@ OAuth2Client.prototype.refreshToken_ = function(refresh_token, opt_callback) {
|
||||
tokens.expiry_date = ((new Date()).getTime() + (tokens.expires_in * 1000));
|
||||
delete tokens.expires_in;
|
||||
}
|
||||
if (opt_callback) {
|
||||
opt_callback(err, tokens, response);
|
||||
}
|
||||
var done = opt_callback || noop;
|
||||
done(err, tokens, response);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -262,14 +261,14 @@ OAuth2Client.prototype.getAccessToken = function(callback) {
|
||||
* {Authorization: 'Bearer <access_token_value>'}
|
||||
*
|
||||
* @param {string} opt_uri the Uri being authorized
|
||||
* @param {function} cb_with_metadata the func described above
|
||||
* @param {function} metadataCb the func described above
|
||||
*/
|
||||
OAuth2Client.prototype.getRequestMetadata = function(opt_uri, cb_with_metadata) {
|
||||
OAuth2Client.prototype.getRequestMetadata = function(opt_uri, metadataCb) {
|
||||
var that = this;
|
||||
var thisCreds = this.credentials;
|
||||
|
||||
if (!thisCreds.access_token && !thisCreds.refresh_token) {
|
||||
return cb_with_metadata(new Error('No access or refresh token is set.'), null);
|
||||
return metadataCb(new Error('No access or refresh token is set.'), null);
|
||||
}
|
||||
|
||||
// if no expiry time, assume it's not expired
|
||||
@@ -279,15 +278,15 @@ OAuth2Client.prototype.getRequestMetadata = function(opt_uri, cb_with_metadata)
|
||||
if (thisCreds.access_token && !isTokenExpired) {
|
||||
thisCreds.token_type = thisCreds.token_type || 'Bearer';
|
||||
var headers = {'Authorization': thisCreds.token_type + ' ' + thisCreds.access_token };
|
||||
return cb_with_metadata(null, headers , null);
|
||||
return metadataCb(null, headers , null);
|
||||
}
|
||||
|
||||
this.refreshToken_(thisCreds.refresh_token, function(err, tokens, response) {
|
||||
return this.refreshToken_(thisCreds.refresh_token, function(err, tokens, response) {
|
||||
if (err) {
|
||||
cb_with_metadata(err, null, response);
|
||||
return metadataCb(err, null, response);
|
||||
} else {
|
||||
if (!tokens || (tokens && !tokens.access_token)) {
|
||||
return cb_with_metadata(new Error('Could not refresh access token.'), null, response);
|
||||
return metadataCb(new Error('Could not refresh access token.'), null, response);
|
||||
}
|
||||
|
||||
var credentials = that.credentials;
|
||||
@@ -295,7 +294,7 @@ OAuth2Client.prototype.getRequestMetadata = function(opt_uri, cb_with_metadata)
|
||||
tokens.refresh_token = credentials.refresh_token;
|
||||
that.credentials = tokens;
|
||||
var headers = {'Authorization': credentials.token_type + ' ' + tokens.access_token };
|
||||
cb_with_metadata(null, headers , response);
|
||||
return metadataCb(err, headers , response);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -340,23 +339,23 @@ OAuth2Client.prototype.request = function(opts, callback) {
|
||||
var that = this;
|
||||
|
||||
// Hook the callback routine to call the _postRequest method.
|
||||
var my_callback = function(e, b, r) {
|
||||
that._postRequest(e, b, r, callback);
|
||||
var postRequestCb = function(err, body, resp) {
|
||||
that._postRequest(err, body, resp, callback);
|
||||
};
|
||||
|
||||
var cb_with_auth = function(err, headers, response) {
|
||||
var authCb = function(err, headers, response) {
|
||||
if (err) {
|
||||
my_callback(err, null, response);
|
||||
postRequestCb(err, null, response);
|
||||
} else {
|
||||
if (headers) {
|
||||
opts.headers = opts.headers || {};
|
||||
opts.headers.Authorization = headers.Authorization;
|
||||
}
|
||||
return that._makeRequest(opts, my_callback);
|
||||
return that._makeRequest(opts, postRequestCb);
|
||||
}
|
||||
};
|
||||
var unusedUri = null;
|
||||
return this.getRequestMetadata(unusedUri, cb_with_auth);
|
||||
return this.getRequestMetadata(unusedUri, authCb);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,7 +69,7 @@ describe('JWT auth client', function() {
|
||||
key: 'private-key-data',
|
||||
iss: 'foo@subjectaccount.com',
|
||||
getToken: function(opt_callback) {
|
||||
opt_callback(null, 'initial-access-token');
|
||||
return opt_callback(null, 'initial-access-token');
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -124,7 +124,7 @@ describe('JWT auth client', function() {
|
||||
var want = 'abc123';
|
||||
jwt.gtoken = {
|
||||
getToken: function(callback) {
|
||||
callback(null, want);
|
||||
return callback(null, want);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -159,18 +159,20 @@ describe('JWT auth client', function() {
|
||||
var wanted_token = 'abc123';
|
||||
jwt.gtoken = {
|
||||
getToken: function(callback) {
|
||||
callback(null, wanted_token);
|
||||
return callback(null, wanted_token);
|
||||
}
|
||||
};
|
||||
var want = 'Bearer ' + wanted_token;
|
||||
|
||||
var retValue = 'dummy';
|
||||
var unusedUri = null;
|
||||
jwt.getRequestMetadata(unusedUri, function(err, got) {
|
||||
var res = jwt.getRequestMetadata(unusedUri, function(err, got) {
|
||||
assert.strictEqual(null, err, 'no error was expected: got\n' + err);
|
||||
assert.strictEqual(want, got.Authorization,
|
||||
'the authorization header was wrong: ' + got.Authorization);
|
||||
done();
|
||||
return retValue;
|
||||
});
|
||||
assert.strictEqual(res, retValue);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -193,7 +195,8 @@ describe('JWT auth client', function() {
|
||||
};
|
||||
|
||||
var testUri = 'http:/example.com/my_test_service';
|
||||
jwt.getRequestMetadata(testUri, function(err, got) {
|
||||
var retValue = 'dummy';
|
||||
var res = jwt.getRequestMetadata(testUri, function(err, got) {
|
||||
assert.strictEqual(null, err, 'no error was expected: got\n' + err);
|
||||
assert.notStrictEqual(null, got, 'the creds should be present');
|
||||
var decoded = jws.decode(got.Authorization.replace('Bearer ', ''));
|
||||
@@ -201,7 +204,9 @@ describe('JWT auth client', function() {
|
||||
assert.strictEqual(email, decoded.payload.sub);
|
||||
assert.strictEqual(testUri, decoded.payload.aud);
|
||||
done();
|
||||
return retValue;
|
||||
});
|
||||
assert.strictEqual(res, retValue);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -252,7 +257,7 @@ describe('JWT auth client', function() {
|
||||
|
||||
jwt.gtoken = {
|
||||
getToken: function(callback) {
|
||||
callback(null, 'abc123');
|
||||
return callback(null, 'abc123');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -336,7 +341,7 @@ describe('JWT auth client', function() {
|
||||
|
||||
jwt.gtoken = {
|
||||
getToken: function(callback) {
|
||||
callback(null, 'token');
|
||||
return callback(null, 'token');
|
||||
},
|
||||
expires_at: dateInMillis
|
||||
};
|
||||
|
||||
@@ -43,7 +43,8 @@ describe('.getRequestMetadata', function() {
|
||||
var auth = new googleAuth();
|
||||
var client = new auth.JWTAccess(email, keys['private']);
|
||||
|
||||
var expect_authorization = function(err, creds) {
|
||||
var retValue = 'dummy';
|
||||
var expectAuth = function(err, creds) {
|
||||
assert.strictEqual(null, err, 'no error was expected: got\n' + err);
|
||||
assert.notStrictEqual(null, creds, 'an creds object should be present');
|
||||
var decoded = jws.decode(creds.Authorization.replace('Bearer ', ''));
|
||||
@@ -51,8 +52,10 @@ describe('.getRequestMetadata', function() {
|
||||
assert.strictEqual(email, decoded.payload.sub);
|
||||
assert.strictEqual(testUri, decoded.payload.aud);
|
||||
done();
|
||||
return retValue;
|
||||
};
|
||||
client.getRequestMetadata(testUri, expect_authorization);
|
||||
var res = client.getRequestMetadata(testUri, expectAuth);
|
||||
assert.strictEqual(res, retValue);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user