Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: use google-auto-auth #823

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 14 additions & 127 deletions lib/common/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/

var extend = require('extend');
var GoogleAuth = require('google-auth-library');
var googleAuth = require('google-auto-auth');
var is = require('is');
var nodeutil = require('util');
var request = require('request').defaults({
Expand Down Expand Up @@ -324,109 +324,6 @@ function shouldRetryRequest(err) {

util.shouldRetryRequest = shouldRetryRequest;

/**
* Create an Auth Client from Google Auth Library, used to get an access token
* for authenticating API requests.
*
* @param {object} config - Configuration object.
* @param {object=} config.authClient - AuthClient object. If not provided,
* it will be created and cached here.
* @param {object=} config.credentials - Credentials object.
* @param {string=} config.email - Account email address, required for PEM/P12
* usage.
* @param {string=} config.keyFile - Path to a .json, .pem, or .p12 keyfile.
* @param {array} config.scopes - Array of scopes required for the API.
* @param {function} callback - The callback function.
*/
function getAuthClient(config, callback) {
if (config.authClient) {
setImmediate(function() {
callback(null, config.authClient);
});
return;
}
var googleAuth = new GoogleAuth();

if (config.keyFile) {
var authClient = new googleAuth.JWT();
authClient.keyFile = config.keyFile;
authClient.email = config.email;
authClient.scopes = config.scopes;
addScope(null, authClient);
} else if (config.credentials) {
googleAuth.fromJSON(config.credentials, addScope);
} else {
googleAuth.getApplicationDefault(addScope);
}

function addScope(err, authClient) {
if (err) {
callback(err);
return;
}

if (authClient.createScopedRequired && authClient.createScopedRequired()) {
authClient = authClient.createScoped(config.scopes);
}

config.authClient = authClient;
callback(null, authClient);
}
}

util.getAuthClient = getAuthClient;

/**
* Authenticate a request by extending its headers object with an access token.
*
* @param {object} config - Configuration object.
* @param {object=} config.authClient - AuthClient object. If not provided,
* it will be created and cached here.
* @param {object=} config.credentials - Credentials object.
* @param {string=} config.email - Account email address, required for PEM/P12
* usage.
* @param {string=} config.keyFile - Path to a .json, .pem, or .p12 keyfile.
* @param {array} config.scopes - Array of scopes required for the API.
* @param {object} reqOpts - HTTP request options. Its `headers` object is
* created or extended with a valid access token.
* @param {function} callback - The callback function.
*/
function authorizeRequest(config, reqOpts, callback) {
util.getAuthClient(config, function(err, authClient) {
if (err) {
// google-auth-library returns a "Could not load..." error if it can't get
// an access token. However, it's possible an API request doesn't need to
// be authenticated, e.g. when downloading a file from a public bucket. We
// consider this error a warning, and allow the request to go through
// without authorization, relying on the upstream API to return an error
// the user would find more helpful, should one occur.
if (err.message.indexOf('Could not load') === 0) {
callback(null, reqOpts);
} else {
callback(err);
}
return;
}

authClient.getAccessToken(function(err, token) {
if (err) {
callback(err);
return;
}

var authorizedReqOpts = extend(true, {}, reqOpts, {
headers: {
Authorization: 'Bearer ' + token
}
});

callback(null, authorizedReqOpts);
});
});
}

util.authorizeRequest = authorizeRequest;

/**
* Get a function for making authorized requests.
*
Expand All @@ -450,6 +347,8 @@ util.authorizeRequest = authorizeRequest;
function makeAuthorizedRequestFactory(config) {
config = config || {};

var authClient = googleAuth(config);

/**
* The returned function that will make an authorized request.
*
Expand All @@ -470,7 +369,13 @@ function makeAuthorizedRequestFactory(config) {
}

function onAuthorized(err, authorizedReqOpts) {
if (err) {
// google-auth-library returns a "Could not load..." error if it can't get
// an access token. However, it's possible an API request doesn't need to
// be authenticated, e.g. when downloading a file from a public bucket. We
// consider this error a warning, and allow the request to go through
// without authorization, relying on the upstream API to return an error
// the user would find more helpful, should one occur.
if (err && err.message.indexOf('Could not load') === -1) {
if (stream) {
stream.destroy(err);
} else {
Expand All @@ -490,38 +395,20 @@ function makeAuthorizedRequestFactory(config) {
}

if (reqConfig.customEndpoint) {
// Using a custom API override. Do not use `google-auth-library` for
// Using a custom API override. Do not use `google-auto-auth` for
// authentication. (ex: connecting to a local Datastore server)
onAuthorized(null, reqOpts);
} else {
util.authorizeRequest(reqConfig, reqOpts, onAuthorized);
authClient.authorizeRequest(reqOpts, onAuthorized);
}

if (stream) {
return stream;
}
}

makeAuthorizedRequest.getCredentials = function(callback) {
util.getAuthClient(config, function(err, authClient) {
if (err) {
callback(err);
return;
}

authClient.authorize(function(err) {
if (err) {
callback(err);
return;
}

callback(null, {
client_email: authClient.email,
private_key: authClient.key
});
});
});
};
makeAuthorizedRequest.getCredentials =
authClient.getCredentials.bind(authClient);

return makeAuthorizedRequest;
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"duplexify": "^3.2.0",
"extend": "^2.0.0",
"gce-images": "^0.1.0",
"google-auth-library": "^0.9.4",
"google-auto-auth": "^0.2.0",
"is": "^3.0.1",
"methmeth": "^1.0.0",
"mime-types": "^2.0.8",
Expand Down
Loading