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