Skip to content

Commit

Permalink
Implemented the listUsersForRole procedure
Browse files Browse the repository at this point in the history
  • Loading branch information
OliviaYtterbrink authored and henriknyman committed Jun 16, 2016
1 parent 53f1c09 commit 27d2373
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ public Stream<StringResult> listRolesForUser( @Name( "username" ) String usernam
return shiroSubject.getRoleManager().getRoleNamesForUser( username ).stream().map( StringResult::new );
}

@PerformsDBMS
@Procedure( "dbms.listUsersForRole" )
public Stream<StringResult> listUsersForRole( @Name( "roleName" ) String roleName )
throws IllegalCredentialsException, IOException
{
ShiroAuthSubject shiroSubject = ShiroAuthSubject.castOrFail( authSubject );
if ( !shiroSubject.isAdmin() )
{
throw new AuthorizationViolationException( PERMISSION_DENIED );
}
return shiroSubject.getRoleManager().getUsernamesForRole( roleName ).stream().map( StringResult::new );
}

public class StringResult {
public final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ public interface RoleManager
Set<String> getAllRoleNames();

Set<String> getRoleNamesForUser( String username );

Set<String> getUsernamesForRole( String roleName );
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,18 @@ public Set<String> getRoleNamesForUser( String username )
return roleRepository.findRoleNamesByUsername( username );
}

@Override
public Set<String> getUsernamesForRole( String roleName )
{
assertAuthEnabled();
RoleRecord role = roleRepository.findByName( roleName );
if (role == null)
{
throw new IllegalArgumentException( "Role " + roleName + " does not exist." );
}
return role.users();
}

public Set<String> getAllUsernames()
{
assertAuthEnabled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public void setUp() throws Throwable
manager.newRole( PredefinedRolesBuilder.ARCHITECT, "schemaSubject" );
manager.newRole( PredefinedRolesBuilder.PUBLISHER, "readWriteSubject" );
manager.newRole( PredefinedRolesBuilder.READER, "readSubject" );
manager.newRole( "empty" );
noneSubject = manager.login( authToken( "noneSubject", "abc" ) );
readSubject = manager.login( authToken( "readSubject", "123" ) );
writeSubject = manager.login( authToken( "readWriteSubject", "abc" ) );
Expand Down Expand Up @@ -722,8 +723,8 @@ public void shouldReturnRoles() throws Exception
List<Object> roles = getObjectsAsList( r, "roles" );
Assert.assertThat( roles,
containsInAnyOrder( PredefinedRolesBuilder.ADMIN, PredefinedRolesBuilder.ARCHITECT,
PredefinedRolesBuilder.PUBLISHER, PredefinedRolesBuilder.READER ) );
assertEquals( 4, roles.size() );
PredefinedRolesBuilder.PUBLISHER, PredefinedRolesBuilder.READER, "empty" ) );
assertEquals( 5, roles.size() );
} );
}

Expand Down Expand Up @@ -827,6 +828,49 @@ public void listingUserRoles() throws Exception
} );
}

@Test
public void shouldListUsersForRole() throws Exception
{
testResult( db, adminSubject, "CALL dbms.listUsersForRole('admin') YIELD value as users RETURN users",
r -> {
List<Object> usernames = getObjectsAsList( r, "users" );
Assert.assertThat( usernames, containsInAnyOrder( adminSubject.name(), "neo4j" ) );
assertEquals( 2, usernames.size() );
} );
}

@Test
public void shouldNotAllowNonAdminListRoleUsers() throws Exception
{
testFailListRoleUsers( noneSubject, PredefinedRolesBuilder.ADMIN );
testFailListRoleUsers( readSubject, PredefinedRolesBuilder.ADMIN);
testFailListRoleUsers( writeSubject, PredefinedRolesBuilder.ADMIN );
testFailListRoleUsers( schemaSubject, PredefinedRolesBuilder.ADMIN );
}

@Test
public void shouldFailToListUsersForUnknownRole() throws Exception
{
try
{
testResult( db, adminSubject, "CALL dbms.listUsersForRole('Foo') YIELD value as users RETURN users",
r -> assertFalse( r.hasNext() ) );
fail( "Expected exception to be thrown" );
}
catch ( QueryExecutionException e )
{
assertTrue( "Exception should contain 'Role Foo does not exist.' but was " + e.getMessage(),
e.getMessage().contains( "Role Foo does not exist." ) );
}
}

@Test
public void shouldListNoUsersForRoleWithNoUsers() throws Exception
{
testResult( db, adminSubject, "CALL dbms.listUsersForRole('empty') YIELD value as users RETURN users",
r -> assertFalse( r.hasNext() ) );
}

//-------------Helper functions---------------

private void testSuccessfulReadAction( AuthSubject subject, Long count )
Expand Down Expand Up @@ -969,7 +1013,7 @@ private void testFailListUsers( AuthSubject subject, Long count )
private void testSuccessfulListRolesAction( AuthSubject subject )
{
testCall( db, subject, "CALL dbms.listRoles() YIELD value AS roles RETURN count(roles)",
( r ) -> assertEquals( r.get( "count(roles)" ), 4L ) );
( r ) -> assertEquals( r.get( "count(roles)" ), 5L ) );
}

private void testFailListRoles( AuthSubject subject )
Expand Down Expand Up @@ -1004,6 +1048,26 @@ private void testFailListUserRoles( AuthSubject subject, String username )
}
}

private void testSuccessfulListRoleUsersAction( AuthSubject subject, String roleName )
{
testCall( db, subject,
"CALL dbms.listUsersForRole('" + roleName + "') YIELD value AS users RETURN count(users)",
Map::clear );
}

private void testFailListRoleUsers( AuthSubject subject, String roleName )
{
try
{
testSuccessfulListRoleUsersAction( subject, roleName );
}
catch ( QueryExecutionException e )
{
assertTrue( "Exception should contain '" + AuthProcedures.PERMISSION_DENIED + "'",
e.getMessage().contains( AuthProcedures.PERMISSION_DENIED ) );
}
}

private List<Object> getObjectsAsList( Result r, String key )
{
return r.stream().map( s -> s.get( key ) ).collect( Collectors.toList() );
Expand Down

0 comments on commit 27d2373

Please sign in to comment.