View | Details | Raw Unified | Return to bug 51953
Collapse All | Expand All

(-)a/java/org/apache/catalina/filters/RemoteNetmaskFilter.java (+97 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
19
package org.apache.catalina.filters;
20
21
22
import org.apache.catalina.comet.CometEvent;
23
import org.apache.catalina.comet.CometFilterChain;
24
import org.apache.juli.logging.Log;
25
import org.apache.juli.logging.LogFactory;
26
27
import javax.servlet.FilterChain;
28
import javax.servlet.ServletException;
29
import javax.servlet.ServletRequest;
30
import javax.servlet.ServletResponse;
31
import java.io.IOException;
32
33
34
/**
35
 * Concrete implementation of <code>RequestNetmaskFilter</code> that filters
36
 * based on the string representation of the remote client's IP address.
37
 *
38
 */
39
40
public final class RemoteNetmaskFilter
41
    extends RequestFilter {
42
43
    // ----------------------------------------------------- Instance Variables
44
    private static final Log log = LogFactory.getLog(RemoteNetmaskFilter.class);
45
46
47
    // ------------------------------------------------------------- Properties
48
49
50
51
    // --------------------------------------------------------- Public Methods
52
53
54
    /**
55
     * Extract the desired request property, and pass it (along with the
56
     * specified request and response objects and associated filter chain) to
57
     * the protected <code>process()</code> method to perform the actual
58
     * filtering.
59
     *
60
     * @param request  The servlet request to be processed
61
     * @param response The servlet response to be created
62
     * @param chain    The filter chain for this request
63
     *
64
     * @exception java.io.IOException if an input/output error occurs
65
     * @exception javax.servlet.ServletException if a servlet error occurs
66
     */
67
    @Override
68
    public void doFilter(ServletRequest request, ServletResponse response,
69
            FilterChain chain) throws IOException, ServletException {
70
71
        process(request.getRemoteAddr(), request, response, chain);
72
73
    }
74
75
    /**
76
     * Extract the desired request property, and pass it (along with the comet
77
     * event and filter chain) to the protected <code>process()</code> method
78
     * to perform the actual filtering.
79
     *
80
     * @param event The comet event to be processed
81
     * @param chain The filter chain for this event
82
     *
83
     * @exception java.io.IOException if an input/output error occurs
84
     * @exception javax.servlet.ServletException if a servlet error occurs
85
     */
86
    @Override
87
    public void doFilterEvent(CometEvent event, CometFilterChain chain)
88
            throws IOException, ServletException {
89
        processCometEvent(event.getHttpServletRequest().getRemoteHost(),
90
                event, chain);        
91
    }
92
93
    @Override
94
    protected Log getLogger() {
95
        return log;
96
    }
97
}
(-)a/java/org/apache/catalina/filters/RequestNetmaskFilter.java (-1 / +269 lines)
Line 0 Link Here
0
- 
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
19
package org.apache.catalina.filters;
20
21
22
import org.apache.catalina.comet.CometEvent;
23
import org.apache.catalina.comet.CometFilter;
24
import org.apache.catalina.comet.CometFilterChain;
25
import org.apache.catalina.util.NetMask;
26
27
import javax.servlet.FilterChain;
28
import javax.servlet.ServletException;
29
import javax.servlet.ServletRequest;
30
import javax.servlet.ServletResponse;
31
import javax.servlet.http.HttpServletResponse;
32
import java.io.IOException;
33
import java.net.InetAddress;
34
import java.net.UnknownHostException;
35
import java.util.ArrayList;
36
import java.util.List;
37
38
/**
39
 * Implementation of a Filter that performs filtering based on comparing the
40
 * appropriate request property (selected based on which subclass you choose
41
 * to configure into your Container's pipeline) against the regular expressions
42
 * configured for this Filter.
43
 * <p>
44
 * This filter is configured by setting the <code>allow</code> and/or
45
 * <code>deny</code> properties to a regular expressions (in the syntax
46
 * supported by {@link java.util.regex.Pattern}) to which the appropriate request property will
47
 * be compared.  Evaluation proceeds as follows:
48
 * <ul>
49
 * <li>The subclass extracts the request property to be filtered, and
50
 *     calls the common <code>process()</code> method.
51
 * <li>If there is a deny expression configured, the property will be compared
52
 *     to the expression. If a match is found, this request will be rejected
53
 *     with a "Forbidden" HTTP response.</li>
54
 * <li>If there is a allow expression configured, the property will be compared
55
 *     to the expression. If a match is found, this request will be allowed to
56
 *     pass through to the next filter in the current pipeline.</li>
57
 * <li>If a deny expression was specified but no allow expression, allow this
58
 *     request to pass through (because none of the deny expressions matched
59
 *     it).
60
 * <li>The request will be rejected with a "Forbidden" HTTP response.</li>
61
 * </ul>
62
 */
63
64
public abstract class RequestNetmaskFilter
65
    extends FilterBase implements CometFilter {
66
67
68
    // ----------------------------------------------------- Instance Variables
69
70
    /**
71
     * The regular expression used to test for allowed requests.
72
     */
73
    protected final List<NetMask> allow = new ArrayList<NetMask>();
74
75
    /**
76
     * The regular expression used to test for denied requests.
77
     */
78
    protected final List<NetMask> deny = new ArrayList<NetMask>();
79
80
    /**
81
     * mime type -- "text/plain"
82
     */
83
    private static final String PLAIN_TEXT_MIME_TYPE = "text/plain";
84
85
86
    // ------------------------------------------------------------- Properties
87
88
89
    /**
90
     * Return a string representation of the NetMask list in allow.
91
     */
92
    public String getAllow() {
93
        return allow.toString();
94
    }
95
96
97
    /**
98
     * Fill the allow list with the list of netmasks provided as an argument,
99
     * if any.
100
     *
101
     * @param input The list of netmasks, as a comma separated string
102
     */
103
    public void setAllow(final String input) {
104
        if (input == null || input.length() == 0)
105
            return;
106
107
        NetMask nm;
108
109
        for (final String s: input.split("\\s*,\\s*"))
110
            try {
111
                nm = new NetMask(s);
112
                allow.add(nm);
113
            } catch (IllegalArgumentException e) {
114
                // FIXME: log
115
            }
116
    }
117
118
119
    /**
120
     * Return a string representation of the NetMask list in deny.
121
     */
122
    public String getDeny() {
123
        if (deny == null) {
124
            return null;
125
        }
126
        return deny.toString();
127
    }
128
129
130
    /**
131
     * Fill the deny list with the list of netmasks provided as an argument,
132
     * if any.
133
     *
134
     * @param input The list of netmasks, as a comma separated string
135
     */
136
    public void setDeny(String input) {
137
        if (input == null || input.length() == 0)
138
            return;
139
140
        NetMask nm;
141
142
        for (final String s: input.split("\\s*,\\s*"))
143
            try {
144
                nm = new NetMask(s);
145
                deny.add(nm);
146
            } catch (IllegalArgumentException e) {
147
                // FIXME: log
148
            }
149
    }
150
151
152
    // --------------------------------------------------------- Public Methods
153
154
155
    /**
156
     * Extract the desired request property, and pass it (along with the
157
     * specified request and response objects) to the protected
158
     * <code>process()</code> method to perform the actual filtering.
159
     * This method must be implemented by a concrete subclass.
160
     *
161
     * @param request The servlet request to be processed
162
     * @param response The servlet response to be created
163
     * @param chain The filter chain
164
     *
165
     * @exception java.io.IOException if an input/output error occurs
166
     * @exception javax.servlet.ServletException if a servlet error occurs
167
     */
168
    @Override
169
    public abstract void doFilter(ServletRequest request,
170
            ServletResponse response, FilterChain chain) throws IOException,
171
            ServletException;
172
173
174
    // ------------------------------------------------------ Protected Methods
175
176
177
    /**
178
     * Perform the filtering that has been configured for this Filter, matching
179
     * against the specified request property.
180
     *
181
     * @param property The request property on which to filter
182
     * @param request The servlet request to be processed
183
     * @param response The servlet response to be processed
184
     * @param chain The filter chain
185
     *
186
     * @exception java.io.IOException if an input/output error occurs
187
     * @exception javax.servlet.ServletException if a servlet error occurs
188
     */
189
    protected void process(String property, ServletRequest request,
190
            ServletResponse response, FilterChain chain)
191
            throws IOException, ServletException {
192
193
        if (isAllowed(property)) {
194
            chain.doFilter(request, response);
195
            return;
196
        }
197
198
        if (!(response instanceof HttpServletResponse)) {
199
            sendErrorWhenNotHttp(response);
200
            return;
201
        }
202
203
        ((HttpServletResponse) response)
204
            .sendError(HttpServletResponse.SC_FORBIDDEN);
205
    }
206
207
    /**
208
     * Perform the filtering that has been configured for this Filter, matching
209
     * against the specified request property.
210
     *
211
     * @param property  The property to check against the allow/deny rules
212
     * @param event     The comet event to be filtered
213
     * @param chain     The comet filter chain
214
     * @exception java.io.IOException if an input/output error occurs
215
     * @exception javax.servlet.ServletException if a servlet error occurs
216
     */
217
    protected void processCometEvent(String property, CometEvent event,
218
            CometFilterChain chain) throws IOException, ServletException {
219
        HttpServletResponse response = event.getHttpServletResponse();
220
        
221
        if (isAllowed(property)) {
222
            chain.doFilterEvent(event);
223
            return;
224
        }
225
226
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
227
        event.close();
228
    }
229
230
    /**
231
     * Process the allow and deny rules for the provided property.
232
     * 
233
     * @param property  The property to test against the allow and deny lists
234
     * @return          <code>true</code> if this request should be allowed,
235
     *                  <code>false</code> otherwise
236
     */
237
    private boolean isAllowed(String property) {
238
        final InetAddress addr;
239
240
        try {
241
            addr = InetAddress.getByName(property);
242
        } catch (UnknownHostException e) {
243
            //Eh?
244
            return false;
245
        }
246
247
        for (final NetMask nm: deny)
248
            if (nm.matches(addr))
249
                return false;
250
251
        for (final NetMask nm: allow)
252
            if (nm.matches(addr))
253
                return true;
254
255
        // Allow if denies specified but not allows
256
        if (!deny.isEmpty() && allow.isEmpty())
257
            return true;
258
259
        // Deny this request
260
        return false;
261
    }
262
263
    private void sendErrorWhenNotHttp(ServletResponse response)
264
            throws IOException {
265
        response.setContentType(PLAIN_TEXT_MIME_TYPE);
266
        response.getWriter().write(sm.getString("http.403"));
267
        response.getWriter().flush();
268
    }
269
}

Return to bug 51953