1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.web.upload;
35
36 import fr.paris.lutece.portal.service.util.AppLogService;
37 import fr.paris.lutece.portal.service.util.AppPropertiesService;
38
39 import java.io.IOException;
40
41 import java.util.HashMap;
42 import java.util.LinkedList;
43 import java.util.Map;
44
45 import javax.servlet.Filter;
46 import javax.servlet.FilterChain;
47 import javax.servlet.FilterConfig;
48 import javax.servlet.ServletException;
49 import javax.servlet.ServletRequest;
50 import javax.servlet.ServletResponse;
51
52 import org.apache.commons.collections4.CollectionUtils;
53
54
55
56
57
58 public class DosGuardFilter implements Filter
59 {
60
61 private static String PROPERTY_DOSGUARDFILTER_MINCONTENTLENGTH = "lutece.upload.dosguard.minContentLength";
62 private static String PROPERTY_DOSGUARDFILTER_MININTERVAL = "lutece.upload.dosguard.minInterval";
63
64
65 private static int CONSTANT_DEFAULT_DOSGUARDFILTER_MINCONTENTLENGTH = 10240 ;
66 private static int CONSTANT_DEFAULT_DOSGUARDFILTER_MININTERVAL = 2000 ;
67
68
69 private static final int INITIAL_CAPACITY = 100;
70 private FilterConfig _filterConfig;
71
72
73 private int _nMinContentLength;
74
75
76 private int _nMinInterval;
77
78
79 private Map<String, Long> _mapLastRequestTimes;
80
81
82
83 private LinkedList<Entry> _listOrderedRequests;
84
85
86
87
88 @Override
89 public void init( FilterConfig config ) throws ServletException
90 {
91 _filterConfig = config;
92 _mapLastRequestTimes = new HashMap<String, Long>( INITIAL_CAPACITY );
93 _listOrderedRequests = new LinkedList<Entry>( );
94
95 _nMinContentLength = AppPropertiesService.getPropertyInt( PROPERTY_DOSGUARDFILTER_MINCONTENTLENGTH, CONSTANT_DEFAULT_DOSGUARDFILTER_MINCONTENTLENGTH ) ;
96 _nMinInterval = AppPropertiesService.getPropertyInt( PROPERTY_DOSGUARDFILTER_MININTERVAL, CONSTANT_DEFAULT_DOSGUARDFILTER_MININTERVAL ) ;
97
98 }
99
100
101
102
103 @Override
104 public void destroy( )
105 {
106
107 }
108
109
110
111
112 @Override
113 public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException
114 {
115
116 if ( this.isAllowed( request.getRemoteAddr( ), request.getContentLength( ) ) )
117 {
118 chain.doFilter( request, response );
119 }
120 else
121 {
122 throw new ServletException( "DOS Guard : Too many upload from the same IP !" );
123 }
124 }
125
126
127
128
129
130
131
132
133
134
135 public synchronized boolean isAllowed( String strRemoteAddr, int iContentLength )
136 {
137 AppLogService.debug( "DosGuard : isAllowed({}, {})", strRemoteAddr, iContentLength );
138
139
140 if ( _nMinInterval < 0 )
141 {
142 AppLogService.debug( "minInterval is below minimum, ignored" );
143
144 return true;
145 }
146
147
148 if ( iContentLength < _nMinContentLength )
149 {
150 AppLogService.debug( "ContentLength is below minimum, ignored" );
151
152 return true;
153 }
154
155
156 long lRequestTime = System.currentTimeMillis( );
157 AppLogService.debug( "Request time : {}", lRequestTime );
158
159
160 Long previousRequestTime = _mapLastRequestTimes.get( strRemoteAddr );
161 AppLogService.debug( "Previous request time : {}", previousRequestTime );
162
163 if ( previousRequestTime != null )
164 {
165 AppLogService.debug( "IP is in the map" );
166
167
168 if ( lRequestTime > ( previousRequestTime.longValue( ) + _nMinInterval ) )
169 {
170 AppLogService.debug( "IP is allowed to make a new request" );
171
172
173 this.cleanExpiredEntries( );
174
175
176 _mapLastRequestTimes.put( strRemoteAddr, Long.valueOf( lRequestTime ) );
177
178
179 _listOrderedRequests.addFirst( new Entry( strRemoteAddr, lRequestTime ) );
180
181 return true;
182 }
183
184 AppLogService.debug( "IP is not allowed to make a new request" );
185
186 return false;
187 }
188
189 AppLogService.debug( "IP is not in the map" );
190
191
192 this.cleanExpiredEntries( );
193
194
195 _mapLastRequestTimes.put( strRemoteAddr, Long.valueOf( lRequestTime ) );
196
197
198 _listOrderedRequests.addFirst( new Entry( strRemoteAddr, lRequestTime ) );
199
200 return true;
201 }
202
203
204
205
206 private void cleanExpiredEntries( )
207 {
208 AppLogService.debug( "DosGuard.class : cleanExpiredEntries()" );
209
210 if ( CollectionUtils.isNotEmpty( _listOrderedRequests ) )
211 {
212
213 long lMinTime = System.currentTimeMillis( ) - _nMinInterval;
214
215 AppLogService.debug( "Min time : {}", lMinTime );
216
217
218 boolean bDone = false;
219
220 while ( !bDone && CollectionUtils.isNotEmpty( _listOrderedRequests ) )
221 {
222
223
224 Entry lastEntry = _listOrderedRequests.getLast( );
225
226 if ( lastEntry.getRequestTime( ) < lMinTime )
227 {
228
229 _mapLastRequestTimes.remove( lastEntry.getRemoteAddr( ) );
230 _listOrderedRequests.removeLast( );
231
232 AppLogService.debug( "Removing [{}, {}]", lastEntry.getRemoteAddr( ), lastEntry.getRequestTime( ) );
233 }
234 else
235 {
236 bDone = true;
237 }
238 }
239 }
240 }
241
242
243
244
245 private static class Entry
246 {
247 private String _strRemoteAddr;
248 private long _lRequestTime;
249
250
251
252
253
254
255
256
257
258 public Entry( String strRemoteAddr, long lRequestTime )
259 {
260 this._strRemoteAddr = strRemoteAddr;
261 this._lRequestTime = lRequestTime;
262 }
263
264
265
266
267
268
269 public String getRemoteAddr( )
270 {
271 return _strRemoteAddr;
272 }
273
274
275
276
277
278
279 public long getRequestTime( )
280 {
281 return _lRequestTime;
282 }
283 }
284 }