Skip to content

Commit

Permalink
Add roles command to the neo4j-admin tool
Browse files Browse the repository at this point in the history
- Added support for subcommands `list`, `create`, `delete`
- Refactor shared test code with `users` command
  • Loading branch information
Mats-SX authored and craigtaverner committed Sep 14, 2016
1 parent 866cc6b commit 3ed1a77
Show file tree
Hide file tree
Showing 12 changed files with 632 additions and 82 deletions.
Expand Up @@ -20,13 +20,13 @@
package org.neo4j.commandline.admin.security; package org.neo4j.commandline.admin.security;


import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.RuleChain;


import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;


import org.neo4j.commandline.admin.AdminTool;
import org.neo4j.commandline.admin.CommandLocator;
import org.neo4j.commandline.admin.OutsideWorld; import org.neo4j.commandline.admin.OutsideWorld;
import org.neo4j.io.fs.DelegateFileSystemAbstraction; import org.neo4j.io.fs.DelegateFileSystemAbstraction;
import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.io.fs.FileSystemAbstraction;
Expand All @@ -37,20 +37,18 @@
import org.neo4j.server.security.auth.User; import org.neo4j.server.security.auth.User;
import org.neo4j.test.rule.TestDirectory; import org.neo4j.test.rule.TestDirectory;


import static org.hamcrest.CoreMatchers.hasItem; import static org.mockito.Matchers.anyString;
import static org.hamcrest.Matchers.not; import static org.mockito.Matchers.contains;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;


public class CommandTestBase abstract class CommandTestBase
{ {
protected static String password_change_required = "password_change_required";
protected TestDirectory testDir = TestDirectory.testDirectory(); protected TestDirectory testDir = TestDirectory.testDirectory();
protected FileSystemAbstraction fileSystem = new DelegateFileSystemAbstraction( FileSystems.getDefault() ); protected FileSystemAbstraction fileSystem = new DelegateFileSystemAbstraction( FileSystems.getDefault() );


@Rule
public RuleChain ruleChain = RuleChain.outerRule( testDir );
File graphDir; File graphDir;
File confDir; File confDir;
File homeDir; File homeDir;
Expand Down Expand Up @@ -81,12 +79,12 @@ protected void resetOutsideWorldMock()
when( out.fileSystem() ).thenReturn( fileSystem ); when( out.fileSystem() ).thenReturn( fileSystem );
} }


protected File authFile() private File authFile()
{ {
return new File( new File( new File( testDir.graphDbDir(), "data" ), "dbms" ), "auth" ); return new File( new File( new File( testDir.graphDbDir(), "data" ), "dbms" ), "auth" );
} }


protected User createTestUser( String username, String password ) throws IOException, InvalidArgumentsException User createTestUser( String username, String password ) throws IOException, InvalidArgumentsException
{ {
FileUserRepository users = new FileUserRepository( fileSystem, authFile(), NullLogProvider.getInstance() ); FileUserRepository users = new FileUserRepository( fileSystem, authFile(), NullLogProvider.getInstance() );
User user = User user =
Expand All @@ -96,26 +94,60 @@ protected User createTestUser( String username, String password ) throws IOExcep
return user; return user;
} }


protected User getUser( String username ) throws Throwable User getUser( String username ) throws Throwable
{ {
FileUserRepository afterUsers = FileUserRepository afterUsers =
new FileUserRepository( fileSystem, authFile(), NullLogProvider.getInstance() ); new FileUserRepository( fileSystem, authFile(), NullLogProvider.getInstance() );
afterUsers.start(); // load users from disk afterUsers.start(); // load users from disk
return afterUsers.getUserByName( username ); return afterUsers.getUserByName( username );
} }


protected void assertUserRequiresPasswordChange( String username ) throws Throwable String[] args(String... args)
{ {
User user = getUser( username ); return args;
assertThat( "User should require password change", user.getFlags(), hasItem( password_change_required ) ); }

protected abstract String command();

private String[] makeArgs( String subCommand, String... args )
{
String[] allArgs = new String[args.length + 2];
System.arraycopy( args, 0, allArgs, 2, args.length );
allArgs[0] = command();
allArgs[1] = subCommand;
return allArgs;
}

void assertFailedSubCommand( String command, String[] args, String... errors )
{
// When running set password on a failing case (missing user, or other error)
resetOutsideWorldMock();
AdminTool tool = new AdminTool( CommandLocator.fromServiceLocator(), out, true );
tool.execute( graphDir.toPath(), confDir.toPath(), makeArgs( command, args ) );


// Then we get the expected error
for ( String error : errors )
{
verify( out ).stdErrLine( contains( error ) );
}
verify( out, times( 0 ) ).stdOutLine( anyString() );
verify( out ).exit( 1 );
} }


