diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/proc/BasicContext.java b/community/kernel/src/main/java/org/neo4j/kernel/api/proc/BasicContext.java index 7291d2253e5d3..d51097f10c4e6 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/proc/BasicContext.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/proc/BasicContext.java @@ -42,6 +42,16 @@ public T get( Key key ) throws ProcedureException return (T) o; } + @Override + public T getOrElse( Key key, T defaultValue ) throws ProcedureException + { + Object o = values.get( key.name() ); + if( o == null ) { + return defaultValue; + } + return (T) o; + } + public void put( Key key, T value ) { values.put( key.name(), value ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/proc/Context.java b/community/kernel/src/main/java/org/neo4j/kernel/api/proc/Context.java index 7b3a5b185a695..fa00879c414bc 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/proc/Context.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/proc/Context.java @@ -31,10 +31,10 @@ */ public interface Context { - Key - KERNEL_TRANSACTION = Key.key( "KernelTransaction", KernelTransaction.class ); + Key KERNEL_TRANSACTION = Key.key( "KernelTransaction", KernelTransaction.class ); Key AUTH_SUBJECT = Key.key( "AuthSubject", AuthSubject.class ); Key THREAD = Key.key( "Thread", Thread.class ); T get( Key key ) throws ProcedureException; + T getOrElse( Key key, T defaultValue ) throws ProcedureException; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/dbms/NonTransactionalDbmsOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/dbms/NonTransactionalDbmsOperations.java index 8d6deb09f8b0a..1c1a84a1a57bf 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/dbms/NonTransactionalDbmsOperations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/dbms/NonTransactionalDbmsOperations.java @@ -24,8 +24,10 @@ import org.neo4j.kernel.api.dbms.DbmsOperations; import org.neo4j.kernel.api.exceptions.ProcedureException; import org.neo4j.kernel.api.proc.BasicContext; +import org.neo4j.kernel.api.proc.CallableProcedure; import org.neo4j.kernel.api.proc.Context; import org.neo4j.kernel.api.proc.QualifiedName; +import org.neo4j.kernel.api.security.AccessMode; import org.neo4j.kernel.api.security.AuthSubject; import org.neo4j.kernel.impl.proc.Procedures; @@ -47,10 +49,10 @@ public RawIterator procedureCallDbms( QualifiedName { BasicContext ctx = new BasicContext(); ctx.put( Context.KERNEL_TRANSACTION, transaction ); - if ( transaction.mode() instanceof AuthSubject ) + AccessMode mode = transaction.mode(); + if ( mode instanceof AuthSubject ) { - AuthSubject subject = (AuthSubject) transaction.mode(); - ctx.put( Context.AUTH_SUBJECT, subject ); + ctx.put( Context.AUTH_SUBJECT, (AuthSubject) mode ); } return procedures.callProcedure( ctx, name, input ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java index 1c076a68e3484..6ba8c75a6a0e1 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java @@ -404,7 +404,9 @@ private Procedures setupProcedures( PlatformModule platform, EditionModule editi procedures.registerComponent( DependencyResolver.class, ( ctx ) -> platform.dependencies ); procedures.registerComponent( KernelTransaction.class, ( ctx ) -> ctx.get( KERNEL_TRANSACTION ) ); procedures.registerComponent( GraphDatabaseAPI.class, ( ctx ) -> platform.graphDatabaseFacade ); - procedures.registerComponent( AuthSubject.class, ctx -> ctx.get( AUTH_SUBJECT ) ); + + // Security procedures + procedures.registerComponent( AuthSubject.class, ctx -> ctx.getOrElse( AUTH_SUBJECT, AuthSubject.ANONYMOUS ) ); // Edition procedures try @@ -416,12 +418,6 @@ private Procedures setupProcedures( PlatformModule platform, EditionModule editi internalLog.error( "Failed to register built-in edition procedures at start up: " + e.getMessage() ); } - // Service providers - for ( ProceduresProvider candidate : Service.load( ProceduresProvider.class ) ) - { - candidate.registerProcedures( procedures ); - } - return procedures; } 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 index 5fd4d05ba4dde..c36ea9737f1c2 100644 --- 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 @@ -428,7 +428,7 @@ public void shouldTerminateQueriesEvenIfUsingPeriodicCommit() throws Throwable } } - private Number getIdOfQuery( String writeQuery ) + protected Number getIdOfQuery( String writeQuery ) { return (Number) single( collectSuccessResult( adminSubject, "CALL dbms.listQueries()" ) .stream() diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresInteractionTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresInteractionTest.java new file mode 100644 index 0000000000000..1506c1eba9a2d --- /dev/null +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresInteractionTest.java @@ -0,0 +1,191 @@ +/* + * 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.Test; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import org.neo4j.graphdb.QueryExecutionException; +import org.neo4j.graphdb.Result; +import org.neo4j.graphdb.config.Setting; +import org.neo4j.graphdb.security.AuthorizationViolationException; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.security.AccessMode; +import org.neo4j.kernel.api.security.AuthSubject; +import org.neo4j.kernel.api.security.AuthenticationResult; +import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; +import org.neo4j.kernel.enterprise.api.security.EnterpriseAuthSubject; +import org.neo4j.kernel.impl.coreapi.InternalTransaction; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; +import org.neo4j.test.DoubleLatch; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.neo4j.graphdb.security.AuthorizationViolationException.PERMISSION_DENIED; + +public class EmbeddedBuiltInProceduresInteractionTest extends BuiltInProceduresInteractionTestBase +{ + @Override + protected NeoInteractionLevel setUpNeoServer( Map, String> config ) throws Throwable + { + return new EmbeddedInteraction( config ); + } + + @Test + public void shouldNotListAnyQueriesIfNotAuthenticated() + { + GraphDatabaseFacade graph = neo.getLocalGraph(); + + try ( InternalTransaction tx = graph + .beginTransaction( KernelTransaction.Type.explicit, AccessMode.Static.FULL ) ) + { + Result result = graph.execute( tx, "CALL dbms.listQueries", Collections.emptyMap() ); + assertFalse( result.hasNext() ); + tx.success(); + } + } + + @Test + public void shouldNotTerminateQueryIfNotAuthenticated() throws Throwable + { + EnterpriseAuthSubject authy = createFakeAnonymousEnterpriseAuthSubject(); + + GraphDatabaseFacade graph = neo.getLocalGraph(); + DoubleLatch latch = new DoubleLatch( 2 ); + ThreadedTransactionCreate read = new ThreadedTransactionCreate<>( neo, latch ); + String query = read.execute( threading, authy, "UNWIND [1,2,3] AS x RETURN x" ); + + latch.startAndWaitForAllToStart(); + + Number id = getIdOfQuery( query ); + + + try ( InternalTransaction tx = graph + .beginTransaction( KernelTransaction.Type.explicit, AuthSubject.ANONYMOUS ) ) + { + graph.execute( tx, "CALL dbms.terminateQuery(" + id + ")", Collections.emptyMap() ); + throw new AssertionError( "Expected exception to be thrown" ); + } + catch ( QueryExecutionException e ) + { + assertThat( e.getMessage(), containsString( PERMISSION_DENIED ) ); + } + + latch.finishAndWaitForAllToFinish(); + read.closeAndAssertSuccess(); + } + + private EnterpriseAuthSubject createFakeAnonymousEnterpriseAuthSubject() + { + return new EnterpriseAuthSubject() + { + + @Override + public boolean allowsReads() + { + return ANONYMOUS.allowsReads(); + } + + @Override + public boolean allowsWrites() + { + return ANONYMOUS.allowsWrites(); + } + + @Override + public boolean allowsSchemaWrites() + { + return ANONYMOUS.allowsSchemaWrites(); + } + + @Override + public boolean overrideOriginalMode() + { + return ANONYMOUS.overrideOriginalMode(); + } + + @Override + public AuthorizationViolationException onViolation( String msg ) + { + return ANONYMOUS.onViolation( msg ); + } + + @Override + public String name() + { + return ANONYMOUS.name(); + } + + @Override + public boolean isAdmin() + { + return false; + } + + @Override + public void logout() + { + ANONYMOUS.logout(); + } + + @Override + public AuthenticationResult getAuthenticationResult() + { + return ANONYMOUS.getAuthenticationResult(); + } + + @Override + public void setPassword( String password, boolean requirePasswordChange ) + throws IOException, InvalidArgumentsException + { + ANONYMOUS.setPassword( password, requirePasswordChange ); + + } + + @Override + public boolean allowsProcedureWith( String[] roleNames ) throws InvalidArgumentsException + { + return ANONYMOUS.allowsProcedureWith( roleNames ); + } + + @Override + public String username() + { + return ANONYMOUS.username(); + } + + @Override + public boolean hasUsername( String username ) + { + return ANONYMOUS.hasUsername( username ); + } + + @Override + public void ensureUserExistsWithName( String username ) throws InvalidArgumentsException + { + ANONYMOUS.ensureUserExistsWithName( username ); + } + }; + } +} diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresTest.java deleted file mode 100644 index 6a10de70a933c..0000000000000 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EmbeddedBuiltInProceduresTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 java.util.Map; - -import org.neo4j.graphdb.config.Setting; -import org.neo4j.kernel.enterprise.api.security.EnterpriseAuthSubject; - -public class EmbeddedBuiltInProceduresTest extends BuiltInProceduresInteractionTestBase -{ - @Override - protected NeoInteractionLevel setUpNeoServer( Map, String> config ) throws Throwable - { - return new EmbeddedInteraction( config ); - } -} diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ThreadedTransactionCreate.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ThreadedTransactionCreate.java index 9ae73ed3eddf9..4bea04ef7e0b7 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ThreadedTransactionCreate.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ThreadedTransactionCreate.java @@ -56,6 +56,7 @@ String execute( ThreadingRule threading, S subject, String query ) return doExecute( threading, subject, KernelTransaction.Type.explicit, false, query ); } + String executeEarly( ThreadingRule threading, S subject, KernelTransaction.Type txType, String query ) { return doExecute( threading, subject, txType, true, query );