001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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    /**
028     * @author Tomas Polesovsky
029     * @author Raymond Aug??
030     */
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 = "&lt;";
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    }