View Javadoc
1   /**
2    * This file Copyright (c) 2003-2014 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.admininterface.dialogs;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.gui.control.Button;
38  import info.magnolia.cms.gui.control.Edit;
39  import info.magnolia.cms.gui.control.Hidden;
40  import info.magnolia.cms.gui.control.Select;
41  import info.magnolia.cms.gui.dialog.DialogBox;
42  import info.magnolia.cms.gui.dialog.DialogButton;
43  import info.magnolia.cms.gui.dialog.DialogFactory;
44  import info.magnolia.cms.gui.misc.CssConstants;
45  import info.magnolia.cms.i18n.Messages;
46  import info.magnolia.cms.i18n.MessagesManager;
47  import info.magnolia.cms.util.ContentUtil;
48  import info.magnolia.module.admininterface.AdminInterfaceModule;
49  import info.magnolia.module.admininterface.config.AclTypeConfiguration;
50  import info.magnolia.module.admininterface.config.PermissionConfiguration;
51  import info.magnolia.module.admininterface.config.RepositoryConfiguration;
52  import info.magnolia.module.admininterface.config.SecurityConfiguration;
53  import info.magnolia.repository.RepositoryConstants;
54  
55  import java.io.IOException;
56  import java.io.PrintWriter;
57  import java.io.Writer;
58  import java.util.Iterator;
59  
60  import javax.jcr.RepositoryException;
61  import javax.servlet.http.HttpServletRequest;
62  import javax.servlet.http.HttpServletResponse;
63  
64  import org.apache.commons.collections.map.ListOrderedMap;
65  import org.apache.commons.lang.StringUtils;
66  
67  
68  /**
69   * Builds a dialog control for ACLs.
70   * @version $Id:RolesACLPage.java 2516 2006-03-31 13:08:03Z philipp $
71   */
72  public class ACLSDialogControl extends DialogBox {
73  
74      private static final String CSS_ACL_DIV = "aclDynamicTable";
75  
76      private SecurityConfiguration securityConf = AdminInterfaceModule.getInstance().getSecurityConfiguration();
77  
78      private static String getHtmlRowInner(String dynamicTable, RepositoryConfiguration repoConf) {
79          boolean small = true;
80          Messages msgs = MessagesManager.getMessages();
81  
82          Select accessRight = new Select() {
83  
84              @Override
85              public String getName() {
86                      return super.getName().replace("'", "'");
87                  }
88          };
89  
90          accessRight.setSaveInfo(false);
91          accessRight.setName("'+prefix+'AccessRight");
92          accessRight.setCssClass("mgnlDialogControlSelect");
93  
94          for (Iterator<PermissionConfiguration> iter = repoConf.getPermissions().iterator(); iter.hasNext();) {
95              PermissionConfiguration permission = iter.next();
96              accessRight.setOptions(escapeJs(permission.getI18nLabel()), Long.toString(permission.getValue()));
97          }
98  
99          accessRight.setValue("' + object.accessRight + '");
100 
101         Select accessType = new Select(){
102 
103             @Override
104             public String getName() {
105                 return super.getName().replace("&#039;", "'");
106             }
107         };
108         accessType.setSaveInfo(false);
109         accessType.setName("'+prefix+'AccessType");
110         accessType.setCssClass("mgnlDialogControlSelect");
111 
112         for (Iterator<AclTypeConfiguration> iter = repoConf.getAclTypes().iterator(); iter.hasNext();) {
113             AclTypeConfiguration patternType = iter.next();
114             accessType.setOptions(escapeJs(patternType.getI18nLabel()), String.valueOf(patternType.getType()));
115         }
116 
117         accessType.setValue("' + object.accessType + '");
118 
119         Edit path = new Edit(){
120 
121             @Override
122             public String getName() {
123                 return super.getName().replace("&#039;", "'");
124             }
125         };
126         path.setSaveInfo(false);
127         path.setName("'+prefix+'Path");
128         path.setValue("'+object.path+'");
129         path.setCssClass(CssConstants.CSSCLASS_EDIT);
130         path.setCssStyles("width", "100%");
131 
132         Button choose = null;
133         if(repoConf.isChooseButton()){
134             choose = new Button();
135             choose.setLabel(escapeJs(msgs.get("buttons.choose")));
136             choose.setOnclick("aclChoose(\\''+prefix+'\\',\\'" + repoConf.getName() + "\\');");
137             choose.setSmall(small);
138         }
139 
140         Button delete = new Button();
141         delete.setLabel(escapeJs(msgs.get("buttons.delete")));
142         delete.setOnclick(dynamicTable + ".del('+index+');");
143         delete.setSmall(small);
144 
145         StringBuilder html = new StringBuilder();
146         // set as table since ie/win does not support setting of innerHTML of a
147         // tr
148         html.append("<table cellpadding=\"0\" cellspacing=\"0\" width=\"100%\"><tr>");
149         html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(accessRight.getHtml()).append("</td>");
150         html.append("<td width=\"1\" class=\"mgnlDialogBoxInput\"></td>");
151 
152         // do we add the type selection dropdown?
153         if(!repoConf.getAclTypes().isEmpty()){
154             html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(accessType.getHtml()).append("</td>");
155             html.append("<td width=\"1\"></td>");
156         }
157         else {
158             html.append("<input type=\"hidden\" id=\"' + prefix + 'AccessType\" name=\"' + prefix + 'AccessType\" value=\"sub\"/>");
159         }
160 
161         html.append("<td width=\"100%\"class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(path.getHtml()).append("</td>");
162         html.append("<td width=\"1\"></td>");
163 
164         if (choose != null) {
165             html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(choose.getHtml()).append("</td>");
166             html.append("<td width=\"1\"></td>");
167         }
168 
169         html.append("<td width=\"1\" class=\"" + CssConstants.CSSCLASS_EDITWITHBUTTON + "\">").append(delete.getHtml()).append("</td>");
170         html.append("</tr></table>");
171 
172         return html.toString();
173     }
174 
175     @Override
176     public void drawHtml(Writer w) throws IOException {
177         PrintWriter out = (PrintWriter) w;
178         this.drawHtmlPre(out);
179         renderACLS(out);
180         this.drawHtmlPost(out);
181 
182     }
183 
184     protected void renderACLS(PrintWriter out) throws IOException {
185         Messages msgs = MessagesManager.getMessages();
186         Content role = getStorageNode();
187         HttpServletRequest request = this.getRequest();
188         HttpServletResponse response = this.getResponse();
189 
190         // select the repository
191         Select repositorySelect = getRepositorySelect();
192 
193         out.print(repositorySelect.getHtml());
194         out.print("<p><p/>");
195 
196         // process with the real existing repositories
197         for (Iterator<RepositoryConfiguration> iter = securityConf.getVisibleRepositories().iterator(); iter.hasNext();) {
198             RepositoryConfiguration repositoryConf = iter.next();
199             try {
200                 writeRepositoryTable(request, response, msgs, out, role, repositoryConf);
201             }
202             catch (RepositoryException e) {
203                 throw new RuntimeException("can't list ", e);
204             }
205         }
206 
207         // out.print("<p>&nbsp;<p>&nbsp;<p>&nbsp;<input type=\"button\" onclick=\"aclChangeRepository('website')\">");
208         out.println("<script type=\"text/javascript\">aclChangeRepository('website');</script>");
209     }
210 
211     /**
212      * @param request
213      * @param out
214      * @param role
215      * @throws RepositoryException
216      * @throws IOException
217      */
218     protected void writeRepositoryTable(HttpServletRequest request,  HttpServletResponse response, Messages msgs,
219         PrintWriter out, Content role, RepositoryConfiguration repoConf) throws RepositoryException, IOException {
220         String tableName = "acl" + repoConf.getName() + "Table";
221         String dynamicTableName = "acl" + repoConf.getName() + "DynamicTable";
222         String hiddenFieldName = "acl" + repoConf.getName() + "List";
223 
224         out.println("<div id=\"acl" + repoConf.getName() + "Div\" class=\"" + CSS_ACL_DIV + "\">"); //$NON-NLS-3$
225         out.println(new Hidden(hiddenFieldName, StringUtils.EMPTY, false).getHtml());
226 
227         // the table
228         out.println("<table id=\""
229             + tableName
230             + "\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td></td></tr></table>");
231 
232         // add button
233         out.println("<table width=\"100%\">");
234         DialogButton add = DialogFactory.getDialogButtonInstance(request, response, null, null);
235         add.setBoxType(DialogBox.BOXTYPE_1COL);
236         add.setConfig("buttonLabel", msgs.get("buttons.add"));
237         add.setConfig("onclick", dynamicTableName + ".addNew();");
238         add.drawHtml(out);
239         out.println("</table>");
240 
241         out.println("</div>");
242 
243         out.println("<script type=\"text/javascript\">");
244         // register the repository
245         out.println("aclRepositories[aclRepositories.length]= '" + repoConf.getName() + "';");
246 
247         // make renderer function
248         out.println("function acl" + repoConf.getName() + "RenderFunction(cell, prefix, index, object)");
249         out.println("{");
250 
251         // get some debug informations
252         out.println("mgnlDebug('acl" + repoConf.getName() + "RenderFunction: prefix = ' + prefix, 'acl', object)");
253         out.println("cell.innerHTML= '" + getHtmlRowInner(dynamicTableName, repoConf) + "';\n");
254         out.println("document.getElementById(prefix + 'AccessType').value = object.accessType;\n");
255         out.println("document.getElementById(prefix + 'AccessRight').value = object.accessRight;\n");
256 
257         out.println("}");
258 
259         // create the dynamicTable
260         out.println(dynamicTableName + " = new MgnlDynamicTable('"
261             + tableName
262             + "',document.getElementById('mgnlFormMain')."
263             + hiddenFieldName
264             + ", aclGetNewPermissionObject, aclGetPermissionObject, acl"
265             + repoConf.getName()
266             + "RenderFunction, null);");
267 
268         // add existing acls to table (by js, so the same mechanism as at
269         // adding rows can be used)
270         addExistingAclToTable(out, role, dynamicTableName, repoConf);
271 
272         out.println("</script>");
273     }
274 
275     /**
276      * @param out
277      * @param role
278      */
279     private void addExistingAclToTable(PrintWriter out, Content role, String dynamicTableName,
280         RepositoryConfiguration repoConf) {
281         // keeps acls per path
282         ACLS acls = new ACLS();
283 
284         Content aclsNode = ContentUtil.getContent(role, "acl_" + repoConf.getName());
285         if (aclsNode == null || aclsNode.getChildren().size() == 0) {
286             out.println(dynamicTableName + ".addNew();");
287             return;
288         }
289 
290         Iterator it = aclsNode.getChildren().iterator();
291         while (it.hasNext()) {
292             Content c = (Content) it.next();
293             String path = c.getNodeData("path").getString();
294             String accessRight = c.getNodeData("permissions").getString();
295             acls.register(path, Integer.valueOf(accessRight).intValue(), repoConf);
296         }
297 
298         for (Iterator<ACL> iter = acls.values().iterator(); iter.hasNext();) {
299             ACL acl = iter.next();
300             out.println(dynamicTableName + ".add({accessRight:"
301                 + acl.accessRight
302                 + ",accessType:'"
303                 + acl.type
304                 + "',path:'"
305                 + acl.path
306                 + "'});");
307         }
308     }
309 
310     private Select getRepositorySelect() {
311         Select repositorySelect = new Select();
312         repositorySelect.setName("aclRepository");
313         repositorySelect.setCssClass("mgnlDialogControlSelect");
314         repositorySelect.setEvent("onchange", "aclChangeRepository(this.value)");
315         repositorySelect.setSaveInfo(false);
316         repositorySelect.setValue(RepositoryConstants.WEBSITE);
317 
318         for (Iterator<RepositoryConfiguration> iter = securityConf.getVisibleRepositories().iterator(); iter.hasNext();) {
319             RepositoryConfiguration repoConf = iter.next();
320             repositorySelect.setOptions(repoConf.getI18nLabel(), repoConf.getName());
321         }
322         return repositorySelect;
323     }
324 
325     private static String escapeJs(String value) {
326         return StringUtils.replace(value, "'", "\\'");
327     }
328 
329     /**
330      * A concrete gui acl
331      * @author Philipp Bracher
332      * @version $Revision$ ($Author$)
333      */
334     protected class ACL {
335 
336         int type = 0;
337 
338         String path;
339 
340         int accessRight;
341 
342         void registerEntry(String path) {
343             if ("/*".equals(path)) {
344                 type = AclTypeConfiguration.TYPE_ALL;
345             }
346             else if (path.endsWith("/*")) {
347                 type = type | AclTypeConfiguration.TYPE_SUBS;
348             }
349             else {
350                 type = type | AclTypeConfiguration.TYPE_THIS;
351             }
352         }
353     }
354 
355     /**
356      * Used to create the gui values out of the entries in the repository
357      * @version $Revision$ ($Author$)
358      */
359     protected class ACLS extends ListOrderedMap {
360 
361         /**
362          * Register an entry
363          * @param path the not cleaned path
364          * @param accessRight the access right
365          */
366         void register(String path, int accessRight, RepositoryConfiguration repoConf) {
367             String cleanPath = repoConf.toViewPattern(path);
368 
369             String key = cleanPath + ":" + accessRight;
370             if (!this.containsKey(key)) {
371                 ACL acl = new ACL();
372                 acl.path = cleanPath;
373                 acl.accessRight = accessRight;
374                 this.put(key, acl);
375             }
376             ((ACL) this.get(key)).registerEntry(path);
377         }
378     }
379 
380 }