From 408981da0c6e70f0d90e08b4f9056a10b363975a Mon Sep 17 00:00:00 2001 From: lajoie Date: Wed, 5 Aug 2009 12:21:59 +0000 Subject: [PATCH 1/1] Create IP range helper class Refactor IP address login handler to use IP range helper Add IP authentication for new status handler git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/branches/REL_2@2876 ab3bd59b-922f-494d-bb5f-6f0a3c29deca --- .../middleware/shibboleth/idp/StatusServlet.java | 75 +++++- .../idp/authn/provider/IPAddressLoginHandler.java | 259 ++++---------------- .../authn/AbstractLoginHandlerFactoryBean.java | 2 +- .../IPAddressLoginHandlerBeanDefinitionParser.java | 70 ++++-- .../authn/IPAddressLoginHandlerFactoryBean.java | 79 ++---- .../idp/profile/StatusProfileHandler.java | 2 + .../middleware/shibboleth/idp/util/IPRange.java | 138 +++++++++++ 7 files changed, 322 insertions(+), 303 deletions(-) create mode 100644 src/main/java/edu/internet2/middleware/shibboleth/idp/util/IPRange.java diff --git a/src/main/java/edu/internet2/middleware/shibboleth/idp/StatusServlet.java b/src/main/java/edu/internet2/middleware/shibboleth/idp/StatusServlet.java index a63cdfb..9b3afe5 100644 --- a/src/main/java/edu/internet2/middleware/shibboleth/idp/StatusServlet.java +++ b/src/main/java/edu/internet2/middleware/shibboleth/idp/StatusServlet.java @@ -18,6 +18,8 @@ package edu.internet2.middleware.shibboleth.idp; import java.io.IOException; import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -25,24 +27,36 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.httpclient.HttpStatus; import org.joda.time.DateTime; import org.joda.time.chrono.ISOChronology; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.opensaml.xml.security.x509.X509Credential; import org.opensaml.xml.util.Base64; +import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.LazyList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException; import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver; import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration; import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfigurationManager; import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper; +import edu.internet2.middleware.shibboleth.idp.util.IPRange; /** A Servlet for displaying the status of the IdP. */ public class StatusServlet extends HttpServlet { /** Serial version UID. */ - private static final long serialVersionUID = 7917509317276109266L; + private static final long serialVersionUID = -5280549109235107879L; + + private final String IP_PARAM_NAME = "AllowedIPs"; + + private final Logger log = LoggerFactory.getLogger(StatusServlet.class); + + private LazyList allowedIPs; /** Formatter used when print date/times. */ private DateTimeFormatter dateFormat; @@ -60,6 +74,15 @@ public class StatusServlet extends HttpServlet { public void init(ServletConfig config) throws ServletException { super.init(config); + allowedIPs = new LazyList(); + + String cidrBlocks = DatatypeHelper.safeTrimOrNullString(config.getInitParameter(IP_PARAM_NAME)); + if (cidrBlocks != null) { + for (String cidrBlock : cidrBlocks.split(" ")) { + allowedIPs.add(IPRange.parseCIDRBlock(cidrBlock)); + } + } + dateFormat = ISODateTimeFormat.dateTimeNoMillis(); startTime = new DateTime(ISOChronology.getInstanceUTC()); attributeResolver = HttpServletHelper.getAttributeResolver(config.getServletContext()); @@ -67,20 +90,49 @@ public class StatusServlet extends HttpServlet { } /** {@inheritDoc} */ - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - resp.setContentType("text/plain"); - PrintWriter output = resp.getWriter(); + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + if (!isAuthenticated(request)) { + response.sendError(HttpStatus.SC_UNAUTHORIZED); + return; + } + + response.setContentType("text/plain"); + PrintWriter output = response.getWriter(); printOperatingEnvironmentInformation(output); output.println(); printIdPInformation(output); output.println(); - printRelyingPartyConfigurationsInformation(output, req.getParameter("relyingParty")); + printRelyingPartyConfigurationsInformation(output, request.getParameter("relyingParty")); output.flush(); } /** + * Checks whether the client is authenticated. + * + * @param request client request + * + * @return true if the client is authenticated, false if not + */ + protected boolean isAuthenticated(HttpServletRequest request) throws ServletException { + log.debug("Attempting to authenticate client '{}'", request.getRemoteAddr()); + try { + InetAddress clientAddress = InetAddress.getByName(request.getRemoteAddr()); + + for (IPRange range : allowedIPs) { + if (range.contains(clientAddress)) { + return true; + } + } + + return false; + } catch (UnknownHostException e) { + throw new ServletException(e); + } + } + + /** * Prints out information about the operating environment. This includes the operating system name, version and * architecture, the JDK version, available CPU cores, memory currently used by the JVM process, the maximum amount * of memory that may be used by the JVM, and the current time in UTC. @@ -155,20 +207,23 @@ public class StatusServlet extends HttpServlet { protected void printRelyingPartyConfigurationInformation(PrintWriter out, RelyingPartyConfiguration config) { out.println("relying_party_id: " + config.getRelyingPartyId()); out.println("idp_entity_id: " + config.getProviderId()); - + if (config.getDefaultAuthenticationMethod() != null) { out.println("default_authentication_method: " + config.getDefaultAuthenticationMethod()); } else { out.println("default_authentication_method: none"); } - try{ + try { X509Credential signingCredential = (X509Credential) config.getDefaultSigningCredential(); - out.println("default_signing_tls_key: " + Base64.encodeBytes(signingCredential.getEntityCertificate().getEncoded(), Base64.DONT_BREAK_LINES)); - }catch(Throwable t){ + out + .println("default_signing_tls_key: " + + Base64.encodeBytes(signingCredential.getEntityCertificate().getEncoded(), + Base64.DONT_BREAK_LINES)); + } catch (Throwable t) { // swallow error } - + for (String profileId : config.getProfileConfigurations().keySet()) { out.println("configured_communication_profile: " + profileId); } diff --git a/src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/IPAddressLoginHandler.java b/src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/IPAddressLoginHandler.java index d6f316e..6e02809 100644 --- a/src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/IPAddressLoginHandler.java +++ b/src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/IPAddressLoginHandler.java @@ -1,5 +1,5 @@ /* - * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.] + * Copyright 2006 University Corporation for Advanced Internet Development, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,32 +16,29 @@ package edu.internet2.middleware.shibboleth.idp.authn.provider; -import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.BitSet; +import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.opensaml.xml.util.DatatypeHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine; +import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationException; import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler; +import edu.internet2.middleware.shibboleth.idp.util.IPRange; /** * IP Address authentication handler. * * This "authenticates" a user based on their IP address. It operates in either default deny or default allow mode, and * evaluates a given request against a list of blocked or permitted IPs. It supports both IPv4 and IPv6. - * - * If an Authentication Context Class or DeclRef URI is not specified, it will default to - * "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol". */ public class IPAddressLoginHandler extends AbstractLoginHandler { @@ -49,37 +46,26 @@ public class IPAddressLoginHandler extends AbstractLoginHandler { private final Logger log = LoggerFactory.getLogger(IPAddressLoginHandler.class); /** The username to use for IP-address "authenticated" users. */ - private String username; - - /** Are the IPs in ipList a permitted list or a deny list. */ - private boolean defaultDeny; + private String authenticatedUser; - /** The list of denied or permitted IPs. */ - private List ipList; + /** List of configured IP ranged. */ + private List ipRanges; - /** - * Set the permitted IP addresses. - * - * If defaultDeny is true then only the IP addresses in ipList will be - * "authenticated." If defaultDeny is false, then all IP addresses except those in - * ipList will be authenticated. - * - * @param entries A list of IP addresses (with CIDR masks). - * @param defaultDeny Does ipList contain a deny or permit list. - */ - public void setEntries(final List entries, boolean defaultDeny) { + /** Whether a user is "authenticated" if their IP address is within a configured IP range. */ + private boolean ipInRangeIsAuthenticated; - this.defaultDeny = defaultDeny; - ipList = new CopyOnWriteArrayList(); + public IPAddressLoginHandler(String user, List ranges, boolean ipInRangeIsAuthenticated) { + authenticatedUser = DatatypeHelper.safeTrimOrNullString(user); + if (authenticatedUser == null) { + throw new IllegalArgumentException("The authenticated user ID may not be null or empty"); + } - for (String addr : entries) { - try { - ipList.add(new edu.internet2.middleware.shibboleth.idp.authn.provider.IPAddressLoginHandler.IPEntry( - addr)); - } catch (UnknownHostException ex) { - log.warn("IPAddressHandler: Error parsing IP entry \"" + addr + "\". Ignoring."); - } + if (ranges == null || ranges.isEmpty()) { + throw new IllegalArgumentException("The list of IP ranges may not be null or empty"); } + ipRanges = new ArrayList(ranges); + + this.ipInRangeIsAuthenticated = ipInRangeIsAuthenticated; } /** {@inheritDoc} */ @@ -92,194 +78,51 @@ public class IPAddressLoginHandler extends AbstractLoginHandler { return true; } - /** - * Get the username for all IP-address authenticated users. - * - * @return The username for IP-address authenticated users. - */ - public String getUsername() { - return username; - } - - /** - * Set the username to use for all IP-address authenticated users. - * - * @param name The username for IP-address authenticated users. - */ - public void setUsername(String name) { - username = name; - } - /** {@inheritDoc} */ public void login(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { - - if (defaultDeny) { - handleDefaultDeny(httpRequest, httpResponse); - } else { - handleDefaultAllow(httpRequest, httpResponse); - } - - AuthenticationEngine.returnToAuthenticationEngine(httpRequest, httpResponse); - } - - protected void handleDefaultDeny(HttpServletRequest request, HttpServletResponse response) { - - boolean ipAllowed = searchIpList(request); - - if (ipAllowed) { - log.debug("Authenticated user by IP address"); - request.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, username); - } - } - - protected void handleDefaultAllow(HttpServletRequest request, HttpServletResponse response) { - - boolean ipDenied = searchIpList(request); - - if (!ipDenied) { - log.debug("Authenticated user by IP address"); - request.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, username); - } - } - - /** - * Search the list of InetAddresses for the client's address. - * - * @param request The ServletReqeust - * - * @return true if the client's address is in ipList - */ - private boolean searchIpList(ServletRequest request) { - - boolean found = false; - + log.debug("Attempting to authenticated client '{}'", httpRequest.getRemoteAddr()); try { - InetAddress addr = InetAddress.getByName(request.getRemoteAddr()); - BitSet addrbits = byteArrayToBitSet(addr.getAddress()); - - for (IPEntry entry : ipList) { - - BitSet netaddr = entry.getNetworkAddress(); - BitSet netmask = entry.getNetmask(); - - addrbits.and(netmask); - if (addrbits.equals(netaddr)) { - found = true; - break; - } + InetAddress clientAddress = InetAddress.getByName(httpRequest.getRemoteAddr()); + if (authenticate(clientAddress)) { + log.debug("Authenticated user by IP address"); + httpRequest.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, authenticatedUser); + } else { + log.debug("Client IP address {} failed authentication.", httpRequest.getRemoteAddr()); + httpRequest.setAttribute(LoginHandler.AUTHENTICATION_ERROR_KEY, new AuthenticationException( + "Client failed IP address authentication")); } - - } catch (UnknownHostException ex) { - log.error("Error resolving hostname.", ex); - return false; + } catch (UnknownHostException e) { + String msg = MessageFormatter.format("Unable to resolve {} in to an IP address", httpRequest + .getRemoteAddr()); + log.warn(msg); + httpRequest.setAttribute(LoginHandler.AUTHENTICATION_ERROR_KEY, new AuthenticationException(msg)); } - return found; + AuthenticationEngine.returnToAuthenticationEngine(httpRequest, httpResponse); } /** - * Converts a byte array to a BitSet. + * Authenticates the client address. * - * The supplied byte array is assumed to have the most signifigant bit in element 0. + * @param clientAddress the client address * - * @param bytes the byte array with most signifigant bit in element 0. - * - * @return the BitSet - */ - protected BitSet byteArrayToBitSet(final byte[] bytes) { - - BitSet bits = new BitSet(); - - for (int i = 0; i < bytes.length * 8; i++) { - if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) { - bits.set(i); - } - } - - return bits; - } - - /** - * Encapsulates a network address and a netmask on ipList. + * @return true if the client address is authenticated, false it not */ - protected class IPEntry { - - /** The network address. */ - private final BitSet networkAddress; - - /** The netmask. */ - private final BitSet netmask; - - /** - * Construct a new IPEntry given a network address in CIDR format. - * - * @param entry A CIDR-formatted network address/netmask - * - * @throws UnknownHostException If entry is malformed. - */ - public IPEntry(String entry) throws UnknownHostException { - - // quick sanity checks - if (entry == null || entry.length() == 0) { - throw new UnknownHostException("entry is null."); - } - - int cidrOffset = entry.indexOf("/"); - if (cidrOffset == -1) { - log.warn("Invalid entry \"" + entry + "\" -- it lacks a netmask component."); - throw new UnknownHostException("entry lacks a netmask component."); - } - - // ensure that only one "/" is present. - if (entry.indexOf("/", cidrOffset + 1) != -1) { - log.warn("Invalid entry \"" + entry + "\" -- too many \"/\" present."); - throw new UnknownHostException("entry has too many netmask components."); - } - - String networkString = entry.substring(0, cidrOffset); - String netmaskString = entry.substring(cidrOffset + 1, entry.length()); - - InetAddress tempAddr = InetAddress.getByName(networkString); - networkAddress = byteArrayToBitSet(tempAddr.getAddress()); - - int masklen = Integer.parseInt(netmaskString); - - int addrlen; - if (tempAddr instanceof Inet4Address) { - addrlen = 32; - } else if (tempAddr instanceof Inet6Address) { - addrlen = 128; - }else{ - throw new UnknownHostException("Unable to determine Inet protocol version"); + protected boolean authenticate(InetAddress clientAddress) { + if (ipInRangeIsAuthenticated) { + for (IPRange range : ipRanges) { + if (range.contains(clientAddress)) { + return true; + } } - - // ensure that the netmask isn't too large - if ((tempAddr instanceof Inet4Address) && (masklen > 32)) { - throw new UnknownHostException("Netmask is too large for an IPv4 address: " + masklen); - } else if ((tempAddr instanceof Inet6Address) && masklen > 128) { - throw new UnknownHostException("Netmask is too large for an IPv6 address: " + masklen); + } else { + for (IPRange range : ipRanges) { + if (!range.contains(clientAddress)) { + return true; + } } - - netmask = new BitSet(addrlen); - netmask.set(addrlen - masklen, addrlen, true); - } - - /** - * Get the network address. - * - * @return the network address. - */ - public BitSet getNetworkAddress() { - return networkAddress; } - /** - * Get the netmask. - * - * @return the netmask. - */ - public BitSet getNetmask() { - return netmask; - } + return false; } } \ No newline at end of file diff --git a/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/AbstractLoginHandlerFactoryBean.java b/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/AbstractLoginHandlerFactoryBean.java index d04bb4c..da37c04 100644 --- a/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/AbstractLoginHandlerFactoryBean.java +++ b/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/AbstractLoginHandlerFactoryBean.java @@ -78,6 +78,6 @@ public abstract class AbstractLoginHandlerFactoryBean extends AbstractFactoryBea if (authenticationMethods != null) { handler.getSupportedAuthenticationMethods().addAll(authenticationMethods); } - handler.setAuthenticationDurection(authenticationDuration * 60 * 1000); + handler.setAuthenticationDuration(authenticationDuration * 60 * 1000); } } diff --git a/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerBeanDefinitionParser.java b/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerBeanDefinitionParser.java index c3dc07d..e9ef96f 100644 --- a/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerBeanDefinitionParser.java +++ b/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerBeanDefinitionParser.java @@ -16,32 +16,28 @@ package edu.internet2.middleware.shibboleth.idp.config.profile.authn; -import java.util.ArrayList; import java.util.List; -import java.util.Map; import javax.xml.namespace.QName; import org.opensaml.xml.util.DatatypeHelper; +import org.opensaml.xml.util.LazyList; import org.opensaml.xml.util.XMLHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.w3c.dom.Element; import edu.internet2.middleware.shibboleth.idp.config.profile.ProfileHandlerNamespaceHandler; +import edu.internet2.middleware.shibboleth.idp.util.IPRange; -/** - * Spring bean definition parser for IP address authentication handlers. - */ +/** Spring bean definition parser for IP address authentication handlers. */ public class IPAddressLoginHandlerBeanDefinitionParser extends AbstractLoginHandlerBeanDefinitionParser { /** Schema type. */ public static final QName SCHEMA_TYPE = new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "IPAddress"); - /** Name of ip entry elements. */ - public static final QName IP_ENTRY_ELEMENT_NAME = new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "IPEntry"); - /** Class logger. */ private final Logger log = LoggerFactory.getLogger(IPAddressLoginHandlerBeanDefinitionParser.class); @@ -54,25 +50,45 @@ public class IPAddressLoginHandlerBeanDefinitionParser extends AbstractLoginHand protected void doParse(Element config, BeanDefinitionBuilder builder) { super.doParse(config, builder); + String username = DatatypeHelper.safeTrimOrNullString(config.getAttributeNS(null, "username")); + if (username == null) { + String msg = "No username specified."; + log.error(msg); + throw new BeanCreationException(msg); + } + log.debug("authenticated username: {}", username); + builder.addPropertyValue("authenticatedUser", username); + + List ranges = getIPRanges(config); + log.debug("registered IP ranges: {}", ranges.size()); + builder.addPropertyValue("ipRanges", ranges); + boolean defaultDeny = XMLHelper.getAttributeValueAsBoolean(config.getAttributeNodeNS(null, "defaultDeny")); - log.debug("Setting defaultDeny to: {}", defaultDeny); - builder.addPropertyValue("defaultDeny", defaultDeny); - - String username = DatatypeHelper.safeTrim(config.getAttributeNS(null, "username")); - log.debug("Setting username to: {}", username); - builder.addPropertyValue("username", username); - - Map> children = XMLHelper.getChildElements(config); - List ipEntries = children.get(IP_ENTRY_ELEMENT_NAME); - List addresses = new ArrayList(); - - for (Element element : ipEntries) { - String address = DatatypeHelper.safeTrimOrNullString(element.getTextContent()); - if (address != null) { - log.debug("Adding IP Address: {}", address); - addresses.add(address); - } + log.debug("default deny: {}", defaultDeny); + builder.addPropertyValue("ipInRangeIsAuthenticated", defaultDeny); + } + + /** + * Gets the list of IP ranges given in the configuration. + * + * @param config current configuration + * + * @return list of IP ranges + */ + protected List getIPRanges(Element config) { + List ipEntries = XMLHelper.getChildElementsByTagNameNS(config, + ProfileHandlerNamespaceHandler.NAMESPACE, "IPEntry"); + if (ipEntries == null || ipEntries.isEmpty()) { + String msg = "At least one IPEntry must be specified."; + log.error(msg); + throw new BeanCreationException(msg); } - builder.addPropertyValue("addresses", addresses); + + List ranges = new LazyList(); + for (Element ipEntry : ipEntries) { + ranges.add(IPRange.parseCIDRBlock(ipEntry.getTextContent())); + } + + return ranges; } -} +} \ No newline at end of file diff --git a/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerFactoryBean.java b/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerFactoryBean.java index 27067aa..807e648 100644 --- a/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerFactoryBean.java +++ b/src/main/java/edu/internet2/middleware/shibboleth/idp/config/profile/authn/IPAddressLoginHandlerFactoryBean.java @@ -19,87 +19,52 @@ package edu.internet2.middleware.shibboleth.idp.config.profile.authn; import java.util.List; import edu.internet2.middleware.shibboleth.idp.authn.provider.IPAddressLoginHandler; +import edu.internet2.middleware.shibboleth.idp.util.IPRange; /** * Spring factory for {@link IPAddressLoginHandler}. */ public class IPAddressLoginHandlerFactoryBean extends AbstractLoginHandlerFactoryBean { - /** The list of denied or permitted IPs. */ - private List addresses; - /** The username to use for IP-address "authenticated" users. */ - private String username; + private String authenticatedUser; - /** Are the IPs in ipList a permitted list or a deny list. */ - private boolean defaultDeny; + /** List of configured IP ranged. */ + private List ipRanges; - /** {@inheritDoc} */ - protected Object createInstance() throws Exception { - IPAddressLoginHandler handler = new IPAddressLoginHandler(); - handler.setUsername(getUsername()); - handler.setEntries(getAddresses(), isDefaultDeny()); - populateHandler(handler); - return handler; - } + /** Whether a user is "authenticated" if their IP address is within a configured IP range. */ + private boolean ipInRangeIsAuthenticated; /** {@inheritDoc} */ public Class getObjectType() { return IPAddressLoginHandler.class; } - - /** - * Get the list of denied or permitted IPs. - * - * @return list of denied or permitted IPs - */ - public List getAddresses() { - return addresses; - } - - /** - * Set the list of denied or permitted IPs. - * - * @param newAddresses list of denied or permitted IPs - */ - public void setAddresses(List newAddresses) { - addresses = newAddresses; - } - + /** - * Get the username to use for IP-address "authenticated" users. - * - * @return username to use for IP-address "authenticated" users + * @param user The authenticatedUser to set. */ - public String getUsername() { - return username; + public void setAuthenticatedUser(String user) { + authenticatedUser = user; } /** - * Set the username to use for IP-address "authenticated" users. - * - * @param newUsername username to use for IP-address "authenticated" users + * @param ranges The ipRanges to set. */ - public void setUsername(String newUsername) { - username = newUsername; + public void setIpRanges(List ranges) { + ipRanges = ranges; } /** - * Get whether the IPs in ipList a permitted list or a deny list. - * - * @return whether the IPs in ipList a permitted list or a deny list + * @param authenticated The ipInRangeIsAuthenticated to set. */ - public boolean isDefaultDeny() { - return defaultDeny; + public void setIpInRangeIsAuthenticated(boolean authenticated) { + ipInRangeIsAuthenticated = authenticated; } - /** - * Set whether the IPs in ipList a permitted list or a deny list. - * - * @param newDefaultDeny whether the IPs in ipList a permitted list or a deny list. - */ - public void setDefaultDeny(boolean newDefaultDeny) { - defaultDeny = newDefaultDeny; + /** {@inheritDoc} */ + protected Object createInstance() throws Exception { + IPAddressLoginHandler handler = new IPAddressLoginHandler(authenticatedUser, ipRanges, ipInRangeIsAuthenticated); + populateHandler(handler); + return handler; } - -} +} \ No newline at end of file diff --git a/src/main/java/edu/internet2/middleware/shibboleth/idp/profile/StatusProfileHandler.java b/src/main/java/edu/internet2/middleware/shibboleth/idp/profile/StatusProfileHandler.java index 2af3fbf..b19ca46 100644 --- a/src/main/java/edu/internet2/middleware/shibboleth/idp/profile/StatusProfileHandler.java +++ b/src/main/java/edu/internet2/middleware/shibboleth/idp/profile/StatusProfileHandler.java @@ -29,6 +29,8 @@ import edu.internet2.middleware.shibboleth.common.profile.provider.AbstractReque /** * A simple profile handler that returns the string "ok" if the IdP is able to answer the request. This may be used for * very basic monitoring of the IdP. + * + * @deprecated */ public class StatusProfileHandler extends AbstractRequestURIMappedProfileHandler { diff --git a/src/main/java/edu/internet2/middleware/shibboleth/idp/util/IPRange.java b/src/main/java/edu/internet2/middleware/shibboleth/idp/util/IPRange.java new file mode 100644 index 0000000..dd0a75b --- /dev/null +++ b/src/main/java/edu/internet2/middleware/shibboleth/idp/util/IPRange.java @@ -0,0 +1,138 @@ +/* + * Copyright 2009 University Corporation for Advanced Internet Development, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package edu.internet2.middleware.shibboleth.idp.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.BitSet; + +import org.opensaml.xml.util.DatatypeHelper; + +/** Represents a range of IP addresses. */ +public class IPRange { + + /** Number of bits within */ + private int addressLength; + + /** The IP network address for the range. */ + private BitSet network; + + /** The netmask for the range. */ + private BitSet mask; + + /** + * Constructor + * + * @param networkAddress the network address for the range + * @param maskSize the number of bits in the netmask + */ + public IPRange(InetAddress networkAddress, int maskSize) { + this(networkAddress.getAddress(), maskSize); + } + + /** + * Constructor + * + * @param networkAddress the network address for the range + * @param maskSize the number of bits in the netmask + */ + public IPRange(byte[] networkAddress, int maskSize) { + addressLength = networkAddress.length * 8; + if (addressLength != 32 && addressLength != 128) { + throw new IllegalArgumentException("Network address was neither an IPv4 or IPv6 address"); + } + + network = toBitSet(networkAddress); + mask = new BitSet(addressLength); + mask.set(addressLength - maskSize, addressLength, true); + } + + /** + * Parses a CIDR block definition in to an IP range. + * + * @param cidrBlock the CIDR block definition + * + * @return the resultant IP range + */ + public static IPRange parseCIDRBlock(String cidrBlock){ + String block = DatatypeHelper.safeTrimOrNullString(cidrBlock); + if(block == null){ + throw new IllegalArgumentException("CIDR block definition may not be null"); + } + + String[] blockParts = block.split("/"); + try{ + InetAddress networkAddress = InetAddress.getByName(blockParts[0]); + int maskSize = Integer.parseInt(blockParts[1]); + return new IPRange(networkAddress, maskSize); + }catch(UnknownHostException e){ + throw new IllegalArgumentException("Invalid IP address"); + }catch(NumberFormatException e){ + throw new IllegalArgumentException("Invalid netmask size"); + } + } + + /** + * Determines whether the given address is contained in the IP range. + * + * @param address the address to check + * + * @return true if the address is in the range, false it not + */ + public boolean contains(InetAddress address) { + return contains(address.getAddress()); + } + + /** + * Determines whether the given address is contained in the IP range. + * + * @param address the address to check + * + * @return true if the address is in the range, false it not + */ + public boolean contains(byte[] address) { + if (address.length * 8 != addressLength) { + return false; + } + + BitSet addrNetwork = toBitSet(address); + addrNetwork.and(mask); + + return addrNetwork.equals(network); + } + + /** + * Converts a byte array to a BitSet. + * + * The supplied byte array is assumed to have the most significant bit in element 0. + * + * @param bytes the byte array with most significant bit in element 0. + * + * @return the BitSet + */ + protected BitSet toBitSet(byte[] bytes) { + BitSet bits = new BitSet(bytes.length * 8); + + for (int i = 0; i < bytes.length * 8; i++) { + if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) { + bits.set(i); + } + } + + return bits; + } +} \ No newline at end of file -- 1.7.10.4