001: /*
002: * Copyright 2007 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: */
013: package com.pentaho.security.acls;
014:
015: import java.util.ArrayList;
016: import java.util.Iterator;
017: import java.util.List;
018: import java.util.Set;
019:
020: import org.acegisecurity.GrantedAuthorityImpl;
021: import org.dom4j.Element;
022: import org.pentaho.core.system.ISystemSettings;
023: import org.pentaho.core.system.PentahoSystem;
024: import org.pentaho.core.util.XmlHelper;
025: import org.pentaho.messages.Messages;
026:
027: public class AclPublisher implements IAclPublisher {
028:
029: private static final String NOTHING = "NOTHING"; //$NON-NLS-1$
030:
031: private static final String ADMINISTRATION = "ADMINISTRATION"; //$NON-NLS-1$
032:
033: private static final String EXECUTE = "EXECUTE"; //$NON-NLS-1$
034:
035: private static final String EXECUTE_ADMINISTRATION = "EXECUTE_ADMINISTRATION"; //$NON-NLS-1$
036:
037: private static final String SUBSCRIBE = "SUBSCRIBE"; //$NON-NLS-1$
038:
039: private static final String CREATE = "CREATE"; //$NON-NLS-1$
040:
041: private static final String UPDATE = "UPDATE"; //$NON-NLS-1$
042:
043: private static final String DELETE = "DELETE"; //$NON-NLS-1$
044:
045: private static final String SUBSCRIBE_ADMINISTRATION = "SUBSCRIBE_ADMINISTRATION"; //$NON-NLS-1$
046:
047: private static final String EXECUTE_SUBSCRIBE = "EXECUTE_SUBSCRIBE"; //$NON-NLS-1$
048:
049: private static final String ADMIN_ALL = "ADMIN_ALL"; //$NON-NLS-1$
050:
051: private List defaultAcls = new ArrayList(4);
052:
053: /**
054: * Constructor that allows overriding the source of the default access
055: * control list. This constructor is mainly used from test cases.
056: *
057: * @param defAcls
058: */
059: public AclPublisher(List defAcls) {
060: this .defaultAcls = defAcls;
061: }
062:
063: /**
064: * Default constructor. This constructor reads the default access controls
065: * from the pentaho.xml. The pentaho.xml needs to have a section similar to
066: * the following: <br>
067: * <br>
068: * <acl-publisher><br>
069: * <!--<br>
070: * These acls are used when
071: * publishing from the file system. Every folder<br>
072: * gets these ACLS.
073: * Authenticated is a "default" role that everyone<br>
074: * gets when they're authenticated
075: * (be sure to setup your bean xml properly<br>
076: * for this to work).<br>
077: * --><br>
078: * <default-acls><br>
079: * <acl-entry role="Admin"
080: * acl="7" /> <!-- Admin users get all authorities --><br>
081: * <acl-entry role="cto"
082: * acl="7" /> <!-- CTO gets everything --><br>
083: * <acl-entry role="dev"
084: * acl="6" /> <!-- Dev gets execute/subscribe --><br>
085: * <acl-entry
086: * role="Authenticated" acl="2" /> <!-- Authenticated users get
087: * execute only --><br>
088: * </default-acls><br>
089: * </acl-publisher><br>
090: *
091: *
092: */
093: public AclPublisher() {
094: // Read the default ACLs from the pentaho.xml.
095: ISystemSettings settings = PentahoSystem.getSystemSettings();
096: List sysAcls = settings.getSystemSettings("default-acls/*"); //$NON-NLS-1$
097: defaultAcls.addAll(aclFromNodeList(sysAcls));
098: }
099:
100: private List aclFromNodeList(List sysAcls) {
101: List pentahoAclEntries = new ArrayList();
102:
103: for (int i = 0; i < sysAcls.size(); i++) {
104: Object obj = sysAcls.get(i);
105: Element defAcl = (Element) obj;
106: String aclRole = XmlHelper.getNodeText(
107: "@role", defAcl, null); //$NON-NLS-1$
108: String aclUser = XmlHelper.getNodeText(
109: "@user", defAcl, null); //$NON-NLS-1$
110: String aclStr = XmlHelper.getNodeText("@acl", defAcl, null); //$NON-NLS-1$
111:
112: int aclValue = -1; // Default to undefined
113: if (aclStr != null) {
114: if (NOTHING.equalsIgnoreCase(aclStr)) {
115: aclValue = 0;
116: } else if (EXECUTE.equalsIgnoreCase(aclStr)) {
117: aclValue = PentahoAclEntry.EXECUTE;
118: } else if (SUBSCRIBE.equalsIgnoreCase(aclStr)) {
119: aclValue = PentahoAclEntry.SUBSCRIBE;
120: } else if (EXECUTE_SUBSCRIBE.equalsIgnoreCase(aclStr)) {
121: aclValue = PentahoAclEntry.EXECUTE_SUBSCRIBE;
122: } else if (CREATE.equalsIgnoreCase(aclStr)) {
123: aclValue = PentahoAclEntry.CREATE;
124: } else if (UPDATE.equalsIgnoreCase(aclStr)) {
125: aclValue = PentahoAclEntry.UPDATE;
126: } else if (DELETE.equalsIgnoreCase(aclStr)) {
127: aclValue = PentahoAclEntry.DELETE;
128: } else if (ADMINISTRATION.equalsIgnoreCase(aclStr)) {
129: aclValue = PentahoAclEntry.ADMINISTRATION;
130: } else if (EXECUTE_ADMINISTRATION
131: .equalsIgnoreCase(aclStr)) {
132: aclValue = PentahoAclEntry.EXECUTE_ADMINISTRATION;
133: } else if (SUBSCRIBE_ADMINISTRATION
134: .equalsIgnoreCase(aclStr)) {
135: aclValue = PentahoAclEntry.SUBSCRIBE_ADMINISTRATION;
136: } else if (ADMIN_ALL.equalsIgnoreCase(aclStr)) {
137: aclValue = PentahoAclEntry.ADMIN_ALL;
138: }
139: }
140: if ((aclRole == null) && (aclUser == null)) {
141: throw new IllegalArgumentException(
142: Messages
143: .getErrorString("AclPublisher.ERROR_0001_DEFAULT_ACL_REQUIRES_USER_OR_ROLE")); //$NON-NLS-1$
144: }
145: if ((aclRole != null) && (aclUser != null)) {
146: throw new IllegalArgumentException(
147: Messages
148: .getErrorString("AclPublisher.ERROR_0002_DEFAULT_ACL_HAS_BOTH")); //$NON-NLS-1$
149: }
150: Object theAuth = null;
151: if (aclRole != null) {
152: theAuth = new GrantedAuthorityImpl(aclRole);
153: } else {
154: theAuth = aclUser;
155: }
156: pentahoAclEntries
157: .add(new PentahoAclEntry(theAuth, aclValue));
158: }
159:
160: return pentahoAclEntries;
161: }
162:
163: /**
164: * This method is called from the RDBMS repository publish method when
165: * publishing a file-based solution to the RDBMS repository. This
166: * implementation recurses through all the children of the specified
167: * <tt>IAclSolutionFile</tt>, and applies the default access controls
168: * only to the
169: *
170: * @param rootFile
171: *
172: * @see IAclSolutionFile
173: */
174: public void publishDefaultAcls(IAclSolutionFile rootFile) {
175: publishDefaultFolderAcls(rootFile);
176: publishOverrideAcls(rootFile);
177: }
178:
179: private void publishDefaultFolderAcls(IAclSolutionFile rootFile) {
180: if ((rootFile != null) && (rootFile.isDirectory())) {
181: // publish acl for folder if it doesn't already exist...
182: List accessControls = rootFile.getAccessControls();
183: if (accessControls.size() == 0) {
184: accessControls = getDefaultAclList();
185: rootFile.resetAccessControls(accessControls);
186: }
187: // Now, recurse through kids looking for folders...
188: Set kids = rootFile.getChildrenFiles();
189: if (kids != null) { // Doesn't have to have kids in it...
190: Iterator it = kids.iterator();
191: IAclSolutionFile aChild = null;
192: while (it.hasNext()) {
193: aChild = (IAclSolutionFile) it.next();
194: if (aChild.isDirectory()) {
195: publishDefaultFolderAcls(aChild); // Recursively publish ACLs
196: // for all child folders
197: }
198: }
199: }
200: }
201: }
202:
203: private void publishOverrideAcls(IAclSolutionFile rootFile) {
204: List accessControls = getOverrideAclList(rootFile.getFullPath());
205: if (accessControls.size() > 0
206: && (rootFile.getAccessControls().size() == 0 || (rootFile
207: .getAccessControls().containsAll(defaultAcls) && rootFile
208: .getAccessControls().size() == defaultAcls
209: .size()))) {
210: // We've got overridden acls and the file contains ONLY the default acls or NO acls at all
211: rootFile.resetAccessControls(accessControls);
212: }
213:
214: // Recurse through this files children
215: Iterator iter = rootFile.getChildrenFiles().iterator();
216: while (iter.hasNext()) {
217: publishOverrideAcls((IAclSolutionFile) iter.next());
218: }
219: }
220:
221: private List getOverrideAclList(String fullPath) {
222: ISystemSettings settings = PentahoSystem.getSystemSettings();
223: List overriddenFiles = settings
224: .getSystemSettings("overrides/file[@path=\"" + fullPath + "\"]/*"); //$NON-NLS-1$//$NON-NLS-2$
225: if (overriddenFiles.size() > 0) {
226: overriddenFiles = aclFromNodeList(overriddenFiles);
227: }
228: return overriddenFiles;
229: }
230:
231: /**
232: * Returns the list of default access controls. The returned list should be
233: * newly created, not simply the list inside the class. In other words, this
234: * should construct a new list, and all the default acls to it.
235: *
236: * @return A new list containing all the default access controls.
237: */
238: public List getDefaultAclList() {
239: List rtn = new ArrayList(defaultAcls.size());
240: rtn.addAll(defaultAcls);
241: return rtn;
242: }
243:
244: }
|