All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jumpmind.symmetric.security.inet.Inet4AddressAuthorizerCompiler Maven / Gradle / Ivy

Go to download

SymmetricDS is an open source database synchronization solution. It is platform-independent, web-enabled, and database-agnostic. SymmetricDS was first built to replicate changes between 'retail store' databases and ad centralized 'corporate' database.

The newest version!
/*
 * Licensed to JumpMind Inc under one or more contributor 
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding 
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU Lesser General Public License (the
 * "License"); you may not use this file except in compliance
 * with the License. 
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see           
 * .
 * 
 * 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.jumpmind.symmetric.security.inet;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;

import org.jumpmind.symmetric.common.logging.ILog;
import org.jumpmind.symmetric.common.logging.LogFactory;

/**
 * Filter compiler for IPv4 addresses.
 * 
 * 2
 *
 * 
 */
public class Inet4AddressAuthorizerCompiler extends AbstractInetAddressAuthorizerCompiler {
    private static final ILog log = LogFactory.getLog(Inet4AddressAuthorizerCompiler.class);

    public static final String IPv4_OCTET_SEPARATOR = ".";

    public static final String BROADCAST_OCTET = "255";

    public static final int NUM_IPv4_OCTETS = 4;

    public static final short SHORT_MASK = 0x00FF;

    public static final byte ANY = (byte) 0xFF;

    /**
     * Used for comparison of a 'range' of IPv4 addresses. Specifically, the
     * address space between 2 IPv4 addresses, inclusive of the bounds (highest
     * and lowest possible) addresses themselves.
     * 
     * 
     */
    static class RawInet4AddressRangeAuthorizer implements IRawInetAddressAuthorizer {
        private final short[] startAddress;

        private final short[] endAddress;

        RawInet4AddressRangeAuthorizer(final short[] startAddress, final short[] endAddress) {
            super();
            if ((startAddress.length != NUM_IPv4_OCTETS) || (endAddress.length != NUM_IPv4_OCTETS)) {
                throw new IllegalArgumentException("Invalid number of octets in IPv4 address filter");
            }
            this.startAddress = startAddress;
            this.endAddress = endAddress;
        }

