View Javadoc
1   /*
2    * Copyright 2012-2017 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.helper;
17  
18  import static org.codelibs.core.stream.StreamUtil.stream;
19  
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import javax.annotation.PostConstruct;
28  import javax.servlet.http.Cookie;
29  import javax.servlet.http.HttpServletRequest;
30  
31  import org.codelibs.core.crypto.CachedCipher;
32  import org.codelibs.core.lang.StringUtil;
33  import org.codelibs.fess.app.service.AccessTokenService;
34  import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
35  import org.codelibs.fess.exception.InvalidAccessTokenException;
36  import org.codelibs.fess.mylasta.action.FessUserBean;
37  import org.codelibs.fess.mylasta.direction.FessConfig;
38  import org.codelibs.fess.util.ComponentUtil;
39  import org.lastaflute.web.servlet.request.RequestManager;
40  import org.lastaflute.web.util.LaRequestUtil;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  /**
45   * This class returns a list of a role from a request parameter,
46   * a request header and a cookie. The format of the default value
47   * is "[\d]+\nrole1,role2,role3", which you can encrypt.
48   *
49   * @author shinsuke
50   *
51   */
52  public class RoleQueryHelper {
53  
54      private static final String USER_ROLES = "userRoles";
55  
56      private static final Logger logger = LoggerFactory.getLogger(RoleQueryHelper.class);
57  
58      public CachedCipher cipher;
59  
60      public String valueSeparator = "\n";
61  
62      public String roleSeparator = ",";
63  
64      public String parameterKey;
65  
66      public boolean encryptedParameterValue = true;
67  
68      public String headerKey;
69  
70      public boolean encryptedHeaderValue = true;
71  
72      public String cookieKey;
73  
74      public boolean encryptedCookieValue = true;
75  
76      protected Map<String, String> cookieNameMap;
77  
78      private final List<String> defaultRoleList = new ArrayList<>();
79  
80      @PostConstruct
81      public void init() {
82          stream(ComponentUtil.getFessConfig().getSearchDefaultPermissionsAsArray()).of(stream -> stream.forEach(name -> {
83              defaultRoleList.add(name);
84          }));
85      }
86  
87      public Set<String> build(final SearchRequestType searchRequestType) {
88          final Set<String> roleSet = new HashSet<>();
89          final HttpServletRequest request = LaRequestUtil.getOptionalRequest().orElse(null);
90          final FessConfig fessConfig = ComponentUtil.getFessConfig();
91          final boolean isApiRequest =
92                  !SearchRequestType.SEARCH.equals(searchRequestType) && !SearchRequestType.ADMIN_SEARCH.equals(searchRequestType);
93  
94          if (request != null) {
95              @SuppressWarnings("unchecked")
96              final Set<String> list = (Set<String>) request.getAttribute(USER_ROLES);
97              if (list != null) {
98                  return list;
99              }
100 
101             // request parameter
102             if (StringUtil.isNotBlank(parameterKey)) {
103                 processParameter(request, roleSet);
104             }
105 
106             // request header
107             if (StringUtil.isNotBlank(headerKey)) {
108                 processHeader(request, roleSet);
109             }
110 
111             // cookie
112             if (StringUtil.isNotBlank(cookieKey)) {
113                 processCookie(request, roleSet);
114             }
115 
116             // cookie mapping
117             if (cookieNameMap != null) {
118                 buildByCookieNameMapping(request, roleSet);
119             }
120 
121             if (isApiRequest) {
122                 processAccessToken(request, roleSet);
123             }
124 
125             final RequestManager requestManager = ComponentUtil.getRequestManager();
126             try {
127                 requestManager.findUserBean(FessUserBean.class)
128                         .ifPresent(fessUserBean -> stream(fessUserBean.getPermissions()).of(stream -> stream.forEach(roleSet::add)))
129                         .orElse(() -> {
130                             if (isApiRequest && ComponentUtil.getFessConfig().getApiAccessTokenRequiredAsBoolean()) {
131                                 throw new InvalidAccessTokenException("invalid_token", "Access token is requried.");
132                             }
133                             roleSet.addAll(fessConfig.getSearchGuestPermissionList());
134                         });
135             } catch (final RuntimeException e) {
136                 try {
137                     requestManager.findLoginManager(FessUserBean.class).ifPresent(manager -> manager.logout());
138                 } catch (final Exception e1) {
139                     // ignore
140                 }
141                 throw e;
142             }
143         }
144 
145         if (defaultRoleList != null) {
146             roleSet.addAll(defaultRoleList);
147         }
148 
149         if (logger.isDebugEnabled()) {
150             logger.debug("roleSet: " + roleSet);
151         }
152 
153         if (request != null) {
154             request.setAttribute(USER_ROLES, roleSet);
155         }
156         return roleSet;
157     }
158 
159     protected void processAccessToken(final HttpServletRequest request, final Set<String> roleSet) {
160         ComponentUtil.getComponent(AccessTokenService.class).getPermissions(request).ifPresent(p -> p.forEach(roleSet::add));
161     }
162 
163     protected String getAccessToken(final HttpServletRequest request) {
164         final String token = request.getHeader("Authorization");
165         if (token != null) {
166             final String[] values = token.trim().split(" ");
167             if (values.length == 2 && "Bearer".equals(values[0])) {
168                 return values[1];
169             }
170             throw new InvalidAccessTokenException("invalid_request", "Invalid format: " + token);
171         }
172         return request.getParameter("access_token");
173     }
174 
175     protected void processParameter(final HttpServletRequest request, final Set<String> roleSet) {
176         final String parameter = request.getParameter(parameterKey);
177         if (logger.isDebugEnabled()) {
178             logger.debug(parameterKey + ":" + parameter);
179         }
180         if (StringUtil.isNotEmpty(parameter)) {
181             parseRoleSet(parameter, encryptedParameterValue, roleSet);
182         }
183 
184     }
185 
186     protected void processHeader(final HttpServletRequest request, final Set<String> roleSet) {
187 
188         final String parameter = request.getHeader(headerKey);
189         if (logger.isDebugEnabled()) {
190             logger.debug(headerKey + ":" + parameter);
191         }
192         if (StringUtil.isNotEmpty(parameter)) {
193             parseRoleSet(parameter, encryptedHeaderValue, roleSet);
194         }
195 
196     }
197 
198     protected void processCookie(final HttpServletRequest request, final Set<String> roleSet) {
199 
200         final Cookie[] cookies = request.getCookies();
201         if (cookies != null) {
202             for (final Cookie cookie : cookies) {
203                 if (cookieKey.equals(cookie.getName())) {
204                     final String value = cookie.getValue();
205                     if (logger.isDebugEnabled()) {
206                         logger.debug(cookieKey + ":" + value);
207                     }
208                     if (StringUtil.isNotEmpty(value)) {
209                         parseRoleSet(value, encryptedCookieValue, roleSet);
210                     }
211                 }
212             }
213         }
214 
215     }
216 
217     protected void buildByCookieNameMapping(final HttpServletRequest request, final Set<String> roleSet) {
218         final Cookie[] cookies = request.getCookies();
219         if (cookies != null) {
220             for (final Cookie cookie : cookies) {
221                 addRoleFromCookieMapping(roleSet, cookie);
222             }
223         }
224 
225     }
226 
227     protected void addRoleFromCookieMapping(final Set<String> roleNameList, final Cookie cookie) {
228         final String roleName = cookieNameMap.get(cookie.getName());
229         if (StringUtil.isNotBlank(roleName)) {
230             roleNameList.add(roleName);
231         }
232     }
233 
234     protected void parseRoleSet(final String value, final boolean encrypted, final Set<String> roleSet) {
235         String rolesStr = value;
236         if (encrypted && cipher != null) {
237             rolesStr = cipher.decryptoText(rolesStr);
238         }
239 
240         if (valueSeparator.length() > 0) {
241             final String[] values = rolesStr.split(valueSeparator);
242             if (values.length > 1) {
243                 final String[] roles = values[1].split(roleSeparator);
244                 for (final String role : roles) {
245                     if (StringUtil.isNotEmpty(role)) {
246                         roleSet.add(role);
247                     }
248                 }
249             }
250         } else {
251             final String[] roles = rolesStr.split(roleSeparator);
252             for (final String role : roles) {
253                 if (StringUtil.isNotEmpty(role)) {
254                     roleSet.add(role);
255                 }
256             }
257         }
258     }
259 
260     public void addCookieNameMapping(final String cookieName, final String roleName) {
261         if (cookieNameMap == null) {
262             cookieNameMap = new HashMap<>();
263         }
264         cookieNameMap.put(cookieName, roleName);
265     }
266 
267 }