Package org.pentaho.platform.security.userroledao.jackrabbit

Source Code of org.pentaho.platform.security.userroledao.jackrabbit.AbstractJcrBackedUserRoleDao

/*
* 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.security.userroledao.jackrabbit;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import javax.jcr.Credentials;
import javax.jcr.NamespaceException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;

import org.apache.commons.collections.map.LRUMap;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.security.authentication.CryptedSimpleCredentials;
import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
import org.apache.jackrabbit.core.security.user.UserManagerImpl;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.NameFactory;
import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
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.engine.security.userroledao.NotFoundException;
import org.pentaho.platform.api.mt.ITenant;
import org.pentaho.platform.api.mt.ITenantedPrincipleNameResolver;
import org.pentaho.platform.api.repository2.unified.IRepositoryDefaultAclHandler;
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.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.core.system.TenantUtils;
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.ILockHelper;
import org.pentaho.platform.repository2.unified.jcr.IPathConversionHelper;
import org.pentaho.platform.repository2.unified.jcr.JcrRepositoryFileAclUtils;
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.userroledao.PentahoRole;
import org.pentaho.platform.security.userroledao.PentahoUser;
import org.pentaho.platform.security.userroledao.messages.Messages;
import org.springframework.security.providers.dao.UserCache;
import org.springframework.security.providers.dao.cache.NullUserCache;

public abstract class AbstractJcrBackedUserRoleDao implements IUserRoleDao {

  NameFactory NF = NameFactoryImpl.getInstance();

  Name P_PRINCIPAL_NAME = NF.create( Name.NS_REP_URI, "principalName" ); //$NON-NLS-1$

  protected ITenantedPrincipleNameResolver tenantedUserNameUtils;

  protected ITenantedPrincipleNameResolver tenantedRoleNameUtils;

  String pPrincipalName = "rep:principalName"; //$NON-NLS-1$

  IRepositoryFileAclDao repositoryFileAclDao;

  IRepositoryFileDao repositoryFileDao;

  String defaultTenant;

  String authenticatedRoleName;

  String tenantAdminRoleName;

  String repositoryAdminUsername;

  IPathConversionHelper pathConversionHelper;

  IRepositoryDefaultAclHandler defaultAclHandler;

  ILockHelper lockHelper;

  List<String> systemRoles;

  List<String> extraRoles;

  HashMap<String, UserManagerImpl> userMgrMap = new HashMap<String, UserManagerImpl>();

  private LRUMap userCache = new LRUMap( 4096 );

  private UserCache userDetailsCache = new NullUserCache();

  public AbstractJcrBackedUserRoleDao( ITenantedPrincipleNameResolver userNameUtils,
      ITenantedPrincipleNameResolver roleNameUtils, String authenticatedRoleName, String tenantAdminRoleName,
      String repositoryAdminUsername, IRepositoryFileAclDao repositoryFileAclDao, IRepositoryFileDao repositoryFileDao,
      final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper,
      final IRepositoryDefaultAclHandler defaultAclHandler, final List<String> systemRoles,
      final List<String> extraRoles, UserCache userDetailsCache ) throws NamespaceException {
    this.tenantedUserNameUtils = userNameUtils;
    this.tenantedRoleNameUtils = roleNameUtils;
    this.authenticatedRoleName = authenticatedRoleName;
    this.tenantAdminRoleName = tenantAdminRoleName;
    this.repositoryAdminUsername = repositoryAdminUsername;
    this.repositoryFileAclDao = repositoryFileAclDao;
    this.repositoryFileDao = repositoryFileDao;
    this.pathConversionHelper = pathConversionHelper;
    this.lockHelper = lockHelper;
    this.defaultAclHandler = defaultAclHandler;
    this.systemRoles = systemRoles;
    this.extraRoles = extraRoles;
    this.userDetailsCache = userDetailsCache;
  }

  public void setRoleMembers( Session session, final ITenant theTenant, final String roleName,
      final String[] memberUserNames ) throws RepositoryException, NotFoundException {
    List<IPentahoUser> currentRoleMembers = getRoleMembers( session, theTenant, roleName );
    String[] usersToBeRemoved = findRemovedUsers( currentRoleMembers, memberUserNames );

    // If we are unassigning a user or users from the Administrator role, we need to check if this is a logged in user
    // or a user designated as a system user. If it is then we
    // will display a message to the user.
    if ( ( oneOfUserIsMySelf( usersToBeRemoved ) || oneOfUserIsDefaultAdminUser( usersToBeRemoved ) )
        && tenantAdminRoleName.equals( roleName ) ) {
      throw new RepositoryException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0009_USER_REMOVE_FAILED_YOURSELF_OR_DEFAULT_ADMIN_USER" ) );
    }

    // If this is the last user from the Administrator role, we will not let the user remove.
    if ( tenantAdminRoleName.equals( roleName ) && ( currentRoleMembers != null && currentRoleMembers.size() > 0 )
        && memberUserNames.length == 0 ) {
      throw new RepositoryException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0001_LAST_ADMIN_ROLE", tenantAdminRoleName ) );
    }
    Group jackrabbitGroup = getJackrabbitGroup( theTenant, roleName, session );

    if ( ( jackrabbitGroup == null )
        || !TenantUtils.isAccessibleTenant( theTenant == null ? tenantedRoleNameUtils.getTenant( jackrabbitGroup
            .getID() ) : theTenant ) ) {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0002_ROLE_NOT_FOUND" ) );
    }
    HashMap<String, User> currentlyAssignedUsers = new HashMap<String, User>();
    Iterator<Authorizable> currentMembers = jackrabbitGroup.getMembers();
    while ( currentMembers.hasNext() ) {
      Authorizable member = currentMembers.next();
      if ( member instanceof User ) {
        currentlyAssignedUsers.put( member.getID(), (User) member );
      }
    }

    HashMap<String, User> finalCollectionOfAssignedUsers = new HashMap<String, User>();
    if ( memberUserNames != null ) {
      ITenant tenant = theTenant == null ? JcrTenantUtils.getTenant( roleName, false ) : theTenant;
      for ( String user : memberUserNames ) {
        User jackrabbitUser = getJackrabbitUser( tenant, user, session );
        if ( jackrabbitUser != null ) {
          finalCollectionOfAssignedUsers.put(
            getTenantedUserNameUtils().getPrincipleId( tenant, user ), jackrabbitUser );
        }
      }
    }

    ArrayList<String> usersToRemove = new ArrayList<String>( currentlyAssignedUsers.keySet() );
    usersToRemove.removeAll( finalCollectionOfAssignedUsers.keySet() );

    ArrayList<String> usersToAdd = new ArrayList<String>( finalCollectionOfAssignedUsers.keySet() );
    usersToAdd.removeAll( currentlyAssignedUsers.keySet() );

    for ( String userId : usersToRemove ) {
      jackrabbitGroup.removeMember( currentlyAssignedUsers.get( userId ) );
      purgeUserFromCache( userId );
    }

    for ( String userId : usersToAdd ) {
      jackrabbitGroup.addMember( finalCollectionOfAssignedUsers.get( userId ) );

      // Purge the UserDetails cache
      purgeUserFromCache( userId );
    }
  }

  private void setUserRolesForNewUser( Session session, final ITenant theTenant, final String userName,
      final String[] roles ) throws RepositoryException, NotFoundException {
    Set<String> roleSet = new HashSet<String>();
    if ( roles != null ) {
      roleSet.addAll( Arrays.asList( roles ) );
    }
    roleSet.add( authenticatedRoleName );

    User jackrabbitUser = getJackrabbitUser( theTenant, userName, session );

    if ( ( jackrabbitUser == null )
        || !TenantUtils.isAccessibleTenant( theTenant == null ? tenantedUserNameUtils
            .getTenant( jackrabbitUser.getID() ) : theTenant ) ) {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND" ) );
    }

    HashMap<String, Group> finalCollectionOfAssignedGroups = new HashMap<String, Group>();
    ITenant tenant = theTenant == null ? JcrTenantUtils.getTenant( userName, true ) : theTenant;
    for ( String role : roleSet ) {
      Group jackrabbitGroup = getJackrabbitGroup( tenant, role, session );
      if ( jackrabbitGroup != null ) {
        finalCollectionOfAssignedGroups.put( tenantedRoleNameUtils.getPrincipleId( tenant, role ), jackrabbitGroup );
      }
    }

    ArrayList<String> groupsToAdd = new ArrayList<String>( finalCollectionOfAssignedGroups.keySet() );

    for ( String groupId : groupsToAdd ) {
      finalCollectionOfAssignedGroups.get( groupId ).addMember( jackrabbitUser );
      // Purge the UserDetails cache
      purgeUserFromCache( userName );
    }
  }

  private void purgeUserFromCache( String userName ) {
    userDetailsCache.removeUserFromCache( getTenantedUserNameUtils().getPrincipleName( userName ) );
  }

  private boolean oneOfUserIsMySelf( String[] users ) {
    for ( int i = 0; i < users.length; i++ ) {
      if ( isMyself( users[i] ) ) {
        return true;
      }
    }
    return false;
  }

  private boolean oneOfUserIsDefaultAdminUser( String[] users ) {
    for ( int i = 0; i < users.length; i++ ) {
      if ( isDefaultAdminUser( users[i] ) ) {
        return true;
      }
    }
    return false;
  }

  private boolean isMyself( String userName ) {
    return PentahoSessionHolder.getSession().getName().equals( userName );
  }

  private boolean isDefaultAdminUser( String userName ) {
    String defaultAdminUser =
        PentahoSystem.get( String.class, "singleTenantAdminUserName", PentahoSessionHolder.getSession() );
    if ( defaultAdminUser != null ) {
      return defaultAdminUser.equals( userName );
    }
    return false;
  }

  private boolean adminRoleExist( String[] newRoles ) {
    return Arrays.asList( newRoles ).contains( tenantAdminRoleName );
  }

  public void setUserRoles( Session session, final ITenant theTenant, final String userName, final String[] roles )
    throws RepositoryException, NotFoundException {

    if ( ( isMyself( userName ) || isDefaultAdminUser( userName ) ) && !adminRoleExist( roles ) ) {
      throw new RepositoryException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0005_YOURSELF_OR_DEFAULT_ADMIN_USER" ) );
    }

    Set<String> roleSet = new HashSet<String>();
    if ( roles != null ) {
      roleSet.addAll( Arrays.asList( roles ) );
    }
    roleSet.add( authenticatedRoleName );

    User jackrabbitUser = getJackrabbitUser( theTenant, userName, session );

    if ( ( jackrabbitUser == null )
        || !TenantUtils.isAccessibleTenant( theTenant == null ? tenantedUserNameUtils
            .getTenant( jackrabbitUser.getID() ) : theTenant ) ) {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND" ) );
    }
    HashMap<String, Group> currentlyAssignedGroups = new HashMap<String, Group>();
    Iterator<Group> currentGroups = jackrabbitUser.memberOf();
    while ( currentGroups.hasNext() ) {
      Group currentGroup = currentGroups.next();
      currentlyAssignedGroups.put( currentGroup.getID(), currentGroup );
    }

    HashMap<String, Group> finalCollectionOfAssignedGroups = new HashMap<String, Group>();
    ITenant tenant = theTenant == null ? JcrTenantUtils.getTenant( userName, true ) : theTenant;
    for ( String role : roleSet ) {
      Group jackrabbitGroup = getJackrabbitGroup( tenant, role, session );
      if ( jackrabbitGroup != null ) {
        finalCollectionOfAssignedGroups.put( tenantedRoleNameUtils.getPrincipleId( tenant, role ), jackrabbitGroup );
      }
    }

    ArrayList<String> groupsToRemove = new ArrayList<String>( currentlyAssignedGroups.keySet() );
    groupsToRemove.removeAll( finalCollectionOfAssignedGroups.keySet() );

    ArrayList<String> groupsToAdd = new ArrayList<String>( finalCollectionOfAssignedGroups.keySet() );
    groupsToAdd.removeAll( currentlyAssignedGroups.keySet() );

    for ( String groupId : groupsToRemove ) {
      currentlyAssignedGroups.get( groupId ).removeMember( jackrabbitUser );
    }

    for ( String groupId : groupsToAdd ) {
      finalCollectionOfAssignedGroups.get( groupId ).addMember( jackrabbitUser );
    }

    // Purge the UserDetails cache
    purgeUserFromCache( userName );
  }

  public IPentahoRole createRole( Session session, final ITenant theTenant, final String roleName,
      final String description, final String[] memberUserNames ) throws AuthorizableExistsException,
    RepositoryException {
    ITenant tenant = theTenant;
    String role = roleName;
    if ( tenant == null ) {
      tenant = JcrTenantUtils.getTenant( roleName, false );
      role = JcrTenantUtils.getPrincipalName( roleName, false );
    }
    if ( tenant == null || tenant.getId() == null ) {
      tenant = JcrTenantUtils.getCurrentTenant();
    }
    if ( !TenantUtils.isAccessibleTenant( tenant ) ) {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0006_TENANT_NOT_FOUND", theTenant.getId() ) );
    }
    String roleId = tenantedRoleNameUtils.getPrincipleId( tenant, role );

    UserManager tenantUserMgr = getUserManager( tenant, session );
    // Intermediate path will always be an empty string. The path is already provided while creating a user manager
    tenantUserMgr.createGroup( new PrincipalImpl( roleId ), "" ); //$NON-NLS-1$
    setRoleMembers( session, tenant, role, memberUserNames );
    setRoleDescription( session, tenant, role, description );
    return getRole( session, theTenant, roleName );
  }

  public IPentahoUser createUser( Session session, final ITenant theTenant, final String userName,
      final String password, final String description, final String[] roles ) throws AuthorizableExistsException,
    RepositoryException {
    ITenant tenant = theTenant;
    String user = userName;
    if ( tenant == null ) {
      tenant = JcrTenantUtils.getTenant( userName, true );
      user = JcrTenantUtils.getPrincipalName( userName, true );
    }
    if ( tenant == null || tenant.getId() == null ) {
      tenant = JcrTenantUtils.getCurrentTenant();
    }
    if ( !TenantUtils.isAccessibleTenant( tenant ) ) {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0006_TENANT_NOT_FOUND", theTenant.getId() ) );
    }
    String userId = tenantedUserNameUtils.getPrincipleId( tenant, user );
    UserManager tenantUserMgr = getUserManager( tenant, session );
    tenantUserMgr.createUser( userId, password, new PrincipalImpl( userId ), "" ); //$NON-NLS-1$
    session.save();
    /**
     * This call is absolutely necessary. setUserRolesForNewUser will never inspect what roles this user is a part of.
     * Since this is a new user it will not be a part of new roles
     **/
    setUserRolesForNewUser( session, tenant, user, roles );
    setUserDescription( session, tenant, user, description );
    session.save();
    createUserHomeFolder( tenant, user, session );
    session.save();
    this.userDetailsCache.removeUserFromCache( userName );
    return getUser( session, tenant, userName );
  }

  public void deleteRole( Session session, final IPentahoRole role ) throws NotFoundException, RepositoryException {
    if ( canDeleteRole( session, role ) ) {
      final List<IPentahoUser> roleMembers = this.getRoleMembers( session, role.getTenant(), role.getName() );
      Group jackrabbitGroup = getJackrabbitGroup( role.getTenant(), role.getName(), session );
      if ( jackrabbitGroup != null
          && TenantUtils.isAccessibleTenant( tenantedRoleNameUtils.getTenant( jackrabbitGroup.getID() ) ) ) {
        jackrabbitGroup.remove();
      } else {
        throw new NotFoundException( "" ); //$NON-NLS-1$
      }
      for ( IPentahoUser roleMember : roleMembers ) {
        purgeUserFromCache( roleMember.getUsername() );
      }
    } else {
      throw new RepositoryException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0007_ATTEMPTED_SYSTEM_ROLE_DELETE" ) );
    }
  }

  public void deleteUser( Session session, final IPentahoUser user ) throws NotFoundException, RepositoryException {
    if ( canDeleteUser( session, user ) ) {
      User jackrabbitUser = getJackrabbitUser( user.getTenant(), user.getUsername(), session );
      if ( jackrabbitUser != null
          && TenantUtils.isAccessibleTenant( tenantedUserNameUtils.getTenant( jackrabbitUser.getID() ) ) ) {

        // [BISERVER-9215] Adding new user with same user name as a previously deleted user, defaults to all
        // previous
        // roles
        Iterator<Group> currentGroups = jackrabbitUser.memberOf();
        while ( currentGroups.hasNext() ) {
          currentGroups.next().removeMember( jackrabbitUser );
        }
        purgeUserFromCache( user.getUsername() );
        // [BISERVER-9215]
        jackrabbitUser.remove();
      } else {
        throw new NotFoundException( "" ); //$NON-NLS-1$
      }
    } else {
      throw new RepositoryException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0004_LAST_USER_NEEDED_IN_ROLE", tenantAdminRoleName ) );
    }
  }

  public List<IPentahoRole> getRoles( Session session ) throws RepositoryException {
    return getRoles( session, JcrTenantUtils.getCurrentTenant() );
  }

  private IPentahoUser convertToPentahoUser( User jackrabbitUser ) throws RepositoryException {
    if ( userCache.containsKey( jackrabbitUser.getID() ) ) {
      return (IPentahoUser) userCache.get( jackrabbitUser.getID() );
    }
    IPentahoUser pentahoUser = null;
    Value[] propertyValues = null;

    String description = null;
    try {
      propertyValues = jackrabbitUser.getProperty( "description" ); //$NON-NLS-1$
      description = propertyValues.length > 0 ? propertyValues[0].getString() : null;
    } catch ( Exception ex ) {
      // CHECKSTYLES IGNORE
    }

    Credentials credentials = jackrabbitUser.getCredentials();
    String password = null;
    if ( credentials instanceof CryptedSimpleCredentials ) {
      password = new String( ( (CryptedSimpleCredentials) credentials ).getPassword() );
    }

    pentahoUser =
        new PentahoUser( tenantedUserNameUtils.getTenant( jackrabbitUser.getID() ), tenantedUserNameUtils
            .getPrincipleName( jackrabbitUser.getID() ), password, description, !jackrabbitUser.isDisabled() );

    userCache.put( jackrabbitUser.getID(), pentahoUser );
    return pentahoUser;
  }

  private IPentahoRole convertToPentahoRole( Group jackrabbitGroup ) throws RepositoryException {
    IPentahoRole role = null;
    Value[] propertyValues = null;

    String description = null;
    try {
      propertyValues = jackrabbitGroup.getProperty( "description" ); //$NON-NLS-1$
      description = propertyValues.length > 0 ? propertyValues[0].getString() : null;
    } catch ( Exception ex ) {
      // CHECKSTYLES IGNORE
    }

    role =
        new PentahoRole( tenantedRoleNameUtils.getTenant( jackrabbitGroup.getID() ), tenantedRoleNameUtils
            .getPrincipleName( jackrabbitGroup.getID() ), description );
    return role;
  }

  public List<IPentahoUser> getUsers( Session session ) throws RepositoryException {
    return getUsers( session, JcrTenantUtils.getCurrentTenant() );
  }

  public void setRoleDescription( Session session, final ITenant theTenant, final String roleName,
      final String description ) throws NotFoundException, RepositoryException {
    Group jackrabbitGroup = getJackrabbitGroup( theTenant, roleName, session );
    if ( jackrabbitGroup != null
        && TenantUtils.isAccessibleTenant( theTenant == null ? tenantedRoleNameUtils
            .getTenant( jackrabbitGroup.getID() ) : theTenant ) ) {
      if ( description == null ) {
        jackrabbitGroup.removeProperty( "description" ); //$NON-NLS-1$
      } else {
        jackrabbitGroup.setProperty( "description", session.getValueFactory().createValue( description ) ); //$NON-NLS-1$
      }
    } else {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0002_ROLE_NOT_FOUND" ) );
    }
  }

  public void setUserDescription( Session session, final ITenant theTenant, final String userName,
      final String description ) throws NotFoundException, RepositoryException {
    User jackrabbitUser = getJackrabbitUser( theTenant, userName, session );
    if ( ( jackrabbitUser == null )
        || !TenantUtils.isAccessibleTenant( theTenant == null ? tenantedUserNameUtils
            .getTenant( jackrabbitUser.getID() ) : theTenant ) ) {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND" ) );
    }
    if ( description == null ) {
      jackrabbitUser.removeProperty( "description" ); //$NON-NLS-1$
    } else {
      jackrabbitUser.setProperty( "description", session.getValueFactory().createValue( description ) ); //$NON-NLS-1$
    }
  }

  public void setPassword( Session session, final ITenant theTenant, final String userName, final String password )
    throws NotFoundException, RepositoryException {
    User jackrabbitUser = getJackrabbitUser( theTenant, userName, session );
    if ( ( jackrabbitUser == null )
        || !TenantUtils.isAccessibleTenant( theTenant == null ? tenantedUserNameUtils
            .getTenant( jackrabbitUser.getID() ) : theTenant ) ) {
      throw new NotFoundException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0003_USER_NOT_FOUND" ) );
    }
    jackrabbitUser.changePassword( password );

    /**
     * BISERVER-9906 Clear cache after changing password
     */
    purgeUserFromCache( userName );
    userCache.remove( jackrabbitUser.getID() );
  }

  public ITenantedPrincipleNameResolver getTenantedUserNameUtils() {
    return tenantedUserNameUtils;
  }

  public ITenantedPrincipleNameResolver getTenantedRoleNameUtils() {
    return tenantedRoleNameUtils;
  }

  public List<IPentahoRole> getRoles( Session session, ITenant tenant ) throws RepositoryException, NamespaceException {
    return getRoles( session, tenant, false );
  }

  public List<IPentahoRole> getRoles( Session session, ITenant theTenant, boolean includeSubtenants )
    throws RepositoryException {
    ArrayList<IPentahoRole> roles = new ArrayList<IPentahoRole>();
    if ( theTenant == null || theTenant.getId() == null ) {
      theTenant = JcrTenantUtils.getTenant();
    }

    if ( TenantUtils.isAccessibleTenant( theTenant ) ) {
      UserManager userMgr = getUserManager( theTenant, session );
      pPrincipalName = ( (SessionImpl) session ).getJCRName( P_PRINCIPAL_NAME );
      Iterator<Authorizable> it = userMgr.findAuthorizables( pPrincipalName, null, UserManager.SEARCH_TYPE_GROUP );
      while ( it.hasNext() ) {
        Group group = (Group) it.next();
        IPentahoRole pentahoRole = convertToPentahoRole( group );
        // Exclude the system role from the list of roles to be returned back
        if ( !extraRoles.contains( pentahoRole.getName() ) ) {
          if ( includeSubtenants ) {
            roles.add( pentahoRole );
          } else {
            if ( pentahoRole.getTenant() != null && pentahoRole.getTenant().equals( theTenant ) ) {
              roles.add( pentahoRole );
            }
          }
        }
      }
    }
    return roles;
  }

  public List<IPentahoUser> getUsers( Session session, ITenant tenant ) throws RepositoryException {
    return getUsers( session, tenant, false );
  }

  public List<IPentahoUser> getUsers( Session session, ITenant theTenant, boolean includeSubtenants )
    throws RepositoryException {
    ArrayList<IPentahoUser> users = new ArrayList<IPentahoUser>();
    if ( theTenant == null || theTenant.getId() == null ) {
      theTenant = JcrTenantUtils.getTenant();
    }
    if ( TenantUtils.isAccessibleTenant( theTenant ) ) {
      UserManager userMgr = getUserManager( theTenant, session );
      pPrincipalName = ( (SessionImpl) session ).getJCRName( P_PRINCIPAL_NAME );
      Iterator<Authorizable> it = userMgr.findAuthorizables( pPrincipalName, null, UserManager.SEARCH_TYPE_USER );
      while ( it.hasNext() ) {
        User user = (User) it.next();
        IPentahoUser pentahoUser = convertToPentahoUser( user );
        if ( includeSubtenants ) {
          users.add( pentahoUser );
        } else {
          if ( pentahoUser.getTenant() != null && pentahoUser.getTenant().equals( theTenant ) ) {
            users.add( pentahoUser );
          }
        }
      }
    }
    return users;
  }

  public IPentahoRole getRole( Session session, final ITenant tenant, final String name ) throws RepositoryException {
    Group jackrabbitGroup = getJackrabbitGroup( tenant, name, session );
    return jackrabbitGroup != null
        && TenantUtils.isAccessibleTenant( tenant == null ? tenantedRoleNameUtils.getTenant( jackrabbitGroup.getID() )
            : tenant ) ? convertToPentahoRole( jackrabbitGroup ) : null;
  }

  private UserManagerImpl getUserManager( ITenant theTenant, Session session ) throws RepositoryException {
    Properties tenantProperties = new Properties();
    tenantProperties.put( UserManagerImpl.PARAM_USERS_PATH, UserManagerImpl.USERS_PATH
        + theTenant.getRootFolderAbsolutePath() );
    tenantProperties.put( UserManagerImpl.PARAM_GROUPS_PATH, UserManagerImpl.GROUPS_PATH
        + theTenant.getRootFolderAbsolutePath() );
    return new UserManagerImpl( (SessionImpl) session, session.getUserID(), tenantProperties );
  }

  public IPentahoUser getUser( Session session, final ITenant tenant, final String name ) throws RepositoryException {
    User jackrabbitUser = getJackrabbitUser( tenant, name, session );
    return jackrabbitUser != null
        && TenantUtils.isAccessibleTenant( tenant == null ? tenantedUserNameUtils.getTenant( jackrabbitUser.getID() )
            : tenant ) ? convertToPentahoUser( jackrabbitUser ) : null;
  }

  private Group getJackrabbitGroup( ITenant theTenant, String name, Session session ) throws RepositoryException {
    Group jackrabbitGroup = null;
    String roleId = name;
    String roleName = name;
    ITenant tenant = theTenant;

    if ( tenant == null ) {
      tenant = JcrTenantUtils.getTenant( roleName, false );
      roleName = JcrTenantUtils.getPrincipalName( roleName, false );
    }
    if ( tenant == null || tenant.getId() == null ) {
      tenant = JcrTenantUtils.getCurrentTenant();
    }
    if ( tenant == null || tenant.getId() == null ) {
      tenant = JcrTenantUtils.getDefaultTenant();
    }
    roleId = tenantedRoleNameUtils.getPrincipleId( tenant, roleName );

    UserManager userMgr = getUserManager( tenant, session );
    Authorizable authorizable = userMgr.getAuthorizable( roleId );
    if ( authorizable instanceof Group ) {
      jackrabbitGroup = (Group) authorizable;
    }
    return jackrabbitGroup;
  }

  private User getJackrabbitUser( ITenant theTenant, String name, Session session ) throws RepositoryException {
    User jackrabbitUser = null;
    String userId = name;
    String userName = name;
    ITenant tenant = theTenant;
    if ( tenant == null ) {
      tenant = JcrTenantUtils.getTenant( userName, true );
      userName = JcrTenantUtils.getPrincipalName( userName, true );
    }
    if ( tenant == null || tenant.getId() == null ) {
      tenant = JcrTenantUtils.getCurrentTenant();
    }
    if ( tenant == null || tenant.getId() == null ) {
      tenant = JcrTenantUtils.getDefaultTenant();
    }

    if ( tenant != null ) {
      userId = tenantedUserNameUtils.getPrincipleId( tenant, userName );

      UserManager userMgr = getUserManager( tenant, session );
      Authorizable authorizable = userMgr.getAuthorizable( userId );
      if ( authorizable instanceof User ) {
        jackrabbitUser = (User) authorizable;
      }
    }
    return jackrabbitUser;
  }

  protected boolean tenantExists( String tenantName ) {
    return tenantName != null && tenantName.trim().length() > 0;
  }

  public List<IPentahoUser> getRoleMembers( Session session, final ITenant theTenant, final String roleName )
    throws RepositoryException {
    List<IPentahoUser> users = new ArrayList<IPentahoUser>();
    Group jackrabbitGroup = getJackrabbitGroup( theTenant, roleName, session );
    if ( ( jackrabbitGroup != null )
        && TenantUtils.isAccessibleTenant( theTenant == null ? tenantedRoleNameUtils
            .getTenant( jackrabbitGroup.getID() ) : theTenant ) ) {
      Iterator<Authorizable> authorizables = jackrabbitGroup.getMembers();
      while ( authorizables.hasNext() ) {
        Authorizable authorizable = authorizables.next();
        if ( authorizable instanceof User ) {
          users.add( convertToPentahoUser( (User) authorizable ) );
        }
      }
    }
    return users;
  }

  public List<IPentahoRole> getUserRoles( Session session, final ITenant theTenant, final String userName )
    throws RepositoryException {
    ArrayList<IPentahoRole> roles = new ArrayList<IPentahoRole>();
    User jackrabbitUser = getJackrabbitUser( theTenant, userName, session );
    if ( ( jackrabbitUser != null )
        && TenantUtils.isAccessibleTenant( theTenant == null ? tenantedUserNameUtils.getTenant( jackrabbitUser.getID() )
            : theTenant ) ) {
      Iterator<Group> groups = jackrabbitUser.memberOf();
      while ( groups.hasNext() ) {
        IPentahoRole role = convertToPentahoRole( groups.next() );
        // Exclude the extra role from the list of roles to be returned back
        if ( !extraRoles.contains( role.getName() ) ) {
          roles.add( role );
        }
      }
    }
    return roles;
  }

  private RepositoryFile createUserHomeFolder( ITenant theTenant, String username, Session session )
    throws RepositoryException {
    Builder aclsForUserHomeFolder = null;
    Builder aclsForTenantHomeFolder = null;

    if ( theTenant == null ) {
      theTenant = JcrTenantUtils.getTenant( username, true );
      username = JcrTenantUtils.getPrincipalName( username, true );
    }
    if ( theTenant == null || theTenant.getId() == null ) {
      theTenant = JcrTenantUtils.getCurrentTenant();
    }
    if ( theTenant == null || theTenant.getId() == null ) {
      theTenant = JcrTenantUtils.getDefaultTenant();
    }
    RepositoryFile userHomeFolder = null;
    String userId = tenantedUserNameUtils.getPrincipleId( theTenant, username );
    final RepositoryFileSid userSid = new RepositoryFileSid( userId );
    RepositoryFile tenantHomeFolder = null;
    RepositoryFile tenantRootFolder = null;
    RepositoryFileSid ownerSid = null;
    // Get the Tenant Root folder. If the Tenant Root folder does not exist then exit.
    tenantRootFolder =
        JcrRepositoryFileUtils.getFileByAbsolutePath( session, ServerRepositoryPaths
            .getTenantRootFolderPath( theTenant ), pathConversionHelper, lockHelper, false, null );
    if ( tenantRootFolder != null ) {
      // Try to see if Tenant Home folder exist
      tenantHomeFolder =
          JcrRepositoryFileUtils.getFileByAbsolutePath( session, ServerRepositoryPaths
              .getTenantHomeFolderPath( theTenant ), pathConversionHelper, lockHelper, false, null );

      if ( tenantHomeFolder == null ) {
        String ownerId = tenantedUserNameUtils.getPrincipleId( theTenant, username );
        ownerSid = new RepositoryFileSid( ownerId, Type.USER );

        String tenantAuthenticatedRoleId = tenantedRoleNameUtils.getPrincipleId( theTenant, authenticatedRoleName );
        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 =
            internalCreateFolder( session, tenantRootFolder.getId(), new RepositoryFile.Builder( ServerRepositoryPaths
                .getTenantHomeFolderName() ).folder( true ).title(
                Messages.getInstance().getString( "AbstractJcrBackedUserRoleDao.usersFolderDisplayName" ) ).build(),
                aclsForTenantHomeFolder.build(), "tenant home folder" ); //$NON-NLS-1$
      } else {
        String ownerId = tenantedUserNameUtils.getPrincipleId( theTenant, username );
        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 =
          JcrRepositoryFileUtils.getFileByAbsolutePath( session, ServerRepositoryPaths.getUserHomeFolderPath(
              theTenant, username ), pathConversionHelper, lockHelper, false, null );
      if ( userHomeFolder == null ) {
        userHomeFolder =
            internalCreateFolder( session, tenantHomeFolder.getId(), new RepositoryFile.Builder( username ).folder(
                true ).build(), aclsForUserHomeFolder.build(), "user home folder" ); //$NON-NLS-1$
      }

    }
    return userHomeFolder;
  }

  private RepositoryFile internalCreateFolder( final Session session, final Serializable parentFolderId,
      final RepositoryFile folder, final RepositoryFileAcl acl, final String versionMessage )
    throws RepositoryException {
    PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants( session );
    JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary( session, pentahoJcrConstants, parentFolderId );
    Node folderNode = JcrRepositoryFileUtils.createFolderNode( session, pentahoJcrConstants, parentFolderId, folder );
    // we must create the acl during checkout
    JcrRepositoryFileAclUtils.createAcl( session, pentahoJcrConstants, folderNode.getIdentifier(), acl == null
        ? defaultAclHandler.createDefaultAcl( folder ) : acl );
    session.save();
    if ( folder.isVersioned() ) {
      JcrRepositoryFileUtils.checkinNearestVersionableNodeIfNecessary( session, pentahoJcrConstants, folderNode,
          versionMessage );
    }
    JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary( session, pentahoJcrConstants, parentFolderId,
        Messages.getInstance().getString( "JcrRepositoryFileDao.USER_0001_VER_COMMENT_ADD_FOLDER", folder.getName(),
            ( parentFolderId == null ? "root" : parentFolderId.toString() ) ) ); //$NON-NLS-1$ //$NON-NLS-2$
    return JcrRepositoryFileUtils.nodeToFile( session, pentahoJcrConstants, pathConversionHelper, lockHelper,
        folderNode );
  }

  /**
   * Checks to see if the removal of the received roles and users would cause the system to have no login associated
   * with the Admin role. This check is to be made before any changes take place
   *
   * @return Error message if invalid or null if ok
   * @throws RepositoryException
   */

  private boolean canDeleteUser( Session session, final IPentahoUser user ) throws RepositoryException {
    boolean userHasAdminRole = false;
    List<IPentahoRole> roles = getUserRoles( null, user.getUsername() );
    for ( IPentahoRole role : roles ) {
      if ( tenantAdminRoleName.equals( role.getName() ) ) {
        userHasAdminRole = true;
        break;
      }
    }

    if ( ( isMyself( user.getUsername() ) || isDefaultAdminUser( user.getUsername() ) ) && userHasAdminRole ) {
      throw new RepositoryException( Messages.getInstance().getString(
          "AbstractJcrBackedUserRoleDao.ERROR_0008_UNABLE_TO_DELETE_USER_IS_YOURSELF_OR_DEFAULT_ADMIN_USER" ) );
    }

    if ( userHasAdminRole ) {
      List<IPentahoUser> usersWithAdminRole = getRoleMembers( session, null, tenantAdminRoleName );
      if ( usersWithAdminRole == null ) {
        throw new RepositoryException( Messages.getInstance().getString(
            "AbstractJcrBackedUserRoleDao.ERROR_0004_LAST_USER_NEEDED_IN_ROLE", tenantAdminRoleName ) );
      }
      if ( usersWithAdminRole.size() > 1 ) {
        return true;
      } else if ( usersWithAdminRole.size() == 1 ) {
        return false;
      } else {
        throw new RepositoryException( Messages.getInstance().getString(
            "AbstractJcrBackedUserRoleDao.ERROR_0004_LAST_USER_NEEDED_IN_ROLE", tenantAdminRoleName ) );
      }
    }
    return true;
  }

  private boolean canDeleteRole( Session session, final IPentahoRole role ) {
    return !( role != null && systemRoles.contains( role.getName() ) );
  }

  private String[] findRemovedUsers( List<IPentahoUser> savedUsers, String[] toBeSaved ) {
    List<String> usersToBeRemoved = new ArrayList<String>();
    List<String> toBeSavedUsers = Arrays.asList( toBeSaved );
    for ( int i = 0; i < savedUsers.size(); i++ ) {
      if ( toBeSavedUsers != null && toBeSaved.length > 0 ) {
        if ( !toBeSavedUsers.contains( savedUsers.get( i ).getUsername() ) ) {
          usersToBeRemoved.add( savedUsers.get( i ).getUsername() );
        }
      } else {
        usersToBeRemoved.add( savedUsers.get( i ).getUsername() );
      }
    }
    return usersToBeRemoved.toArray( new String[0] );
  }
}
TOP

Related Classes of org.pentaho.platform.security.userroledao.jackrabbit.AbstractJcrBackedUserRoleDao

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.