001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.permission;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.spring.osgi.OSGiBeanProperties;
019    import com.liferay.portal.model.Group;
020    import com.liferay.portal.model.Layout;
021    import com.liferay.portal.model.LayoutConstants;
022    import com.liferay.portal.model.LayoutType;
023    import com.liferay.portal.model.LayoutTypeController;
024    import com.liferay.portal.model.Organization;
025    import com.liferay.portal.model.ResourceConstants;
026    import com.liferay.portal.model.ResourcePermission;
027    import com.liferay.portal.model.User;
028    import com.liferay.portal.model.impl.VirtualLayout;
029    import com.liferay.portal.security.auth.PrincipalException;
030    import com.liferay.portal.security.permission.ActionKeys;
031    import com.liferay.portal.security.permission.BaseModelPermissionChecker;
032    import com.liferay.portal.security.permission.PermissionChecker;
033    import com.liferay.portal.service.GroupLocalServiceUtil;
034    import com.liferay.portal.service.LayoutLocalServiceUtil;
035    import com.liferay.portal.service.OrganizationLocalServiceUtil;
036    import com.liferay.portal.service.ResourceLocalServiceUtil;
037    import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
038    import com.liferay.portal.service.UserLocalServiceUtil;
039    import com.liferay.portal.util.PropsValues;
040    import com.liferay.portlet.exportimport.staging.permission.StagingPermissionUtil;
041    import com.liferay.sites.kernel.util.SitesUtil;
042    
043    import java.util.List;
044    
045    /**
046     * @author Charles May
047     * @author Brian Wing Shun Chan
048     * @author Raymond Aug??
049     */
050    @OSGiBeanProperties(
051            property = {"model.class.name=com.liferay.portal.model.Layout"}
052    )
053    public class LayoutPermissionImpl
054            implements BaseModelPermissionChecker, LayoutPermission {
055    
056            @Override
057            public void check(
058                            PermissionChecker permissionChecker, Layout layout,
059                            boolean checkViewableGroup, String actionId)
060                    throws PortalException {
061    
062                    if (!contains(
063                                    permissionChecker, layout, checkViewableGroup, actionId)) {
064    
065                            throw new PrincipalException.MustHavePermission(
066                                    permissionChecker, Layout.class.getName(), layout.getLayoutId(),
067                                    actionId);
068                    }
069            }
070    
071            @Override
072            public void check(
073                            PermissionChecker permissionChecker, Layout layout, String actionId)
074                    throws PortalException {
075    
076                    if (!contains(permissionChecker, layout, actionId)) {
077                            throw new PrincipalException.MustHavePermission(
078                                    permissionChecker, Layout.class.getName(), layout.getLayoutId(),
079                                    actionId);
080                    }
081            }
082    
083            @Override
084            public void check(
085                            PermissionChecker permissionChecker, long groupId,
086                            boolean privateLayout, long layoutId, String actionId)
087                    throws PortalException {
088    
089                    if (!contains(
090                                    permissionChecker, groupId, privateLayout, layoutId,
091                                    actionId)) {
092    
093                            throw new PrincipalException.MustHavePermission(
094                                    permissionChecker, Layout.class.getName(), layoutId, actionId);
095                    }
096            }
097    
098            @Override
099            public void check(
100                            PermissionChecker permissionChecker, long plid, String actionId)
101                    throws PortalException {
102    
103                    Layout layout = LayoutLocalServiceUtil.getLayout(plid);
104    
105                    check(permissionChecker, layout, actionId);
106            }
107    
108            @Override
109            public void checkBaseModel(
110                            PermissionChecker permissionChecker, long groupId, long primaryKey,
111                            String actionId)
112                    throws PortalException {
113    
114                    check(permissionChecker, primaryKey, actionId);
115            }
116    
117            @Override
118            public boolean contains(
119                            PermissionChecker permissionChecker, Layout layout,
120                            boolean checkViewableGroup, String actionId)
121                    throws PortalException {
122    
123                    if (actionId.equals(ActionKeys.VIEW)) {
124                            LayoutType layoutType = layout.getLayoutType();
125    
126                            LayoutTypeController layoutTypeController =
127                                    layoutType.getLayoutTypeController();
128    
129                            if (!layoutTypeController.isCheckLayoutViewPermission()) {
130                                    return true;
131                            }
132                    }
133    
134                    if (layout.isTypeControlPanel()) {
135                            if (!permissionChecker.isSignedIn()) {
136                                    return false;
137                            }
138    
139                            return true;
140                    }
141    
142                    if (actionId.equals(ActionKeys.CUSTOMIZE) &&
143                            (layout instanceof VirtualLayout)) {
144    
145                            VirtualLayout virtualLayout = (VirtualLayout)layout;
146    
147                            layout = virtualLayout.getWrappedModel();
148                    }
149    
150                    if (isAttemptToModifyLockedLayout(layout, actionId)) {
151                            return false;
152                    }
153    
154                    Boolean hasPermission = StagingPermissionUtil.hasPermission(
155                            permissionChecker, layout.getGroup(), Layout.class.getName(),
156                            layout.getGroupId(), null, actionId);
157    
158                    if (hasPermission != null) {
159                            return hasPermission.booleanValue();
160                    }
161    
162                    return containsWithViewableGroup(
163                            permissionChecker, layout, checkViewableGroup, actionId);
164            }
165    
166            @Override
167            public boolean contains(
168                            PermissionChecker permissionChecker, Layout layout, String actionId)
169                    throws PortalException {
170    
171                    return contains(permissionChecker, layout, false, actionId);
172            }
173    
174            /**
175             * @deprecated As of 6.2.0, replaced by {@link #contains(PermissionChecker,
176             *             Layout, boolean, String)}
177             */
178            @Deprecated
179            @Override
180            public boolean contains(
181                            PermissionChecker permissionChecker, Layout layout,
182                            String controlPanelCategory, boolean checkViewableGroup,
183                            String actionId)
184                    throws PortalException {
185    
186                    return contains(
187                            permissionChecker, layout, checkViewableGroup, actionId);
188            }
189    
190            /**
191             * @deprecated As of 6.2.0, replaced by {@link #contains(PermissionChecker,
192             *             Layout, String)}
193             */
194            @Deprecated
195            @Override
196            public boolean contains(
197                            PermissionChecker permissionChecker, Layout layout,
198                            String controlPanelCategory, String actionId)
199                    throws PortalException {
200    
201                    return contains(permissionChecker, layout, actionId);
202            }
203    
204            @Override
205            public boolean contains(
206                            PermissionChecker permissionChecker, long groupId,
207                            boolean privateLayout, long layoutId, String actionId)
208                    throws PortalException {
209    
210                    Layout layout = LayoutLocalServiceUtil.getLayout(
211                            groupId, privateLayout, layoutId);
212    
213                    return contains(permissionChecker, layout, actionId);
214            }
215    
216            /**
217             * @deprecated As of 6.2.0, replaced by {@link #contains(PermissionChecker,
218             *             long, boolean, long, String)}
219             */
220            @Deprecated
221            @Override
222            public boolean contains(
223                            PermissionChecker permissionChecker, long groupId,
224                            boolean privateLayout, long layoutId, String controlPanelCategory,
225                            String actionId)
226                    throws PortalException {
227    
228                    return contains(
229                            permissionChecker, groupId, privateLayout, layoutId, actionId);
230            }
231    
232            @Override
233            public boolean contains(
234                            PermissionChecker permissionChecker, long plid, String actionId)
235                    throws PortalException {
236    
237                    Layout layout = LayoutLocalServiceUtil.getLayout(plid);
238    
239                    return contains(permissionChecker, layout, actionId);
240            }
241    
242            @Override
243            public boolean containsWithoutViewableGroup(
244                            PermissionChecker permissionChecker, Layout layout,
245                            boolean checkLayoutUpdateable, String actionId)
246                    throws PortalException {
247    
248                    if (layout.isTypeControlPanel()) {
249                            return false;
250                    }
251    
252                    if (checkLayoutUpdateable && !actionId.equals(ActionKeys.CUSTOMIZE) &&
253                            !actionId.equals(ActionKeys.VIEW) &&
254                            (layout instanceof VirtualLayout)) {
255    
256                            return false;
257                    }
258    
259                    if (actionId.equals(ActionKeys.CUSTOMIZE) &&
260                            (layout instanceof VirtualLayout)) {
261    
262                            VirtualLayout virtualLayout = (VirtualLayout)layout;
263    
264                            layout = virtualLayout.getWrappedModel();
265                    }
266    
267                    if (actionId.equals(ActionKeys.ADD_LAYOUT)) {
268                            if (!SitesUtil.isLayoutSortable(layout)) {
269                                    return false;
270                            }
271    
272                            LayoutType layoutType = layout.getLayoutType();
273    
274                            if (!layoutType.isParentable()) {
275                                    return false;
276                            }
277                    }
278    
279                    if (actionId.equals(ActionKeys.DELETE) &&
280                            !SitesUtil.isLayoutDeleteable(layout)) {
281    
282                            return false;
283                    }
284    
285                    Group group = layout.getGroup();
286    
287                    if (checkLayoutUpdateable && !group.isLayoutSetPrototype() &&
288                            isAttemptToModifyLockedLayout(layout, actionId)) {
289    
290                            return false;
291                    }
292    
293                    User user = permissionChecker.getUser();
294    
295                    if (!user.isDefaultUser() && !group.isUser()) {
296    
297                            // This is new way of doing an ownership check without having to
298                            // have a userId field on the model. When the instance model was
299                            // first created, we set the user's userId as the ownerId of the
300                            // individual scope ResourcePermission of the Owner Role. Therefore,
301                            // ownership can be determined by obtaining the Owner role
302                            // ResourcePermission for the current instance model and testing it
303                            // with the hasOwnerPermission call.
304    
305                            ResourcePermission resourcePermission =
306                                    ResourcePermissionLocalServiceUtil.getResourcePermission(
307                                            layout.getCompanyId(), Layout.class.getName(),
308                                            ResourceConstants.SCOPE_INDIVIDUAL,
309                                            String.valueOf(layout.getPlid()),
310                                            permissionChecker.getOwnerRoleId());
311    
312                            if (permissionChecker.hasOwnerPermission(
313                                            layout.getCompanyId(), Layout.class.getName(),
314                                            String.valueOf(layout.getPlid()),
315                                            resourcePermission.getOwnerId(), actionId)) {
316    
317                                    return true;
318                            }
319                    }
320    
321                    if (actionId.equals(ActionKeys.ADD_LAYOUT) &&
322                            GroupPermissionUtil.contains(
323                                    permissionChecker, group, ActionKeys.ADD_LAYOUT)) {
324    
325                            return true;
326                    }
327    
328                    if (GroupPermissionUtil.contains(
329                                    permissionChecker, group, ActionKeys.MANAGE_LAYOUTS)) {
330    
331                            return true;
332                    }
333    
334                    if (PropsValues.PERMISSIONS_VIEW_DYNAMIC_INHERITANCE &&
335                            !actionId.equals(ActionKeys.VIEW)) {
336    
337                            // Check upward recursively to see if any pages above grant the
338                            // action
339    
340                            long parentLayoutId = layout.getParentLayoutId();
341    
342                            while (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
343                                    Layout parentLayout = LayoutLocalServiceUtil.getLayout(
344                                            layout.getGroupId(), layout.isPrivateLayout(),
345                                            parentLayoutId);
346    
347                                    if (contains(permissionChecker, parentLayout, actionId)) {
348                                            return true;
349                                    }
350    
351                                    parentLayoutId = parentLayout.getParentLayoutId();
352                            }
353                    }
354    
355                    int resourcePermissionsCount =
356                            ResourcePermissionLocalServiceUtil.getResourcePermissionsCount(
357                                    layout.getCompanyId(), Layout.class.getName(),
358                                    ResourceConstants.SCOPE_INDIVIDUAL,
359                                    String.valueOf(layout.getPlid()));
360    
361                    if (resourcePermissionsCount == 0) {
362                            boolean addGroupPermission = true;
363                            boolean addGuestPermission = true;
364    
365                            if (layout.isPrivateLayout()) {
366                                    addGuestPermission = false;
367                            }
368    
369                            ResourceLocalServiceUtil.addResources(
370                                    layout.getCompanyId(), layout.getGroupId(), 0,
371                                    Layout.class.getName(), layout.getPlid(), false,
372                                    addGroupPermission, addGuestPermission);
373                    }
374    
375                    return permissionChecker.hasPermission(
376                            layout.getGroupId(), Layout.class.getName(), layout.getPlid(),
377                            actionId);
378            }
379    
380            @Override
381            public boolean containsWithoutViewableGroup(
382                            PermissionChecker permissionChecker, Layout layout, String actionId)
383                    throws PortalException {
384    
385                    return containsWithoutViewableGroup(
386                            permissionChecker, layout, true, actionId);
387            }
388    
389            /**
390             * @deprecated As of 6.2.0, replaced by {@link
391             *             #containsWithoutViewableGroup(PermissionChecker, Layout,
392             *             boolean, String)}
393             */
394            @Deprecated
395            @Override
396            public boolean containsWithoutViewableGroup(
397                            PermissionChecker permissionChecker, Layout layout,
398                            String controlPanelCategory, boolean checkLayoutUpdateable,
399                            String actionId)
400                    throws PortalException {
401    
402                    return containsWithoutViewableGroup(
403                            permissionChecker, layout, checkLayoutUpdateable, actionId);
404            }
405    
406            /**
407             * @deprecated As of 6.2.0, replaced by {@link
408             *             #containsWithoutViewableGroup(PermissionChecker, Layout,
409             *             String)}
410             */
411            @Deprecated
412            @Override
413            public boolean containsWithoutViewableGroup(
414                            PermissionChecker permissionChecker, Layout layout,
415                            String controlPanelCategory, String actionId)
416                    throws PortalException {
417    
418                    return containsWithoutViewableGroup(
419                            permissionChecker, layout, actionId);
420            }
421    
422            protected boolean containsWithViewableGroup(
423                            PermissionChecker permissionChecker, Layout layout,
424                            boolean checkViewableGroup, String actionId)
425                    throws PortalException {
426    
427                    if (actionId.equals(ActionKeys.VIEW) && checkViewableGroup) {
428                            return isViewableGroup(
429                                    permissionChecker, layout, checkViewableGroup);
430                    }
431    
432                    return containsWithoutViewableGroup(
433                            permissionChecker, layout, actionId);
434            }
435    
436            protected boolean isAttemptToModifyLockedLayout(
437                    Layout layout, String actionId) {
438    
439                    if ((ActionKeys.CUSTOMIZE.equals(actionId) ||
440                             ActionKeys.UPDATE.equals(actionId)) &&
441                            !SitesUtil.isLayoutUpdateable(layout)) {
442    
443                            return true;
444                    }
445    
446                    return false;
447            }
448    
449            protected boolean isViewableGroup(
450                            PermissionChecker permissionChecker, Layout layout,
451                            boolean checkResourcePermission)
452                    throws PortalException {
453    
454                    Group group = GroupLocalServiceUtil.getGroup(layout.getGroupId());
455    
456                    // Inactive sites are not viewable
457    
458                    if (!group.isActive()) {
459                            return false;
460                    }
461                    else if (group.isStagingGroup()) {
462                            Group liveGroup = group.getLiveGroup();
463    
464                            if (!liveGroup.isActive()) {
465                                    return false;
466                            }
467                    }
468    
469                    // User private layouts are only viewable by the user and anyone who can
470                    // update the user. The user must also be active.
471    
472                    if (group.isUser()) {
473                            long groupUserId = group.getClassPK();
474    
475                            if (groupUserId == permissionChecker.getUserId()) {
476                                    return true;
477                            }
478    
479                            User groupUser = UserLocalServiceUtil.getUserById(groupUserId);
480    
481                            if (!groupUser.isActive()) {
482                                    return false;
483                            }
484    
485                            if (layout.isPrivateLayout()) {
486                                    if (GroupPermissionUtil.contains(
487                                                    permissionChecker, group, ActionKeys.MANAGE_LAYOUTS) ||
488                                            UserPermissionUtil.contains(
489                                                    permissionChecker, groupUserId,
490                                                    groupUser.getOrganizationIds(), ActionKeys.UPDATE)) {
491    
492                                            return true;
493                                    }
494    
495                                    return false;
496                            }
497                    }
498    
499                    // If the current group is staging, only users with editorial rights can
500                    // access it
501    
502                    if (group.isStagingGroup()) {
503                            if (GroupPermissionUtil.contains(
504                                            permissionChecker, group, ActionKeys.VIEW_STAGING)) {
505    
506                                    return true;
507                            }
508    
509                            return false;
510                    }
511    
512                    // Site layouts are only viewable by users who are members of the site
513                    // or by users who can update the site
514    
515                    if (group.isSite()) {
516                            if (GroupPermissionUtil.contains(
517                                            permissionChecker, group, ActionKeys.MANAGE_LAYOUTS) ||
518                                    GroupPermissionUtil.contains(
519                                            permissionChecker, group, ActionKeys.UPDATE)) {
520    
521                                    return true;
522                            }
523    
524                            if (layout.isPrivateLayout() &&
525                                    !permissionChecker.isGroupMember(group.getGroupId())) {
526    
527                                    return false;
528                            }
529                    }
530    
531                    // Organization site layouts are also viewable by users who belong to
532                    // the organization or by users who can update organization
533    
534                    if (group.isCompany()) {
535                            return false;
536                    }
537                    else if (group.isLayoutPrototype()) {
538                            if (LayoutPrototypePermissionUtil.contains(
539                                            permissionChecker, group.getClassPK(), ActionKeys.VIEW)) {
540    
541                                    return true;
542                            }
543    
544                            return false;
545                    }
546                    else if (group.isLayoutSetPrototype()) {
547                            if (LayoutSetPrototypePermissionUtil.contains(
548                                            permissionChecker, group.getClassPK(), ActionKeys.VIEW)) {
549    
550                                    return true;
551                            }
552    
553                            return false;
554                    }
555                    else if (group.isOrganization()) {
556                            long organizationId = group.getOrganizationId();
557    
558                            if (OrganizationLocalServiceUtil.hasUserOrganization(
559                                            permissionChecker.getUserId(), organizationId, false,
560                                            false)) {
561    
562                                    return true;
563                            }
564                            else if (OrganizationPermissionUtil.contains(
565                                                    permissionChecker, organizationId, ActionKeys.UPDATE)) {
566    
567                                    return true;
568                            }
569    
570                            if (!PropsValues.ORGANIZATIONS_MEMBERSHIP_STRICT) {
571                                    List<Organization> userOrgs =
572                                            OrganizationLocalServiceUtil.getUserOrganizations(
573                                                    permissionChecker.getUserId());
574    
575                                    for (Organization organization : userOrgs) {
576                                            for (Organization ancestorOrganization :
577                                                            organization.getAncestors()) {
578    
579                                                    if (organizationId ==
580                                                                    ancestorOrganization.getOrganizationId()) {
581    
582                                                            return true;
583                                                    }
584                                            }
585                                    }
586                            }
587                    }
588                    else if (group.isUserGroup()) {
589                            if (UserGroupPermissionUtil.contains(
590                                            permissionChecker, group.getClassPK(), ActionKeys.UPDATE)) {
591    
592                                    return true;
593                            }
594                    }
595    
596                    // Only check the actual Layout if all of the above failed
597    
598                    if (containsWithoutViewableGroup(
599                                    permissionChecker, layout, ActionKeys.VIEW)) {
600    
601                            return true;
602                    }
603    
604                    // As a last resort, check if any top level pages are viewable by the
605                    // user
606    
607                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
608                            layout.getGroupId(), layout.isPrivateLayout(),
609                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
610    
611                    for (Layout curLayout : layouts) {
612                            if (containsWithoutViewableGroup(
613                                            permissionChecker, curLayout, ActionKeys.VIEW) &&
614                                    !curLayout.isHidden()) {
615    
616                                    return true;
617                            }
618                    }
619    
620                    return false;
621            }
622    
623    }