Package org.pentaho.platform.repository2.unified.jcr

Source Code of org.pentaho.platform.repository2.unified.jcr.JcrRepositoryFileAclDao$IPermissionConversionHelper

/*
* 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.unified.jcr;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.mt.ITenant;
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.api.repository2.unified.RepositoryFileSid.Type;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.repository2.messages.Messages;
import org.pentaho.platform.repository2.unified.IRepositoryFileAclDao;
import org.pentaho.platform.repository2.unified.jcr.IAclMetadataStrategy.AclMetadata;
import org.pentaho.platform.repository2.unified.jcr.jackrabbit.security.SpringSecurityRolePrincipal;
import org.pentaho.platform.repository2.unified.jcr.jackrabbit.security.SpringSecurityUserPrincipal;
import org.springframework.extensions.jcr.JcrCallback;
import org.springframework.extensions.jcr.JcrTemplate;
import org.springframework.util.Assert;

import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlList;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.AccessControlPolicy;
import javax.jcr.security.AccessControlPolicyIterator;
import javax.jcr.security.Privilege;
import java.io.IOException;
import java.io.Serializable;
import java.security.Principal;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;

/**
* Jackrabbit-based implementation of {@link IRepositoryFileAclDao}.
* <p/>
* <p>
* All mutating public methods require checkout and checkin calls since the act of simply calling
* {@code AccessControlManager.getApplicablePolicies()} (as is done in
* {@link #toAcl(Session, PentahoJcrConstants, Serializable)}) will query that the node is allowed to have the
* "access controlled" mixin type added. If the node is checked in, this query will return false. See Jackrabbit's
* {@code ItemValidator.hasCondition()}.
* </p>
*
* @author mlowery
*/
public class JcrRepositoryFileAclDao implements IRepositoryFileAclDao {

  // ~ Static fields/initializers
  // ======================================================================================

  private static final Log logger = LogFactory.getLog( JcrRepositoryFileAclDao.class );

  // ~ Instance fields
  // =================================================================================================

  private JcrTemplate jcrTemplate;

  private IPathConversionHelper pathConversionHelper;

  private String tenantAdminAuthorityName;

  // ~ Constructors
  // ====================================================================================================

  public JcrRepositoryFileAclDao( final JcrTemplate jcrTemplate, final IPathConversionHelper pathConversionHelper,
      String tenantAdminAuthorityName ) {
    super();
    this.jcrTemplate = jcrTemplate;
    this.pathConversionHelper = pathConversionHelper;
    this.tenantAdminAuthorityName = tenantAdminAuthorityName;
  }

  // ~ Methods
  // =========================================================================================================

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings( "unchecked" )
  public List<RepositoryFileAce> getEffectiveAces( final Serializable id, final boolean forceEntriesInheriting ) {
    return (List<RepositoryFileAce>) jcrTemplate.execute( new JcrCallback() {
      public Object doInJcr( final Session session ) throws RepositoryException, IOException {
        Node node = session.getNodeByIdentifier( id.toString() );

        if ( node == null ) {
          throw new RepositoryException( Messages.getInstance().getString(
              "JackrabbitRepositoryFileAclDao.ERROR_0001_NODE_NOT_FOUND", id.toString() ) ); //$NON-NLS-1$
        }

        // consult the parent node's effective policy if force is true and parent is not null
        if ( forceEntriesInheriting && session.getNodeByIdentifier( id.toString() ).getParent() != null ) {
          node = node.getParent();
        }

        String absPath = node.getPath();

        AccessControlPolicy[] acPolicies = session.getAccessControlManager().getEffectivePolicies( absPath );
        // logic assumes policies are ordered from leaf to root
        for ( AccessControlPolicy policy : acPolicies ) {
          Assert.isTrue( policy instanceof AccessControlList );
          AccessControlList acList = ( (AccessControlList) policy );
          if ( !isEntriesInheriting( session, absPath, acList ) ) {
            List<RepositoryFileAce> aces = new ArrayList<RepositoryFileAce>();
            AccessControlEntry[] acEntries = acList.getAccessControlEntries();
            List<AccessControlEntry> cleanedAcEntries =
                JcrRepositoryFileAclUtils.removeAclMetadata( Arrays.asList( acEntries ) );
            for ( AccessControlEntry acEntry : cleanedAcEntries ) {
              if ( !acEntry.getPrincipal().equals(
                  new SpringSecurityRolePrincipal( JcrTenantUtils.getTenantedRole( tenantAdminAuthorityName ) ) ) ) {
                aces.add( toAce( session, acEntry ) );
              }
            }
            return aces;
          }
        }

        // none are entriesInheriting=false so root aces are the effective aces
        AccessControlList acList = (AccessControlList) acPolicies[acPolicies.length - 1];
        List<RepositoryFileAce> aces = new ArrayList<RepositoryFileAce>();
        AccessControlEntry[] acEntries = acList.getAccessControlEntries();
        List<AccessControlEntry> cleanedAcEntries =
            JcrRepositoryFileAclUtils.removeAclMetadata( Arrays.asList( acEntries ) );
        for ( AccessControlEntry acEntry : cleanedAcEntries ) {
          if ( !acEntry.getPrincipal().equals(
              new SpringSecurityRolePrincipal( JcrTenantUtils.getTenantedRole( tenantAdminAuthorityName ) ) ) ) {
            aces.add( toAce( session, acEntry ) );
          }
        }
        return aces;
      }
    } );
  }

