Skip to content

Commit

Permalink
Support creating initial user with set-password
Browse files Browse the repository at this point in the history
  • Loading branch information
craigtaverner committed Aug 12, 2016
1 parent 23da4f8 commit 2c1df52
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 9 deletions.
Expand Up @@ -31,6 +31,8 @@
import org.neo4j.commandline.admin.OutsideWorld; import org.neo4j.commandline.admin.OutsideWorld;
import org.neo4j.dbms.DatabaseManagementSystemSettings; import org.neo4j.dbms.DatabaseManagementSystemSettings;
import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.helpers.Args;
import org.neo4j.kernel.api.security.exception.InvalidArgumentsException;
import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.logging.NullLogProvider; import org.neo4j.logging.NullLogProvider;
import org.neo4j.server.configuration.ConfigLoader; import org.neo4j.server.configuration.ConfigLoader;
Expand All @@ -55,7 +57,7 @@ public Provider()
@Override @Override
public Optional<String> arguments() public Optional<String> arguments()
{ {
return Optional.of( "<username> <password>" ); return Optional.of( "--create <username> <password>" );
} }


@Override @Override
Expand Down Expand Up @@ -83,12 +85,15 @@ public SetPasswordCommand( Path homeDir, Path configDir )
@Override @Override
public void execute( String[] args ) throws IncorrectUsage, CommandFailed public void execute( String[] args ) throws IncorrectUsage, CommandFailed
{ {
if ( args.length < 2 ) Args parsedArgs = Args.parse( args );
if ( parsedArgs.orphans().size() < 2 )
{ {
throw new IncorrectUsage( "Missing arguments: expected username and password" ); throw new IncorrectUsage( "Missing arguments: expected username and password" );
} }
String username = args[0];
String password = args[1]; String username = parsedArgs.orphans().get( 0 );
String password = parsedArgs.orphans().get( 1 );
boolean shouldCreate = parsedArgs.asMap().containsKey( "create" );
try try
{ {
Config config = loadNeo4jConfig( homeDir, configDir ); Config config = loadNeo4jConfig( homeDir, configDir );
Expand All @@ -98,15 +103,28 @@ public void execute( String[] args ) throws IncorrectUsage, CommandFailed
userRepository.start(); userRepository.start();
PasswordPolicy passwordPolicy = new BasicPasswordPolicy(); PasswordPolicy passwordPolicy = new BasicPasswordPolicy();
BasicAuthManager authManager = new BasicAuthManager( userRepository, passwordPolicy, systemUTC() ); BasicAuthManager authManager = new BasicAuthManager( userRepository, passwordPolicy, systemUTC() );
authManager.setUserPassword( username, password ); try
{
authManager.setUserPassword( username, password );
}
catch ( InvalidArgumentsException e )
{
if ( shouldCreate )
{
authManager.getUserManager().newUser( username, password, false );
} else {
throw e;
}
}
} }
catch ( Exception e ) catch ( Exception e )
{ {
throw new CommandFailed( "Failed to set password for '" + username + "': " + e.getMessage(), e ); throw new CommandFailed( "Failed to set password for '" + username + "': " + e.getMessage(), e );
} }
catch ( Throwable t ) catch ( Throwable t )
{ {
throw new CommandFailed( "Failed to set password for '" + username + "': " + t.getMessage(), new RuntimeException(t.getMessage()) ); throw new CommandFailed( "Failed to set password for '" + username + "': " + t.getMessage(),
new RuntimeException( t.getMessage() ) );
} }
} }


Expand Down
Expand Up @@ -112,7 +112,7 @@ public void shouldFailWitNonExistingUser() throws Exception
} }


@Test @Test
public void shouldRunSetPasswordCommand() throws Throwable public void shouldRunSetPasswordCommandWithExistinguser() throws Throwable
{ {
// Given - new user that requires password change // Given - new user that requires password change
File graphDir = testDir.graphDbDir(); File graphDir = testDir.graphDbDir();
Expand All @@ -128,6 +128,41 @@ public void shouldRunSetPasswordCommand() throws Throwable
assertUserDoesNotRequirePasswordChange( "neo4j" ); assertUserDoesNotRequirePasswordChange( "neo4j" );
} }


@Test
public void shouldRunSetPasswordCommandWithoutExistingUser() throws Throwable
{
// Given - no user
File graphDir = testDir.graphDbDir();

// When - the admin command sets the password
File confDir = new File( graphDir, "conf" );
SetPasswordCommand setPasswordCommand = new SetPasswordCommand( graphDir.toPath(), confDir.toPath() );
setPasswordCommand.execute( new String[]{"neo4j", "abc", "--create"} );

// Then - the new user no longer requires a password change
assertUserDoesNotRequirePasswordChange( "neo4j" );
}

