Skip to content

Commit

Permalink
Added editor role
Browse files Browse the repository at this point in the history
Added new role `Editor` that is allowed to read and write data but not
allowed to create new tokens
  • Loading branch information
OliviaYtterbrink committed Mar 23, 2017
1 parent 8ec070f commit 1211792
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 19 deletions.
Expand Up @@ -27,5 +27,6 @@ public class PredefinedRoles
public static final String ADMIN = "admin";
public static final String ARCHITECT = "architect";
public static final String PUBLISHER = "publisher";
public static final String EDITOR = "editor";
public static final String READER = "reader";
}
Expand Up @@ -181,7 +181,7 @@ private FunctionResult( UserFunctionSignature signature )
this.name = signature.name().toString();
this.signature = signature.toString();
this.description = signature.description().orElse( "" );
roles = Stream.of( "admin", "reader", "publisher", "architect" ).collect( toList() );
roles = Stream.of( "admin", "reader", "editor", "publisher", "architect" ).collect( toList() );
roles.addAll( Arrays.asList( signature.allowed() ) );
}
}
Expand Down Expand Up @@ -220,6 +220,7 @@ public ProcedureResult( ProcedureSignature signature )
case READ:
roles.add( "reader" );
case WRITE:
roles.add( "editor" );
roles.add( "publisher" );
case SCHEMA:
roles.add( "architect" );
Expand Down
Expand Up @@ -27,7 +27,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.*;
Expand All @@ -37,7 +36,7 @@ public class PredefinedRolesBuilder implements RolesBuilder
private static final WildcardPermission SCHEMA = new WildcardPermission( "schema:*" );
private static final WildcardPermission FULL = new WildcardPermission( "*" );
private static final WildcardPermission TOKEN = new WildcardPermission( "token:*" );
private static final WildcardPermission WRITE = new WildcardPermission( "data:*" );
private static final WildcardPermission READ_WRITE = new WildcardPermission( "data:*" );
private static final WildcardPermission READ = new WildcardPermission( "data:read" );

private static final Map<String,SimpleRole> innerRoles = staticBuildRoles();
Expand All @@ -53,15 +52,19 @@ private static Map<String,SimpleRole> staticBuildRoles()

SimpleRole architect = new SimpleRole( ARCHITECT );
architect.add( SCHEMA );
architect.add( WRITE );
architect.add( READ_WRITE );
architect.add( TOKEN );
roles.put( ARCHITECT, architect );

SimpleRole publisher = new SimpleRole( PUBLISHER );
publisher.add( WRITE );
publisher.add( READ_WRITE );
publisher.add( TOKEN );
roles.put( PUBLISHER, publisher );

SimpleRole editor = new SimpleRole( EDITOR );
editor.add( READ_WRITE );
roles.put( EDITOR, editor );

SimpleRole reader = new SimpleRole( READER );
reader.add( READ );
roles.put( READER, reader );
Expand Down Expand Up @@ -95,5 +98,4 @@ public Map<String,SimpleRole> buildRoles()
{
return roles;
}

}
Expand Up @@ -48,6 +48,7 @@
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ARCHITECT;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.PUBLISHER;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.READER;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.EDITOR;

