/* * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig licenses this file to you 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 the following location: * * 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 org.jasig.cas.adaptors.ldap.remote; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.GeneralSecurityException; import org.jasig.cas.authentication.AbstractAuthenticationHandler; import org.jasig.cas.authentication.HandlerResult; import org.jasig.cas.authentication.Credential; import org.jasig.cas.authentication.principal.SimplePrincipal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.security.auth.login.FailedLoginException; import javax.validation.constraints.NotNull; /** * Checks if the remote address is in the range of allowed addresses. * * @author David Harrison * @author Scott Battaglia * @since 3.2.1 * */ public final class RemoteAddressAuthenticationHandler extends AbstractAuthenticationHandler { private final Logger logger = LoggerFactory.getLogger(getClass()); /** The network netmask. */ @NotNull private InetAddress inetNetmask = null; /** The network base address. */ @NotNull private InetAddress inetNetwork = null; @Override public HandlerResult authenticate(final Credential credential) throws GeneralSecurityException { final RemoteAddressCredential c = (RemoteAddressCredential) credential; try { final InetAddress inetAddress = InetAddress.getByName(c.getRemoteAddress().trim()); if (containsAddress(this.inetNetwork, this.inetNetmask, inetAddress)) { return new HandlerResult(this, c, new SimplePrincipal(c.getId())); } } catch (final UnknownHostException e) { logger.debug("Unknown host {}", c.getRemoteAddress()); } throw new FailedLoginException(c.getRemoteAddress() + " not in allowed range."); } @Override public boolean supports(final Credential credential) { return credential instanceof RemoteAddressCredential; } /** * The following code is from the Apache Software Foundations's Lenya project * See InetAddressUtil.java * Distributed under the Apache 2.0 software license */ /** * Checks if a subnet contains a specific IP address. * * @param network The network address. * @param netmask The subnet mask. * @param ip The IP address to check. * @return A boolean value. */ private boolean containsAddress(final InetAddress network, final InetAddress netmask, final InetAddress ip) { logger.debug("Checking IP address: {} in ", ip, network, netmask); byte[] networkBytes = network.getAddress(); byte[] netmaskBytes = netmask.getAddress(); byte[] ipBytes = ip.getAddress(); /* check IPv4/v6-compatibility or parameters: */ if(networkBytes.length != netmaskBytes.length || netmaskBytes.length != ipBytes.length) { logger.debug("Network address {}, subnet mask {} and/or host address {}" + " have different sizes! (return false ...)", network, netmask, ip); return false; } /* Check if the masked network and ip addresses match: */ for(int i=0; i<netmaskBytes.length; i++) { int mask = netmaskBytes[i] & 0xff; if((networkBytes[i] & mask) != (ipBytes[i] & mask)) { logger.debug("{} is not in {}/{}", ip, network, netmask); return false; } } logger.debug("{} is in {}/{}", ip, network, netmask); return true; } /** * @param ipAddressRange the IP address range that should be allowed trusted logins * */ public void setIpNetworkRange(final String ipAddressRange) { if(ipAddressRange != null) { final String[] splitAddress = ipAddressRange.split("/"); if (splitAddress.length == 2) { // A valid ip address/netmask was supplied parse values final String network = splitAddress[0].trim(); final String netmask = splitAddress[1].trim(); try { this.inetNetwork = InetAddress.getByName(network); logger.debug("InetAddress network: {}", this.inetNetwork.toString()); } catch (final UnknownHostException e) { logger.error("The network address was not valid: {}", e.getMessage()); } try { this.inetNetmask = InetAddress.getByName(netmask); logger.debug("InetAddress netmask: {}", this.inetNetmask.toString()); } catch (final UnknownHostException e) { logger.error("The network netmask was not valid: {}", e.getMessage()); } } } } }