diff --git a/community/security/src/main/java/org/neo4j/commandline/admin/security/SetPasswordCommand.java b/community/security/src/main/java/org/neo4j/commandline/admin/security/SetPasswordCommand.java index 61695dd46a2c9..0aa5248c984a1 100644 --- a/community/security/src/main/java/org/neo4j/commandline/admin/security/SetPasswordCommand.java +++ b/community/security/src/main/java/org/neo4j/commandline/admin/security/SetPasswordCommand.java @@ -44,10 +44,10 @@ public class SetPasswordCommand implements AdminCommand { - public class Provider extends AdminCommand.Provider + public static class Provider extends AdminCommand.Provider { - protected Provider() + public Provider() { super( "set-password" ); } diff --git a/community/security/src/main/resources/META-INF/services/org.neo4j.commandline.admin.AdminCommand$Provider b/community/security/src/main/resources/META-INF/services/org.neo4j.commandline.admin.AdminCommand$Provider new file mode 100644 index 0000000000000..af41464c1e454 --- /dev/null +++ b/community/security/src/main/resources/META-INF/services/org.neo4j.commandline.admin.AdminCommand$Provider @@ -0,0 +1 @@ +org.neo4j.commandline.admin.security.SetPasswordCommand$Provider diff --git a/community/security/src/test/java/org/neo4j/commandline/admin/security/SetPasswordCommandTest.java b/community/security/src/test/java/org/neo4j/commandline/admin/security/SetPasswordCommandTest.java index 14d5561795148..1f8b9d1f838d8 100644 --- a/community/security/src/test/java/org/neo4j/commandline/admin/security/SetPasswordCommandTest.java +++ b/community/security/src/test/java/org/neo4j/commandline/admin/security/SetPasswordCommandTest.java @@ -24,9 +24,15 @@ import org.junit.rules.RuleChain; import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import org.neo4j.commandline.admin.AdminTool; import org.neo4j.commandline.admin.CommandFailed; +import org.neo4j.commandline.admin.CommandLocator; import org.neo4j.commandline.admin.IncorrectUsage; +import org.neo4j.commandline.admin.OutsideWorld; +import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; import org.neo4j.logging.NullLogProvider; import org.neo4j.server.security.auth.Credential; import org.neo4j.server.security.auth.FileUserRepository; @@ -38,10 +44,15 @@ import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; public class SetPasswordCommandTest { private TargetDirectory.TestDirectory testDir = TargetDirectory.testDirForTest( getClass() ); + private static String password_change_required = "password_change_required"; @Rule public RuleChain ruleChain = RuleChain.outerRule( testDir ); @@ -104,14 +115,9 @@ public void shouldFailWitNonExistingUser() throws Exception public void shouldRunSetPasswordCommand() throws Throwable { // Given - new user that requires password change - String password_change_required = "password_change_required"; File graphDir = testDir.graphDbDir(); - File authFile = new File( new File( new File( graphDir, "data" ), "dbms" ), "auth.db" ); - FileUserRepository beforeUsers = new FileUserRepository( authFile.toPath(), NullLogProvider.getInstance() ); - User before = new User.Builder( "neo4j", Credential.forPassword( "neo4j" ) ).withRequiredPasswordChange( true ) - .build(); - beforeUsers.create( before ); - assertThat( "User should require password change", before.getFlags(), hasItem( password_change_required ) ); + createTestUser("neo4j", "neo4j"); + assertUserRequiresPasswordChange( "neo4j" ); // When - the admin command sets the password File confDir = new File( graphDir, "conf" ); @@ -119,11 +125,86 @@ public void shouldRunSetPasswordCommand() throws Throwable setPasswordCommand.execute( new String[]{"neo4j", "abc"} ); // Then - the new user no longer requires a password change - FileUserRepository afterUsers = new FileUserRepository( authFile.toPath(), NullLogProvider.getInstance() ); + assertUserDoesNotRequirePasswordChange( "neo4j" ); + } + + @Test + public void shouldRunAdminToolWithSetPasswordCommandAndNoArgs() throws Throwable + { + // Given a user that requires password change + createTestUser("neo4j", "neo4j"); + assertUserRequiresPasswordChange( "neo4j" ); + + // When running the neo4j-admin tool with incorrect 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" ); + + // Then we get error output and user still requires password change + verify( out, times( 0 ) ).stdOutLine( anyString() ); + verify( out ).stdErrLine( "neo4j-admin set-password " ); + verify( out ).stdErrLine( " Sets the password for the specified user and removes the password change " ); + verify( out ).stdErrLine( " requirement" ); + verify( out ).stdErrLine( "Missing arguments: expected username and password" ); + assertUserRequiresPasswordChange( "neo4j" ); + } + + @Test + public void shouldRunAdminToolWithSetPasswordCommandAndCorrectArgs() throws Throwable + { + // Given a user that requires password change + createTestUser("neo4j", "neo4j"); + assertUserRequiresPasswordChange( "neo4j" ); + + // 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", "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 ) ).stdErrLine( anyString() ); + verify( out ).exit(0); + assertUserDoesNotRequirePasswordChange( "neo4j" ); + } + + private File authFile() + { + return new File( new File( new File( testDir.graphDbDir(), "data" ), "dbms" ), "auth.db" ); + } + + private User createTestUser(String username, String password) throws IOException, InvalidArgumentsException + { + FileUserRepository users = new FileUserRepository( authFile().toPath(), NullLogProvider.getInstance() ); + User user = new User.Builder( username, Credential.forPassword( password ) ).withRequiredPasswordChange( true ) + .build(); + users.create( user ); + return user; + } + + private User getUser(String username) throws Throwable + { + FileUserRepository afterUsers = new FileUserRepository( authFile().toPath(), NullLogProvider.getInstance() ); afterUsers.start(); // load users from disk - User after = afterUsers.getUserByName( "neo4j" ); - assertThat( "User should require password change", after.getFlags(), - not( hasItem( password_change_required ) ) ); + return afterUsers.getUserByName( username ); + } + + private void assertUserRequiresPasswordChange(String username) throws Throwable + { + User user = getUser( username ); + assertThat( "User should require password change", user.getFlags(), hasItem( password_change_required ) ); + } + private void assertUserDoesNotRequirePasswordChange(String username) throws Throwable + { + User user = getUser( username ); + assertThat( "User should not require password change", user.getFlags(), + not( hasItem( password_change_required ) ) ); + + } }