View Javadoc
1   /**
2    * This file Copyright (c) 2016-2017 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.tools.permission;
35  
36  import info.magnolia.cms.security.AccessDeniedException;
37  import info.magnolia.cms.security.Group;
38  import info.magnolia.cms.security.Permission;
39  import info.magnolia.cms.security.Role;
40  import info.magnolia.cms.security.SecuritySupport;
41  import info.magnolia.cms.security.User;
42  import info.magnolia.cms.security.auth.ACL;
43  import info.magnolia.i18nsystem.SimpleTranslator;
44  import info.magnolia.security.app.tools.AbstractSecurityToolPresenter;
45  import info.magnolia.security.app.tools.SecurityToolView;
46  import info.magnolia.ui.api.context.UiContext;
47  import info.magnolia.ui.dialog.formdialog.FormBuilder;
48  import info.magnolia.ui.framework.tools.FormToolActionExecutor;
49  
50  import java.util.Arrays;
51  import java.util.Collections;
52  import java.util.Iterator;
53  import java.util.List;
54  
55  import javax.inject.Inject;
56  
57  import com.google.common.collect.HashBasedTable;
58  import com.google.common.collect.Table;
59  import com.vaadin.data.Container;
60  import com.vaadin.data.Item;
61  import com.vaadin.data.util.BeanItem;
62  import com.vaadin.data.util.HierarchicalContainer;
63  
64  /**
65   * The security tools help verifying the system's security setup and ACLs.
66   */
67  public class PermissionToolPresenter extends AbstractSecurityToolPresenter {
68  
69      private final SecuritySupport securitySupport;
70      private final SimpleTranslator i18n;
71      private PermissionViewOption viewOption;
72  
73      @Inject
74      public PermissionToolPresenter(SecurityToolView view, FormBuilder formBuilder, FormToolActionExecutor actionExecutor,
75                                     UiContext uiContext, SecuritySupport securitySupport, SimpleTranslator i18n) {
76          super(view, formBuilder, actionExecutor, uiContext);
77          this.securitySupport = securitySupport;
78          this.i18n = i18n;
79      }
80  
81      @Override
82      protected Item getItem() {
83          viewOption = new PermissionViewOption();
84          return new BeanItem<>(viewOption);
85      }
86  
87      @Override
88      protected Container.Hierarchical buildContainer() throws AccessDeniedException {
89          container = new HierarchicalContainer();
90          container.addContainerProperty(VALUE_ID, String.class, "");
91  
92          Iterator<String> iterGroups = Collections.emptyIterator();
93          Iterator<String> iterRoles = Collections.emptyIterator();
94          switch (viewOption.getType()) {
95          case GROUP:
96              Group group = securitySupport.getGroupManager().getGroup(viewOption.getName());
97              if (group == null) {
98                  return null;
99              }
100             iterGroups = group.getGroups().iterator();
101             iterRoles = group.getRoles().iterator();
102             break;
103         case USER:
104             User user = securitySupport.getUserManager().getUser(viewOption.getName());
105             if (user == null) {
106                 return null;
107             }
108             iterGroups = user.getGroups().iterator();
109             iterRoles = user.getRoles().iterator();
110             break;
111         default:
112             break;
113         }
114 
115         boolean withPermissions = DumpMode.WITH_PERMISSIONS.equals(viewOption.getDumpMode());
116         getGroupRole(iterGroups, withPermissions, null);
117         getRole(iterRoles, withPermissions, null);
118 
119         // Resolve parent tree node
120         for (Object itemId : container.getItemIds()) {
121             container.setChildrenAllowed(itemId, container.getChildren(itemId) != null && container.getChildren(itemId).size() > 0);
122         }
123 
124         return container;
125     }
126 
127     @Override
128     protected String getErrorMessage() {
129         String errorKey = String.format("security.permissionsTab.%s.error", viewOption.getType().name().toLowerCase());
130         return i18n.translate(errorKey, viewOption.getName());
131     }
132 
133     /**
134      * Finding and adding subgroups to container.
135      */
136     private void getGroupRole(Iterator<String> iterGroup, boolean withPermissions, Object parentId) throws AccessDeniedException {
137         while (iterGroup.hasNext()) {
138             Group group = securitySupport.getGroupManager().getGroup(iterGroup.next());
139             Object itemId = addContainerItem(VALUE_ID, getGroupRepresentation(group), parentId);
140 
141             getGroupRole(group.getGroups().iterator(), withPermissions, itemId);
142             getRole(group.getRoles().iterator(), withPermissions, itemId);
143         }
144     }
145 
146     /**
147      * Finding and adding roles to container.
148      */
149     private void getRole(Iterator<String> iterRoles, boolean withPermissions, Object parentId) {
150         while (iterRoles.hasNext()) {
151             Role role = securitySupport.getRoleManager().getRole(iterRoles.next());
152             Object itemId = addContainerItem(VALUE_ID, getRoleRepresentation(role), parentId);
153             if (withPermissions) {
154                 getPermission(role.getName(), itemId);
155             }
156         }
157     }
158 
159     /**
160      * Finding and adding permissions to container.
161      */
162     private void getPermission(String role, Object parentId) {
163         Iterator<ACL> iterPermission = securitySupport.getRoleManager().getACLs(role).values().iterator();
164         while (iterPermission.hasNext()) {
165             ACL acl = iterPermission.next();
166             for (Permission permission : acl.getList()) {
167                 addContainerItem(VALUE_ID, getPermissionRepresentation(permission, acl.getName()), parentId);
168             }
169         }
170     }
171 
172     private String getGroupRepresentation(Group group) {
173         return i18n.translate("security.tools.results.group", group.getName());
174     }
175 
176     private String getRoleRepresentation(Role role) {
177         return i18n.translate("security.tools.results.role", role.getName());
178     }
179 
180     private String getPermissionRepresentation(Permission permission, String repoName) {
181         return i18n.translate("security.tools.results.permission", new String[] { getPermissionAsName(repoName, permission), repoName, permission.getPattern().getPatternString() });
182     }
183 
184     /**
185      * Mapping permission to name.
186      */
187     private String getPermissionAsName(String repoName, Permission permission) {
188         String messageKeyName;
189 
190         if (!REPO_NAMES.contains(repoName)) {
191             repoName = "";
192         }
193         messageKeyName = PERMISSION_MESSAGES.get(repoName, permission.getPermissions());
194 
195         if (messageKeyName == null) {
196             return ("(" + permission.getPermissions() + ") unknown ");
197         }
198 
199         return i18n.translate(messageKeyName);
200     }
201 
202 
203     private static final List<String> REPO_NAMES = Arrays.asList("uri", "forum");
204     private static final Table<String, Long, String> PERMISSION_MESSAGES = HashBasedTable.create();
205 
206     static {
207         PERMISSION_MESSAGES.put("uri", 0L, "roles.permission.deny");
208         PERMISSION_MESSAGES.put("uri", Permission.READ, "roles.permission.get");
209         PERMISSION_MESSAGES.put("uri", Permission.ALL, "roles.permission.getAndPost");
210 
211         PERMISSION_MESSAGES.put("forum", 0L, "roles.permission.deny");
212         PERMISSION_MESSAGES.put("forum", Permission.READ, "roles.permission.readOnly");
213         PERMISSION_MESSAGES.put("forum", Permission.WRITE, "roles.permission.post");
214         PERMISSION_MESSAGES.put("forum", 75L, "roles.permission.moderate");
215         PERMISSION_MESSAGES.put("forum", 79L, "roles.permission.moderateAndDelete");
216         PERMISSION_MESSAGES.put("forum", 111L, "roles.permission.admin");
217 
218         PERMISSION_MESSAGES.put("", 0L, "roles.permission.deny");
219         PERMISSION_MESSAGES.put("", Permission.READ, "roles.permission.readOnly");
220         PERMISSION_MESSAGES.put("", Permission.ALL, "roles.permission.readWrite");
221     }
222 
223     /**
224      * Options for permission tools.
225      */
226     public static class PermissionViewOption extends AbstractSecurityToolPresenter.ViewOption {
227         private DumpType type;
228         private DumpMode dumpMode;
229 
230         public DumpType getType() {
231             return type;
232         }
233 
234         public void setType(DumpType type) {
235             this.type = type;
236         }
237 
238         public DumpMode getDumpMode() {
239             return dumpMode;
240         }
241 
242         public void setDumpMode(DumpMode dumpMode) {
243             this.dumpMode = dumpMode;
244         }
245     }
246 
247     /**
248      * Type is used to query permissions for.
249      */
250     public enum DumpType {
251         USER, GROUP
252     }
253 
254     /**
255      * Mode of querying permissions.
256      */
257     public enum DumpMode {
258         WITH_PERMISSIONS, WITHOUT_PERMISSIONS
259     }
260 
261 }