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.search;
016    
017    import com.liferay.portal.NoSuchResourceException;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.search.BooleanClauseOccur;
021    import com.liferay.portal.kernel.search.Document;
022    import com.liferay.portal.kernel.search.Field;
023    import com.liferay.portal.kernel.search.Indexer;
024    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
025    import com.liferay.portal.kernel.search.SearchContext;
026    import com.liferay.portal.kernel.search.SearchPermissionChecker;
027    import com.liferay.portal.kernel.search.filter.BooleanFilter;
028    import com.liferay.portal.kernel.search.filter.TermsFilter;
029    import com.liferay.portal.kernel.util.ArrayUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.ListUtil;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.model.Group;
035    import com.liferay.portal.model.GroupConstants;
036    import com.liferay.portal.model.ResourceConstants;
037    import com.liferay.portal.model.Role;
038    import com.liferay.portal.model.RoleConstants;
039    import com.liferay.portal.model.UserGroupRole;
040    import com.liferay.portal.security.permission.ActionKeys;
041    import com.liferay.portal.security.permission.AdvancedPermissionChecker;
042    import com.liferay.portal.security.permission.PermissionChecker;
043    import com.liferay.portal.security.permission.PermissionCheckerBag;
044    import com.liferay.portal.security.permission.PermissionThreadLocal;
045    import com.liferay.portal.security.permission.ResourceActionsUtil;
046    import com.liferay.portal.security.permission.ResourceBlockIdsBag;
047    import com.liferay.portal.service.GroupLocalServiceUtil;
048    import com.liferay.portal.service.ResourceBlockLocalServiceUtil;
049    import com.liferay.portal.service.ResourceBlockPermissionLocalServiceUtil;
050    import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
051    import com.liferay.portal.service.RoleLocalServiceUtil;
052    import com.liferay.portal.service.UserGroupRoleLocalServiceUtil;
053    import com.liferay.portal.util.PortalUtil;
054    
055    import java.util.ArrayList;
056    import java.util.HashMap;
057    import java.util.LinkedHashSet;
058    import java.util.List;
059    import java.util.Map;
060    import java.util.Set;
061    
062    /**
063     * @author Allen Chiang
064     * @author Bruno Farache
065     * @author Raymond Aug??
066     * @author Amos Fong
067     */
068    public class SearchPermissionCheckerImpl implements SearchPermissionChecker {
069    
070            @Override
071            public void addPermissionFields(long companyId, Document document) {
072                    try {
073                            long groupId = GetterUtil.getLong(document.get(Field.GROUP_ID));
074    
075                            String className = document.get(Field.ENTRY_CLASS_NAME);
076    
077                            boolean relatedEntry = GetterUtil.getBoolean(
078                                    document.get(Field.RELATED_ENTRY));
079    
080                            if (relatedEntry) {
081                                    long classNameId = GetterUtil.getLong(
082                                            document.get(Field.CLASS_NAME_ID));
083    
084                                    className = PortalUtil.getClassName(classNameId);
085                            }
086    
087                            if (Validator.isNull(className)) {
088                                    return;
089                            }
090    
091                            String classPK = document.get(Field.ROOT_ENTRY_CLASS_PK);
092    
093                            if (Validator.isNull(classPK)) {
094                                    classPK = document.get(Field.ENTRY_CLASS_PK);
095                            }
096    
097                            if (relatedEntry) {
098                                    classPK = document.get(Field.CLASS_PK);
099                            }
100    
101                            if (Validator.isNull(classPK)) {
102                                    return;
103                            }
104    
105                            Indexer indexer = IndexerRegistryUtil.getIndexer(className);
106    
107                            if (!indexer.isPermissionAware()) {
108                                    return;
109                            }
110    
111                            doAddPermissionFields_6(
112                                    companyId, groupId, className, classPK, document);
113                    }
114                    catch (NoSuchResourceException nsre) {
115                            if (_log.isDebugEnabled()) {
116                                    _log.debug(nsre, nsre);
117                            }
118                    }
119                    catch (Exception e) {
120                            _log.error(e, e);
121                    }
122            }
123    
124            @Override
125            public BooleanFilter getPermissionBooleanFilter(
126                    long companyId, long[] groupIds, long userId, String className,
127                    BooleanFilter booleanFilter, SearchContext searchContext) {
128    
129                    try {
130                            booleanFilter = doGetPermissionBooleanFilter(
131                                    companyId, groupIds, userId, className, booleanFilter,
132                                    searchContext);
133                    }
134                    catch (Exception e) {
135                            _log.error(e, e);
136                    }
137    
138                    return booleanFilter;
139            }
140    
141            @Override
142            public void updatePermissionFields(
143                    String resourceName, String resourceClassPK) {
144    
145                    try {
146                            doUpdatePermissionFields(resourceName, resourceClassPK);
147                    }
148                    catch (Exception e) {
149                            _log.error(e, e);
150                    }
151            }
152    
153            protected void addRequiredMemberRole(
154                            Group group, TermsFilter groupRolesTermsFilter)
155                    throws Exception {
156    
157                    if (group.isOrganization()) {
158                            Role organizationUserRole = RoleLocalServiceUtil.getRole(
159                                    group.getCompanyId(), RoleConstants.ORGANIZATION_USER);
160    
161                            groupRolesTermsFilter.addValue(
162                                    group.getGroupId() + StringPool.DASH +
163                                            organizationUserRole.getRoleId());
164                    }
165    
166                    if (group.isSite()) {
167                            Role siteMemberRole = RoleLocalServiceUtil.getRole(
168                                    group.getCompanyId(), RoleConstants.SITE_MEMBER);
169    
170                            groupRolesTermsFilter.addValue(
171                                    group.getGroupId() + StringPool.DASH +
172                                            siteMemberRole.getRoleId());
173                    }
174            }
175    
176            protected void doAddPermissionFields_6(
177                            long companyId, long groupId, String className, String classPK,
178                            Document doc)
179                    throws Exception {
180    
181                    Group group = null;
182    
183                    if (groupId > 0) {
184                            group = GroupLocalServiceUtil.getGroup(groupId);
185                    }
186    
187                    List<Role> roles = ListUtil.copy(
188                            ResourceActionsUtil.getRoles(companyId, group, className, null));
189    
190                    if (groupId > 0) {
191                            List<Role> teamRoles = RoleLocalServiceUtil.getTeamRoles(groupId);
192    
193                            roles.addAll(teamRoles);
194                    }
195    
196                    long[] roleIdsArray = new long[roles.size()];
197    
198                    for (int i = 0; i < roleIdsArray.length; i++) {
199                            Role role = roles.get(i);
200    
201                            roleIdsArray[i] = role.getRoleId();
202                    }
203    
204                    boolean[] hasResourcePermissions = null;
205    
206                    if (ResourceBlockLocalServiceUtil.isSupported(className)) {
207                            ResourceBlockIdsBag resourceBlockIdsBag =
208                                    ResourceBlockLocalServiceUtil.getResourceBlockIdsBag(
209                                            companyId, groupId, className, roleIdsArray);
210    
211                            long actionId = ResourceBlockLocalServiceUtil.getActionId(
212                                    className, ActionKeys.VIEW);
213    
214                            List<Long> resourceBlockIds =
215                                    resourceBlockIdsBag.getResourceBlockIds(actionId);
216    
217                            hasResourcePermissions = new boolean[roleIdsArray.length];
218    
219                            for (long resourceBlockId : resourceBlockIds) {
220                                    for (int i = 0; i < roleIdsArray.length; i++) {
221                                            int count =
222                                                    ResourceBlockPermissionLocalServiceUtil.
223                                                            getResourceBlockPermissionsCount(
224                                                                    resourceBlockId, roleIdsArray[i]);
225    
226                                            hasResourcePermissions[i] = (count > 0);
227                                    }
228                            }
229                    }
230                    else {
231                            hasResourcePermissions =
232                                    ResourcePermissionLocalServiceUtil.hasResourcePermissions(
233                                            companyId, className, ResourceConstants.SCOPE_INDIVIDUAL,
234                                            classPK, roleIdsArray, ActionKeys.VIEW);
235                    }
236    
237                    List<Long> roleIds = new ArrayList<>();
238                    List<String> groupRoleIds = new ArrayList<>();
239    
240                    for (int i = 0; i < hasResourcePermissions.length; i++) {
241                            if (!hasResourcePermissions[i]) {
242                                    continue;
243                            }
244    
245                            Role role = roles.get(i);
246    
247                            if ((role.getType() == RoleConstants.TYPE_ORGANIZATION) ||
248                                    (role.getType() == RoleConstants.TYPE_SITE)) {
249    
250                                    groupRoleIds.add(groupId + StringPool.DASH + role.getRoleId());
251                            }
252                            else {
253                                    roleIds.add(role.getRoleId());
254                            }
255                    }
256    
257                    doc.addKeyword(
258                            Field.ROLE_ID, roleIds.toArray(new Long[roleIds.size()]));
259                    doc.addKeyword(
260                            Field.GROUP_ROLE_ID,
261                            groupRoleIds.toArray(new String[groupRoleIds.size()]));
262            }
263    
264            protected BooleanFilter doGetPermissionBooleanFilter(
265                            long companyId, long[] groupIds, long userId, String className,
266                            BooleanFilter booleanFilter, SearchContext searchContext)
267                    throws Exception {
268    
269                    Indexer indexer = IndexerRegistryUtil.getIndexer(className);
270    
271                    if (!indexer.isPermissionAware()) {
272                            return booleanFilter;
273                    }
274    
275                    PermissionChecker permissionChecker =
276                            PermissionThreadLocal.getPermissionChecker();
277    
278                    AdvancedPermissionChecker advancedPermissionChecker = null;
279    
280                    if ((permissionChecker != null) &&
281                            (permissionChecker instanceof AdvancedPermissionChecker)) {
282    
283                            advancedPermissionChecker =
284                                    (AdvancedPermissionChecker)permissionChecker;
285                    }
286    
287                    if (advancedPermissionChecker == null) {
288                            return booleanFilter;
289                    }
290    
291                    PermissionCheckerBag permissionCheckerBag = getPermissionCheckerBag(
292                            advancedPermissionChecker, userId);
293    
294                    if (permissionCheckerBag == null) {
295                            return booleanFilter;
296                    }
297    
298                    Set<Group> groups = new LinkedHashSet<>();
299                    Set<Role> roles = new LinkedHashSet<>();
300                    Set<UserGroupRole> userGroupRoles = new LinkedHashSet<>();
301                    Map<Long, List<Role>> groupIdsToRoles = new HashMap<>();
302    
303                    populate(
304                            companyId, groupIds, userId, advancedPermissionChecker,
305                            permissionCheckerBag, groups, roles, userGroupRoles,
306                            groupIdsToRoles);
307    
308                    return doGetPermissionFilter_6(
309                            companyId, groupIds, userId, className, booleanFilter, groups,
310                            roles, userGroupRoles, groupIdsToRoles);
311            }
312    
313            protected BooleanFilter doGetPermissionFilter_6(
314                            long companyId, long[] groupIds, long userId, String className,
315                            BooleanFilter booleanFilter, Set<Group> groups, Set<Role> roles,
316                            Set<UserGroupRole> userGroupRoles,
317                            Map<Long, List<Role>> groupIdsToRoles)
318                    throws Exception {
319    
320                    BooleanFilter permissionBooleanFilter = new BooleanFilter();
321    
322                    if (userId > 0) {
323                            permissionBooleanFilter.addTerm(Field.USER_ID, userId);
324                    }
325    
326                    TermsFilter groupsTermsFilter = new TermsFilter(Field.GROUP_ID);
327                    TermsFilter groupRolesTermsFilter = new TermsFilter(
328                            Field.GROUP_ROLE_ID);
329                    TermsFilter rolesTermsFilter = new TermsFilter(Field.ROLE_ID);
330    
331                    for (Role role : roles) {
332                            String roleName = role.getName();
333    
334                            if (roleName.equals(RoleConstants.ADMINISTRATOR)) {
335                                    return booleanFilter;
336                            }
337    
338                            if (ResourcePermissionLocalServiceUtil.hasResourcePermission(
339                                            companyId, className, ResourceConstants.SCOPE_COMPANY,
340                                            String.valueOf(companyId), role.getRoleId(),
341                                            ActionKeys.VIEW)) {
342    
343                                    return booleanFilter;
344                            }
345    
346                            if ((role.getType() == RoleConstants.TYPE_REGULAR) &&
347                                    ResourcePermissionLocalServiceUtil.hasResourcePermission(
348                                            companyId, className,
349                                            ResourceConstants.SCOPE_GROUP_TEMPLATE,
350                                            String.valueOf(GroupConstants.DEFAULT_PARENT_GROUP_ID),
351                                            role.getRoleId(), ActionKeys.VIEW)) {
352    
353                                    return booleanFilter;
354                            }
355    
356                            for (Group group : groups) {
357                                    if (ResourcePermissionLocalServiceUtil.hasResourcePermission(
358                                                    companyId, className, ResourceConstants.SCOPE_GROUP,
359                                                    String.valueOf(group.getGroupId()), role.getRoleId(),
360                                                    ActionKeys.VIEW)) {
361    
362                                            groupsTermsFilter.addValue(
363                                                    String.valueOf(group.getGroupId()));
364                                    }
365    
366                                    if ((role.getType() != RoleConstants.TYPE_REGULAR) &&
367                                            ResourcePermissionLocalServiceUtil.hasResourcePermission(
368                                                    companyId, className,
369                                                    ResourceConstants.SCOPE_GROUP_TEMPLATE,
370                                                    String.valueOf(GroupConstants.DEFAULT_PARENT_GROUP_ID),
371                                                    role.getRoleId(), ActionKeys.VIEW)) {
372    
373                                            List<Role> groupRoles = groupIdsToRoles.get(
374                                                    group.getGroupId());
375    
376                                            if (groupRoles.contains(role)) {
377                                                    groupsTermsFilter.addValue(
378                                                            String.valueOf(group.getGroupId()));
379                                            }
380                                    }
381    
382                                    if (group.isSite() &&
383                                            !roleName.equals(RoleConstants.SITE_MEMBER) &&
384                                            (role.getType() == RoleConstants.TYPE_SITE)) {
385    
386                                            groupRolesTermsFilter.addValue(
387                                                    group.getGroupId() + StringPool.DASH +
388                                                            role.getRoleId());
389                                    }
390                            }
391    
392                            if (ArrayUtil.isNotEmpty(groupIds)) {
393                                    for (long groupId : groupIds) {
394                                            if (ResourcePermissionLocalServiceUtil.
395                                                            hasResourcePermission(
396                                                                    companyId, className,
397                                                                    ResourceConstants.SCOPE_GROUP,
398                                                                    String.valueOf(groupId), role.getRoleId(),
399                                                                    ActionKeys.VIEW)) {
400    
401                                                    groupsTermsFilter.addValue(String.valueOf(groupId));
402                                            }
403                                    }
404                            }
405    
406                            rolesTermsFilter.addValue(String.valueOf(role.getRoleId()));
407                    }
408    
409                    for (Group group : groups) {
410                            addRequiredMemberRole(group, groupRolesTermsFilter);
411                    }
412    
413                    for (UserGroupRole userGroupRole : userGroupRoles) {
414                            groupRolesTermsFilter.addValue(
415                                    userGroupRole.getGroupId() + StringPool.DASH +
416                                            userGroupRole.getRoleId());
417                    }
418    
419                    if (!groupsTermsFilter.isEmpty()) {
420                            permissionBooleanFilter.add(groupsTermsFilter);
421                    }
422    
423                    if (!groupRolesTermsFilter.isEmpty()) {
424                            permissionBooleanFilter.add(groupRolesTermsFilter);
425                    }
426    
427                    if (!rolesTermsFilter.isEmpty()) {
428                            permissionBooleanFilter.add(rolesTermsFilter);
429                    }
430    
431                    if (!permissionBooleanFilter.hasClauses()) {
432                            return booleanFilter;
433                    }
434    
435                    BooleanFilter fullBooleanFilter = new BooleanFilter();
436    
437                    if ((booleanFilter != null) && booleanFilter.hasClauses()) {
438                            fullBooleanFilter.add(booleanFilter, BooleanClauseOccur.MUST);
439                    }
440    
441                    fullBooleanFilter.add(permissionBooleanFilter, BooleanClauseOccur.MUST);
442    
443                    return fullBooleanFilter;
444            }
445    
446            protected void doUpdatePermissionFields(
447                            String resourceName, String resourceClassPK)
448                    throws Exception {
449    
450                    Indexer indexer = IndexerRegistryUtil.getIndexer(resourceName);
451    
452                    if (indexer != null) {
453                            indexer.reindex(resourceName, GetterUtil.getLong(resourceClassPK));
454                    }
455            }
456    
457            protected PermissionCheckerBag getPermissionCheckerBag(
458                            AdvancedPermissionChecker advancedPermissionChecker, long userId)
459                    throws Exception {
460    
461                    if (!advancedPermissionChecker.isSignedIn()) {
462                            return advancedPermissionChecker.getGuestUserBag();
463                    }
464                    else {
465                            return advancedPermissionChecker.getUserBag(userId, 0);
466                    }
467            }
468    
469            protected void populate(
470                            long companyId, long[] groupIds, long userId,
471                            AdvancedPermissionChecker advancedPermissionChecker,
472                            PermissionCheckerBag permissionCheckerBag, Set<Group> groups,
473                            Set<Role> roles, Set<UserGroupRole> userGroupRoles,
474                            Map<Long, List<Role>> groupIdsToRoles)
475                    throws Exception {
476    
477                    roles.addAll(permissionCheckerBag.getRoles());
478    
479                    if (ArrayUtil.isEmpty(groupIds)) {
480                            groups.addAll(GroupLocalServiceUtil.getUserGroups(userId, true));
481                            groups.addAll(permissionCheckerBag.getGroups());
482    
483                            userGroupRoles.addAll(
484                                    UserGroupRoleLocalServiceUtil.getUserGroupRoles(userId));
485                    }
486                    else {
487                            for (long groupId : groupIds) {
488                                    if (GroupLocalServiceUtil.hasUserGroup(userId, groupId)) {
489                                            Group group = GroupLocalServiceUtil.getGroup(groupId);
490    
491                                            groups.add(group);
492                                    }
493    
494                                    userGroupRoles.addAll(
495                                            UserGroupRoleLocalServiceUtil.getUserGroupRoles(
496                                                    userId, groupId));
497                                    userGroupRoles.addAll(
498                                            UserGroupRoleLocalServiceUtil.
499                                                    getUserGroupRolesByUserUserGroupAndGroup(
500                                                            userId, groupId));
501                            }
502                    }
503    
504                    if (advancedPermissionChecker.isSignedIn()) {
505                            roles.add(
506                                    RoleLocalServiceUtil.getRole(companyId, RoleConstants.GUEST));
507                    }
508    
509                    for (Group group : groups) {
510                            PermissionCheckerBag userBag = advancedPermissionChecker.getUserBag(
511                                    userId, group.getGroupId());
512    
513                            List<Role> groupRoles = ListUtil.fromCollection(userBag.getRoles());
514    
515                            groupIdsToRoles.put(group.getGroupId(), groupRoles);
516    
517                            roles.addAll(groupRoles);
518                    }
519            }
520    
521            private static final Log _log = LogFactoryUtil.getLog(
522                    SearchPermissionCheckerImpl.class);
523    
524    }