Skip to content

Service account based auth credentials being cached improperly #1505

Description

@nikmartin

Environment details

  • OS: Google App Engine
  • Node.js version: 10
  • npm version:?
  • googleapis version: 36.0.0

Steps to reproduce

  1. create a new GoogleApis instance and try to get a client using different service account credentials multiple times in different parallel calls

I have a node.js app engine app function:

app.post('/myroutehandler/sometask', async (req, res) => {
 
  const storeID = Buffer.from(req.body.message.data, 'base64').toString('utf-8');
  let pageToken = '';
  if (req.body.message.attributes) {
    pageToken = req.body.message.attributes.pageToken;
  }

  const pageSize = 250;
  console.log('StoreID:', storeID);
  const config: StoreConfig = await getConfigById(storeID);

const g = new GoogleApis({});
  g.auth
    .getClient({
      credentials: {
        client_email: config.content_api.credentials.client_email,
        private_key: config.content_api.credentials.private_key.replace(/\\n/g, '\n').trim(),
      },
      scopes: ['https://www.googleapis.com/auth/content'],
    })
    .then(cli => {
      const content = g.content({ version: 'v2', auth: cli });
      
const qryParam: any = { merchantId: config.content_api.merchant_id, maxResults: pageSize, auth: cli };
      if (pageToken) {
        qryParam.pageToken = pageToken;
      }
      content.productstatuses
        .list(qryParam)
        .then(errorList => {
          const nextPageToken = errorList.data.nextPageToken;

          const prmAry = [];
          const upd = fsdb.batch();
          errorList.data.resources.forEach(prod => {
            if (
              prod.itemLevelIssues &&
              prod.itemLevelIssues.some(issue => issue.code === 'policy_violation')
            ) {
              const pid = prod.productId;
              console.log('VIOLATION: ', pid);
              const parsedPid = pid.split(':');
              const issueRef = feedIssuesRef.doc(parsedPid[3]);
              upd.set(issueRef, { pid: parsedPid[3] });
              prmAry.push(deleteFeedItem(pid));
            }
          });
          Promise.all(prmAry)
            .then(results => {
              // console.log('feed updated!');
              upd.commit().then(() => {
                // console.log('issues updated!');
                if (nextPageToken) {
                 
                  const pubsub = new PubSub({ projectId: 'my-project-id' });
                  const dataBuffer = Buffer.from(storeID);
                  const customAttributes = { pageToken: nextPageToken };

                  pubsub
                    .topic('my-special-topic')
                    .publisher()
                    .publish(dataBuffer, customAttributes, (err, messageID) => {
                      res.status(200).end();
                    });
                } else {
                  console.log('no more tokens');
                  res.status(200).end();
                }
              });
            })
            .catch(err => {
              console.log('error in feed update! ', err);
              upd.commit().then(() => {
                console.log('issues updated anyway!');
                res.status(200).end();
              });
            });
        })
        .catch(error => {
          console.error(error.code);
          console.error(error.errors);
          return res.status(200).end();
        });
    });
});

This function takes a config id as a query parameter, looks up the service account info, and attempts to connect to the google content api to check for feed issues. when this function is called within the same instance for two different service accounts, all but the first will throw permission errors "'User cannot access account nnnnnnn'. These all are verified to work when called independently in their own app engine instance, but when called back to back or simultaneously, the credentials are being cached somewhere, even though we are creating a new instance of the GoogleApis object.

Metadata

Metadata

Labels

🚨This issue needs some love.priority: p2Moderately-important priority. Fix may not be included in next release.status: blockedResolving the issue is dependent on other work.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions