org.xins.server.AccessRule Maven / Gradle / Ivy
/*
* $Id: AccessRule.java,v 1.49 2007/09/18 08:45:06 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.apache.oro.text.regex.Perl5Matcher;
import org.apache.oro.text.regex.Perl5Pattern;
import org.xins.common.MandatoryArgumentChecker;
import org.xins.common.Utils;
import org.xins.common.text.ParseException;
import org.xins.common.text.SimplePatternParser;
/**
* Access rule. This class can take a character string to produce an
* {@link AccessRule} object from it.
*
* Descriptor format
*
* A descriptor must comply to the following format:
*
* - start with either
"allow"
or "deny"
;
* - followed by any number of white space characters;
*
- followed by a valid IP address;
*
- followed by a slash character (
'/'
);
* - followed by a mask between 0 and 32 in decimal format, without
* leading zeroes;
*
- followed by any number of white space characters;
*
- followed by a simple pattern, see class {@link SimplePatternParser}.
*
*
* Descriptor examples
*
* Example of access rule descriptors:
*
*
* "allow 194.134.168.213/32 *"
* - Allows 194.134.168.213 to access any function.
*
* "deny 194.134.168.213/24 _*"
* - Denies all 194.134.168.x IP addresses to access any function
* starting with an underscore (
'_'
).
*
*
* @version $Revision: 1.49 $ $Date: 2007/09/18 08:45:06 $
* @author Ernst de Haan
* @author Chris Gilbride
* @author Anthony Goubard
*
* @since XINS 1.0.0
*/
public final class AccessRule implements AccessRuleContainer {
/**
* If the access method is 'allow' or not.
*/
private final boolean _allow;
/**
* The IP address filter used to create the access rule. Cannot be
* null
.
*/
private final IPFilter _ipFilter;
/**
* The function name pattern. Cannot be null
.
*/
private final Perl5Pattern _functionNameRegex;
/**
* The calling convention name pattern. Cannot be null
.
*/
private final Perl5Pattern _conventionNameRegex;
/**
* String representation of this object. Cannot be null
.
*/
private final String _asString;
/**
* Flag that indicates whether this object is disposed.
*/
private boolean _disposed;
/**
* Constructs a new AccessRule
.
*
* @param allow
* flag that indicates if this rule grants access (true
) or
* denies access (false
).
*
* @param ipFilter
* filter used for matching (or not) IP addresses, cannot be
* null
.
*
* @param asString
* textual presentation of this access rule, cannot be
* null
.
*
* @param functionNameRegex
* regular expression used for matching (or not) a function name; cannot
* be null
.
*
* @param conventionNameRegex
* regular expression used for matching (or not) a calling convention name; cannot be null
.
*
* @throws IllegalArgumentException
* if ipFilter == null
* || functionNameRegex == null
* || conventionNameRegex == null
* || asString == null
.
*/
private AccessRule(boolean allow,
IPFilter ipFilter,
Perl5Pattern functionNameRegex,
Perl5Pattern conventionNameRegex,
String asString)
throws IllegalArgumentException {
// Check preconditions
MandatoryArgumentChecker.check("ipFilter", ipFilter,
"functionNameRegex", functionNameRegex,
"conventionNameRegex", conventionNameRegex,
"asString", asString);
// Store the data
_allow = allow;
_ipFilter = ipFilter;
_functionNameRegex = functionNameRegex;
_conventionNameRegex = conventionNameRegex;
_asString = asString;
}
/**
* Parses the specified character string to construct a new
* AccessRule
object.
*
* @param descriptor
* the access rule descriptor, the character string to parse, cannot be
* null
.
*
* @return
* an {@link AccessRule} instance, never null
.
*
* @throws IllegalArgumentException
* if descriptor == null
.
*
* @throws ParseException
* If there was a parsing error.
*/
public static AccessRule parseAccessRule(String descriptor)
throws IllegalArgumentException, ParseException {
// Check preconditions
MandatoryArgumentChecker.check("descriptor", descriptor);
StringTokenizer tokenizer = new StringTokenizer(descriptor," \t\n\r");
// Determine if it is an 'allow' or a 'deny' rule
boolean allow;
String sAllow = nextToken(descriptor, tokenizer);
if ("allow".equals(sAllow)) {
allow = true;
} else if ("deny".equals(sAllow)) {
allow = false;
} else {
String message = "First token of descriptor is \""
+ sAllow
+ "\", instead of either 'allow' or 'deny'.";
throw new ParseException(message);
}
// Determine the IP address filter
String sFilter = nextToken(descriptor, tokenizer);
IPFilter filter = IPFilter.parseIPFilter(sFilter);
SimplePatternParser parser = new SimplePatternParser();
// Determine the function the access is to be checked for
String functionPatternString = nextToken(descriptor, tokenizer);
Perl5Pattern functionPattern = parser.parseSimplePattern(functionPatternString);
// Determine the function the access is to be checked for
String conventionPatternString = "*";
if (tokenizer.hasMoreTokens()) {
conventionPatternString = tokenizer.nextToken();
}
Perl5Pattern conventionPattern = parser.parseSimplePattern(conventionPatternString);
// Construct a description
String asString = sAllow + ' ' + filter.toString() + ' ' +
functionPatternString + ' ' + conventionPatternString;
return new AccessRule(allow, filter, functionPattern, conventionPattern, asString);
}
/**
* Returns the next token in the descriptor.
*
* @param descriptor
* the original descriptor, useful when constructing the message for a
* {@link ParseException}, when appropriate, should not be
* null
.
*
* @param tokenizer
* the {@link StringTokenizer} to retrieve the next token from, cannot be
* null
.
*
* @return
* the next token, never null
.
*
* @throws ParseException
* if tokenizer.{@link StringTokenizer#hasMoreTokens()
* hasMoreTokens}() == false
.
*/
private static String nextToken(String descriptor,
StringTokenizer tokenizer)
throws ParseException {
if (! tokenizer.hasMoreTokens()) {
String message = "The string \""
+ descriptor
+ "\" is invalid as an access rule descriptor. "
+ "More tokens expected.";
throw new ParseException(message);
} else {
return tokenizer.nextToken();
}
}
/**
* Returns if this rule is an allow or a deny rule.
*
* @return
* true
if this is an allow rule, or
* false
if this is a deny rule.
*/
public boolean isAllowRule() {
return _allow;
}
/**
* Returns the IP filter.
*
* @return
* the {@link IPFilter} associated with this access rule, never
* null
.
*/
public IPFilter getIPFilter() {
return _ipFilter;
}
/**
* Determines if the specified IP address and function match this rule.
*
* Calling this function is equivalent to calling:
*
*
{@link #isAllowed(String,String) isAllowed}(ip,
* functionName) != null
*
* @param ip
* the IP address to match, cannot be null
.
*
* @param functionName
* the name of the function to match, cannot be null
.
*
* @param conventionName
* the name of the calling convention to match, can be null
.
*
* @return
* true
if this rule matches, false
otherwise.
*
* @throws IllegalStateException
* if this access rule is disposed (since XINS 1.3.0).
*
* @throws IllegalArgumentException
* if ip == null || functionName == null
.
*
* @throws ParseException
* if the specified IP address cannot be parsed.
*
* @since XINS 2.1.
*/
public boolean match(String ip, String functionName, String conventionName)
throws IllegalStateException, IllegalArgumentException, ParseException {
// Check state
if (_disposed) {
String detail = "This AccessRule is disposed.";
Utils.logProgrammingError(detail);
throw new IllegalStateException(detail);
}
// Delegate to the isAllowed method
return isAllowed(ip, functionName, conventionName) != null;
}
/**
* 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, 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 there is no match.
*
* @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 AccessRule is disposed.";
Utils.logProgrammingError(detail);
throw new IllegalStateException(detail);
}
// Check arguments
MandatoryArgumentChecker.check("ip", ip, "functionName", functionName);
// First check if the IP filter matches
Perl5Matcher patternMatcher = new Perl5Matcher();
if (_ipFilter.match(ip)) {
// Then check if the function name matches
if (patternMatcher.matches(functionName, _functionNameRegex) &&
(conventionName == null || patternMatcher.matches(conventionName, _conventionNameRegex))) {
return _allow ? Boolean.TRUE : Boolean.FALSE;
}
}
return null;
}
/**
* Disposes this access rule. All claimed resources are freed as much as
* possible.
*
*
Once disposed, neither {@link #match} nor {@link #isAllowed} should
* be called.
*
* @throws IllegalStateException
* if this access rule is already disposed (since XINS 1.3.0).
*/
public void dispose() {
// Check state
if (_disposed) {
String detail = "This AccessRule is already disposed.";
Utils.logProgrammingError(detail);
throw new IllegalStateException(detail);
}
// Mark this object as disposed
_disposed = true;
}
/**
* Returns a character string representation of this object. The returned
* string is in the form:
*
*
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;
}
}