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;

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

import java.io.File;
import java.io.IOException;
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.io.fs.DelegateFileSystemAbstraction;
import org.neo4j.io.fs.FileSystemAbstraction;
Expand All @@ -37,20 +37,18 @@
import org.neo4j.server.security.auth.User;
import org.neo4j.test.rule.TestDirectory;

import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.contains;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
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 FileSystemAbstraction fileSystem = new DelegateFileSystemAbstraction( FileSystems.getDefault() );

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

protected File authFile()
private File authFile()
{
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() );
User user =
Expand All @@ -96,26 +94,60 @@ protected User createTestUser( String username, String password ) throws IOExcep
return user;
}

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

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

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 );
assertThat( "User should not require password change", user.getFlags(),
not( hasItem( password_change_required ) ) );
// 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 );
}

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

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

import org.neo4j.commandline.admin.CommandFailed;

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

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

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

public class DeleteCommandTest extends CommandTestBase
public class DeleteCommandTest extends UsersCommandTestBase
{
@Rule
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.verify;

public class ListCommandTest extends CommandTestBase
public class ListCommandTest extends UsersCommandTestBase
{
@Rule
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.fail;

public class SetPasswordCommandTest extends CommandTestBase
public class SetPasswordCommandTest extends UsersCommandTestBase
{

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

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

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

private void assertFailedUserCommand( String command, String... errors )
{
// 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 ).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.