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

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

Closed
anish-bhanwala-qp opened this issue Jun 3, 2021 · 4 comments

Comments

@anish-bhanwala-qp
Copy link

[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.

@samtstern
Copy link
Contributor

@anishbhanwala thank you for the detailed report!

@dius00
Copy link

dius00 commented Jun 9, 2021

I am experiencing the issue as well
firebase-tools:
9.12.1
Platform:
Win 10 Pro (19043.1023)

I hope the following brings some useful information to the table.

I've tried to narrow down the cause, which seems to be related to the JWT formatting. When validating the token through jwt.io, I receive the following warnings.

Warning: Looks like your JWT header is not encoded correctly using base64url
(https://tools.ietf.org/html/rfc4648#section-5). Note that padding ("=") must be
omitted as per https://tools.ietf.org/html/rfc7515#section-2

Warning: Looks like your JWT payload is not encoded correctly using base64url
(https://tools.ietf.org/html/rfc4648#section-5). Note that padding ("=") must be
omitted as per https://tools.ietf.org/html/rfc7515#section-2

While not a proper solution, adding

opts.token = opts.token.replaceAll(/(=+.)/g, '.');

to fix the formatting issue before calling the decode method here, fixed it for me, and the JWTs are decoded properly, and readable by the rules.

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

Ideally, the proper fix would ensure the token should be properly formatted/decodable when emitted.

@abeisgoat
Copy link
Contributor

Yeah so this definitely looks like a bug in the unit testing library where we're not stripping the padding as per the spec and @dius00's notes. Will look at getting a fix into the library.

@abeisgoat
Copy link
Contributor

PR in SDK repo over here firebase/firebase-js-sdk#5002 gonna close this and handle further discussion over there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants