Package org.pentaho.platform.engine.security

Source Code of org.pentaho.platform.engine.security.SecurityHelper

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

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.engine.IAclHolder;
import org.pentaho.platform.api.engine.IAclVoter;
import org.pentaho.platform.api.engine.IParameterProvider;
import org.pentaho.platform.api.engine.IPentahoAclEntry;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.ISecurityHelper;
import org.pentaho.platform.api.engine.ISolutionFile;
import org.pentaho.platform.api.engine.IUserRoleListService;
import org.pentaho.platform.api.mt.ITenant;
import org.pentaho.platform.api.mt.ITenantedPrincipleNameResolver;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.core.system.StandaloneSession;
import org.pentaho.platform.engine.core.system.UserSession;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
import org.springframework.security.userdetails.User;
import org.springframework.security.userdetails.UserDetailsService;

import java.util.concurrent.Callable;

/**
* A utility class with several methods that are used to either bind the <tt>Authentication</tt> to the
* <tt>IPentahoSession</tt>, retrieve the <tt>Authentication</tt> from the <tt>IPentahoSession</tt>, and other various
* helper functions.
*
* @author mbatchel
*/

public class SecurityHelper implements ISecurityHelper {

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

  /**
   * The default instance of this singleton
   */
  private static ISecurityHelper instance = new SecurityHelper();
  private static ISecurityHelper mockInstance;

  private ITenantedPrincipleNameResolver tenantedUserNameUtils;
  private IAclVoter aclVoter;
  private UserDetailsService userDetailsService;
  private IUserRoleListService userRoleListService;

  /**
   * Returns the default instance, if the test instance is not null return the test instance
   */
  public static ISecurityHelper getInstance() {
    if ( mockInstance != null ) {
      return mockInstance;
    }

    return instance;
  }

  /**
   * Set the mockInstance, this should only be used for testing
   *
   * @param mockInstanceValue the test implementation of SecurityHelper
   */
  public static void setMockInstance( ISecurityHelper mockInstanceValue ) {
    mockInstance = mockInstanceValue;
  }

  /**
   * Default constructor - protected so that it may be only constructed by a sub-class since this is a singleton
   */
  protected SecurityHelper() {

  }

  /**
   * Hi-jacks the system for the named user. <p/> <p> This will essentially create a session for this user, make that
   * session the current session, and add the Authentication objects to the session and Spring context holder. WARNING:
   * this method is irreversible!!! If you want execute a block of code as a surrogate user and have the orignal user
   * resume after it is complete, you want {@link #runAsUser(String, Callable)}. </p> <p/> <p> This is for unit tests
   * only. </p>
   *
   * @param principalName the user to become in the system
   */
  @Override
  public void becomeUser( final String principalName ) {
    becomeUser( principalName, null );
  }

  /**
   * Hi-jacks the system for the named user. <p/> <p> This is for unit tests only. </p>
   */
  @Override
  public void becomeUser( final String principalName, final IParameterProvider paramProvider ) {
    UserSession session = null;
    tenantedUserNameUtils = getTenantedUserNameUtils();
    if ( tenantedUserNameUtils != null ) {
      session = new UserSession( principalName, null, false, paramProvider );
      ITenant tenant = tenantedUserNameUtils.getTenant( principalName );
      session.setAttribute( IPentahoSession.TENANT_ID_KEY, tenant.getId() );
      session.setAuthenticated( tenant.getId(), principalName );
    } else {
      session = new UserSession( principalName, null, false, paramProvider );
      session.setAuthenticated( principalName );
    }

    PentahoSessionHolder.setSession( session );

    Authentication auth = createAuthentication( principalName );
    // TODO We need to figure out how to inject this
    // Get the tenant id from the principle name and set it as an attribute of the pentaho session

    SecurityContextHolder.getContext().setAuthentication( auth );
    PentahoSystem.sessionStartup( PentahoSessionHolder.getSession(), paramProvider );
  }

  /**
   * Utility method that allows you to run a block of code as the given user. Regardless of success or exception
   * situation, the original session and authentication will be restored once your block of code is finished executing,
   * i.e. the given user will apply only to your {@link Callable}, then the system environment will return to the user
   * present prior to you calling this method.
   *
   * @param <T>           the return type of your operation, specify this type as <code>T</code>
   * @param principalName the user under whom you wish to run a section of code
   * @param callable      {@link Callable#call()} contains the code you wish to run as the given user
   * @return the value returned by your implementation of {@link Callable#call()}
   * @throws Exception
   * @see {@link Callable}
   */
  @Override
  public <T> T runAsUser( final String principalName, final Callable<T> callable ) throws Exception {
    return runAsUser( principalName, null, callable );
  }

