Keeping Properties Secret in Neo4j

DZone 's Guide to

Keeping Properties Secret in Neo4j

Imagine you are working in Area 51 and have to deal with very important information. How do you give some people top secret access, some confidential access, and others no access?

· Database Zone ·
Free Resource

We're an open-source company with nothing to hide, but some of our customers have things they need to keep close to their chest. Sometimes, you don't want everybody to have access to salary information or future predictions. Maybe you want to hide personally identifiable information (PII) or Health Insurance Portability and Accountability Act (HIPPA) data. In Neo4j 3.4, we are introducing more security controls. We are starting with role-based database-wide property key blacklists. That's a bit of a mouthful, but let's walk through and look at an example to see one of the ways it can be utilized. Imagine you are working in Area 51 and have to deal with very important information.

You want your boss who has "top secret" access to know the truth, you want your friend James from Area 50 who has "secret" access to know a little less than the whole truth. You want those like Tim who have "confidential" access to know a little less than that, and finally, you want the public to know the least and only the unclassified information. We will need to change the neo4j.conf file in the config directory of our Neo4j installation, add a couple of lines, save the file, and restart Neo4j (on all cluster members):


In Neo4j Enterprise Edition, you will need to create a few accounts. The format is:

CALL dbms.security.createUser(username, password, requirePasswordChange)

So, for example:

CALL dbms.security.createUser("james", "1234", false); 
CALL dbms.security.createUser("tim", "5678", false);
CALL dbms.security.createUser("public", "password", false);

Next, we will create security roles for these accounts:

CALL dbms.security.createRole("Secret");
CALL dbms.security.createRole("Confidential");
CALL dbms.security.createRole("Unclassified");

And we will add the roles to the users:

CALL dbms.security.addRoleToUser("Secret", "james");
CALL dbms.security.addRoleToUser("Confidential", "tim");
CALL dbms.security.addRoleToUser("Unclassified", "public");

But before they can read anything from the database, they also need reader access:

CALL dbms.security.addRoleToUser("reader","james");
CALL dbms.security.addRoleToUser("reader","tim");
CALL dbms.security.addRoleToUser("reader","public");

We can call listRoles to see how it looks:

CALL dbms.security.listRoles();

Now that everything is set, we will create a report on the existence of "Aliens".

We have different versions of the truth, so we will create multiple properties to answer the question in our document:

CREATE (u:Document {name:'Aliens?', 
                    top_secret:'They hate us!', 
                    secret:'They like us!', 
                    confidential:'They exist!', 
                    public:'They do not exist.'})

We can query for the truth using COALESCE. It will use the first non-null property it finds. Since we are logged on as the Neo4j admin user with full access when we ask:

MATCH (u:Document {name:'Aliens?'})
RETURN COALESCE (u.top_secret, u.secret, u.confidential, u.public) AS truth

We get the real answer "They hate us!" Now, let's disconnect and try a different account.

:server disconnect

Log back in as James, and rerun the query and we get "They like us!" Disconnect again, and log back in as Tim and you get "They exist!" One more time as user public, and you get "They do not exist". Pretty neat right? So, you can use this feature to keep sensitive data away from people and also show different levels of detail. If you want to try it out, you can get a pre-release version of Neo4j 3.4 here.

database ,neo4j ,properties ,tutorial

Published at DZone with permission of Max De Marzi , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}