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

Authentication token property "firebase" not defined on test app's instance #2405

Closed
malliaridis opened this issue Jun 27, 2020 · 10 comments
Closed

Comments

@malliaridis
Copy link

[REQUIRED] Environment info

firebase-tools: 8.4.1

Platform: Windows 10

[REQUIRED] Test case

Firestore rules file:

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {

    match /{prefix=**}/{document} {
        allow read, write: if request.auth.token.admin == true;
        // TODO Verify that this is not a bad practice
    }

    match /articles/{articleId} {
        allow read: if request.auth.uid != null;
        allow write: if "sign_in_provider" in request.auth.token.firebase
                     && request.auth.token.firebase.sign_in_provider != "anonymous";
    }
}

Test Suite:

import * as firebase from "@firebase/testing";
import * as fs from "fs";

const projectId = "firestore-emulator-example";
const data = {
  "title": "hello world"
}

const rules = fs.readFileSync("../firestore.rules", "utf8");

before(async () => {
  await firebase.loadFirestoreRules({projectId, rules});
});

beforeEach(async () => {
  await firebase.clearFirestoreData({projectId});
});

after(async () => {
  await Promise.all(firebase.apps().map(app => app.delete()));
});

describe('Articles collection', () => {
  it('should allow authenticated users to create an article', async () => {
    const db = firebase.initializeTestApp({"projectId": projectId, "auth": {
        "uid": "user-id",
        "email": "user@example.com",
        "token": {
          "sub": "user-id",
          "aud": "test-project",
          "firebase": {
            "sign_in_provider": "password"
          }
        }
      }}).firestore();
    const articles = db.collection("articles");
    await firebase.assertSucceeds(articles.doc("article-id").set(data));
  });
});

[REQUIRED] Steps to reproduce

  1. Create a firebase project with firestore
  2. Use the firestore rules above
  3. Run firestore emulator
  4. Run test suite from above

[REQUIRED] Expected behavior

The tests runned locally fail with false negative and with the error "Property firebase is undefined on object.". The same rules applied on the cloud rules succeed with the expected behavior.

[REQUIRED] Actual behavior

It is expected that the emulator's instance is mirroring the correct behavior like in the actual production environment. The property firebase should, since it was provided by the authentication object auth, be defined and not null. The object structure is copied from the browser tests that can be run directly when modifying the rules.

Further Information

See https://groups.google.com/g/firebase-talk/c/g79uxsyOf3E/m/TvXnaqcjAwAJ

@samtstern
Copy link
Contributor

Assigning to @scottcrossen who is currently the on-call for Access. Scott do you know if the firebase key is somehow protected and therefore unable to be mocked by @firebase/testing?

@scottcrossen
Copy link
Contributor

Hi! Can you initialize your test app like this instead? The reason is that the auth field in the configuration object is actually the token and not the rules auth object. If I wrote this code I probably would have done it differently.

const db = firebase.initializeTestApp({"projectId": projectId, "auth": {
  "sub": "user-id",
  "aud": "test-project",
  "email": "user@example.com",
  "firebase": {
    "sign_in_provider": "password"
  }
}}).firestore();

@scottcrossen
Copy link
Contributor

Let me know if that works!

@malliaridis
Copy link
Author

Hello Scott,
that solved my problem, thanks. 👍

The documentation varies a bit from the actual implementation at this point. Therefore the confusion with the auth object from https://firebase.google.com/docs/rules/rules-and-auth.

Maybe I could provide some suggestions to improve that part? Let me know. :)

@scottcrossen
Copy link
Contributor

Sure! If you have any suggestions let me know and I'll pass it onto the person who does the documentation. I wish I could change the testing SDK to use the word "token" instead of "auth" in the object though: That would make this more clear.

@malliaridis
Copy link
Author

Many tutorials show only examples with uid which is in a different layer according to the playground tests (outside the token object). Mixing uid and sub let me assume that the object represents the outer object (like in playground) instead of the token itself (as you also mentioned with the parameter name).
In Firestore.Request.auth and in Security Rules and Firebase Authentication it is also mentioned that the information is inside the token, but doesn't provide information about the testing framework that varies from this structure (which would be very helpful).

Maybe a more detailed documentation about the auth object would be useful in Test your security Rules -> Run local tests and a reference to the testing part of custom tokens in Creating Custom Tokens too. Especially the attributes that can be expected while testing.

A documentation of the actual object that auth represents (here token instead of auth) like in Firestore.Request.auth just with more details and a couple of examples (for using it in combination with the rules) would be very helpful. The only information I find in the docs are simple examples with uid and email or in a different context, which is for introduction good but for production a bit superficial.

A guideline for structuring the firestore rules and dos and don'ts could help especially beginners for getting a concrete idea of how a product ready setup could look like. Everything needs of course examples for a better understanding.

I could provide some concrete ideas if I would know the format and the styleguides of the contributions to the docs.

Of course I don't want to complain about anything with my suggestions. You guys do the best job outside there and your documentation and tutorials are by far the best I've ever seen 🥇. It's worth mentioning it.

@samtstern
Copy link
Contributor

@malliaridis thank you so much for the detailed feedback! The good news is that we're currently cleaning up / repositioning @firebase/testing so we have a chance to correct these mistakes.

The uid property of the token is a bit tricky. Technically it's in the token just like everything else, but for convenience we hoist it up onto request.auth.uid in rules and context.auth.uid in Cloud Functions. So by making this one property special we've made things much harder to understand.

Sounds like we should:

  1. Improve the documentation of these methods in @firebase/testing
  2. Change our examples to use more properties of auth so that things are clearer.

@samtstern
Copy link
Contributor

@malliaridis I have referenced this discussion in our brand new quickstart-testing repo where I think we will be able to address it:

firebase/quickstart-testing#2

@malliaridis
Copy link
Author

malliaridis commented Jul 2, 2020

@samtstern sorry for the late response. That's right. You pointed it out.

I find very useful the tutorial Role based access, would be great if there would be more examples like this. Especially role based access is one of the most used access control strategies I think.

@samtstern
Copy link
Contributor

@malliaridis (and anyone else following along here) this should be mostly addressed by this PR:
firebase/firebase-js-sdk#3876

In the next release of @firebase/rules-unit-testing the options.auth object will have strong types that help you discover and use all the available fields. I hope that helps!

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

3 participants