/* * Copyright 2012-2017 CodeLibs Project and the Others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.codelibs.fess.helper; import static org.codelibs.core.stream.StreamUtil.stream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.PostConstruct; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.codelibs.core.crypto.CachedCipher; import org.codelibs.core.lang.StringUtil; import org.codelibs.fess.app.service.AccessTokenService; import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType; import org.codelibs.fess.exception.InvalidAccessTokenException; import org.codelibs.fess.mylasta.action.FessUserBean; import org.codelibs.fess.mylasta.direction.FessConfig; import org.codelibs.fess.util.ComponentUtil; import org.lastaflute.web.servlet.request.RequestManager; import org.lastaflute.web.util.LaRequestUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class returns a list of a role from a request parameter, * a request header and a cookie. The format of the default value * is "[\d]+\nrole1,role2,role3", which you can encrypt. * * @author shinsuke * */ public class RoleQueryHelper { private static final String USER_ROLES = "userRoles"; private static final Logger logger = LoggerFactory.getLogger(RoleQueryHelper.class); public CachedCipher cipher; public String valueSeparator = "\n"; public String roleSeparator = ","; public String parameterKey; public boolean encryptedParameterValue = true; public String headerKey; public boolean encryptedHeaderValue = true; public String cookieKey; public boolean encryptedCookieValue = true; protected Map<String, String> cookieNameMap; private final List<String> defaultRoleList = new ArrayList<>(); @PostConstruct public void init() { stream(ComponentUtil.getFessConfig().getSearchDefaultPermissionsAsArray()).of(stream -> stream.forEach(name -> { defaultRoleList.add(name); })); } public Set<String> build(final SearchRequestType searchRequestType) { final Set<String> roleSet = new HashSet<>(); final HttpServletRequest request = LaRequestUtil.getOptionalRequest().orElse(null); final FessConfig fessConfig = ComponentUtil.getFessConfig(); final boolean isApiRequest = !SearchRequestType.SEARCH.equals(searchRequestType) && !SearchRequestType.ADMIN_SEARCH.equals(searchRequestType); if (request != null) { @SuppressWarnings("unchecked") final Set<String> list = (Set<String>) request.getAttribute(USER_ROLES); if (list != null) { return list; } // request parameter if (StringUtil.isNotBlank(parameterKey)) { processParameter(request, roleSet); } // request header if (StringUtil.isNotBlank(headerKey)) { processHeader(request, roleSet); } // cookie if (StringUtil.isNotBlank(cookieKey)) { processCookie(request, roleSet); } // cookie mapping if (cookieNameMap != null) { buildByCookieNameMapping(request, roleSet); } if (isApiRequest) { processAccessToken(request, roleSet); } final RequestManager requestManager = ComponentUtil.getRequestManager(); try { requestManager.findUserBean(FessUserBean.class) .ifPresent(fessUserBean -> stream(fessUserBean.getPermissions()).of(stream -> stream.forEach(roleSet::add))) .orElse(() -> { if (isApiRequest && ComponentUtil.getFessConfig().getApiAccessTokenRequiredAsBoolean()) { throw new InvalidAccessTokenException("invalid_token", "Access token is requried."); } roleSet.addAll(fessConfig.getSearchGuestPermissionList()); }); } catch (final RuntimeException e) { try { requestManager.findLoginManager(FessUserBean.class).ifPresent(manager -> manager.logout()); } catch (final Exception e1) { // ignore } throw e; } } if (defaultRoleList != null) { roleSet.addAll(defaultRoleList); } if (logger.isDebugEnabled()) { logger.debug("roleSet: " + roleSet); } if (request != null) { request.setAttribute(USER_ROLES, roleSet); } return roleSet; } protected void processAccessToken(final HttpServletRequest request, final Set<String> roleSet) { ComponentUtil.getComponent(AccessTokenService.class).getPermissions(request).ifPresent(p -> p.forEach(roleSet::add)); } protected String getAccessToken(final HttpServletRequest request) { final String token = request.getHeader("Authorization"); if (token != null) { final String[] values = token.trim().split(" "); if (values.length == 2 && "Bearer".equals(values[0])) { return values[1]; } throw new InvalidAccessTokenException("invalid_request", "Invalid format: " + token); } return request.getParameter("access_token"); } protected void processParameter(final HttpServletRequest request, final Set<String> roleSet) { final String parameter = request.getParameter(parameterKey); if (logger.isDebugEnabled()) { logger.debug(parameterKey + ":" + parameter); } if (StringUtil.isNotEmpty(parameter)) { parseRoleSet(parameter, encryptedParameterValue, roleSet); } } protected void processHeader(final HttpServletRequest request, final Set<String> roleSet) { final String parameter = request.getHeader(headerKey); if (logger.isDebugEnabled()) { logger.debug(headerKey + ":" + parameter); } if (StringUtil.isNotEmpty(parameter)) { parseRoleSet(parameter, encryptedHeaderValue, roleSet); } } protected void processCookie(final HttpServletRequest request, final Set<String> roleSet) { final Cookie[] cookies = request.getCookies(); if (cookies != null) { for (final Cookie cookie : cookies) { if (cookieKey.equals(cookie.getName())) { final String value = cookie.getValue(); if (logger.isDebugEnabled()) { logger.debug(cookieKey + ":" + value); } if (StringUtil.isNotEmpty(value)) { parseRoleSet(value, encryptedCookieValue, roleSet); } } } } } protected void buildByCookieNameMapping(final HttpServletRequest request, final Set<String> roleSet) { final Cookie[] cookies = request.getCookies(); if (cookies != null) { for (final Cookie cookie : cookies) { addRoleFromCookieMapping(roleSet, cookie); } } } protected void addRoleFromCookieMapping(final Set<String> roleNameList, final Cookie cookie) { final String roleName = cookieNameMap.get(cookie.getName()); if (StringUtil.isNotBlank(roleName)) { roleNameList.add(roleName); } } protected void parseRoleSet(final String value, final boolean encrypted, final Set<String> roleSet) { String rolesStr = value; if (encrypted && cipher != null) { rolesStr = cipher.decryptoText(rolesStr); } if (valueSeparator.length() > 0) { final String[] values = rolesStr.split(valueSeparator); if (values.length > 1) { final String[] roles = values[1].split(roleSeparator); for (final String role : roles) { if (StringUtil.isNotEmpty(role)) { roleSet.add(role); } } } } else { final String[] roles = rolesStr.split(roleSeparator); for (final String role : roles) { if (StringUtil.isNotEmpty(role)) { roleSet.add(role); } } } } public void addCookieNameMapping(final String cookieName, final String roleName) { if (cookieNameMap == null) { cookieNameMap = new HashMap<>(); } cookieNameMap.put(cookieName, roleName); } }