source: branches/TaskRewrite/src/plugins/acegi-0.5.1/src/java/org/codehaus/groovy/grails/plugins/springsecurity/IpAddressFilter.java @ 58

Last change on this file since 58 was 58, checked in by gav, 15 years ago

Configure BootStrap? with latest concepts.
Install and setup Acegi plugin with custom views.
Test Fixture plugin in a test app but couldn't get it to work with Acegi encodePassword() so gave up.

File size: 5.4 KB
Line 
1/* Copyright 2006-2009 the original author or authors.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *      http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15package org.codehaus.groovy.grails.plugins.springsecurity;
16
17import java.io.IOException;
18import java.net.InetAddress;
19import java.net.UnknownHostException;
20import java.util.Arrays;
21import java.util.Map;
22
23import javax.servlet.FilterChain;
24import javax.servlet.ServletException;
25import javax.servlet.http.HttpServletRequest;
26import javax.servlet.http.HttpServletResponse;
27
28import org.apache.log4j.Logger;
29import org.springframework.beans.factory.InitializingBean;
30import org.springframework.beans.factory.annotation.Required;
31import org.springframework.security.ui.FilterChainOrder;
32import org.springframework.security.ui.SpringSecurityFilter;
33import org.springframework.util.AntPathMatcher;
34import org.springframework.util.Assert;
35import org.springframework.util.StringUtils;
36
37/**
38 * Blocks access to protected resources based on IP address. Sends 404 rather than
39 * reporting error to hide visibility of the resources.
40 * <br/>
41 * Supports either Ant-style patterns (e.g. 10.**) or masked patterns
42 * (e.g. 192.168.1.0/24 or 202.24.0.0/14).
43 *
44 * @author <a href='mailto:beckwithb@studentsonly.com'>Burt Beckwith</a>
45 */
46public class IpAddressFilter extends SpringSecurityFilter implements InitializingBean {
47
48        private final Logger _log = Logger.getLogger(getClass());
49
50        private final AntPathMatcher _pathMatcher = new AntPathMatcher();
51
52        private Map<String, String> _restrictions;
53
54        /**
55         * {@inheritDoc}
56         * @see org.springframework.security.ui.SpringSecurityFilter#doFilterHttp(
57         *      javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse,
58         *      javax.servlet.FilterChain)
59         */
60        @Override
61        protected void doFilterHttp(
62                          final HttpServletRequest request,
63                          final HttpServletResponse response,
64                          final FilterChain chain) throws IOException, ServletException {
65
66                if (!isAllowed(request.getRemoteAddr(), request.getRequestURI())) {
67                        response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404
68                        return;
69                }
70
71                chain.doFilter(request, response);
72        }
73
74        /**
75         * {@inheritDoc}
76         * @see org.springframework.security.ui.SpringSecurityFilter#getOrder()
77         */
78        public int getOrder() {
79                return FilterChainOrder.LOGOUT_FILTER + 1;
80        }
81
82        /**
83         * {@inheritDoc}
84         * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
85         */
86        public void afterPropertiesSet() {
87                Assert.notNull(_restrictions, "ipRestrictions is required");
88        }
89
90        /**
91         * Dependency injection for the ip/pattern restriction map.
92         * @param restrictions  the map
93         */
94        @Required
95        public void setIpRestrictions(final Map<String, String> restrictions) {
96                _restrictions = restrictions;
97        }
98
99        private boolean isAllowed(final String ip, final String requestURI) {
100
101                if ("127.0.0.1".equals(ip)) {
102                        return true;
103                }
104
105                String reason = null;
106
107                for (Map.Entry<String, String> entry : _restrictions.entrySet()) {
108                        String uriPattern = entry.getKey();
109                        if (!_pathMatcher.match(uriPattern, requestURI)) {
110                                continue;
111                        }
112
113                        String ipPattern = entry.getValue();
114                        if (ipPattern.contains("/")) {
115                                try {
116                                        if (!matchesUsingMask(ipPattern, ip)) {
117                                                reason = ipPattern;
118                                                break;
119                                        }
120                                }
121                                catch (UnknownHostException e) {
122                                        reason = e.getMessage();
123                                        break;
124                                }
125                        }
126                        else if (!_pathMatcher.match(ipPattern, ip)) {
127                                reason = ipPattern;
128                                break;
129                        }
130                }
131
132                if (reason != null) {
133                        _log.error("disallowed request " + requestURI + " from " + ip + ": " + reason);
134                        return false;
135                }
136
137                return true;
138        }
139
140        private boolean matchesUsingMask(final String ipPattern, final String ip) throws UnknownHostException {
141
142                String[] addressAndMask = StringUtils.split(ipPattern, "/");
143
144                InetAddress requiredAddress = parseAddress(addressAndMask[0]);
145                InetAddress remoteAddress = parseAddress(ip);
146                if (!requiredAddress.getClass().equals(remoteAddress.getClass())) {
147                        throw new IllegalArgumentException(
148                                        "IP Address in expression must be the same type as version returned by request");
149                }
150
151                int maskBits = Integer.parseInt(addressAndMask[1]);
152                if (maskBits == 0) {
153                        return remoteAddress.equals(requiredAddress);
154                }
155
156                int oddBits = maskBits % 8;
157                byte[] mask = new byte[maskBits / 8 + (oddBits == 0 ? 0 : 1)];
158
159                Arrays.fill(mask, 0, oddBits == 0 ? mask.length : mask.length - 1, (byte)0xFF);
160
161                if (oddBits != 0) {
162                        int finalByte = (1 << oddBits) - 1;
163                        finalByte <<= 8 - oddBits;
164                        mask[mask.length - 1] = (byte) finalByte;
165                }
166
167                byte[] remoteAddressBytes = remoteAddress.getAddress();
168                byte[] requiredAddressBytes = requiredAddress.getAddress();
169                for (int i = 0; i < mask.length; i++) {
170                        if ((remoteAddressBytes[i] & mask[i]) != (requiredAddressBytes[i] & mask[i])) {
171                                return false;
172                        }
173                }
174
175                return true;
176        }
177
178        private InetAddress parseAddress(final String address) throws UnknownHostException {
179                try {
180                        return InetAddress.getByName(address);
181                }
182                catch (UnknownHostException e) {
183                        _log.error("unable to parse " + address);
184                        throw e;
185                }
186        }
187}
Note: See TracBrowser for help on using the repository browser.