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


User getUser( String username ); User getUser( String username );


User assertAndGetUser( String username ) throws IllegalArgumentException;

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


import org.neo4j.graphdb.DependencyResolver;
import org.neo4j.graphdb.security.AuthorizationViolationException; 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.AuthSubject;
import org.neo4j.kernel.api.security.exception.IllegalCredentialsException; 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.Context;
import org.neo4j.procedure.Name; import org.neo4j.procedure.Name;
import org.neo4j.procedure.Procedure; import org.neo4j.procedure.Procedure;
Expand All @@ -41,6 +45,9 @@ public class AuthProcedures
@Context @Context
public AuthSubject authSubject; public AuthSubject authSubject;


@Context
public GraphDatabaseAPI graph;

@Procedure( name = "dbms.createUser", mode = DBMS ) @Procedure( name = "dbms.createUser", mode = DBMS )
public void createUser( @Name( "username" ) String username, @Name( "password" ) String password, public void createUser( @Name( "username" ) String username, @Name( "password" ) String password,
@Name( "requirePasswordChange" ) boolean requirePasswordChange ) @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 ); 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() private EnterpriseAuthSubject ensureAdminAuthSubject()
{ {
EnterpriseAuthSubject enterpriseAuthSubject = EnterpriseAuthSubject.castOrFail( authSubject ); EnterpriseAuthSubject enterpriseAuthSubject = EnterpriseAuthSubject.castOrFail( authSubject );
Expand Down Expand Up @@ -214,4 +259,24 @@ public RoleResult( String role, Set<String> users )
this.users.addAll( 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 newRole( String roleName, String... usernames ) throws IOException;


RoleRecord assertAndGetRole( String roleName ) throws IllegalArgumentException;

/** /**
* Add a user to a role. The role has to exist. * 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; 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 @Override
public void addUserToRole( String username, String roleName ) throws IOException public void addUserToRole( String username, String roleName ) throws IOException
{ {
checkValidityOfUsernameAndRoleName( username, roleName ); checkValidityOfUsernameAndRoleName( username, roleName );


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


synchronized ( this ) synchronized ( this )
{ {
User user = userRepository.getUserByName( username ); assertAndGetUser( username );
if ( user == null ) RoleRecord role = assertAndGetRole( roleName );
{
throw new IllegalArgumentException( "User " + username + " does not exist." ); RoleRecord newRole = role.augment().withoutUser( username ).build();
} try
RoleRecord role = roleRepository.getRoleByName( roleName );
if ( role == null )
{ {
throw new IllegalArgumentException( "Role " + roleName + " does not exist." ); roleRepository.update( role, newRole );
} }
else catch ( ConcurrentModificationException e )
{ {
RoleRecord newRole = role.augment().withoutUser( username ).build(); // Try again
try removeUserFromRole( username, roleName );
{
roleRepository.update( role, newRole );
}
catch ( ConcurrentModificationException e )
{
// Try again
removeUserFromRole( username, roleName );
}
} }
} }
clearCachedAuthorizationInfoForUser( username ); clearCachedAuthorizationInfoForUser( username );
Expand All @@ -407,15 +397,16 @@ public boolean deleteUser( String username ) throws IOException
boolean result = false; boolean result = false;
synchronized ( this ) synchronized ( this )
{ {
User user = userRepository.getUserByName( username ); User user = assertAndGetUser( username );
if ( user != null && userRepository.delete( user ) ) if ( userRepository.delete( user ) )
{ {
removeUserFromAllRoles( username ); removeUserFromAllRoles( username );
result = true; result = true;
} }
else 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 ); clearCacheForUser( username );
Expand All @@ -428,14 +419,19 @@ public User getUser( String username )
return userRepository.getUserByName( 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 @Override
public void setUserPassword( String username, String password ) throws IOException, IllegalCredentialsException public void setUserPassword( String username, String password ) throws IOException, IllegalCredentialsException
{ {
User existingUser = userRepository.getUserByName( username ); User existingUser = assertAndGetUser( username );
if ( existingUser == null )
{
throw new IllegalCredentialsException( "User " + username + " does not exist" );
}


passwordPolicy.validatePassword( password ); 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 // 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 // If user is modified between getUserByName and update, we get ConcurrentModificationException and try again
User user = userRepository.getUserByName( username ); User user = assertAndGetUser( username );
if ( user == null )
{
throw new IllegalArgumentException( "User " + username + " does not exist." );
}
if ( !user.hasFlag( IS_SUSPENDED ) ) if ( !user.hasFlag( IS_SUSPENDED ) )
{ {
User suspendedUser = user.augment().withFlag( IS_SUSPENDED ).build(); 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 // 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 // If user is modified between getUserByName and update, we get ConcurrentModificationException and try again
User user = userRepository.getUserByName( username ); User user = assertAndGetUser( username );
if ( user == null )
{
throw new IllegalArgumentException( "User " + username + " does not exist." );
}
if ( user.hasFlag( IS_SUSPENDED ) ) if ( user.hasFlag( IS_SUSPENDED ) )
{ {
User activatedUser = user.augment().withoutFlag( IS_SUSPENDED ).build(); User activatedUser = user.augment().withoutFlag( IS_SUSPENDED ).build();
Expand Down Expand Up @@ -529,11 +517,7 @@ public Set<String> getRoleNamesForUser( String username )
@Override @Override
public Set<String> getUsernamesForRole( String roleName ) public Set<String> getUsernamesForRole( String roleName )
{ {
RoleRecord role = roleRepository.getRoleByName( roleName ); RoleRecord role = assertAndGetRole( roleName );
if ( role == null )
{
throw new IllegalArgumentException( "Role " + roleName + " does not exist." );
}
return role.users(); return role.users();
} }


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


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

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

0 comments on commit 9030b06

Please sign in to comment.