Skip to content

Commit

Permalink
auth: also use @googleapis/ package
Browse files Browse the repository at this point in the history
  • Loading branch information
lotas committed Apr 29, 2024
1 parent 926f11b commit 8e3ff1a
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 245 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"@azure/ms-rest-azure-js": "^2.0.1",
"@azure/ms-rest-js": "^2.6.6",
"@azure/ms-rest-nodeauth": "^3.0.5",
"@google-cloud/iam-credentials": "^3.2.0",
"@googleapis/compute": "^10.0.0",
"@googleapis/iam": "^16.0.0",
"@googleapis/iamcredentials": "^3.0.0",
"@graphql-tools/schema": "^10.0.3",
"@octokit/auth-app": "^4.0.7",
"@octokit/core": "^3.0.0",
Expand Down
2 changes: 1 addition & 1 deletion services/auth/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const builder = new APIBuilder({
// the loaded config
'cfg',

// An object containing { allowedServiceAccounts, credentials, iamCredentialsClient } for interacting
// An object containing {googleapis, auth, credentials} for interacting
// with GCP.
'gcp',
],
Expand Down
16 changes: 8 additions & 8 deletions services/auth/src/gcp.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,24 @@ export const gcpBuilder = builder => builder.declare({
);
}

const iamcredentials = this.gcp.googleapis.iamcredentials({
version: 'v1',
auth: this.gcp.auth,
});

try {
const response = await this.gcp.iamCredentialsClient.generateAccessToken({
const response = await iamcredentials.projects.serviceAccounts.generateAccessToken({
// NOTE: the `-` here represents the projectId, and uses the projectId
// from this.gcp.auth, which is why we verified those match above.
name: `projects/-/serviceAccounts/${serviceAccount}`,
scope: [
'https://www.googleapis.com/auth/cloud-platform',
],
delegates: [],
lifetime: {
seconds: 3600,
},
lifetime: '3600s',
});

const [{ accessToken, expireTime }] = response;
const expires = new Date(expireTime.seconds * 1000);

return res.reply({ accessToken, expireTime: expires.toISOString() });
return res.reply(response.data);
} catch (err) {
return res.reportError('ResourceNotFound', err.message);
}
Expand Down
25 changes: 14 additions & 11 deletions services/auth/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import createSignatureValidator from './signaturevalidator.js';
import taskcluster from 'taskcluster-client';
import makeSentryManager from './sentrymanager.js';
import * as libPulse from 'taskcluster-lib-pulse';
import { IAMCredentialsClient } from '@google-cloud/iam-credentials';
import googleapis from '@googleapis/iamcredentials';
import assert from 'assert';
import { fileURLToPath } from 'url';
import { syncStaticClients } from './static-clients.js';
Expand Down Expand Up @@ -173,7 +173,7 @@ const load = Loader({
assert(projectIds.length <= 1, "at most one GCP project is supported");

if (projectIds.length === 0) {
return { auth: {}, credentials: {}, allowedServiceAccounts: [] };
return { googleapis, auth: {}, credentials: {}, allowedServiceAccounts: [] };
}

const project = projects[projectIds[0]];
Expand All @@ -182,22 +182,25 @@ const load = Loader({

assert(Array.isArray(allowedServiceAccounts));

const iamCredentialsClient = new IAMCredentialsClient({
scopes: [
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/iam',
],
credentials,
});
// note that this service can currently start up correctly without GCP
// credentials configured.
const auth = credentials ? googleapis.auth.fromJSON(credentials) : {};

auth.scopes = [
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/iam',
];

// return an object with..
return {
// the googleapis module (useful for dependency injection in tests)
googleapis,
// the constructed auth object
auth,
// and the credentials configuration
credentials,
// service accounts we allow to generate temporary credentials from
allowedServiceAccounts,
// IAM Credentials client
iamCredentialsClient,
};
},
},
Expand Down
85 changes: 63 additions & 22 deletions services/auth/test/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,28 +275,67 @@ helper.withServers = (mock, skipping) => {
* using real credentials.
*/
helper.withGcp = (mock, skipping) => {
const fakeGoogleApis = ({ credentials }) => {
const { client_email } = credentials;
return {
generateAccessToken: async ({ name, scope, delegates, lifetime }) => {
if (name === 'projects/-/serviceAccounts/invalid@mozilla.com') {
throw new Error('Invalid account');
}
assert.equal(name, `projects/-/serviceAccounts/${client_email}`);
assert.deepEqual(scope, ['https://www.googleapis.com/auth/cloud-platform']);
assert.deepEqual(delegates, []);
assert.deepEqual(lifetime, { seconds: 3600 });

return [
{
accessToken: 'sekrit',
expireTime: { seconds: Math.floor(new Date(1978, 6, 15).getTime() / 1000), nanos: 0 },
let policy = {};

const fakeGoogleApis = {
iam: ({ version, auth }) => {
assert.equal(version, 'v1');

const { client_email } = auth.testCredentials;
const iamResource = `projects/-/serviceAccounts/${client_email}`;

return {
projects: {
serviceAccounts: {
getIamPolicy: async ({ resource_ }) => {
if (resource_ !== iamResource) {
// api method treats any error as "not found"
throw new Error('Not found');
}

return { data: _.cloneDeep(policy) };
},
setIamPolicy: async ({ resource, requestBody }) => {
if (resource !== iamResource) {
throw new Error('Not found');
}

assert.equal(requestBody.updateMask, 'bindings');
policy = requestBody.policy;
},
},
null,
null,
];
},
};
},
};
},

iamcredentials: ({ version, auth }) => {
assert.equal(version, 'v1');

const { client_email } = auth.testCredentials;

return {
projects: {
serviceAccounts: {
generateAccessToken: async ({ name, scope, delegates, lifetime }) => {
if (name === 'projects/-/serviceAccounts/invalid@mozilla.com') {
throw new Error('Invalid account');
}
assert.equal(name, `projects/-/serviceAccounts/${client_email}`);
assert.deepEqual(scope, ['https://www.googleapis.com/auth/cloud-platform']);
assert.deepEqual(delegates, []);
assert.equal(lifetime, '3600s');

return {
data: {
accessToken: 'sekrit',
expireTime: new Date(1978, 6, 15).toJSON(),
},
};
},
},
},
};
},
};

suiteSetup('GCP credentials', async () => {
Expand All @@ -309,13 +348,15 @@ helper.withGcp = (mock, skipping) => {
project_id: 'testproject',
client_email: 'test_client@example.com',
};
const auth = { testCredentials: credentials };
const allowedServiceAccounts = [
credentials.client_email,
'invalid@mozilla.com',
];

load.inject('gcp', {
iamCredentialsClient: fakeGoogleApis({ credentials }),
auth,
googleapis: fakeGoogleApis,
credentials,
allowedServiceAccounts,
});
Expand Down

0 comments on commit 8e3ff1a

Please sign in to comment.