1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.idp.authn.provider;
18
19 import java.net.Inet4Address;
20 import java.net.Inet6Address;
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.util.BitSet;
24 import java.util.List;
25 import java.util.concurrent.CopyOnWriteArrayList;
26
27 import javax.servlet.ServletRequest;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine;
35 import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
36
37
38
39
40
41
42
43
44
45
46 public class IPAddressLoginHandler extends AbstractLoginHandler {
47
48
49 private final Logger log = LoggerFactory.getLogger(IPAddressLoginHandler.class);
50
51
52 private String authnMethodURI = "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol";
53
54
55 private String username;
56
57
58 private boolean defaultDeny;
59
60
61 private List<IPEntry> ipList;
62
63
64
65
66
67
68
69
70
71
72
73 public void setEntries(final List<String> entries, boolean defaultDeny) {
74
75 this.defaultDeny = defaultDeny;
76 ipList = new CopyOnWriteArrayList<IPEntry>();
77
78 for (String addr : entries) {
79 try {
80 ipList.add(new edu.internet2.middleware.shibboleth.idp.authn.provider.IPAddressLoginHandler.IPEntry(
81 addr));
82 } catch (UnknownHostException ex) {
83 log.error("IPAddressHandler: Error parsing IP entry \"" + addr + "\". Ignoring.");
84 }
85 }
86 }
87
88
89 public boolean supportsPassive() {
90 return true;
91 }
92
93
94 public boolean supportsForceAuthentication() {
95 return true;
96 }
97
98
99
100
101
102
103 public String getUsername() {
104 return username;
105 }
106
107
108
109
110
111
112 public void setUsername(String name) {
113 username = name;
114 }
115
116
117 public void login(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
118
119 if (defaultDeny) {
120 handleDefaultDeny(httpRequest, httpResponse);
121 } else {
122 handleDefaultAllow(httpRequest, httpResponse);
123 }
124
125 AuthenticationEngine.returnToAuthenticationEngine(httpRequest, httpResponse);
126 }
127
128 protected void handleDefaultDeny(HttpServletRequest request, HttpServletResponse response) {
129
130 boolean ipAllowed = searchIpList(request);
131
132 if (ipAllowed) {
133 log.debug("Authenticated user by IP address");
134 request.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, username);
135 }
136 }
137
138 protected void handleDefaultAllow(HttpServletRequest request, HttpServletResponse response) {
139
140 boolean ipDenied = searchIpList(request);
141
142 if (!ipDenied) {
143 log.debug("Authenticated user by IP address");
144 request.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, username);
145 }
146 }
147
148
149
150
151
152
153
154
155 private boolean searchIpList(ServletRequest request) {
156
157 boolean found = false;
158
159 try {
160 InetAddress addr = InetAddress.getByName(request.getRemoteAddr());
161 BitSet addrbits = byteArrayToBitSet(addr.getAddress());
162
163 for (IPEntry entry : ipList) {
164
165 BitSet netaddr = entry.getNetworkAddress();
166 BitSet netmask = entry.getNetmask();
167
168 addrbits.and(netmask);
169 if (addrbits.equals(netaddr)) {
170 found = true;
171 break;
172 }
173 }
174
175 } catch (UnknownHostException ex) {
176 log.error("Error resolving hostname.", ex);
177 return false;
178 }
179
180 return found;
181 }
182
183
184
185
186
187
188
189
190
191
192 protected BitSet byteArrayToBitSet(final byte[] bytes) {
193
194 BitSet bits = new BitSet();
195
196 for (int i = 0; i < bytes.length * 8; i++) {
197 if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
198 bits.set(i);
199 }
200 }
201
202 return bits;
203 }
204
205
206
207
208 protected class IPEntry {
209
210
211 private final BitSet networkAddress;
212
213
214 private final BitSet netmask;
215
216
217
218
219
220
221
222
223 public IPEntry(String entry) throws UnknownHostException {
224
225
226 if (entry == null || entry.length() == 0) {
227 throw new UnknownHostException("entry is null.");
228 }
229
230 int cidrOffset = entry.indexOf("/");
231 if (cidrOffset == -1) {
232 log.error("Invalid entry \"" + entry + "\" -- it lacks a netmask component.");
233 throw new UnknownHostException("entry lacks a netmask component.");
234 }
235
236
237 if (entry.indexOf("/", cidrOffset + 1) != -1) {
238 log.error("Invalid entry \"" + entry + "\" -- too many \"/\" present.");
239 throw new UnknownHostException("entry has too many netmask components.");
240 }
241
242 String networkString = entry.substring(0, cidrOffset);
243 String netmaskString = entry.substring(cidrOffset + 1, entry.length());
244
245 InetAddress tempAddr = InetAddress.getByName(networkString);
246 networkAddress = byteArrayToBitSet(tempAddr.getAddress());
247
248 int masklen = Integer.parseInt(netmaskString);
249 int addrlen = networkAddress.length();
250
251
252 if ((tempAddr instanceof Inet4Address) && (masklen > 32)) {
253 throw new UnknownHostException("Netmask is too large for an IPv4 address: " + masklen);
254 } else if ((tempAddr instanceof Inet6Address) && masklen > 128) {
255 throw new UnknownHostException("Netmask is too large for an IPv6 address: " + masklen);
256 }
257
258 netmask = new BitSet(addrlen);
259 netmask.set(addrlen - masklen, addrlen, true);
260 }
261
262
263
264
265
266
267 public BitSet getNetworkAddress() {
268 return networkAddress;
269 }
270
271
272
273
274
275
276 public BitSet getNetmask() {
277 return netmask;
278 }
279 }
280 }