@Override protected User deserializeRecord( String line, int lineNumber ) throws FormatException { String[] parts = line.split( userSeparator, -1 ); if ( parts.length != 3 ) { throw new FormatException( format( "wrong number of line fields, expected 3, got %d [line %d]", parts.length, lineNumber ) ); } User.Builder b = new User.Builder() .withName( parts[0] ) .withCredentials( deserializeCredentials( parts[1], lineNumber ) ); for ( String flag : parts[2].split( ",", -1 ) ) { String trimmed = flag.trim(); if ( !trimmed.isEmpty() ) { b = b.withFlag( trimmed ); } } return b.build(); }
@Test public void shouldBuildImmutableUser() { LegacyCredential abc = LegacyCredential.forPassword( "123abc" ); LegacyCredential fruit = LegacyCredential.forPassword( "fruit" ); User u1 = new User.Builder( "Steve", abc ).build(); User u2 = new User.Builder( "Steve", fruit ) .withRequiredPasswordChange( true ) .withFlag( "nice_guy" ).build(); assertThat( u1, equalTo( u1 ) ); assertThat( u1, not( equalTo( u2 ) ) ); User u1AsU2 = u1.augment().withCredentials( fruit ) .withRequiredPasswordChange( true ) .withFlag( "nice_guy" ).build(); assertThat( u1, not( equalTo( u1AsU2 ))); assertThat( u2, equalTo( u1AsU2 )); User u2AsU1 = u2.augment().withCredentials( abc ) .withRequiredPasswordChange( false ) .withoutFlag( "nice_guy" ).build(); assertThat( u2, not( equalTo( u2AsU1 ))); assertThat( u1, equalTo( u2AsU1 )); assertThat( u1, not( equalTo( u2 ) ) ); } }
@Before public void setup() throws IOException, InvalidArgumentsException { OutsideWorld mock = mock( OutsideWorld.class ); when( mock.fileSystem() ).thenReturn( fileSystem ); setDefaultAdmin = new SetDefaultAdminCommand( testDir.directory( "home" ).toPath(), testDir.directory( "conf" ).toPath(), mock ); config = setDefaultAdmin.loadNeo4jConfig(); UserRepository users = CommunitySecurityModule.getUserRepository( config, NullLogProvider.getInstance(), fileSystem ); users.create( new User.Builder( "jake", LegacyCredential.forPassword( "123" ) ) .withRequiredPasswordChange( false ) .build() ); adminIniFile = new File( CommunitySecurityModule.getUserRepositoryFile( config ).getParentFile(), "admin.ini" ); }
@Test public void shouldThrowIfExistingUserDoesNotMatch() throws Throwable { // Given FileUserRepository users = new FileUserRepository( fs, authFile, logProvider ); User user = new User.Builder( "jake", LegacyCredential.INACCESSIBLE ).withRequiredPasswordChange( true ).build(); users.create( user ); User modifiedUser = user.augment().withCredentials( LegacyCredential.forPassword( "foo" ) ).build(); // When User updatedUser = user.augment().withCredentials( LegacyCredential.forPassword( "bar" ) ).build(); try { users.update( modifiedUser, updatedUser ); fail( "expected exception not thrown" ); } catch ( ConcurrentModificationException e ) { // Then continue } }
@Test public void shouldLoadInitialUserIfNoneExist() throws Throwable { // Given FileUserRepository initialUserRepository = CommunitySecurityModule.getInitialUserRepository( config, NullLogProvider.getInstance(), fsRule.get() ); initialUserRepository.start(); initialUserRepository.create( new User.Builder( "neo4j", LegacyCredential.forPassword( "123" ) ) .withRequiredPasswordChange( false ) .build() ); initialUserRepository.shutdown(); // When authManager().start(); // Then final User user = users.getUserByName( "neo4j" ); assertNotNull( user ); assertTrue( user.credentials().matchesPassword( "123" ) ); assertFalse( user.passwordChangeRequired() ); }
@Test public void shouldThrowIfUpdateChangesName() throws Throwable { // Given FileUserRepository users = new FileUserRepository( fs, authFile, logProvider ); User user = new User.Builder( "jake", LegacyCredential.INACCESSIBLE ).withRequiredPasswordChange( true ).build(); users.create( user ); // When User updatedUser = new User.Builder( "john", LegacyCredential.INACCESSIBLE ).withRequiredPasswordChange( true ) .build(); try { users.update( user, updatedUser ); fail( "expected exception not thrown" ); } catch ( IllegalArgumentException e ) { // Then continue } assertThat( users.getUserByName( user.name() ), equalTo( user ) ); }
@Test public void shouldProvideUserByUsernameEvenIfMidSetUsers() throws Throwable { // Given FileUserRepository users = new FileUserRepository( fs, authFile, logProvider ); users.create( new User.Builder( "oskar", LegacyCredential.forPassword( "hidden" ) ).build() ); DoubleLatch latch = new DoubleLatch( 2 ); // When Future<Object> setUsers = threading.execute( o -> { users.setUsers( new HangingListSnapshot( latch, 10L, Collections.emptyList() ) ); return null; }, null ); latch.startAndWaitForAllToStart(); // Then assertNotNull( users.getUserByName( "oskar" ) ); latch.finish(); setUsers.get(); }
@Test public void shouldLoadInitialUserIfNoneExistEvenWithSamePassword() throws Throwable { // Given FileUserRepository initialUserRepository = CommunitySecurityModule.getInitialUserRepository( config, NullLogProvider.getInstance(), fsRule.get() ); initialUserRepository.start(); initialUserRepository.create( new User.Builder( "neo4j", LegacyCredential.forPassword( "neo4j" ) ) .withRequiredPasswordChange( false ) .build() ); initialUserRepository.shutdown(); // When authManager().start(); // Then final User user = users.getUserByName( "neo4j" ); assertNotNull( user ); assertTrue( user.credentials().matchesPassword( "neo4j" ) ); assertFalse( user.passwordChangeRequired() ); }
private void testSlowRequestRateOnMultipleFailedAttemptsWhereAttemptIsValid( int maxFailedAttempts, Duration lockDuration ) { // Given FakeClock clock = getFakeClock(); AuthenticationStrategy authStrategy = newAuthStrategy( clock, maxFailedAttempts, lockDuration ); User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // When we've failed max number of times for ( int i = 0; i < maxFailedAttempts; i++ ) { assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); } // Then assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.TOO_MANY_ATTEMPTS )); // But when time heals all wounds clock.forward( lockDuration.plus( 1, SECONDS ) ); // Then things should be alright assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.SUCCESS ) ); }
private void testSlowRequestRateOnMultipleFailedAttempts( int maxFailedAttempts, Duration lockDuration ) { // Given FakeClock clock = getFakeClock(); AuthenticationStrategy authStrategy = newAuthStrategy( clock, maxFailedAttempts, lockDuration ); User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // When we've failed max number of times for ( int i = 0; i < maxFailedAttempts; i++ ) { assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); } // Then assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.TOO_MANY_ATTEMPTS ) ); // But when time heals all wounds clock.forward( lockDuration.plus( 1, SECONDS ) ); // Then things should be alright assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); }
@Test public void shouldSerializeAndDeserialize() throws Exception { // Given UserSerialization serialization = new UserSerialization(); List<User> users = asList( new User.Builder( "Mike", LegacyCredential.forPassword( "1234321" ) ).withFlag( "not_as_nice" ).build(), new User.Builder( "Steve", LegacyCredential.forPassword( "1234321" ) ).build(), new User.Builder( "steve.stevesson@WINDOMAIN", LegacyCredential.forPassword( "1234321" ) ).build(), new User.Builder( "Bob", LegacyCredential.forPassword( "0987654" ) ).build() ); // When byte[] serialized = serialization.serialize( users ); // Then assertThat( serialization.deserializeRecords( serialized ), equalTo( users ) ); }
@Test public void shouldPersistUsers() throws Throwable { // Given FileUserRepository users = new FileUserRepository( fs, authFile, logProvider ); User user = new User.Builder( "jake", LegacyCredential.INACCESSIBLE ).withRequiredPasswordChange( true ).build(); users.create( user ); users = new FileUserRepository( fs, authFile, logProvider ); users.start(); // When User resultByName = users.getUserByName( user.name() ); // Then assertThat( resultByName, equalTo( user ) ); }
private void insertUser( String username, boolean initial ) throws Throwable { File userFile = getAuthFile( initial ? CommunitySecurityModule.INITIAL_USER_STORE_FILENAME : CommunitySecurityModule.USER_STORE_FILENAME ); FileUserRepository userRepository = new FileUserRepository( fileSystem, userFile, NullLogProvider.getInstance() ); userRepository.start(); userRepository.create( new User.Builder( username, LegacyCredential.INACCESSIBLE ).build() ); assertTrue( userRepository.getAllUsernames().contains( username ) ); userRepository.stop(); userRepository.shutdown(); }
@Test public void shouldStoreAndRetrieveUsersByName() throws Exception { // Given FileUserRepository users = new FileUserRepository( fs, authFile, logProvider ); User user = new User.Builder( "jake", LegacyCredential.INACCESSIBLE ).withRequiredPasswordChange( true ).build(); users.create( user ); // When User result = users.getUserByName( user.name() ); // Then assertThat( result, equalTo( user ) ); }
@Test public void shouldReturnFailureForInvalidAttempt() { // Given FakeClock clock = getFakeClock(); AuthenticationStrategy authStrategy = newAuthStrategy( clock, 3 ); User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // Then assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); }
@Test public void shouldNotSlowRequestRateOnLessThanMaxFailedAttempts() { // Given FakeClock clock = getFakeClock(); AuthenticationStrategy authStrategy = newAuthStrategy( clock, 3 ); User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // When we've failed two times assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); // Then assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.SUCCESS )); }
@Test public void shouldNotFindUserAfterDelete() throws Throwable { // Given FileUserRepository users = new FileUserRepository( fs, authFile, logProvider ); User user = new User.Builder( "jake", LegacyCredential.INACCESSIBLE ).withRequiredPasswordChange( true ).build(); users.create( user ); // When users.delete( user ); // Then assertThat( users.getUserByName( user.name() ), nullValue() ); }
@Test public void shouldReturnSuccessForValidAttempt() { // Given FakeClock clock = getFakeClock(); AuthenticationStrategy authStrategy = newAuthStrategy( clock, 3 ); User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // Then assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.SUCCESS ) ); }
protected User newUser( String userName, String password, boolean pwdChange ) { return new User.Builder( userName, LegacyCredential.forPassword( password ) ) .withRequiredPasswordChange( pwdChange ) .build(); } }
private void testUnlimitedFailedAuthAttempts( int maxFailedAttempts ) { FakeClock clock = getFakeClock(); AuthenticationStrategy authStrategy = newAuthStrategy( clock, maxFailedAttempts ); User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); int attempts = ThreadLocalRandom.current().nextInt( 5, 100 ); for ( int i = 0; i < attempts; i++ ) { assertEquals( AuthenticationResult.FAILURE, authStrategy.authenticate( user, password( "wrong" ) ) ); } }