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         Group guestGroup = GroupLocalServiceUtil.getGroup(
421             companyId, GroupImpl.GUEST);
422 
423         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
424             defaultUserId, guestGroup.getGroupId());
425 
426         if (bag == null) {
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(
440                 defaultUserId, guestGroup.getGroupId(), bag);
441         }
442 
443         try {
444             return PermissionLocalServiceUtil.hasUserPermissions(
445                 defaultUserId, 0, actionId, resourceIds, bag);
446         }
447         catch (Exception e) {
448             return false;
449         }
450     }
451 
452     protected boolean hasPermissionImpl(
453         long groupId, String name, String primKey, String actionId) {
454 
455         try {
456             if (!signedIn) {
457                 return hasGuestPermission(name, primKey, actionId);
458             }
459             else {
460                 boolean value = false;
461 
462                 if (checkGuest) {
463                     value = hasGuestPermission(name, primKey, actionId);
464                 }
465 
466                 if (!value) {
467                     value = hasUserPermission(
468                         groupId, name, primKey, actionId, true);
469                 }
470 
471                 return value;
472             }
473         }
474         catch (Exception e) {
475             _log.error(e, e);
476 
477             return false;
478         }
479     }
480 
481     protected boolean hasUserPermissionImpl(
482             long groupId, String name, String primKey, String actionId,
483             boolean checkAdmin)
484         throws Exception {
485 
486         StopWatch stopWatch = null;
487 
488         if (_log.isDebugEnabled()) {
489             stopWatch = new StopWatch();
490 
491             stopWatch.start();
492         }
493 
494         long companyId = user.getCompanyId();
495 
496         boolean hasLayoutManagerPermission = true;
497 
498         // Check if the layout manager has permission to do this action for the
499         // current portlet
500 
501         if ((Validator.isNotNull(name)) && (Validator.isNotNull(primKey)) &&
502             (primKey.indexOf(PortletConstants.LAYOUT_SEPARATOR) != -1)) {
503 
504             hasLayoutManagerPermission =
505                 PortletPermissionUtil.hasLayoutManagerPermission(
506                     name, actionId);
507         }
508 
509         if (checkAdmin &&
510             (isCompanyAdminImpl(companyId) ||
511                 (isCommunityAdminImpl(groupId) &&
512                     hasLayoutManagerPermission))) {
513 
514             return true;
515         }
516 
517         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 1);
518 
519         long[] resourceIds = getResourceIds(
520             companyId, groupId, name, primKey, actionId);
521 
522         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 2);
523 
524         // Check if user has access to perform the action on the given
525         // resource scopes. The resources are scoped to check first for an
526         // individual class, then for the group that the class may belong
527         // to, and then for the company that the class belongs to.
528 
529         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
530             user.getUserId(), groupId);
531 
532         boolean value = PermissionLocalServiceUtil.hasUserPermissions(
533             user.getUserId(), groupId, actionId, resourceIds, bag);
534 
535         logHasUserPermission(groupId, name, primKey, actionId, stopWatch, 3);
536 
537         return value;
538     }
539 
540     protected boolean isCompanyAdminImpl(long companyId) throws Exception {
541         if (!signedIn) {
542             return false;
543         }
544 
545         if (isOmniadmin()) {
546             return true;
547         }
548 
549         Boolean value = companyAdmins.get(companyId);
550 
551         if (value == null) {
552             boolean hasAdminRole = RoleLocalServiceUtil.hasUserRole(
553                 user.getUserId(), companyId, RoleImpl.ADMINISTRATOR, true);
554 
555             value = Boolean.valueOf(hasAdminRole);
556 
557             companyAdmins.put(companyId, value);
558         }
559 
560         return value.booleanValue();
561     }
562 
563     protected boolean isCommunityAdminImpl(long groupId) throws Exception {
564         if (!signedIn) {
565             return false;
566         }
567 
568         if (isOmniadmin()) {
569             return true;
570         }
571 
572         if (groupId <= 0) {
573             return false;
574         }
575 
576         Group group = GroupLocalServiceUtil.getGroup(groupId);
577 
578         if (isCompanyAdmin(group.getCompanyId())) {
579             return true;
580         }
581 
582         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
583             user.getUserId(), groupId);
584 
585         if (bag == null) {
586             _log.error("Bag should never be null");
587         }
588 
589         if (bag.isCommunityAdmin(this, group)) {
590             return true;
591         }
592         else {
593             return false;
594         }
595     }
596 
597     protected boolean isCommunityOwnerImpl(long groupId) throws Exception {
598         if (!signedIn) {
599             return false;
600         }
601 
602         if (isOmniadmin()) {
603             return true;
604         }
605 
606         if (groupId <= 0) {
607             return false;
608         }
609 
610         Group group = GroupLocalServiceUtil.getGroup(groupId);
611 
612         if (isCompanyAdmin(group.getCompanyId())) {
613             return true;
614         }
615 
616         PermissionCheckerBag bag = PermissionCacheUtil.getBag(
617             user.getUserId(), groupId);
618 
619         if (bag == null) {
620             _log.error("Bag should never be null");
621         }
622 
623         if (bag.isCommunityOwner(this, group)) {
624             return true;
625         }
626         else {
627             return false;
628         }
629     }
630 
631     protected void logHasUserPermission(
632         long groupId, String name, String primKey, String actionId,
633         StopWatch stopWatch, int block) {
634 
635         if (!_log.isDebugEnabled()) {
636             return;
637         }
638 
639         _log.debug(
640             "Checking user permission block " + block + " for " + groupId +
641                 " " + name + " " + primKey + " " + actionId + " takes " +
642                     stopWatch.getTime() + " ms");
643     }
644 
645     protected static final String RESULTS_SEPARATOR = "_RESULTS_SEPARATOR_";
646 
647     protected Map<Long, Boolean> companyAdmins = new HashMap<Long, Boolean>();
648 
649     private static Log _log =
650         LogFactory.getLog(AdvancedPermissionChecker.class);
651 
652 }