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