diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/query/Neo4jTransactionalContextTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/query/Neo4jTransactionalContextTest.java index 0147acface58b..c670adf4be2d5 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/query/Neo4jTransactionalContextTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/query/Neo4jTransactionalContextTest.java @@ -1,3 +1,22 @@ +/* + * 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.kernel.impl.query; import org.junit.Test; @@ -23,6 +42,7 @@ public class Neo4jTransactionalContextTest { + @SuppressWarnings( "ConstantConditions" ) @Test public void neverStopsExecutingQueryDuringCommitAndRestartTx() { diff --git a/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java b/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java index 888d0d230c6b7..0ae0483f422d4 100644 --- a/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java +++ b/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java @@ -61,7 +61,7 @@ public class AuthProceduresIT { - static final String PWD_CHANGE = PASSWORD_CHANGE_REQUIRED.name().toLowerCase(); + private static final String PWD_CHANGE = PASSWORD_CHANGE_REQUIRED.name().toLowerCase(); protected GraphDatabaseAPI db; private EphemeralFileSystemAbstraction fs; @@ -278,8 +278,8 @@ private void assertFail( BasicAuthSubject subject, String query, String partOfEr containsString( partOfErrorMsg ) ); } - void assertSuccess( BasicAuthSubject subject, String query, - Consumer>> resultConsumer ) + private void assertSuccess( BasicAuthSubject subject, String query, + Consumer>> resultConsumer ) { assertThat( execute( subject, query, resultConsumer ), @@ -301,24 +301,35 @@ private String execute( BasicAuthSubject subject, String query, } } - List getObjectsAsList( ResourceIterator> r, String key ) + private List getObjectsAsList( ResourceIterator> r, String key ) { return r.stream().map( s -> s.get( key ) ).collect( Collectors.toList() ); } - void assertKeyIs( ResourceIterator> r, String key, String... items ) + private void assertKeyIs( ResourceIterator> r, String key, String... items ) { assertKeyIsArray( r, key, items ); } - void assertKeyIsArray( ResourceIterator> r, String key, String[] items ) + private void assertKeyIsArray( ResourceIterator> r, String key, String[] items ) { List results = getObjectsAsList( r, key ); assertEquals( Arrays.asList( items ).size(), results.size() ); Assert.assertThat( results, containsInAnyOrder( items ) ); } - protected void assertKeyIsMap( ResourceIterator> r, String keyKey, String valueKey, Map expected ) + protected String[] with( String[] strs, String... moreStr ) + { + return Stream.concat( Arrays.stream(strs), Arrays.stream( moreStr ) ).toArray( String[]::new ); + } + + private List listOf( String... values ) + { + return Stream.of( values ).collect( Collectors.toList() ); + } + + @SuppressWarnings( "unchecked" ) + public static void assertKeyIsMap( ResourceIterator> r, String keyKey, String valueKey, Map expected ) { List> result = r.stream().collect( Collectors.toList() ); @@ -351,14 +362,4 @@ protected void assertKeyIsMap( ResourceIterator> r, String k } } } - - protected String[] with( String[] strs, String... moreStr ) - { - return Stream.concat( Arrays.stream(strs), Arrays.stream( moreStr ) ).toArray( String[]::new ); - } - - protected List listOf( String... values ) - { - return Stream.of( values ).collect( Collectors.toList() ); - } } diff --git a/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java b/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java index 4fdf877eb78a6..4e2f311110305 100644 --- a/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java +++ b/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java @@ -19,6 +19,10 @@ */ package org.neo4j.kernel.impl.query; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -32,19 +36,15 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.ResourceIterator; import org.neo4j.graphdb.Result; import org.neo4j.graphdb.factory.GraphDatabaseBuilder; import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.kernel.configuration.Settings; -import org.neo4j.logging.AssertableLogProvider; import org.neo4j.kernel.enterprise.api.security.EnterpriseAuthSubject; -import org.neo4j.server.security.enterprise.auth.NeoShallowEmbeddedInteraction; +import org.neo4j.logging.AssertableLogProvider; +import org.neo4j.server.security.enterprise.auth.EmbeddedInteraction; import org.neo4j.test.TestEnterpriseGraphDatabaseFactory; import org.neo4j.test.rule.TestDirectory; import org.neo4j.test.rule.fs.EphemeralFileSystemRule; @@ -55,7 +55,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; - import static org.neo4j.kernel.api.security.AccessMode.Static.FULL; import static org.neo4j.kernel.impl.query.QueryEngineProvider.embeddedSession; @@ -86,7 +85,7 @@ public void shouldLogCustomUserName() throws Throwable // turn on query logging databaseBuilder.setConfig( GraphDatabaseSettings.logs_directory, logsDirectory.getPath() ); databaseBuilder.setConfig( GraphDatabaseSettings.log_queries, Settings.TRUE ); - NeoShallowEmbeddedInteraction db = new NeoShallowEmbeddedInteraction( databaseBuilder ); + EmbeddedInteraction db = new EmbeddedInteraction( databaseBuilder ); // create users db.getManager().newUser( "mats", "neo4j", false ); diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresTestLogic.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresInteractionTestBase.java similarity index 72% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresTestLogic.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresInteractionTestBase.java index cbad280a8e66b..314652bdf5696 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresTestLogic.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresInteractionTestBase.java @@ -19,56 +19,37 @@ */ package org.neo4j.server.security.enterprise.auth; -import org.hamcrest.Matcher; import org.junit.Rule; import org.junit.Test; -import java.time.OffsetDateTime; -import java.util.Collections; import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.neo4j.bolt.v1.transport.integration.TransportTestUtil; -import org.neo4j.bolt.v1.transport.socket.client.SocketConnection; import org.neo4j.bolt.v1.transport.socket.client.TransportConnection; -import org.neo4j.helpers.HostnamePort; import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; -import org.neo4j.test.DoubleLatch; import org.neo4j.test.rule.concurrent.ThreadingRule; import static java.lang.String.format; -import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.isA; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.neo4j.bolt.v1.messaging.message.InitMessage.init; -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; import static org.neo4j.kernel.api.security.AuthenticationResult.PASSWORD_CHANGE_REQUIRED; +import static org.neo4j.server.security.auth.AuthProceduresIT.assertKeyIsMap; import static org.neo4j.server.security.enterprise.auth.AuthProcedures.PERMISSION_DENIED; import static org.neo4j.server.security.enterprise.auth.InternalFlatFileRealm.IS_SUSPENDED; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.ADMIN; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.ARCHITECT; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.PUBLISHER; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.READER; -import static org.neo4j.test.matchers.CommonMatchers.itemsMatchingExactlyOneOf; -public abstract class AuthProceduresTestLogic extends AuthTestBase +public abstract class AuthProceduresInteractionTestBase extends ProcedureInteractionTestBase { private static final String PWD_CHANGE = PASSWORD_CHANGE_REQUIRED.name().toLowerCase(); @@ -129,295 +110,6 @@ public void shouldNotChangeOwnPasswordIfNewPasswordInvalid() throws Exception "Old password and new password cannot be the same." ); } - //---------- list running transactions ----------- - - @Test - public void shouldListSelfTransaction() - { - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); - } - - @Test - public void shouldNotListTransactionsIfNotAdmin() - { - assertFail( noneSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); - assertFail( readSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); - assertFail( writeSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); - assertFail( schemaSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); - } - - @Test - public void shouldListTransactions() throws Throwable - { - DoubleLatch latch = new DoubleLatch( 3 ); - ThreadedTransactionCreate write1 = new ThreadedTransactionCreate<>( neo, latch ); - ThreadedTransactionCreate write2 = new ThreadedTransactionCreate<>( neo, latch ); - - String q1 = write1.execute( threading, writeSubject ); - String q2 = write2.execute( threading, writeSubject ); - latch.startAndWaitForAllToStart(); - - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIsMap( r, "username", "activeTransactions", - map( "adminSubject", "1", "writeSubject", "2" ) ) ); - - latch.finishAndWaitForAllToFinish(); - - write1.closeAndAssertSuccess(); - write2.closeAndAssertSuccess(); - } - - @Test - public void shouldListRestrictedTransaction() - { - final DoubleLatch doubleLatch = new DoubleLatch( 2 ); - - ClassWithProcedures.setTestLatch( new ClassWithProcedures.LatchedRunnables( doubleLatch, () -> {}, () -> {} ) ); - - new Thread( () -> assertEmpty( writeSubject, "CALL test.waitForLatch()" ) ).start(); - doubleLatch.startAndWaitForAllToStart(); - try - { - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIsMap( r, "username", "activeTransactions", - map( "adminSubject", "1", "writeSubject", "1" ) ) ); - } - finally - { - doubleLatch.finishAndWaitForAllToFinish(); - } - } - - @Test - public void shouldListAllQueriesWhenRunningAsAdmin() throws Throwable - { - DoubleLatch latch = new DoubleLatch( 3, true ); - String startTime = OffsetDateTime.now().format( ISO_OFFSET_DATE_TIME ); - - ThreadedTransactionCreate read1 = new ThreadedTransactionCreate<>( neo, latch ); - ThreadedTransactionCreate read2 = new ThreadedTransactionCreate<>( neo, latch ); - - String q1 = read1.execute( threading, readSubject, "UNWIND [1,2,3] AS x RETURN x" ); - String q2 = read2.execute( threading, readSubject, "UNWIND [4,5,6] AS y RETURN y" ); - latch.startAndWaitForAllToStart(); - - String query = "CALL dbms.listQueries()"; - assertSuccess( adminSubject, query, r -> - { - Set> maps = r.stream().collect( Collectors.toSet() ); - - Matcher> thisQuery = listedQuery( startTime, "adminSubject", query ); - Matcher> matcher1 = listedQuery( startTime, "readSubject", q1 ); - Matcher> matcher2 = listedQuery( startTime, "readSubject", q2 ); - - assertThat( maps, itemsMatchingExactlyOneOf( matcher1, matcher2, thisQuery ) ); - } ); - - latch.finishAndWaitForAllToFinish(); - - read1.closeAndAssertSuccess(); - read2.closeAndAssertSuccess(); - } - - @Test - public void shouldOnlyListOwnQueriesWhenNotRunningAsAdmin() throws Throwable - { - DoubleLatch latch = new DoubleLatch( 3, true ); - String startTime = OffsetDateTime.now().format( ISO_OFFSET_DATE_TIME ); - ThreadedTransactionCreate read1 = new ThreadedTransactionCreate<>( neo, latch ); - ThreadedTransactionCreate read2 = new ThreadedTransactionCreate<>( neo, latch ); - - String q1 = read1.execute( threading, readSubject, "UNWIND [1,2,3] AS x RETURN x" ); - String ignored = read2.execute( threading, writeSubject, "UNWIND [4,5,6] AS y RETURN y" ); - latch.startAndWaitForAllToStart(); - - String query = "CALL dbms.listQueries()"; - assertSuccess( readSubject, query, r -> - { - Set> maps = r.stream().collect( Collectors.toSet() ); - - Matcher> thisQuery = listedQuery( startTime, "readSubject", query ); - Matcher> queryMatcher = listedQuery( startTime, "readSubject", q1 ); - - assertThat( maps, itemsMatchingExactlyOneOf( queryMatcher, thisQuery ) ); - } ); - - latch.finishAndWaitForAllToFinish(); - - read1.closeAndAssertSuccess(); - read2.closeAndAssertSuccess(); - } - - - //---------- terminate transactions for user ----------- - - @Test - public void shouldTerminateTransactionForUser() throws Throwable - { - DoubleLatch latch = new DoubleLatch( 2 ); - ThreadedTransactionCreate write = new ThreadedTransactionCreate<>( neo, latch ); - write.execute( threading, writeSubject ); - latch.startAndWaitForAllToStart(); - - assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", - r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "writeSubject", "1" ) ) ); - - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); - - latch.finishAndWaitForAllToFinish(); - - write.closeAndAssertTransactionTermination(); - - assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); - } - - @Test - public void shouldTerminateOnlyGivenUsersTransaction() throws Throwable - { - DoubleLatch latch = new DoubleLatch( 3 ); - ThreadedTransactionCreate schema = new ThreadedTransactionCreate<>( neo, latch ); - ThreadedTransactionCreate write = new ThreadedTransactionCreate<>( neo, latch ); - - schema.execute( threading, schemaSubject ); - write.execute( threading, writeSubject ); - latch.startAndWaitForAllToStart(); - - assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'schemaSubject' )", - r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "schemaSubject", "1" ) ) ); - - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIsMap( r, "username", "activeTransactions", - map( "adminSubject", "1", "writeSubject", "1" ) ) ); - - latch.finishAndWaitForAllToFinish(); - - schema.closeAndAssertTransactionTermination(); - write.closeAndAssertSuccess(); - - assertSuccess( adminSubject, "MATCH (n:Test) RETURN n.name AS name", - r -> assertKeyIs( r, "name", "writeSubject-node" ) ); - } - - @Test - public void shouldTerminateAllTransactionsForGivenUser() throws Throwable - { - DoubleLatch latch = new DoubleLatch( 3 ); - ThreadedTransactionCreate schema1 = new ThreadedTransactionCreate<>( neo, latch ); - ThreadedTransactionCreate schema2 = new ThreadedTransactionCreate<>( neo, latch ); - - schema1.execute( threading, schemaSubject ); - schema2.execute( threading, schemaSubject ); - latch.startAndWaitForAllToStart(); - - assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'schemaSubject' )", - r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "schemaSubject", "2" ) ) ); - - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); - - latch.finishAndWaitForAllToFinish(); - - schema1.closeAndAssertTransactionTermination(); - schema2.closeAndAssertTransactionTermination(); - - assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); - } - - @Test - public void shouldNotTerminateTerminationTransaction() throws InterruptedException, ExecutionException - { - assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'adminSubject' )", - r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "adminSubject", "0" ) ) ); - assertSuccess( readSubject, "CALL dbms.security.terminateTransactionsForUser( 'readSubject' )", - r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "readSubject", "0" ) ) ); - } - - @Test - public void shouldTerminateSelfTransactionsExceptTerminationTransactionIfAdmin() throws Throwable - { - shouldTerminateSelfTransactionsExceptTerminationTransaction( adminSubject ); - } - - @Test - public void shouldTerminateSelfTransactionsExceptTerminationTransactionIfNotAdmin() throws Throwable - { - shouldTerminateSelfTransactionsExceptTerminationTransaction( writeSubject ); - } - - private void shouldTerminateSelfTransactionsExceptTerminationTransaction( S subject ) throws Throwable - { - DoubleLatch latch = new DoubleLatch( 2 ); - ThreadedTransactionCreate create = new ThreadedTransactionCreate<>( neo, latch ); - create.execute( threading, subject ); - - latch.startAndWaitForAllToStart(); - - String subjectName = neo.nameOf( subject ); - assertSuccess( subject, "CALL dbms.security.terminateTransactionsForUser( '" + subjectName + "' )", - r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( subjectName, "1" ) ) ); - - latch.finishAndWaitForAllToFinish(); - - create.closeAndAssertTransactionTermination(); - - assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); - } - - @Test - public void shouldNotTerminateTransactionsIfNonExistentUser() throws InterruptedException, ExecutionException - { - assertFail( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'Petra' )", "User 'Petra' does not exist" ); - assertFail( adminSubject, "CALL dbms.security.terminateTransactionsForUser( '' )", "User '' does not exist" ); - } - - @Test - public void shouldNotTerminateTransactionsIfNotAdmin() throws Throwable - { - DoubleLatch latch = new DoubleLatch( 2 ); - ThreadedTransactionCreate write = new ThreadedTransactionCreate<>( neo, latch ); - write.execute( threading, writeSubject ); - latch.startAndWaitForAllToStart(); - - assertFail( noneSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", PERMISSION_DENIED ); - assertFail( pwdSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", CHANGE_PWD_ERR_MSG ); - assertFail( readSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", PERMISSION_DENIED ); - assertFail( schemaSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", PERMISSION_DENIED ); - - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIs( r, "username", "adminSubject", "writeSubject" ) ); - - latch.finishAndWaitForAllToFinish(); - - write.closeAndAssertSuccess(); - - assertSuccess( adminSubject, "MATCH (n:Test) RETURN n.name AS name", - r -> assertKeyIs( r, "name", "writeSubject-node" ) ); - } - - @Test - public void shouldTerminateRestrictedTransaction() - { - final DoubleLatch doubleLatch = new DoubleLatch( 2 ); - - ClassWithProcedures.setTestLatch( new ClassWithProcedures.LatchedRunnables( doubleLatch, () -> {}, () -> {} ) ); - - new Thread( () -> assertFail( writeSubject, "CALL test.waitForLatch()", "Explicitly terminated by the user." ) ) - .start(); - - doubleLatch.startAndWaitForAllToStart(); - try - { - assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", - r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "writeSubject", "1" ) ) ); - } - finally - { - doubleLatch.finishAndWaitForAllToFinish(); - } - } - //---------- change user password ----------- // Should change password for admin subject and valid user @@ -1288,79 +980,9 @@ public void shouldSetCorrectMultiRolePermissions() throws Exception assertEmpty( schemaSubject, "CALL dbms.security.changePassword( '321' )" ); } - // --------------------- helpers ----------------------- - - private void shouldTerminateTransactionsForUser( S subject, String procedure ) throws Throwable - { - DoubleLatch latch = new DoubleLatch( 2 ); - ThreadedTransactionCreate userThread = new ThreadedTransactionCreate<>( neo, latch ); - userThread.execute( threading, subject ); - latch.startAndWaitForAllToStart(); - - assertEmpty( adminSubject, "CALL " + format(procedure, neo.nameOf( subject ) ) ); - - assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", - r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); - - latch.finishAndWaitForAllToFinish(); - - userThread.closeAndAssertTransactionTermination(); - - assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); - } - - private TransportConnection startBoltSession( String username, String password ) throws Exception - { - TransportConnection connection = new SocketConnection(); - HostnamePort address = new HostnamePort( "localhost:7687" ); - Map authToken = map( "principal", username, "credentials", password, "scheme", "basic" ); - - connection.connect( address ).send( TransportTestUtil.acceptedVersions( 1, 0, 0, 0 ) ) - .send( TransportTestUtil.chunk( init( "TestClient/1.1", authToken ) ) ); - - assertThat( connection, eventuallyReceives( new byte[]{0, 0, 0, 1} ) ); - assertThat( connection, eventuallyReceives( msgSuccess() ) ); - return connection; - } - - //---------- matchers----------- - private Matcher> listedQuery( String startTime, String username, String query ) - { - return allOf( - hasQuery( query ), - hasUsername( username ), - hasQueryId(), - hasStartTimeAfter( startTime ), - hasNoParameters() - ); - } - @SuppressWarnings( "unchecked" ) - private Matcher> hasQuery( String query ) - { - return (Matcher>) (Matcher) hasEntry( equalTo( "query" ), equalTo( query ) ); - } - - @SuppressWarnings( "unchecked" ) - private Matcher> hasUsername( String username ) - { - return (Matcher>) (Matcher) hasEntry( equalTo( "username" ), equalTo( username ) ); - } - - @SuppressWarnings( "unchecked" ) - private Matcher> hasQueryId() - { - return (Matcher>) (Matcher) hasEntry( equalTo( "queryId" ), anyOf( (Matcher) isA( Integer.class ), isA( Long.class ) ) ); - } - - @SuppressWarnings( "unchecked" ) - private Matcher> hasStartTimeAfter( String base ) - { - return (Matcher>) (Matcher) hasEntry( equalTo( "startTime" ), allOf( greaterThanOrEqualTo( base ) ) ); - } - - @SuppressWarnings( "unchecked" ) - private Matcher> hasNoParameters() + @Override + protected ThreadingRule threading() { - return (Matcher>) (Matcher) hasEntry( equalTo( "parameters" ), equalTo ( Collections.emptyMap() ) ); + return threading; } -} \ No newline at end of file +} diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthScenariosLogic.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthScenariosInteractionTestBase.java similarity index 99% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthScenariosLogic.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthScenariosInteractionTestBase.java index be990f5e50e56..dde761b2b8555 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthScenariosLogic.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthScenariosInteractionTestBase.java @@ -22,7 +22,6 @@ import org.junit.Rule; import org.junit.Test; - import org.neo4j.graphdb.Transaction; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; @@ -32,15 +31,14 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThan; - import static org.junit.Assert.fail; -import static org.neo4j.server.security.enterprise.auth.AuthProcedures.*; +import static org.neo4j.server.security.enterprise.auth.AuthProcedures.PERMISSION_DENIED; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.ADMIN; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.ARCHITECT; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.PUBLISHER; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.READER; -public abstract class AuthScenariosLogic extends AuthTestBase +public abstract class AuthScenariosInteractionTestBase extends ProcedureInteractionTestBase { @Rule public final ThreadingRule threading = new ThreadingRule(); @@ -767,4 +765,10 @@ public void changeUserPassword3() throws Throwable testSuccessfulRead( subject, 3 ); assertFail( subject, "CALL dbms.security.changeUserPassword('Craig', '123')", PERMISSION_DENIED ); } + + @Override + protected ThreadingRule threading() + { + return threading; + } } diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltProceduresIT.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltAuthProceduresInteractionTest.java similarity index 84% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltProceduresIT.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltAuthProceduresInteractionTest.java index a4037e543f653..423b8febad16c 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltProceduresIT.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltAuthProceduresInteractionTest.java @@ -28,24 +28,22 @@ import org.neo4j.test.TestGraphDatabaseFactory; import org.neo4j.test.rule.SuppressOutput; -public class BoltProceduresIT extends AuthProceduresTestLogic +public class BoltAuthProceduresInteractionTest extends AuthProceduresInteractionTestBase { private Neo4jWithSocket server = new Neo4jWithSocket( getTestGraphDatabaseFactory(), - settings -> { - settings.put( GraphDatabaseSettings.auth_enabled, "true" ); - } ); + settings -> settings.put( GraphDatabaseSettings.auth_enabled, "true" ) ); @Rule public final RuleChain ruleChain = RuleChain.outerRule( SuppressOutput.suppressAll() ).around( server ); - public BoltProceduresIT() + public BoltAuthProceduresInteractionTest() { super(); IS_EMBEDDED = false; IS_BOLT = true; } - protected TestGraphDatabaseFactory getTestGraphDatabaseFactory() + private TestGraphDatabaseFactory getTestGraphDatabaseFactory() { return new TestEnterpriseGraphDatabaseFactory(); } diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltScenariosIT.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltAuthScenariosInteractionTest.java similarity index 84% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltScenariosIT.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltAuthScenariosInteractionTest.java index 1b637c252078e..8135e23928dd6 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltScenariosIT.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltAuthScenariosInteractionTest.java @@ -28,24 +28,22 @@ import org.neo4j.test.TestGraphDatabaseFactory; import org.neo4j.test.rule.SuppressOutput; -public class BoltScenariosIT extends AuthScenariosLogic +public class BoltAuthScenariosInteractionTest extends AuthScenariosInteractionTestBase { private Neo4jWithSocket server = new Neo4jWithSocket( getTestGraphDatabaseFactory(), - settings -> { - settings.put( GraphDatabaseSettings.auth_enabled, "true" ); - } ); + settings -> settings.put( GraphDatabaseSettings.auth_enabled, "true" ) ); @Rule public final RuleChain ruleChain = RuleChain.outerRule( SuppressOutput.suppressAll() ).around( server ); - public BoltScenariosIT() + public BoltAuthScenariosInteractionTest() { super(); IS_EMBEDDED = false; IS_BOLT = true; } - protected TestGraphDatabaseFactory getTestGraphDatabaseFactory() + private TestGraphDatabaseFactory getTestGraphDatabaseFactory() { return new TestEnterpriseGraphDatabaseFactory(); } diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltBuiltInProceduresInteractionTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltBuiltInProceduresInteractionTest.java new file mode 100644 index 0000000000000..2b7d2ba8c36c0 --- /dev/null +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BoltBuiltInProceduresInteractionTest.java @@ -0,0 +1,56 @@ +/* + * 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; + +import org.junit.Rule; +import org.junit.rules.RuleChain; + +import org.neo4j.bolt.v1.transport.integration.Neo4jWithSocket; +import org.neo4j.graphdb.factory.GraphDatabaseSettings; +import org.neo4j.test.TestEnterpriseGraphDatabaseFactory; +import org.neo4j.test.TestGraphDatabaseFactory; +import org.neo4j.test.rule.SuppressOutput; + +public class BoltBuiltInProceduresInteractionTest extends BuiltInProceduresInteractionTestBase +{ + private Neo4jWithSocket server = new Neo4jWithSocket( getTestGraphDatabaseFactory(), + settings -> settings.put( GraphDatabaseSettings.auth_enabled, "true" ) ); + + @Rule + public final RuleChain ruleChain = RuleChain.outerRule( SuppressOutput.suppressAll() ).around( server ); + + public BoltBuiltInProceduresInteractionTest() + { + super(); + IS_EMBEDDED = false; + IS_BOLT = true; + } + + private TestGraphDatabaseFactory getTestGraphDatabaseFactory() + { + return new TestEnterpriseGraphDatabaseFactory(); + } + + @Override + public NeoInteractionLevel setUpNeoServer() throws Throwable + { + return new BoltInteraction( server ); + } +} diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BuiltInProceduresInteractionTestBase.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BuiltInProceduresInteractionTestBase.java new file mode 100644 index 0000000000000..296241cba536a --- /dev/null +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BuiltInProceduresInteractionTestBase.java @@ -0,0 +1,394 @@ +/* + * 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; + +import org.hamcrest.Matcher; +import org.junit.Rule; +import org.junit.Test; + +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import org.neo4j.test.DoubleLatch; +import org.neo4j.test.rule.concurrent.ThreadingRule; + +import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.isA; +import static org.neo4j.helpers.collection.MapUtil.map; +import static org.neo4j.kernel.api.security.AuthenticationResult.PASSWORD_CHANGE_REQUIRED; +import static org.neo4j.server.security.auth.AuthProceduresIT.assertKeyIsMap; +import static org.neo4j.server.security.enterprise.auth.AuthProcedures.PERMISSION_DENIED; +import static org.neo4j.test.matchers.CommonMatchers.itemsMatchingExactlyOneOf; + +public abstract class BuiltInProceduresInteractionTestBase extends ProcedureInteractionTestBase +{ + private static final String PWD_CHANGE = PASSWORD_CHANGE_REQUIRED.name().toLowerCase(); + + @Rule + public final ThreadingRule threading = new ThreadingRule(); + + //---------- list running transactions ----------- + + @Test + public void shouldListSelfTransaction() + { + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); + } + + @Test + public void shouldNotListTransactionsIfNotAdmin() + { + assertFail( noneSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); + assertFail( readSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); + assertFail( writeSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); + assertFail( schemaSubject, "CALL dbms.security.listTransactions()", PERMISSION_DENIED ); + } + + @Test + public void shouldListTransactions() throws Throwable + { + DoubleLatch latch = new DoubleLatch( 3 ); + ThreadedTransactionCreate write1 = new ThreadedTransactionCreate<>( neo, latch ); + ThreadedTransactionCreate write2 = new ThreadedTransactionCreate<>( neo, latch ); + + String q1 = write1.execute( threading, writeSubject ); + String q2 = write2.execute( threading, writeSubject ); + latch.startAndWaitForAllToStart(); + + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIsMap( r, "username", "activeTransactions", + map( "adminSubject", "1", "writeSubject", "2" ) ) ); + + latch.finishAndWaitForAllToFinish(); + + write1.closeAndAssertSuccess(); + write2.closeAndAssertSuccess(); + } + + @Test + public void shouldListRestrictedTransaction() + { + final DoubleLatch doubleLatch = new DoubleLatch( 2 ); + + ClassWithProcedures.setTestLatch( new ClassWithProcedures.LatchedRunnables( doubleLatch, () -> {}, () -> {} ) ); + + new Thread( () -> assertEmpty( writeSubject, "CALL test.waitForLatch()" ) ).start(); + doubleLatch.startAndWaitForAllToStart(); + try + { + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIsMap( r, "username", "activeTransactions", + map( "adminSubject", "1", "writeSubject", "1" ) ) ); + } + finally + { + doubleLatch.finishAndWaitForAllToFinish(); + } + } + + @SuppressWarnings( "unchecked" ) + @Test + public void shouldListAllQueriesWhenRunningAsAdmin() throws Throwable + { + DoubleLatch latch = new DoubleLatch( 3, true ); + String startTime = OffsetDateTime.now().format( ISO_OFFSET_DATE_TIME ); + + ThreadedTransactionCreate read1 = new ThreadedTransactionCreate<>( neo, latch ); + ThreadedTransactionCreate read2 = new ThreadedTransactionCreate<>( neo, latch ); + + String q1 = read1.execute( threading, readSubject, "UNWIND [1,2,3] AS x RETURN x" ); + String q2 = read2.execute( threading, readSubject, "UNWIND [4,5,6] AS y RETURN y" ); + latch.startAndWaitForAllToStart(); + + String query = "CALL dbms.listQueries()"; + assertSuccess( adminSubject, query, r -> + { + Set> maps = r.stream().collect( Collectors.toSet() ); + + Matcher> thisQuery = listedQuery( startTime, "adminSubject", query ); + Matcher> matcher1 = listedQuery( startTime, "readSubject", q1 ); + Matcher> matcher2 = listedQuery( startTime, "readSubject", q2 ); + + assertThat( maps, itemsMatchingExactlyOneOf( matcher1, matcher2, thisQuery ) ); + } ); + + latch.finishAndWaitForAllToFinish(); + + read1.closeAndAssertSuccess(); + read2.closeAndAssertSuccess(); + } + + @Test + public void shouldOnlyListOwnQueriesWhenNotRunningAsAdmin() throws Throwable + { + DoubleLatch latch = new DoubleLatch( 3, true ); + String startTime = OffsetDateTime.now().format( ISO_OFFSET_DATE_TIME ); + ThreadedTransactionCreate read1 = new ThreadedTransactionCreate<>( neo, latch ); + ThreadedTransactionCreate read2 = new ThreadedTransactionCreate<>( neo, latch ); + + String q1 = read1.execute( threading, readSubject, "UNWIND [1,2,3] AS x RETURN x" ); + String ignored = read2.execute( threading, writeSubject, "UNWIND [4,5,6] AS y RETURN y" ); + latch.startAndWaitForAllToStart(); + + String query = "CALL dbms.listQueries()"; + assertSuccess( readSubject, query, r -> + { + Set> maps = r.stream().collect( Collectors.toSet() ); + + Matcher> thisQuery = listedQuery( startTime, "readSubject", query ); + Matcher> queryMatcher = listedQuery( startTime, "readSubject", q1 ); + + assertThat( maps, itemsMatchingExactlyOneOf( queryMatcher, thisQuery ) ); + } ); + + latch.finishAndWaitForAllToFinish(); + + read1.closeAndAssertSuccess(); + read2.closeAndAssertSuccess(); + } + + + //---------- terminate transactions for user ----------- + + @Test + public void shouldTerminateTransactionForUser() throws Throwable + { + DoubleLatch latch = new DoubleLatch( 2 ); + ThreadedTransactionCreate write = new ThreadedTransactionCreate<>( neo, latch ); + write.execute( threading, writeSubject ); + latch.startAndWaitForAllToStart(); + + assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", + r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "writeSubject", "1" ) ) ); + + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); + + latch.finishAndWaitForAllToFinish(); + + write.closeAndAssertTransactionTermination(); + + assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); + } + + @Test + public void shouldTerminateOnlyGivenUsersTransaction() throws Throwable + { + DoubleLatch latch = new DoubleLatch( 3 ); + ThreadedTransactionCreate schema = new ThreadedTransactionCreate<>( neo, latch ); + ThreadedTransactionCreate write = new ThreadedTransactionCreate<>( neo, latch ); + + schema.execute( threading, schemaSubject ); + write.execute( threading, writeSubject ); + latch.startAndWaitForAllToStart(); + + assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'schemaSubject' )", + r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "schemaSubject", "1" ) ) ); + + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIsMap( r, "username", "activeTransactions", + map( "adminSubject", "1", "writeSubject", "1" ) ) ); + + latch.finishAndWaitForAllToFinish(); + + schema.closeAndAssertTransactionTermination(); + write.closeAndAssertSuccess(); + + assertSuccess( adminSubject, "MATCH (n:Test) RETURN n.name AS name", + r -> assertKeyIs( r, "name", "writeSubject-node" ) ); + } + + @Test + public void shouldTerminateAllTransactionsForGivenUser() throws Throwable + { + DoubleLatch latch = new DoubleLatch( 3 ); + ThreadedTransactionCreate schema1 = new ThreadedTransactionCreate<>( neo, latch ); + ThreadedTransactionCreate schema2 = new ThreadedTransactionCreate<>( neo, latch ); + + schema1.execute( threading, schemaSubject ); + schema2.execute( threading, schemaSubject ); + latch.startAndWaitForAllToStart(); + + assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'schemaSubject' )", + r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "schemaSubject", "2" ) ) ); + + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); + + latch.finishAndWaitForAllToFinish(); + + schema1.closeAndAssertTransactionTermination(); + schema2.closeAndAssertTransactionTermination(); + + assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); + } + + @Test + public void shouldNotTerminateTerminationTransaction() throws InterruptedException, ExecutionException + { + assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'adminSubject' )", + r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "adminSubject", "0" ) ) ); + assertSuccess( readSubject, "CALL dbms.security.terminateTransactionsForUser( 'readSubject' )", + r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "readSubject", "0" ) ) ); + } + + @Test + public void shouldTerminateSelfTransactionsExceptTerminationTransactionIfAdmin() throws Throwable + { + shouldTerminateSelfTransactionsExceptTerminationTransaction( adminSubject ); + } + + @Test + public void shouldTerminateSelfTransactionsExceptTerminationTransactionIfNotAdmin() throws Throwable + { + shouldTerminateSelfTransactionsExceptTerminationTransaction( writeSubject ); + } + + private void shouldTerminateSelfTransactionsExceptTerminationTransaction( S subject ) throws Throwable + { + DoubleLatch latch = new DoubleLatch( 2 ); + ThreadedTransactionCreate create = new ThreadedTransactionCreate<>( neo, latch ); + create.execute( threading, subject ); + + latch.startAndWaitForAllToStart(); + + String subjectName = neo.nameOf( subject ); + assertSuccess( subject, "CALL dbms.security.terminateTransactionsForUser( '" + subjectName + "' )", + r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( subjectName, "1" ) ) ); + + latch.finishAndWaitForAllToFinish(); + + create.closeAndAssertTransactionTermination(); + + assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); + } + + @Test + public void shouldNotTerminateTransactionsIfNonExistentUser() throws InterruptedException, ExecutionException + { + assertFail( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'Petra' )", "User 'Petra' does not exist" ); + assertFail( adminSubject, "CALL dbms.security.terminateTransactionsForUser( '' )", "User '' does not exist" ); + } + + @Test + public void shouldNotTerminateTransactionsIfNotAdmin() throws Throwable + { + DoubleLatch latch = new DoubleLatch( 2 ); + ThreadedTransactionCreate write = new ThreadedTransactionCreate<>( neo, latch ); + write.execute( threading, writeSubject ); + latch.startAndWaitForAllToStart(); + + assertFail( noneSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", PERMISSION_DENIED ); + assertFail( pwdSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", CHANGE_PWD_ERR_MSG ); + assertFail( readSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", PERMISSION_DENIED ); + assertFail( schemaSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", PERMISSION_DENIED ); + + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIs( r, "username", "adminSubject", "writeSubject" ) ); + + latch.finishAndWaitForAllToFinish(); + + write.closeAndAssertSuccess(); + + assertSuccess( adminSubject, "MATCH (n:Test) RETURN n.name AS name", + r -> assertKeyIs( r, "name", "writeSubject-node" ) ); + } + + @Test + public void shouldTerminateRestrictedTransaction() + { + final DoubleLatch doubleLatch = new DoubleLatch( 2 ); + + ClassWithProcedures.setTestLatch( new ClassWithProcedures.LatchedRunnables( doubleLatch, () -> {}, () -> {} ) ); + + new Thread( () -> assertFail( writeSubject, "CALL test.waitForLatch()", "Explicitly terminated by the user." ) ) + .start(); + + doubleLatch.startAndWaitForAllToStart(); + try + { + assertSuccess( adminSubject, "CALL dbms.security.terminateTransactionsForUser( 'writeSubject' )", + r -> assertKeyIsMap( r, "username", "transactionsTerminated", map( "writeSubject", "1" ) ) ); + } + finally + { + doubleLatch.finishAndWaitForAllToFinish(); + } + } + + //---------- matchers----------- + + private Matcher> listedQuery( String startTime, String username, String query ) + { + return allOf( + hasQuery( query ), + hasUsername( username ), + hasQueryId(), + hasStartTimeAfter( startTime ), + hasNoParameters() + ); + } + @SuppressWarnings( "unchecked" ) + private Matcher> hasQuery( String query ) + { + return (Matcher>) (Matcher) hasEntry( equalTo( "query" ), equalTo( query ) ); + } + + @SuppressWarnings( "unchecked" ) + private Matcher> hasUsername( String username ) + { + return (Matcher>) (Matcher) hasEntry( equalTo( "username" ), equalTo( username ) ); + } + + @SuppressWarnings( "unchecked" ) + private Matcher> hasQueryId() + { + return (Matcher>) (Matcher) hasEntry( equalTo( "queryId" ), anyOf( (Matcher) isA( Integer.class ), isA( Long.class ) ) ); + } + + @SuppressWarnings( "unchecked" ) + private Matcher> hasStartTimeAfter( String base ) + { + return (Matcher>) (Matcher) hasEntry( equalTo( "startTime" ), allOf( greaterThanOrEqualTo( base ) ) ); + } + + @SuppressWarnings( "unchecked" ) + private Matcher> hasNoParameters() + { + return (Matcher>) (Matcher) hasEntry( equalTo( "parameters" ), equalTo ( Collections.emptyMap() ) ); + } + + @Override + protected ThreadingRule threading() + { + return threading; + } +} diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedAuthProceduresInteractionTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedAuthProceduresInteractionTest.java new file mode 100644 index 0000000000000..d64875885b122 --- /dev/null +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedAuthProceduresInteractionTest.java @@ -0,0 +1,31 @@ +/* + * 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; + +import org.neo4j.kernel.enterprise.api.security.EnterpriseAuthSubject; + +public class EmbeddedAuthProceduresInteractionTest extends AuthProceduresInteractionTestBase +{ + @Override + protected NeoInteractionLevel setUpNeoServer() throws Throwable + { + return new EmbeddedInteraction(); + } +} diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedScenariosTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedAuthScenariosInteractionTest.java similarity index 87% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedScenariosTest.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedAuthScenariosInteractionTest.java index 1a3c036231939..0dde2d02dfaf5 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedScenariosTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedAuthScenariosInteractionTest.java @@ -21,11 +21,11 @@ import org.neo4j.kernel.enterprise.api.security.EnterpriseAuthSubject; -public class NeoShallowEmbeddedScenariosTest extends AuthScenariosLogic +public class EmbeddedAuthScenariosInteractionTest extends AuthScenariosInteractionTestBase { @Override protected NeoInteractionLevel setUpNeoServer() throws Throwable { - return new NeoShallowEmbeddedInteraction(); + return new EmbeddedInteraction(); } } diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedProceduresTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresTest.java similarity index 87% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedProceduresTest.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresTest.java index 1a0e92d5ed8db..aecb88b36e125 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedProceduresTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresTest.java @@ -21,11 +21,11 @@ import org.neo4j.kernel.enterprise.api.security.EnterpriseAuthSubject; -public class NeoShallowEmbeddedProceduresTest extends AuthProceduresTestLogic +public class EmbeddedBuiltInProceduresTest extends BuiltInProceduresInteractionTestBase { @Override protected NeoInteractionLevel setUpNeoServer() throws Throwable { - return new NeoShallowEmbeddedInteraction(); + return new EmbeddedInteraction(); } } diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedInteraction.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedInteraction.java similarity index 95% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedInteraction.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedInteraction.java index 7c1b885afe548..79761a0fa2323 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/NeoShallowEmbeddedInteraction.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedInteraction.java @@ -40,18 +40,18 @@ import static org.neo4j.graphdb.factory.GraphDatabaseSettings.boltConnector; import static org.neo4j.server.security.auth.SecurityTestUtils.authToken; -public class NeoShallowEmbeddedInteraction implements NeoInteractionLevel +public class EmbeddedInteraction implements NeoInteractionLevel { private GraphDatabaseFacade db; private MultiRealmAuthManager manager; private EnterpriseUserManager userManager; - NeoShallowEmbeddedInteraction() throws Throwable + EmbeddedInteraction() throws Throwable { this(new TestEnterpriseGraphDatabaseFactory().newImpermanentDatabaseBuilder()); } - public NeoShallowEmbeddedInteraction( GraphDatabaseBuilder builder ) throws Throwable + public EmbeddedInteraction( GraphDatabaseBuilder builder ) throws Throwable { builder.setConfig( boltConnector( "0" ).enabled, "true" ); builder.setConfig( boltConnector( "0" ).encryption_level, OPTIONAL.name() ); diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthTestBase.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ProcedureInteractionTestBase.java similarity index 83% rename from enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthTestBase.java rename to enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ProcedureInteractionTestBase.java index 35663c4be5946..58625778d5bba 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthTestBase.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ProcedureInteractionTestBase.java @@ -31,18 +31,22 @@ import java.util.stream.Stream; import org.neo4j.bolt.v1.transport.integration.Neo4jWithSocket; +import org.neo4j.bolt.v1.transport.integration.TransportTestUtil; +import org.neo4j.bolt.v1.transport.socket.client.SocketConnection; +import org.neo4j.bolt.v1.transport.socket.client.TransportConnection; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.ResourceIterator; -import org.neo4j.graphdb.Result; +import org.neo4j.helpers.HostnamePort; import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; import org.neo4j.kernel.impl.proc.Procedures; import org.neo4j.logging.Log; import org.neo4j.procedure.Context; import org.neo4j.procedure.Procedure; import org.neo4j.test.DoubleLatch; +import org.neo4j.test.rule.concurrent.ThreadingRule; +import static java.lang.String.format; import static java.util.stream.Collectors.toList; - import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.either; import static org.hamcrest.MatcherAssert.assertThat; @@ -51,33 +55,37 @@ import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.neo4j.bolt.v1.messaging.message.InitMessage.init; +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; import static org.neo4j.procedure.Procedure.Mode.READ; import static org.neo4j.procedure.Procedure.Mode.WRITE; +import static org.neo4j.server.security.auth.AuthProceduresIT.assertKeyIsMap; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.ADMIN; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.ARCHITECT; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.PUBLISHER; import static org.neo4j.server.security.enterprise.auth.PredefinedRolesBuilder.READER; -abstract class AuthTestBase +abstract class ProcedureInteractionTestBase { protected boolean PWD_CHANGE_CHECK_FIRST = false; protected String CHANGE_PWD_ERR_MSG = AuthProcedures.PERMISSION_DENIED; - protected String BOLT_PWD_ERR_MSG = + private String BOLT_PWD_ERR_MSG = "The credentials you provided were valid, but must be changed before you can use this instance."; - protected String READ_OPS_NOT_ALLOWED = "Read operations are not allowed"; - protected String WRITE_OPS_NOT_ALLOWED = "Write operations are not allowed"; - protected String SCHEMA_OPS_NOT_ALLOWED = "Schema operations are not allowed"; + String READ_OPS_NOT_ALLOWED = "Read operations are not allowed"; + String WRITE_OPS_NOT_ALLOWED = "Write operations are not allowed"; + String SCHEMA_OPS_NOT_ALLOWED = "Schema operations are not allowed"; protected boolean IS_EMBEDDED = true; - protected boolean IS_BOLT = false; + boolean IS_BOLT = false; - protected String pwdReqErrMsg( String errMsg ) + String pwdReqErrMsg( String errMsg ) { return PWD_CHANGE_CHECK_FIRST ? CHANGE_PWD_ERR_MSG : IS_EMBEDDED ? errMsg : BOLT_PWD_ERR_MSG; } - final String EMPTY_ROLE = "empty"; + private final String EMPTY_ROLE = "empty"; S adminSubject; S schemaSubject; @@ -90,7 +98,9 @@ protected String pwdReqErrMsg( String errMsg ) "writeSubject", "pwdSubject", "noneSubject", "neo4j" }; String[] initialRoles = { ADMIN, ARCHITECT, PUBLISHER, READER, EMPTY_ROLE }; - protected EnterpriseUserManager userManager; + protected abstract ThreadingRule threading(); + + EnterpriseUserManager userManager; protected NeoInteractionLevel neo; @@ -138,7 +148,7 @@ protected String[] with( String[] strs, String... moreStr ) return Stream.concat( Arrays.stream(strs), Arrays.stream( moreStr ) ).toArray( String[]::new ); } - protected List listOf( String... values ) + List listOf( String... values ) { return Stream.of( values ).collect( toList() ); } @@ -321,7 +331,7 @@ void assertFail( S subject, String call, String partOfErrorMsg ) assertThat( err, containsString( partOfErrorMsg ) ); } - void assertFail( S subject, String call, String partOfErrorMsg1, String partOfErrorMsg2 ) + private void assertFail( S subject, String call, String partOfErrorMsg1, String partOfErrorMsg2 ) { String err = assertCallEmpty( subject, call ); assertThat( err, not( equalTo( "" ) ) ); @@ -367,48 +377,50 @@ void assertKeyIs( ResourceIterator> r, String key, String... assertKeyIsArray( r, key, items ); } - void assertKeyIsArray( ResourceIterator> r, String key, String[] items ) + private void assertKeyIsArray( ResourceIterator> r, String key, String[] items ) { List results = getObjectsAsList( r, key ); assertEquals( Arrays.asList( items ).size(), results.size() ); Assert.assertThat( results, containsInAnyOrder( items ) ); } - protected void assertKeyIsMap( ResourceIterator> r, String keyKey, String valueKey, Map expected ) + // --------------------- helpers ----------------------- + + void shouldTerminateTransactionsForUser( S subject, String procedure ) throws Throwable { - List> result = r.stream().collect( toList() ); + DoubleLatch latch = new DoubleLatch( 2 ); + ThreadedTransactionCreate userThread = new ThreadedTransactionCreate<>( neo, latch ); + userThread.execute( threading(), subject ); + latch.startAndWaitForAllToStart(); - assertEquals( "Results for should have size " + expected.size() + " but was " + result.size(), - expected.size(), result.size() ); + assertEmpty( adminSubject, "CALL " + format(procedure, neo.nameOf( subject ) ) ); - for ( Map row : result ) - { - String key = (String) row.get( keyKey ); - assertTrue( "Unexpected key '" + key + "'", expected.containsKey( key ) ); + assertSuccess( adminSubject, "CALL dbms.security.listTransactions()", + r -> assertKeyIsMap( r, "username", "activeTransactions", map( "adminSubject", "1" ) ) ); - assertTrue( "Value key '" + valueKey + "' not found in results", row.containsKey( valueKey ) ); - Object objectValue = row.get( valueKey ); - if ( objectValue instanceof List ) - { - List value = (List) objectValue; - List expectedValues = (List) expected.get( key ); - assertEquals( "Results for '" + key + "' should have size " + expectedValues.size() + " but was " + - value.size(), value.size(), expectedValues.size() ); - assertThat( value, containsInAnyOrder( expectedValues.toArray() ) ); - } - else - { - String value = objectValue.toString(); - String expectedValue = expected.get( key ).toString(); - assertTrue( - String.format( "Wrong value for '%s', expected '%s', got '%s'", key, expectedValue, value), - value.equals( expectedValue ) - ); - } - } + latch.finishAndWaitForAllToFinish(); + + userThread.closeAndAssertTransactionTermination(); + + assertEmpty( adminSubject, "MATCH (n:Test) RETURN n.name AS name" ); + } + + @SuppressWarnings( "unchecked" ) + TransportConnection startBoltSession( String username, String password ) throws Exception + { + TransportConnection connection = new SocketConnection(); + HostnamePort address = new HostnamePort( "localhost:7687" ); + Map authToken = map( "principal", username, "credentials", password, "scheme", "basic" ); + + connection.connect( address ).send( TransportTestUtil.acceptedVersions( 1, 0, 0, 0 ) ) + .send( TransportTestUtil.chunk( init( "TestClient/1.1", authToken ) ) ); + + assertThat( connection, eventuallyReceives( new byte[]{0, 0, 0, 1} ) ); + assertThat( connection, eventuallyReceives( msgSuccess() ) ); + return connection; } - public static class CountResult + private static class CountResult { public final String count; @@ -418,7 +430,7 @@ public static class CountResult } } - public static class ClassWithProcedures + static class ClassWithProcedures { @Context public GraphDatabaseService db; @@ -490,7 +502,7 @@ static class LatchedRunnables implements AutoCloseable Runnable runBefore; Runnable runAfter; - public LatchedRunnables( DoubleLatch doubleLatch, Runnable runBefore, Runnable runAfter ) + LatchedRunnables( DoubleLatch doubleLatch, Runnable runBefore, Runnable runAfter ) { this.doubleLatch = doubleLatch; this.runBefore = runBefore; @@ -504,7 +516,7 @@ public void close() throws Exception } } - public static void setTestLatch( LatchedRunnables testLatch ) + static void setTestLatch( LatchedRunnables testLatch ) { ClassWithProcedures.testLatch.set( testLatch ); } diff --git a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTProceduresIT.java b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTAuthProceduresIT.java similarity index 85% rename from enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTProceduresIT.java rename to enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTAuthProceduresIT.java index 82d3a4abf727b..d456102e92886 100644 --- a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTProceduresIT.java +++ b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTAuthProceduresIT.java @@ -21,18 +21,18 @@ import org.junit.Rule; -import org.neo4j.server.security.enterprise.auth.AuthProceduresTestLogic; +import org.neo4j.server.security.enterprise.auth.AuthProceduresInteractionTestBase; import org.neo4j.server.security.enterprise.auth.NeoInteractionLevel; import org.neo4j.test.rule.SuppressOutput; import static org.neo4j.test.rule.SuppressOutput.suppressAll; -public class NeoFullRESTProceduresIT extends AuthProceduresTestLogic +public class RESTAuthProceduresIT extends AuthProceduresInteractionTestBase { @Rule public SuppressOutput suppressOutput = suppressAll(); - public NeoFullRESTProceduresIT() + public RESTAuthProceduresIT() { super(); CHANGE_PWD_ERR_MSG = "User is required to change their password."; @@ -43,6 +43,6 @@ public NeoFullRESTProceduresIT() @Override public NeoInteractionLevel setUpNeoServer() throws Throwable { - return new NeoFullRESTInteraction(); + return new RESTInteraction(); } } diff --git a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTScenariosIT.java b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTAuthScenariosIT.java similarity index 85% rename from enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTScenariosIT.java rename to enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTAuthScenariosIT.java index 2abbb1bb57785..b3a37f0759d8e 100644 --- a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTScenariosIT.java +++ b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTAuthScenariosIT.java @@ -21,18 +21,18 @@ import org.junit.Rule; -import org.neo4j.server.security.enterprise.auth.AuthScenariosLogic; +import org.neo4j.server.security.enterprise.auth.AuthScenariosInteractionTestBase; import org.neo4j.server.security.enterprise.auth.NeoInteractionLevel; import org.neo4j.test.rule.SuppressOutput; import static org.neo4j.test.rule.SuppressOutput.suppressAll; -public class NeoFullRESTScenariosIT extends AuthScenariosLogic +public class RESTAuthScenariosIT extends AuthScenariosInteractionTestBase { @Rule public SuppressOutput suppressOutput = suppressAll(); - public NeoFullRESTScenariosIT() + public RESTAuthScenariosIT() { super(); CHANGE_PWD_ERR_MSG = "User is required to change their password."; @@ -43,6 +43,6 @@ public NeoFullRESTScenariosIT() @Override protected NeoInteractionLevel setUpNeoServer() throws Throwable { - return new NeoFullRESTInteraction(); + return new RESTInteraction(); } } diff --git a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTBuiltInProceduresIT.java b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTBuiltInProceduresIT.java new file mode 100644 index 0000000000000..e49fc8d7b8b1a --- /dev/null +++ b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTBuiltInProceduresIT.java @@ -0,0 +1,48 @@ +/* + * 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.rest.security; + +import org.junit.Rule; + +import org.neo4j.server.security.enterprise.auth.BuiltInProceduresInteractionTestBase; +import org.neo4j.server.security.enterprise.auth.NeoInteractionLevel; +import org.neo4j.test.rule.SuppressOutput; + +import static org.neo4j.test.rule.SuppressOutput.suppressAll; + +public class RESTBuiltInProceduresIT extends BuiltInProceduresInteractionTestBase +{ + @Rule + public SuppressOutput suppressOutput = suppressAll(); + + public RESTBuiltInProceduresIT() + { + super(); + CHANGE_PWD_ERR_MSG = "User is required to change their password."; + PWD_CHANGE_CHECK_FIRST = true; + IS_EMBEDDED = false; + } + + @Override + public NeoInteractionLevel setUpNeoServer() throws Throwable + { + return new RESTInteraction(); + } +} diff --git a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTInteraction.java b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTInteraction.java similarity index 94% rename from enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTInteraction.java rename to enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTInteraction.java index 12b12f1b8afde..37e4f087079d8 100644 --- a/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/NeoFullRESTInteraction.java +++ b/enterprise/server-enterprise/src/test/java/org/neo4j/server/rest/security/RESTInteraction.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.function.Consumer; @@ -59,14 +58,14 @@ import static org.neo4j.graphdb.factory.GraphDatabaseSettings.boltConnector; import static org.neo4j.kernel.api.security.AuthToken.newBasicAuthToken; -public class NeoFullRESTInteraction extends CommunityServerTestBase implements NeoInteractionLevel +class RESTInteraction extends CommunityServerTestBase implements NeoInteractionLevel { - String COMMIT_PATH = "db/data/transaction/commit"; - String POST = "POST"; + private String COMMIT_PATH = "db/data/transaction/commit"; + private String POST = "POST"; EnterpriseAuthManager authManager; - public NeoFullRESTInteraction() throws IOException + RESTInteraction() throws IOException { server = EnterpriseServerBuilder.server() .withProperty( boltConnector( "0" ).enabled.name(), "true" ) @@ -211,18 +210,18 @@ private String parseErrorMessage( HTTP.Response response ) return ""; } - protected String commitURL() + private String commitURL() { return server.baseUri().resolve( COMMIT_PATH ).toString(); } - class RESTResult implements ResourceIterator> + private class RESTResult implements ResourceIterator> { private JsonNode data; private JsonNode columns; private int index = 0; - public RESTResult( JsonNode fullResult ) + RESTResult( JsonNode fullResult ) { this.data = fullResult.get( "data" ); this.columns = fullResult.get( "columns" ); @@ -244,7 +243,7 @@ public boolean hasNext() public Map next() { JsonNode row = data.get( index++ ).get( "row" ); - TreeMap map = new TreeMap(); + TreeMap map = new TreeMap<>(); for ( int i = 0; i < columns.size(); i++ ) { String key = columns.get( i ).asText(); @@ -270,7 +269,7 @@ else if ( valueNode instanceof ObjectNode ) else if ( valueNode instanceof ArrayNode ) { ArrayNode aNode = (ArrayNode) valueNode; - ArrayList listValue = new ArrayList( aNode.size() ); + ArrayList listValue = new ArrayList<>( aNode.size() ); for ( int j = 0; j < aNode.size(); j++ ) { listValue.add( aNode.get( j ).asText() ); @@ -297,7 +296,7 @@ else if ( valueNode instanceof LongNode ) private Map mapValue( Iterator columns, JsonNode node ) { - TreeMap map = new TreeMap(); + TreeMap map = new TreeMap<>(); while ( columns.hasNext() ) { String key = columns.next();