  protected String getOwner( final Session session, final String path, final AccessControlList acList )
    throws RepositoryException {
    AclMetadata aclMetadata = JcrRepositoryFileAclUtils.getAclMetadata( session, path, acList );
    if ( aclMetadata != null ) {
      return aclMetadata.getOwner();
    } else {
      return null;
    }
  }

  protected boolean isEntriesInheriting( final Session session, final String path, final AccessControlList acList )
    throws RepositoryException {
    AclMetadata aclMetadata = JcrRepositoryFileAclUtils.getAclMetadata( session, path, acList );
    if ( aclMetadata != null ) {
      return aclMetadata.isEntriesInheriting();
    } else {
      return false;
    }
  }

  /**
   * {@inheritDoc}
   */
  public boolean hasAccess( final String relPath, final EnumSet<RepositoryFilePermission> permissions ) {
    return (Boolean) jcrTemplate.execute( new JcrCallback() {
      public Object doInJcr( final Session session ) throws RepositoryException, IOException {
        DefaultPermissionConversionHelper permissionConversionHelper = new DefaultPermissionConversionHelper( session );
        Privilege[] privs = permissionConversionHelper.pentahoPermissionsToPrivileges( session, permissions );
        try {
          String absPath = pathConversionHelper.relToAbs( relPath );
          return session.getAccessControlManager().hasPrivileges( JcrStringHelper.pathEncode( absPath ), privs );
        } catch ( PathNotFoundException e ) {
          // never throw an exception if the path does not exist; just return false
          return false;
        }
      }
    } );
  }

  private RepositoryFileAcl toAcl( final Session session, final PentahoJcrConstants pentahoJcrConstants,
      final Serializable id ) throws RepositoryException {

    Node node = session.getNodeByIdentifier( id.toString() );
    if ( node == null ) {
      throw new RepositoryException( Messages.getInstance().getString(
          "JackrabbitRepositoryFileAclDao.ERROR_0001_NODE_NOT_FOUND", id.toString() ) ); //$NON-NLS-1$
    }
    String absPath = node.getPath();
    AccessControlManager acMgr = session.getAccessControlManager();
    AccessControlList acList = getAccessControlList( acMgr, absPath );

    RepositoryFileSid owner = null;
    String ownerString = getOwner( session, absPath, acList );

    if ( ownerString != null ) {
      // for now, just assume all owners are users; only has UI impact
      owner =
          new RepositoryFileSid( JcrTenantUtils.getUserNameUtils().getPrincipleName( ownerString ),
              RepositoryFileSid.Type.USER );
    }

    RepositoryFileAcl.Builder aclBuilder = new RepositoryFileAcl.Builder( id, owner );

    aclBuilder.entriesInheriting( isEntriesInheriting( session, absPath, acList ) );

    List<AccessControlEntry> cleanedAcEntries =
        JcrRepositoryFileAclUtils.removeAclMetadata( Arrays.asList( acList.getAccessControlEntries() ) );

    for ( AccessControlEntry acEntry : cleanedAcEntries ) {
      if ( !acEntry.getPrincipal().equals(
          new SpringSecurityRolePrincipal( JcrTenantUtils.getTenantedRole( tenantAdminAuthorityName ) ) ) ) {
        aclBuilder.ace( toAce( session, acEntry ) );
      }
    }
    return aclBuilder.build();

  }

  protected RepositoryFileAce toAce( final Session session, final AccessControlEntry acEntry )
    throws RepositoryException {
    Principal principal = acEntry.getPrincipal();
    RepositoryFileSid sid = null;
    String name = principal.getName();
    DefaultPermissionConversionHelper permissionConversionHelper = new DefaultPermissionConversionHelper( session );

    if ( principal instanceof Group ) {
      sid =
          new RepositoryFileSid( JcrTenantUtils.getRoleNameUtils().getPrincipleName( name ),
              RepositoryFileSid.Type.ROLE );
    } else {
      sid =
          new RepositoryFileSid( JcrTenantUtils.getUserNameUtils().getPrincipleName( name ),
              RepositoryFileSid.Type.USER );
    }
    logger.debug( String.format( "principal class [%s]", principal.getClass().getName() ) ); //$NON-NLS-1$
    Privilege[] privileges = acEntry.getPrivileges();
    return new RepositoryFileAce( sid, permissionConversionHelper
      .privilegesToPentahoPermissions( session, privileges ) );
  }

