diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerRule.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerRule.java index 4b7f2b4f974c3..db7149683df2b 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerRule.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerRule.java @@ -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( @@ -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() @@ -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 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 ) ) ); + } } } diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/BoltInitChangePasswordTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/BoltInitChangePasswordTest.java new file mode 100644 index 0000000000000..ce4a50a426798 --- /dev/null +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/BoltInitChangePasswordTest.java @@ -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 . + */ + +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 authToken( String username, String password, String newPassword ) + { + return map( "principal", username, "credentials", password, + "new_credentials", newPassword, "scheme", "basic" ); + } +} diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/EnterpriseAuthenticationIT.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/EnterpriseAuthenticationIT.java index 5ecb06170fcad..532d50c9a6648 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/EnterpriseAuthenticationIT.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/EnterpriseAuthenticationIT.java @@ -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() { @@ -70,7 +50,6 @@ protected Consumer> 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" ); @@ -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 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 ) ) ); - } - } } diff --git a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/EnterpriseUserServiceTest.java b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/EnterpriseUserServiceTest.java index a612b4163a5ef..c2712b88684da 100644 --- a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/EnterpriseUserServiceTest.java +++ b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/EnterpriseUserServiceTest.java @@ -53,7 +53,8 @@ public void shouldLogPasswordChange() throws Exception { shouldChangePasswordAndReturnSuccess(); - authManagerRule.assertExactlyInfoInLog( "[neo4j]: changed password%s", "" ); + MultiRealmAuthManagerRule.FullSecurityLog fullLog = authManagerRule.getFullSecurityLog(); + fullLog.assertHasLine( "neo4j", "changed password" ); } @Test @@ -61,7 +62,7 @@ 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." ); } }