From 742d377d978115fa1c38e43c3e5dad8830901e9f Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Thu, 28 Jun 2007 12:12:21 +0000
Subject: [PATCH] Fix ACI IP bind rule behavior to be compatible with DSEE. Issue 461.
---
/dev/null | 140 ------
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PatternIP.java | 458 ++++++++++++++++++++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/IPTestCase.java | 386 +++++++++++++++++
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java | 2
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IP.java | 132 ++++++
opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java | 174 +++++++
6 files changed, 1,148 insertions(+), 144 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
index 502d8b1..5910b65 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
@@ -508,7 +508,7 @@
}
case IP:
{
- rule = IpCriteria.decode(expr, op);
+ rule=IP.decode(expr, op);
break;
}
case DNS:
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IP.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IP.java
new file mode 100644
index 0000000..555a28e
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IP.java
@@ -0,0 +1,132 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.authorization.dseecompat;
+
+import static org.opends.server.messages.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.regex.Pattern;
+import java.util.*;
+import java.net.InetAddress;
+
+/**
+ * This class represents a single ACI's IP bind rule expression. It is possble
+ * for that expression to contain several IP addresses to evaluate, so the
+ * class contains a list of classes that can evaluate a remote clients IP
+ * address for each IP address parsed from the bind rule.
+ */
+public class IP implements KeywordBindRule {
+
+ /*
+ Regular expression used to do a quick check on the characters in a
+ bind rule address. These are all of the valid characters that may
+ appear in an bind rule address part.
+ */
+ private static final String ipRegEx =
+ "((?i)[\\.{1}[a-f]\\d:\\+{1}\\*/{1}\\t\\[{1}\\]{1}]+(?-i))";
+
+ /*
+ List of the pattern classes, one for each address decoded from the
+ bind rule.
+ */
+ private List<PatternIP> patternIPList=null;
+
+ /*
+ The type of the bind rule (!= or =).
+ */
+ private EnumBindRuleType type=null;
+
+ /**
+ * Create a class representing the IP bind rule expressions for this ACI.
+ * @param patternIPList A list of PatternIP objects representing the IP
+ * bind rule expressions decoded from ACI.
+ * @param type An enumeration representing the expression type.
+ */
+ private IP(List<PatternIP> patternIPList, EnumBindRuleType type) {
+ this.patternIPList=patternIPList;
+ this.type=type;
+ }
+
+ /**
+ * Decodes the provided IP bind rule expression string and returns an
+ * IP class the can be used to evaluate remote clients IP addresses.
+ *
+ * @param expr The expression string from the ACI IP bind rule.
+ * @param type An enmumeration representing the expression type.
+ * @return A class that can be used to evaluate remote clients IP
+ * addresses.
+ * @throws AciException If there is a parsing error.
+ */
+ public static KeywordBindRule decode(String expr, EnumBindRuleType type)
+ throws AciException {
+ //Split on the ','.
+ String[] ipStrs=expr.split("\\,", -1);
+ List<PatternIP> patternIPList= new LinkedList<PatternIP>();
+ for (String ipStr : ipStrs) {
+ if (!Pattern.matches(ipRegEx, ipStr)) {
+ int msgID = MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION;
+ String message = getMessage(msgID, expr);
+ throw new AciException(msgID, message);
+ }
+ PatternIP ipPattern = PatternIP.decode(ipStr);
+ patternIPList.add(ipPattern);
+ }
+ return new IP(patternIPList, type);
+ }
+
+ /**
+ * Perform an evaluation using the provided evaluation context's remote
+ * IP address information.
+ *
+ * @param evalCtx An evaluation context containing the remote clients
+ * IP address information.
+ *
+ * @return An enumeration representing if the address matched.
+ */
+ public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+ InetAddress remoteAddr=evalCtx.getRemoteAddress();
+ return evaluate(remoteAddr);
+ }
+
+ /**
+ * Perform an evaluation using the InetAddress.
+ *
+ * @param addr The InetAddress to evaluate against PatternIP classes.
+ * @return An enumeration representing if the address matched one
+ * of the patterns.
+ */
+ EnumEvalResult evaluate(InetAddress addr) {
+ EnumEvalResult matched=EnumEvalResult.FALSE;
+ Iterator<PatternIP> it=patternIPList.iterator();
+ for(; it.hasNext() && matched != EnumEvalResult.TRUE &&
+ matched != EnumEvalResult.ERR;) {
+ PatternIP patternIP=it.next();
+ matched=patternIP.evaluate(addr);
+ }
+ return matched.getRet(type, false);
+ }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpBitsNetworkCriteria.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpBitsNetworkCriteria.java
deleted file mode 100644
index a0c4348..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpBitsNetworkCriteria.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Portions Copyright 2007 Sun Microsystems, Inc.
- */
-
-package org.opends.server.authorization.dseecompat;
-
-import static org.opends.server.messages.AciMessages.*;
-import static org.opends.server.messages.MessageHandler.getMessage;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * This class builds a network string to an internal representation.
- */
-public class IpBitsNetworkCriteria {
-
- byte[] _address; // address in byte format
- int _bits; // number of bits for matching
- byte[] _bitsArray; // bits in network order
- InetAddress _inetAddress;
-
- /**
- * Creates a new IpBitsNeworkCriteria instance.
- *
- * @param theInputAddress IP address associated the rule. For IPV4
- * addresses, the following
- * textual formats are supported
- * a.b.c.d
- * a.b.c
- * a.b
- * a
- * For IPv6 addresses, the following textual
- * format are supported:
- * x:x:x:x:x:x:x:x, where x are the hexadecimal
- * values of the 8
- * 16-bits pieces of the address
- * Use of :: to compress the leading
- * and/or trailing zeros e.g.
- * x::x:x:x:x:x:x
- *
- * @param theBits Number of bits of the network address
- * necessary for matching.
- * Max is 32 for IPv4 addresses and 128
- * for IPv6 addresses \
- *
- * @throws UnknownHostException Thrown if the inetaddress cannot be gotten
- * from the input address string.
- * @throws AciException Thrown if the bit count is not in the correct
- * ranges.
- */
-
- public IpBitsNetworkCriteria(String theInputAddress, int theBits)
- throws UnknownHostException, AciException
- {
- boolean ipv4 = true;
- _inetAddress = InetAddress.getByName(theInputAddress);
-
- if (_inetAddress instanceof Inet6Address)
- {
- if (theBits < 0 || theBits > 128) {
- int msgID = MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH;
- String message = getMessage(msgID, "IPV6",
- "Bits must be in [0..128] range.");
- throw new AciException(msgID, message);
- }
- ipv4=false;
- }
- else
- {
- // Assume IPv4
- if (theBits < 0 || theBits > 32) {
- int msgID = MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH;
- String message = getMessage(msgID, "IPV4",
- "Bits must be in [0..32] range.");
- throw new AciException(msgID, message);
- }
- }
-
- _bits = theBits;
-
- // Convert the bits into a mask in network byte order
- if (ipv4)
- {
- _bitsArray = new byte[4];
- // in java int is exactly 4 bytes
- int rawBits;
- if (theBits==0)
- rawBits=0;
- else
- rawBits=~0;
- rawBits = rawBits << (32 - theBits);
- // Use network order for the comparison
- _bitsArray[0] = (byte) ((rawBits >> 24) & 0xFF );
- _bitsArray[1] = (byte) ((rawBits >> 16) & 0xFF );
- _bitsArray[2] = (byte) ((rawBits >> 8) & 0xFF );
- _bitsArray[3] = (byte) ((rawBits) & 0xFF );
- }
- else
- {
- _bitsArray = new byte[16];
- int index=0;
- if (theBits > 64)
- {
- _bitsArray[0] = (byte) 0xFF;
- _bitsArray[1] = (byte) 0xFF;
- _bitsArray[2] = (byte) 0xFF;
- _bitsArray[3] = (byte) 0xFF;
- _bitsArray[4] = (byte) 0xFF;
- _bitsArray[5] = (byte) 0xFF;
- _bitsArray[6] = (byte) 0xFF;
- _bitsArray[7] = (byte) 0xFF;
- theBits-=64;
- index=8;
- }
- long rawBits = ~0;
- rawBits = rawBits << (64 - theBits);
-
- if (_bits !=0)
- {
- _bitsArray[index++] = (byte) ((rawBits >> 56) & 0xFF );
- _bitsArray[index++] = (byte) ((rawBits >> 48) & 0xFF );
- _bitsArray[index++] = (byte) ((rawBits >> 40) & 0xFF );
- _bitsArray[index++] = (byte) ((rawBits >> 32) & 0xFF );
- _bitsArray[index++] = (byte) ((rawBits >> 24) & 0xFF );
- _bitsArray[index++] = (byte) ((rawBits >> 16) & 0xFF );
- _bitsArray[index++] = (byte) ((rawBits >> 8) & 0xFF );
- _bitsArray[index] = (byte) ((rawBits ) & 0xFF );
- }
- }
-
- _address = _inetAddress.getAddress();
- }
-
- /**
- * Compare an IP address with the network rule.
- *
- * @param theSourceAddress IP source address of the client contacting
- * the proxy server.
- * @return <CODE>true</CODE> if client matches the network rule or
- * <CODE>false</CODE> if they may not.
- */
-
- public boolean match (InetAddress theSourceAddress)
- {
- byte[] addr = theSourceAddress.getAddress();
-
- if ((addr.length * 8) < _bits) {
- // Client IP too small. Won't match.
- return false;
- }
-
- for (int i=0; i<addr.length; i++)
- {
- if ((addr[i] & _bitsArray[i]) != (_address[i] & _bitsArray[i])) {
- return false;
- }
- }
-
- return true;
-
- }
-
- /**
- * String representation of this criteria.
- *
- * @return a String representation of the IpMaskNetworkCriteria
- */
-
- public String toString()
- {
- return "Address:" + _inetAddress.getHostAddress() +
- "/" + Integer.toString(_bits);
- }
-
-}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java
deleted file mode 100644
index 88c5ea3..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Portions Copyright 2007 Sun Microsystems, Inc.
- */
-
-package org.opends.server.authorization.dseecompat;
-
-import static org.opends.server.messages.AciMessages.*;
-import static org.opends.server.authorization.dseecompat.Aci.*;
-import static org.opends.server.messages.MessageHandler.getMessage;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HashSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * This class represents a ip bind rule keyword.
- */
-public class IpCriteria implements KeywordBindRule {
- private EnumBindRuleType type=null;
-
- // private token to express that any address is accepted
- private final static String ANY_ADDRESSES = "ALL";
- private boolean matchAnyAddress = false;
-
- private IpBitsNetworkCriteria[] ipBitsCriteria = null;
- private IpMaskNetworkCriteria[] ipMaskCriteria = null;
-
- private static final String valueRegex =
- "([^," + ZERO_OR_MORE_WHITESPACE + "]+)";
-
- private static final String valuesRegex =
- valueRegex + ZERO_OR_MORE_WHITESPACE + "(," +
- ZERO_OR_MORE_WHITESPACE + valueRegex + ")*";
-
- /*
- * TODO Verifiy IpCriteria constructor adheres to DS 5.2 ip keyword
- * syntax.
- *
- * Based on the contents of the constructor, it doesn't appear that the
- * IpCriteria class uses the same set of allowed values as DS 5.2 does
- * with the "ip" keyword (as documented at
- * http://docs.sun.com/source/817-7613/aci.html#wp20242). Was that the
- * intention? It looks like it doesn't allow asterisks as wild-ccards or
- * plus signs to specify netmasks (although it appears that it expects a
- * slash to be used if you want a netmask). While I don't mind allowing
- * alternate formats (e.g., CIDR-style addresses), we can't drop support
- * for the existing ones if we're trying to maintain compatibility.
- */
- /**
- * Constructor that creates an IpCriteria from an array of values and
- * an enumeration bind rule type.
- * @param values An array of address values.
- * @param type An enumeration of the bind rule type.
- * @throws UnknownHostException If the host address cannot be resolved to
- * a hostname.
- * @throws AciException If a part of the address is invalid.
- * @throws IndexOutOfBoundsException If an index is incremented past an
- * array bounds when copying or evaluating an address.
- */
- public IpCriteria(String[] values, EnumBindRuleType type)
- throws UnknownHostException, IndexOutOfBoundsException, AciException {
- IpBitsNetworkCriteria[] ipBitsCriteria_2 = null;
- IpMaskNetworkCriteria[] ipMaskCriteria_2 = null;
- try
- {
- for (String value : values)
- {
- if (value.equalsIgnoreCase(ANY_ADDRESSES))
- {
- matchAnyAddress = true;
- continue;
- }
- // determine what format it is to instantiate
- // the right criteria object
- int slash = value.indexOf("/");
- if (slash == -1)
- {
- // simple raw IP address
- IpBitsNetworkCriteria newInstance;
- if (InetAddress.getByName(value)
- instanceof Inet6Address)
- {
- newInstance = new IpBitsNetworkCriteria(value, 128);
- } else
- {
- newInstance = new IpBitsNetworkCriteria(value, 32);
- }
- if (ipBitsCriteria_2 == null)
- {
- ipBitsCriteria_2 = new IpBitsNetworkCriteria[1];
- } else
- {
- IpBitsNetworkCriteria[] newIpBitsCriteria =
- new IpBitsNetworkCriteria[ipBitsCriteria_2.length + 1];
- System.arraycopy(ipBitsCriteria_2, 0,
- newIpBitsCriteria, 0, ipBitsCriteria_2.length);
- ipBitsCriteria_2 = newIpBitsCriteria;
- }
- ipBitsCriteria_2[ipBitsCriteria_2.length - 1] = newInstance;
- } else
- {
- // Extract data following the / and figure out whether it
- // is a bit number or a mask
- try
- {
- int bits =
- Integer.parseInt(value.substring(slash + 1));
- // Well, no exception, so this is a bit
- // Let's instantiate the corresponding criterion
- if (ipBitsCriteria_2 == null)
- {
- ipBitsCriteria_2 = new IpBitsNetworkCriteria[1];
- } else
- {
- IpBitsNetworkCriteria[] newIpBitsCriteria =
- new IpBitsNetworkCriteria[ipBitsCriteria_2.length + 1];
- System.arraycopy(ipBitsCriteria_2, 0,
- newIpBitsCriteria, 0, ipBitsCriteria_2.length);
- ipBitsCriteria_2 = newIpBitsCriteria;
- }
- ipBitsCriteria_2[ipBitsCriteria_2.length - 1] =
- new IpBitsNetworkCriteria(value.
- substring(0, slash), bits);
- }
- catch (IndexOutOfBoundsException e1)
- {
- throw e1;
- }
- catch (Exception e2)
- {
- // Looks like this is a network mask.
- if (ipMaskCriteria_2 == null)
- {
- ipMaskCriteria_2 = new IpMaskNetworkCriteria[1];
- } else
- {
- IpMaskNetworkCriteria[] newIpMaskCriteria =
- new IpMaskNetworkCriteria[ipMaskCriteria_2.length + 1];
- System.arraycopy(ipMaskCriteria_2, 0,
- newIpMaskCriteria, 0, ipMaskCriteria_2.length);
- ipMaskCriteria_2 = newIpMaskCriteria;
- }
- try
- {
- ipMaskCriteria_2[ipMaskCriteria_2.length - 1] =
- new IpMaskNetworkCriteria(value.
- substring(0, slash), value.substring(slash + 1));
- }
- catch (IndexOutOfBoundsException e3)
- {
- throw e3;
- }
- }
- }
- }
- }
- catch (UnknownHostException ue)
- {
- throw ue;
- }
- ipBitsCriteria = ipBitsCriteria_2;
- ipMaskCriteria = ipMaskCriteria_2;
- this.type=type;
- }
-
- /**
- * Return the ipBitsNetworkCriteria of this IpCriteria.
- * @return Returns the ipBitsNetworkCriteria.
- */
- public IpBitsNetworkCriteria[] getIpBitsNetworkCriteria() {
- return ipBitsCriteria;
- }
-
- /**
- * Return the ipMaskNetworkCriteria of this IpCriteria.
- * @return Returns the ipMaskNetworkCriteria.
- */
- public IpMaskNetworkCriteria[] getIpMaskNetworkCriteria() {
- return ipMaskCriteria;
- }
-
- /**
- * Compare an IP address with the network rule.
- *
- * @param theSourceAddress IP source address of the client.
- * @return <CODE>true</CODE> if client matches the network rule or
- * <CODE>false</CODE> if they may not.
- */
- public boolean match (InetAddress theSourceAddress)
- {
- if (matchAnyAddress){
- return true;
- }
- if (ipMaskCriteria != null)
- {
- for (IpMaskNetworkCriteria anIpMaskCriteria : ipMaskCriteria)
- {
- if (anIpMaskCriteria.match(theSourceAddress))
- {
- return true;
- }
- }
- }
-
- if (ipBitsCriteria != null)
- {
- for (IpBitsNetworkCriteria anIpBitsCriteria : ipBitsCriteria)
- {
- if (anIpBitsCriteria.match(theSourceAddress))
- {
- return true;
- }
- }
- }
-
- return (ipBitsCriteria == null) && (ipMaskCriteria == null);
- }
-
- /**
- * Decode an expression string representing a ip keyword bind rule
- * expression.
- * @param expr A string representing the expression.
- * @param type An enumeration representing the bind rule type.
- * @return An keyword bind rule that can be used to evaluate the
- * expression.
- * @throws AciException If the expression string is invalid.
- */
- public static KeywordBindRule decode(String expr, EnumBindRuleType type)
- throws AciException {
- if (!Pattern.matches(valuesRegex, expr)) {
- int msgID = MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION;
- String message = getMessage(msgID, expr);
- throw new AciException(msgID, message);
- }
-
- int valuePos = 1;
- Pattern valuePattern = Pattern.compile(valueRegex);
- Matcher valueMatcher = valuePattern.matcher(expr);
- HashSet<String> values = new HashSet<String>();
- while (valueMatcher.find()) {
- String value = valueMatcher.group(valuePos);
- values.add(value);
- }
- IpCriteria ipCriteria;
- String[] strValues = null;
- if (!values.isEmpty()) {
- strValues = values.toArray(new String[values.size()]);
- }
- try {
- ipCriteria = new IpCriteria(strValues, type);
- } catch (Exception e) {
- int msgID = MSGID_ACI_SYNTAX_INVALID_IP_CRITERIA_DECODE;
- String message = getMessage(msgID, e.getMessage());
- throw new AciException(msgID, message);
- }
- return ipCriteria;
- }
-
- /**
- * Evaluate the evaluation context against this ip criteria.
- * @param evalCtx An evaluation context to use.
- * @return An enumeration evaluation result.
- */
- public EnumEvalResult evaluate(AciEvalContext evalCtx) {
- EnumEvalResult matched=EnumEvalResult.FALSE;
- if(match(evalCtx.getRemoteAddress()))
- matched=EnumEvalResult.TRUE;
- return matched.getRet(type, false);
- }
-}
-
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpMaskNetworkCriteria.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpMaskNetworkCriteria.java
deleted file mode 100644
index 4c4c5d0..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpMaskNetworkCriteria.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Portions Copyright 2007 Sun Microsystems, Inc.
- */
-
-package org.opends.server.authorization.dseecompat;
-
-import static org.opends.server.messages.AciMessages.*;
-import static org.opends.server.messages.MessageHandler.getMessage;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * This class creates a network mask criteria from the address and mask
- * string passed to it.
- */
-class IpMaskNetworkCriteria
-{
-
- byte[] _address; // address in byte format
- byte[] _mask; // mask in byte format
- InetAddress _inetAddress;
- InetAddress _inetMask;
- boolean _ipv4; // true if ipv4 address
-
-
- /**
- * Creates a new IpMaskNeworkCriteria instance.
- *
- * @param theInputAddress IP address associated the rule. For IPV4
- * addresses, the following
- * textual formats are supported
- * a.b.c.d
- * a.b.c
- * a.b
- * a
- * For IPv6 addresses, the following textual
- * format are supported:
- * x:x:x:x:x:x:x:x, where x are the hexadecimal
- * values of the 8 16-bits pieces of the address
- * Use of :: to compress the leading and/or
- * trailing zeros e.g.x::x:x:x:x:x:x
- *
- * @param theInputMask Bits of the network address necessary
- * for matching.
- * Same format as the IP address above.
- *
- * @throws UnknownHostException Thrown if the hostname of the input address
- * cannot be resolved.
- * @throws AciException If the address family has a mismatch.
- */
-
- public IpMaskNetworkCriteria(String theInputAddress, String theInputMask)
- throws UnknownHostException, AciException {
- _inetAddress = InetAddress.getByName(theInputAddress);
- _inetMask = InetAddress.getByName(theInputMask);
- _address = _inetAddress.getAddress();
- _mask = _inetMask.getAddress();
-
- if (_inetAddress instanceof Inet4Address)
- _ipv4=true;
-
- if (_ipv4 && !(_inetMask instanceof Inet4Address) ||
- (!_ipv4 && !(_inetMask instanceof Inet6Address))) {
- int msgID = MSGID_ACI_SYNTAX_ADDRESS_FAMILY_MISMATCH;
- String message = getMessage(msgID, theInputMask, theInputAddress);
- throw new AciException(msgID, message);
- }
- }
-
- /**
- * Compare an IP address with the network criteria.
- *
- * @param theSourceAddress IP source address of the client.
- * @return <CODE>true</CODE> if client matches the network rule or
- * <CODE>false</CODE> if they may not.
- */
-
- public boolean match (InetAddress theSourceAddress)
- {
- // First address family must match
- if (_ipv4)
- {
- if (!(theSourceAddress instanceof Inet4Address))
- return false;
- }
- else
- {
- if (!(theSourceAddress instanceof Inet6Address))
- return false;
- }
-
- byte[] addr = theSourceAddress.getAddress();
- for (int i=0; i<addr.length; i++) {
- if ((addr[i] & _mask[i]) != (_address[i] & _mask[i])) {
- return false;
- }
- }
- return true;
-
- }
-
- /**
- * String representation of this rule.
- *
- * @return a String representation of the IpMaskNetworkRule.
- */
-
- public String toString()
- {
- return "Address:" + _inetAddress.getHostAddress() +
- " Mask:" + _inetMask.getHostAddress();
- }
-}
-
-
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PatternIP.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PatternIP.java
new file mode 100644
index 0000000..e56cc77
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PatternIP.java
@@ -0,0 +1,458 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+
+package org.opends.server.authorization.dseecompat;
+
+import static org.opends.server.messages.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.net.Inet6Address;
+
+/**
+ * A class representing a single IP address parsed from a IP bind rule
+ * expression. The class can be used to evaluate a remote clients IP address
+ * using the information parsed from the IP bind rule expression.
+ */
+public class PatternIP {
+
+ /**
+ * Enumeration that represents if the pattern is IPv5 or
+ * IPv4.
+ */
+ enum IPType {
+ IPv4, IPv6
+ }
+
+ /*
+ The IP address type (v6 or v4).
+ */
+ private IPType ipType;
+
+ /*
+ IPv4 sizes of addresses and prefixes.
+ */
+ private static int IN4ADDRSZ = 4;
+ private static int IPV4MAXPREFIX = 32;
+
+ /*
+ IPv6 sizes of addresses and prefixes.
+ */
+ private static int IN6ADDRSZ = 16;
+ private static int IPV6MAXPREFIX = 128;
+
+ /*
+ Byte arrays used to match the remote IP address. The ruleAddrByte array
+ contains the bytes of the address from the ACI IP bind rule. The
+ rulePrefixBytes array contains the bytes of the cidr prefix or netmask
+ representation.
+ */
+ private byte[] ruleAddrBytes, rulePrefixBytes;
+
+ /*
+ Bit set that holds the wild-card information of processed IPv4 addresses.
+ */
+ private BitSet wildCardBitSet;
+
+ /*
+ Hash map of valid netmask strings. Used in parsing netmask values.
+ */
+ private static HashMap<String,String> validNetMasks =
+ new HashMap<String, String>();
+
+ /*
+ Initialize valid netmask hash map.
+ */
+ static {
+ initNetMask(
+ "255.255.255.255",
+ "255.255.255.254",
+ "255.255.255.252",
+ "255.255.255.248",
+ "255.255.255.240",
+ "255.255.255.224",
+ "255.255.255.192",
+ "255.255.255.128",
+ "255.255.255.0",
+ "255.255.254.0",
+ "255.255.252.0",
+ "255.255.248.0",
+ "255.255.240.0",
+ "255.255.224.0",
+ "255.255.192.0",
+ "255.255.128.0",
+ "255.255.0.0",
+ "255.254.0.0",
+ "255.252.0.0",
+ "255.248.0.0",
+ "255.240.0.0",
+ "255.224.0.0",
+ "255.192.0.0",
+ "255.128.0.0",
+ "255.0.0.0",
+ "254.0.0.0",
+ "252.0.0.0",
+ "248.0.0.0",
+ "240.0.0.0",
+ "224.0.0.0",
+ "192.0.0.0",
+ "128.0.0.0",
+ "0.0.0.0"
+ );
+ }
+
+ /**
+ * Load the valid netmask hash map with the 33 possible valid netmask
+ * strings.
+ *
+ * @param lines The strings representing the valid netmasks.
+ */
+ private static void initNetMask(String... lines) {
+ for(String line : lines) {
+ validNetMasks.put(line, line);
+ }
+ }
+
+ /**
+ * Create a class that can be used to evaluate an IP address using the
+ * information decoded from the ACI IP bind rule expression.
+ *
+ * @param ipType The type of the ACI IP address (IPv4 or 6).
+ * @param ruleAddrBytes Byte array representing the ACI IP address.
+ * @param rulePrefixBytes Prefix byte array corresponding to the bits set
+ * by the cidr prefix or netmask.
+ * @param wildCardBitSet Bit set holding IPv4 wild-card information.
+ */
+ private PatternIP(IPType ipType, byte[] ruleAddrBytes,
+ byte[] rulePrefixBytes, BitSet wildCardBitSet) {
+ this.ipType=ipType;
+ this.ruleAddrBytes=ruleAddrBytes;
+ this.rulePrefixBytes=rulePrefixBytes;
+ this.wildCardBitSet=wildCardBitSet;
+ }
+
+ /**
+ * Decode the provided address expression string and create a class that
+ * can be used to perform an evaluation of an IP address based on the
+ * decoded expression string information.
+ *
+ * @param expr The address expression string from the ACI IP bind rule.
+ * @return A class that can evaluate a remote clients IP address using the
+ * expression's information.
+ * @throws AciException If the address expression is invalid.
+ */
+ public static
+ PatternIP decode(String expr) throws AciException {
+ IPType ipType=IPType.IPv4;
+ byte[] prefixBytes;
+ String addrStr;
+ if(expr.indexOf(':') != -1)
+ ipType = IPType.IPv6;
+ if(expr.indexOf('/') != -1) {
+ String prefixStr=null;
+ String[] s = expr.split("[/]", -1);
+ if(s.length == 2) prefixStr=s[1];
+ int prefix = getPrefixValue(ipType, s.length, expr, prefixStr);
+ prefixBytes=getPrefixBytes(prefix, ipType);
+ addrStr=s[0];
+ } else if(expr.indexOf('+') != -1) {
+ String netMaskStr=null;
+ String[] s = expr.split("[+]", -1);
+ if(s.length == 2)
+ netMaskStr=s[1];
+ prefixBytes=getNetmaskBytes(netMaskStr, s.length, expr);
+ addrStr=s[0];
+ } else {
+ int prefix = getPrefixValue(ipType, 1, expr, null);
+ prefixBytes=getPrefixBytes(prefix, ipType);
+ addrStr=expr;
+ }
+ //Set the bit set size fo IN6ADDRSZ even though only 4 positions are
+ //used.
+ BitSet wildCardBitSet = new BitSet(IN6ADDRSZ);
+ byte[] addrBytes;
+ if(ipType == IPType.IPv4)
+ addrBytes = procIPv4Addr(addrStr, wildCardBitSet, expr);
+ else {
+ addrBytes=procIPv6Addr(addrStr, expr);
+ //The IPv6 address processed above might be a IPv4-compatible
+ //address, in which case only 4 bytes will be returned in the
+ //address byte array. Ignore any IPv6 prefix.
+ if(addrBytes.length == IN4ADDRSZ) {
+ ipType=IPType.IPv4;
+ prefixBytes=getPrefixBytes(IPV4MAXPREFIX, ipType);
+ }
+ }
+ return new PatternIP(ipType, addrBytes, prefixBytes, wildCardBitSet);
+ }
+
+ /**
+ * Process the IP address prefix part of the expression. Handles if there is
+ * no prefix in the expression.
+ *
+ * @param ipType The type of the expression, either IPv6 or IPv4.
+ * @param numParts The number of parts in the IP address expression.
+ * 1 if there isn't a prefix, and 2 if there is. Anything
+ * else is an error (i.e., 254.244.123.234/7/6).
+ * @param expr The original expression from the bind rule.
+ * @param prefixStr The string representation of the prefix part of the
+ * IP address.
+ * @return An integer value determined from the prefix string.
+ * @throws AciException If the prefix string is invalid.
+ */
+ private static int
+ getPrefixValue(IPType ipType, int numParts, String expr, String prefixStr)
+ throws AciException {
+
+ int prefix = IPV4MAXPREFIX;
+ int maxPrefix= IPV4MAXPREFIX;
+ if(ipType == IPType.IPv6) {
+ prefix= IPV6MAXPREFIX;
+ maxPrefix=IPV6MAXPREFIX;
+ }
+ try {
+ //Can only have one prefix value and one address string.
+ if((numParts < 1) || (numParts > 2) ) {
+ int msgID = MSGID_ACI_SYNTAX_INVALID_PREFIX_FORMAT;
+ String message = getMessage(msgID, expr);
+ throw new AciException(msgID, message);
+ }
+ if(prefixStr != null)
+ prefix = Integer.parseInt(prefixStr);
+ //Must be between 0 to maxprefix.
+ if((prefix < 0) || (prefix > maxPrefix)) {
+ int msgID=MSGID_ACI_SYNTAX_INVALID_PREFIX_VALUE;
+ String message = getMessage(msgID, expr);
+ throw new AciException(msgID, message);
+ }
+ } catch(NumberFormatException nfex) {
+ int msgID=MSGID_ACI_SYNTAX_PREFIX_NOT_NUMERIC;
+ String msg = getMessage(msgID, expr);
+ throw new AciException(msgID,msg);
+ }
+ return prefix;
+ }
+
+ /**
+ * Determine the prefix bit mask based on the provided prefix value. Handles
+ * both IPv4 and IPv6 prefix values.
+ *
+ * @param prefix The value of the prefix parsed from the address
+ * expression.
+ * @param ipType The type of the prefix, either IPv6 or IPv4.
+ * @return A byte array representing the prefix bit mask used to match
+ * IP addresses.
+ */
+ private static byte[] getPrefixBytes(int prefix, IPType ipType) {
+ int i;
+ int maxSize=IN4ADDRSZ;
+ if(ipType==IPType.IPv6)
+ maxSize= IN6ADDRSZ;
+ byte[] prefixBytes=new byte[maxSize];
+ for(i=0;prefix > 8 ; i++) {
+ prefixBytes[i] = (byte) 0xff;
+ prefix -= 8;
+ }
+ prefixBytes[i] = (byte) ((0xff) << (8 - prefix));
+ return prefixBytes;
+ }
+
+ /**
+ * Process the specified netmask string. Only pertains to IPv4 address
+ * expressions.
+ *
+ * @param netmaskStr String represntation of the netmask parsed from the
+ * address expression.
+ * @param numParts The number of parts in the IP address expression.
+ * 1 if there isn't a netmask, and 2 if there is. Anything
+ * else is an error (i.e., 254.244.123.234++255.255.255.0).
+ * @param expr The original expression from the bind rule.
+ * @return A byte array representing the netmask bit mask used to match
+ * IP addresses.
+ * @throws AciException If the netmask string is invalid.
+ */
+ private static
+ byte[] getNetmaskBytes(String netmaskStr, int numParts, String expr)
+ throws AciException {
+ byte[] netmaskBytes=new byte[IN4ADDRSZ];
+ //Look up the string in the valid netmask hash table. If it isn't
+ //there it is an error.
+ if(!validNetMasks.containsKey(netmaskStr)) {
+ int id=MSGID_ACI_SYNTAX_INVALID_NETMASK;
+ String message = getMessage(id, expr);
+ throw new AciException(id, message);
+ }
+ //Can only have one netmask value and one address string.
+ if((numParts < 1) || (numParts > 2) ) {
+ int msgID = MSGID_ACI_SYNTAX_INVALID_NETMASK_FORMAT;
+ String message = getMessage(msgID, expr);
+ throw new AciException(msgID, message);
+ }
+ String[] s = netmaskStr.split("\\.", -1);
+ try {
+ for(int i=0; i < IN4ADDRSZ; i++) {
+ String quad=s[i].trim();
+ long val=Integer.parseInt(quad);
+ netmaskBytes[i] = (byte) (val & 0xff);
+ }
+ } catch (NumberFormatException nfex) {
+ int id=MSGID_ACI_SYNTAX_IPV4_NOT_NUMERIC;
+ String message = getMessage(id, expr);
+ throw new AciException(id, message);
+ }
+ return netmaskBytes;
+ }
+
+ /**
+ * Process the provided IPv4 address string parsed from the IP bind rule
+ * address expression. It returns a byte array corresponding to the
+ * address string. The specified bit set represents wild-card characters
+ * '*' found in the string.
+ *
+ * @param addrStr A string representing an IPv4 address.
+ * @param wildCardBitSet A bit set used to save wild-card information.
+ * @param expr The original expression from the IP bind rule.
+ * @return A address byte array that can be used along with the prefix bit
+ * mask to evaluate an IPv4 address.
+ *
+ * @throws AciException If the address string is not a valid IPv4 address
+ * string.
+ */
+ private static byte[]
+ procIPv4Addr(String addrStr, BitSet wildCardBitSet, String expr)
+ throws AciException {
+ byte[] addrBytes=new byte[IN4ADDRSZ];
+ String[] s = addrStr.split("\\.", -1);
+ try {
+ if(s.length != IN4ADDRSZ) {
+ int id=MSGID_ACI_SYNTAX_INVALID_IPV4_FORMAT;
+ String message = getMessage(id, expr);
+ throw new AciException(id, message);
+ }
+ for(int i=0; i < IN4ADDRSZ; i++) {
+ String quad=s[i].trim();
+ if(quad.equals("*"))
+ wildCardBitSet.set(i) ;
+ else {
+ long val=Integer.parseInt(quad);
+ //must be between 0-255
+ if((val < 0) || (val > 0xff)) {
+ int id=MSGID_ACI_SYNTAX_INVALID_IPV4_VALUE;
+ String message = getMessage(id, expr);
+ throw new AciException(id, message);
+ }
+ addrBytes[i] = (byte) (val & 0xff);
+ }
+ }
+ } catch (NumberFormatException nfex) {
+ int id=MSGID_ACI_SYNTAX_IPV4_NOT_NUMERIC;
+ String message = getMessage(id, expr);
+ throw new AciException(id, message);
+ }
+ return addrBytes;
+ }
+
+ /**
+ * Process the provided IPv6 address string parsed from the IP bind rule
+ * IP expression. It returns a byte array corresponding to the
+ * address string. Wild-cards are not allowed in IPv6 addresses.
+ *
+ * @param addrStr A string representing an IPv6 address.
+ * @param expr The original expression from the IP bind rule.
+ * @return A address byte array that can be used along with the prefix bit
+ * mask to evaluate an IPv6 address.
+ * @throws AciException If the address string is not a valid IPv6 address
+ * string.
+ */
+ private static byte[]
+ procIPv6Addr(String addrStr, String expr) throws AciException {
+ if(addrStr.indexOf('*') > -1) {
+ int msgID=MSGID_ACI_SYNTAX_IPV6_WILDCARD_INVALID;
+ String message = getMessage(msgID, expr);
+ throw new AciException(msgID, message);
+ }
+ byte[] addrBytes;
+ try {
+ addrBytes=InetAddress.getByName(addrStr).getAddress();
+ } catch (UnknownHostException ex) {
+ int id=MSGID_ACI_SYNTAX_INVALID_IPV6_FORMAT;
+ String message = getMessage(id, expr, ex.getMessage());
+ throw new AciException(id, message);
+ }
+ return addrBytes;
+ }
+
+ /**
+ * Evaluate the provided IP address against the information processed during
+ * the IP bind rule expression decode.
+ *
+ * @param remoteAddr A IP address to evaluate.
+ * @return An enumeration representing the result of the evaluation.
+ */
+ public EnumEvalResult evaluate(InetAddress remoteAddr) {
+ EnumEvalResult matched=EnumEvalResult.FALSE;
+ IPType ipType=IPType.IPv4;
+ byte[] addressBytes=remoteAddr.getAddress();
+ if(remoteAddr instanceof Inet6Address) {
+ ipType=IPType.IPv6;
+ Inet6Address addr6 = (Inet6Address) remoteAddr;
+ addressBytes= addr6.getAddress();
+ if(addr6.isIPv4CompatibleAddress())
+ ipType=IPType.IPv4;
+ }
+ if(ipType != this.ipType)
+ return EnumEvalResult.FALSE;
+ if(matchAddress(addressBytes))
+ matched=EnumEvalResult.TRUE;
+ return matched;
+ }
+
+ /**
+ * Attempt to match the address byte array using the prefix bit mask array
+ * and the address byte array processed in the decode. Wild-cards take
+ * priority over the mask.
+ *
+ * @param addrBytes IP address byte array.
+ * @return True if the remote address matches based on the information
+ * parsed from the IP bind rule expression.
+ */
+ private boolean matchAddress(byte[] addrBytes) {
+ if(wildCardBitSet.cardinality() == IN4ADDRSZ)
+ return true;
+ for(int i=0;i <rulePrefixBytes.length; i++) {
+ if(!wildCardBitSet.get(i)) {
+ if((ruleAddrBytes[i] & rulePrefixBytes[i]) !=
+ (addrBytes[i] & rulePrefixBytes[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
index 1b366b6..08a595c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
@@ -807,6 +807,113 @@
CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 80;
/**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field had an invalid
+ * prefix format. This takes one argument, which is the IP field from the
+ * bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_INVALID_PREFIX_FORMAT =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 81;
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field had an invalid
+ * prefix value. This takes one argument, which is the IP field from the
+ * bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_INVALID_PREFIX_VALUE =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 82;
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field has an
+ * prefix value that is not numeric. This takes one argument, which is
+ * the IP field from the bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_PREFIX_NOT_NUMERIC =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 83;
+
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field IPv4 address has an
+ * invalid format. This takes one argument, which is
+ * the IP field from the bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_INVALID_IPV4_FORMAT =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 84;
+
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field IPv4 address has an
+ * invalid value. This takes one argument, which is
+ * the IP field from the bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_INVALID_IPV4_VALUE =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 85;
+
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field IPv4 address has an
+ * non-numeric value. This takes one argument, which is
+ * the IP field from the bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_IPV4_NOT_NUMERIC =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 86;
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field IPv6 address
+ * contains a wildcard character '*'. This takes one argument, which is
+ * the IP field from the bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_IPV6_WILDCARD_INVALID =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 87;
+
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field IPv6 address
+ * has an invalid format. This takes otwo arguments, which are
+ * the IP field from the bind rule expression and the message from the
+ * IPv6 parsing method.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_INVALID_IPV6_FORMAT =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 88;
+
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field had an invalid
+ * netmask format. This takes one argument, which is the IP field from the
+ * bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_INVALID_NETMASK_FORMAT =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 89;
+
+
+ /**
+ * The message ID for the message that will be used if an "aci" attribute
+ * type value parse fails beacause a bind rule IP field had an invalid
+ * netmask value. This takes one argument, which is the IP field from the
+ * bind rule expression.
+ */
+
+ public static final int MSGID_ACI_SYNTAX_INVALID_NETMASK =
+ CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 89;
+
+ /**
* Associates a set of generic messages with the message IDs defined in
* this class.
*/
@@ -926,8 +1033,9 @@
registerMessage(MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION,
"The provided Access Control Instruction (ACI) bind rule " +
"ip expression value \"%s\" is invalid. A valid ip " +
- "keyword expression value requires one or more" +
- "comma-separated elements of an IP address list expression");
+ "keyword expression requires one or more " +
+ "comma-separated elements of a valid IP address list" +
+ " expression");
registerMessage(MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION,
"The provided Access Control Instruction (ACI) bind rule " +
@@ -935,7 +1043,6 @@
"keyword expression value requires a valid fully qualified"+
" DNS domain name");
-
registerMessage(MSGID_ACI_SYNTAX_INVALID_DNS_WILDCARD,
"The provided Access Control Instruction (ACI) bind rule " +
"dns expression value \"%s\" is invalid, because a wild-card" +
@@ -1267,5 +1374,66 @@
"userattr expression value failed to parse because the " +
"attribute field of the ldap URL \"%s\" either contains more " +
"than one description or the field is empty");
+
+ registerMessage(MSGID_ACI_SYNTAX_INVALID_PREFIX_FORMAT,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "prefix part of the expression \"%s\" has an invalid format");
+
+ registerMessage(MSGID_ACI_SYNTAX_INVALID_PREFIX_VALUE,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "prefix value of the expression \"%s\" was an invalid" +
+ " value. All values must greater than or equal to 0 and " +
+ "either less than or equal 32 for IPV4 addresses or less than" +
+ " or equal to 128 for IPV6 addresses");
+
+ registerMessage(MSGID_ACI_SYNTAX_PREFIX_NOT_NUMERIC,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "prefix part of the expression \"%s\" has an non-numeric" +
+ " value");
+
+ registerMessage(MSGID_ACI_SYNTAX_INVALID_IPV4_FORMAT,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "the IPv4 address expression \"%s\" format was invalid");
+
+ registerMessage(MSGID_ACI_SYNTAX_INVALID_IPV4_VALUE,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ " IPv4 address expression \"%s\" contains an invalid value." +
+ "All values of the address must be between 0 and 255");
+
+ registerMessage(MSGID_ACI_SYNTAX_IPV4_NOT_NUMERIC,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "the IPv4 address expression \"%s\" contains a non-numeric" +
+ " value");
+
+ registerMessage(MSGID_ACI_SYNTAX_IPV6_WILDCARD_INVALID,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "the IPv6 address expression \"%s\" contains an illegal" +
+ " wildcard character. Wildcards are not supported when " +
+ "using IPv6 addresses in a IP bind rule expression");
+
+ registerMessage(MSGID_ACI_SYNTAX_INVALID_IPV6_FORMAT,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression \"%s\" failed to parse for the " +
+ "following reason: \"%s\"");
+
+
+ registerMessage(MSGID_ACI_SYNTAX_INVALID_NETMASK_FORMAT,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "netmask part of the expression \"%s\" has an invalid format");
+
+
+ registerMessage(MSGID_ACI_SYNTAX_INVALID_NETMASK_FORMAT,
+ "The provided Access Control Instruction (ACI) bind rule " +
+ "IP address expression failed to parse because the " +
+ "netmask part of the expression \"%s\" has an invalid value");
+
}
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/IPTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/IPTestCase.java
new file mode 100644
index 0000000..0f802cd
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/IPTestCase.java
@@ -0,0 +1,386 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+
+package org.opends.server.authorization.dseecompat;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import java.net.InetAddress;
+
+/**
+ * Test of IP bind rule address decoding and address matching.
+ */
+public class IPTestCase extends AciTestCase {
+
+ //Various patterns and addresses that can be put in IP bind rule
+ //expressions. For example: ip="72.*.78.*,*.*.*.*".
+
+ private String ipExpr="72.56.78.9,127.0.0.1";
+ private String ipExprWc="72.*.78.*,*.*.*.*";
+ private String netmaskWc=
+ "72.56.78.0+255.255.255.240,127.0.0.0+255.255.255.0";
+ private String netmaskWcOverRide=
+ "72.*.78.*+255.255.255.248,*.0.0.0+192.0.0.0";
+ private String ip6Expr="12AB:0000:0000:CD30:0000:0000:0000:0000";
+ private String ip6ExprC="12ab:0:0:cd30::";
+ private String ip6ExprCidr="12ab:0:0:cd30::/60";
+ private String ip6ExprCidrB="[12ab:0:0:cd30::]/60";
+ private String ip4compat="::ffff:127.0.0.1,::ffff:72.56.78.9";
+ private String cidr=
+ "72.56.78.0/28,127.0.0.0/24";
+ private String cidrWc=
+ "72.*.78.*/29,*.0.0.0/7";
+ private String
+ mixed="::ffff:72.56.78.9,45.*.33.*,[12ab:0:0:cd30::]/60," +
+ "56.56.78.0+255.255.255.0";
+
+ //Providers that test the above expressions.
+ //Mix of Ipv6 and Ipv4 addresses.
+ @DataProvider(name = "mixedMatches")
+ public Object[][] mixedData() {
+ return new Object[][] {
+ {"12AB:0000:0000:CD30:0000:0000:0000:0000"},
+ {"12ab:0:0:cd3f:0000:0000:23DC:DC30"},
+ {"45.56.33.9"},
+ {"72.56.78.9"},
+ {"56.56.78.9"}
+
+ };
+ }
+ //Ipv6 addresses in long and various compressed forms.
+ @DataProvider(name = "v6Matches")
+ public Object[][] v6MatchData() {
+ return new Object[][] {
+ {"12AB:0000:0000:CD30:0000:0000:0000:0000"},
+ {"12AB::CD30:0:0:0:0"},
+ {"12ab:0:0:cd30::"}
+ };
+ }
+
+ //Ipv6 addresses used in cidr tests.
+ @DataProvider(name = "v6Matches1")
+ public Object[][] v6MatchData1() {
+ return new Object[][] {
+ {"12ab:0:0:cd3f:0000:0000:23DC:DC30"},
+ {"12ab::cd3f:0:0:23dc:dc30"}
+ };
+ }
+
+ //Ipv4 addresses.
+ @DataProvider(name = "v4Matches")
+ public Object[][] v4MatchData() {
+ return new Object[][] {
+ {"127.0.0.1"},
+ {"72.56.78.9"}
+ };
+ }
+
+ //Valid IPv4 expressions.
+ @DataProvider(name = "validRules")
+ public Object[][] validData() {
+ return new Object[][] {
+ { "129.34.55.67/0"},
+ { "129.*.78.55+255.255.248.0"},
+ {"128.*.*.*"},
+ {"129.45.23.67/22"},
+ {"128.33.23.*/32"},
+ {"*.*.*.*"},
+ {"129.45.67.34/0"},
+ {"129.45.67.34+255.255.255.0"}
+ };
+ }
+
+ //Valid IPv6 expressions.
+ @DataProvider(name = "valid6Rules")
+ public Object[][] valid6Data() {
+ return new Object[][] {
+ {"2001:fecd:ba23:cd1f:dcb1:1010:9234:4088/124"},
+ {"2001:fecd:ba23:cd1f:dcb1:1010:9234:4088"},
+ {"[2001:fecd:ba23:cd1f:dcb1:1010:9234:4088]/45"},
+ {"::/128"},
+ {"::1/128"},
+ {"::"},
+ {"0:0:0:0:0:ffff:101.45.75.219"},
+ {"1080::8:800:200C:417A"},
+ {"0:0:0:0:0:0:101.45.75.219"},
+ {"::101.45.75.219"}
+ };
+ }
+
+ //Invalid Ipv4 expressions.
+ @DataProvider(name = "invalidRules")
+ public Object[][] inValidData() {
+ return new Object[][] {
+ {"128.33.23.xx"},
+ {"128.33.23.22++"},
+ {"128.33.23.22+"},
+ {"128.33.23.22+56"},
+ {"128.33.23.22+255.255.45"},
+ {"128.33.23.22+255.255.45.45"},//netmask is invalid
+ {"128.33.23.22/-1"},
+ {"128..33.23"},
+ {"128.33.23.66.88"},
+ {"128.33.600.66"},
+ {"128.33.9.66/33"},
+ {"."},
+ {"foo"}
+ };
+ }
+
+ //Invalid IPv6 expressions.
+ @DataProvider(name = "invalid6Rules")
+ public Object[][] inValid5Data() {
+ return new Object[][] {
+ {"2001:feca:ba23:cd1f:dcb1:1010:9234:4088///124"},
+ {"2001:feca:ba23:cd1f:dcb1:1010:9234:4088?124"},
+ {"2001:fecz:ba23:cd1f:dcb1:1010:9234:4088/124"},
+ {"2001:fecd:ba23:cd1ff:dcb1:1010:9234:4088/46"},
+ {"0:0:0:0:0:ffff:101..45.75.219"},
+ {"0:0:0:0:0:0:101.45.75.700"},
+ {"1080::8:800:200C:417A/500"},
+ {"1080::8:800:*:417A/66"},
+ };
+ }
+
+ /**
+ * This test uses the mixed (ipv4 and 6) expression above to match against
+ * ipv4 and 6 addresses. All addresses should pass.
+ *
+ * @param ipStr The string to convert into InetAddress.
+ * @throws Exception If the evaluation doesn't return true.
+ */
+ @Test(dataProvider="mixedMatches")
+ public void testMixed(String ipStr) throws Exception {
+ IP ip=(IP) IP.decode(mixed, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ InetAddress addr=InetAddress.getByName(ipStr);
+ EnumEvalResult res=ip.evaluate(addr);
+ if(res != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + mixed);
+ }
+
+
+ /**
+ * Test Ipv6 Ipv4 compat expression. All addresses should pass.
+ *
+ * @param ipStr The string to convert into IPv4 InetAddress.
+ * @throws Exception If the evaluation doesn't return true.
+ */
+ @Test(dataProvider = "v4Matches")
+ public void test4compat(String ipStr) throws Exception {
+ IP ip=(IP) IP.decode(ip4compat, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ InetAddress addr=InetAddress.getByName(ipStr);
+ EnumEvalResult res=ip.evaluate(addr);
+ if(res != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + ip4compat);
+ }
+
+ /**
+ * Test various IPv6 expressions. First IPv6 expression with CIDR prefix,
+ * then RFC 2732 format (brackets around address) expression.
+ *
+ * @param ipStr The string to convert into IPv6 InetAddress.
+ * @throws Exception If the evaluation doesn't return true.
+ */
+ @Test(dataProvider = "v6Matches1")
+ public void test6Cidr(String ipStr) throws Exception {
+ IP ip=(IP) IP.decode(ip6ExprCidr, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ InetAddress addr=InetAddress.getByName(ipStr);
+ EnumEvalResult res=ip.evaluate(addr);
+ if(res != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + ip6ExprCidr);
+ IP ip1=(IP) IP.decode(ip6ExprCidrB, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ EnumEvalResult res1=ip1.evaluate(addr);
+ if(res1 != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + ip6ExprCidrB);
+ }
+
+ /**
+ * Test IPv6 address expressions. First using the long form, then the
+ * compressed form. The addresses to match have long and compressed forms
+ * also. All tests should pass.
+ *
+ * @param ipStr The string to convert into IPv6 InetAddress.
+ * @throws Exception If the evaluation doesn't return true.
+ */
+ @Test(dataProvider = "v6Matches")
+ public void test6Simple(String ipStr) throws Exception {
+ IP ip=(IP) IP.decode(ip6Expr, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ InetAddress addr=InetAddress.getByName(ipStr);
+ EnumEvalResult res=ip.evaluate(addr);
+ if(res != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + ip6Expr);
+ IP ip1=(IP) IP.decode(ip6ExprC, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ EnumEvalResult res1=ip1.evaluate(addr);
+ if(res1 != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + ip6ExprC);
+ }
+
+ /**
+ * Test IPv4 cidr prefix expressions and cidr prefix with wild-card
+ * expressions. All tests should pass.
+ *
+ * @param ipStr The string to convert into IPv4 InetAddress.
+ * @throws Exception If the evaluation doesn't return true.
+ */
+ @Test(dataProvider = "v4Matches")
+ public void test4NCidr(String ipStr) throws Exception {
+ IP ip=(IP) IP.decode(cidr, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ InetAddress addr=InetAddress.getByName(ipStr);
+ EnumEvalResult res=ip.evaluate(addr);
+ if(res != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + cidr);
+
+ IP ip1=(IP) IP.decode(cidrWc, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ EnumEvalResult res1=ip.evaluate(addr);
+ if(res1 != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + cidrWc);
+ }
+
+ /**
+ * Test IPv4 netmask expressions and netmask with wild-card expressions.
+ * All tests should pass.
+ *
+ * @param ipStr The string to convert into IPv4 InetAddress.
+ * @throws Exception If the evaluation doesn't return true.
+ */
+ @Test(dataProvider = "v4Matches")
+ public void test4Netmasks(String ipStr) throws Exception {
+ IP ip=(IP) IP.decode(netmaskWc, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ InetAddress addr=InetAddress.getByName(ipStr);
+ EnumEvalResult res=ip.evaluate(addr);
+ if(res != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + netmaskWc);
+ IP ip1 = (IP) IP.decode(netmaskWcOverRide,
+ EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ EnumEvalResult res1=ip1.evaluate(addr);
+ if(res1 != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + netmaskWc);
+ }
+
+ /**
+ * Test IPv4 expressions and expression with wild-cards.
+ * All Tests should pass.
+ *
+ * @param ipStr The string to convert into IPv4 InetAddress.
+ * @throws Exception If the evaluation doesn't return true.
+ */
+ @Test(dataProvider = "v4Matches")
+ public void test4SimpleWildCard(String ipStr) throws Exception {
+ IP ip=(IP) IP.decode(ipExpr, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ InetAddress addr=InetAddress.getByName(ipStr);
+ EnumEvalResult res=ip.evaluate(addr);
+ if(res != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr: " + ipExpr);
+ IP ipWc=(IP) IP.decode(ipExprWc, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ EnumEvalResult resWc=ipWc.evaluate(addr);
+ if(resWc != EnumEvalResult.TRUE)
+ throw new RuntimeException ("Addr: " + ipStr +
+ "expr:" + ipExprWc);
+ }
+
+ /**
+ * Test decoding of various valid rules.
+ *
+ * @param mask The expression to decode.
+ * @throws Exception If the valid rule failed decoding.
+ */
+ @Test(dataProvider = "validRules")
+ public void testValidIPDecode(String mask)
+ throws Exception {
+ IP.decode(mask, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ }
+
+ /**
+ * Test decoding of invalid rules.
+ *
+ * @param mask The expression to decode.
+ * @throws Exception If the valid rule failed decoding.
+ */
+ @Test(expectedExceptions= AciException.class, dataProvider="invalidRules")
+ public void testInvalidDecode(String mask)
+ throws Exception {
+ try {
+ IP.decode(mask, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ } catch (AciException ae) {
+ throw ae;
+ } catch (Exception e) {
+ System.out.println(
+ "Invalid mask <" + mask + "> threw wrong exception type.");
+ throw e;
+ }
+ throw new RuntimeException(
+ "Invalid mask <" + mask + "> did not throw an exception.");
+ }
+
+ /**
+ * Test decoding of valid IPv6 rules.
+ *
+ * @param mask The expression to decode.
+ * @throws Exception If the valid rule failed decoding.
+ */
+ @Test(dataProvider = "valid6Rules")
+ public void testValidIP6Decode(String mask)
+ throws Exception {
+ IP.decode(mask, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ }
+
+
+ /**
+ * Test deocding of invalid IPV6 rules.
+ *
+ * @param mask The expression to decode.
+ * @throws Exception If the valid rule failed decoding.
+ */
+ @Test(expectedExceptions= AciException.class, dataProvider="invalid6Rules")
+ public void testInvalid6Decode(String mask)
+ throws Exception {
+ try {
+ IP.decode(mask, EnumBindRuleType.EQUAL_BINDRULE_TYPE);
+ } catch (AciException ae) {
+ throw ae;
+ } catch (Exception e) {
+ System.out.println(
+ "Invalid mask <" + mask + "> threw wrong exception type.");
+ throw e;
+ }
+ throw new RuntimeException(
+ "Invalid mask <" + mask + "> did not throw an exception.");
+ }
+}
--
Gitblit v1.10.0