View Javadoc

1   /**
2    * This file Copyright (c) 2013-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.security.app.dialog.field;
35  
36  import info.magnolia.cms.core.Path;
37  import info.magnolia.jcr.util.NodeTypes;
38  import info.magnolia.jcr.util.NodeUtil;
39  
40  import java.util.Collection;
41  import java.util.LinkedHashMap;
42  
43  import javax.jcr.Node;
44  import javax.jcr.RepositoryException;
45  
46  import org.apache.commons.lang3.StringUtils;
47  
48  /**
49   * Represents an access control list as visualized in the UI with the access type separated from the path.
50   */
51  public class AccessControlList {
52  
53      public static final String PERMISSIONS_PROPERTY_NAME = "permissions";
54      public static final String PATH_PROPERTY_NAME = "path";
55  
56      public static final long ACCESS_TYPE_NODE = 1;
57      public static final long ACCESS_TYPE_CHILDREN = 2;
58      public static final long ACCESS_TYPE_NODE_AND_CHILDREN = ACCESS_TYPE_NODE | ACCESS_TYPE_CHILDREN;
59  
60      /**
61       * Used for testing equality of entries.
62       */
63      public static final class EntryKey {
64  
65          private long permissions;
66          private String path;
67  
68          public EntryKey(long permissions, String path) {
69              this.permissions = permissions;
70              this.path = path;
71          }
72  
73          @Override
74          public boolean equals(Object o) {
75              if (this == o) return true;
76              if (o == null || getClass() != o.getClass()) return false;
77  
78              EntryKey entryKey = (EntryKey) o;
79  
80              if (permissions != entryKey.permissions) return false;
81              if (!path.equals(entryKey.path)) return false;
82  
83              return true;
84          }
85  
86          @Override
87          public int hashCode() {
88              int result = (int) (permissions ^ (permissions >>> 32));
89              result = 31 * result + path.hashCode();
90              return result;
91          }
92      }
93  
94      /**
95       * An entry in the access control list.
96       */
97      public static class Entry {
98  
99          private long permissions;
100         private long accessType;
101         private String path;
102 
103         public Entry(long permissions, long accessType, String path) {
104             this.permissions = permissions;
105             this.accessType = accessType;
106             this.path = path;
107         }
108 
109         public long getPermissions() {
110             return permissions;
111         }
112 
113         public void setPermissions(long permissions) {
114             this.permissions = permissions;
115         }
116 
117         public long getAccessType() {
118             return accessType;
119         }
120 
121         public void setAccessType(long accessType) {
122             this.accessType = accessType;
123         }
124 
125         public String getPath() {
126             return path;
127         }
128 
129         public void setPath(String path) {
130             this.path = path;
131         }
132 
133         public void merge(Entry entry) {
134             accessType |= entry.getAccessType();
135         }
136 
137         public EntryKey createKey() {
138             return new EntryKey(permissions,  path);
139         }
140 
141         @Override
142         public boolean equals(Object o) {
143             if (this == o) return true;
144             if (!(o instanceof Entry)) return false;
145 
146             return createKey().equals(((Entry)o).createKey());
147         }
148 
149         @Override
150         public int hashCode() {
151             return createKey().hashCode();
152         }
153     }
154 
155     private LinkedHashMap<EntryKey, Entry> entries = new LinkedHashMap<EntryKey, Entry>();
156 
157     public Collection<Entry> getEntries() {
158         return entries.values();
159     }
160 
161     public void addEntry(Entry entry) {
162         EntryKey key = entry.createKey();
163         Entry existingEntry = entries.get(key);
164         if (existingEntry == null) {
165             entries.put(key, entry);
166         } else {
167             existingEntry.merge(entry);
168         }
169     }
170 
171     public void readEntries(Node aclNode) throws RepositoryException {
172         for (Node entryNode : NodeUtil.getNodes(aclNode)) {
173             readEntry(entryNode);
174         }
175     }
176 
177     public void readEntry(Node entryNode) throws RepositoryException {
178         addEntry(doGetEntryFromNode(entryNode));
179     }
180 
181     public Entry getEntryByNode(Node entryNode) throws RepositoryException {
182         Entry entry = doGetEntryFromNode(entryNode);
183         Entry existingEntry = entries.get(entry.createKey());
184         if (existingEntry != null) {
185             return existingEntry;
186         }
187         return entry;
188     }
189 
190     private Entry doGetEntryFromNode(Node entryNode) throws RepositoryException {
191         long permissions = entryNode.getProperty(PERMISSIONS_PROPERTY_NAME).getLong();
192         String path = entryNode.getProperty(PATH_PROPERTY_NAME).getString();
193 
194         long accessType;
195 
196         if (path.equals("/")) {
197             accessType = ACCESS_TYPE_NODE;
198         } else if (path.equals("/*")) {
199             accessType = ACCESS_TYPE_NODE_AND_CHILDREN;
200             path = "/";
201         } else if (path.endsWith("/*")) {
202             accessType = ACCESS_TYPE_CHILDREN;
203             path = StringUtils.substringBeforeLast(path, "/*");
204         } else {
205             accessType = ACCESS_TYPE_NODE;
206             path = StringUtils.removeEnd(path, "/");
207         }
208 
209         return new Entry(permissions, accessType, path);
210     }
211 
212     public void saveEntries(Node aclNode) throws RepositoryException {
213         for (Entry entry : entries.values()) {
214 
215             Node entryNode = aclNode.addNode(Path.getUniqueLabel(aclNode.getSession(), aclNode.getPath(), "0"), NodeTypes.ContentNode.NAME);
216 
217             String path = entry.getPath();
218             long permissions = entry.getPermissions();
219             long accessType = entry.getAccessType();
220 
221             if (path.equals("/")) {
222                 switch ((int) accessType) {
223                 case (int) ACCESS_TYPE_CHILDREN:
224                     path = "/*";
225                     break;
226                 case (int) ACCESS_TYPE_NODE:
227                     path = "/";
228                     break;
229                 case (int) ACCESS_TYPE_NODE_AND_CHILDREN:
230                     path = "/*";
231                     break;
232                 }
233             } else {
234                 switch ((int) accessType) {
235                 case (int) ACCESS_TYPE_CHILDREN:
236                     path += "/*";
237                     break;
238                 case (int) ACCESS_TYPE_NODE:
239                     break;
240                 case (int) ACCESS_TYPE_NODE_AND_CHILDREN:
241                     String nodeName = Path.getUniqueLabel(aclNode.getSession(), aclNode.getPath(), "0");
242                     Node extraEntry = aclNode.addNode(nodeName, NodeTypes.ContentNode.NAME);
243                     extraEntry.setProperty(PATH_PROPERTY_NAME, path + "/*");
244                     extraEntry.setProperty(PERMISSIONS_PROPERTY_NAME, permissions);
245                     break;
246                 }
247             }
248 
249             entryNode.setProperty(PERMISSIONS_PROPERTY_NAME, permissions);
250             entryNode.setProperty(PATH_PROPERTY_NAME, path);
251         }
252     }
253 }