Skip to content

Commit

Permalink
Implemented the listRolesForUser procedure
Browse files Browse the repository at this point in the history
  • Loading branch information
OliviaYtterbrink authored and henriknyman committed Jun 16, 2016
1 parent cceacb1 commit 53f1c09
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 4 deletions.
Expand Up @@ -21,6 +21,7 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -50,9 +51,10 @@ public RoleRecord findByName( String name )
}

@Override
public Set<String> findByUsername( String username )
public Set<String> findRoleNamesByUsername( String username )
{
return rolesByUsername.get( username );
Set<String> roleNames = rolesByUsername.get( username );
return roleNames != null ? roleNames : Collections.emptySet();
}

@Override
Expand Down
Expand Up @@ -137,6 +137,19 @@ public Stream<StringResult> listRoles() throws IllegalCredentialsException, IOEx
return shiroSubject.getRoleManager().getAllRoleNames().stream().map( StringResult::new );
}

@PerformsDBMS
@Procedure( "dbms.listRolesForUser" )
public Stream<StringResult> listRolesForUser( @Name( "username" ) String username )
throws IllegalCredentialsException, IOException
{
ShiroAuthSubject shiroSubject = ShiroAuthSubject.castOrFail( authSubject );
if ( !shiroSubject.isAdmin() )
{
throw new AuthorizationViolationException( PERMISSION_DENIED );
}
return shiroSubject.getRoleManager().getRoleNamesForUser( username ).stream().map( StringResult::new );
}

public class StringResult {
public final String value;

Expand Down
Expand Up @@ -125,7 +125,7 @@ protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principa
}
else
{
Set<String> roles = roleRepository.findByUsername( user.name() );
Set<String> roles = roleRepository.findRoleNamesByUsername( user.name() );
return new SimpleAuthorizationInfo( roles );
}
}
Expand Down
Expand Up @@ -45,4 +45,6 @@ public interface RoleManager
void removeUserFromRole( String username, String roleName ) throws IOException;

Set<String> getAllRoleNames();

Set<String> getRoleNamesForUser( String username );
}
Expand Up @@ -32,7 +32,7 @@ public interface RoleRepository extends Lifecycle
{
RoleRecord findByName( String name );

Set<String> findByUsername( String username );
Set<String> findRoleNamesByUsername( String username );

/**
* Create a role, given that the roles token is unique.
Expand Down
Expand Up @@ -238,6 +238,17 @@ public Set<String> getAllRoleNames()
return roleRepository.getAllRoleNames();
}

@Override
public Set<String> getRoleNamesForUser( String username )
{
assertAuthEnabled();
if (users.findByName( username ) == null)
{
throw new IllegalArgumentException( "User " + username + " does not exist." );
}
return roleRepository.findRoleNamesByUsername( username );
}

public Set<String> getAllUsernames()
{
assertAuthEnabled();
Expand Down
Expand Up @@ -757,6 +757,76 @@ public void rolesListing() throws Exception
testSuccessfulListRolesAction( subject );
}

@Test
public void shouldListRolesForUser() throws Exception
{
testResult( db, adminSubject, "CALL dbms.listRolesForUser('adminSubject') YIELD value as roles RETURN roles",
r -> {
List<Object> roles = getObjectsAsList( r, "roles" );
Assert.assertThat( roles, containsInAnyOrder( PredefinedRolesBuilder.ADMIN ) );
assertEquals( 1, roles.size() );
} );
}

@Test
public void shouldNotAllowNonAdminListUserRoles() throws Exception
{
testFailListUserRoles( noneSubject, "adminSubject" );
testFailListUserRoles( readSubject, "adminSubject" );
testFailListUserRoles( writeSubject, "adminSubject" );
testFailListUserRoles( schemaSubject, "adminSubject" );
}

@Test
public void shouldFailToListRolesForUnknownUser() throws Exception
{
try
{
testResult( db, adminSubject, "CALL dbms.listRolesForUser('Henrik') YIELD value as roles RETURN roles",
r -> assertFalse( r.hasNext() ) );
fail( "Expected exception to be thrown" );
}
catch ( QueryExecutionException e )
{
assertTrue( "Exception should contain 'User Henrik does not exist.' but was " + e.getMessage(),
e.getMessage().contains( "User Henrik does not exist." ) );
}
}

@Test
public void shouldListNoRolesForUserWithNoRoles() throws Exception
{
testCallEmpty( db, adminSubject, "CALL dbms.createUser('Henrik', 'bar', false)", null );
testResult( db, adminSubject, "CALL dbms.listRolesForUser('Henrik') YIELD value as roles RETURN roles",
r -> assertFalse( r.hasNext() ) );
}

/*
Admin creates user Henrik with password bar
Admin creates user Craig with password foo
Admin adds user Craig to role Publisher
Henrik logs in with correct password → ok
Henrik lists all roles for user Craig → permission denied
Admin lists all roles for user Craig → ok
*/
@Test
public void listingUserRoles() throws Exception
{
testCallEmpty( db, adminSubject, "CALL dbms.createUser('Henrik', 'bar', false)", null );
testCallEmpty( db, adminSubject, "CALL dbms.createUser('Craig', 'foo', false)", null );
testCallEmpty( db, adminSubject, "CALL dbms.addUserToRole('Craig', '" + PredefinedRolesBuilder.PUBLISHER + "')",
null );
AuthSubject subject = manager.login( authToken( "Henrik", "bar" ) );
assertEquals( AuthenticationResult.SUCCESS, subject.getAuthenticationResult() );
testFailListUserRoles( subject, "Craig" );
testResult( db, adminSubject, "CALL dbms.listRolesForUser('Craig') YIELD value as roles RETURN roles",
r -> {
List<Object> roles = getObjectsAsList( r, "roles" );
Assert.assertThat( roles, containsInAnyOrder( PredefinedRolesBuilder.PUBLISHER ) );
assertEquals( 1, roles.size() );
} );
}

//-------------Helper functions---------------

private void testSuccessfulReadAction( AuthSubject subject, Long count )
Expand Down Expand Up @@ -915,6 +985,25 @@ private void testFailListRoles( AuthSubject subject )
}
}

private void testSuccessfulListUserRolesAction( AuthSubject subject, String username )
{
testCall( db, subject,
"CALL dbms.listRolesForUser('" + username + "') YIELD value AS roles RETURN count(roles)", Map::clear );
}

private void testFailListUserRoles( AuthSubject subject, String username )
{
try
{
testSuccessfulListUserRolesAction( subject, username );
}
catch ( QueryExecutionException e )
{
assertTrue( "Exception should contain '" + AuthProcedures.PERMISSION_DENIED + "'",
e.getMessage().contains( AuthProcedures.PERMISSION_DENIED ) );
}
}

private List<Object> getObjectsAsList( Result r, String key )
{
return r.stream().map( s -> s.get( key ) ).collect( Collectors.toList() );
Expand Down

0 comments on commit 53f1c09

Please sign in to comment.