Skip to content

Commit

Permalink
Added procedures to list transactions and terminate transactions for …
Browse files Browse the repository at this point in the history
…user.
  • Loading branch information
fickludd committed Jul 4, 2016
1 parent f50e5ba commit 9030b06
Show file tree
Hide file tree
Showing 12 changed files with 412 additions and 94 deletions.
Expand Up @@ -146,6 +146,15 @@ public User getUser( String username )
return users.getUserByName( username );
}

@Override
public User assertAndGetUser( String username ) throws IllegalArgumentException
{
User user = getUser( username );
if ( user == null )
throw new IllegalArgumentException( "User " + username + " does not exist!" );
return user;
}

public void setPassword( AuthSubject authSubject, String username, String password ) throws IOException,
IllegalCredentialsException
{
Expand Down
Expand Up @@ -32,5 +32,7 @@ User newUser( String username, String initialPassword, boolean requirePasswordCh

User getUser( String username );

User assertAndGetUser( String username ) throws IllegalArgumentException;

void setUserPassword( String username, String password ) throws IOException, IllegalCredentialsException;
}
Expand Up @@ -25,9 +25,13 @@
import java.util.Set;
import java.util.stream.Stream;

import org.neo4j.graphdb.DependencyResolver;
import org.neo4j.graphdb.security.AuthorizationViolationException;
import org.neo4j.kernel.api.KernelTransaction;
import org.neo4j.kernel.api.security.AuthSubject;
import org.neo4j.kernel.api.security.exception.IllegalCredentialsException;
import org.neo4j.kernel.impl.api.KernelTransactions;
import org.neo4j.kernel.internal.GraphDatabaseAPI;
import org.neo4j.procedure.Context;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.Procedure;
Expand All @@ -41,6 +45,9 @@ public class AuthProcedures
@Context
public AuthSubject authSubject;

@Context
public GraphDatabaseAPI graph;

@Procedure( name = "dbms.createUser", mode = DBMS )
public void createUser( @Name( "username" ) String username, @Name( "password" ) String password,
@Name( "requirePasswordChange" ) boolean requirePasswordChange )
Expand Down Expand Up @@ -169,6 +176,44 @@ public Stream<StringResult> listUsersForRole( @Name( "roleName" ) String roleNam
return adminSubject.getUserManager().getUsernamesForRole( roleName ).stream().map( StringResult::new );
}

@Procedure( name = "dbms.listTransactions", mode = DBMS )
public Stream<TransactionResult> listTransactions()
throws IllegalCredentialsException, IOException
{
ensureAdminAuthSubject();

DependencyResolver resolver = graph.getDependencyResolver();
KernelTransactions kernelTransactions = resolver.resolveDependency( KernelTransactions.class );
return kernelTransactions.activeTransactions().stream()
.filter( tx -> !tx.shouldBeTerminated() )
.map( tx -> new TransactionResult( tx ) );
}

@Procedure( name = "dbms.terminateTransactionsForUser", mode = DBMS )
public Stream<TransactionResult> terminateTransactionsForUser( @Name( "username" ) String username )
throws IllegalCredentialsException, IOException
{
EnterpriseAuthSubject adminSubject = ensureAdminAuthSubject();

adminSubject.getUserManager().assertAndGetUser( username );

DependencyResolver resolver = graph.getDependencyResolver();
KernelTransactions kernelTransactions = resolver.resolveDependency( KernelTransactions.class );
ArrayList<TransactionResult> killedTransactions = new ArrayList<>();
for ( KernelTransaction tx : kernelTransactions.activeTransactions() )
{
if (( (EnterpriseAuthSubject) tx.mode()).doesUsernameMatch( username ))
{
TransactionResult r = new TransactionResult( tx );
tx.markForTermination();
killedTransactions.add( r );
}
}
return killedTransactions.stream();
}

// --------------------------------------

private EnterpriseAuthSubject ensureAdminAuthSubject()
{
EnterpriseAuthSubject enterpriseAuthSubject = EnterpriseAuthSubject.castOrFail( authSubject );
Expand Down Expand Up @@ -214,4 +259,24 @@ public RoleResult( String role, Set<String> users )
this.users.addAll( users );
}
}

public class TransactionResult
{
public final String username;
public final String transaction;

public TransactionResult( KernelTransaction tx )
{
if ( tx.mode() instanceof AuthSubject )
{
AuthSubject authSubject = (AuthSubject) tx.mode();
username = authSubject.name();
}
else
{
username = "-";
}
transaction = tx.toString();
}
}
}
Expand Up @@ -39,6 +39,8 @@ void setPassword( AuthSubject authSubject, String username, String password ) th

RoleRecord newRole( String roleName, String... usernames ) throws IOException;

RoleRecord assertAndGetRole( String roleName ) throws IllegalArgumentException;

