Package examples.security.net

Source Code of examples.security.net.SimpleConnectionFilter

package examples.security.net;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StreamCorruptedException;
import java.net.InetAddress;
import java.util.StringTokenizer;
import java.util.Vector;
import weblogic.security.net.ConnectionEvent;
import weblogic.security.net.ConnectionFilter;
import weblogic.security.net.FilterException;


/**
* Simple rule-based connection filter example.  This example reads in
* a set of rules from a file and bases its filtering decisions on
* these rules. <p>
*
* Syntax of the rule file is as follows: each rule is written on a
* single line.  Tokens in a rule are separated by whitespace.  "#" is
* the comment character; everything after it on a line is ignored.
* Whitespace before or after a rule is ignored.  Lines consisting
* solely of whitespace or comments are skipped. <p>
*
* All rules follow this form:
*
* <pre>
target  action  protocols
</pre>
*
* where <tt>target</tt> is a specification of one or more hosts to
* filter, <tt>action</tt> is the action to perform (and must be
* either <tt>allow</tt> or <tt>deny</tt>), and <tt>protocols</tt> is
* the list of protocol names to match (must be one of <tt>http</tt>,
* <tt>https</tt>, <tt>t3</tt>, <tt>t3s</tt>, or <tt>giop</tt>; if no
* protocols are listed, all protocols will match a rule). <p>
*
* This example recognizes two kinds of rule:
*
* <ul>
*
* <li>A "fast" rule applies to a hostname or IP address, with an
* optional netmask.  If a hostname corresponds to multiple IP
* addresses, multiple rules are generated (in no particular order).
* Netmasks can be specified either in numeric or dotted-quad form.
* Examples:
*
* <pre>
dialup-650-555-1212.pa.example.net  deny  t3 t3s  # http and https OK
192.168.81.0/255.255.254.0    allow    # 23-bit netmask
192.168.0.0/16        deny    # like /255.255.0.0
</pre>
*
* Hostnames for fast rules are looked up once, at server startup
* time.  While this greatly reduces connect-time overhead, it can
* result in the filter having an out-of-date idea of what addresses
* correspond to a hostname.  For maximal comfort of mind, use numeric
* IP addresses instead.
*
* <li>A "slow" rule applies to part of a domain name.  Since it
* requires a connect-time DNS lookup on a client in order to perform
* a match, it may be much slower than the "fast" rule, and it may
* also be subject to DNS spoofing.  Slow rules are specified as follows:
*
* <pre>
*.script-kiddiez.org  deny
</pre>
*
* The "*" <i>only</i> matches at the head of a pattern.  If you
* specify one anywhere else, it will be treated as part of the
* pattern (and so that pattern will never match anything, since "*"
* is not a legal part of a domain name).
*
* </ul>
*
* When a client connects, these rules are evaluated in the order in
* which they were written, and the first rule to match determines how
* the connection is treated.  If no rules match, the connection is
* permitted. <p>
*
* If you want to "lock down" your server and only allow connections
* from certain addresses, you can specify <tt>0.0.0.0/0 deny</tt> as
* your last rule. <p>
*
* Note that this example does not take full advantage of the
* information provided by the connection filter.  Further expansion
* is left as an exercise for the reader.  Note further that this
* example assumes IPv4 addresses, but it should be easy to convert it
* to use IPv6 addresses, if necessary.
*
* @author Copyright (c) 1999-2000 by BEA Systems, Inc. All Rights Reserved.
*/
public class SimpleConnectionFilter
  implements ConnectionFilter
{
  /**
   * The name of the filter rule file.
   */
  public static final String FILTER_FILE = "filter";

  /**
   * This is our set of filter rules.
   */
  private FilterEntry[] rules;

  /**
   * Construct a new connection filter.  This constructor attempts to
   * find the rule file in either the current directory or as a
   * resource in the server's classpath.
   *
   * @see #FILTER_FILE
   * @exception IOException a problem occurred while reading the rule
   * file
   */
  public SimpleConnectionFilter()
    throws IOException
  {
    InputStream in = null;

    try
    {
      in = new FileInputStream(FILTER_FILE);
    }
    catch (FileNotFoundException e)
    {
      // ignore
    }

    if (in == null)
    {
      in = SimpleConnectionFilter.class.getResourceAsStream(FILTER_FILE);
    }

    if (in == null)
    {
      throw new FileNotFoundException("cannot find \"" + FILTER_FILE +
              "\" in current directory or classpath");
    }

    setup(in);
  }

 
  /**
   * Construct a new connection filter.  Rules are read from the given
   * stream.
   *
   * @param is stream to read from
   * @exception IOException a problem occurred while reading the rule
   * file
   */
  public SimpleConnectionFilter(InputStream is)
    throws IOException
  {
    setup(is);
  }

 
  /**
   * Read rules from the given stream.
   *
   * @param is stream to read from
   * @exception IOException a problem occurred while reading the rule
   * file
   */
  private void setup(InputStream is)
    throws IOException
  {
    LineNumberReader r = new LineNumberReader(new InputStreamReader(is));

    Vector entries = new Vector();

    String line;

    while ((line = r.readLine()) != null)
    {
      // Ignore comments, surrounding whitespace, and empty lines.

      int hash = line.indexOf('#');

      if (hash != -1)
      {
  line = line.substring(0, hash).trim();
      }

      if (line.length() == 0)
      {
  continue;
      }

      try
      {
  parseLine(line, entries);
      }
      catch (StreamCorruptedException e)
      {
  throw new IOException("line " + r.getLineNumber() + ": " + e.getMessage());
      }
      catch (IllegalArgumentException e)
      {
  throw new IOException("line " + r.getLineNumber() + ": " + e.getMessage());
      }
    }

    rules = new FilterEntry[entries.size()];

    entries.copyInto(rules);
  }

 
  /**
   * Parse an individual line of the rule file.  Any resulting rules
   * are added to the given entries vector.
   *
   * @param line the line to parse (guaranteed not to contain
   * comments, surrounding whitespace, or be empty)
   * @param entries the running list of rules
   */
  protected void parseLine(String line, Vector entries)
    throws IOException, IllegalArgumentException
  {
    StringTokenizer toks = new StringTokenizer(line);
    String addr = toks.nextToken();
    boolean allow = parseAction(toks.nextToken());
     
    // If it starts with a star, it's a slow rule.
   
    if (addr.startsWith("*"))
    {
      SlowFilterEntry sent = new SlowFilterEntry(allow,
             parseProtocols(toks),
             addr);

      entries.addElement(sent);
    } else {
      // It doesn't start with a star; it's a fast rule.  Check for a
      // netmask.

      int slash = addr.indexOf('/');
     
      int[] addrs = null;
      int netmask = 0xffffffff; // if no explicit netmask, require exact match
 
      if (slash != -1)
      {
  addrs = parseAddresses(addr.substring(0, slash));
  netmask = parseNetmask(addr.substring(slash + 1));
      } else {
  addrs = parseAddresses(addr);
      }
 
      int protomask = parseProtocols(toks);

      // We may have obtained multiple addresses from a DNS lookup.
      // Add a rule for each.  Note that most DNS servers will return
      // multiple addresses in different orders on every lookup.

      for (int i = 0; i < addrs.length; i++)
      {
  FastFilterEntry fent = new FastFilterEntry(allow,
               protomask,
               addrs[i],
               netmask);
   
  entries.addElement(fent);
      }
    }
  }
 

  /**
   * Filter a client connection event.  If the connection should be
   * allowed, this method returns normally.
   *
   * @param evt the connection event
   * @exception FilterException the connection should be rejected by
   * the server
   */
  public void accept(ConnectionEvent evt)
    throws FilterException
  {
    InetAddress remoteAddress = evt.getRemoteAddress();
    String protocol = evt.getProtocol().toLowerCase();
    int bit = protocolToMaskBit(protocol);

    if (bit == 0xdeadbeef)
    {
      bit = 0;
    }
   
    // Check rules in the order in which they were written.
   
    for (int i = 0; i < rules.length; i++)
    {
      switch (rules[i].check(remoteAddress, bit))
      {
      case FilterEntry.ALLOW:
  return;
      case FilterEntry.DENY:
  throw new FilterException("rule " + (i + 1));
      case FilterEntry.IGNORE:
  break;
      default:
  throw new RuntimeException("connection filter internal error!");
      }
    }
   
    // If no rule matched, we allow the connection to succeed.
   
    return;
  }


  /**
   * This array is used for quick matching of protocols to bits.  It
   * should only contain protocols that the server supports.
   */
  private static final String[] PROTOCOLS = new String[]
  {
    "http", "t3", "https", "t3s", "giop"
  };

 
  /**
   * Parse a list of protocols and return a bitmask that will let us
   * match a protocol quickly at connect time.
   */
  protected static final int parseProtocols(StringTokenizer toks)
    throws FilterException
  {
    int protomask = 0;
     
    while (toks.hasMoreTokens())
    {
      String tok = toks.nextToken();
      int bit = protocolToMaskBit(tok);

      if (bit == 0xdeadbeef)
      {
  throw new IllegalArgumentException("unknown protocol \"" + tok + "\"");
      }
     
      protomask |= bit;
    }

    return protomask;
  }

 
  /**
   * Parse a single protocol description into a bit in a field.
   */
  private static final int protocolToMaskBit(String proto)
    throws FilterException
  {
    if (proto == null)
    {
      return 0;
    }

    proto = proto.toLowerCase();
   
    for (int i = 1; i < PROTOCOLS.length; i++)
    {
      if (proto.equals(PROTOCOLS[i]))
      {
  return 1 << i;
      }
    }

    // Magic return indicating no match.
   
    return 0xdeadbeef;
  }


  /**
   * Given a string, return an array of IPv4 addresses corresponding
   * to that string as a host.
   *
   * @param str hostname or IPv4 address in string form
   */
  protected static final int[] parseAddresses(String str)
    throws IOException
  {
    InetAddress[] addrs = InetAddress.getAllByName(str);
    int[] raw = new int[addrs.length];

    for (int i = 0; i < addrs.length; i++)
    {
      raw[i] = addressToInt(addrs[i]);
    }
     
    return raw;
  }


  /**
   * Turn an address object into a single IPv4 address.
   */
  static final int addressToInt(InetAddress addr)
  {
    byte[] roh = addr.getAddress();
    int raw = 0;
     
    for (int j = 0; j < roh.length; j++)
    {
      raw |= (0xff & roh[j]) << (8 * (roh.length - j - 1));
    }

    return raw;
  }
 

  /**
   * Return an IPv4 netmask, as derived from a spec string.  The
   * string can either be a number, for a mask length, or a
   * dotted-quad mask.
   *
   * @param maskStr mask spec string
   */
  protected static final int parseNetmask(String maskStr)
    throws IOException
  {
    StringTokenizer toks = new StringTokenizer(maskStr, ".");
    int ntoks = toks.countTokens();

    try
    {
      if (ntoks == 1)
      {
  int bits = Integer.parseInt(toks.nextToken());

  if (bits > 32 || bits < 0)
  {
    throw new StreamCorruptedException("bad netmask: \"" + maskStr + "\"");
  }

  return ~((1 << (32 - bits)) - 1);
      }

      int mask = 0;
   
      if (ntoks != 4)
      {
  throw new StreamCorruptedException("bad netmask: \"" + maskStr + "\"");
      } else {
  for (int i = 24; toks.hasMoreTokens(); i -= 8)
  {
    int num = Integer.parseInt(toks.nextToken());

    if (num < 0 || num > 255)
    {
      throw new StreamCorruptedException("bad netmask: \"" + maskStr + "\"");
    }

    mask |= num << i;
  }
      }

      return mask;
    }
    catch (NumberFormatException e)
    {
      throw new StreamCorruptedException("bad netmask: \"" + maskStr + "\"");
    }
  }


  /**
   * Parse an action and return its meaning.  True to allow, false to
   * deny.
   *
   * @param whatever the action string
   */
  protected static final boolean parseAction(String whatever)
    throws IOException
  {
    String action = whatever.toLowerCase();

    if (action.equals("allow"))
    {
      return true;
    }
    else if (action.equals("deny"))
    {
      return false;
    } else {
      throw new StreamCorruptedException("bad action \"" + action + "\"");
    }
  }
 

  /**
   * Simple test harness.  You can use this to write rules by hand,
   * and then check them.
   */
  public static void main(String[] args)
    throws Exception
  {
    System.out.println("Enter rules on separate lines:");
    ConnectionFilter cf = new SimpleConnectionFilter(System.in);

    LineNumberReader r =
      new LineNumberReader(new InputStreamReader(System.in));

    String line;
   
    System.out.println("Enter addresses on separate lines:");

    while ((line = r.readLine()) != null)
    {
      try
      {
  StringTokenizer toks = new StringTokenizer(line.trim());
  String addr = toks.nextToken();
  String proto = toks.nextToken();
  InetAddress[] addrs = InetAddress.getAllByName(addr);

  for (int i = 0; i < addrs.length; i++)
  {
    try
    {
      cf.accept(new ConnectionEvent(addrs[i], 0, 0, proto));
      System.out.println("ALLOW");
    }
    catch (FilterException e)
    {
      System.out.println("DENY: " + e.getMessage());
    }
  }
      }
      catch (Exception e)
      {
  e.printStackTrace();
      }
    }
  }
}
TOP

Related Classes of examples.security.net.SimpleConnectionFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.