org.signserver.server.ListBasedAddressAuthorizer.java Source code

Java tutorial

Introduction

Here is the source code for org.signserver.server.ListBasedAddressAuthorizer.java

Source

/*************************************************************************
 *                                                                       *
 *  SignServer: The OpenSource Automated Signing Server                  *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/
package org.signserver.server;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.signserver.common.AccessDeniedException;
import org.signserver.common.IllegalRequestException;
import org.signserver.common.ProcessRequest;
import org.signserver.common.RequestContext;
import org.signserver.common.SignServerException;
import org.signserver.common.WorkerConfig;
import org.signserver.common.util.XForwardedForUtils;
import org.signserver.server.log.LogMap;

/**
 * Authorizer with the ability to accept or deny remote and
 * forwarded addresses based on white and black listing.
 * 
 * @author Marcus Lundblad
 * @version $Id: ListBasedAddressAuthorizer.java 3539 2013-06-03 14:34:03Z malu9369 $
 */

public class ListBasedAddressAuthorizer implements IAuthorizer {

    /** Logger for this class. */
    private static final Logger LOG = Logger.getLogger(ListBasedAddressAuthorizer.class);

    private static final String PROPERTY_WHITELISTED_DIRECT_ADDRESSES = "WHITELISTED_DIRECT_ADDRESSES";
    private static final String PROPERTY_BLACKLISTED_DIRECT_ADDRESSES = "BLACKLISTED_DIRECT_ADDRESSES";
    private static final String PROPERTY_WHITELISTED_FORWARDED_ADDRESSES = "WHITELISTED_FORWARDED_ADDRESSES";
    private static final String PROPERTY_BLACKLISTED_FORWARDED_ADDRESSES = "BLACKLISTED_FORWARDED_ADDRESSES";
    private static final String PROPERTY_MAX_FORWARDED_ADDRESSES = "MAX_FORWARDED_ADDRESSES";

    private static final int MAX_FORWARDED_ADDRESSES_DEFAULT = 1;

    private Set<InetAddress> addressesDirect;
    private Set<InetAddress> addressesForwarded;
    private boolean isDirectWhitelisting;
    private boolean isForwardedWhitelisting;
    private String whitelistedDirectAddresses;
    private String blacklistedDirectAddresses;
    private String whitelistedForwardedAddresses;
    private String blacklistedForwardedAddresses;
    private int maxForwardedAddresses;

    private int workerId;

    private List<String> fatalErrors;

    @Override
    public void init(int workerId, WorkerConfig config, EntityManager em) throws SignServerException {
        this.workerId = workerId;

        fatalErrors = new LinkedList<String>();

        whitelistedDirectAddresses = config.getProperty(PROPERTY_WHITELISTED_DIRECT_ADDRESSES);
        blacklistedDirectAddresses = config.getProperty(PROPERTY_BLACKLISTED_DIRECT_ADDRESSES);
        whitelistedForwardedAddresses = config.getProperty(PROPERTY_WHITELISTED_FORWARDED_ADDRESSES);
        blacklistedForwardedAddresses = config.getProperty(PROPERTY_BLACKLISTED_FORWARDED_ADDRESSES);

        try {
            maxForwardedAddresses = Integer.parseInt(config.getProperty(PROPERTY_MAX_FORWARDED_ADDRESSES,
                    Integer.toString(MAX_FORWARDED_ADDRESSES_DEFAULT)));
        } catch (NumberFormatException e) {
            fatalErrors.add("Illegal value for MAX_FORWARDED_ADDRESSES specified: " + e.getMessage());
        }

        checkAndAddFatalErrors(config);

        isDirectWhitelisting = whitelistedDirectAddresses != null;
        isForwardedWhitelisting = whitelistedForwardedAddresses != null;

        if (whitelistedDirectAddresses != null) {
            addressesDirect = splitAddresses(whitelistedDirectAddresses, PROPERTY_WHITELISTED_DIRECT_ADDRESSES);
        } else if (blacklistedDirectAddresses != null) {
            addressesDirect = splitAddresses(blacklistedDirectAddresses, PROPERTY_BLACKLISTED_DIRECT_ADDRESSES);
        }

        if (whitelistedForwardedAddresses != null) {
            addressesForwarded = splitAddresses(whitelistedForwardedAddresses,
                    PROPERTY_WHITELISTED_FORWARDED_ADDRESSES);
        } else if (blacklistedForwardedAddresses != null) {
            addressesForwarded = splitAddresses(blacklistedForwardedAddresses,
                    PROPERTY_BLACKLISTED_FORWARDED_ADDRESSES);
        }

        if (fatalErrors.size() > 0) {
            throw new SignServerException("Invalid properties specified: " + StringUtils.join(fatalErrors, '\n'));
        }
    }

    /**
     * Helper method to extract addresses from configuration properties. Will also set fatal errors for malformed addresses.
     * 
     * @param addresses Comma-separated list of IP addresses (taken from the configuration)
     * @param component Used to prefix a possible error string
     * @return A set of InetAddress objects representing the list
     */
    private Set<InetAddress> splitAddresses(final String addresses, final String component) {
        final Set<InetAddress> res = new HashSet<InetAddress>();
        final String[] addressArr = addresses.split(",");

        for (String address : addressArr) {
            address = address.trim();
            if (address.length() > 0) {
                try {
                    res.add(InetAddress.getByName(address));
                } catch (UnknownHostException e) {
                    fatalErrors.add(component + ", illegal address specified: " + e.getMessage());
                }
            }
        }

        return res;
    }

