gdamour 2005/03/31 05:29:27
Modified: modules/core/src/java/org/openejb/server
ServiceAccessController.java
SimpleSocketService.java StandardServiceStack.java
StandardServiceStackGBean.java
Log:
GERONIMO-620
o Support IPv6.
o Replace my own lame IP masking with a more IP centric implementation
using some of the xinetd syntax to qualify IP addresses.
Revision Changes Path
1.8 +365 -30
openejb/modules/core/src/java/org/openejb/server/ServiceAccessController.java
Index: ServiceAccessController.java
===================================================================
RCS file:
/home/projects/openejb/scm/openejb/modules/core/src/java/org/openejb/server/ServiceAccessController.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- ServiceAccessController.java 28 Mar 2005 22:50:20 -0000 1.7
+++ ServiceAccessController.java 31 Mar 2005 10:29:26 -0000 1.8
@@ -47,6 +47,7 @@
import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.io.Serializable;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Socket;
@@ -71,13 +72,13 @@
*/
public class ServiceAccessController implements ServerService {
private final ServerService next;
- private IPAddressMask[] allowHosts;
+ private IPAddressPermission[] allowHosts;
public ServiceAccessController(ServerService next) {
this.next = next;
}
- public ServiceAccessController(String name, ServerService next,
IPAddressMask[] ipAddressMasks) {
+ public ServiceAccessController(String name, ServerService next,
IPAddressPermission[] ipAddressMasks) {
this.next = next;
this.allowHosts = ipAddressMasks;
}
@@ -89,11 +90,11 @@
next.service(socket);
}
- public IPAddressMask[] getAllowHosts() {
+ public IPAddressPermission[] getAllowHosts() {
return allowHosts;
}
- public void setAllowHosts(IPAddressMask[] ipAddressMasks) {
+ public void setAllowHosts(IPAddressPermission[] ipAddressMasks) {
this.allowHosts = ipAddressMasks;
}
@@ -121,7 +122,9 @@
InetAddress[] localIps = InetAddress.getAllByName("localhost");
for (int i = 0; i < localIps.length; i++) {
if (localIps[i] instanceof Inet4Address) {
- ipAddressMasksList.add(new
IPAddressMask(localIps[i].getHostAddress()));
+ ipAddressMasksList.add(new
ExactIPAddressPermission(localIps[i].getAddress()));
+ } else {
+ ipAddressMasksList.add(new
ExactIPv6AddressPermission(localIps[i].getAddress()));
}
}
} catch (UnknownHostException e) {
@@ -130,14 +133,14 @@
String ipString = props.getProperty("only_from");
if (ipString != null) {
- StringTokenizer st = new StringTokenizer(ipString, ",");
+ StringTokenizer st = new StringTokenizer(ipString, " ");
while (st.hasMoreTokens()) {
String mask = st.nextToken();
- ipAddressMasksList.add(new IPAddressMask(mask));
+
ipAddressMasksList.add(IPAddressPermissionFactory.getIPAddressMask(mask));
}
}
- allowHosts = (IPAddressMask[]) ipAddressMasksList.toArray(new
IPAddressMask[ipAddressMasksList.size()]);
+ allowHosts = (IPAddressPermission[]) ipAddressMasksList.toArray(new
IPAddressPermission[ipAddressMasksList.size()]);
}
public void init(Properties props) throws Exception {
@@ -165,44 +168,292 @@
return next.getPort();
}
- public static class IPAddressMask implements Serializable {
- private static final Pattern MASK_VALIDATOR =
Pattern.compile("^(\\*|\\d{1,3})\\.(\\*|\\d{1,3})\\.(\\*|\\d{1,3})\\.(\\*|\\d{1,3})$");
+ public interface IPAddressPermission extends Serializable {
+ public boolean implies(InetAddress address);
+ }
+
+ private static class ExactIPAddressPermission implements
IPAddressPermission {
+ private static final Pattern MASK_VALIDATOR =
Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$");
+
+ private static boolean canSupport(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ return matcher.matches();
+ }
- private final String mask;
- private final byte[] byteMask;
- private final boolean[] definedBytes;
+ private final byte[] bytes;
+
+ private ExactIPAddressPermission(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ private ExactIPAddressPermission(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ if (false == matcher.matches()) {
+ throw new IllegalArgumentException("Mask " + mask + " does
not match pattern " + MASK_VALIDATOR.pattern());
+ }
+
+ bytes = new byte[4];
+ for (int i = 0; i < 4; i++) {
+ String group = matcher.group(i + 1);
+ int value = Integer.parseInt(group);
+ if (value < 0 || 255 < value) {
+ throw new IllegalArgumentException("byte #" + i + " is
not valid.");
+ }
+ bytes[i] = (byte) value;
+ }
+ }
- public IPAddressMask(String mask) {
- this.mask = mask;
+ public boolean implies(InetAddress address) {
+ if (false == address instanceof Inet4Address) {
+ return false;
+ }
+ byte[] byteAddress = address.getAddress();
+ for (int i = 0; i < 4; i++) {
+ if (byteAddress[i] != bytes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private static class StartWithIPAddressPermission implements
IPAddressPermission {
+ private static final Pattern MASK_VALIDATOR =
Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.0$");
+
+ private static boolean canSupport(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ return matcher.matches();
+ }
+
+ private final byte[] bytes;
+
+ private StartWithIPAddressPermission(String mask) {
Matcher matcher = MASK_VALIDATOR.matcher(mask);
if (false == matcher.matches()) {
throw new IllegalArgumentException("Mask " + mask + " does
not match pattern " + MASK_VALIDATOR.pattern());
}
- byteMask = new byte[4];
- definedBytes = new boolean[4];
- for (int i = 1; i < 5; i++) {
- String group = matcher.group(i);
- if (false == group.equals("*")) {
+ Byte[] tmpBytes = new Byte[4];
+ boolean isWildCard = false;
+ int size = 0;
+ for (int i = 0; i < 3; i++) {
+ String group = matcher.group(i + 1);
+ if (group.equals("0")) {
+ isWildCard = true;
+ } else if (isWildCard) {
+ throw new IllegalArgumentException("0 at position " +
size + " in mask");
+ } else {
int value = Integer.parseInt(group);
if (value < 0 || 255 < value) {
throw new IllegalArgumentException("byte #" + i + "
is not valid.");
}
- byteMask[i - 1] = (byte) value;
- definedBytes[i - 1] = true;
+ tmpBytes[i] = new Byte((byte) value);
+ size++;
+ }
+ }
+
+ bytes = new byte[size];
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = tmpBytes[i].byteValue();
+ }
+ }
+
+ public boolean implies(InetAddress address) {
+ if (false == address instanceof Inet4Address) {
+ return false;
+ }
+
+ byte[] byteAddress = address.getAddress();
+ for (int i = 0; i < bytes.length; i++) {
+ if (byteAddress[i] != bytes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private static class FactorizedIPAddressPermission implements
IPAddressPermission {
+ private static final Pattern MASK_VALIDATOR =
Pattern.compile("^((\\d{1,3}){1}(\\.\\d{1,3}){0,2}\\.)?\\{(\\d{1,3}){1}((,\\d{1,3})*)\\}$");
+
+ private static boolean canSupport(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ return matcher.matches();
+ }
+
+ private final byte[] prefixBytes;
+ private final byte[] suffixBytes;
+
+ private FactorizedIPAddressPermission(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ if (false == matcher.matches()) {
+ throw new IllegalArgumentException("Mask " + mask + " does
not match pattern " + MASK_VALIDATOR.pattern());
+ }
+
+ // group 1 is the factorized IP part.
+ // e.g. group 1 in "1.2.3.{4,5,6}" is "1.2.3."
+ String prefix = matcher.group(1);
+ StringTokenizer tokenizer = new StringTokenizer(prefix, ".");
+ prefixBytes = new byte[tokenizer.countTokens()];
+ for (int i = 0; i < prefixBytes.length; i++) {
+ String token = tokenizer.nextToken();
+ int value = Integer.parseInt(token);
+ if (value < 0 || 255 < value) {
+ throw new IllegalArgumentException("byte #" + i + " is
not valid.");
}
+ prefixBytes[i] = (byte) value;
}
+
+ // group 5 is a comma separated list of optional suffixes.
+ // e.g. group 5 in "1.2.3.{4,5,6}" is ",5,6"
+ String suffix = matcher.group(5);
+ tokenizer = new StringTokenizer(suffix, ",");
+ suffixBytes = new byte[1 + tokenizer.countTokens()];
+
+ // group 4 is the compulsory and first suffix.
+ // e.g. group 4 in "1.2.3.{4,5,6}" is "4"
+ int value = Integer.parseInt(matcher.group(4));
+ int i = 0;
+ if (value < 0 || 255 < value) {
+ throw new IllegalArgumentException("suffix " + i + " is not
valid.");
+ }
+ suffixBytes[i++] = (byte) value;
+
+ for (; i < suffixBytes.length; i++) {
+ String token = tokenizer.nextToken();
+ value = Integer.parseInt(token);
+ if (value < 0 || 255 < value) {
+ throw new IllegalArgumentException("byte #" + i + " is
not valid.");
+ }
+ suffixBytes[i] = (byte) value;
+ }
+ }
+
+ public boolean implies(InetAddress address) {
+ if (false == address instanceof Inet4Address) {
+ return false;
+ }
+
+ byte[] byteAddress = address.getAddress();
+ for (int i = 0; i < prefixBytes.length; i++) {
+ if (byteAddress[i] != prefixBytes[i]) {
+ return false;
+ }
+ }
+ byte lastByte = byteAddress[prefixBytes.length];
+ for (int i = 0; i < suffixBytes.length; i++) {
+ if (lastByte == suffixBytes[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private static class NetmaskIPAddressPermission implements
IPAddressPermission {
+ private static final Pattern MASK_VALIDATOR =
Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/((\\d{1,2})|(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3}))$");
+
+ private static boolean canSupport(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ return matcher.matches();
}
- public String getMask() {
- return mask;
+ private final byte[] networkAddressBytes;
+ private final byte[] netmaskBytes;
+
+ private NetmaskIPAddressPermission(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ if (false == matcher.matches()) {
+ throw new IllegalArgumentException("Mask " + mask + " does
not match pattern " + MASK_VALIDATOR.pattern());
+ }
+
+ networkAddressBytes = new byte[4];
+ for (int i = 0; i < 4; i++) {
+ String group = matcher.group(i + 1);
+ int value = Integer.parseInt(group);
+ if (value < 0 || 255 < value) {
+ throw new IllegalArgumentException("byte #" + i + " is
not valid.");
+ }
+ networkAddressBytes[i] = (byte) value;
+ }
+
+ netmaskBytes = new byte[4];
+ String netmask = matcher.group(6);
+ if (null != netmask) {
+ int value = Integer.parseInt(netmask);
+ int pos = value / 8;
+ int shift = 8 - value % 8;
+ for (int i = 0; i < pos; i++) {
+ netmaskBytes[i] = (byte) 0xff;
+ }
+ netmaskBytes[pos] = (byte) (0xff << shift);
+ } else {
+ for (int i = 0; i < 4; i++) {
+ String group = matcher.group(i + 7);
+ int value = Integer.parseInt(group);
+ if (value < 0 || 255 < value) {
+ throw new IllegalArgumentException("byte #" + i + "
is not valid.");
+ }
+ netmaskBytes[i] = (byte) value;
+ }
+ }
}
public boolean implies(InetAddress address) {
+ if (false == address instanceof Inet4Address) {
+ return false;
+ }
+
byte[] byteAddress = address.getAddress();
for (int i = 0; i < 4; i++) {
- if (definedBytes[i] && byteAddress[i] != byteMask[i]) {
+ if ((netmaskBytes[i] & byteAddress[i]) !=
networkAddressBytes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private static class ExactIPv6AddressPermission implements
IPAddressPermission {
+ private static final Pattern MASK_VALIDATOR =
Pattern.compile("^(([a-fA-F0-9]{1,4}:){7})([a-fA-F0-9]{1,4})$");
+
+ private static boolean canSupport(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ return matcher.matches();
+ }
+
+ private final byte[] bytes;
+
+ private ExactIPv6AddressPermission(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ private ExactIPv6AddressPermission(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ if (false == matcher.matches()) {
+ throw new IllegalArgumentException("Mask " + mask + " does
not match pattern " + MASK_VALIDATOR.pattern());
+ }
+
+ bytes = new byte[16];
+ int pos = 0;
+ StringTokenizer tokenizer = new StringTokenizer(mask, ":");
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ int value = Integer.parseInt(token, 16);
+ bytes[pos++] = (byte) ((value & 0xff00) >> 8);
+ bytes[pos++] = (byte) value;
+ }
+ }
+
+ public boolean implies(InetAddress address) {
+ if (false == address instanceof Inet6Address) {
+ return false;
+ }
+
+ byte[] byteAddress = address.getAddress();
+ for (int i = 0; i < 16; i++) {
+ if (byteAddress[i] != bytes[i]) {
return false;
}
}
@@ -210,12 +461,96 @@
}
}
- public static class IPAddressMaskEditor extends PropertyEditorSupport {
- private IPAddressMask addressMask;
+ private static class NetmaskIPv6AddressPermission implements
IPAddressPermission {
+ private static final Pattern MASK_VALIDATOR =
Pattern.compile("^(([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4})/((\\d{1,3})|(([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}))$");
+
+ private static boolean canSupport(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ return matcher.matches();
+ }
- public void setAsText(String text) throws IllegalArgumentException {
- addressMask = new IPAddressMask(text);
+ private final byte[] networkAddressBytes;
+ private final byte[] netmaskBytes;
+
+ private NetmaskIPv6AddressPermission(String mask) {
+ Matcher matcher = MASK_VALIDATOR.matcher(mask);
+ if (false == matcher.matches()) {
+ throw new IllegalArgumentException("Mask " + mask + " does
not match pattern " + MASK_VALIDATOR.pattern());
+ }
+
+ networkAddressBytes = new byte[16];
+ int pos = 0;
+ StringTokenizer tokenizer = new
StringTokenizer(matcher.group(1), ":");
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ int value = Integer.parseInt(token, 16);
+ networkAddressBytes[pos++] = (byte) ((value & 0xff00) >> 8);
+ networkAddressBytes[pos++] = (byte) value;
+ }
+
+ netmaskBytes = new byte[16];
+ String netmask = matcher.group(4);
+ if (null != netmask) {
+ int value = Integer.parseInt(netmask);
+ pos = value / 8;
+ int shift = 8 - value % 8;
+ for (int i = 0; i < pos; i++) {
+ netmaskBytes[i] = (byte) 0xff;
+ }
+ netmaskBytes[pos] = (byte) (0xff << shift);
+ } else {
+ pos = 0;
+ tokenizer = new StringTokenizer(matcher.group(5), ":");
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ int value = Integer.parseInt(token, 16);
+ netmaskBytes[pos++] = (byte) ((value & 0xff00) >> 8);
+ netmaskBytes[pos++] = (byte) value;
+ }
+ }
+ }
+
+ public boolean implies(InetAddress address) {
+ if (false == address instanceof Inet6Address) {
+ return false;
+ }
+
+ byte[] byteAddress = address.getAddress();
+ for (int i = 0; i < 16; i++) {
+ if ((netmaskBytes[i] & byteAddress[i]) !=
networkAddressBytes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ public static class IPAddressPermissionFactory {
+
+ public static IPAddressPermission getIPAddressMask(String mask) {
+ if (StartWithIPAddressPermission.canSupport(mask)) {
+ return new StartWithIPAddressPermission(mask);
+ } else if (ExactIPAddressPermission.canSupport(mask)) {
+ return new ExactIPAddressPermission(mask);
+ } else if (FactorizedIPAddressPermission.canSupport(mask)) {
+ return new FactorizedIPAddressPermission(mask);
+ } else if (NetmaskIPAddressPermission.canSupport(mask)) {
+ return new NetmaskIPAddressPermission(mask);
+ } else if (ExactIPv6AddressPermission.canSupport(mask)) {
+ return new ExactIPv6AddressPermission(mask);
+ } else if (NetmaskIPv6AddressPermission.canSupport(mask)) {
+ return new NetmaskIPv6AddressPermission(mask);
+ }
+ throw new IllegalArgumentException("Mask " + mask + " is not
supported.");
}
+ }
+
+ public static class IPAddressPermissionEditor extends
PropertyEditorSupport {
+ private IPAddressPermission addressMask;
+
+ public void setAsText(String text) throws IllegalArgumentException {
+ addressMask = IPAddressPermissionFactory.getIPAddressMask(text);
+ }
public Object getValue() {
return addressMask;
1.16 +2 -2
openejb/modules/core/src/java/org/openejb/server/SimpleSocketService.java
Index: SimpleSocketService.java
===================================================================
RCS file:
/home/projects/openejb/scm/openejb/modules/core/src/java/org/openejb/server/SimpleSocketService.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- SimpleSocketService.java 26 Mar 2005 06:32:06 -0000 1.15
+++ SimpleSocketService.java 31 Mar 2005 10:29:27 -0000 1.16
@@ -69,7 +69,7 @@
private static final Log log =
LogFactory.getLog(SimpleSocketService.class);
private final ServerService server;
- public SimpleSocketService(String serviceClassName,
ServiceAccessController.IPAddressMask[] onlyFrom, ContainerIndex
containerIndex, ClassLoader cl) throws Exception {
+ public SimpleSocketService(String serviceClassName,
ServiceAccessController.IPAddressPermission[] onlyFrom, ContainerIndex
containerIndex, ClassLoader cl) throws Exception {
ServerService service;
Class serviceClass = ClassLoading.loadClass(serviceClassName, cl);
1.6 +4 -4
openejb/modules/core/src/java/org/openejb/server/StandardServiceStack.java
Index: StandardServiceStack.java
===================================================================
RCS file:
/home/projects/openejb/scm/openejb/modules/core/src/java/org/openejb/server/StandardServiceStack.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- StandardServiceStack.java 26 Mar 2005 06:32:06 -0000 1.5
+++ StandardServiceStack.java 31 Mar 2005 10:29:27 -0000 1.6
@@ -62,7 +62,7 @@
private ServicePool pool;
private ServerService server;
- public StandardServiceStack(String name, int port, InetAddress address,
ServiceAccessController.IPAddressMask[] allowHosts, String[] logOnSuccess,
String[] logOnFailure, Executor executor, ServerService server) {
+ public StandardServiceStack(String name, int port, InetAddress address,
ServiceAccessController.IPAddressPermission[] allowHosts, String[]
logOnSuccess, String[] logOnFailure, Executor executor, ServerService server) {
this.server = server;
this.name = name;
this.pool = new ServicePool(server, executor);
@@ -100,11 +100,11 @@
return logger.getLogOnFailure();
}
- public ServiceAccessController.IPAddressMask[] getAllowHosts() {
+ public ServiceAccessController.IPAddressPermission[] getAllowHosts() {
return hba.getAllowHosts();
}
- public void setAllowHosts(ServiceAccessController.IPAddressMask[]
allowHosts) {
+ public void setAllowHosts(ServiceAccessController.IPAddressPermission[]
allowHosts) {
hba.setAllowHosts(allowHosts);
}
1.5 +2 -2
openejb/modules/core/src/java/org/openejb/server/StandardServiceStackGBean.java
Index: StandardServiceStackGBean.java
===================================================================
RCS file:
/home/projects/openejb/scm/openejb/modules/core/src/java/org/openejb/server/StandardServiceStackGBean.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- StandardServiceStackGBean.java 26 Mar 2005 06:32:06 -0000 1.4
+++ StandardServiceStackGBean.java 31 Mar 2005 10:29:27 -0000 1.5
@@ -70,7 +70,7 @@
infoFactory.addAttribute("port", int.class, true);
infoFactory.addAttribute("soTimeout", int.class, true);
infoFactory.addAttribute("address", InetAddress.class, true);
- infoFactory.addAttribute("allowHosts",
ServiceAccessController.IPAddressMask[].class, true);
+ infoFactory.addAttribute("allowHosts",
ServiceAccessController.IPAddressPermission[].class, true);
infoFactory.addAttribute("logOnSuccess", String[].class, true);
infoFactory.addAttribute("logOnFailure", String[].class, true);