Skip to content

Commit

Permalink
Add test to ensure we have an auth subject even if not authenticated …
Browse files Browse the repository at this point in the history
…in core API
  • Loading branch information
boggle authored and systay committed Sep 14, 2016
1 parent 2a4f610 commit deeff3b
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 47 deletions.
Expand Up @@ -42,6 +42,16 @@ public <T> T get( Key<T> key ) throws ProcedureException
return (T) o;
}

@Override
public <T> T getOrElse( Key<T> key, T defaultValue ) throws ProcedureException
{
Object o = values.get( key.name() );
if( o == null ) {
return defaultValue;
}
return (T) o;
}

public <T> void put( Key<T> key, T value )
{
values.put( key.name(), value );
Expand Down
Expand Up @@ -31,10 +31,10 @@
*/
public interface Context
{
Key<KernelTransaction>
KERNEL_TRANSACTION = Key.key( "KernelTransaction", KernelTransaction.class );
Key<KernelTransaction> KERNEL_TRANSACTION = Key.key( "KernelTransaction", KernelTransaction.class );
Key<AuthSubject> AUTH_SUBJECT = Key.key( "AuthSubject", AuthSubject.class );
Key<Thread> THREAD = Key.key( "Thread", Thread.class );

<T> T get( Key<T> key ) throws ProcedureException;
<T> T getOrElse( Key<T> key, T defaultValue ) throws ProcedureException;
}
Expand Up @@ -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;

Expand All @@ -47,10 +49,10 @@ public RawIterator<Object[],ProcedureException> 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 );
}
Expand Down
Expand Up @@ -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
Expand All @@ -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;
}

Expand Down
Expand Up @@ -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()
Expand Down
@@ -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 <http://www.gnu.org/licenses/>.
*/
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<EnterpriseAuthSubject>
{
@Override
protected NeoInteractionLevel<EnterpriseAuthSubject> setUpNeoServer( Map<Setting<?>, 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<EnterpriseAuthSubject> 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 );
}
};
}
}

This file was deleted.

Expand Up @@ -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 );
Expand Down

0 comments on commit deeff3b

Please sign in to comment.