Using Firestore for Survey Data - everybody can write, a few can read - api

I'm setting up an online survey. This survey will be anonymous - to fill it all you need to have is the survey's URL. I want to store the survey answers in Firestore, and later run scripts that retrieve the data and generate reports.
I want to set it up so that everybody can write to it, but only specific accounts that have access to the project can read the data. I've set up the following rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth.uid != null;
allow write;
}
}
}
Now I want to create the script that reads the data, and I'm not sure - which API key should I use? Firestore automatically created a firebase-sdk-admin service account - should I use this account? There are also the Browser Key and Web client Key that were created automatically. Are those the ones to use?
What I would really want is to set up the script in a way that asks me for my Google Credentials (much like the gcloud sdk does it). That way there's no sensitive information in the script at all - if the script user logs in to Google with an account that has access to the database - it works. If it doesn't - it doesn't.
Can I do that?

You can either user Firebase Custom Claims which are basically like roles in Discord so or store UIDs of authorized users in Firestore or RTDB. Then you can write you security rules like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth.uid != null;
allow write: if request.auth.token.admin == true;
}
}
}
Now only the users with "admin" claim set to true will be able to write to those documents. If you go with storing the user UIDs in a Firestore document then you can check if user's UID is present their as shown below:
allow write: get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
Regarding the Service Account, you should not use them from frontend. They grant privileged access to your Firebase resources i.e. security rules are redundant. So you usually use them with the Firebase Admin SDK in a secure server env like Cloud functions. You can create a Firebase Cloud Function and then allow only whitelisted users to invoke it. That means if unauthenticated users or someone you haven't whitelisted won't be able to invoke it.
If you want to give access to your database to a teammate, then you can add members to your project from the Firebase Console. Let me know if you have any further queries.

I think I got it. Since I want to let everybody write, and only read data from scripts run by admins and not users, I can set up the following access rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if false;
allow write;
}
}
}
For reading, my scripts will authenticate as a service account (keeping the service account json file a secret), and will be able to read the data properly.

Related

Cloud Firestore: setting security rule based on authentication

I would like to understand how secure it is a security rule based on authentication, like this:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
I have collections where each document is relative to a specific user.
I am using Cloud Firestore only from mobile, both Android and iOS, not from web.
Is there any way for a user to get authenticated outside my mobile apps, and hence going to read or write some other user's documents?
If you want to make sure that users cannot read each other's information, you should implement stronger rules than auth != null.
For example, these rules make it so you can only read and write the data at /users/userId if you are authenticated as userId.
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
// Anybody can write to their ouser doc
allow read, write: if request.auth.uid == userId;
}
}
}
This will make it impossible for someone to "get authenticated outside my mobile apps, and hence going to read or write some other user's documents" as you mentioned.

React/Rebase/Firebase warning: Permission Denied - How do I add user authentication?

