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