  @Override
  public <T> T
  runAsUser( final String principalName, final IParameterProvider paramProvider, final Callable<T> callable )
    throws Exception {
    IPentahoSession origSession = PentahoSessionHolder.getSession();
    Authentication origAuth = SecurityContextHolder.getContext().getAuthentication();
    try {
      becomeUser( principalName );
      return callable.call();
    } finally {
      IPentahoSession sessionToDestroy = PentahoSessionHolder.getSession();
      if ( sessionToDestroy != null && sessionToDestroy != origSession ) {
        try {
          sessionToDestroy.destroy();
        } catch ( Exception e ) {
          e.printStackTrace();
        }
      }
      PentahoSessionHolder.setSession( origSession );
      SecurityContextHolder.getContext().setAuthentication( origAuth );
    }
  }

  /**
   * Utility method that allows you to run a block of code as the given user. Regardless of success or exception
   * situation, the original session and authentication will be restored once your block of code is finished executing,
   * i.e. the given user will apply only to your {@link Callable}, then the system environment will return to the user
   * present prior to you calling this method.
   *
   * @param <T>      the return type of your operation, specify this type as <code>T</code>
   * @param callable {@link Callable#call()} contains the code you wish to run as the given user
   * @return the value returned by your implementation of {@link Callable#call()}
   * @throws Exception
   * @see {@link Callable}
   */
  @Override
  public <T> T runAsAnonymous( final Callable<T> callable ) throws Exception {
    IPentahoSession origSession = PentahoSessionHolder.getSession();
    Authentication origAuth = SecurityContextHolder.getContext().getAuthentication();
    try {
      PentahoSessionHolder.setSession( new StandaloneSession() );

      // get anonymous username/role defined in pentaho.xml
      String user = PentahoSystem
        .getSystemSetting( "anonymous-authentication/anonymous-user", "anonymousUser" ); //$NON-NLS-1$//$NON-NLS-2$
      String role = PentahoSystem
        .getSystemSetting( "anonymous-authentication/anonymous-role", "Anonymous" ); //$NON-NLS-1$//$NON-NLS-2$
      GrantedAuthority[] authorities = new GrantedAuthority[] { new GrantedAuthorityImpl( role ) };

      Authentication auth =
        new AnonymousAuthenticationToken( "anonymousUser", new User( user, "ignored", true, true, true, true,
          authorities ), authorities );

      SecurityContextHolder.getContext().setAuthentication( auth );
      return callable.call();
    } finally {
      PentahoSessionHolder.setSession( origSession );
      SecurityContextHolder.getContext().setAuthentication( origAuth );
    }
  }

  /**
   * Utility method that communicates with the installed ACLVoter to determine administrator status
   *
   * @param session The users IPentahoSession object
   * @return true if the user is considered a Pentaho administrator
   */
  @Override
  public boolean isPentahoAdministrator( final IPentahoSession session ) {
    return getAclVoter().isPentahoAdministrator( session );
  }

  /**
   * Utility method that communicates with the installed ACLVoter to determine whether a particular role is granted to
   * the specified user.
   *
   * @param session The users' IPentahoSession
   * @param role    The role to look for
   * @return true if the user is granted the specified role.
   */
  @Override
  public boolean isGranted( final IPentahoSession session, final GrantedAuthority role ) {
    return getAclVoter().isGranted( session, role );
  }

  /**
   * @param aFile
   * @return a boolean that indicates if this file can have ACLS placed on it.
   */
  @Override
  public boolean canHaveACLS( final ISolutionFile aFile ) {
    if ( aFile.isDirectory() ) { // All Directories can have ACLS
      return true;
    }

    // Otherwise anything in the PentahoSystem extension list.
    return PentahoSystem.getACLFileExtensionList().contains( aFile.getExtension() );
  }

  @Override
  public boolean hasAccess( final IAclHolder aHolder, final int actionOperation, final IPentahoSession session ) {
    int aclMask = -1;

    switch( actionOperation ) {
      case ( IAclHolder.ACCESS_TYPE_READ ): {
        aclMask = IPentahoAclEntry.PERM_EXECUTE;
        break;
      }
      case IAclHolder.ACCESS_TYPE_WRITE:
      case IAclHolder.ACCESS_TYPE_UPDATE: {
        aclMask = IPentahoAclEntry.PERM_UPDATE;
        break;
      }
      case IAclHolder.ACCESS_TYPE_DELETE: {
        aclMask = IPentahoAclEntry.PERM_DELETE;
        break;
      }
      case IAclHolder.ACCESS_TYPE_ADMIN: {
        aclMask = IPentahoAclEntry.PERM_ADMINISTRATION;
        break;
      }
      default: {
        aclMask = IPentahoAclEntry.PERM_EXECUTE;
        break;
      }

    }
    return getAclVoter().hasAccess( session, aHolder, aclMask );
  }

