001
014
015 package com.liferay.portal.kernel.log;
016
017 import com.liferay.portal.kernel.util.CharPool;
018 import com.liferay.portal.kernel.util.GetterUtil;
019 import com.liferay.portal.kernel.util.PropsKeys;
020 import com.liferay.portal.kernel.util.StringPool;
021 import com.liferay.portal.kernel.util.StringUtil;
022 import com.liferay.portal.kernel.util.SystemProperties;
023
024 import java.util.ArrayList;
025 import java.util.List;
026
027
031 public class SanitizerLogWrapper extends LogWrapper {
032
033 public static Log allowCRLF(Log log) {
034 if (!(log instanceof SanitizerLogWrapper)) {
035 return log;
036 }
037
038 SanitizerLogWrapper sanitizerLogWrapper = (SanitizerLogWrapper)log;
039
040 sanitizerLogWrapper = new SanitizerLogWrapper(
041 sanitizerLogWrapper.getWrappedLog());
042
043 sanitizerLogWrapper._allowCRLF = true;
044
045 return sanitizerLogWrapper;
046 }
047
048 public static void init() {
049 if (!_LOG_SANITIZER_ENABLED) {
050 return;
051 }
052
053 _LOG_SANITIZER_ESCAPE_HTML_ENABLED = GetterUtil.getBoolean(
054 SystemProperties.get(PropsKeys.LOG_SANITIZER_ESCAPE_HTML_ENABLED));
055
056 _LOG_SANITIZER_REPLACEMENT_CHARACTER = (char)GetterUtil.getInteger(
057 SystemProperties.get(
058 PropsKeys.LOG_SANITIZER_REPLACEMENT_CHARACTER));
059
060 for (int i = 0; i < _whitelistCharacters.length; i++) {
061 _whitelistCharacters[i] = 1;
062 }
063
064 int[] whitelistCharacters = GetterUtil.getIntegerValues(
065 StringUtil.split(
066 SystemProperties.get(
067 PropsKeys.LOG_SANITIZER_WHITELIST_CHARACTERS)));
068
069 for (int whitelistCharacter : whitelistCharacters) {
070 if ((whitelistCharacter >= 0) &&
071 (whitelistCharacter < _whitelistCharacters.length)) {
072
073 _whitelistCharacters[whitelistCharacter] = 0;
074 }
075 else {
076 System.err.println(
077 "Unable to register log whitelist character " +
078 whitelistCharacter);
079 }
080 }
081 }
082
083 public static boolean isEnabled() {
084 return _LOG_SANITIZER_ENABLED;
085 }
086
087 public SanitizerLogWrapper(Log log) {
088 super(log);
089
090 setLogWrapperClassName(SanitizerLogWrapper.class.getName());
091 }
092
093 @Override
094 public void debug(Object msg) {
095 super.debug(sanitize(msg));
096 }
097
098 @Override
099 public void debug(Object msg, Throwable t) {
100 super.debug(sanitize(msg), sanitize(t));
101 }
102
103 @Override
104 public void debug(Throwable t) {
105 super.debug(sanitize(t));
106 }
107
108 @Override
109 public void error(Object msg) {
110 super.error(sanitize(msg));
111 }
112
113 @Override
114 public void error(Object msg, Throwable t) {
115 super.error(sanitize(msg), sanitize(t));
116 }
117
118 @Override
119 public void error(Throwable t) {
120 super.error(sanitize(t));
121 }
122
123 @Override
124 public void fatal(Object msg) {
125 super.fatal(sanitize(msg));
126 }
127
128 @Override
129 public void fatal(Object msg, Throwable t) {
130 super.fatal(sanitize(msg), sanitize(t));
131 }
132
133 @Override
134 public void fatal(Throwable t) {
135 super.fatal(sanitize(t));
136 }
137
138 @Override
139 public void info(Object msg) {
140 super.info(sanitize(msg));
141 }
142
143 @Override
144 public void info(Object msg, Throwable t) {
145 super.info(sanitize(msg), sanitize(t));
146 }
147
148 @Override
149 public void info(Throwable t) {
150 super.info(sanitize(t));
151 }
152
153 @Override
154 public void trace(Object msg) {
155 super.trace(sanitize(msg));
156 }
157
158 @Override
159 public void trace(Object msg, Throwable t) {
160 super.trace(sanitize(msg), sanitize(t));
161 }
162
163 @Override
164 public void trace(Throwable t) {
165 super.trace(sanitize(t));
166 }
167
168 @Override
169 public void warn(Object msg) {
170 super.warn(sanitize(msg));
171 }
172
173 @Override
174 public void warn(Object msg, Throwable t) {
175 super.warn(sanitize(msg), sanitize(t));
176 }
177
178 @Override
179 public void warn(Throwable t) {
180 super.warn(sanitize(t));
181 }
182
183 protected String sanitize(Object obj) {
184 if (obj == null) {
185 return null;
186 }
187
188 String message = obj.toString();
189
190 return sanitize(message, message);
191 }
192
193 protected String sanitize(String message, String defaultResult) {
194 if (message == null) {
195 return null;
196 }
197
198 char[] chars = message.toCharArray();
199 boolean hasCRLF = false;
200 boolean hasLessThanCharacter = false;
201 boolean sanitized = false;
202
203 for (int i = 0; i < chars.length; i++) {
204 int c = chars[i];
205
206 if (_allowCRLF &&
207 ((c == CharPool.NEW_LINE) || (c == CharPool.RETURN))) {
208
209 hasCRLF = true;
210
211 continue;
212 }
213
214 if ((c >= 0) && (c < _whitelistCharacters.length) &&
215 (_whitelistCharacters[c] != 0)) {
216
217 chars[i] = _LOG_SANITIZER_REPLACEMENT_CHARACTER;
218 sanitized = true;
219 }
220
221 if (c == CharPool.LESS_THAN) {
222 hasLessThanCharacter = true;
223 }
224 }
225
226 boolean escapeHTML = false;
227
228 if (_LOG_SANITIZER_ESCAPE_HTML_ENABLED && hasLessThanCharacter) {
229 escapeHTML = true;
230 }
231
232 if (sanitized || escapeHTML || hasCRLF) {
233 String sanitizedMessage = new String(chars);
234
235 if (escapeHTML) {
236 sanitizedMessage = sanitizedMessage.replaceAll(
237 StringPool.LESS_THAN, _LESS_THAN_ESCAPED);
238 }
239
240 if (sanitized) {
241 sanitizedMessage = sanitizedMessage.concat(_SANITIZED);
242 }
243
244 if (hasCRLF) {
245 sanitizedMessage = CRLF_WARNING.concat(sanitizedMessage);
246 }
247
248 return sanitizedMessage;
249 }
250
251 return defaultResult;
252 }
253
254 protected Throwable sanitize(Throwable throwable) {
255 List<Throwable> throwables = new ArrayList<Throwable>();
256
257 Throwable tempThrowable = throwable;
258
259 while (tempThrowable != null) {
260 throwables.add(tempThrowable);
261
262 tempThrowable = tempThrowable.getCause();
263 }
264
265 Throwable resultThrowable = null;
266
267 boolean sanitized = false;
268
269 for (int i = throwables.size() - 1; i > - 1; i--) {
270 Throwable curThrowable = throwables.get(i);
271
272 String message = curThrowable.toString();
273
274 String sanitizedMessage = sanitize(message, null);
275
276 if (!sanitized && (sanitizedMessage == null)) {
277 resultThrowable = curThrowable;
278
279 continue;
280 }
281
282 if (sanitizedMessage == null) {
283 sanitizedMessage = message;
284 }
285
286 sanitized = true;
287
288 resultThrowable = new LogSanitizerException(
289 sanitizedMessage, curThrowable.getStackTrace(),
290 resultThrowable);
291 }
292
293 return resultThrowable;
294 }
295
296 protected static final String CRLF_WARNING =
297 "SanitizerLogWrapper warning: Following message contains CRLF " +
298 "characters\n";
299
300 private static final String _LESS_THAN_ESCAPED = "<";
301
302 private static final String _SANITIZED = " [Sanitized]";
303
304 private static boolean _LOG_SANITIZER_ENABLED = GetterUtil.getBoolean(
305 SystemProperties.get(PropsKeys.LOG_SANITIZER_ENABLED));
306
307 private static boolean _LOG_SANITIZER_ESCAPE_HTML_ENABLED = false;
308
309 private static char _LOG_SANITIZER_REPLACEMENT_CHARACTER =
310 CharPool.UNDERLINE;
311
312 private static int[] _whitelistCharacters = new int[128];
313
314 private boolean _allowCRLF;
315
316 }