Skip to content

Commit

Permalink
Fixed flaky tests for bolt init and REST UserService change password …
Browse files Browse the repository at this point in the history
…logging
  • Loading branch information
fickludd committed Oct 5, 2016
1 parent 2cb92a8 commit c005099
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 123 deletions.
Expand Up @@ -25,45 +25,49 @@
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.neo4j.kernel.api.security.AuthSubject;
import org.neo4j.server.security.enterprise.log.SecurityLog;
import org.neo4j.kernel.impl.util.JobScheduler;
import org.neo4j.logging.AssertableLogProvider;
import org.neo4j.logging.FormattedLog;
import org.neo4j.logging.Log;
import org.neo4j.server.security.auth.AuthenticationStrategy;
import org.neo4j.server.security.auth.BasicPasswordPolicy;
import org.neo4j.server.security.auth.InMemoryUserRepository;
import org.neo4j.server.security.auth.UserRepository;
import org.neo4j.server.security.enterprise.log.SecurityLog;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.neo4j.logging.AssertableLogProvider.inLog;

public class MultiRealmAuthManagerRule implements TestRule
{
private UserRepository users;
private AuthenticationStrategy authStrategy;
private MultiRealmAuthManager manager;
private EnterpriseUserManager userManager;
private AssertableLogProvider logProvider;
private SecurityLog securityLog;
private StringWriter securityLogWriter;

public MultiRealmAuthManagerRule(
UserRepository users,
AuthenticationStrategy authStrategy
)
{
) {
this.users = users;
this.authStrategy = authStrategy;

logProvider = new AssertableLogProvider();
}

private void setupAuthManager( AuthenticationStrategy authStrategy ) throws Throwable
{
Log log = logProvider.getLog( this.getClass() );
FormattedLog.Builder builder = FormattedLog.withUTCTimeZone();
securityLogWriter = new StringWriter();
Log log = builder.toWriter( securityLogWriter );

securityLog = new SecurityLog( log );
InternalFlatFileRealm internalFlatFileRealm =
new InternalFlatFileRealm(
Expand All @@ -78,8 +82,6 @@ private void setupAuthManager( AuthenticationStrategy authStrategy ) throws Thro
manager = new MultiRealmAuthManager( internalFlatFileRealm, Collections.singleton( internalFlatFileRealm ),
new MemoryConstrainedCacheManager(), securityLog, true );
manager.init();

userManager = manager.getUserManager();
}

public EnterpriseAuthAndUserManager getManager()
Expand Down Expand Up @@ -129,33 +131,23 @@ public void tearDown() throws Throwable
manager.shutdown();
}

public void assertExactlyInfoInLog( String message )
{
logProvider.assertExactly( inLog( this.getClass() ).info( message ) );
}

public void assertExactlyInfoInLog( String message, Object... values )
{
logProvider.assertExactly( inLog( this.getClass() ).info( message, values ) );
}

public void assertExactlyWarnInLog( String message )
public FullSecurityLog getFullSecurityLog()
{
logProvider.assertExactly( inLog( this.getClass() ).warn( message ) );
return new FullSecurityLog( securityLogWriter.getBuffer().toString().split( "\n" ) );
}

public void assertExactlyWarnInLog( String message, Object... values )
public static class FullSecurityLog
{
logProvider.assertExactly( inLog( this.getClass() ).warn( message, values ) );
}
List<String> lines;

public void assertExactlyErrorInLog( String message )
{
logProvider.assertExactly( inLog( this.getClass() ).error( message ) );
}
private FullSecurityLog( String[] logLines )
{
lines = Arrays.asList( logLines );
}

public void assertExactlyErrorInLog( String message, Object... values )
{
logProvider.assertExactly( inLog( this.getClass() ).error( message, values ) );
public void assertHasLine( String subject, String msg )
{
assertThat( lines, hasItem( containsString( "[" + subject + "]: " + msg ) ) );
}
}
}
@@ -0,0 +1,80 @@
/*
* 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 Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.neo4j.server.security.enterprise.auth.integration.bolt;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import java.time.Clock;
import java.util.Map;

import org.neo4j.bolt.security.auth.AuthenticationException;
import org.neo4j.bolt.security.auth.BasicAuthentication;
import org.neo4j.server.security.auth.InMemoryUserRepository;
import org.neo4j.server.security.auth.RateLimitedAuthenticationStrategy;
import org.neo4j.server.security.enterprise.auth.MultiRealmAuthManagerRule;
import org.neo4j.server.security.enterprise.auth.MultiRealmAuthManagerRule.FullSecurityLog;

import static org.neo4j.helpers.collection.MapUtil.map;
import static org.neo4j.test.assertion.Assert.assertException;

public class BoltInitChangePasswordTest
{
@Rule
public MultiRealmAuthManagerRule authManagerRule = new MultiRealmAuthManagerRule( new InMemoryUserRepository(),
new RateLimitedAuthenticationStrategy( Clock.systemUTC(), 3 ) );
private BasicAuthentication authentication;

@Before
public void setup() throws Throwable
{
authentication = new BasicAuthentication( authManagerRule.getManager() );
authManagerRule.getManager().getUserManager().newUser( "neo4j", "123", true );
}

@Test
public void shouldLogInitPasswordChange() throws Throwable
{
authentication.authenticate( authToken( "neo4j", "123", "secret" ) );

FullSecurityLog fullLog = authManagerRule.getFullSecurityLog();
fullLog.assertHasLine( "neo4j", "logged in" );
fullLog.assertHasLine( "neo4j", "changed password" );
}

@Test
public void shouldLogFailedInitPasswordChange() throws Throwable
{
assertException( () -> authentication.authenticate( authToken( "neo4j", "123", "123" ) ),
AuthenticationException.class, "Old password and new password cannot be the same." );

FullSecurityLog fullLog = authManagerRule.getFullSecurityLog();
fullLog.assertHasLine( "neo4j", "logged in" );
fullLog.assertHasLine( "neo4j", "tried to change password: Old password and new password cannot be the same." );
}

private Map<String,Object> authToken( String username, String password, String newPassword )
{
return map( "principal", username, "credentials", password,
"new_credentials", newPassword, "scheme", "basic" );
}
}
Expand Up @@ -19,39 +19,19 @@
*/
package org.neo4j.server.security.enterprise.auth.integration.bolt;