protected void assertUserDoesNotRequirePasswordChange( String username ) throws Throwable void assertSuccessfulSubCommand( String command, String[] args, String... messages )
{ {
User user = getUser( username ); // When running set password on a successful case (user exists)
assertThat( "User should not require password change", user.getFlags(), resetOutsideWorldMock();
not( hasItem( password_change_required ) ) ); AdminTool tool = new AdminTool( CommandLocator.fromServiceLocator(), out, true );
tool.execute( graphDir.toPath(), confDir.toPath(), makeArgs( command, args ));


// Then we get the expected output messages
for ( String message : messages )
{
verify( out ).stdOutLine( contains( message ) );
}
verify( out, times( 0 ) ).stdErrLine( anyString() );
verify( out ).exit( 0 );
} }

} }
Expand Up @@ -19,7 +19,9 @@
*/ */
package org.neo4j.commandline.admin.security; package org.neo4j.commandline.admin.security;


import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.RuleChain;


import org.neo4j.commandline.admin.CommandFailed; import org.neo4j.commandline.admin.CommandFailed;


Expand All @@ -30,8 +32,11 @@
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;


public class CreateCommandTest extends CommandTestBase public class CreateCommandTest extends UsersCommandTestBase
{ {
@Rule
public RuleChain ruleChain = RuleChain.outerRule( testDir );

@Test @Test
public void shouldFailToCreateExistingUser() throws Throwable public void shouldFailToCreateExistingUser() throws Throwable
{ {
Expand Down
Expand Up @@ -32,7 +32,7 @@
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;


public class DeleteCommandTest extends CommandTestBase public class DeleteCommandTest extends UsersCommandTestBase
{ {
@Rule @Rule
public RuleChain ruleChain = RuleChain.outerRule( testDir ); public RuleChain ruleChain = RuleChain.outerRule( testDir );
Expand Down
Expand Up @@ -32,7 +32,7 @@
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;


public class ListCommandTest extends CommandTestBase public class ListCommandTest extends UsersCommandTestBase
{ {
@Rule @Rule
public RuleChain ruleChain = RuleChain.outerRule( testDir ); public RuleChain ruleChain = RuleChain.outerRule( testDir );
Expand Down
Expand Up @@ -30,7 +30,7 @@
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;


public class SetPasswordCommandTest extends CommandTestBase public class SetPasswordCommandTest extends UsersCommandTestBase
{ {


@Rule @Rule
Expand Down
Expand Up @@ -31,7 +31,7 @@
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;


public class UsersCommandIT extends CommandTestBase public class UsersCommandIT extends UsersCommandTestBase
{ {
@Rule @Rule
public RuleChain ruleChain = RuleChain.outerRule( testDir ); public RuleChain ruleChain = RuleChain.outerRule( testDir );
Expand Down Expand Up @@ -281,11 +281,6 @@ public void shouldDeleteExistingUser() throws Throwable
// Utilities for testing AdminTool // Utilities for testing AdminTool
// //


private String[] args(String... args)
{
return args;
}

private void assertFailedUserCommand( String command, String... errors ) private void assertFailedUserCommand( String command, String... errors )
{ {
// When running users command without a command or with incorrect command // When running users command without a command or with incorrect command
Expand All @@ -307,46 +302,4 @@ private void assertFailedUserCommand( String command, String... errors )
verify( out, times( 0 ) ).stdOutLine( anyString() ); verify( out, times( 0 ) ).stdOutLine( anyString() );
verify( out ).exit( 1 ); verify( out ).exit( 1 );
} }

private String[] makeArgs(String command, String... args)
{
String[] allArgs = new String[args.length + 2];
System.arraycopy( args, 0, allArgs, 2, args.length );
allArgs[0] = "users";
allArgs[1] = command;
return allArgs;
}

private void assertFailedSubCommand( String command, String[] args, String... errors )
{
// When running set password on a failing case (missing user, or other error)
resetOutsideWorldMock();
AdminTool tool = new AdminTool( CommandLocator.fromServiceLocator(), out, true );
tool.execute( graphDir.toPath(), confDir.toPath(), makeArgs( command, args ) );

// Then we get the expected error
for ( String error : errors )
{
verify( out ).stdErrLine( contains( error ) );
}
verify( out, times( 0 ) ).stdOutLine( anyString() );
verify( out ).exit( 1 );
}

private void assertSuccessfulSubCommand( String command, String[] args, String... messages )
{
// When running set password on a successful case (user exists)
resetOutsideWorldMock();
AdminTool tool = new AdminTool( CommandLocator.fromServiceLocator(), out, true );
tool.execute( graphDir.toPath(), confDir.toPath(), makeArgs( command, args ));

// Then we get the expected output messages
for ( String message : messages )
{
verify( out ).stdOutLine( contains( message ) );
}
verify( out, times( 0 ) ).stdErrLine( anyString() );
verify( out ).exit( 0 );
}

} }
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.commandline.admin.security;

import org.neo4j.server.security.auth.User;

import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;

class UsersCommandTestBase extends CommandTestBase
{
protected static String password_change_required = "password_change_required";

@Override
protected String command()
{
return "users";
}

void assertUserRequiresPasswordChange( String username ) throws Throwable
{
User user = getUser( username );
assertThat( "User should require password change", user.getFlags(), hasItem( password_change_required ) );
}

void assertUserDoesNotRequirePasswordChange( String username ) throws Throwable
{
User user = getUser( username );
assertThat( "User should not require password change", user.getFlags(),
not( hasItem( password_change_required ) ) );
}

}

0 comments on commit 3ed1a77

Please sign in to comment.