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