package org.pentaho.platform.repository2.unified.jcr;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.pentaho.platform.api.mt.ITenant;
import org.pentaho.platform.api.repository2.unified.RepositoryFile;
import org.pentaho.platform.api.repository2.unified.RepositoryFileAce;
import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl;
import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission;
import org.pentaho.platform.api.repository2.unified.RepositoryFileSid;
import org.pentaho.platform.engine.core.system.TenantUtils;
import org.pentaho.platform.repository2.ClientRepositoryPaths;
import org.pentaho.platform.repository2.unified.DefaultUnifiedRepositoryBase;
import org.pentaho.platform.repository2.unified.ServerRepositoryPaths;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.jcr.PathNotFoundException;
import java.util.EnumSet;
import static org.junit.Assert.*;
@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration( locations = { "classpath:/repository.spring.xml",
"classpath:/repository-test-override.spring.xml" } )
public class JcrAclNodeHelperIT extends DefaultUnifiedRepositoryBase {
private JcrAclNodeHelperCallTester helper;
private ITenant defaultTenant;
private RepositoryFile targetFile;
@Before
public void setUp() throws Exception {
super.setUp();
createUsers();
ensurePublicExists();
loginAsRepositoryAdmin();
targetFile = createSampleFile( "/public", "test.txt", "test", true, 1 );
RepositoryFileAcl acl = repo.getAcl( targetFile.getId() );
RepositoryFileAcl newAcl = new RepositoryFileAcl.Builder( acl ).entriesInheriting( false )
.clearAces()
.entriesInheriting( false )
.ace( AUTHENTICATED_ROLE_NAME, RepositoryFileSid.Type.ROLE, EnumSet.of( RepositoryFilePermission.READ ) )
.build();
repo.updateAcl( newAcl );
helper = new JcrAclNodeHelperCallTester( repo ); // Subclass for ensuring no redundant calls are made.
logout();
}
private void createUsers() {
loginAsSysTenantAdmin();
defaultTenant = tenantManager.createTenant( systemTenant, TenantUtils.getDefaultTenant(), tenantAdminRoleName,
tenantAuthenticatedRoleName, ANONYMOUS_ROLE_NAME );
createUser( defaultTenant, singleTenantAdminUserName, PASSWORD, tenantAdminRoleName );
createUser( defaultTenant, USERNAME_SUZY, PASSWORD, tenantAuthenticatedRoleName );
createUser( defaultTenant, USERNAME_TIFFANY, PASSWORD, tenantAuthenticatedRoleName );
logout();
}
private void ensurePublicExists() {
ensureFolderExists( ClientRepositoryPaths.getPublicFolderPath() );
}
@After
public void tearDown() throws Exception {
loginAsSysTenantAdmin();
ITenant defaultTenant = tenantManager.getTenant( "/" + ServerRepositoryPaths.getPentahoRootFolderName() + "/"
+ TenantUtils.getDefaultTenant() );
if ( defaultTenant != null ) {
cleanupUserAndRoles( defaultTenant );
}
super.tearDown();
}
@Test
public void visibleForEveryOne() {
loginAsRepositoryAdmin();
helper.resetAclNodeCallCounter();
assertTrue( helper.canAccess( targetFile, EnumSet.of( RepositoryFilePermission.READ ) ) );
// This tests that canAccess doesn't make redundant calls to getAclNode - BISERVER-12780
assertEquals( 1, helper.getAclNodeCallCounter() );
}
@Test
public void suzycanAccess() {
makeDsPrivate();
loginAsSuzy();
assertTrue( helper.canAccess( targetFile, EnumSet.of( RepositoryFilePermission.READ ) ) );
}
@Test
public void tiffanyHasNoAccess() {
makeDsPrivate();
loginAsTiffany();
assertFalse( helper.canAccess( targetFile, EnumSet.of( RepositoryFilePermission.READ ) ) );
}
@Test
public void publish() {
makeDsPrivate();
helper.removeAclFor( targetFile );
loginAsTiffany();
assertTrue( helper.canAccess( targetFile, EnumSet.of( RepositoryFilePermission.READ ) ) );
}
@Test
public void aclIsReplaced() throws InterruptedException {
loginAsRepositoryAdmin();
RepositoryFileAcl acl = createAclFor( USERNAME_TIFFANY );
helper.setAclFor( targetFile, acl );
loginAsTiffany();
assertTrue( helper.canAccess( targetFile, EnumSet.of( RepositoryFilePermission.READ ) ) );
loginAsSuzy();
assertFalse( helper.canAccess( targetFile, EnumSet.of( RepositoryFilePermission.READ ) ) );
loginAsRepositoryAdmin();
acl = createAclFor( USERNAME_SUZY );
helper.setAclFor( targetFile, acl );
loginAsSuzy();
// This is failing most of the time in this integration test. ACL is set properly yet Suzy can still see ACL node.
// If execution is paused long enough, it does work properly.
assertTrue( helper.canAccess( targetFile, EnumSet.of( RepositoryFilePermission.READ ) ) );
}
@Test
public void aclNodeIsCreated() {
makeDsPrivate();
loginAsRepositoryAdmin();
assertTrue( "No ACL node was created", !repo.getReferrers( targetFile.getId() ).isEmpty() );
}
@Test
public void aclNodeIsRemoved() {
makeDsPrivate();
loginAsRepositoryAdmin();
helper.setAclFor( targetFile, null );
assertTrue( "Referrers should be null after ACL delete", repo.getReferrers( targetFile.getId() ).isEmpty() );
}
@Test
public void cannotDeleteTargetWithAclNode() {
makeDsPrivate();
loginAsRepositoryAdmin();
try {
repo.deleteFile( targetFile.getId(), true, "I cannot be killed" );
fail("Should have thrown Referential Integrity Exception");
} catch( Exception e ){
assertTrue( repo.getFile( targetFile.getPath() ) != null );
}
}
@Test
public void canDeleteTargetIfAclNodeRemoved() {
makeDsPrivate();
loginAsRepositoryAdmin();
helper.setAclFor( targetFile, null );
repo.deleteFile( targetFile.getId(), true, "I can be killed" );
Throwable pathNotFound = null;
try {
repo.getFile( targetFile.getPath() );
} catch ( Throwable e ) {
while ( e != null ) {
if (e instanceof PathNotFoundException) {
pathNotFound = e;
e = null;
} else {
e = e.getCause();
}
}
}
assertNotNull( pathNotFound );
}
@Test
public void administratorRoleIsAdded() {
makeDsPrivate();
loginAsSuzy();
helper.resetAclNodeCallCounter();
RepositoryFileAcl aclReturned = helper.getAclFor( targetFile );
// This tests that getAclFor doesn't make redundant calls to getAclNode - BISERVER-12780
assertEquals( 1, helper.getAclNodeCallCounter() );
boolean adminPresent = false;
for( RepositoryFileAce ace : aclReturned.getAces() ){
if( ace.getSid().getName() == tenantAdminRoleName ) {
adminPresent = true;
break;
}
}
assertFalse( adminPresent );
loginAsRepositoryAdmin();
aclReturned = helper.getAclFor( targetFile );
adminPresent = false;
for( RepositoryFileAce ace : aclReturned.getAces() ){
if( ace.getSid().getName() == tenantAdminRoleName ) {
adminPresent = true;
break;
}
}
assertTrue( adminPresent );
}
@Test
public void getAclFor_Null_ReturnsFalse() throws Exception {
loginAsRepositoryAdmin();
assertNull( helper.getAclFor( null ) );
}
@Test
public void canAccess_Null_ReturnsFalse() throws Exception {
loginAsRepositoryAdmin();
assertFalse( helper.canAccess( null, EnumSet.of( RepositoryFilePermission.READ ) ) );
}
private void makeDsPrivate() {
loginAsRepositoryAdmin();
RepositoryFileAcl acl = createAclFor( USERNAME_SUZY );
helper.setAclFor( targetFile, acl );
logout();
}
private static RepositoryFileAcl createAclFor( String user ) {
RepositoryFileSid userSid = new RepositoryFileSid( user, RepositoryFileSid.Type.USER );
return new RepositoryFileAcl.Builder( user )
.ace( userSid, EnumSet.of( RepositoryFilePermission.ALL ) )
.entriesInheriting( false )
.build();
}
private RepositoryFile ensureFolderExists( String folderName ) {
loginAsRepositoryAdmin();
try {
RepositoryFile folder = repo.getFile( folderName );
if ( folder == null ) {
folder = repo.createFolder( repo.getFile( "/" ).getId(), new RepositoryFile.Builder( folderName ).
folder( true ).build(), "" );
}
RepositoryFileAcl acl = repo.getAcl( folder.getId() );
RepositoryFileAcl newAcl = new RepositoryFileAcl.Builder( acl ).entriesInheriting( true )
.ace( AUTHENTICATED_ROLE_NAME, RepositoryFileSid.Type.ROLE, EnumSet.of( RepositoryFilePermission.ALL ) )
.build();
repo.updateAcl( newAcl );
return folder;
} finally {
logout();
}
}
private void loginAsSuzy() {
login( USERNAME_SUZY, defaultTenant, new String[] { tenantAuthenticatedRoleName } );
}
private void loginAsTiffany() {
login( USERNAME_TIFFANY, defaultTenant, new String[] { tenantAuthenticatedRoleName } );
}
}