firebase / firebase/firebase-tools

RTDB emulator doesn't work properly with databaseAuthVariableOverride

Open
#2,554 6 comments 1 reaction 0 assignees View on GitHub
emulator-suite emulators: database Needs: Attention type: bug
Dominant language
TypeScript
Stars
4.5k
Forks
1.3k
Avg merge
1d 12h
Merged PRs (30d)
84

Description

### [REQUIRED] Environment info

**firebase-tools:** 8.7.0
**Platform:** macOS
**node:** v10.22.0
**firebase-admin:** 9.1.0
**firebase-database-emulator:** v4.5.0

### [REQUIRED] Test case

Add some rules like the following:

```json
{
"rules": {
"$userId": {
"publicAccess": {
".validate": "newData.isBoolean()"
},
"data": {
".read": "$userId === auth.uid || (auth.token.auth_time >= ((now / 1000) - 60 * 60) && auth.token.customClaimAccess === $userId) || data.parent().child('publicAccess').val() === true"
}
}
}
}
```

### [REQUIRED] Steps to reproduce

```js

const admin = require('firebase-admin')

const adminApp = admin.initializeApp({
databaseURL: 'https://blah.firebaseio.com',
})

const noAuthApp = admin.initializeApp({
databaseURL: 'https://blah.firebaseio.com',
databaseAuthVariableOverride: null,
}, 'no-auth')
const userAuthApp = admin.initializeApp({
databaseURL: 'https://blah.firebaseio.com',
databaseAuthVariableOverride: {
uid: 'USER_ID_1',
},
}, 'user-auth')
const customClaimsAuthApp = admin.initializeApp({
databaseURL: 'https://blah.firebaseio.com',
databaseAuthVariableOverride: {
uid: 'USER_ABC',
token: {
customClaimAccess: 'USER_ID_2',
auth_time: (Date.now() / 1000)
},
},
}, 'custom-claims-auth')

const assert = require('assert').strict

async function test() {
await adminApp.database().ref().set({
USER_ID_1: {
data: {
blah: "hello1",
},
},
USER_ID_2: {
data: {
blah: "hello2",
},
},
USER_ID_3: {
publicAccess: true,
data: {
blah: "hello3",
},
}
})

await assert.rejects(noAuthApp.database().ref('USER_ID_1/data').once('value'), /permission_denied/i, 'Should deny access with noAuthApp as not accessing public data')
await assert.doesNotReject(userAuthApp.database().ref('USER_ID_1/data').once('value'), 'Should allow access with userAuthApp as accessing own data')
await assert.doesNotReject(customClaimsAuthApp.database().ref('USER_ID_2/data').once('value'), 'Should allow access with customClaimsAuthApp as accessing data specified in claims')
await assert.doesNotReject(noAuthApp.database().ref('USER_ID_3/data').once('value'), 'Should allow access with noAuthApp as accessing public data')
}

test().catch(error => {
console.error(error)
}).finally(() => Promise.all(admin.apps.map(a => a.delete())))
```

1. Run emulator `firebase --project blah emulators:start --only database` (can't use `emulators:exec` as need to keep it running to view the rule evaluations).
2. Run the above script against the emulator `FIREBASE_DATABASE_EMULATOR_HOST=localhost:9000 node script.js`.
3. View the evaluated DB rules: `http://localhost:9000/.inspect/coverage?ns=blah`

### [REQUIRED] Expected behavior

I'd expect the tests to pass and the `auth_time` rule to be evaluated 3 times - returning `true` once and `false` twice.

### [REQUIRED] Actual behavior

Rules are not always evaluated - seems to bail out...

![image](https://user-images.githubusercontent.com/1810588/90512933-cf534780-e156-11ea-9f93-7a3fcbc0bd35.png)
![image](https://user-images.githubusercontent.com/1810588/90512964-d712ec00-e156-11ea-9737-75e843ddaf07.png)
![image](https://user-images.githubusercontent.com/1810588/90512975-dda16380-e156-11ea-888e-af75f2a4d59b.png)

To simplify the case when running:

```js
await assert.rejects(noAuthApp.database().ref('USER_ID_1/data').once('value'), /permission_denied/i, 'Should deny access with noAuthApp as not accessing public data')
```

I'd expect this rule to be evaluated (as there's no `auth.uid`):
`(auth.token.auth_time >= ((now / 1000) - 60 * 60) && auth.token.customClaimAccess === $userId) || data.parent().child('publicAccess').val() === true`

![image](https://user-images.githubusercontent.com/1810588/90513400-82bc3c00-e157-11ea-856f-f04bd1856b46.png)

The whole rule seems not to be evaluated, despite the first rule being evaluated...!

![image](https://user-images.githubusercontent.com/1810588/90513651-e181b580-e157-11ea-96e3-413362f97beb.png)

![image](https://user-images.githubusercontent.com/1810588/90513709-f8c0a300-e157-11ea-8992-3257bf8f6a6d.png)

Contributor guide

Open the contributing guide

Research direction

Start the database emulator with `firebase --project blah emulators:start --only database`, then run the supplied Node.js reproduction with `FIREBASE_DATABASE_EMULATOR_HOST=localhost:9000`. Inspect the evaluated rules at `/.inspect/coverage?ns=blah`; done means all four assertions pass and the `auth_time` rule is evaluated three times, returning true once and false twice.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.