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