@Test
public void shouldFailToRunSetPasswordCommandWithoutExistingUser() throws Throwable
{
// Given - no user
File graphDir = testDir.graphDbDir();

// When - the admin command sets the password
try
{
File confDir = new File( graphDir, "conf" );
SetPasswordCommand setPasswordCommand = new SetPasswordCommand( graphDir.toPath(), confDir.toPath() );
setPasswordCommand.execute( new String[]{"neo4j", "abc"} );
}
catch ( CommandFailed e )
{
// Then we get an error
assertThat( e.getMessage(), containsString( "does not exist" ) );
}
}

@Test @Test
public void shouldRunAdminToolWithSetPasswordCommandAndNoArgs() throws Throwable public void shouldRunAdminToolWithSetPasswordCommandAndNoArgs() throws Throwable
{ {
Expand All @@ -144,15 +179,32 @@ public void shouldRunAdminToolWithSetPasswordCommandAndNoArgs() throws Throwable


// Then we get error output and user still requires password change // Then we get error output and user still requires password change
verify( out, times( 0 ) ).stdOutLine( anyString() ); verify( out, times( 0 ) ).stdOutLine( anyString() );
verify( out ).stdErrLine( "neo4j-admin set-password <username> <password>" ); verify( out ).stdErrLine( "neo4j-admin set-password --create <username> <password>" );
verify( out ).stdErrLine( " Sets the password for the specified user and removes the password change " ); verify( out ).stdErrLine( " Sets the password for the specified user and removes the password change " );
verify( out ).stdErrLine( " requirement" ); verify( out ).stdErrLine( " requirement" );
verify( out ).stdErrLine( "Missing arguments: expected username and password" ); verify( out ).stdErrLine( "Missing arguments: expected username and password" );
assertUserRequiresPasswordChange( "neo4j" ); assertUserRequiresPasswordChange( "neo4j" );
} }


@Test @Test
public void shouldRunAdminToolWithSetPasswordCommandAndCorrectArgs() throws Throwable public void shouldRunAdminToolWithSetPasswordCommandAndArgsButNoUser() throws Throwable
{
// Given no existing user

// When running the neo4j-admin tool without --create parameter
Path homeDir = testDir.graphDbDir().toPath();
Path configDir = testDir.directory( "conf" ).toPath();
OutsideWorld out = mock( OutsideWorld.class );
AdminTool tool = new AdminTool( CommandLocator.fromServiceLocator(), out, true );
tool.execute( homeDir, configDir, "set-password", "neo4j", "abc" );

// Then we get error output and user still requires password change
verify( out, times( 0 ) ).stdOutLine( anyString() );
verify( out ).stdErrLine( "command failed: Failed to set password for 'neo4j': User 'neo4j' does not exist" );
}

@Test
public void shouldRunAdminToolWithSetPasswordCommandAndExistingUser() throws Throwable
{ {
// Given a user that requires password change // Given a user that requires password change
createTestUser("neo4j", "neo4j"); createTestUser("neo4j", "neo4j");
Expand All @@ -172,6 +224,26 @@ public void shouldRunAdminToolWithSetPasswordCommandAndCorrectArgs() throws Thro
assertUserDoesNotRequirePasswordChange( "neo4j" ); assertUserDoesNotRequirePasswordChange( "neo4j" );
} }


@Test
public void shouldRunAdminToolWithSetPasswordCommandAndNoExistingUser() throws Throwable
{
// Given no previously existing user

// When running the neo4j-admin tool with correct parameters
Path homeDir = testDir.graphDbDir().toPath();
Path configDir = testDir.directory( "conf" ).toPath();
OutsideWorld out = mock( OutsideWorld.class );
AdminTool tool = new AdminTool( CommandLocator.fromServiceLocator(), out, true );
tool.execute( homeDir, configDir, "set-password", "--create=true", "neo4j", "abc" );

// Then we get no error output and the user no longer requires password change
verify( out, times( 0 ) ).stdOutLine( anyString() );
verify( out, times( 0 ) ).stdOutLine( anyString() );
verify( out, times( 0 ) ).stdErrLine( anyString() );
verify( out ).exit(0);
assertUserDoesNotRequirePasswordChange( "neo4j" );
}

private File authFile() private File authFile()
{ {
return new File( new File( new File( testDir.graphDbDir(), "data" ), "dbms" ), "auth.db" ); return new File( new File( new File( testDir.graphDbDir(), "data" ), "dbms" ), "auth.db" );
Expand Down

0 comments on commit 2c1df52

Please sign in to comment.