1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.security.permission;
16  
17  import com.liferay.portal.NoSuchResourceException;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.util.StringPool;
21  import com.liferay.portal.kernel.util.Validator;
22  import com.liferay.portal.model.Group;
23  import com.liferay.portal.model.GroupConstants;
24  import com.liferay.portal.model.Layout;
25  import com.liferay.portal.model.Organization;
26  import com.liferay.portal.model.Permission;
27  import com.liferay.portal.model.PortletConstants;
28  import com.liferay.portal.model.Resource;
29  import com.liferay.portal.model.ResourceConstants;
30  import com.liferay.portal.model.Role;
31  import com.liferay.portal.model.RoleConstants;
32  import com.liferay.portal.model.Team;
33  import com.liferay.portal.model.UserGroup;
34  import com.liferay.portal.security.permission.comparator.PermissionActionIdComparator;
35  import com.liferay.portal.service.GroupLocalServiceUtil;
36  import com.liferay.portal.service.LayoutLocalServiceUtil;
37  import com.liferay.portal.service.OrganizationLocalServiceUtil;
38  import com.liferay.portal.service.PermissionLocalServiceUtil;
39  import com.liferay.portal.service.ResourceLocalServiceUtil;
40  import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
41  import com.liferay.portal.service.RoleLocalServiceUtil;
42  import com.liferay.portal.service.TeamLocalServiceUtil;
43  import com.liferay.portal.service.UserGroupLocalServiceUtil;
44  import com.liferay.portal.service.permission.PortletPermissionUtil;
45  import com.liferay.portal.util.PropsValues;
46  import com.liferay.util.UniqueList;
47  
48  import java.util.ArrayList;
49  import java.util.Collections;
50  import java.util.HashMap;
51  import java.util.List;
52  import java.util.Map;
53  
54  import org.apache.commons.lang.time.StopWatch;
55  
56  /**
57   * <a href="AdvancedPermissionChecker.java.html"><b><i>View Source</i></b></a>
58   *
59   * @author Charles May
60   * @author Brian Wing Shun Chan
61   * @author Raymond Augé
62   */
63  public class AdvancedPermissionChecker extends BasePermissionChecker {
64  
65      public long[] getRoleIds(long userId, long groupId) {
66          PermissionCheckerBag bag = null;
67  
68          try {
69              bag = getUserBag(userId, groupId);
70          }
71          catch (Exception e) {
72          }
73  
74          if (bag != null) {
75              return bag.getRoleIds();
76          }
77  
78          return PermissionChecker.DEFAULT_ROLE_IDS;
79      }
80  
81      public PermissionCheckerBag getUserBag(long userId, long groupId)
82          throws Exception {
83  
84          PermissionCheckerBag bag = PermissionCacheUtil.getBag(userId, groupId);
85  
86          if (bag != null) {
87              return bag;
88          }
89  
90          try {
91  
92              Group group = null;
93  
94              if (groupId > 0) {
95                  group = GroupLocalServiceUtil.getGroup(groupId);
96              }
97  
98              // If we are checking permissions on an object that belongs to a
99              // community, then it's only necessary to check the group that
100             // represents the community and not all the groups that the user
101             // belongs to. This is so because an object cannot belong to
102             // more than one community.
103 
104             List<Group> userGroups = new ArrayList<Group>();
105             //List<Group> userGroups = UserUtil.getGroups(userId);
106 
107             if ((group != null) && group.isCommunity() &&
108                 GroupLocalServiceUtil.hasUserGroup(userId, groupId)) {
109 
110                 userGroups.add(group);
111             }
112 
113             List<Organization> userOrgs = getUserOrgs(userId);
114 
115             List<Group> userOrgGroups =
116                 GroupLocalServiceUtil.getOrganizationsGroups(userOrgs);
117 
118             List<UserGroup> userUserGroups =
119                 UserGroupLocalServiceUtil.getUserUserGroups(userId);
120 
121             List<Group> userUserGroupGroups =
122                 GroupLocalServiceUtil.getUserGroupsGroups(userUserGroups);
123 
124             List<Group> groups = new ArrayList<Group>(
125                 userGroups.size() + userOrgGroups.size() +
126                     userUserGroupGroups.size());
127 
128             groups.addAll(userGroups);
129             groups.addAll(userOrgGroups);
130             groups.addAll(userUserGroupGroups);
131 
132             List<Role> roles = new UniqueList<Role>();
133 
134             if ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 3) ||
135                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 4) ||
136                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) ||
137                 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6)) {
138 
139                 if (groups.size() > 0) {
140                     List<Role> userRelatedRoles=
141                         RoleLocalServiceUtil.getUserRelatedRoles(
142                             userId, groups);
143 
144                     roles.addAll(userRelatedRoles);
145                 }
146                 else {
147                     roles.addAll(RoleLocalServiceUtil.getUserRoles(userId));
148                 }
149 
150                 List<Role> userGroupRoles =
151                     RoleLocalServiceUtil.getUserGroupRoles(userId, groupId);
152 
153                 roles.addAll(userGroupRoles);
154 
155                 List<Role> userGroupGroupRoles =
156                     RoleLocalServiceUtil.getUserGroupGroupRoles(
157                         userId, groupId);
158 
159                 roles.addAll(userGroupGroupRoles);
160 
161                 if ((group != null) &&
162                     ((group.isCommunity() && userGroups.contains(group)) ||
163                      (group.isOrganization() &&
164                         userOrgGroups.contains(group)))) {
165 
166                     addRequiredMemberRole(group, roles);
167                     addTeamRoles(userId, group, roles);
168                 }
169             }
170             else {
171                 roles = new ArrayList<Role>();
172             }
173 
174             bag = new PermissionCheckerBagImpl(
175                 userId, userGroups, userOrgs, userOrgGroups,
176                 userUserGroupGroups, groups, roles);
177 
178             return bag;
179         }
180         finally {
181             if (bag == null) {
182                 bag = new PermissionCheckerBagImpl(
183                     userId, new ArrayList<Group>(),
184                     new ArrayList<Organization>(), new ArrayList<Group>(),
185                     new ArrayList<Group>(), new ArrayList<Group>(),
186                     new ArrayList<Role>());
187             }
188 
189             PermissionCacheUtil.putBag(userId, groupId, bag);
190         }
191     }
192 
193     public boolean hasOwnerPermission(
194         long companyId, String name, String primKey, long ownerId,
195         String actionId) {
196 
197         if (ownerId != getUserId()) {
198             return false;
199         }
200 
201         if (ownerId == defaultUserId) {
202             if (actionId == ActionKeys.VIEW) {
203                 return true;
204             }
205             else {
206                 return false;
207             }
208         }
209 
210         try {
211             if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
212                 return ResourcePermissionLocalServiceUtil.hasResourcePermission(
213                     companyId, name, ResourceConstants.SCOPE_INDIVIDUAL,
214                     primKey, getOwnerRoleId(), actionId);
215             }
216             else {
217                 ResourceActionsUtil.checkAction(name, actionId);
218 
219                 Resource resource = ResourceLocalServiceUtil.getResource(
220                     companyId, name, ResourceConstants.SCOPE_INDIVIDUAL,
221                     primKey);
222 
223                 List<Permission> permissions =
224                     PermissionLocalServiceUtil.getRolePermissions(
225                         getOwnerRoleId(), resource.getResourceId());
226 
227                 int pos = Collections.binarySearch(
228                     permissions, actionId, new PermissionActionIdComparator());
229 
230                 if (pos >= 0) {
231                     return true;
232                 }
233             }
234         }
235         catch (Exception e) {
236             if (_log.isDebugEnabled()) {
237                 _log.debug(e, e);
238             }
239         }
240 
241         return false;
242     }
243 
244     public boolean hasPermission(
245         long groupId, String name, String primKey, String actionId) {
246 
247         StopWatch stopWatch = null;
248 
249         if (_log.isDebugEnabled()) {
250             stopWatch = new StopWatch();
251 
252             stopWatch.start();
253         }
254 
255         Group group = null;
256 
257         // If the current group is a staging group, check the live group. If the
258         // current group is a scope group for a layout, check the original
259         // group.
260 
261         try {
262             if (groupId > 0) {
263                 group = GroupLocalServiceUtil.getGroup(groupId);
264 
265                 if (group.isStagingGroup()) {
266                     if (primKey.equals(String.valueOf(groupId))) {
267                         primKey = String.valueOf(group.getLiveGroupId());
268                     }
269 
270                     groupId = group.getLiveGroupId();
271                     group = group.getLiveGroup();
272                 }
273                 else if (group.isLayout()) {
274                     Layout layout = LayoutLocalServiceUtil.getLayout(
275                         group.getClassPK());
276 
277                     groupId = layout.getGroupId();
278                 }
279             }
280         }
281         catch (Exception e) {
282             _log.error(e, e);
283         }
284 
285         Boolean value = PermissionCacheUtil.getPermission(
286             user.getUserId(), groupId, name, primKey, actionId);
287 
288         if (value == null) {
289             try {
290                 value = Boolean.valueOf(
291                     hasPermissionImpl(groupId, name, primKey, actionId));
292 
293                 if (_log.isDebugEnabled()) {
294                     _log.debug(
295                         "Checking permission for " + groupId + " " + name +
296                             " " + primKey + " " + actionId + " takes " +
297                                 stopWatch.getTime() + " ms");
298                 }
299             }
300             finally {
301                 if (value == null) {
302                     value = Boolean.FALSE;
303                 }
304 
305                 PermissionCacheUtil.putPermission(
306                     user.getUserId(), groupId, name, primKey, actionId, value);
307             }
308         }
309 
310         return value.booleanValue();
311     }
312 
313     public boolean hasUserPermission(
314         long groupId, String name, String primKey, String actionId,
315         boolean checkAdmin) {
316 
317         try {
318             return hasUserPermissionImpl(
319                 groupId, name, primKey, actionId, checkAdmin);
320         }
321         catch (Exception e) {
322             _log.error(e, e);
323 
324             return false;
325         }
326     }
327 
328     public boolean isCommunityAdmin(long groupId) {
329         try {
330             return isCommunityAdminImpl(groupId);
331         }
332         catch (Exception e) {
333             _log.error(e, e);
334 
335             return false;
336         }
337     }
338 
339     public boolean isCommunityOwner(long groupId) {
340         try {
341             return isCommunityOwnerImpl(groupId);
342         }
343         catch (Exception e) {
344             _log.error(e, e);
345 
346             return false;
347         }
348     }
349 
350     public boolean isCompanyAdmin() {
351         try {
352             return isCompanyAdminImpl();
353         }
354         catch (Exception e) {
355             _log.error(e, e);
356 
357             return false;
358         }
359     }
360 
361     public boolean isCompanyAdmin(long companyId) {
362         try {
363             return isCompanyAdminImpl(companyId);
364         }
365         catch (Exception e) {
366             _log.error(e, e);
367 
368             return false;
369         }
370     }
371 
372     protected void addRequiredMemberRole(Group group, List<Role> roles)
373         throws Exception {
374 
375         if (group.isCommunity()) {
376             Role communityMemberRole = RoleLocalServiceUtil.getRole(
377                 group.getCompanyId(), RoleConstants.COMMUNITY_MEMBER);
378 
379             roles.add(communityMemberRole);
380         }
381         else if (group.isOrganization()) {
382             Role organizationMemberRole = RoleLocalServiceUtil.getRole(
383                 group.getCompanyId(), RoleConstants.ORGANIZATION_MEMBER);
384 
385             roles.add(organizationMemberRole);
386         }
387     }
388 
389     protected void addTeamRoles(long userId, Group group, List<Role> roles)
390         throws Exception {
391 
392         if ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) ||
393             (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6)) {
394 
395             List<Team> teams = TeamLocalServiceUtil.getUserTeams(
396                 userId, group.getGroupId());
397 
398             for (Team team : teams) {
399                 Role role = RoleLocalServiceUtil.getTeamRole(
400                     team.getCompanyId(), team.getTeamId());
401 
402                 roles.add(role);
403             }
404         }
405     }
406 
407     protected List<Resource> getResources(
408             long companyId, long groupId, String name, String primKey,
409             String actionId)
410         throws Exception {
411 
412         // Individual
413 
414         List<Resource> resources = new ArrayList<Resource>(4);
415 
416         try {
417             Resource resource = ResourceLocalServiceUtil.getResource(
418                 companyId, name, ResourceConstants.SCOPE_INDIVIDUAL, primKey);
419 
420             resources.add(resource);
421         }
422         catch (NoSuchResourceException nsre) {
423             if (_log.isWarnEnabled()) {
424                 _log.warn(
425                     "Resource " + companyId + " " + name + " " +
426                         ResourceConstants.SCOPE_INDIVIDUAL + " " + primKey +
427                             " does not exist");
428             }
429         }
430 
431         // Group
432 
433         try {
434             if (groupId > 0) {
435                 Resource resource = ResourceLocalServiceUtil.getResource(
436                     companyId, name, ResourceConstants.SCOPE_GROUP,
437                     String.valueOf(groupId));
438 
439                 resources.add(resource);
440             }
441         }
442         catch (NoSuchResourceException nsre) {
443             if (_log.isWarnEnabled()) {
444                 _log.warn(
445                     "Resource " + companyId + " " + name + " " +
446                         ResourceConstants.SCOPE_GROUP + " " + groupId +
447                             " does not exist");
448             }
449         }
450 
451         // Group template
452 
453         try {
454             if (signedIn && (groupId > 0)) {
455                 Resource resource = ResourceLocalServiceUtil.getResource(
456                     companyId, name, ResourceConstants.SCOPE_GROUP_TEMPLATE,
457                     String.valueOf(GroupConstants.DEFAULT_PARENT_GROUP_ID));
458 
459                 resources.add(resource);
460             }
461         }
462         catch (NoSuchResourceException nsre) {
463             if (_log.isWarnEnabled()) {
464                 _log.warn(
465                     "Resource " + companyId + " " + name + " " +
466                         ResourceConstants.SCOPE_GROUP_TEMPLATE + " " +
467                             GroupConstants.DEFAULT_PARENT_GROUP_ID +
468                                 " does not exist");
469             }
470         }
471 
472         // Company
473 
474         try {
475             Resource resource = ResourceLocalServiceUtil.getResource(
476                 companyId, name, ResourceConstants.SCOPE_COMPANY,
477                 String.valueOf(companyId));
478 
479             resources.add(resource);
480         }
481         catch (NoSuchResourceException nsre) {
482             if (_log.isWarnEnabled()) {
483                 _log.warn(
484                     "Resource " + companyId + " " + name + " " +
485                         ResourceConstants.SCOPE_COMPANY + " " + companyId +
486                             " does not exist");
487             }
488         }
489 
490         return resources;
491     }
492 
493     protected List<Organization> getUserOrgs(long userId) throws Exception {
494         List<Organization> userOrgs =
495             OrganizationLocalServiceUtil.getUserOrganizations(userId, true);
496 
497         if (userOrgs.size() == 0) {
498             return userOrgs;
499         }
500 
501         List<Organization> organizations = new UniqueList<Organization>();
502 
503         for (Organization organization : userOrgs) {
504             if (!organizations.contains(organization)) {
505                 organizations.add(organization);
506 
507                 List<Organization> ancestorOrganizations =
508                     OrganizationLocalServiceUtil.getParentOrganizations(
509                         organization.getOrganizationId());
510 
511                 organizations.addAll(ancestorOrganizations);
512             }
513         }
514 
515         return organizations;
516     }
517 
518     protected boolean hasGuestPermission(
519             long groupId, String name, String primKey, String actionId)
520         throws Exception {
521 
522         ResourceActionsUtil.checkAction(name, actionId);
523 
524         if (name.indexOf(StringPool.PERIOD) != -1) {
525 
526             // Check unsupported model actions
527 
528             List<String> actions = ResourceActionsUtil.
529                 getModelResourceGuestUnsupportedActions(name);
530 
531             if (actions.contains(actionId)) {
532                 return false;
533             }
534         }
535         else {
536 
537             // Check unsupported portlet actions
538 
539             List<String> actions = ResourceActionsUtil.
540                 getPortletResourceGuestUnsupportedActions(name);
541 
542             if (actions.contains(actionId)) {
543                 return false;
544             }
545         }
546 
547         long companyId = user.getCompanyId();
548 
549         List<Resource> resources = getResources(
550             companyId, groupId, name, primKey, actionId);
551 
552         Group guestGroup = GroupLocalServiceUtil.getGroup(
553             companyId, GroupConstants.GUEST);
554 
555         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
556             defaultUserId, guestGroup.getGroupId());
557 
558         if (bag == null) {
559             try {
560                 List<Group> groups = new ArrayList<Group>();
561 
562                 groups.add(guestGroup);
563 
564                 List<Role> roles = RoleLocalServiceUtil.getUserRelatedRoles(
565                     defaultUserId, groups);
566 
567                 bag = new PermissionCheckerBagImpl(
568                     defaultUserId, new ArrayList<Group>(),
569                     new ArrayList<Organization>(), new ArrayList<Group>(),
570                     new ArrayList<Group>(), new ArrayList<Group>(), roles);
571             }
572             finally {
573                 if (bag == null) {
574                     bag = new PermissionCheckerBagImpl(
575                         defaultUserId, new ArrayList<Group>(),
576                         new ArrayList<Organization>(), new ArrayList<Group>(),
577                         new ArrayList<Group>(), new ArrayList<Group>(),
578                         new ArrayList<Role>());
579                 }
580 
581                 PermissionCacheUtil.putBag(
582                     defaultUserId, guestGroup.getGroupId(), bag);
583             }
584         }
585 
586         try {
587             return PermissionLocalServiceUtil.hasUserPermissions(
588                 defaultUserId, groupId, resources, actionId, bag);
589         }
590         catch (Exception e) {
591             _log.error(e, e);
592 
593             return false;
594         }
595     }
596 
597     protected boolean hasPermissionImpl(
598         long groupId, String name, String primKey, String actionId) {
599 
600         try {
601             if (!signedIn) {
602                 return hasGuestPermission(groupId, name, primKey, actionId);
603             }
604             else {
605                 boolean value = false;
606 
607                 if (checkGuest) {
608                     value = hasGuestPermission(
609                         groupId, name, primKey, actionId);
610                 }
611 
612                 if (!value) {
613                     value = hasUserPermission(
614                         groupId, name, primKey, actionId, true);
615                 }
616 
617                 return value;
618             }
619         }
620         catch (Exception e) {
621             _log.error(e, e);
622 
623             return false;
624         }
625     }
626 
627     protected boolean hasUserPermissionImpl(
628             long groupId, String name, String primKey, String actionId,
629             boolean checkAdmin)
630         throws Exception {
631 
632         StopWatch stopWatch = null;
633 
634         if (_log.isDebugEnabled()) {
635             stopWatch = new StopWatch();
636 
637             stopWatch.start();
638         }
639 
640         long companyId = user.getCompanyId();
641 
642         boolean hasLayoutManagerPermission = true;
643 
644         // Check if the layout manager has permission to do this action for the
645         // current portlet
646 
647         if ((Validator.isNotNull(name)) && (Validator.isNotNull(primKey)) &&
648             (primKey.indexOf(PortletConstants.LAYOUT_SEPARATOR) != -1)) {
649 
650             hasLayoutManagerPermission =
651                 PortletPermissionUtil.hasLayoutManagerPermission(
652                     name, actionId);
653         }
654 
655         if (checkAdmin &&
656             (isCompanyAdminImpl(companyId) ||
657                 (isCommunityAdminImpl(groupId) &&
658                     hasLayoutManagerPermission))) {
659 
660             return true;
661         }
662 
663         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 1);
664 
665         List<Resource> resources = getResources(
666             companyId, groupId, name, primKey, actionId);
667 
668         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 2);
669 
670         // Check if user has access to perform the action on the given
671         // resource scopes. The resources are scoped to check first for an
672         // individual class, then for the group that the class may belong
673         // to, and then for the company that the class belongs to.
674 
675         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
676 
677         boolean value = PermissionLocalServiceUtil.hasUserPermissions(
678             user.getUserId(), groupId, resources, actionId, bag);
679 
680         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 3);
681 
682         return value;
683     }
684 
685     protected boolean isCommunityAdminImpl(long groupId) throws Exception {
686         if (!signedIn) {
687             return false;
688         }
689 
690         if (isOmniadmin()) {
691             return true;
692         }
693 
694         if (groupId <= 0) {
695             return false;
696         }
697 
698         Group group = GroupLocalServiceUtil.getGroup(groupId);
699 
700         if (isCompanyAdmin(group.getCompanyId())) {
701             return true;
702         }
703 
704         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
705 
706         if (bag == null) {
707             _log.error("Bag should never be null");
708         }
709 
710         if (bag.isCommunityAdmin(this, group)) {
711             return true;
712         }
713         else {
714             return false;
715         }
716     }
717 
718     protected boolean isCommunityOwnerImpl(long groupId) throws Exception {
719         if (!signedIn) {
720             return false;
721         }
722 
723         if (isOmniadmin()) {
724             return true;
725         }
726 
727         if (groupId <= 0) {
728             return false;
729         }
730 
731         Group group = GroupLocalServiceUtil.getGroup(groupId);
732 
733         if (isCompanyAdmin(group.getCompanyId())) {
734             return true;
735         }
736 
737         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
738 
739         if (bag == null) {
740             _log.error("Bag should never be null");
741         }
742 
743         if (bag.isCommunityOwner(this, group)) {
744             return true;
745         }
746         else {
747             return false;
748         }
749     }
750 
751     protected boolean isCompanyAdminImpl() throws Exception {
752         return isCompanyAdminImpl(user.getCompanyId());
753     }
754 
755     protected boolean isCompanyAdminImpl(long companyId) throws Exception {
756         if (!signedIn) {
757             return false;
758         }
759 
760         if (isOmniadmin()) {
761             return true;
762         }
763 
764         Boolean value = companyAdmins.get(companyId);
765 
766         if (value == null) {
767             boolean hasAdminRole = RoleLocalServiceUtil.hasUserRole(
768                 user.getUserId(), companyId, RoleConstants.ADMINISTRATOR, true);
769 
770             value = Boolean.valueOf(hasAdminRole);
771 
772             companyAdmins.put(companyId, value);
773         }
774 
775         return value.booleanValue();
776     }
777 
778     protected void logHasUserPermission(
779         long groupId, String name, String primKey, String actionId,
780         StopWatch stopWatch, int block) {
781 
782         if (!_log.isDebugEnabled()) {
783             return;
784         }
785 
786         _log.debug(
787             "Checking user permission block " + block + " for " + groupId +
788                 " " + name + " " + primKey + " " + actionId + " takes " +
789                     stopWatch.getTime() + " ms");
790     }
791 
792     /**
793      * @deprecated
794      */
795     protected static final String RESULTS_SEPARATOR = "_RESULTS_SEPARATOR_";
796 
797     protected Map<Long, Boolean> companyAdmins = new HashMap<Long, Boolean>();
798 
799     private static Log _log = LogFactoryUtil.getLog(
800         AdvancedPermissionChecker.class);
801 
802 }