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