Skip to content

Commit

Permalink
Moved enterprise auth procs logging and admin checks to personal user…
Browse files Browse the repository at this point in the history
… manager
  • Loading branch information
fickludd committed Oct 5, 2016
1 parent 143751e commit 5fb06a7
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 280 deletions.
Expand Up @@ -25,6 +25,7 @@
import java.util.Set;
import java.util.stream.Stream;

import org.neo4j.graphdb.security.AuthorizationViolationException;
import org.neo4j.kernel.api.security.AuthSubject;
import org.neo4j.kernel.api.exceptions.InvalidArgumentsException;
import org.neo4j.procedure.Context;
Expand Down Expand Up @@ -78,6 +79,10 @@ public void changePasswordDeprecated( @Name( "password" ) String password ) thro
@Procedure( name = "dbms.security.changePassword", mode = DBMS )
public void changePassword( @Name( "password" ) String password ) throws InvalidArgumentsException, IOException
{
if ( authSubject == AuthSubject.ANONYMOUS )
{
throw new AuthorizationViolationException( "Anonymous cannot change password" );
}
userManager.setUserPassword( authSubject.username(), password, false );
}

Expand Down
Expand Up @@ -23,43 +23,19 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;

import org.neo4j.collection.RawIterator;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.kernel.api.exceptions.ProcedureException;
import org.neo4j.kernel.api.security.AccessMode;
import org.neo4j.kernel.api.security.AuthSubject;
import org.neo4j.kernel.impl.api.integrationtest.KernelIntegrationTest;
import org.neo4j.test.TestGraphDatabaseBuilder;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.emptyIterable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.neo4j.helpers.collection.Iterators.asList;
import static org.neo4j.kernel.api.proc.ProcedureSignature.procedureName;

public class AuthProceduresTest extends KernelIntegrationTest
{
@Rule
public ExpectedException exception = ExpectedException.none();

@Test
public void callDeprecatedChangePasswordWithAccessModeInDbmsMode() throws Throwable
{
// Given
Object[] inputArray = new Object[1];
inputArray[0] = "newPassword";
AuthSubject authSubject = mock( AuthSubject.class );

// When
RawIterator<Object[], ProcedureException> stream = dbmsOperations().procedureCallDbms(
procedureName( "dbms", "changePassword" ), inputArray, authSubject );

// Then
verify( authSubject ).setPassword( (String) inputArray[0], false );
assertThat( asList( stream ), emptyIterable() );
}

@Test
public void shouldFailWhenDeprecatedChangePasswordWithStaticAccessModeInDbmsMode() throws Throwable
{
Expand All @@ -76,23 +52,6 @@ public void shouldFailWhenDeprecatedChangePasswordWithStaticAccessModeInDbmsMode
.procedureCallDbms( procedureName( "dbms", "changePassword" ), inputArray, AccessMode.Static.NONE );
}

@Test
public void callChangePasswordWithAccessModeInDbmsMode() throws Throwable
{
// Given
Object[] inputArray = new Object[1];
inputArray[0] = "newPassword";
AuthSubject authSubject = mock( AuthSubject.class );

// When
RawIterator<Object[],ProcedureException> stream = dbmsOperations().procedureCallDbms(
procedureName( "dbms", "security", "changePassword" ), inputArray, authSubject );

// Then
verify( authSubject ).setPassword( (String) inputArray[0], false );
assertThat( asList( stream ), emptyIterable() );
}

@Test
public void shouldFailWhenChangePasswordWithStaticAccessModeInDbmsMode() throws Throwable
{
Expand Down
Expand Up @@ -35,8 +35,10 @@
import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge;
import org.neo4j.kernel.internal.GraphDatabaseAPI;
import org.neo4j.procedure.Context;
import org.neo4j.server.security.auth.User;
import org.neo4j.server.security.enterprise.log.SecurityLog;

import static java.util.Collections.emptyList;
import static org.neo4j.graphdb.security.AuthorizationViolationException.PERMISSION_DENIED;
import static org.neo4j.kernel.impl.api.security.OverriddenAccessMode.getUsernameFromAccessMode;

Expand All @@ -51,8 +53,26 @@ public class AuthProceduresBase
@Context
public SecurityLog securityLog;

@Context
public EnterpriseUserManager userManager;

// ----------------- helpers ---------------------

protected void kickoutUser( String username, String reason )
{
try
{
terminateTransactionsForValidUser( username );
terminateConnectionsForValidUser( username );
}
catch ( Exception e )
{
securityLog.error( authSubject, "failed to terminate running transaction and bolt connections for " +
"user `%s` following %s: %s", username, reason, e.getMessage() );
throw e;
}
}

protected void terminateTransactionsForValidUser( String username )
{
KernelTransaction currentTx = getCurrentTx();
Expand Down Expand Up @@ -119,6 +139,14 @@ public static class StringResult
}
}

protected UserResult userResultForName( String username )
{
User user = userManager.silentlyGetUser( username );
Iterable<String> flags = user == null ? emptyList() : user.getFlags();
Set<String> roles = userManager.silentlyGetRoleNamesForUser( username );
return new UserResult( username, roles, flags );
}

public static class UserResult
{
public final String username;
Expand All @@ -135,6 +163,11 @@ public static class UserResult
}
}

