/* * 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 - 2016 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.repository.usersettings; import org.pentaho.platform.api.engine.IAuthorizationPolicy; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.usersettings.IAnyUserSettingService; import org.pentaho.platform.api.usersettings.IUserSettingService; import org.pentaho.platform.api.usersettings.pojo.IUserSetting; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.security.SecurityHelper; import org.pentaho.platform.repository.usersettings.pojo.UserSetting; import org.pentaho.platform.repository2.ClientRepositoryPaths; import org.pentaho.platform.security.policy.rolebased.actions.AdministerSecurityAction; import org.pentaho.platform.security.policy.rolebased.actions.RepositoryCreateAction; import org.pentaho.platform.security.policy.rolebased.actions.RepositoryReadAction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; public class UserSettingService implements IAnyUserSettingService, IUserSettingService { public static final String SETTING_PREFIX = "_USERSETTING"; //$NON-NLS-1$ IPentahoSession session = null; private static final byte[] lock = new byte[0]; protected IUnifiedRepository repository; private Logger log = LoggerFactory.getLogger( getClass() ); public UserSettingService( IUnifiedRepository repository ) { this.repository = repository; } public void init( IPentahoSession session ) { this.session = session; } // //////////////////////////////////////////////////////////////////////////////////////////////// // GENERIC/ADMIN METHODS // //////////////////////////////////////////////////////////////////////////////////////////////// // delete all settings for a given user public void deleteUserSettings() { String homePath = ClientRepositoryPaths.getUserHomeFolderPath( PentahoSessionHolder.getSession().getName() ); Serializable id = repository.getFile( homePath ).getId(); Map<String, Serializable> fileMetadata = repository.getFileMetadata( id ); Map<String, Serializable> finalMetadata = new HashMap<String, Serializable>( fileMetadata.size() ); for ( Map.Entry<String, Serializable> entry : fileMetadata.entrySet() ) { String key = entry.getKey(); if ( !key.startsWith( SETTING_PREFIX ) ) { finalMetadata.put( key, entry.getValue() ); } } repository.setFileMetadata( id, finalMetadata ); } // //////////////////////////////////////////////////////////////////////////////////////////////// // USER SETTINGS METHODS // //////////////////////////////////////////////////////////////////////////////////////////////// private static UserSetting createSetting( String name, Serializable value ) { return createSetting( name, value.toString() ); } private static UserSetting createSetting( String name, String value ) { UserSetting setting = new UserSetting(); setting.setSettingName( name ); setting.setSettingValue( value ); return setting; } public List<IUserSetting> getUserSettings() { // get the global settings and the user settings // merge unseen global settings into the user settings list List<IUserSetting> userSettings = new ArrayList<IUserSetting>(); String tentantHomePath = ClientRepositoryPaths.getEtcFolderPath(); Serializable tenantHomeId = repository.getFile( tentantHomePath ).getId(); Map<String, Serializable> tenantMetadata = repository.getFileMetadata( tenantHomeId ); for ( Map.Entry<String, Serializable> entry : tenantMetadata.entrySet() ) { String key = entry.getKey(); if ( key.startsWith( SETTING_PREFIX ) ) { UserSetting setting = createSetting( key.substring( SETTING_PREFIX.length() ), entry.getValue() ); userSettings.add( setting ); } } String homePath = ClientRepositoryPaths.getUserHomeFolderPath( PentahoSessionHolder.getSession().getName() ); Serializable userHomeId = repository.getFile( homePath ).getId(); Map<String, Serializable> userMetadata = repository.getFileMetadata( userHomeId ); for ( Map.Entry<String, Serializable> entry : userMetadata.entrySet() ) { String key = entry.getKey(); if ( key.startsWith( SETTING_PREFIX ) ) { UserSetting setting = createSetting( key.substring( SETTING_PREFIX.length() ), entry.getValue() ); // see if a global setting exists which will be overridden if ( userSettings.contains( setting ) ) { userSettings.remove( setting ); } userSettings.add( setting ); } } return userSettings; } public IUserSetting getUserSetting( String settingName, String defaultValue ) { // if the user does not have the setting, check if a global setting exists boolean hasAuth = PentahoSessionHolder.getSession().getAttribute( "SPRING_SECURITY_CONTEXT" ) != null; if ( hasAuth ) { try { String homePath = ClientRepositoryPaths.getUserHomeFolderPath( PentahoSessionHolder.getSession().getName() ); Serializable userHomeId = repository.getFile( homePath ).getId(); Map<String, Serializable> userMetadata = repository.getFileMetadata( userHomeId ); for ( Map.Entry<String, Serializable> entry : userMetadata.entrySet() ) { String key = entry.getKey(); if ( key.startsWith( SETTING_PREFIX ) ) { String settingFromKey = key.substring( SETTING_PREFIX.length() ); if ( settingFromKey.equals( settingName ) ) { return createSetting( settingFromKey, entry.getValue() ); } } } String tentantHomePath = ClientRepositoryPaths.getEtcFolderPath(); Serializable tenantHomeId = repository.getFile( tentantHomePath ).getId(); Map<String, Serializable> tenantMetadata = repository.getFileMetadata( tenantHomeId ); for ( Map.Entry<String, Serializable> entry : tenantMetadata.entrySet() ) { String key = entry.getKey(); if ( key.startsWith( SETTING_PREFIX ) ) { String settingFromKey = key.substring( SETTING_PREFIX.length() ); if ( settingFromKey.equals( settingName ) ) { return createSetting( settingFromKey, entry.getValue() ); } } } } catch ( Throwable ignored ) { // if anything goes wrong with authentication (anonymous user) or permissions // just return the default value, if we continue to log these errors (like on before Login) // we'll see *many* errors in the logs which are not helpful } } return createSetting( settingName, defaultValue ); } public void setUserSetting( String settingName, String settingValue ) { String name = PentahoSessionHolder.getSession().getName(); String homePath = ClientRepositoryPaths.getUserHomeFolderPath( name ); synchronized ( lock ) { final Serializable id = repository.getFile( homePath ).getId(); final Map<String, Serializable> fileMetadata = repository.getFileMetadata( id ); fileMetadata.put( SETTING_PREFIX + settingName, settingValue ); try { SecurityHelper.getInstance().runAsSystem( new Callable<Void>() { @Override public Void call() throws Exception { repository.setFileMetadata( id, fileMetadata ); return null; } } ); } catch ( Exception e ) { if ( log.isDebugEnabled() ) { log.debug( "Error storing user setting for user: " + name + ", setting: " + settingName + ", value: " + settingValue, e ); } log.error( "Error storing user setting", e ); } } } @Override public void deleteUserSettings( String username ) throws SecurityException { if( canAdminister() ) { String homePath = ClientRepositoryPaths.getUserHomeFolderPath( username ); Serializable id = repository.getFile( homePath ).getId(); Map<String, Serializable> fileMetadata = repository.getFileMetadata( id ); Map<String, Serializable> finalMetadata = new HashMap<String, Serializable>( fileMetadata.size() ); for ( Map.Entry<String, Serializable> entry : fileMetadata.entrySet() ) { String key = entry.getKey(); if ( !key.startsWith( SETTING_PREFIX ) ) { finalMetadata.put( key, entry.getValue() ); } } repository.setFileMetadata( id, finalMetadata ); } else { throw new SecurityException( "Unauthorized User" ); } } @Override public List<IUserSetting> getUserSettings( String username ) throws SecurityException { // if the user does not have the setting, check if a global setting exists List<IUserSetting> userSettings = new ArrayList<>(); if ( canAdminister() ) { try { String homePath = ClientRepositoryPaths.getUserHomeFolderPath( username ); Serializable userHomeId = repository.getFile( homePath ).getId(); Map<String, Serializable> userMetadata = repository.getFileMetadata( userHomeId ); for ( Map.Entry<String, Serializable> entry : userMetadata.entrySet() ) { String key = entry.getKey(); if ( key.startsWith( SETTING_PREFIX ) ) { String settingFromKey = key.substring( SETTING_PREFIX.length() ); userSettings.add( createSetting( settingFromKey, entry.getValue() ) ); } } } catch ( Throwable ignored ) { // if anything goes wrong with authentication (anonymous user) or permissions // just return the default value, if we continue to log these errors (like on before Login) // we'll see *many* errors in the logs which are not helpful } } else { throw new SecurityException( "Unauthorized User" ); } return userSettings; } @Override public IUserSetting getUserSetting( String username, String settingName, String defaultValue ) throws SecurityException { // if the user does not have the setting, check if a global setting exists if ( canAdminister() ) { try { String homePath = ClientRepositoryPaths.getUserHomeFolderPath( PentahoSessionHolder.getSession().getName() ); Serializable userHomeId = repository.getFile( homePath ).getId(); Map<String, Serializable> userMetadata = repository.getFileMetadata( userHomeId ); for ( Map.Entry<String, Serializable> entry : userMetadata.entrySet() ) { String key = entry.getKey(); if ( key.startsWith( SETTING_PREFIX ) ) { String settingFromKey = key.substring( SETTING_PREFIX.length() ); if ( settingFromKey.equals( settingName ) ) { return createSetting( settingFromKey, entry.getValue() ); } } } } catch ( Throwable ignored ) { // if anything goes wrong with authentication (anonymous user) or permissions // just return the default value, if we continue to log these errors (like on before Login) // we'll see *many* errors in the logs which are not helpful } } else { throw new SecurityException( "Unauthorized User" ); } return createSetting( settingName, defaultValue ); } @Override public void setUserSetting( String username, String settingName, String settingValue ) throws SecurityException { if ( canAdminister() ) { String homePath = ClientRepositoryPaths.getUserHomeFolderPath( username ); synchronized ( lock ) { final Serializable id = repository.getFile( homePath ).getId(); final Map<String, Serializable> fileMetadata = repository.getFileMetadata( id ); fileMetadata.put( SETTING_PREFIX + settingName, settingValue ); try { SecurityHelper.getInstance().runAsSystem( new Callable<Void>() { @Override public Void call() throws Exception { repository.setFileMetadata( id, fileMetadata ); return null; } } ); } catch ( Exception e ) { if ( log.isDebugEnabled() ) { log.debug( "Error storing user setting for user: " + username + ", setting: " + settingName + ", value: " + settingValue, e ); } log.error( "Error storing user setting", e ); } } } else { throw new SecurityException( "Unauthorized User" ); } } // //////////////////////////////////////////////////////////////////////////////////////////////// // GLOBAL USER SETTINGS METHODS // //////////////////////////////////////////////////////////////////////////////////////////////// public IUserSetting getGlobalUserSetting( String settingName, String defaultValue ) { String tentantHomePath = ClientRepositoryPaths.getEtcFolderPath(); Serializable tenantHomeId = repository.getFile( tentantHomePath ).getId(); Map<String, Serializable> tenantMetadata = repository.getFileMetadata( tenantHomeId ); String key = SETTING_PREFIX + settingName; Serializable value = tenantMetadata.get( key ); if ( value != null ) { return createSetting( settingName, value.toString() ); } return createSetting( settingName, defaultValue ); } public List<IUserSetting> getGlobalUserSettings() { String tentantHomePath = ClientRepositoryPaths.getEtcFolderPath(); Serializable tenantHomeId = repository.getFile( tentantHomePath ).getId(); Map<String, Serializable> tenantMetadata = repository.getFileMetadata( tenantHomeId ); List<IUserSetting> userSettings = new ArrayList<IUserSetting>( tenantMetadata.size() ); for ( Map.Entry<String, Serializable> entry : tenantMetadata.entrySet() ) { String key = entry.getKey(); if ( key.startsWith( SETTING_PREFIX ) ) { userSettings.add( createSetting( key.substring( SETTING_PREFIX.length() ), entry.getValue() ) ); } } return userSettings; } public void setGlobalUserSetting( String settingName, String settingValue ) { if ( canAdminister() ) { String tentantHomePath = ClientRepositoryPaths.getEtcFolderPath(); Serializable tenantHomeId = repository.getFile( tentantHomePath ).getId(); Map<String, Serializable> tenantMetadata = repository.getFileMetadata( tenantHomeId ); tenantMetadata.put( SETTING_PREFIX + settingName, settingValue ); repository.setFileMetadata( tenantHomeId, tenantMetadata ); } } protected boolean canAdminister() { IAuthorizationPolicy policy = PentahoSystem.get( IAuthorizationPolicy.class ); return policy.isAllowed( RepositoryReadAction.NAME ) && policy.isAllowed( RepositoryCreateAction.NAME ) && ( policy.isAllowed( AdministerSecurityAction.NAME ) ); } }