  /**
   * Converts between {@code RepositoryFilePermission} and {@code Privilege} instances.
   */
  public static interface IPermissionConversionHelper {
    Privilege[] pentahoPermissionsToPrivileges( final Session session,
        final EnumSet<RepositoryFilePermission> permission ) throws RepositoryException;

    EnumSet<RepositoryFilePermission> privilegesToPentahoPermissions( final Session session,
        final Privilege[] privileges ) throws RepositoryException;
  }

  public void addAce( final Serializable id, final RepositoryFileSid recipient,
      final EnumSet<RepositoryFilePermission> permission ) {
    if ( isKioskEnabled() ) {
      throw new RuntimeException( Messages.getInstance().getString( "JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED" ) ); //$NON-NLS-1$
    }

    Assert.notNull( id );
    Assert.notNull( recipient );
    Assert.notNull( permission );
    RepositoryFileAcl acl = getAcl( id );
    Assert.notNull( acl );
    // TODO mlowery find an ACE with the recipient and update that rather than adding a new ACE
    RepositoryFileSid newRecipient = recipient;
    if ( recipient.getType().equals( Type.USER ) ) {
      if ( JcrTenantUtils.getUserNameUtils().getTenant( recipient.getName() ) == null ) {
        newRecipient =
            new RepositoryFileSid( JcrTenantUtils.getTenantedUser( recipient.getName() ), recipient.getType() );
      }
    } else {
      if ( JcrTenantUtils.getRoleNameUtils().getTenant( recipient.getName() ) == null ) {
        newRecipient =
            new RepositoryFileSid( JcrTenantUtils.getTenantedRole( recipient.getName() ), recipient.getType() );
      }
    }
    RepositoryFileAcl updatedAcl = new RepositoryFileAcl.Builder( acl ).ace( newRecipient, permission ).build();
    updateAcl( updatedAcl );
    logger.debug( "added ace: id=" + id + ", sid=" + recipient + ", permission=" + permission ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  }

  public RepositoryFileAcl createAcl( final Serializable fileId, final RepositoryFileAcl acl ) {
    if ( isKioskEnabled() ) {
      throw new RuntimeException( Messages.getInstance().getString( "JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED" ) ); //$NON-NLS-1$
    }

    return (RepositoryFileAcl) jcrTemplate.execute( new JcrCallback() {
      public Object doInJcr( final Session session ) throws RepositoryException, IOException {
        PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants( session );
        Node node = session.getNodeByIdentifier( fileId.toString() );
        String absPath = node.getPath();
        AccessControlManager acMgr = session.getAccessControlManager();
        AccessControlList acList = getAccessControlList( acMgr, absPath );
        acMgr.setPolicy( absPath, acList );
        return internalUpdateAcl( session, pentahoJcrConstants, fileId, acl );
      }
    } );
  }

  private AccessControlList getAccessControlList( final AccessControlManager acMgr, final String path )
    throws RepositoryException {
    AccessControlPolicyIterator applicablePolicies = acMgr.getApplicablePolicies( path );
    while ( applicablePolicies.hasNext() ) {
      AccessControlPolicy policy = applicablePolicies.nextAccessControlPolicy();
      if ( policy instanceof AccessControlList ) {
        return (AccessControlList) policy;
      }
    }
    AccessControlPolicy[] policies = acMgr.getPolicies( path );
    for ( int i = 0; i < policies.length; i++ ) {
      if ( policies[i] instanceof AccessControlList ) {
        return (AccessControlList) policies[i];
      }
    }
    throw new IllegalStateException( "no access control list applies or is bound to node" );
  }

  public RepositoryFileAcl getAcl( final Serializable id ) {
    return (RepositoryFileAcl) jcrTemplate.execute( new JcrCallback() {
      public Object doInJcr( final Session session ) throws RepositoryException, IOException {
        PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants( session );
        return toAcl( session, pentahoJcrConstants, id );
      }
    } );
  }

  protected RepositoryFileAcl getParentAcl( final Serializable id ) {
    return (RepositoryFileAcl) jcrTemplate.execute( new JcrCallback() {
      public Object doInJcr( final Session session ) throws RepositoryException, IOException {
        PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants( session );
        Node node = session.getNodeByIdentifier( id.toString() );
        if ( !node.getParent().isSame( session.getRootNode() ) ) {
          return toAcl( session, pentahoJcrConstants, node.getParent().getIdentifier() );
        } else {
          return null;
        }
      }
    } );
  }

  public void setFullControl( Serializable id, RepositoryFileSid sid, RepositoryFilePermission permission ) {
    addAce( id, sid, EnumSet.of( permission ) );
  }

  public RepositoryFileAcl updateAcl( final RepositoryFileAcl acl ) {
    return (RepositoryFileAcl) jcrTemplate.execute( new JcrCallback() {
      public Object doInJcr( final Session session ) throws RepositoryException, IOException {
        PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants( session );
        JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary( session, pentahoJcrConstants, acl.getId() );
        RepositoryFileAcl updatedAcl = internalUpdateAcl( session, pentahoJcrConstants, acl.getId(), acl );
        JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary( session, pentahoJcrConstants, acl.getId(),
            null, null, true );
        return updatedAcl;
      }
    } );
  }

  protected RepositoryFileAcl internalUpdateAcl( final Session session, final PentahoJcrConstants pentahoJcrConstants,
      final Serializable fileId, final RepositoryFileAcl acl ) throws RepositoryException {
    if ( isKioskEnabled() ) {
      throw new RuntimeException( Messages.getInstance().getString( "JcrRepositoryFileDao.ERROR_0006_ACCESS_DENIED" ) ); //$NON-NLS-1$
    }

    DefaultPermissionConversionHelper permissionConversionHelper = new DefaultPermissionConversionHelper( session );
    Node node = session.getNodeByIdentifier( fileId.toString() );
    if ( node == null ) {
      throw new RepositoryException( Messages.getInstance().getString(
          "JackrabbitRepositoryFileAclDao.ERROR_0001_NODE_NOT_FOUND", fileId.toString() ) ); //$NON-NLS-1$
    }
    String absPath = node.getPath();
    AccessControlManager acMgr = session.getAccessControlManager();
    AccessControlList acList = getAccessControlList( acMgr, absPath );

    // clear all entries
    AccessControlEntry[] acEntries = acList.getAccessControlEntries();
    for ( int i = 0; i < acEntries.length; i++ ) {
      acList.removeAccessControlEntry( acEntries[i] );
    }

    JcrRepositoryFileAclUtils.setAclMetadata( session, absPath, acList, new AclMetadata( acl.getOwner().getName(), acl
        .isEntriesInheriting() ) );

    // add entries to now empty list but only if not inheriting; force user to start with clean slate
    boolean adminPrincipalExist = false;
    ITenant principalTenant = null;
    if ( !acl.isEntriesInheriting() ) {
      for ( RepositoryFileAce ace : acl.getAces() ) {
        Principal principal = null;
        if ( RepositoryFileSid.Type.ROLE == ace.getSid().getType() ) {
          String principalName = JcrTenantUtils.getRoleNameUtils().getPrincipleName( ace.getSid().getName() );
          if ( tenantAdminAuthorityName.equals( principalName ) ) {
            adminPrincipalExist = true;
          }
          principal = new SpringSecurityRolePrincipal( JcrTenantUtils.getTenantedRole( ace.getSid().getName() ) );
        } else {
          principal = new SpringSecurityUserPrincipal( JcrTenantUtils.getTenantedUser( ace.getSid().getName() ) );
        }
        acList.addAccessControlEntry( principal, permissionConversionHelper.pentahoPermissionsToPrivileges( session,
            ace.getPermissions() ) );
      }
      if ( !adminPrincipalExist ) {
        if ( acl.getAces() != null && acl.getAces().size() > 0 ) {
          principalTenant = JcrTenantUtils.getRoleNameUtils().getTenant( acl.getAces().get( 0 ).getSid().getName() );
        }

        if ( principalTenant == null || principalTenant.getId() == null ) {
          principalTenant = JcrTenantUtils.getTenant();
        }

        List<RepositoryFilePermission> permissionList = new ArrayList<RepositoryFilePermission>();
        permissionList.add( RepositoryFilePermission.ALL );
        Principal adminPrincipal =
            new SpringSecurityRolePrincipal( JcrTenantUtils.getRoleNameUtils().getPrincipleId( principalTenant,
                tenantAdminAuthorityName ) );
        acList.addAccessControlEntry( adminPrincipal, permissionConversionHelper.pentahoPermissionsToPrivileges(
            session, EnumSet.copyOf( permissionList ) ) );
      }

    }
    acMgr.setPolicy( absPath, acList );
    session.save();
    return getAcl( fileId );

  }

  private boolean isKioskEnabled() {
    if ( PentahoSystem.getInitializedOK() ) {
      return "true".equals( PentahoSystem.getSystemSetting( "kiosk-mode", "false" ) );
    } else {
      return false;
    }
  }
}
TOP

Related Classes of org.pentaho.platform.repository2.unified.jcr.JcrRepositoryFileAclDao$IPermissionConversionHelper

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.