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