    @Override
    public void isAuthorized(ProcessRequest request, RequestContext requestContext)
            throws IllegalRequestException, AccessDeniedException, SignServerException {
        final String remote = (String) requestContext.get(RequestContext.REMOTE_IP);
        final String[] forwardedAddresses = XForwardedForUtils.getXForwardedForIPs(requestContext,
                maxForwardedAddresses);
        InetAddress remoteAddress;
        try {
            remoteAddress = InetAddress.getByName(remote);
        } catch (UnknownHostException e) {
            throw new IllegalRequestException("Illegal remote address in request: " + e.getMessage());
        }

        if (!fatalErrors.isEmpty()) {
            throw new SignServerException("Misconfigured");
        }

        // check direct address
        if ((isDirectWhitelisting && !addressesDirect.contains(remoteAddress))
                || (!isDirectWhitelisting && addressesDirect.contains(remoteAddress))) {
            LOG.error("Worker " + workerId + ": " + "Not authorized remote address: " + remote);
            throw new AccessDeniedException("Remote address not authorized");
        }

        if (isForwardedWhitelisting) {
            // if there is no forwarded header, of if header is empty
            if (forwardedAddresses == null || forwardedAddresses.length == 0) {
                throw new AccessDeniedException("No forwarded address in request");
            }

            for (final String forwarded : forwardedAddresses) {
                InetAddress forwardedAddress;
                try {
                    forwardedAddress = InetAddress.getByName(forwarded);
                } catch (UnknownHostException e) {
                    throw new IllegalRequestException("Illegal forwarded address in request: " + e.getMessage());
                }

                if (!addressesForwarded.contains(forwardedAddress)) {
                    LOG.error("Worker " + workerId + ": "
                            + "No authorized forwarded address among inspected addesses");
                    throw new AccessDeniedException("Forwarded address not athorized");
                }
            }
        } else {
            if (forwardedAddresses != null && forwardedAddresses.length > 0) {
                for (final String forwarded : forwardedAddresses) {
                    InetAddress forwardedAddress;
                    try {
                        forwardedAddress = InetAddress.getByName(forwarded);
                    } catch (UnknownHostException e) {
                        throw new IllegalRequestException(
                                "Illegal forwarded address in request: " + e.getMessage());
                    }

                    if (addressesForwarded.contains(forwardedAddress)) {
                        LOG.error("Worker " + workerId + ": "
                                + "Found blacklisted address among inspected addresses: " + forwarded);
                        throw new AccessDeniedException("Forwarded address not athorized");
                    }
                }
            }
        }

        logRemoteAddress(remote, forwardedAddresses, requestContext);
    }

    /**
     * Sets fatal errors based on members set in init().
     * 
     * @param config The worker config
     */
    private void checkAndAddFatalErrors(final WorkerConfig config) {
        // check that one (and only one) each of the direct and forwarded properties at a time is specified
        if (whitelistedDirectAddresses != null && blacklistedDirectAddresses != null) {
            fatalErrors.add("Only one of " + PROPERTY_WHITELISTED_DIRECT_ADDRESSES + " and "
                    + PROPERTY_BLACKLISTED_DIRECT_ADDRESSES + " can be specified.");
        }

        if (whitelistedForwardedAddresses != null && blacklistedForwardedAddresses != null) {
            fatalErrors.add("Only one of " + PROPERTY_WHITELISTED_FORWARDED_ADDRESSES + " and "
                    + PROPERTY_BLACKLISTED_FORWARDED_ADDRESSES + " can be specified.");
        }

        if (whitelistedDirectAddresses == null && blacklistedDirectAddresses == null) {
            fatalErrors.add("One of " + PROPERTY_WHITELISTED_DIRECT_ADDRESSES + " or "
                    + PROPERTY_BLACKLISTED_DIRECT_ADDRESSES + " must be specified.");
        }

        if (whitelistedForwardedAddresses == null && blacklistedForwardedAddresses == null) {
            fatalErrors.add("One of " + PROPERTY_WHITELISTED_FORWARDED_ADDRESSES + " or "
                    + PROPERTY_BLACKLISTED_FORWARDED_ADDRESSES + " must be specified.");
        }

        if (maxForwardedAddresses < 1) {
            fatalErrors.add("Illegal value for " + PROPERTY_MAX_FORWARDED_ADDRESSES + ": "
                    + config.getProperty(PROPERTY_MAX_FORWARDED_ADDRESSES));
        }
    }

    @Override
    public List<String> getFatalErrors() {
        return fatalErrors;
    }

    private void logRemoteAddress(final String remoteAddress, final String[] forwardedAddresses,
            final RequestContext requestContext) {
        final LogMap logMap = LogMap.getInstance(requestContext);
        logMap.put(IAuthorizer.LOG_REMOTEADDRESS, remoteAddress);
        logMap.put(IAuthorizer.LOG_FORWARDED_ADDRESS, StringUtils.join(forwardedAddresses, ","));
    }
}