1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.security.permission;
24  
25  import com.liferay.portal.NoSuchResourceException;
26  import com.liferay.portal.kernel.log.Log;
27  import com.liferay.portal.kernel.log.LogFactoryUtil;
28  import com.liferay.portal.kernel.util.StringPool;
29  import com.liferay.portal.kernel.util.Validator;
30  import com.liferay.portal.model.Group;
31  import com.liferay.portal.model.GroupConstants;
32  import com.liferay.portal.model.Organization;
33  import com.liferay.portal.model.Permission;
34  import com.liferay.portal.model.PortletConstants;
35  import com.liferay.portal.model.Resource;
36  import com.liferay.portal.model.ResourceConstants;
37  import com.liferay.portal.model.Role;
38  import com.liferay.portal.model.RoleConstants;
39  import com.liferay.portal.model.UserGroup;
40  import com.liferay.portal.security.permission.comparator.PermissionActionIdComparator;
41  import com.liferay.portal.service.GroupLocalServiceUtil;
42  import com.liferay.portal.service.OrganizationLocalServiceUtil;
43  import com.liferay.portal.service.PermissionLocalServiceUtil;
44  import com.liferay.portal.service.ResourceLocalServiceUtil;
45  import com.liferay.portal.service.RoleLocalServiceUtil;
46  import com.liferay.portal.service.UserGroupLocalServiceUtil;
47  import com.liferay.portal.service.permission.PortletPermissionUtil;
48  import com.liferay.portal.util.PropsValues;
49  import com.liferay.util.UniqueList;
50  
51  import java.util.ArrayList;
52  import java.util.Collections;
53  import java.util.HashMap;
54  import java.util.List;
55  import java.util.Map;
56  
57  import org.apache.commons.lang.time.StopWatch;
58  
59  /**
60   * <a href="AdvancedPermissionChecker.java.html"><b><i>View Source</i></b></a>
61   *
62   * @author Charles May
63   * @author Brian Wing Shun Chan
64   * @author Raymond Augé
65   *
66   */
67  public class AdvancedPermissionChecker extends BasePermissionChecker {
68  
69      public boolean hasOwnerPermission(
70          long companyId, String name, String primKey, long ownerId,
71          String actionId) {
72  
73          if (ownerId == getUserId()) {
74              try {
75                  Resource resource = ResourceLocalServiceUtil.getResource(
76                      companyId, name, ResourceConstants.SCOPE_INDIVIDUAL,
77                      primKey);
78  
79                  List<Permission> permissions =
80                      PermissionLocalServiceUtil.getRolePermissions(
81                          getOwnerRoleId(), resource.getResourceId());
82  
83                  int pos = Collections.binarySearch(
84                      permissions, actionId, new PermissionActionIdComparator());
85  
86                  if (pos >= 0) {
87                      return true;
88                  }
89              }
90              catch (Exception e) {
91                  if (_log.isDebugEnabled()) {
92                      _log.debug(e, e);
93                  }
94              }
95          }
96  
97          return false;
98      }
99  
100     public boolean hasPermission(
101         long groupId, String name, String primKey, String actionId) {
102 
103         StopWatch stopWatch = null;
104 
105         if (_log.isDebugEnabled()) {
106             stopWatch = new StopWatch();
107 
108             stopWatch.start();
109         }
110 
111         Group group = null;
112 
113         // If the current group is staging, the live group should be checked for
114         // permissions instead
115 
116         try {
117             if (groupId > 0) {
118                 group = GroupLocalServiceUtil.getGroup(groupId);
119 
120                 if (group.isStagingGroup()) {
121                     if (primKey.equals(String.valueOf(groupId))) {
122                         primKey = String.valueOf(group.getLiveGroupId());
123                     }
124 
125                     groupId = group.getLiveGroupId();
126                     group = group.getLiveGroup();
127                 }
128             }
129         }
130         catch (Exception e) {
131             _log.error(e, e);
132         }
133 
134         Boolean value = PermissionCacheUtil.getPermission(
135             user.getUserId(), groupId, name, primKey, actionId);
136 
137         if (value == null) {
138             value = Boolean.valueOf(
139                 hasPermissionImpl(groupId, name, primKey, actionId));
140 
141             PermissionCacheUtil.putPermission(
142                 user.getUserId(), groupId, name, primKey, actionId, value);
143 
144             if (_log.isDebugEnabled()) {
145                 _log.debug(
146                     "Checking permission for " + groupId + " " + name + " " +
147                         primKey + " " + actionId + " takes " +
148                             stopWatch.getTime() + " ms");
149             }
150         }
151 
152         return value.booleanValue();
153     }
154 
155     public boolean hasUserPermission(
156         long groupId, String name, String primKey, String actionId,
157         boolean checkAdmin) {
158 
159         try {
160             return hasUserPermissionImpl(
161                 groupId, name, primKey, actionId, checkAdmin);
162         }
163         catch (Exception e) {
164             _log.error(e, e);
165 
166             return false;
167         }
168     }
169 
170     public boolean isCommunityAdmin(long groupId) {
171         try {
172             return isCommunityAdminImpl(groupId);
173         }
174         catch (Exception e) {
175             _log.error(e, e);
176 
177             return false;
178         }
179     }
180 
181     public boolean isCommunityOwner(long groupId) {
182         try {
183             return isCommunityOwnerImpl(groupId);
184         }
185         catch (Exception e) {
186             _log.error(e, e);
187 
188             return false;
189         }
190     }
191 
192     public boolean isCompanyAdmin() {
193         try {
194             return isCompanyAdminImpl();
195         }
196         catch (Exception e) {
197             _log.error(e, e);
198 
199             return false;
200         }
201     }
202 
203     public boolean isCompanyAdmin(long companyId) {
204         try {
205             return isCompanyAdminImpl(companyId);
206         }
207         catch (Exception e) {
208             _log.error(e, e);
209 
210             return false;
211         }
212     }
213 
214     protected long[] getResourceIds(
215             long companyId, long groupId, String name, String primKey,
216             String actionId)
217         throws Exception {
218 
219         // Individual
220 
221         long[] resourceIds = new long[4];
222 
223         try {
224             Resource resource = ResourceLocalServiceUtil.getResource(
225                 companyId, name, ResourceConstants.SCOPE_INDIVIDUAL, primKey);
226 
227             resourceIds[0] = resource.getResourceId();
228         }
229         catch (NoSuchResourceException nsre) {
230             if (_log.isWarnEnabled()) {
231                 _log.warn(
232                     "Resource " + companyId + " " + name + " " +
233                         ResourceConstants.SCOPE_INDIVIDUAL + " " + primKey +
234                             " does not exist");
235             }
236         }
237 
238         // Group
239 
240         try {
241             if (groupId > 0) {
242                 Resource resource = ResourceLocalServiceUtil.getResource(
243                     companyId, name, ResourceConstants.SCOPE_GROUP,
244                     String.valueOf(groupId));
245 
246                 resourceIds[1] = resource.getResourceId();
247             }
248         }
249         catch (NoSuchResourceException nsre) {
250             if (_log.isWarnEnabled()) {
251                 _log.warn(
252                     "Resource " + companyId + " " + name + " " +
253                         ResourceConstants.SCOPE_GROUP + " " + groupId +
254                             " does not exist");
255             }
256         }
257 
258         // Group template
259 
260         try {
261             if (signedIn && (groupId > 0)) {
262                 Resource resource = ResourceLocalServiceUtil.getResource(
263                     companyId, name, ResourceConstants.SCOPE_GROUP_TEMPLATE,
264                     String.valueOf(GroupConstants.DEFAULT_PARENT_GROUP_ID));
265 
266                 resourceIds[2] = resource.getResourceId();
267             }
268         }
269         catch (NoSuchResourceException nsre) {
270             if (_log.isWarnEnabled()) {
271                 _log.warn(
272                     "Resource " + companyId + " " + name + " " +
273                         ResourceConstants.SCOPE_GROUP_TEMPLATE + " " +
274                             GroupConstants.DEFAULT_PARENT_GROUP_ID +
275                                 " does not exist");
276             }
277         }
278 
279         // Company
280 
281         try {
282             Resource resource = ResourceLocalServiceUtil.getResource(
283                 companyId, name, ResourceConstants.SCOPE_COMPANY,
284                 String.valueOf(companyId));
285 
286             resourceIds[3] = resource.getResourceId();
287         }
288         catch (NoSuchResourceException nsre) {
289             if (_log.isWarnEnabled()) {
290                 _log.warn(
291                     "Resource " + companyId + " " + name + " " +
292                         ResourceConstants.SCOPE_COMPANY + " " + companyId +
293                             " does not exist");
294             }
295         }
296 
297         return resourceIds;
298     }
299 
300     protected PermissionCheckerBag getUserBag(long userId, long groupId)
301         throws Exception {
302 
303         PermissionCheckerBag bag = PermissionCacheUtil.getBag(userId, groupId);
304 
305         if (bag != null) {
306             return bag;
307         }
308 
309         // If we are checking permissions on an object that belongs to a
310         // community, then it's only necessary to check the group that
311         // represents the community and not all the groups that the user
312         // belongs to. This is so because an object cannot belong to
313         // more than one community.
314 
315         List<Group> userGroups = new ArrayList<Group>();
316         //List<Group> userGroups = UserUtil.getGroups(userId);
317 
318         if (groupId > 0) {
319             if (GroupLocalServiceUtil.hasUserGroup(userId, groupId)) {
320                 Group group = GroupLocalServiceUtil.getGroup(groupId);
321 
322                 userGroups.add(group);
323             }
324         }
325 
326         List<Organization> userOrgs = getUserOrgs(userId);
327 
328         List<Group> userOrgGroups =
329             GroupLocalServiceUtil.getOrganizationsGroups(userOrgs);
330 
331         List<UserGroup> userUserGroups =
332             UserGroupLocalServiceUtil.getUserUserGroups(userId);
333 
334         List<Group> userUserGroupGroups =
335             GroupLocalServiceUtil.getUserGroupsGroups(userUserGroups);
336 
337         List<Group> groups = new ArrayList<Group>(
338             userGroups.size() + userOrgGroups.size() +
339                 userUserGroupGroups.size());
340 
341         groups.addAll(userGroups);
342         groups.addAll(userOrgGroups);
343         groups.addAll(userUserGroupGroups);
344 
345         List<Role> roles = new ArrayList<Role>(10);
346 
347         if ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 3) ||
348             (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 4) ||
349             (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5)) {
350 
351             if (groups.size() > 0) {
352                 roles.addAll(
353                     RoleLocalServiceUtil.getUserRelatedRoles(userId, groups));
354             }
355             else {
356                 roles.addAll(RoleLocalServiceUtil.getUserRoles(userId));
357             }
358 
359             if (userGroups.size() > 0) {
360                 Role role = RoleLocalServiceUtil.getRole(
361                     user.getCompanyId(), RoleConstants.COMMUNITY_MEMBER);
362 
363                 roles.add(role);
364             }
365 
366             if (userOrgs.size() > 0) {
367                 Role role = RoleLocalServiceUtil.getRole(
368                     user.getCompanyId(), RoleConstants.ORGANIZATION_MEMBER);
369 
370                 roles.add(role);
371             }
372 
373             List<Role> userGroupRoles = RoleLocalServiceUtil.getUserGroupRoles(
374                 userId, groupId);
375 
376             roles.addAll(userGroupRoles);
377         }
378         else {
379             roles = new ArrayList<Role>();
380         }
381 
382         bag = new PermissionCheckerBagImpl(
383             userId, userGroups, userOrgs, userOrgGroups,
384             userUserGroupGroups, groups, roles);
385 
386         PermissionCacheUtil.putBag(userId, groupId, bag);
387 
388         return bag;
389     }
390 
391     protected List<Organization> getUserOrgs(long userId) throws Exception {
392         List<Organization> userOrgs =
393             OrganizationLocalServiceUtil.getUserOrganizations(userId);
394 
395         if (userOrgs.size() == 0) {
396             return userOrgs;
397         }
398 
399         List<Organization> organizations = new UniqueList<Organization>();
400 
401         for (Organization organization : userOrgs) {
402             if (!organizations.contains(organization)) {
403                 organizations.add(organization);
404 
405                 List<Organization> ancestorOrganizations =
406                     OrganizationLocalServiceUtil.getParentOrganizations(
407                         organization.getOrganizationId());
408 
409                 organizations.addAll(ancestorOrganizations);
410             }
411         }
412 
413         return organizations;
414     }
415 
416     protected boolean hasGuestPermission(
417             long groupId, String name, String primKey, String actionId)
418         throws Exception {
419 
420         if (name.indexOf(StringPool.PERIOD) != -1) {
421 
422             // Check unsupported model actions
423 
424             List<String> actions = ResourceActionsUtil.
425                 getModelResourceGuestUnsupportedActions(name);
426 
427             if (actions.contains(actionId)) {
428                 return false;
429             }
430         }
431         else {
432 
433             // Check unsupported portlet actions
434 
435             List<String> actions = ResourceActionsUtil.
436                 getPortletResourceGuestUnsupportedActions(name);
437 
438             if (actions.contains(actionId)) {
439                 return false;
440             }
441         }
442 
443         long companyId = user.getCompanyId();
444 
445         long[] resourceIds = getResourceIds(
446             companyId, groupId, name, primKey, actionId);
447 
448         Group guestGroup = GroupLocalServiceUtil.getGroup(
449             companyId, GroupConstants.GUEST);
450 
451         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
452             defaultUserId, guestGroup.getGroupId());
453 
454         if (bag == null) {
455             List<Group> groups = new ArrayList<Group>();
456 
457             groups.add(guestGroup);
458 
459             List<Role> roles = RoleLocalServiceUtil.getUserRelatedRoles(
460                 defaultUserId, groups);
461 
462             bag = new PermissionCheckerBagImpl(
463                 defaultUserId, new ArrayList<Group>(),
464                 new ArrayList<Organization>(), new ArrayList<Group>(),
465                 new ArrayList<Group>(), new ArrayList<Group>(), roles);
466 
467             PermissionCacheUtil.putBag(
468                 defaultUserId, guestGroup.getGroupId(), bag);
469         }
470 
471         try {
472             return PermissionLocalServiceUtil.hasUserPermissions(
473                 defaultUserId, groupId, actionId, resourceIds, bag);
474         }
475         catch (Exception e) {
476             return false;
477         }
478     }
479 
480     protected boolean hasPermissionImpl(
481         long groupId, String name, String primKey, String actionId) {
482 
483         try {
484             if (!signedIn) {
485                 return hasGuestPermission(groupId, name, primKey, actionId);
486             }
487             else {
488                 boolean value = false;
489 
490                 if (checkGuest) {
491                     value = hasGuestPermission(
492                         groupId, name, primKey, actionId);
493                 }
494 
495                 if (!value) {
496                     value = hasUserPermission(
497                         groupId, name, primKey, actionId, true);
498                 }
499 
500                 return value;
501             }
502         }
503         catch (Exception e) {
504             _log.error(e, e);
505 
506             return false;
507         }
508     }
509 
510     protected boolean hasUserPermissionImpl(
511             long groupId, String name, String primKey, String actionId,
512             boolean checkAdmin)
513         throws Exception {
514 
515         StopWatch stopWatch = null;
516 
517         if (_log.isDebugEnabled()) {
518             stopWatch = new StopWatch();
519 
520             stopWatch.start();
521         }
522 
523         long companyId = user.getCompanyId();
524 
525         boolean hasLayoutManagerPermission = true;
526 
527         // Check if the layout manager has permission to do this action for the
528         // current portlet
529 
530         if ((Validator.isNotNull(name)) && (Validator.isNotNull(primKey)) &&
531             (primKey.indexOf(PortletConstants.LAYOUT_SEPARATOR) != -1)) {
532 
533             hasLayoutManagerPermission =
534                 PortletPermissionUtil.hasLayoutManagerPermission(
535                     name, actionId);
536         }
537 
538         if (checkAdmin &&
539             (isCompanyAdminImpl(companyId) ||
540                 (isCommunityAdminImpl(groupId) &&
541                     hasLayoutManagerPermission))) {
542 
543             return true;
544         }
545 
546         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 1);
547 
548         long[] resourceIds = getResourceIds(
549             companyId, groupId, name, primKey, actionId);
550 
551         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 2);
552 
553         // Check if user has access to perform the action on the given
554         // resource scopes. The resources are scoped to check first for an
555         // individual class, then for the group that the class may belong
556         // to, and then for the company that the class belongs to.
557 
558         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
559 
560         boolean value = PermissionLocalServiceUtil.hasUserPermissions(
561             user.getUserId(), groupId, actionId, resourceIds, bag);
562 
563         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 3);
564 
565         return value;
566     }
567 
568     protected boolean isCompanyAdminImpl() throws Exception {
569         return isCompanyAdminImpl(user.getCompanyId());
570     }
571 
572     protected boolean isCompanyAdminImpl(long companyId) throws Exception {
573         if (!signedIn) {
574             return false;
575         }
576 
577         if (isOmniadmin()) {
578             return true;
579         }
580 
581         Boolean value = companyAdmins.get(companyId);
582 
583         if (value == null) {
584             boolean hasAdminRole = RoleLocalServiceUtil.hasUserRole(
585                 user.getUserId(), companyId, RoleConstants.ADMINISTRATOR, true);
586 
587             value = Boolean.valueOf(hasAdminRole);
588 
589             companyAdmins.put(companyId, value);
590         }
591 
592         return value.booleanValue();
593     }
594 
595     protected boolean isCommunityAdminImpl(long groupId) throws Exception {
596         if (!signedIn) {
597             return false;
598         }
599 
600         if (isOmniadmin()) {
601             return true;
602         }
603 
604         if (groupId <= 0) {
605             return false;
606         }
607 
608         Group group = GroupLocalServiceUtil.getGroup(groupId);
609 
610         if (isCompanyAdmin(group.getCompanyId())) {
611             return true;
612         }
613 
614         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
615 
616         if (bag == null) {
617             _log.error("Bag should never be null");
618         }
619 
620         if (bag.isCommunityAdmin(this, group)) {
621             return true;
622         }
623         else {
624             return false;
625         }
626     }
627 
628     protected boolean isCommunityOwnerImpl(long groupId) throws Exception {
629         if (!signedIn) {
630             return false;
631         }
632 
633         if (isOmniadmin()) {
634             return true;
635         }
636 
637         if (groupId <= 0) {
638             return false;
639         }
640 
641         Group group = GroupLocalServiceUtil.getGroup(groupId);
642 
643         if (isCompanyAdmin(group.getCompanyId())) {
644             return true;
645         }
646 
647         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
648 
649         if (bag == null) {
650             _log.error("Bag should never be null");
651         }
652 
653         if (bag.isCommunityOwner(this, group)) {
654             return true;
655         }
656         else {
657             return false;
658         }
659     }
660 
661     protected void logHasUserPermission(
662         long groupId, String name, String primKey, String actionId,
663         StopWatch stopWatch, int block) {
664 
665         if (!_log.isDebugEnabled()) {
666             return;
667         }
668 
669         _log.debug(
670             "Checking user permission block " + block + " for " + groupId +
671                 " " + name + " " + primKey + " " + actionId + " takes " +
672                     stopWatch.getTime() + " ms");
673     }
674 
675     protected static final String RESULTS_SEPARATOR = "_RESULTS_SEPARATOR_";
676 
677     protected Map<Long, Boolean> companyAdmins = new HashMap<Long, Boolean>();
678 
679     private static Log _log =
680         LogFactoryUtil.getLog(AdvancedPermissionChecker.class);
681 
682 }