1   /**
2    * Copyright (c) 2000-2008 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.util.StringPool;
27  import com.liferay.portal.kernel.util.Validator;
28  import com.liferay.portal.model.Group;
29  import com.liferay.portal.model.GroupConstants;
30  import com.liferay.portal.model.Organization;
31  import com.liferay.portal.model.Permission;
32  import com.liferay.portal.model.PortletConstants;
33  import com.liferay.portal.model.Resource;
34  import com.liferay.portal.model.ResourceConstants;
35  import com.liferay.portal.model.Role;
36  import com.liferay.portal.model.RoleConstants;
37  import com.liferay.portal.model.UserGroup;
38  import com.liferay.portal.security.permission.comparator.PermissionActionIdComparator;
39  import com.liferay.portal.service.GroupLocalServiceUtil;
40  import com.liferay.portal.service.OrganizationLocalServiceUtil;
41  import com.liferay.portal.service.PermissionLocalServiceUtil;
42  import com.liferay.portal.service.ResourceLocalServiceUtil;
43  import com.liferay.portal.service.RoleLocalServiceUtil;
44  import com.liferay.portal.service.UserGroupLocalServiceUtil;
45  import com.liferay.portal.service.permission.PortletPermissionUtil;
46  import com.liferay.portal.util.PropsValues;
47  import com.liferay.util.UniqueList;
48  
49  import java.util.ArrayList;
50  import java.util.Collections;
51  import java.util.HashMap;
52  import java.util.List;
53  import java.util.Map;
54  
55  import org.apache.commons.lang.time.StopWatch;
56  import org.apache.commons.logging.Log;
57  import org.apache.commons.logging.LogFactory;
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 != -1) {
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     public void recycle() {
215         super.recycle();
216 
217         companyAdmins.clear();
218     }
219 
220     protected long[] getResourceIds(
221             long companyId, long groupId, String name, String primKey,
222             String actionId)
223         throws Exception {
224 
225         // Individual
226 
227         long[] resourceIds = new long[4];
228 
229         try {
230             Resource resource = ResourceLocalServiceUtil.getResource(
231                 companyId, name, ResourceConstants.SCOPE_INDIVIDUAL, primKey);
232 
233             resourceIds[0] = resource.getResourceId();
234         }
235         catch (NoSuchResourceException nsre) {
236             if (_log.isWarnEnabled()) {
237                 _log.warn(
238                     "Resource " + companyId + " " + name + " " +
239                         ResourceConstants.SCOPE_INDIVIDUAL + " " + primKey +
240                             " does not exist");
241             }
242         }
243 
244         // Group
245 
246         try {
247             if (groupId > 0) {
248                 Resource resource = ResourceLocalServiceUtil.getResource(
249                     companyId, name, ResourceConstants.SCOPE_GROUP,
250                     String.valueOf(groupId));
251 
252                 resourceIds[1] = resource.getResourceId();
253             }
254         }
255         catch (NoSuchResourceException nsre) {
256             if (_log.isWarnEnabled()) {
257                 _log.warn(
258                     "Resource " + companyId + " " + name + " " +
259                         ResourceConstants.SCOPE_GROUP + " " + groupId +
260                             " does not exist");
261             }
262         }
263 
264         // Group template
265 
266         try {
267             if (signedIn && (groupId > 0)) {
268                 Resource resource = ResourceLocalServiceUtil.getResource(
269                     companyId, name, ResourceConstants.SCOPE_GROUP_TEMPLATE,
270                     String.valueOf(GroupConstants.DEFAULT_PARENT_GROUP_ID));
271 
272                 resourceIds[2] = resource.getResourceId();
273             }
274         }
275         catch (NoSuchResourceException nsre) {
276             if (_log.isWarnEnabled()) {
277                 _log.warn(
278                     "Resource " + companyId + " " + name + " " +
279                         ResourceConstants.SCOPE_GROUP_TEMPLATE + " " +
280                             GroupConstants.DEFAULT_PARENT_GROUP_ID +
281                                 " does not exist");
282             }
283         }
284 
285         // Company
286 
287         try {
288             Resource resource = ResourceLocalServiceUtil.getResource(
289                 companyId, name, ResourceConstants.SCOPE_COMPANY,
290                 String.valueOf(companyId));
291 
292             resourceIds[3] = resource.getResourceId();
293         }
294         catch (NoSuchResourceException nsre) {
295             if (_log.isWarnEnabled()) {
296                 _log.warn(
297                     "Resource " + companyId + " " + name + " " +
298                         ResourceConstants.SCOPE_COMPANY + " " + companyId +
299                             " does not exist");
300             }
301         }
302 
303         return resourceIds;
304     }
305 
306     protected PermissionCheckerBag getUserBag(long userId, long groupId)
307         throws Exception {
308 
309         PermissionCheckerBag bag = PermissionCacheUtil.getBag(userId, groupId);
310 
311         if (bag != null) {
312             return bag;
313         }
314 
315         // If we are checking permissions on an object that belongs to a
316         // community, then it's only necessary to check the group that
317         // represents the community and not all the groups that the user
318         // belongs to. This is so because an object cannot belong to
319         // more than one community.
320 
321         List<Group> userGroups = new ArrayList<Group>();
322         //List<Group> userGroups = UserUtil.getGroups(userId);
323 
324         if (groupId > 0) {
325             if (GroupLocalServiceUtil.hasUserGroup(userId, groupId)) {
326                 Group group = GroupLocalServiceUtil.getGroup(groupId);
327 
328                 userGroups.add(group);
329             }
330         }
331 
332         List<Organization> userOrgs = getUserOrgs(userId);
333 
334         List<Group> userOrgGroups =
335             GroupLocalServiceUtil.getOrganizationsGroups(userOrgs);
336 
337         List<UserGroup> userUserGroups =
338             UserGroupLocalServiceUtil.getUserUserGroups(userId);
339 
340         List<Group> userUserGroupGroups =
341             GroupLocalServiceUtil.getUserGroupsGroups(userUserGroups);
342 
343         List<Group> groups = new ArrayList<Group>(
344             userGroups.size() + userOrgGroups.size() +
345                 userUserGroupGroups.size());
346 
347         groups.addAll(userGroups);
348         groups.addAll(userOrgGroups);
349         groups.addAll(userUserGroupGroups);
350 
351         List<Role> roles = new ArrayList<Role>(10);
352 
353         if ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 3) ||
354             (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 4) ||
355             (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5)) {
356 
357             if (groups.size() > 0) {
358                 roles = RoleLocalServiceUtil.getUserRelatedRoles(
359                     userId, groups);
360             }
361             else {
362                 roles.addAll(RoleLocalServiceUtil.getUserRoles(userId));
363             }
364 
365             if (userGroups.size() > 0) {
366                 Role role = RoleLocalServiceUtil.getRole(
367                     user.getCompanyId(), RoleConstants.COMMUNITY_MEMBER);
368 
369                 roles.add(role);
370             }
371 
372             if (userOrgs.size() > 0) {
373                 Role role = RoleLocalServiceUtil.getRole(
374                     user.getCompanyId(), RoleConstants.ORGANIZATION_MEMBER);
375 
376                 roles.add(role);
377             }
378 
379             List<Role> userGroupRoles = RoleLocalServiceUtil.getUserGroupRoles(
380                 userId, groupId);
381 
382             roles.addAll(userGroupRoles);
383         }
384         else {
385             roles = new ArrayList<Role>();
386         }
387 
388         bag = new PermissionCheckerBagImpl(
389             userId, userGroups, userOrgs, userOrgGroups,
390             userUserGroupGroups, groups, roles);
391 
392         PermissionCacheUtil.putBag(userId, groupId, bag);
393 
394         return bag;
395     }
396 
397     protected List<Organization> getUserOrgs(long userId) throws Exception {
398         List<Organization> userOrgs =
399             OrganizationLocalServiceUtil.getUserOrganizations(userId);
400 
401         if (userOrgs.size() == 0) {
402             return userOrgs;
403         }
404 
405         List<Organization> organizations = new UniqueList<Organization>();
406 
407         for (Organization organization : userOrgs) {
408             if (!organizations.contains(organization)) {
409                 organizations.add(organization);
410 
411                 List<Organization> ancestorOrganizations =
412                     OrganizationLocalServiceUtil.getParentOrganizations(
413                         organization.getOrganizationId());
414 
415                 organizations.addAll(ancestorOrganizations);
416             }
417         }
418 
419         return organizations;
420     }
421 
422     protected boolean hasGuestPermission(
423             long groupId, String name, String primKey, String actionId)
424         throws Exception {
425 
426         if (name.indexOf(StringPool.PERIOD) != -1) {
427 
428             // Check unsupported model actions
429 
430             List<String> actions = ResourceActionsUtil.
431                 getModelResourceGuestUnsupportedActions(name);
432 
433             if (actions.contains(actionId)) {
434                 return false;
435             }
436         }
437         else {
438 
439             // Check unsupported portlet actions
440 
441             List<String> actions = ResourceActionsUtil.
442                 getPortletResourceGuestUnsupportedActions(name);
443 
444             if (actions.contains(actionId)) {
445                 return false;
446             }
447         }
448 
449         long companyId = user.getCompanyId();
450 
451         long[] resourceIds = getResourceIds(
452             companyId, groupId, name, primKey, actionId);
453 
454         Group guestGroup = GroupLocalServiceUtil.getGroup(
455             companyId, GroupConstants.GUEST);
456 
457         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
458             defaultUserId, guestGroup.getGroupId());
459 
460         if (bag == null) {
461             List<Group> groups = new ArrayList<Group>();
462 
463             groups.add(guestGroup);
464 
465             List<Role> roles = RoleLocalServiceUtil.getUserRelatedRoles(
466                 defaultUserId, groups);
467 
468             bag = new PermissionCheckerBagImpl(
469                 defaultUserId, new ArrayList<Group>(),
470                 new ArrayList<Organization>(), new ArrayList<Group>(),
471                 new ArrayList<Group>(), new ArrayList<Group>(), roles);
472 
473             PermissionCacheUtil.putBag(
474                 defaultUserId, guestGroup.getGroupId(), bag);
475         }
476 
477         try {
478             return PermissionLocalServiceUtil.hasUserPermissions(
479                 defaultUserId, groupId, actionId, resourceIds, bag);
480         }
481         catch (Exception e) {
482             return false;
483         }
484     }
485 
486     protected boolean hasPermissionImpl(
487         long groupId, String name, String primKey, String actionId) {
488 
489         try {
490             if (!signedIn) {
491                 return hasGuestPermission(groupId, name, primKey, actionId);
492             }
493             else {
494                 boolean value = false;
495 
496                 if (checkGuest) {
497                     value = hasGuestPermission(
498                         groupId, name, primKey, actionId);
499                 }
500 
501                 if (!value) {
502                     value = hasUserPermission(
503                         groupId, name, primKey, actionId, true);
504                 }
505 
506                 return value;
507             }
508         }
509         catch (Exception e) {
510             _log.error(e, e);
511 
512             return false;
513         }
514     }
515 
516     protected boolean hasUserPermissionImpl(
517             long groupId, String name, String primKey, String actionId,
518             boolean checkAdmin)
519         throws Exception {
520 
521         StopWatch stopWatch = null;
522 
523         if (_log.isDebugEnabled()) {
524             stopWatch = new StopWatch();
525 
526             stopWatch.start();
527         }
528 
529         long companyId = user.getCompanyId();
530 
531         boolean hasLayoutManagerPermission = true;
532 
533         // Check if the layout manager has permission to do this action for the
534         // current portlet
535 
536         if ((Validator.isNotNull(name)) && (Validator.isNotNull(primKey)) &&
537             (primKey.indexOf(PortletConstants.LAYOUT_SEPARATOR) != -1)) {
538 
539             hasLayoutManagerPermission =
540                 PortletPermissionUtil.hasLayoutManagerPermission(
541                     name, actionId);
542         }
543 
544         if (checkAdmin &&
545             (isCompanyAdminImpl(companyId) ||
546                 (isCommunityAdminImpl(groupId) &&
547                     hasLayoutManagerPermission))) {
548 
549             return true;
550         }
551 
552         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 1);
553 
554         long[] resourceIds = getResourceIds(
555             companyId, groupId, name, primKey, actionId);
556 
557         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 2);
558 
559         // Check if user has access to perform the action on the given
560         // resource scopes. The resources are scoped to check first for an
561         // individual class, then for the group that the class may belong
562         // to, and then for the company that the class belongs to.
563 
564         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
565 
566         boolean value = PermissionLocalServiceUtil.hasUserPermissions(
567             user.getUserId(), groupId, actionId, resourceIds, bag);
568 
569         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 3);
570 
571         return value;
572     }
573 
574     protected boolean isCompanyAdminImpl() throws Exception {
575         return isCompanyAdminImpl(user.getCompanyId());
576     }
577 
578     protected boolean isCompanyAdminImpl(long companyId) throws Exception {
579         if (!signedIn) {
580             return false;
581         }
582 
583         if (isOmniadmin()) {
584             return true;
585         }
586 
587         Boolean value = companyAdmins.get(companyId);
588 
589         if (value == null) {
590             boolean hasAdminRole = RoleLocalServiceUtil.hasUserRole(
591                 user.getUserId(), companyId, RoleConstants.ADMINISTRATOR, true);
592 
593             value = Boolean.valueOf(hasAdminRole);
594 
595             companyAdmins.put(companyId, value);
596         }
597 
598         return value.booleanValue();
599     }
600 
601     protected boolean isCommunityAdminImpl(long groupId) throws Exception {
602         if (!signedIn) {
603             return false;
604         }
605 
606         if (isOmniadmin()) {
607             return true;
608         }
609 
610         if (groupId <= 0) {
611             return false;
612         }
613 
614         Group group = GroupLocalServiceUtil.getGroup(groupId);
615 
616         if (isCompanyAdmin(group.getCompanyId())) {
617             return true;
618         }
619 
620         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
621 
622         if (bag == null) {
623             _log.error("Bag should never be null");
624         }
625 
626         if (bag.isCommunityAdmin(this, group)) {
627             return true;
628         }
629         else {
630             return false;
631         }
632     }
633 
634     protected boolean isCommunityOwnerImpl(long groupId) throws Exception {
635         if (!signedIn) {
636             return false;
637         }
638 
639         if (isOmniadmin()) {
640             return true;
641         }
642 
643         if (groupId <= 0) {
644             return false;
645         }
646 
647         Group group = GroupLocalServiceUtil.getGroup(groupId);
648 
649         if (isCompanyAdmin(group.getCompanyId())) {
650             return true;
651         }
652 
653         PermissionCheckerBag bag = getUserBag(user.getUserId(), groupId);
654 
655         if (bag == null) {
656             _log.error("Bag should never be null");
657         }
658 
659         if (bag.isCommunityOwner(this, group)) {
660             return true;
661         }
662         else {
663             return false;
664         }
665     }
666 
667     protected void logHasUserPermission(
668         long groupId, String name, String primKey, String actionId,
669         StopWatch stopWatch, int block) {
670 
671         if (!_log.isDebugEnabled()) {
672             return;
673         }
674 
675         _log.debug(
676             "Checking user permission block " + block + " for " + groupId +
677                 " " + name + " " + primKey + " " + actionId + " takes " +
678                     stopWatch.getTime() + " ms");
679     }
680 
681     protected static final String RESULTS_SEPARATOR = "_RESULTS_SEPARATOR_";
682 
683     protected Map<Long, Boolean> companyAdmins = new HashMap<Long, Boolean>();
684 
685     private static Log _log =
686         LogFactory.getLog(AdvancedPermissionChecker.class);
687 
688 }