1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.codelibs.core.crypto.CachedCipher;
30 import org.codelibs.core.lang.StringUtil;
31 import org.codelibs.fess.app.service.AccessTokenService;
32 import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
33 import org.codelibs.fess.exception.InvalidAccessTokenException;
34 import org.codelibs.fess.mylasta.action.FessUserBean;
35 import org.codelibs.fess.mylasta.direction.FessConfig;
36 import org.codelibs.fess.util.ComponentUtil;
37 import org.lastaflute.web.login.LoginManager;
38 import org.lastaflute.web.servlet.request.RequestManager;
39 import org.lastaflute.web.util.LaRequestUtil;
40
41 import jakarta.annotation.PostConstruct;
42 import jakarta.servlet.http.Cookie;
43 import jakarta.servlet.http.HttpServletRequest;
44
45
46
47
48
49
50
51
52 public class RoleQueryHelper {
53
54
55
56
57 public RoleQueryHelper() {
58 super();
59 }
60
61 private static final Logger logger = LogManager.getLogger(RoleQueryHelper.class);
62
63
64
65
66 protected static final String USER_ROLES = "userRoles";
67
68
69
70
71 protected CachedCipher cipher;
72
73
74
75
76 protected String valueSeparator = "\n";
77
78
79
80
81 protected String roleSeparator = ",";
82
83
84
85
86 protected String parameterKey;
87
88
89
90
91 protected boolean encryptedParameterValue = true;
92
93
94
95
96 protected String headerKey;
97
98
99
100
101 protected boolean encryptedHeaderValue = true;
102
103
104
105
106 protected String cookieKey;
107
108
109
110
111 protected boolean encryptedCookieValue = true;
112
113
114
115
116 protected long maxAge = 30 * 60;
117
118
119
120
121 protected Map<String, String> cookieNameMap;
122
123
124
125
126 protected final List<String> defaultRoleList = new ArrayList<>();
127
128
129
130
131 @PostConstruct
132 public void init() {
133 if (logger.isDebugEnabled()) {
134 logger.debug("Initializing {}", this.getClass().getSimpleName());
135 }
136 stream(ComponentUtil.getFessConfig().getSearchDefaultPermissionsAsArray()).of(stream -> stream.forEach(name -> {
137 defaultRoleList.add(name);
138 }));
139 }
140
141
142
143
144
145
146 public Set<String> build(final SearchRequestType searchRequestType) {
147 final Set<String> roleSet = new HashSet<>();
148 final HttpServletRequest request = LaRequestUtil.getOptionalRequest().orElse(null);
149 final FessConfig fessConfig = ComponentUtil.getFessConfig();
150 final boolean isApiRequest =
151 !SearchRequestType.SEARCH.equals(searchRequestType) && !SearchRequestType.ADMIN_SEARCH.equals(searchRequestType);
152
153 if (request != null) {
154 @SuppressWarnings("unchecked")
155 final Set<String> list = (Set<String>) request.getAttribute(USER_ROLES);
156 if (list != null) {
157 return list;
158 }
159
160
161 if (StringUtil.isNotBlank(parameterKey)) {
162 processParameter(request, roleSet);
163 }
164
165
166 if (StringUtil.isNotBlank(headerKey)) {
167 processHeader(request, roleSet);
168 }
169
170
171 if (StringUtil.isNotBlank(cookieKey)) {
172 processCookie(request, roleSet);
173 }
174
175
176 if (cookieNameMap != null) {
177 buildByCookieNameMapping(request, roleSet);
178 }
179
180 final boolean hasAccessToken = processAccessToken(request, roleSet, isApiRequest);
181
182 final RequestManager requestManager = ComponentUtil.getRequestManager();
183 try {
184 requestManager.findUserBean(FessUserBean.class)
185 .ifPresent(fessUserBean -> stream(fessUserBean.getPermissions()).of(stream -> stream.forEach(roleSet::add)))
186 .orElse(() -> {
187 if (isApiRequest && ComponentUtil.getFessConfig().getApiAccessTokenRequiredAsBoolean()) {
188 throw new InvalidAccessTokenException("invalid_token", "Access token is requried.");
189 }
190 if (!hasAccessToken || roleSet.isEmpty()) {
191 roleSet.addAll(fessConfig.getSearchGuestRoleList());
192 }
193 });
194 } catch (final RuntimeException e) {
195 try {
196 requestManager.findLoginManager(FessUserBean.class).ifPresent(LoginManager::logout);
197 } catch (final Exception e1) {
198
199 }
200 throw e;
201 }
202 }
203
204 if (defaultRoleList != null) {
205 roleSet.addAll(defaultRoleList);
206 }
207
208 if (logger.isDebugEnabled()) {
209 logger.debug("roleSet: {}", roleSet);
210 }
211
212 if (request != null) {
213 request.setAttribute(USER_ROLES, roleSet);
214 }
215 return roleSet;
216 }
217
218
219
220
221
222
223
224
225 protected boolean processAccessToken(final HttpServletRequest request, final Set<String> roleSet, final boolean isApiRequest) {
226 if (isApiRequest) {
227 return ComponentUtil.getComponent(AccessTokenService.class).getPermissions(request).map(p -> {
228 p.forEach(roleSet::add);
229 return true;
230 }).orElse(false);
231 }
232 return false;
233 }
234
235
236
237
238
239
240 protected void processParameter(final HttpServletRequest request, final Set<String> roleSet) {
241 final String parameter = request.getParameter(parameterKey);
242 if (logger.isDebugEnabled()) {
243 logger.debug("{}:{}", parameterKey, parameter);
244 }
245 if (StringUtil.isNotEmpty(parameter)) {
246 parseRoleSet(parameter, encryptedParameterValue, roleSet);
247 }
248
249 }
250
251
252
253
254
255
256 protected void processHeader(final HttpServletRequest request, final Set<String> roleSet) {
257
258 final String parameter = request.getHeader(headerKey);
259 if (logger.isDebugEnabled()) {
260 logger.debug("{}:{}", headerKey, parameter);
261 }
262 if (StringUtil.isNotEmpty(parameter)) {
263 parseRoleSet(parameter, encryptedHeaderValue, roleSet);
264 }
265
266 }
267
268
269
270
271
272
273 protected void processCookie(final HttpServletRequest request, final Set<String> roleSet) {
274
275 final Cookie[] cookies = request.getCookies();
276 if (cookies != null) {
277 for (final Cookie cookie : cookies) {
278 if (cookieKey.equals(cookie.getName())) {
279 final String value = cookie.getValue();
280 if (logger.isDebugEnabled()) {
281 logger.debug("{}:{}", cookieKey, value);
282 }
283 if (StringUtil.isNotEmpty(value)) {
284 parseRoleSet(value, encryptedCookieValue, roleSet);
285 }
286 }
287 }
288 }
289
290 }
291
292
293
294
295
296
297 protected void buildByCookieNameMapping(final HttpServletRequest request, final Set<String> roleSet) {
298 final Cookie[] cookies = request.getCookies();
299 if (cookies != null) {
300 for (final Cookie cookie : cookies) {
301 addRoleFromCookieMapping(roleSet, cookie);
302 }
303 }
304
305 }
306
307
308
309
310
311
312 protected void addRoleFromCookieMapping(final Set<String> roleNameList, final Cookie cookie) {
313 final String roleName = cookieNameMap.get(cookie.getName());
314 if (StringUtil.isNotBlank(roleName)) {
315 roleNameList.add(roleName);
316 }
317 }
318
319
320
321
322
323
324
325 protected void parseRoleSet(final String value, final boolean encrypted, final Set<String> roleSet) {
326 String rolesStr = value;
327 if (encrypted && cipher != null) {
328 try {
329 rolesStr = cipher.decryptoText(rolesStr);
330 } catch (final Exception e) {
331 if (logger.isDebugEnabled()) {
332 logger.debug("Failed to decrypt {}", rolesStr, e);
333 }
334 return;
335 }
336 }
337
338 if (logger.isDebugEnabled()) {
339 logger.debug("role: original: {}, decrypto: {}", value, rolesStr);
340 }
341
342 if (valueSeparator.length() > 0) {
343 final String[] values = rolesStr.split(valueSeparator);
344 if (maxAge > 0) {
345 try {
346 final long time = getCurrentTime() / 1000 - Long.parseLong(values[0]);
347 if (time > maxAge || time < 0) {
348 if (logger.isDebugEnabled()) {
349 logger.debug("role info is expired: {} > {}", time, maxAge);
350 }
351 return;
352 }
353 } catch (final NumberFormatException e) {
354 logger.warn("Invalid role info: failed to parse timestamp from '{}'", rolesStr, e);
355 return;
356 }
357 }
358 if (values.length > 1) {
359 final String[] roles = values[1].split(roleSeparator);
360 for (final String role : roles) {
361 if (StringUtil.isNotEmpty(role)) {
362 roleSet.add(role);
363 }
364 }
365 }
366 } else {
367 final String[] roles = rolesStr.split(roleSeparator);
368 for (final String role : roles) {
369 if (StringUtil.isNotEmpty(role)) {
370 roleSet.add(role);
371 }
372 }
373 }
374 }
375
376
377
378
379
380 protected long getCurrentTime() {
381 return ComponentUtil.getSystemHelper().getCurrentTimeAsLong();
382 }
383
384
385
386
387
388
389 public void addCookieNameMapping(final String cookieName, final String roleName) {
390 if (cookieNameMap == null) {
391 cookieNameMap = new HashMap<>();
392 }
393 cookieNameMap.put(cookieName, roleName);
394 }
395
396
397
398
399
400 public void setCipher(final CachedCipher cipher) {
401 this.cipher = cipher;
402 }
403
404
405
406
407
408 public void setValueSeparator(final String valueSeparator) {
409 this.valueSeparator = valueSeparator;
410 }
411
412
413
414
415
416 public void setRoleSeparator(final String roleSeparator) {
417 this.roleSeparator = roleSeparator;
418 }
419
420
421
422
423
424 public void setParameterKey(final String parameterKey) {
425 this.parameterKey = parameterKey;
426 }
427
428
429
430
431
432 public void setEncryptedParameterValue(final boolean encryptedParameterValue) {
433 this.encryptedParameterValue = encryptedParameterValue;
434 }
435
436
437
438
439
440 public void setHeaderKey(final String headerKey) {
441 this.headerKey = headerKey;
442 }
443
444
445
446
447
448 public void setEncryptedHeaderValue(final boolean encryptedHeaderValue) {
449 this.encryptedHeaderValue = encryptedHeaderValue;
450 }
451
452
453
454
455
456 public void setCookieKey(final String cookieKey) {
457 this.cookieKey = cookieKey;
458 }
459
460
461
462
463
464 public void setEncryptedCookieValue(final boolean encryptedCookieValue) {
465 this.encryptedCookieValue = encryptedCookieValue;
466 }
467
468
469
470
471
472 public void setMaxAge(final long maxAge) {
473 this.maxAge = maxAge;
474 }
475
476 }