/* * 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 - 2008 Pentaho Corporation. All rights reserved. * */ package org.pentaho.platform.engine.security.acls; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.dom4j.Element; import org.pentaho.platform.api.engine.IAclPublisher; import org.pentaho.platform.api.engine.IAclSolutionFile; import org.pentaho.platform.api.engine.IPentahoAclEntry; import org.pentaho.platform.api.engine.IPermissionMask; import org.pentaho.platform.api.engine.IPermissionRecipient; import org.pentaho.platform.api.engine.ISystemSettings; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.security.SpringSecurityPermissionMgr; import org.pentaho.platform.engine.security.SimplePermissionMask; import org.pentaho.platform.engine.security.SimpleRole; import org.pentaho.platform.engine.security.SimpleUser; import org.pentaho.platform.engine.security.messages.Messages; import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper; public class AclPublisher implements IAclPublisher { private static final String NOTHING = "NOTHING"; //$NON-NLS-1$ private static final String ADMINISTRATION = "ADMINISTRATION"; //$NON-NLS-1$ private static final String EXECUTE = "EXECUTE"; //$NON-NLS-1$ private static final String EXECUTE_ADMINISTRATION = "EXECUTE_ADMINISTRATION"; //$NON-NLS-1$ private static final String SUBSCRIBE = "SUBSCRIBE"; //$NON-NLS-1$ private static final String CREATE = "CREATE"; //$NON-NLS-1$ private static final String UPDATE = "UPDATE"; //$NON-NLS-1$ private static final String DELETE = "DELETE"; //$NON-NLS-1$ private static final String SUBSCRIBE_ADMINISTRATION = "SUBSCRIBE_ADMINISTRATION"; //$NON-NLS-1$ private static final String EXECUTE_SUBSCRIBE = "EXECUTE_SUBSCRIBE"; //$NON-NLS-1$ /** * @deprecated Do not use this constant; instead use FULL_CONTROL * Previously referenced a static list of access controls */ @Deprecated private static final String ADMIN_ALL = "ADMIN_ALL"; //$NON-NLS-1$ private static final String FULL_CONTROL = "FULL_CONTROL"; //$NON-NLS-1$ private Map<IPermissionRecipient, IPermissionMask> defaultAcls = Collections.EMPTY_MAP; /** * Constructor that allows overriding the source of the default access * control list. This constructor is mainly used from test cases. * * @param defAcls */ public AclPublisher(final Map<IPermissionRecipient, IPermissionMask> defAcls) { this.defaultAcls = new LinkedHashMap<IPermissionRecipient, IPermissionMask>(defAcls); } /** * Default constructor. This constructor reads the default access controls * from the pentaho.xml. The pentaho.xml needs to have a section similar to * the following: <br> * <br> *   <acl-publisher><br> *     <!--<br> *        These acls are used when * publishing from the file system. Every folder<br> *        gets these ACLS. * Authenticated is a "default" role that everyone<br> *        gets when they're authenticated * (be sure to setup your bean xml properly<br> *        for this to work).<br> *     --><br> *     <default-acls><br> *        <acl-entry role="Admin" * acl="7" /> <!-- Admin users get all authorities --><br> *        <acl-entry role="cto" * acl="7" /> <!-- CTO gets everything --><br> *        <acl-entry role="dev" * acl="6" /> <!-- Dev gets execute/subscribe --><br> *        <acl-entry * role="Authenticated" acl="2" /> <!-- Authenticated users get * execute only --><br> *     </default-acls><br> *   </acl-publisher><br> * * */ public AclPublisher() { // Read the default ACLs from the pentaho.xml. ISystemSettings settings = PentahoSystem.getSystemSettings(); List sysAcls = settings.getSystemSettings("default-acls/*"); //$NON-NLS-1$ defaultAcls = aclFromNodeList(sysAcls); } @SuppressWarnings("deprecation") private Map<IPermissionRecipient, IPermissionMask> aclFromNodeList(final List sysAcls) { Map<IPermissionRecipient, IPermissionMask> pentahoAclEntries = new LinkedHashMap<IPermissionRecipient, IPermissionMask>(); for (int i = 0; i < sysAcls.size(); i++) { Object obj = sysAcls.get(i); Element defAcl = (Element) obj; String aclRole = XmlDom4JHelper.getNodeText("@role", defAcl, null); //$NON-NLS-1$ String aclUser = XmlDom4JHelper.getNodeText("@user", defAcl, null); //$NON-NLS-1$ String aclStr = XmlDom4JHelper.getNodeText("@acl", defAcl, null); //$NON-NLS-1$ if ((aclRole == null) && (aclUser == null)) { throw new IllegalArgumentException(Messages.getInstance() .getErrorString("AclPublisher.ERROR_0001_DEFAULT_ACL_REQUIRES_USER_OR_ROLE")); //$NON-NLS-1$ } if ((aclRole != null) && (aclUser != null)) { throw new IllegalArgumentException(Messages.getInstance().getErrorString("AclPublisher.ERROR_0002_DEFAULT_ACL_HAS_BOTH")); //$NON-NLS-1$ } int aclValue = -1; // Default to undefined if (aclStr != null) { if (AclPublisher.NOTHING.equalsIgnoreCase(aclStr)) { aclValue = 0; } else if (AclPublisher.EXECUTE.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_EXECUTE; } else if (AclPublisher.SUBSCRIBE.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_SUBSCRIBE; } else if (AclPublisher.EXECUTE_SUBSCRIBE.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_EXECUTE_SUBSCRIBE; } else if (AclPublisher.CREATE.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_CREATE; } else if (AclPublisher.UPDATE.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_UPDATE; } else if (AclPublisher.DELETE.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_DELETE; } else if (AclPublisher.ADMINISTRATION.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_ADMINISTRATION; } else if (AclPublisher.EXECUTE_ADMINISTRATION.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_EXECUTE_ADMINISTRATION; } else if (AclPublisher.SUBSCRIBE_ADMINISTRATION.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_SUBSCRIBE_ADMINISTRATION; } else if (AclPublisher.ADMIN_ALL.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_ADMIN_ALL; } else if (AclPublisher.FULL_CONTROL.equalsIgnoreCase(aclStr)) { aclValue = IPentahoAclEntry.PERM_FULL_CONTROL; } else { continue; } } if (aclUser != null) { pentahoAclEntries.put(new SimpleUser(aclUser), new SimplePermissionMask(aclValue)); } else { pentahoAclEntries.put(new SimpleRole(aclRole), new SimplePermissionMask(aclValue)); } } return pentahoAclEntries; } /** * This method is called from the RDBMS repository publish method when * publishing a file-based solution to the RDBMS repository. This * implementation recurses through all the children of the specified * <tt>IAclSolutionFile</tt>, and applies the default access controls * only to the * * @param rootFile * * @see IAclSolutionFile */ public void publishDefaultAcls(final IAclSolutionFile rootFile) { publishDefaultFolderAcls(rootFile); publishOverrideAcls(rootFile); } private void publishDefaultFolderAcls(final IAclSolutionFile rootFile) { if ((rootFile != null) && (rootFile.isDirectory())) { // publish acl for folder if it doesn't already exist... if (rootFile.getAccessControls().size() == 0) { SpringSecurityPermissionMgr.instance().setPermissions(defaultAcls, rootFile); } // Now, recurse through kids looking for folders... Set kids = rootFile.getChildrenFiles(); if (kids != null) { // Doesn't have to have kids in it... Iterator it = kids.iterator(); IAclSolutionFile aChild = null; while (it.hasNext()) { // Recursively publish ACLs for all child folders aChild = (IAclSolutionFile)it.next(); if (aChild.isDirectory()) { publishDefaultFolderAcls(aChild); } } } } } private void publishOverrideAcls(final IAclSolutionFile rootFile) { Map<IPermissionRecipient, IPermissionMask> overridePerms = getOverrideAclList(rootFile.getFullPath()); if (overridePerms.size() > 0) { Map<IPermissionRecipient, IPermissionMask> currentPerms = SpringSecurityPermissionMgr.instance().getPermissions(rootFile); if ((currentPerms.size() == 0) || (currentPerms.size() == defaultAcls.size()) && (currentPerms.entrySet().containsAll(defaultAcls.entrySet()))) { // We've got overridden acls and the file contains ONLY the default acls or NO acls at all SpringSecurityPermissionMgr.instance().setPermissions(overridePerms, rootFile); } } // Recurse through this files children if (rootFile.isDirectory()) { Iterator iter = rootFile.getChildrenFiles().iterator(); while (iter.hasNext()) { publishOverrideAcls((IAclSolutionFile) iter.next()); } } } private Map<IPermissionRecipient, IPermissionMask> getOverrideAclList(final String fullPath) { ISystemSettings settings = PentahoSystem.getSystemSettings(); return aclFromNodeList(settings.getSystemSettings("overrides/file[@path=\"" + fullPath + "\"]/*")); //$NON-NLS-1$//$NON-NLS-2$; } /** * Returns an unmodifiable map of default access controls. * * @return An unmodifiable map containing all the default access controls. */ public Map<IPermissionRecipient, IPermissionMask> getDefaultAclList() { return Collections.unmodifiableMap(defaultAcls); } }