org.xins.server.AccessRuleList Maven / Gradle / Ivy
/*
* $Id: AccessRuleList.java,v 1.51 2007/09/11 13:24:21 agoubard Exp $
*
* Copyright 2003-2007 Orange Nederland Breedband B.V.
* See the COPYRIGHT file for redistribution and use restrictions.
*/
package org.xins.server;
import java.util.StringTokenizer;
import org.xins.common.MandatoryArgumentChecker;
import org.xins.common.Utils;
import org.xins.common.text.ParseException;
/**
* Access rule list.
*
* Descriptor format
*
* An access rule list descriptor, a character string, can be
* converted to produce an {@link AccessRuleList} object. A valid descriptor
* consists of a list of access rule descriptors (see class
* {@link AccessRule}) and/or access rule file descriptors (see class
* {@link AccessRuleFile}), separated by semi-colon characters (';'
).
* Optionally, the rules can have any amount of whitespace (space-, tab-,
* newline- and carriage return-characters), before and after them. The last
* descriptor cannot end with a semi-colon.
*
*
Descriptor examples
*
* An example of an access rule list descriptor is:
*
*
allow 194.134.168.213/32 *;
*
deny 194.134.168.213/24 _*;
*
allow 194.134.168.213/24 *;
*
file /var/conf/file1.acl;
*
deny 0.0.0.0/0 *
*
* The above access control list grants the IP address 194.134.168.213
* access to all functions. Then in the second rule it denies
* access to all IP addresses in the range 194.134.168.0 to 194.134.168.255 to
* all functions that start with an underscore ('_'
). Then it
* allows access for those IP addresses to all other functions, then it
* applies the rules in the /var/conf/file1.acl
file and finally
* all other IP addresses are denied access to any of the functions.
*
* @version $Revision: 1.51 $ $Date: 2007/09/11 13:24:21 $
* @author Ernst de Haan
*
* @since XINS 1.0.0
*/
public final class AccessRuleList implements AccessRuleContainer {
/**
* An empty access rule list. This field is never null
.
*/
static final AccessRuleList EMPTY = new AccessRuleList(new AccessRuleContainer[0]);
/**
* The list of rules. Cannot be null
.
*/
private AccessRuleContainer[] _rules;
/**
* The string representation of this instance. Cannot be null
.
*/
private String _asString;
/**
* Flag that indicates whether this object is disposed.
*/
private boolean _disposed;
/**
* Creates a new AccessRuleList
object. The passed
* {@link AccessRuleContainer} array is assumed to be owned by the
* constructor.
*
* @param rules
* the list of rules, not null
and should not contain any
* duplicate or null
elements; if one of these latter 2
* constraints are violated, the behaviour is undefined.
*
* @throws NullPointerException
* if rules == null
.
*/
private AccessRuleList(AccessRuleContainer[] rules)
throws NullPointerException {
// Count number of rules (may throw NPE)
int ruleCount = rules.length;
// Build string representation and log
StringBuffer buffer = new StringBuffer(ruleCount * 40);
if (ruleCount > 0) {
String s = rules[0].toString();
buffer.append(s);
Log.log_3429(0, s);
for (int i = 1; i < ruleCount; i++) {
s = rules[i].toString();
buffer.append(';');
buffer.append(s);
Log.log_3429(i, s);
}
}
_asString = buffer.toString();
// Store the rules
_rules = rules;
}
/**
* Parses the specified character string to construct a new
* AccessRuleList
object, with the specified watch interval
* for referenced files.
*
*
If the specified interval is 0
, then no watching will be
* performed.
*
* @param descriptor
* the access rule list descriptor, the character string to parse,
* cannot be null
.
*
* @param interval
* the interval used to check the ACL files for modification, in
* seconds, must be >= 0.
*
* @return
* an {@link AccessRuleList} instance, never null
.
*
* @throws IllegalArgumentException
* if descriptor == null || interval < 0
.
*
* @throws ParseException
* if there was a parsing error.
*
* @since XINS 1.1.0
*/
public static final AccessRuleList parseAccessRuleList(String descriptor,
int interval)
throws IllegalArgumentException, ParseException {
// Check preconditions
MandatoryArgumentChecker.check("descriptor", descriptor);
if (interval < 0) {
throw new IllegalArgumentException("interval ("
+ interval
+ ") < 0");
}
// First trim whitespace from the descriptor
descriptor = descriptor.trim();
// Tokenize the descriptor, separator is semi-colon
StringTokenizer tokenizer = new StringTokenizer(descriptor, ";");
int ruleCount = tokenizer.countTokens();
// Parse all tokens
AccessRuleContainer[] rules = new AccessRuleContainer[ruleCount];
for (int i = 0; i < ruleCount; i++) {
// Remove leading and trailing whitespace from the next token
String token = tokenizer.nextToken().trim();
// Parse and add the rule
if (token.startsWith("allow") || token.startsWith("deny")) {
rules[i] = AccessRule.parseAccessRule(token);
} else if (token.startsWith("file")) {
rules[i] = new AccessRuleFile(token, interval);
} else {
String detail = "Failed to parse access rule list. "
+ "Expected token \""
+ token
+ "\" to start with "
+ "\"allow\", \"deny\" or \"file\".";
throw new ParseException(detail);
}
}
return new AccessRuleList(rules);
}
/**
* Counts the number of rules in this list.
*
* @return
* the number of rules, always >= 0.
*/
public int getRuleCount() {
return _rules.length;
}
/**
* Determines if the specified IP address is allowed to access the
* specified function, returning a Boolean
object or
* null
.
*
*
This method finds the first matching rule and then returns the
* allow property of that rule (see
* {@link AccessRule#isAllowRule()}). If there is no matching rule, then
* null
is returned.
*
* @param ip
* the IP address, cannot be null
.
*
* @param functionName
* the name of the function, cannot be null
.
*
* @param conventionName
* the name of the calling convention to match, can be null
.
*
* @return
* {@link Boolean#TRUE} if the specified IP address is allowed to access
* the specified function, {@link Boolean#FALSE} if it is disallowed
* access or null
if no match is found.
*
* @throws IllegalStateException
* if this object is disposed (since XINS 1.3.0).
*
* @throws IllegalArgumentException
* if ip == null || functionName == null
.
*
* @throws ParseException
* if the specified IP address is malformed.
*
* @since XINS 2.1.
*/
public Boolean isAllowed(String ip, String functionName, String conventionName)
throws IllegalStateException, IllegalArgumentException, ParseException {
// Check state
if (_disposed) {
String detail = "This AccessRuleList is disposed.";
Utils.logProgrammingError(detail);
throw new IllegalStateException(detail);
}
// Check preconditions
MandatoryArgumentChecker.check("ip", ip, "functionName", functionName);
int ruleCount = _rules.length;
for (int i = 0; i < ruleCount; i++) {
AccessRuleContainer rule = _rules[i];
String ruleString = rule.toString();
Boolean allowed = rule.isAllowed(ip, functionName, conventionName);
if (allowed != null) {
// Choose between 'allow' and 'deny'
boolean allow = allowed.booleanValue();
// Log this match
// XXX: Should this logging really be done in this class?
if (allow) {
Log.log_3550(ip, functionName, conventionName, i, ruleString);
} else {
Log.log_3551(ip, functionName, conventionName, i, ruleString);
}
return allowed;
}
}
return null;
}
/**
* Disposes this access rule. All claimed resources are freed as much as
* possible.
*
*
Once disposed, the {@link #isAllowed} method should no longer be
* called.
*/
public void dispose() {
// Check state
if (_disposed) {
String detail = "This AccessRule is already disposed.";
Utils.logProgrammingError(detail);
throw new IllegalStateException(detail);
}
// Do not dispose the EMPTY list
if (this == EMPTY) {
return;
}
// Mark this object as disposed
_disposed = true;
// Dispose the current rules
int count = _rules == null ? 0 : _rules.length;
for (int i = 0; i < count; i++) {
AccessRuleContainer rule = _rules[i];
if (rule != null) {
try {
rule.dispose();
} catch (Throwable exception) {
Utils.logIgnoredException(exception);
}
}
}
_rules = null;
}
/**
* Returns a character string representation of this object. The returned
* string is in the form:
*
*
type a.b.c.d/m pattern;type a.b.c.d/m pattern
*
* where type is either "allow"
or
* "deny"
, a.b.c.d is the base IP address, m
* is the mask, and pattern is the function name simple pattern.
*
* @return
* a character string representation of this access rule, never
* null
.
*/
public String toString() {
return _asString;
}
}