Merge remote branch 'tags/2.3.4'
[java-idp.git] / src / main / java / edu / internet2 / middleware / shibboleth / idp / authn / provider / IPAddressLoginHandler.java
1 /*
2  * Licensed to the University Corporation for Advanced Internet Development, 
3  * Inc. (UCAID) under one or more contributor license agreements.  See the 
4  * NOTICE file distributed with this work for additional information regarding
5  * copyright ownership. The UCAID licenses this file to You under the Apache 
6  * License, Version 2.0 (the "License"); you may not use this file except in 
7  * compliance with 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 package edu.internet2.middleware.shibboleth.idp.authn.provider;
19
20 import java.net.InetAddress;
21 import java.net.UnknownHostException;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27
28 import org.opensaml.saml2.core.AuthnContext;
29 import org.opensaml.xml.util.DatatypeHelper;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine;
34 import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
35 import edu.internet2.middleware.shibboleth.idp.util.IPRange;
36
37 /**
38  * IP Address authentication handler.
39  * 
40  * This "authenticates" a user based on their IP address. It operates in either default deny or default allow mode, and
41  * evaluates a given request against a list of blocked or permitted IPs. It supports both IPv4 and IPv6.
42  */
43 public class IPAddressLoginHandler extends AbstractLoginHandler {
44
45     /** Class logger. */
46     private final Logger log = LoggerFactory.getLogger(IPAddressLoginHandler.class);
47
48     /** The username to use for IP-address "authenticated" users. */
49     private String authenticatedUser;
50
51     /** List of configured IP ranged. */
52     private List<IPRange> ipRanges;
53
54     /** Whether a user is "authenticated" if their IP address is within a configured IP range. */
55     private boolean ipInRangeIsAuthenticated;
56
57     /**
58      * Constructor.
59      * 
60      * @param user username to return upon successful "authentication"
61      * @param ranges range of IP addresses specified
62      * @param isIpInRangeAuthenticated whether the specified IP address range represent those that are authenticated or
63      *            those that are not
64      */
65     public IPAddressLoginHandler(String user, List<IPRange> ranges, boolean isIpInRangeAuthenticated) {
66         authenticatedUser = DatatypeHelper.safeTrimOrNullString(user);
67         if (authenticatedUser == null) {
68             throw new IllegalArgumentException("The authenticated user ID may not be null or empty");
69         }
70
71         if (ranges == null || ranges.isEmpty()) {
72             throw new IllegalArgumentException("The list of IP ranges may not be null or empty");
73         }
74         ipRanges = new ArrayList<IPRange>(ranges);
75
76         this.ipInRangeIsAuthenticated = isIpInRangeAuthenticated;
77     }
78
79     /** {@inheritDoc} */
80     public boolean supportsPassive() {
81         return true;
82     }
83
84     /** {@inheritDoc} */
85     public boolean supportsForceAuthentication() {
86         return true;
87     }
88
89     /** {@inheritDoc} */
90     public void login(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
91         log.debug("Attempting to authenticated client '{}'", httpRequest.getRemoteAddr());
92         try {
93             InetAddress clientAddress = InetAddress.getByName(httpRequest.getRemoteAddr());
94             if (authenticate(clientAddress)) {
95                 log.debug("Authenticated user by IP address");
96                 httpRequest.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, authenticatedUser);
97                 httpRequest.setAttribute(LoginHandler.AUTHENTICATION_METHOD_KEY, AuthnContext.IP_AUTHN_CTX);
98             } else {
99                 log.debug("Client IP address {} failed authentication.", httpRequest.getRemoteAddr());
100                 httpRequest.setAttribute(LoginHandler.AUTHENTICATION_ERROR_KEY,
101                         "Client failed IP address authentication");
102             }
103         } catch (UnknownHostException e) {
104             String msg = "Unable to resolve " + httpRequest.getRemoteAddr() + " in to an IP address";
105             log.warn(msg);
106             httpRequest.setAttribute(LoginHandler.AUTHENTICATION_ERROR_KEY, msg);
107         }
108
109         AuthenticationEngine.returnToAuthenticationEngine(httpRequest, httpResponse);
110     }
111
112     /**
113      * Authenticates the client address.
114      * 
115      * @param clientAddress the client address
116      * 
117      * @return true if the client address is authenticated, false it not
118      */
119     protected boolean authenticate(InetAddress clientAddress) {
120         if (ipInRangeIsAuthenticated) {
121             for (IPRange range : ipRanges) {
122                 if (range.contains(clientAddress)) {
123                     return true;
124                 }
125             }
126         } else {
127             for (IPRange range : ipRanges) {
128                 if (!range.contains(clientAddress)) {
129                     return true;
130                 }
131             }
132         }
133
134         return false;
135     }
136 }