  /**
   * Utility method for hydrating a Spring Authentication object (Principal) given just a user name. Note: The {@link
   * IUserRoleListService} will be consulted for the roles associated with this user.
   *
   * @param principalName the subject of this Authentication object
   * @return a Spring Authentication for the given user
   */
  @Override
  public Authentication createAuthentication( String principalName ) {

    //get 'anonymousUser' defined name from pentaho.xml's <anonymous-authentication> block
    String anonymousUser = PentahoSystem
      .getSystemSetting( "anonymous-authentication/anonymous-user", "anonymousUser" ); //$NON-NLS-1$//$NON-NLS-2$

    userDetailsService = getUserDetailsService();
    userRoleListService = getUserRoleListService();


    List<String> roles = new ArrayList<String>();

    // anonymousUser gets its roles from session
    if ( anonymousUser.equals( principalName ) ) {

      //get 'anonymous' defined role from pentaho.xml's <anonymous-authentication> block
      String anonymousRole = PentahoSystem
        .getSystemSetting( "anonymous-authentication/anonymous-role", "Anonymous" ); //$NON-NLS-1$//$NON-NLS-2$
      roles.add( anonymousRole );

    } else {

      // default (standard) role fetching via IUserRoleListService
      roles = userRoleListService.getRolesForUser( null, principalName );

    }

    if ( SecurityHelper.logger.isDebugEnabled() ) {
      SecurityHelper.logger.debug( "rolesForUser:" + roles ); //$NON-NLS-1$
    }

    GrantedAuthority[] grantedAuthorities = new GrantedAuthority[ roles.size() ];
    for ( int i = 0; i < roles.size(); i++ ) {
      grantedAuthorities[ i ] = new GrantedAuthorityImpl( roles.get( i ) );
    }

    User user = new User( principalName, "", true, true, true, true, grantedAuthorities );
    Authentication auth = new UsernamePasswordAuthenticationToken( user, null, grantedAuthorities );
    return auth;

  }

  @Override
  public Authentication getAuthentication() {
    return SecurityContextHolder.getContext().getAuthentication();
  }

  /**
   * Remove this method when data-access is JCR-branched
   *
   * @param ignoredSession
   * @param ignoredAllowAnonymous
   * @return
   */
  @Override
  public Authentication getAuthentication( IPentahoSession ignoredSession, boolean ignoredAllowAnonymous ) {
    return getAuthentication();
  }

  /**
   * Runs code as system with full privileges.
   */
  public <T> T runAsSystem( final Callable<T> callable ) throws Exception {
    String singleTenantAdmin = PentahoSystem.get( String.class, "singleTenantAdminUserName", null );
    IPentahoSession origSession = PentahoSessionHolder.getSession();

    Authentication origAuth = SecurityContextHolder.getContext().getAuthentication();

    StandaloneSession session = null;
    try {
      session = new StandaloneSession( singleTenantAdmin );
      session.setAuthenticated( singleTenantAdmin );

      // Set the session first or else the call to
      // createAuthentication will fail
      PentahoSessionHolder.setSession( session );

      // Now create the authentication
      Authentication auth = createAuthentication( singleTenantAdmin ); //$NON-NLS-1$
      SecurityContextHolder.getContext().setAuthentication( auth );

      // Invoke the delta.
      return callable.call();
    } finally {
      // Make sure to destroy the system session so we don't leak anything.
      if ( session != null ) {
        try {
          session.destroy();
        } catch ( Exception e ) {
          // We can safely ignore this.
          e.printStackTrace();
        }
      }
      // Reset the original session.
      PentahoSessionHolder.setSession( origSession );
      SecurityContextHolder.getContext().setAuthentication( origAuth );
    }
  }

  public ITenantedPrincipleNameResolver getTenantedUserNameUtils() {
    if ( tenantedUserNameUtils == null ) {
      tenantedUserNameUtils = PentahoSystem.get( ITenantedPrincipleNameResolver.class, "tenantedUserNameUtils", null );
    }
    return tenantedUserNameUtils;
  }

  public IAclVoter getAclVoter() {
    if ( aclVoter == null ) {
      aclVoter = PentahoSystem.get( IAclVoter.class );
    }
    return aclVoter;
  }

  public UserDetailsService getUserDetailsService() {
    if ( userDetailsService == null ) {
      userDetailsService = PentahoSystem.get( UserDetailsService.class );
    }
    return userDetailsService;
  }

  public IUserRoleListService getUserRoleListService() {
    if ( userRoleListService == null ) {
      userRoleListService = PentahoSystem.get( IUserRoleListService.class );
    }
    return userRoleListService;
  }
}
TOP

Related Classes of org.pentaho.platform.engine.security.SecurityHelper

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.