/**
* Add a user to a role. The role has to exist.
*
Expand Down
Expand Up @@ -333,35 +333,35 @@ public RoleRecord newRole( String roleName, String... usernames ) throws IOExcep
return role;
}

@Override
public RoleRecord assertAndGetRole( String roleName ) throws IllegalArgumentException
{
RoleRecord role = roleRepository.getRoleByName( roleName );
if ( role == null )
{
throw new IllegalArgumentException( "Role " + roleName + " does not exist." );
}
return role;
}

@Override
public void addUserToRole( String username, String roleName ) throws IOException
{
checkValidityOfUsernameAndRoleName( username, roleName );

synchronized ( this )
{
User user = userRepository.getUserByName( username );
if ( user == null )
{
throw new IllegalArgumentException( "User " + username + " does not exist." );
}
RoleRecord role = roleRepository.getRoleByName( roleName );
if ( role == null )
assertAndGetUser( username );
RoleRecord role = assertAndGetRole( roleName );
RoleRecord newRole = role.augment().withUser( username ).build();
try
{
throw new IllegalArgumentException( "Role " + roleName + " does not exist." );
roleRepository.update( role, newRole );
}
else
catch ( ConcurrentModificationException e )
{
RoleRecord newRole = role.augment().withUser( username ).build();
try
{
roleRepository.update( role, newRole );
}
catch ( ConcurrentModificationException e )
{
// Try again
addUserToRole( username, roleName );
}
// Try again
addUserToRole( username, roleName );
}
}
clearCachedAuthorizationInfoForUser( username );
Expand All @@ -374,28 +374,18 @@ public void removeUserFromRole( String username, String roleName ) throws IOExce

synchronized ( this )
{
User user = userRepository.getUserByName( username );
if ( user == null )
{
throw new IllegalArgumentException( "User " + username + " does not exist." );
}
RoleRecord role = roleRepository.getRoleByName( roleName );
if ( role == null )
assertAndGetUser( username );
RoleRecord role = assertAndGetRole( roleName );

RoleRecord newRole = role.augment().withoutUser( username ).build();
try
{
throw new IllegalArgumentException( "Role " + roleName + " does not exist." );
roleRepository.update( role, newRole );
}
else
catch ( ConcurrentModificationException e )
{
RoleRecord newRole = role.augment().withoutUser( username ).build();
try
{
roleRepository.update( role, newRole );
}
catch ( ConcurrentModificationException e )
{
// Try again
removeUserFromRole( username, roleName );
}
// Try again
removeUserFromRole( username, roleName );
}
}
clearCachedAuthorizationInfoForUser( username );
Expand All @@ -407,15 +397,16 @@ public boolean deleteUser( String username ) throws IOException
boolean result = false;
synchronized ( this )
{
User user = userRepository.getUserByName( username );
if ( user != null && userRepository.delete( user ) )
User user = assertAndGetUser( username );
if ( userRepository.delete( user ) )
{
removeUserFromAllRoles( username );
result = true;
}
else
{
throw new IllegalArgumentException( "The user '" + username + "' does not exist" );
// We should not get here, but if we do the assert will fail and give a nice error msg
assertAndGetUser( username );
}
}
clearCacheForUser( username );
Expand All @@ -428,14 +419,19 @@ public User getUser( String username )
return userRepository.getUserByName( username );
}

@Override
public User assertAndGetUser( String username ) throws IllegalArgumentException
{
User u = getUser( username );
if ( u == null )
throw new IllegalArgumentException( "User " + username + " does not exist." );
return u;
}

@Override
public void setUserPassword( String username, String password ) throws IOException, IllegalCredentialsException
{
User existingUser = userRepository.getUserByName( username );
if ( existingUser == null )
{
throw new IllegalCredentialsException( "User " + username + " does not exist" );
}
User existingUser = assertAndGetUser( username );

passwordPolicy.validatePassword( password );

Expand Down Expand Up @@ -463,11 +459,7 @@ public void suspendUser( String username ) throws IOException
{
// This method is not synchronized as it only modifies the UserRepository, which is synchronized in itself
// If user is modified between getUserByName and update, we get ConcurrentModificationException and try again
User user = userRepository.getUserByName( username );
if ( user == null )
{
throw new IllegalArgumentException( "User " + username + " does not exist." );
}
User user = assertAndGetUser( username );
if ( !user.hasFlag( IS_SUSPENDED ) )
{
User suspendedUser = user.augment().withFlag( IS_SUSPENDED ).build();
Expand All @@ -489,11 +481,7 @@ public void activateUser( String username ) throws IOException
{
// This method is not synchronized as it only modifies the UserRepository, which is synchronized in itself
// If user is modified between getUserByName and update, we get ConcurrentModificationException and try again
User user = userRepository.getUserByName( username );
if ( user == null )
{
throw new IllegalArgumentException( "User " + username + " does not exist." );
}
User user = assertAndGetUser( username );
if ( user.hasFlag( IS_SUSPENDED ) )
{
User activatedUser = user.augment().withoutFlag( IS_SUSPENDED ).build();
Expand Down Expand Up @@ -529,11 +517,7 @@ public Set<String> getRoleNamesForUser( String username )
@Override
public Set<String> getUsernamesForRole( String roleName )
{
RoleRecord role = roleRepository.getRoleByName( roleName );
if ( role == null )
{
throw new IllegalArgumentException( "Role " + roleName + " does not exist." );
}
RoleRecord role = assertAndGetRole( roleName );
return role.users();
}

Expand All @@ -543,11 +527,6 @@ public Set<String> getAllUsernames()
return userRepository.getAllUsernames();
}

User findUser( String username )
{
return userRepository.getUserByName( username );
}

private void removeUserFromAllRoles( String username ) throws IOException
{
try
Expand Down

0 comments on commit 9030b06

Please sign in to comment.