        public boolean isAuthorized(final byte[] addrBytes) {
            final short[] addrAsShorts = convertAddressBytesToShort(addrBytes);
            for (int i = 0; i < addrAsShorts.length; i++) {
                // if we don't have an all inclusive octet at the start (255)
                // offset and the octet
                // does not fall within the bounds, it's nix'd
                if ((startAddress[i] != SHORT_MASK)
                        && ((addrAsShorts[i] < startAddress[i]) || (addrAsShorts[i] > endAddress[i]))) {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * Used for comparison of addresses to a CIDR (Classless Inter-Domain
     * Routing) address block (i.e. '10.5.5.32/27')
     * 
     * 
     */
    static class RawInet4AddressCidrAuthorizer implements IRawInetAddressAuthorizer {
        private final int checkAddress;

        private int cidrMask = 0x80000000;

        private final byte significantBits;

        RawInet4AddressCidrAuthorizer(final byte[] address, final byte signifcantBits) {
            super();
            // Make sure the CIDR notation is valid (0-32 excluding 31)
            if ((signifcantBits < 0) || (signifcantBits > 32)) {
                throw new IllegalArgumentException(String.format("Invalid CIDR Notation '/%s'. Values must be 0-32.",
                        signifcantBits));
            }

            cidrMask = cidrMask >> (signifcantBits - 1);
            this.checkAddress = bytesToCidrInt(address);
            this.significantBits = signifcantBits;
        }

        public boolean isAuthorized(final byte[] addrBytes) {
            // This means that all addrs are allowed (i.e. CIDR notation '/0')
            if (significantBits == 0) {
                return true;
            }
            final int convertedAddress = bytesToCidrInt(addrBytes);
            if ((convertedAddress & checkAddress) == convertedAddress) {
                return true;
            }
            return false;
        }

        private int bytesToCidrInt(final byte[] address) {
            if ((address == null) || (address.length != NUM_IPv4_OCTETS)) {
                return 0;
            }
            int addressAsInt = 0;
            addressAsInt = address[3] & 0xFF;
            addressAsInt |= ((address[2] << 8) & 0xFF00);
            addressAsInt |= ((address[1] << 16) & 0xFF0000);
            addressAsInt |= ((address[0] << 24) & 0xFF000000);
            return addressAsInt & cidrMask;
        }
    }

    /**
     * Used for comparison to a static IP address (which may be wildcarded to a
     * broadcast). So, static IP addresses such as 10.5.5.32 and
     * 10.5.5.* are handled by this authorizer.
     * 
     * 
     */
    static class RawInet4AddressAuthorizer implements IRawInetAddressAuthorizer {
        private final byte[] checkAddress;

        RawInet4AddressAuthorizer(final byte[] address) {
            super();
            this.checkAddress = address;
        }

        public boolean isAuthorized(final byte[] addrBytes) {
            for (int i = 0; i < addrBytes.length; i++) {
                if ((checkAddress[i] != ANY) && (addrBytes[i] != checkAddress[i])) {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * Compiles for IPv4 specific address filter strings.
     * 
     * @param filter
     * @return
     * @throws UnknownHostException
     */
    @Override
    protected IRawInetAddressAuthorizer compileForIpVersion(String filter) throws UnknownHostException {
        filter = filter.trim();

        log.debug("FilterStringIPv4Compiling", filter);

        filter = replaceSymbols(filter);

        final String[] octets = filter.split('\\' + IPv4_OCTET_SEPARATOR);
        if (octets.length != NUM_IPv4_OCTETS) {
            throw new IllegalArgumentException(String.format(
                    "Invalid IPv4 filter. Must have 4 octects separated by: '%s'. Provided: %s Length: %s",
                    IPv4_OCTET_SEPARATOR, filter, octets.length));
        }
        log.debug("FilterRangeValuesChecking", filter);

        if (filter.contains(CIDR_TOKEN)) {
            return compileCidrAuthorizer(filter);
        } else if (filter.contains(RANGE_TOKEN)) {
            return compileRangeAuthorizer(octets);
        } else {
            // Both static and wild-carded addresses apply here
            final Inet4Address addr = (Inet4Address) InetAddress.getByName(filter);
            return new RawInet4AddressAuthorizer(addr.getAddress());
        }
    }

    /**
     * 
     */
    @Override
    protected String getAddressSeparator() {
        return IPv4_OCTET_SEPARATOR;
    }

    /**
     * 
     */
    @Override
    protected String getBroadcastString() {
        return BROADCAST_OCTET;
    }

    /**
     * Mechanism to pull a short from the provided textual octet.
     * Use short values as we have to do comparisons and
     * bytes are signed (and we'd have to add 254 prior to
     * comparison, blah, blah, blah)
     * 
     * @param octect
     * @return
     */
    protected short getOctetFromString(final String octect) {
        final short octetVal = Short.parseShort(octect);

        if ((octetVal > SHORT_MASK) || (octetVal < 0)) {
            throw new IllegalArgumentException("Invalid IPv4 octect: " + octetVal);
        }
        return octetVal;
    }

    /**
     * Utility method to convert between the actual byte[] address
     * representation and a short[] used to perform the address and
     * range comparison.
     * 
     * @param bytes
     * @return
     */
    public static short[] convertAddressBytesToShort(final byte[] bytes) {
        final short[] retVal = new short[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            retVal[i] = (short) ((SHORT_MASK) & (bytes[i]));
        }
        return retVal;

    }

    /**
     * Utility method to convert between the short[] used for
     * comparison and a byte[] for actual address representation.
     * 
     * @param shorts
     * @return
     */
    public static byte[] convertShortToAddressBytes(final short[] shorts) {
        final byte[] retVal = new byte[shorts.length];
        for (int i = 0; i < shorts.length; i++) {
            retVal[i] = (byte) shorts[i];
        }
        return retVal;
    }

    /**
     * @param octets
     * @return
     * @throws UnknownHostException
     */
    private RawInet4AddressRangeAuthorizer compileRangeAuthorizer(final String[] octets) throws UnknownHostException {
        final short[] startRange = new short[NUM_IPv4_OCTETS];
        final short[] endRange = new short[NUM_IPv4_OCTETS];
        for (int i = 0; i < octets.length; i++) {
            if (octets[i].contains(RANGE_TOKEN)) {
                final String[] range = octets[i].split(RANGE_TOKEN);
                if (range.length != 2) {
                    throw new IllegalArgumentException("Illegal range pattern for filter address octet. Provided: "
                            + octets[i]);
                }

                final short upperBounds = getOctetFromString(range[0]);
                final short lowerBounds = getOctetFromString(range[1]);
                if (upperBounds < lowerBounds) {
                    throw new IllegalArgumentException("Byte Range must be specificed as '"
                            + RANGE_TOKEN + "'. Provided: " + octets[i]);
                }
                startRange[i] = lowerBounds;
                endRange[i] = upperBounds;
            } else {
                final short singleVal = getOctetFromString(octets[i]);
                startRange[i] = singleVal;
                endRange[i] = singleVal;
            }
        }
        // Do a validation of the compiled short addr representations
        InetAddress.getByAddress(convertShortToAddressBytes(startRange));
        InetAddress.getByAddress(convertShortToAddressBytes(endRange));

        return new RawInet4AddressRangeAuthorizer(startRange, endRange);
    }

    /**
     * @param octets
     * @return
     * @throws UnknownHostException
     */
    private RawInet4AddressCidrAuthorizer compileCidrAuthorizer(final String filter) throws UnknownHostException {
        if (filter.contains(RANGE_TOKEN) || filter.contains(ANY_TOKEN)) {
            throw new IllegalArgumentException("CIDR formatted filters cannot contain other tokens");
        }
        final String[] cidrNotation = filter.split(CIDR_TOKEN, 2);
        if (cidrNotation.length != 2) {
            throw new IllegalArgumentException("Expected format of CIDR string is '###.###.###.###/##'");
        }
        final InetAddress inetAddr = InetAddress.getByName(cidrNotation[0]);
        final byte significantBits = Byte.parseByte(cidrNotation[1]);
        return new RawInet4AddressCidrAuthorizer(inetAddr.getAddress(), significantBits);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy