Realtime Cloud Storage
Security

  • Feb 27, 2015
  • Starting Guide

Security is a key feature in any enterprise-grade storage solution and Realtime Cloud Storage gives you the right tools to secure your data. The first thing you must guarantee is that your Cloud Storage application key has the authentication feature turned on. You can turn it on using the Realtime.co Web Console.

Go to your subscriptions page and click the details link on the Realtime Cloud Storage subscription in which you want to activate authentication:

Edit the subscription details by clicking the “Edit Subscription Details” link as shown at the following picture:

Slide the authentication slider-button to the ON position and click SAVE:

From this point on only authenticated users (represented by tokens) will be able to use your Cloud Storage and perform the operations you allow them to do. How? You just need to authenticate the tokens you provide to them. But before we dive into the actual authentication procedures, let’s understand a bit better the Realtime Cloud Storage Security model.

ROLES

When you define a role you are defining a set of permissions known as policies. Policies are divided into three groups:

Database policies: refer to general database operations like create a table or list the existing tables;

Table policies: refer to specific tables on your database;

Item policies: refer to specific items of specific tables in your database.

After defining your roles you can use them to authenticate users assigning them the appropriate roles.

Let’s say you want to allow users to read any item from the ProductCatalog table but restrict them from updating or deleting items. You could define a role named ReadOnly and grant READ permission to the ProductCatalog table by adding a table policy with “allow read”. Since by default all operations are restricted you don’t need to define a policy to deny the updates and deletes, they are denied by default.

To define the ReadOnly role using the Realtime.co Web Console you would need to click the Roles button at the Storage console page:

At the roles page click the “Create Role” button. You’ll be presented with the following page where you should enter the role name, ReadOnly, and select the Table Policies tab.

Now let’s click the “Add Table Rule” button. To define the “allow read” from ProductCatalog select the ProductCatalog table from the tables dropdown and check the read check-box at the “Access Item Rules”.

NOTE: You could add more tables to the role by clicking the “Add Table Rule” button and repeat the process until you have defined the policies for all the desired tables.

When you’re ready to save your new role just click the “Save Role” button on the bottom of the page. You can now use this role when you authenticate your read-only users.

TOKENS

An authentication token is a set of policies (database, table and item policies) and it’s represented by a string.

Let’s say you want that all the anonymous users, those who are not logged in into your application, can only read from your ProductCatalog table. Since you have already the ReadOnly role with that set of policies you just need to authenticate a token using the ReadOnly role (the token will inherit the role policies). You could name the token Anonymous.

To do this using the Web Console you need to navigate to the Autentication page by clicking the Authentication button on your Realtime Cloud Storage console.

At the authentication page you just need to enter the token name, Anonymous, define the time-to-live in seconds (the maximum inactivity time for the token to remain valid) and select the appropriate role, in this example the ReadOnly role. Click SAVE to authenticate the token.

From this point on you’re able to create a storage reference using the Anonymous token. Here’s an example using the JavaScript SDK:

var storageRef;
var credentials = {
  applicationKey: "[YOUR_APP_KEY]", // Your application key
  authenticationToken: "Anonymous", // Representing this user permissions
  isSecure: true                    // Use SSL connection
};
Realtime.Storage.create(
credentials,
     function(ref) {
            storageRef = ref;  // Keep the Storage Reference
            startApp();        // Start using the Cloud Storage
     },
     function(error){
            console.log(“Error connecting to the Storage”, error);
     }
);

Now, whenever this storageRef is used to perform an operation the Realtime Cloud Storage Security System will verify if the request token allows the operation being performed. If it’s not allowed an error will be generated and the operation will be immediately aborted. On the other hand if the token allows the operation it will proceed as normal.

The authentication procedure can also be performed programmatically using the NodeJS SDK (the JavaScript SDK doesn’t allow you to perform authentications for security reasons, since it would compromise your private key which should remain private at all times).

Here’s an example of how you would authenticate the Anonymous token using the NodeJS SDK:

var Realtime = require("realtime-storage");
 
Realtime.Storage.create({
      applicationKey: "[YOUR_APP_KEY]",
      // Must use privateKey to authenticate tokens and manage roles
      privateKey: "[YOUR_PRIVATE_KEY]"
  }, 
  function(ref) {  
      ref.authenticate({
           // The token name
           authenticationToken: "Anonymous",
           // The token is valid for 900 seconds
           timeout: 900,
           // The token will inherit the policies of the ReadOnly role
           roles: ["ReadOnly"]       
      }, function(success) {
           if (success) {
                  console.log("Token was successfully authenticated.");
           }
      }, function(error) {
          console.log("Error authenticating: ", error);
      });   
  }, 
  function(error) {
    console.log("Error connecting: ", error);
  }
);

A complete example of security features can be found at https://github.com/realtime-framework/Storage/tree/master/nodejs-auth-example

When users share the same policies they can share the same authentication token, but if each user has a different set of policies than you will need to authenticate a token for each user.

A good practice is to authenticate the user’s token when he logs in and starts a session in your app. A randomly generated string appended to the user login is generally a good way to have individual tokens. Also, if you need to add a specific policy to a certain user you could authenticate an individual token inheriting from the ReadOnly role and add the specific policies.

Let’s say you want user John Doe to be able to read and update any item in the ProductCatalog table. You could use the ReadOnly role and add a specific table policy allowing the updates.

It would look like this if using the NodeJS SDK:

var Realtime = require("realtime-storage");
 
Realtime.Storage.create(
    {
        applicationKey: "[YOUR_APP_KEY]",
        // Must use privateKey to authenticate tokens and manage roles
        privateKey: "[YOUR_PRIVATE_KEY]"
    }, 
    function(ref) {  
 
        ref.authenticate(
          {
            // The token name
            authenticationToken: "JohnDoe_Some_Random_String_Like_A_GUID",
            // The token is valid for 900 seconds
            timeout: 900,
            // The token will inherit the policies of the ReadOnly role
            roles: ["ReadOnly"],
            // The additional update policy for ProductCatalog table
            policies: {               
                tables: {
                   "ProductCatalog": {
                          //Set the update policy
                          //"U" means UPDATE
                          allow: "U"
                   }
                }
            }             
          }, 
          function(success) {
             if (success) {
                    console.log("Token was successfully authenticated.");
             }
          }, 
          function(error) {
            console.log("Error authenticating: ", error);
          }
        );   
    }, 
    function(error) {
      console.log("Error connecting: ", error);
    }
);

After this authentication the user John Doe could create a Storage Reference using the JohnDoe_Some_Random_String_Like_A_GUID token. Any update to any item in table ProductCatalog could be performed through that Storage Reference.

What if John Doe could only update the “Cannondale 2013 Trail SL 29ER” item at the ProductCatalog table? Then, instead of adding a general table policy to John Doe’s token you would need to add a specific item policy referring the item primary key (B00EP1D35O, see the previous “Applying filters” section of this documentation to understand why this is the primary key).

For this purpose the policies object used to authenticate the token would be like this:

policies: {               
    tables: {
           "ProductCatalog": {
                // Set the update policy for specific item
                // with primary key == “B00EP1D35O”
                // "U" means UPDATE
                items: [
                  { key: {primary: “B00EP1D35O”}, allow: “U” }
                ]
           }
    }
}

Back to Real-time notifications or proceed to Mobile Push Notifications

If you find this interesting please share: