/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* Copyright 2006 - 2013 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.platform.repository2.mt;
import org.pentaho.platform.api.engine.security.userroledao.IPentahoRole;
import org.pentaho.platform.api.engine.security.userroledao.IPentahoUser;
import org.pentaho.platform.api.engine.security.userroledao.IUserRoleDao;
import org.pentaho.platform.api.mt.ITenant;
import org.pentaho.platform.api.mt.ITenantManager;
import org.pentaho.platform.api.mt.ITenantedPrincipleNameResolver;
import org.pentaho.platform.api.repository2.unified.IUnifiedRepository;
import org.pentaho.platform.api.repository2.unified.RepositoryFile;
import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl;
import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl.Builder;
import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission;
import org.pentaho.platform.api.repository2.unified.RepositoryFileSid;
import org.pentaho.platform.api.repository2.unified.RepositoryFileSid.Type;
import org.pentaho.platform.core.mt.Tenant;
import org.pentaho.platform.repository2.unified.IRepositoryFileAclDao;
import org.pentaho.platform.repository2.unified.IRepositoryFileDao;
import org.pentaho.platform.repository2.unified.ServerRepositoryPaths;
import org.pentaho.platform.repository2.unified.jcr.DefaultPathConversionHelper;
import org.pentaho.platform.repository2.unified.jcr.IPathConversionHelper;
import org.pentaho.platform.repository2.unified.jcr.JcrRepositoryFileUtils;
import org.pentaho.platform.repository2.unified.jcr.JcrTenantUtils;
import org.pentaho.platform.repository2.unified.jcr.PentahoJcrConstants;
import org.pentaho.platform.security.policy.rolebased.IRoleAuthorizationPolicyRoleBindingDao;
import org.springframework.util.Assert;
import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
public abstract class AbstractRepositoryTenantManager implements ITenantManager {
public static final String FOLDER_NAME_AUTHZ = ".authz"; //$NON-NLS-1$
public static final String FOLDER_NAME_ROLEBASED = "roleBased"; //$NON-NLS-1$
public static final String FOLDER_NAME_RUNTIMEROLES = "runtimeRoles"; //$NON-NLS-1$
protected IRepositoryFileAclDao repositoryFileAclDao;
protected IRoleAuthorizationPolicyRoleBindingDao roleBindingDao;
protected IUserRoleDao userRoleDao;
protected IRepositoryFileDao repositoryFileDao;
protected ITenantedPrincipleNameResolver tenantedRoleNameResolver;
protected ITenantedPrincipleNameResolver tenantedUserNameResolver;
protected String repositoryAdminUsername;
protected String tenantAdminRoleName;
protected String tenantAuthenticatedRoleName;
protected List<String> singleTenantAuthenticatedAuthorityRoleBindingList;
protected IPathConversionHelper pathConversionHelper = new DefaultPathConversionHelper();
protected AbstractRepositoryTenantManager( final IRepositoryFileDao contentDao, final IUserRoleDao userRoleDao,
final IRepositoryFileAclDao repositoryFileAclDao, IRoleAuthorizationPolicyRoleBindingDao roleBindingDao,
final String repositoryAdminUsername, final String tenantAuthenticatedAuthorityNamePattern,
final ITenantedPrincipleNameResolver tenantedUserNameResolver,
final ITenantedPrincipleNameResolver tenantedRoleNameResolver, final String tenantAdminRoleName,
final List<String> singleTenantAuthenticatedAuthorityRoleBindingList ) {
Assert.notNull( contentDao );
Assert.notNull( repositoryFileAclDao );
Assert.notNull( roleBindingDao );
Assert.hasText( repositoryAdminUsername );
Assert.hasText( tenantAuthenticatedAuthorityNamePattern );
this.repositoryFileDao = contentDao;
this.repositoryFileAclDao = repositoryFileAclDao;
this.userRoleDao = userRoleDao;
this.roleBindingDao = roleBindingDao;
this.repositoryAdminUsername = repositoryAdminUsername;
this.tenantAdminRoleName = tenantAdminRoleName;
this.tenantAuthenticatedRoleName = tenantAuthenticatedAuthorityNamePattern;
this.tenantedRoleNameResolver = tenantedRoleNameResolver;
this.tenantedUserNameResolver = tenantedUserNameResolver;
this.singleTenantAuthenticatedAuthorityRoleBindingList = singleTenantAuthenticatedAuthorityRoleBindingList;
}
public void deleteTenants( Session session, final List<ITenant> tenants ) throws RepositoryException {
for ( ITenant tenant : tenants ) {
deleteTenant( session, tenant );
}
}
private void deleteUserRole( Session session, ITenant parentTenant, List<ITenant> tenants )
throws RepositoryException {
for ( ITenant tenant : tenants ) {
deleteUserRole( session, tenant, getChildTenants( session, tenant ) );
}
for ( IPentahoRole role : userRoleDao.getRoles( parentTenant ) ) {
userRoleDao.deleteRole( role );
}
for ( IPentahoUser user : userRoleDao.getUsers( parentTenant ) ) {
userRoleDao.deleteUser( user );
}
}
public void deleteTenant( Session jcrSession, final ITenant tenant ) throws RepositoryException {
deleteUserRole( jcrSession, tenant, getChildTenants( jcrSession, tenant ) );
repositoryFileDao.permanentlyDeleteFile( getTenantRootFolder( jcrSession, tenant ).getId(), "tenant delete" );
}
public void enableTenant( Session session, final ITenant tenant, final boolean enable ) throws ItemNotFoundException,
RepositoryException {
Map<String, Serializable> fileMeta =
JcrRepositoryFileUtils.getFileMetadata( session, getTenantRootFolder( session, tenant ).getId() );
fileMeta.put( ITenantManager.TENANT_ENABLED, enable );
JcrRepositoryFileUtils.setFileMetadata( session, getTenantRootFolder( session, tenant ).getId(), fileMeta );
}
@Override
public RepositoryFile getTenantRootFolder( ITenant tenant ) {
RepositoryFile rootFolder = repositoryFileDao.getFileByAbsolutePath( tenant.getRootFolderAbsolutePath() );
if ( rootFolder != null ) {
Map<String, Serializable> metadata = repositoryFileDao.getFileMetadata( rootFolder.getId() );
if ( !metadata.containsKey( ITenantManager.TENANT_ROOT ) || !(Boolean)
metadata.get( ITenantManager.TENANT_ROOT ) ) {
rootFolder = null;
}
}
return rootFolder;
}
private RepositoryFile getTenantRootFolder( Session session, final ITenant tenant ) throws RepositoryException {
RepositoryFile rootFolder =
JcrRepositoryFileUtils.getFileByAbsolutePath( session, tenant.getRootFolderAbsolutePath(),
pathConversionHelper, null, false, null );
if ( rootFolder != null ) {
Map<String, Serializable> metadata = JcrRepositoryFileUtils.getFileMetadata( session, rootFolder.getId() );
if ( !metadata.containsKey( ITenantManager.TENANT_ROOT )
|| !(Boolean) metadata.get( ITenantManager.TENANT_ROOT ) ) {
rootFolder = null;
}
}
return rootFolder;
}
public void enableTenants( Session session, final List<ITenant> tenants, final boolean enable )
throws ItemNotFoundException, RepositoryException {
for ( ITenant tenant : tenants ) {
enableTenant( session, tenant, enable );
}
}
public List<ITenant> getChildTenants( Session session, final ITenant parentTenant,
final boolean includeDisabledTenants ) throws RepositoryException {
List<ITenant> children = new ArrayList<ITenant>();
List<RepositoryFile> allChildren =
JcrRepositoryFileUtils.getChildren( session, new PentahoJcrConstants( session ), pathConversionHelper, null,
getTenantRootFolder( session, parentTenant ).getId(), null );
for ( RepositoryFile repoFile : allChildren ) {
Map<String, Serializable> metadata = JcrRepositoryFileUtils.getFileMetadata( session, repoFile.getId() );
if ( metadata.containsKey( ITenantManager.TENANT_ROOT )
&& (Boolean) metadata.get( ITenantManager.TENANT_ROOT ) ) {
Tenant tenant = new Tenant( repoFile.getPath(), isTenantEnabled( session, repoFile.getId() ) );
if ( includeDisabledTenants || tenant.isEnabled() ) {
children.add( new Tenant( pathConversionHelper.relToAbs(repoFile.getPath()), isTenantEnabled(session, repoFile.getId()) ) );
}
}
}
return children;
}
public List<ITenant> getChildTenants( Session session, final ITenant parentTenant ) throws RepositoryException {
return getChildTenants( session, parentTenant, false );
}
public void updateTentant( Session jcrSession, String arg0, Map<String, Serializable> arg1 ) {
}
protected void createInitialTenantFolders( Session session, final RepositoryFile tenantRootFolder,
final RepositoryFileSid fileOwnerSid, final RepositoryFileSid authenticatedRoleSid ) throws RepositoryException {
// We create a tenant's home folder while creating a user
repositoryFileDao.createFolder( tenantRootFolder.getId(), new RepositoryFile.Builder( ServerRepositoryPaths
.getTenantPublicFolderName() ).folder( true ).build(), new RepositoryFileAcl.Builder( fileOwnerSid ).build(),
null );
repositoryFileDao
.createFolder( tenantRootFolder.getId(), new RepositoryFile.Builder( ServerRepositoryPaths
.getTenantEtcFolderName() ).folder( true ).build(), new RepositoryFileAcl.Builder( fileOwnerSid ).build(),
null );
}
protected void setAsSystemFolder( Serializable fileId ) {
Map<String, Serializable> fileMeta = repositoryFileDao.getFileMetadata( fileId );
fileMeta.put( IUnifiedRepository.SYSTEM_FOLDER, true );
repositoryFileDao.setFileMetadata( fileId, fileMeta );
}
private boolean isTenantEnabled( Session session, final Serializable tenantFolderId ) throws ItemNotFoundException,
RepositoryException {
Map<String, Serializable> metadata = JcrRepositoryFileUtils.getFileMetadata( session, tenantFolderId );
return metadata.containsKey( ITenantManager.TENANT_ENABLED )
&& (Boolean) metadata.get( ITenantManager.TENANT_ENABLED );
}
public boolean isSubTenant( Session jcrSession, ITenant parentTenant, ITenant descendantTenant ) {
return internalIsSubTenant( parentTenant, descendantTenant );
}
private boolean internalIsSubTenant( ITenant descendantTenant, List<ITenant> childTenants ) {
for ( ITenant tenant : childTenants ) {
if ( tenant != null ) {
if ( tenant.equals( childTenants ) ) {
return true;
}
}
}
return false;
}
private boolean internalIsSubTenant( ITenant parentTenant, ITenant descendantTenant ) {
if ( parentTenant.equals( descendantTenant ) ) {
return true;
} else {
List<ITenant> childTenants = getChildTenants( parentTenant );
if ( childTenants != null && childTenants.size() > 0 ) {
if ( internalIsSubTenant( descendantTenant, childTenants ) ) {
return true;
} else {
for ( ITenant childTenant : childTenants ) {
boolean done = internalIsSubTenant( childTenant, descendantTenant );
if ( done ) {
return done;
}
}
}
} else {
return false;
}
}
return false;
}
public ITenant getTenant( Session session, String tenantId ) throws RepositoryException {
ITenant tenant = null;
RepositoryFile tenantRootFolder =
JcrRepositoryFileUtils.getFileByAbsolutePath( session, tenantId, pathConversionHelper, null, false, null );
if ( ( tenantRootFolder != null ) && isTenantRoot( session, tenantRootFolder.getId() ) ) {
tenant = new Tenant( tenantId, isTenantEnabled( session, tenantRootFolder.getId() ) );
}
return tenant;
}
private boolean isTenantRoot( Session session, final Serializable tenantFolderId ) throws ItemNotFoundException,
RepositoryException {
Map<String, Serializable> metadata = JcrRepositoryFileUtils.getFileMetadata( session, tenantFolderId );
return metadata.containsKey( ITenantManager.TENANT_ROOT ) && (Boolean) metadata.get( ITenantManager.TENANT_ROOT );
}
@Override
public RepositoryFile createUserHomeFolder( ITenant theTenant, String username ) {
Builder aclsForUserHomeFolder = null;
Builder aclsForTenantHomeFolder = null;
RepositoryFile userHomeFolder = null;
RepositoryFile tenantHomeFolder = null;
RepositoryFile tenantRootFolder = null;
String userId = tenantedUserNameResolver.getPrincipleId( theTenant, username );
final RepositoryFileSid userSid = new RepositoryFileSid( userId );
username = JcrTenantUtils.getPrincipalName( username, true );
if ( theTenant == null ) {
theTenant = JcrTenantUtils.getTenant( username, true );
}
// Get the Tenant Root folder. If the Tenant Root folder does not exist then exit.
tenantRootFolder =
repositoryFileDao.getFileByAbsolutePath( ServerRepositoryPaths.getTenantRootFolderPath( theTenant ) );
if ( tenantRootFolder != null ) {
// Try to see if Tenant Home folder exist
tenantHomeFolder =
repositoryFileDao.getFileByAbsolutePath( ServerRepositoryPaths.getTenantHomeFolderPath( theTenant ) );
if ( tenantHomeFolder == null ) {
String ownerId = tenantedUserNameResolver.getPrincipleId( theTenant, username );
RepositoryFileSid ownerSid = new RepositoryFileSid( ownerId, Type.USER );
String tenantAuthenticatedRoleId =
tenantedRoleNameResolver.getPrincipleId( theTenant, tenantAuthenticatedRoleName );
RepositoryFileSid tenantAuthenticatedRoleSid = new RepositoryFileSid( tenantAuthenticatedRoleId, Type.ROLE );
aclsForTenantHomeFolder =
new RepositoryFileAcl.Builder( userSid ).ace( tenantAuthenticatedRoleSid, EnumSet
.of( RepositoryFilePermission.READ ) );
aclsForUserHomeFolder =
new RepositoryFileAcl.Builder( userSid ).ace( ownerSid, EnumSet.of( RepositoryFilePermission.ALL ) );
tenantHomeFolder =
repositoryFileDao.createFolder( tenantRootFolder.getId(), new RepositoryFile.Builder( ServerRepositoryPaths
.getTenantHomeFolderName() ).folder( true ).build(), aclsForTenantHomeFolder.build(),
"tenant home folder" );
} else {
String ownerId = tenantedUserNameResolver.getPrincipleId( theTenant, username );
RepositoryFileSid ownerSid = new RepositoryFileSid( ownerId, Type.USER );
aclsForUserHomeFolder =
new RepositoryFileAcl.Builder( userSid ).ace( ownerSid, EnumSet.of( RepositoryFilePermission.ALL ) );
}
// now check if user's home folder exist
userHomeFolder =
repositoryFileDao.getFileByAbsolutePath( ServerRepositoryPaths.getUserHomeFolderPath( theTenant, username ) );
if ( userHomeFolder == null ) {
userHomeFolder =
repositoryFileDao.createFolder( tenantHomeFolder.getId(), new RepositoryFile.Builder( username ).folder(
true ).build(), aclsForUserHomeFolder.build(), "user home folder" ); //$NON-NLS-1$
}
}
return userHomeFolder;
}
@Override
public RepositoryFile getUserHomeFolder( ITenant theTenant, String username ) {
return repositoryFileDao.getFileByAbsolutePath( ServerRepositoryPaths
.getUserHomeFolderPath( theTenant, username ) );
}
}