Skip to content

Commit

Permalink
Make eagerRefreshThresholdMillis an option which can be passed to fun…
Browse files Browse the repository at this point in the history
…ctions in googleAuth
  • Loading branch information
nolanmar511 committed Jan 16, 2018
1 parent abe3203 commit 63ab7cc
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 50 deletions.
4 changes: 3 additions & 1 deletion src/auth/computeclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {RequestError} from './../transporters';
import {CredentialRequest, Credentials} from './credentials';
import {GetTokenResponse, OAuth2Client, RefreshOptions} from './oauth2client';

export interface ComputeOptions extends RefreshOptions {}

export class Compute extends OAuth2Client {
/**
* Google Compute Engine metadata server token endpoint.
Expand All @@ -33,7 +35,7 @@ export class Compute extends OAuth2Client {
* Retrieve access token from the metadata server.
* See: https://developers.google.com/compute/docs/authentication
*/
constructor(options?: RefreshOptions) {
constructor(options?: ComputeOptions) {
super(options);
// Start with an expired refresh token, which will automatically be
// refreshed before the first API call is made.
Expand Down
108 changes: 61 additions & 47 deletions src/auth/googleauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ export class GoogleAuth {

cachedCredential: OAuth2Client|null = null;

private eagerRefreshThresholdMillis: number|undefined;

/**
* Export DefaultTransporter as a static property of the class.
*/
Expand Down Expand Up @@ -167,17 +165,28 @@ export class GoogleAuth {
*/
getApplicationDefault(): Promise<ADCResponse>;
getApplicationDefault(callback: ADCCallback): void;
getApplicationDefault(callback?: ADCCallback): void|Promise<ADCResponse> {
getApplicationDefault(options: RefreshOptions): Promise<ADCResponse>;
getApplicationDefault(options: RefreshOptions, callback: ADCCallback): void;
getApplicationDefault(
optionsOrCallback: ADCCallback|RefreshOptions = {},
callback?: ADCCallback): void|Promise<ADCResponse> {
let options: RefreshOptions|undefined;
if (typeof optionsOrCallback === 'function') {
callback = optionsOrCallback;
} else {
options = optionsOrCallback;
}
if (callback) {
this.getApplicationDefaultAsync()
.then(r => callback(null, r.credential, r.projectId))
this.getApplicationDefaultAsync(options)
.then(r => callback!(null, r.credential, r.projectId))
.catch(callback);
} else {
return this.getApplicationDefaultAsync();
return this.getApplicationDefaultAsync(options);
}
}

private async getApplicationDefaultAsync(): Promise<ADCResponse> {
private async getApplicationDefaultAsync(options?: RefreshOptions):
Promise<ADCResponse> {
// If we've already got a cached credential, just return it.
if (this.cachedCredential) {
return {
Expand All @@ -192,15 +201,17 @@ export class GoogleAuth {
// location of the credential file. This is typically used in local
// developer scenarios.
credential =
await this._tryGetApplicationCredentialsFromEnvironmentVariable();
await this._tryGetApplicationCredentialsFromEnvironmentVariable(
options);
if (credential) {
this.cachedCredential = credential;
projectId = await this.getDefaultProjectId();
return {credential, projectId};
}

// Look in the well-known credential file location.
credential = await this._tryGetApplicationCredentialsFromWellKnownFile();
credential =
await this._tryGetApplicationCredentialsFromWellKnownFile(options);
if (credential) {
this.cachedCredential = credential;
projectId = await this.getDefaultProjectId();
Expand All @@ -214,11 +225,7 @@ export class GoogleAuth {
// For GCE, just return a default ComputeClient. It will take care of
// the rest.
// TODO: cache the result
return {
projectId: null,
credential: new Compute(
{eagerRefreshThresholdMillis: this.eagerRefreshThresholdMillis})
};
return {projectId: null, credential: new Compute(options)};
} else {
// We failed to find the default credentials. Bail out with an error.
throw new Error(
Expand All @@ -231,14 +238,6 @@ export class GoogleAuth {
}
}

/**
* Sets time to eagerly refresh tokens before they are expired.
* @param {number=} eagerRefreshThresholdMillis Time in ms to refresh an unexpired token before it expires.
*/
setEagerRefreshThresholdMillis(eagerRefreshThresholdMillis: number) {
this.eagerRefreshThresholdMillis = eagerRefreshThresholdMillis;
}

/**
* Determines whether the auth layer is running on Google Compute Engine.
* @returns A promise that resolves with the boolean.
Expand Down Expand Up @@ -280,14 +279,15 @@ export class GoogleAuth {
* @returns Promise that resolves with the OAuth2Client or null.
* @api private
*/
async _tryGetApplicationCredentialsFromEnvironmentVariable():
Promise<JWT|UserRefreshClient|null> {
async _tryGetApplicationCredentialsFromEnvironmentVariable(
options?: RefreshOptions): Promise<JWT|UserRefreshClient|null> {
const credentialsPath = this._getEnv('GOOGLE_APPLICATION_CREDENTIALS');
if (!credentialsPath || credentialsPath.length === 0) {
return null;
}
try {
return this._getApplicationCredentialsFromFilePath(credentialsPath);
return this._getApplicationCredentialsFromFilePath(
credentialsPath, options);
} catch (e) {
throw this.createError(
'Unable to read the credential file specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable.',
Expand All @@ -300,8 +300,8 @@ export class GoogleAuth {
* @return Promise that resolves with the OAuth2Client or null.
* @api private
*/
async _tryGetApplicationCredentialsFromWellKnownFile():
Promise<JWT|UserRefreshClient|null> {
async _tryGetApplicationCredentialsFromWellKnownFile(
options?: RefreshOptions): Promise<JWT|UserRefreshClient|null> {
// First, figure out the location of the file, depending upon the OS type.
let location = null;
if (this._isWindows()) {
Expand Down Expand Up @@ -330,7 +330,7 @@ export class GoogleAuth {
return null;
}
// The file seems to exist. Try to use it.
return this._getApplicationCredentialsFromFilePath(location);
return this._getApplicationCredentialsFromFilePath(location, options);
}

/**
Expand All @@ -339,8 +339,9 @@ export class GoogleAuth {
* @returns Promise that resolves with the OAuth2Client
* @api private
*/
async _getApplicationCredentialsFromFilePath(filePath: string):
Promise<JWT|UserRefreshClient> {
async _getApplicationCredentialsFromFilePath(
filePath: string,
options: RefreshOptions = {}): Promise<JWT|UserRefreshClient> {
// Make sure the path looks like a string.
if (!filePath || filePath.length === 0) {
throw new Error('The file path is invalid.');
Expand All @@ -366,7 +367,7 @@ export class GoogleAuth {
// Now open a read stream on the file, and parse it.
try {
const readStream = this._createReadStream(filePath);
return this.fromStream(readStream);
return this.fromStream(readStream, options);
} catch (err) {
throw this.createError(
util.format('Unable to read the file at %s.', filePath), err);
Expand All @@ -378,19 +379,18 @@ export class GoogleAuth {
* @param {object=} json The input object.
* @returns JWT or UserRefresh Client with data
*/
fromJSON(json: JWTInput): JWT|UserRefreshClient {
fromJSON(json: JWTInput, options?: RefreshOptions): JWT|UserRefreshClient {
let client: UserRefreshClient|JWT;
if (!json) {
throw new Error(
'Must pass in a JSON object containing the Google auth settings.');
}
this.jsonContent = json;
options = options || {};
if (json.type === 'authorized_user') {
client = new UserRefreshClient(
{eagerRefreshThresholdMillis: this.eagerRefreshThresholdMillis});
client = new UserRefreshClient(options);
} else {
client = new JWT(
{eagerRefreshThresholdMillis: this.eagerRefreshThresholdMillis});
client = new JWT(options);
}
client.fromJSON(json);
return client;
Expand All @@ -403,19 +403,33 @@ export class GoogleAuth {
*/
fromStream(inputStream: stream.Readable): Promise<JWT|UserRefreshClient>;
fromStream(inputStream: stream.Readable, callback: CredentialCallback): void;
fromStream(inputStream: stream.Readable, callback?: CredentialCallback):
Promise<JWT|UserRefreshClient>|void {
fromStream(inputStream: stream.Readable, options: RefreshOptions):
Promise<JWT|UserRefreshClient>;
fromStream(
inputStream: stream.Readable, options: RefreshOptions,
callback: CredentialCallback): void;
fromStream(
inputStream: stream.Readable,
optionsOrCallback: RefreshOptions|CredentialCallback = {},
callback?: CredentialCallback): Promise<JWT|UserRefreshClient>|void {
let options: RefreshOptions = {};
if (typeof optionsOrCallback === 'function') {
callback = optionsOrCallback;
} else {
options = optionsOrCallback;
}
if (callback) {
this.fromStreamAsync(inputStream)
.then(r => callback(null, r))
this.fromStreamAsync(inputStream, options)
.then(r => callback!(null, r))
.catch(callback);
} else {
return this.fromStreamAsync(inputStream);
return this.fromStreamAsync(inputStream, options);
}
}

private fromStreamAsync(inputStream: stream.Readable):
Promise<JWT|UserRefreshClient> {
private fromStreamAsync(
inputStream: stream.Readable,
options?: RefreshOptions): Promise<JWT|UserRefreshClient> {
return new Promise((resolve, reject) => {
if (!inputStream) {
throw new Error(
Expand All @@ -429,7 +443,7 @@ export class GoogleAuth {
inputStream.on('end', () => {
try {
const data = JSON.parse(s);
const r = this.fromJSON(data);
const r = this.fromJSON(data, options);
return resolve(r);
} catch (err) {
return reject(err);
Expand All @@ -443,9 +457,9 @@ export class GoogleAuth {
* @param {string} - The API key string
* @returns A JWT loaded from the key
*/
fromAPIKey(apiKey: string): JWT {
const client = new JWT(
{eagerRefreshThresholdMillis: this.eagerRefreshThresholdMillis});
fromAPIKey(apiKey: string, options?: RefreshOptions): JWT {
options = options || {};
const client = new JWT(options);
client.fromAPIKey(apiKey);
return client;
}
Expand Down
Loading

0 comments on commit 63ab7cc

Please sign in to comment.