Skip to content

Storage emulator doesn't validate auth token when unit testing with the @firebase/rules-unit-testing package #3442

Closed
@anish-bhanwala-qp

Description

@anish-bhanwala-qp

[REQUIRED] Environment info

firebase-tools:
9.12.1

Platform:
macOS (Big Sur version 11.4)

[REQUIRED] Test case

https://github.com/anishbhanwala/firebase-tools-storage-eumlator-report-bug

[REQUIRED] Steps to reproduce

I am trying to unit test firebase Storage using the @firebase/rules-unit-testing package. To reproduce the issue follow the below steps:

  1. Clone the repo and install dependencies:
    1. git clone https://github.com/anishbhanwala/firebase-tools-storage-eumlator-report-bug.git
    2. cd firebase-tools-storage-eumlator-report-bug
    3. npm i
  2. Start emulator:
    1. firebase emulators:start
  3. Run the test cases:
    1. 'npm test'

[REQUIRED] Expected behavior

The test case should be successful.

[REQUIRED] Actual behavior

The test case timeouts after 5 seconds. This happens because there is an error in the firebase emulator logs:

➜  firebase-tools-storage-eumlator-report-bug git:(master) firebase emulators:start 
i  emulators: Starting emulators: storage
⚠  emulators: The Emulator UI requires a project ID to start. Configure your default project with 'firebase use' or pass the --project flag.

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
└─────────────────────────────────────────────────────────────┘

┌──────────┬────────────────┐
│ Emulator │ Host:Port      │
├──────────┼────────────────┤
│ Storage  │ localhost:9199 │
└──────────┴────────────────┘
  Emulator Hub not running.
  Other reserved ports: None

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

(node:33754) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'user_id' of null
    at createAuthExpressionValue (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/lib/emulator/storage/rules/runtime.js:274:31)
    at createRequestExpressionValue (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/lib/emulator/storage/rules/runtime.js:295:28)
    at StorageRulesRuntime.verifyWithRuleset (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/lib/emulator/storage/rules/runtime.js:185:114)
    at StorageRulesetInstance.verify (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/lib/emulator/storage/rules/runtime.js:31:29)
    at isPermitted (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/lib/emulator/storage/apis/firebase.js:20:54)
    at handleUpload (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/lib/emulator/storage/apis/firebase.js:294:25)
    at Layer.handle [as handle_request] (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/layer.js:95:5)
    at /Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/index.js:281:22
    at param (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/index.js:354:14)
    at param (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/index.js:365:14)
    at param (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/index.js:365:14)
    at Function.process_params (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/index.js:410:3)
    at next (/Users/anishbhanwala/.nvm/versions/node/v12.14.1/lib/node_modules/firebase-tools/node_modules/express/lib/router/index.js:275:10)
(node:33754) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 22)

Additional Info

I looked at the code and looks like this is happening because the @firebase/rules-unit-testing when sending JWT token doesn't include signature:
https://github.com/firebase/firebase-js-sdk/blob/66deb252d9aebf318d2410d2dee47f19ad0968da/packages/rules-unit-testing/src/api/index.ts#L200

  // Unsecured JWTs use the empty string as a signature.
  const signature = '';
  return [
    base64.encodeString(JSON.stringify(header), /*webSafe=*/ false),
    base64.encodeString(JSON.stringify(payload), /*webSafe=*/ false),
    signature
  ].join('.');
}

In the firebase-tools emulator code although the token is correctly received because of missing signature the below line returns null.

const tokenPayload = jwt.decode(opts.token) as any;

I am not sure if this is expected behavior or not but I thought it made sense to report this as an issue. Also, if you have a fix in mind I would love to raise a pull request with the suggested solution.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions