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 javax.annotation.PostConstruct;
28 import javax.servlet.http.Cookie;
29 import javax.servlet.http.HttpServletRequest;
30
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.Logger;
33 import org.codelibs.core.crypto.CachedCipher;
34 import org.codelibs.core.lang.StringUtil;
35 import org.codelibs.fess.app.service.AccessTokenService;
36 import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
37 import org.codelibs.fess.exception.InvalidAccessTokenException;
38 import org.codelibs.fess.mylasta.action.FessUserBean;
39 import org.codelibs.fess.mylasta.direction.FessConfig;
40 import org.codelibs.fess.util.ComponentUtil;
41 import org.lastaflute.web.login.LoginManager;
42 import org.lastaflute.web.servlet.request.RequestManager;
43 import org.lastaflute.web.util.LaRequestUtil;
44
45
46
47
48
49
50
51
52
53 public class RoleQueryHelper {
54
55 private static final Logger logger = LogManager.getLogger(RoleQueryHelper.class);
56
57 protected static final String USER_ROLES = "userRoles";
58
59 protected CachedCipher cipher;
60
61 protected String valueSeparator = "\n";
62
63 protected String roleSeparator = ",";
64
65 protected String parameterKey;
66
67 protected boolean encryptedParameterValue = true;
68
69 protected String headerKey;
70
71 protected boolean encryptedHeaderValue = true;
72
73 protected String cookieKey;
74
75 protected boolean encryptedCookieValue = true;
76
77 protected long maxAge = 30 * 60;
78
79 protected Map<String, String> cookieNameMap;
80
81 protected final List<String> defaultRoleList = new ArrayList<>();
82
83 @PostConstruct
84 public void init() {
85 if (logger.isDebugEnabled()) {
86 logger.debug("Initialize {}", this.getClass().getSimpleName());
87 }
88 stream(ComponentUtil.getFessConfig().getSearchDefaultPermissionsAsArray()).of(stream -> stream.forEach(name -> {
89 defaultRoleList.add(name);
90 }));
91 }
92
93 public Set<String> build(final SearchRequestType searchRequestType) {
94 final Set<String> roleSet = new HashSet<>();
95 final HttpServletRequest request = LaRequestUtil.getOptionalRequest().orElse(null);
96 final FessConfig fessConfig = ComponentUtil.getFessConfig();
97 final boolean isApiRequest =
98 !SearchRequestType.SEARCH.equals(searchRequestType) && !SearchRequestType.ADMIN_SEARCH.equals(searchRequestType);
99
100 if (request != null) {
101 @SuppressWarnings("unchecked")
102 final Set<String> list = (Set<String>) request.getAttribute(USER_ROLES);
103 if (list != null) {
104 return list;
105 }
106
107
108 if (StringUtil.isNotBlank(parameterKey)) {
109 processParameter(request, roleSet);
110 }
111
112
113 if (StringUtil.isNotBlank(headerKey)) {
114 processHeader(request, roleSet);
115 }
116
117
118 if (StringUtil.isNotBlank(cookieKey)) {
119 processCookie(request, roleSet);
120 }
121
122
123 if (cookieNameMap != null) {
124 buildByCookieNameMapping(request, roleSet);
125 }
126
127 final boolean hasAccessToken = processAccessToken(request, roleSet, isApiRequest);
128
129 final RequestManager requestManager = ComponentUtil.getRequestManager();
130 try {
131 requestManager.findUserBean(FessUserBean.class)
132 .ifPresent(fessUserBean -> stream(fessUserBean.getPermissions()).of(stream -> stream.forEach(roleSet::add)))
133 .orElse(() -> {
134 if (isApiRequest && ComponentUtil.getFessConfig().getApiAccessTokenRequiredAsBoolean()) {
135 throw new InvalidAccessTokenException("invalid_token", "Access token is requried.");
136 }
137 if (!hasAccessToken || roleSet.isEmpty()) {
138 roleSet.addAll(fessConfig.getSearchGuestPermissionList());
139 }
140 });
141 } catch (final RuntimeException e) {
142 try {
143 requestManager.findLoginManager(FessUserBean.class).ifPresent(LoginManager::logout);
144 } catch (final Exception e1) {
145
146 }
147 throw e;
148 }
149 }
150
151 if (defaultRoleList != null) {
152 roleSet.addAll(defaultRoleList);
153 }
154
155 if (logger.isDebugEnabled()) {
156 logger.debug("roleSet: {}", roleSet);
157 }
158
159 if (request != null) {
160 request.setAttribute(USER_ROLES, roleSet);
161 }
162 return roleSet;
163 }
164
165 protected boolean processAccessToken(final HttpServletRequest request, final Set<String> roleSet, final boolean isApiRequest) {
166 if (isApiRequest) {
167 return ComponentUtil.getComponent(AccessTokenService.class).getPermissions(request).map(p -> {
168 p.forEach(roleSet::add);
169 return true;
170 }).orElse(false);
171 }
172 return false;
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 try {
238 rolesStr = cipher.decryptoText(rolesStr);
239 } catch (final Exception e) {
240 if (logger.isDebugEnabled()) {
241 logger.debug("Failed to decrypt {}", rolesStr, e);
242 }
243 return;
244 }
245 }
246
247 if (logger.isDebugEnabled()) {
248 logger.debug("role: original: {}, decrypto: {}", value, rolesStr);
249 }
250
251 if (valueSeparator.length() > 0) {
252 final String[] values = rolesStr.split(valueSeparator);
253 if (maxAge > 0) {
254 try {
255 final long time = getCurrentTime() / 1000 - Long.parseLong(values[0]);
256 if (time > maxAge || time < 0) {
257 if (logger.isDebugEnabled()) {
258 logger.debug("role info is expired: {} > {}", time, maxAge);
259 }
260 return;
261 }
262 } catch (final NumberFormatException e) {
263 logger.warn("Invalid role info: {}", rolesStr, e);
264 return;
265 }
266 }
267 if (values.length > 1) {
268 final String[] roles = values[1].split(roleSeparator);
269 for (final String role : roles) {
270 if (StringUtil.isNotEmpty(role)) {
271 roleSet.add(role);
272 }
273 }
274 }
275 } else {
276 final String[] roles = rolesStr.split(roleSeparator);
277 for (final String role : roles) {
278 if (StringUtil.isNotEmpty(role)) {
279 roleSet.add(role);
280 }
281 }
282 }
283 }
284
285 protected long getCurrentTime() {
286 return ComponentUtil.getSystemHelper().getCurrentTimeAsLong();
287 }
288
289 public void addCookieNameMapping(final String cookieName, final String roleName) {
290 if (cookieNameMap == null) {
291 cookieNameMap = new HashMap<>();
292 }
293 cookieNameMap.put(cookieName, roleName);
294 }
295
296 public void setCipher(final CachedCipher cipher) {
297 this.cipher = cipher;
298 }
299
300 public void setValueSeparator(final String valueSeparator) {
301 this.valueSeparator = valueSeparator;
302 }
303
304 public void setRoleSeparator(final String roleSeparator) {
305 this.roleSeparator = roleSeparator;
306 }
307
308 public void setParameterKey(final String parameterKey) {
309 this.parameterKey = parameterKey;
310 }
311
312 public void setEncryptedParameterValue(final boolean encryptedParameterValue) {
313 this.encryptedParameterValue = encryptedParameterValue;
314 }
315
316 public void setHeaderKey(final String headerKey) {
317 this.headerKey = headerKey;
318 }
319
320 public void setEncryptedHeaderValue(final boolean encryptedHeaderValue) {
321 this.encryptedHeaderValue = encryptedHeaderValue;
322 }
323
324 public void setCookieKey(final String cookieKey) {
325 this.cookieKey = cookieKey;
326 }
327
328 public void setEncryptedCookieValue(final boolean encryptedCookieValue) {
329 this.encryptedCookieValue = encryptedCookieValue;
330 }
331
332 public void setMaxAge(final long maxAge) {
333 this.maxAge = maxAge;
334 }
335
336 }