public abstract class AuthProceduresInteractionTestBase<S> extends ProcedureInteractionTestBase<S>
{
Expand Down Expand Up @@ -686,6 +687,7 @@ public void shouldReturnUsersWithRoles() throws Exception
"readSubject", listOf( READER ),
"schemaSubject", listOf( ARCHITECT ),
"writeSubject", listOf( READER, PUBLISHER ),
"editorSubject", listOf( EDITOR ),
"pwdSubject", listOf( ),
"noneSubject", listOf( ),
"neo4j", listOf( ADMIN )
Expand All @@ -702,6 +704,7 @@ public void shouldReturnUsersWithFlags() throws Exception
"adminSubject", listOf(),
"readSubject", listOf(),
"schemaSubject", listOf(),
"editorSubject", listOf(),
"writeSubject", listOf( IS_SUSPENDED ),
"pwdSubject", listOf( PWD_CHANGE, IS_SUSPENDED ),
"noneSubject", listOf(),
Expand Down Expand Up @@ -756,6 +759,7 @@ ADMIN, listOf( "adminSubject", "neo4j" ),
READER, listOf( "readSubject" ),
ARCHITECT, listOf( "schemaSubject" ),
PUBLISHER, listOf( "writeSubject" ),
EDITOR, listOf( "editorSubject" ),
"empty", listOf()
);
assertSuccess( adminSubject, "CALL dbms.security.listRoles()",
Expand Down Expand Up @@ -979,16 +983,29 @@ public void shouldSetCorrectReaderPermissions() throws Exception
{
testSuccessfulRead( readSubject, 3 );
testFailWrite( readSubject );
testFailTokenWrite( readSubject, WRITE_OPS_NOT_ALLOWED );
testFailSchema( readSubject );
testFailCreateUser( readSubject, PERMISSION_DENIED );
assertEmpty( readSubject, "CALL dbms.security.changePassword( '321' )" );
}

@Test
public void shouldSetCorrectEditorPermissions() throws Exception
{
testSuccessfulRead( editorSubject, 3 );
testSuccessfulWrite( editorSubject );
testFailTokenWrite( editorSubject );
testFailSchema( editorSubject );
testFailCreateUser( editorSubject, PERMISSION_DENIED );
assertEmpty( editorSubject, "CALL dbms.security.changePassword( '321' )" );
}

@Test
public void shouldSetCorrectPublisherPermissions() throws Exception
{
testSuccessfulRead( writeSubject, 3 );
testSuccessfulWrite( writeSubject );
testSuccessfulTokenWrite( writeSubject );
testFailSchema( writeSubject );
testFailCreateUser( writeSubject, PERMISSION_DENIED );
assertEmpty( writeSubject, "CALL dbms.security.changePassword( '321' )" );
Expand All @@ -999,6 +1016,7 @@ public void shouldSetCorrectSchemaPermissions() throws Exception
{
testSuccessfulRead( schemaSubject, 3 );
testSuccessfulWrite( schemaSubject );
testSuccessfulTokenWrite( schemaSubject );
testSuccessfulSchema( schemaSubject );
testFailCreateUser( schemaSubject, PERMISSION_DENIED );
assertEmpty( schemaSubject, "CALL dbms.security.changePassword( '321' )" );
Expand All @@ -1009,6 +1027,7 @@ public void shouldSetCorrectAdminPermissions() throws Exception
{
testSuccessfulRead( adminSubject, 3 );
testSuccessfulWrite( adminSubject );
testSuccessfulTokenWrite( adminSubject );
testSuccessfulSchema( adminSubject );
assertEmpty( adminSubject, "CALL dbms.security.createUser('Olivia', 'bar', true)" );
assertEmpty( adminSubject, "CALL dbms.security.changePassword( '321' )" );
Expand Down
Expand Up @@ -320,6 +320,46 @@ public void shouldListAllQueriesWithAuthDisabled() throws Throwable
read.closeAndAssertSuccess();
}

//---------- Create Tokens query -------

@Test
public void shouldCreateLabel()
{
assertFail( editorSubject, "CREATE (:MySpecialLabel)", TOKEN_CREATE_OPS_NOT_ALLOWED );
assertFail( editorSubject, "CALL db.createLabel('MySpecialLabel')", TOKEN_CREATE_OPS_NOT_ALLOWED );
assertEmpty( writeSubject, "CALL db.createLabel('MySpecialLabel')" );
assertSuccess( writeSubject, "MATCH (n:MySpecialLabel) RETURN count(n) AS count",
r -> r.next().get( "count" ).equals( 0 ) );
assertEmpty( editorSubject, "CREATE (:MySpecialLabel)" );
}

@Test
public void shouldCreateRelationshipType()
{
assertEmpty( writeSubject, "CREATE (a:Node {id:0}) CREATE ( b:Node {id:1} )" );
assertFail( editorSubject,
"MATCH (a:Node), (b:Node) WHERE a.id = 0 AND b.id = 1 CREATE (a)-[:MySpecialRelationship]->(b)",
TOKEN_CREATE_OPS_NOT_ALLOWED );
assertFail( editorSubject, "CALL db.createRelationshipType('MySpecialRelationship')",
TOKEN_CREATE_OPS_NOT_ALLOWED );
assertEmpty( writeSubject, "CALL db.createRelationshipType('MySpecialRelationship')" );
assertSuccess( editorSubject, "MATCH (n)-[c:MySpecialRelationship]-(m) RETURN count(c) AS count",
r -> r.next().get( "count" ).equals( 0 ) );
assertEmpty( editorSubject,
"MATCH (a:Node), (b:Node) WHERE a.id = 0 AND b.id = 1 CREATE (a)-[:MySpecialRelationship]->(b)" );
}

@Test
public void shouldCreateProperty()
{
assertFail( editorSubject, "CREATE (a) SET a.MySpecialProperty = 'a'", TOKEN_CREATE_OPS_NOT_ALLOWED );
assertFail( editorSubject, "CALL db.createProperty('MySpecialProperty')", TOKEN_CREATE_OPS_NOT_ALLOWED );
assertEmpty( writeSubject, "CALL db.createProperty('MySpecialProperty')" );
assertSuccess( editorSubject, "MATCH (n) WHERE n.MySpecialProperty IS NULL RETURN count(n) AS count",
r -> r.next().get( "count" ).equals( 0 ) );
assertEmpty( editorSubject, "CREATE (a) SET a.MySpecialProperty = 'a'" );
}

//---------- terminate query -----------

/*
Expand Down
Expand Up @@ -40,6 +40,7 @@
import static org.neo4j.helpers.collection.MapUtil.stringMap;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ADMIN;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ARCHITECT;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.EDITOR;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.PUBLISHER;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.READER;

Expand Down Expand Up @@ -101,6 +102,7 @@ public void shouldNotWarnWhenOnlyUsingNativeProvider() throws Throwable
"readSubject", listOf( READER ),
"schemaSubject", listOf( ARCHITECT ),
"writeSubject", listOf( PUBLISHER ),
"editorSubject", listOf( EDITOR ),
"pwdSubject", listOf( ),
"noneSubject", listOf( ),
"neo4j", listOf( ADMIN )
Expand Down
Expand Up @@ -46,6 +46,7 @@
import static org.neo4j.helpers.collection.MapUtil.stringMap;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ADMIN;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ARCHITECT;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.EDITOR;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.PUBLISHER;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.READER;

Expand Down Expand Up @@ -231,17 +232,17 @@ public void shouldShowAllowedRolesWhenListingProcedures() throws Throwable
SecuritySettings.default_allowed.name(), "default" ) );

Map<String,Set<String>> expected = genericMap(
"test.staticReadProcedure", newSet( "default", READER, PUBLISHER, ARCHITECT, ADMIN ),
"test.staticWriteProcedure", newSet( "default", PUBLISHER, ARCHITECT, ADMIN ),
"test.staticReadProcedure", newSet( "default", READER, EDITOR, PUBLISHER, ARCHITECT, ADMIN ),
"test.staticWriteProcedure", newSet( "default", EDITOR, PUBLISHER, ARCHITECT, ADMIN ),
"test.staticSchemaProcedure", newSet( "default", ARCHITECT, ADMIN ),
"test.annotatedProcedure", newSet( "annotated", READER, PUBLISHER, ARCHITECT, ADMIN ),
"test.numNodes", newSet( "counter", "user", READER, PUBLISHER, ARCHITECT, ADMIN ),
"db.labels", newSet( "default", READER, PUBLISHER, ARCHITECT, ADMIN ),
"test.annotatedProcedure", newSet( "annotated", READER, EDITOR, PUBLISHER, ARCHITECT, ADMIN ),
"test.numNodes", newSet( "counter", "user", READER, EDITOR, PUBLISHER, ARCHITECT, ADMIN ),
"db.labels", newSet( "default", READER, EDITOR, PUBLISHER, ARCHITECT, ADMIN ),
"dbms.security.changePassword", newSet( ADMIN ),
"dbms.procedures", newSet( ADMIN ),
"dbms.listQueries", newSet( ADMIN ),
"dbms.security.createUser", newSet( ADMIN ),
"db.createLabel", newSet( "default", PUBLISHER, ARCHITECT, ADMIN ));
"db.createLabel", newSet( "default", EDITOR, PUBLISHER, ARCHITECT, ADMIN ));

String call = "CALL dbms.procedures";
assertListProceduresHasRoles( adminSubject, expected, call );
Expand All @@ -258,9 +259,9 @@ public void shouldShowAllowedRolesWhenListingFunctions() throws Throwable
SecuritySettings.default_allowed.name(), "default" ) );

Map<String,Set<String>> expected = genericMap(
"test.annotatedFunction", newSet( "annotated", READER, PUBLISHER, ARCHITECT, ADMIN ),
"test.allowedFunc", newSet( "counter", "user", READER, PUBLISHER, ARCHITECT, ADMIN ),
"test.nonAllowedFunc", newSet( "default", READER, PUBLISHER, ARCHITECT, ADMIN ) );
"test.annotatedFunction", newSet( "annotated", READER, EDITOR, PUBLISHER, ARCHITECT, ADMIN ),
"test.allowedFunc", newSet( "counter", "user", READER, EDITOR, PUBLISHER, ARCHITECT, ADMIN ),
"test.nonAllowedFunc", newSet( "default", READER, EDITOR, PUBLISHER, ARCHITECT, ADMIN ) );

String call = "CALL dbms.functions";
assertListProceduresHasRoles( adminSubject, expected, call );
Expand Down
Expand Up @@ -88,6 +88,7 @@
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ARCHITECT;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.PUBLISHER;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.READER;
import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.EDITOR;

public abstract class ProcedureInteractionTestBase<S>
{
Expand All @@ -113,13 +114,14 @@ String pwdReqErrMsg( String errMsg )
S adminSubject;
S schemaSubject;
S writeSubject;
S editorSubject;
S readSubject;
S pwdSubject;
S noneSubject;

String[] initialUsers = { "adminSubject", "readSubject", "schemaSubject",
"writeSubject", "pwdSubject", "noneSubject", "neo4j" };
String[] initialRoles = { ADMIN, ARCHITECT, PUBLISHER, READER, EMPTY_ROLE };
"writeSubject", "editorSubject", "pwdSubject", "noneSubject", "neo4j" };
String[] initialRoles = { ADMIN, ARCHITECT, PUBLISHER, EDITOR, READER, EMPTY_ROLE };

@Rule
public final ThreadingRule threading = new ThreadingRule();
Expand Down Expand Up @@ -160,16 +162,19 @@ void configuredSetup( Map<String,String> config ) throws Throwable
userManager.newUser( "adminSubject", "abc", false );
userManager.newUser( "schemaSubject", "abc", false );
userManager.newUser( "writeSubject", "abc", false );
userManager.newUser( "editorSubject", "abc", false );
userManager.newUser( "readSubject", "123", false );
// Currently admin role is created by default
userManager.addRoleToUser( ADMIN, "adminSubject" );
userManager.addRoleToUser( ARCHITECT, "schemaSubject" );
userManager.addRoleToUser( PUBLISHER, "writeSubject" );
userManager.addRoleToUser( EDITOR, "editorSubject" );
userManager.addRoleToUser( READER, "readSubject" );
userManager.newRole( EMPTY_ROLE );
noneSubject = neo.login( "noneSubject", "abc" );
pwdSubject = neo.login( "pwdSubject", "abc" );
readSubject = neo.login( "readSubject", "123" );
editorSubject = neo.login( "editorSubject", "abc" );
writeSubject = neo.login( "writeSubject", "abc" );
schemaSubject = neo.login( "schemaSubject", "abc" );
adminSubject = neo.login( "adminSubject", "abc" );
Expand Down Expand Up @@ -235,6 +240,21 @@ void testFailWrite( S subject, String errMsg )
assertFail( subject, "CREATE (:Node)", errMsg );
}

void testSuccessfulTokenWrite( S subject )
{
assertEmpty( subject, "CALL db.createLabel('NewNodeName')" );
}

void testFailTokenWrite( S subject )
{
testFailTokenWrite( subject, TOKEN_CREATE_OPS_NOT_ALLOWED );
}

void testFailTokenWrite( S subject, String errMsg )
{
assertFail( subject, "CALL db.createLabel('NewNodeName')", errMsg );
}

void testSuccessfulSchema( S subject )
{
assertEmpty( subject, "CREATE INDEX ON :Node(number)" );
Expand Down
Expand Up @@ -66,10 +66,10 @@ public void shouldHavePredefinedRoles() throws Exception
assertThat( "Should have no errors", errors.size(), equalTo( 0 ) );
ArrayNode results = (ArrayNode) response.get("results");
ArrayNode data = (ArrayNode) results.get(0).get("data");
assertThat( "Should have 4 predefined roles", data.size(), equalTo( 4 ) );
assertThat( "Should have 5 predefined roles", data.size(), equalTo( 5 ) );
Stream<String> values = data.findValues( "row" ).stream().map( row -> row.get(0).asText() );
assertThat( "Expected specific roles", values.collect( Collectors.toList()),
hasItems( "admin", "architect", "publisher", "reader") );
hasItems( "admin", "architect", "publisher", "editor", "reader") );

}

Expand Down

0 comments on commit 1211792

Please sign in to comment.