// Copyright 2010 Google 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 com.google.enterprise.connector.servlet;
import com.google.enterprise.connector.manager.Context;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Remote Address Filter that can be used to restrict access to the
* Servlets. In general, we allow access from the GSA, localhost,
* proxies, and perhaps certain adminstrator machines.
*/
// TODO: This was intended to be extensible replacement for the
// Tomcat RemoteIPAddrValve. It has since been stripped of all
// such pretense and becomes, instead, a more generalized version
// of the hack perpetrated in revision r2607.
// Offboard Connector Managers must still rely on Tomcat RemoteIPAddrValve
// to determine access.
// TODO: This should really be a javax.servlet.Filter.
public class RemoteAddressFilter {
private static Logger LOGGER =
Logger.getLogger(ServletUtil.class.getName());
// Singleton instance.
private static RemoteAddressFilter instance = null;
// If true, Connector Manager is on-board GSA.
private final boolean onboard;
/**
* The various access modes. The GSA has access to all the servlets.
* The access mode names here are arbitrary, as their interpretations
* vary greatly between GSA on-board and off-board.
*/
public enum Access {
RED, BLACK
}
/** Restrict constructor to singlton. */
private RemoteAddressFilter() {
Properties props = Context.getInstance().getConnectorManagerProperties();
this.onboard = Boolean.valueOf(props.getProperty("manager.onboard"));
// TODO: extract accept/deny IP address patterns from properties.
LOGGER.config(((this.onboard) ? "On-board" : "External")
+ " Connector Manager detected.");
}
/** Returns the singleton RemoteAddressFilter for this context. */
public static synchronized RemoteAddressFilter getInstance() {
// Delay instantiating the singleton until we are sure the
// Context has been initialized.
if (instance == null) {
instance = new RemoteAddressFilter();
}
return instance;
}
/**
* Determine whether the supplied {@code remoteAddr} is allowed
* access under the given {@code Access} mode.
*
* @param accessMode the {@code Access} mode for the calling servlet.
* @param remoteAddr the IP address of the servlet's caller.
* @return {@code true} if the caller is permitted access to the servlet,
* {@code false} otherwise.
*/
public boolean allowed(Access accessMode, String remoteAddr) {
// Offboard - defer to RemoteIPAddr Valve.
// Onboard - RED is Public access, BLACK is GSA or localhost only.
if (!onboard || accessMode == Access.RED) {
return true;
}
try {
InetAddress caller = InetAddress.getByName(remoteAddr);
if (caller.isLoopbackAddress() ||
caller.equals(InetAddress.getLocalHost())) {
return true; // localhost is allowed access
}
String gsaHost = Context.getInstance().getGsaFeedHost();
InetAddress[] gsaAddrs = InetAddress.getAllByName(gsaHost);
for (int i = 0; i < gsaAddrs.length; i++) {
if (caller.equals(gsaAddrs[i])) {
return true; // GSA is allowed access
}
}
LOGGER.warning("Denying caller: " + caller );
} catch (UnknownHostException uhe) {
// Unknown host - fall through to fail.
LOGGER.log(Level.WARNING, "Denying caller:" + remoteAddr, uhe);
}
return false;
}
/**
* Determine whether the supplied {@code remoteAddr} is the configured
* Feed Host.
*
* @param remoteAddr the IP address of the servlet's caller.
* @return {@code true} if the caller is the Feed Host,
* {@code false} otherwise.
*/
public boolean isFeedHost(String remoteAddr) {
try {
InetAddress caller = InetAddress.getByName(remoteAddr);
if (onboard) {
// If onboard, localhost is feed host.
return caller.isLoopbackAddress() ||
caller.equals(InetAddress.getLocalHost());
}
String gsaHost = Context.getInstance().getGsaFeedHost();
InetAddress[] gsaAddrs = InetAddress.getAllByName(gsaHost);
for (int i = 0; i < gsaAddrs.length; i++) {
if (caller.equals(gsaAddrs[i])) {
return true; // The GSA Feed Host is the caller.
}
}
} catch (UnknownHostException uhe) {
// Unknown host - fall through to fail.
}
return false;
}
}