Please excuse the simplicity of my question but I can't get Rebase/Firebase to work due to permission errors (Rebase is very similar to Firebase https://github.com/tylermcginnis/re-base)
I am building a simple website as part of a React.js tutorial and I simply want to persist some state on my page. To do this, all I want is the Firebase database, without user authentication, however when I set up the database, I get permission errors so user authentication must be mandatory.
This is what I have at the top of my main.js:
var Rebase = require('re-base');
var base = Rebase.createClass('https://fishmonger-f3761.firebaseio.com/');
and then in my main app component, I added this:
componentDidMount : function() {
base.syncState(this.props.params.storeId + '/fishes', {
context : this,
state : 'fishes'
});
I get the following warning in my console:
FIREBASE WARNING: set at /(*my custom store name*)/fishes/fish1/name failed: permission_denied
How do I add in anonymous browser-session based user authentication to disregard this error?
Firebase DB default rules require authentication.
From the Get Started with Database Rules page:
By default, your database rules require Firebase Authentication and
grant full read and write permissions only to authenticated users. The
default rules ensure your database isn't accessible by just anyone
before you get a chance to configure it.
That means that, for instance, you can give access to anyone. You just need to change the default rules of your database to look like this (again from the same documentation page):
// These rules give anyone, even people who are not users of your app,
// read and write access to your database
{
"rules": {
".read": true,
".write": true
}
}
Read the other samples on the page I linked to find one that suit your needs.
EDIT
To access the rules go to your console (make sure you're logged in Google) and select "Database" in the sidebar menu, then click on the "rules" tab. The url should be something like https://console.firebase.google.com/project/<your-project>/database/rules

How to restrict access some part of module in ZendFramework 2 (i.e. only administrator can do some actions)

so!
I have a question: how to allow access some part of module only for adminisitrator, for example.
For example, I have module album. It has controllers index, delete, add, edit, full. I want full and index controller be available for all roles, but edit, delete and add action only for administrators.
What module I have to use to do that? I found Zend\Authentification.
Table is: username, password, role.
How to authentificate user?:
// do the authentication
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
// success: store database row to auth's storage
// system. (Not the password though!)
$data = $authAdapter->getResultRowObject(null, 'password');
$auth->getStorage()->write($data);
$this->_redirect('/');
} else {
// failure: clear database row from session
$this->view->message = 'Login failed.';
}
After that I will get access to user data, for example, by:
Zend_Auth::getInstance()->getIdentity()->username;
So, in action, in which I want to restrict access I just need to use:
if(Zend_Auth::getInstance()->getIdentity()->role == admin) {
redirect("auth/login");
}
Right?
The questions:
Is my suggestion about how to check user role in each contoller correct?
Do I understand correctly how to work with Zend\Authentification and restrict access to some actions? So in future I will just use same for each action, right?
Additional question: Does Aclmodule uses for managing permissions? So Acl is needed to help Zend_Auth with permissions, right?
To be able to do this you have to build or implement an ACL (Access Control List). You can also use a third party solution in combination with the earlier mentioned Zend_Auth (or any other authentication module). You can read more on Zend ACL here: Zend ACL introduction
You could for example also take a look at BjyAuthorize. This ACL module provides a complete authorization solution for your application but depends on ZfcUser for user authentication and registration. It might be a good way to get started.
If you are done building or implementing BjyAuthorize you can easily tie your access permission checking to your routes (but there are many other ways). You can see how this works here on the BjyAuthorize GitHub page
These modules will teach you a lot about how authentication and authorization can be build into your Zend Framework 2 application.

Limit logins via Github organizations in Firebase

I am working on an application using Firebase as the backend. I have a working implementation of GitHub authentication using Firebase. However, I want to limit my complete application (all read/write operations) to people in a specific GitHub organization.
From what I gather, it is to be done via adding Security Rules in Forge. However, the organization of a user is not part of the "basic auth data" that GitHub provides to Firebase for use. Is there any way for me to make the app available to members of a particular organization only?
Current Code:
var FB = new Firebase('https://XXXXX.firebaseio.com');
var auth = new FirebaseSimpleLogin(FB, function(error, user){
if(user==null){
auth.login('github',{rememberMe:true});
}
else{
//We are logged in
$.getJSON("https://api.github.com/user/orgs?access_token="+user.accessToken+"&callback=?", function(data){
var orgs = data.data.map(function(org){return org.login});
if(orgs.indexOf(config.github_org)>-1){
//Public Member of Chosen Github Org
//Now we fetch the data and render it
}
else{
//Throw them out
alert("Join the group "+config.github_org+" on GitHub to get access to Eon");
document.location="https://github.com/"+config.github_org;
}
})
}
});
To use FB Security Rules you'll need to compare the auth data with something in the Firebase (like a list of organizations), but it looks like you are trying to get those on the fly every time. Instead I'd recommend keeping a collection of users in your Firebase organized by their auth.uid that have organization lists you can check against:
users
uid1
...
uidX
orgs
org1
...
orgX
So when a user tries to access a given orgX you can check to see if root.child('users').child(auth.uid).child('orgs/orgX') exists in your Security Rules.

Disable Cloudant's _user database and go back to Cloudant's own security feature

I once enabled the _user database in my cloudant account to try out some things (via the HTTP PUT call to _security https://cloudant.com/for-developers/faq/auth/ last Paragraph), but now I would go back to the regular cloudant authentication. How can I make this happen?
You can enable regular Cloudant authentication by removing the "nobody" roles from the _security object. The "nobody" roles essentially let anyone through Cloudant's auth layer, so CouchDB's can kick in.
To do this you need to PUT a JSON document like the following to the _security endpoint of the database (for example https://USERNAME.cloudant.com/DATABASE/_security):
{
"cloudant": {
"nobody": []
}
}
I just got some feedback from the cloud ant IRC chat.
To reset the authentication system to the cloudant system I had so
PUT the following document to security
{
"cloudant": {
"nobody": []
},
"readers": {
"names":[],
"roles":[]
}
}
Thanks to user mikerhodes