import org.apache.commons.compress.utils.Charsets;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import org.neo4j.bolt.v1.messaging.message.InitMessage;
import org.neo4j.bolt.v1.transport.integration.AuthenticationIT;
import org.neo4j.bolt.v1.transport.integration.TransportTestUtil;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.kernel.api.exceptions.Status;
import org.neo4j.test.TestEnterpriseGraphDatabaseFactory;
import org.neo4j.test.TestGraphDatabaseFactory;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem;
import static org.neo4j.bolt.v1.messaging.util.MessageMatchers.msgFailure;
import static org.neo4j.bolt.v1.messaging.util.MessageMatchers.msgSuccess;
import static org.neo4j.bolt.v1.transport.integration.TransportTestUtil.eventuallyReceives;
import static org.neo4j.helpers.collection.MapUtil.map;

public class EnterpriseAuthenticationIT extends AuthenticationIT
{
private File securityLog;

@Override
protected TestGraphDatabaseFactory getTestGraphDatabaseFactory()
{
Expand All @@ -70,7 +50,6 @@ protected Consumer<Map<String, String>> getSettingsFunction()
{
throw new RuntimeException( "Test setup failed to create temporary directory", e );
}
securityLog = new File( homeDir.toFile(), "security.log" );

return settings -> {
settings.put( GraphDatabaseSettings.auth_enabled.name(), "true" );
Expand All @@ -83,69 +62,4 @@ public void shouldFailIfMalformedAuthTokenUnknownScheme() throws Throwable
{
// Ignore this test in enterprise since custom schemes may be allowed
}

@SuppressWarnings( "unchecked" )
@Test
public void shouldLogInitPasswordChange() throws Throwable
{
// When
client.connect( address )
.send( TransportTestUtil.acceptedVersions( 1, 0, 0, 0 ) )
.send( TransportTestUtil.chunk(
InitMessage.init( "TestClient/1.1", map( "principal", "neo4j",
"credentials", "neo4j", "new_credentials", "secret", "scheme", "basic" ) ) ) );

// Then
assertThat( client, eventuallyReceives( new byte[]{0, 0, 0, 1} ) );
assertThat( client, eventuallyReceives( msgSuccess() ) );

server.graphDatabaseService().shutdown(); // to force writing of async logs

FullLog log = new FullLog();
log.assertHasLine( "neo4j", "changed password" );
}

@SuppressWarnings( "unchecked" )
@Test
public void shouldLogFailedInitPasswordChange() throws Throwable
{
// When
client.connect( address )
.send( TransportTestUtil.acceptedVersions( 1, 0, 0, 0 ) )
.send( TransportTestUtil.chunk(
InitMessage.init( "TestClient/1.1", map( "principal", "neo4j",
"credentials", "neo4j", "new_credentials", "neo4j", "scheme", "basic" ) ) ) );

// Then
assertThat( client, eventuallyReceives( new byte[]{0, 0, 0, 1} ) );
assertThat( client, eventuallyReceives( msgFailure( Status.General.InvalidArguments,
"Old password and new password cannot be the same.") ) );

server.graphDatabaseService().shutdown(); // to force writing of async logs

FullLog log = new FullLog();
log.assertHasLine( "neo4j", "tried to change password: Old password and new password cannot be the same." );
}

private class FullLog
{
List<String> lines;

FullLog() throws IOException
{
lines = new ArrayList<>();
BufferedReader bufferedReader = new BufferedReader(
fsRule.get().openAsReader(
new File( securityLog.getAbsolutePath() ),
Charsets.UTF_8
) );
lines.add( bufferedReader.readLine() );
bufferedReader.lines().forEach( lines::add );
}

void assertHasLine( String subject, String msg )
{
assertThat( lines, hasItem( containsString( "[" + subject + "]: " + msg ) ) );
}
}
}
Expand Up @@ -53,15 +53,16 @@ public void shouldLogPasswordChange() throws Exception
{
shouldChangePasswordAndReturnSuccess();

authManagerRule.assertExactlyInfoInLog( "[neo4j]: changed password%s", "" );
MultiRealmAuthManagerRule.FullSecurityLog fullLog = authManagerRule.getFullSecurityLog();
fullLog.assertHasLine( "neo4j", "changed password" );
}

@Test
public void shouldLogFailedPasswordChange() throws Exception
{
shouldReturn422IfPasswordIdentical();

authManagerRule.assertExactlyErrorInLog( "[neo4j]: tried to change password: %s",
"Old password and new password cannot be the same." );
MultiRealmAuthManagerRule.FullSecurityLog fullLog = authManagerRule.getFullSecurityLog();
fullLog.assertHasLine( "neo4j", "tried to change password: Old password and new password cannot be the same." );
}
}

0 comments on commit c005099

Please sign in to comment.