protected RoleResult roleResultForName( String roleName )
{
return new RoleResult( roleName, userManager.silentlyGetUsernamesForRole( roleName ) );
}

public static class RoleResult
{
public final String role;
Expand Down
Expand Up @@ -37,6 +37,8 @@ public interface EnterpriseUserManager extends UserManager

RoleRecord getRole( String roleName ) throws InvalidArgumentsException;

RoleRecord silentlyGetRole( String roleName );

/**
* Assign a role to a user. The role and the user have to exist.
*
Expand All @@ -61,5 +63,9 @@ public interface EnterpriseUserManager extends UserManager

Set<String> getRoleNamesForUser( String username ) throws InvalidArgumentsException;

Set<String> silentlyGetRoleNamesForUser( String username );

Set<String> getUsernamesForRole( String roleName ) throws InvalidArgumentsException;

Set<String> silentlyGetUsernamesForRole( String roleName );
}
Expand Up @@ -61,6 +61,7 @@
import org.neo4j.server.security.enterprise.configuration.SecuritySettings;

import static java.lang.String.format;
import static java.util.Collections.emptySet;

/**
* Shiro realm wrapping FileUserRepository and FileRoleRepository
Expand All @@ -71,7 +72,7 @@ public class InternalFlatFileRealm extends AuthorizingRealm implements RealmLife
* This flag is used in the same way as User.PASSWORD_CHANGE_REQUIRED, but it's
* placed here because of user suspension not being a part of community edition
*/
private int MAX_READ_ATTEMPTS = 10;
private static int MAX_READ_ATTEMPTS = 10;

static final String IS_SUSPENDED = "is_suspended";

Expand Down Expand Up @@ -467,6 +468,12 @@ public RoleRecord getRole( String roleName ) throws InvalidArgumentsException
return role;
}

@Override
public RoleRecord silentlyGetRole( String roleName )
{
return roleRepository.getRoleByName( roleName );
}

@Override
public void addRoleToUser( String roleName, String username ) throws IOException, InvalidArgumentsException
{
Expand Down Expand Up @@ -650,13 +657,26 @@ public Set<String> getRoleNamesForUser( String username ) throws InvalidArgument
return roleRepository.getRoleNamesByUsername( username );
}

@Override
public Set<String> silentlyGetRoleNamesForUser( String username )
{
return roleRepository.getRoleNamesByUsername( username );
}

@Override
public Set<String> getUsernamesForRole( String roleName ) throws InvalidArgumentsException
{
RoleRecord role = getRole( roleName );
return role.users();
}

@Override
public Set<String> silentlyGetUsernamesForRole( String roleName )
{
RoleRecord role = silentlyGetRole( roleName );
return role == null ? emptySet() : role.users();
}

@Override
public Set<String> getAllUsernames()
{
Expand Down

0 comments on commit 5fb06a7

Please sign in to comment.