ParentInheritance.java revision 88f16d892d54fd8c3e190cc1f6363638b11ae1a3
/*
* 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 legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* 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 legal-notices/CDDLv1_0.txt.
* 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
*
*
* Copyright 2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
package org.opends.server.authorization.dseecompat;
import org.forgerock.i18n.LocalizableMessage;
import static org.opends.messages.AccessControlMessages.*;
import static org.opends.server.authorization.dseecompat.Aci.*;
import java.util.StringTokenizer;
import java.util.LinkedHashSet;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
import org.opends.server.types.LDAPURL;
import org.opends.server.types.DirectoryException;
/**
* This class is used by USERDN and GROUPDN userattr types
* to determine what parent inheritance checks to make.
*/
public class ParentInheritance {
/*
* The maximum number of parent inheritance levels supported.
*/
private static final int MAX_LEVELS=10;
/*
* Pattern to match for parent inheritance.
*/
private final String parentPat="parent[";
/*
* Array used to hold the level information. Each slot corresponds to a
* level parsed from the rule.
*/
private final int[] levels=new int[MAX_LEVELS];
/*
* The number of levels parsed.
*/
private int numLevels;
/*
* The attribute type string parsed from the rule. Only used in
* inheritance search.
*/
private String attrTypeStr;
/*
* The base DN of a URL parsed from the rule. Used to make sure groupdn
* are under this suffix. Originally a way to search all nested groups
* under this suffix, so the behavior is slightly different.
*/
private DN baseDN;
/**
* Construct a class from the inheritance pattern. The skipParsing boolean
* specifies that parent parsing should be skipped and sets up the class:
* with numLevels=1, level[0]=0 and an attribute type from the
* specified pattern.
*
* @param pattern The string pattern containing the inheritance
* information.
* @param skipParse Specify if the parent inheritance parsing should be
* skipped or not.
* @throws AciException If the pattern is invalid.
*/
ParentInheritance (String pattern, boolean skipParse) throws AciException {
if (skipParse) {
//The "parent[" pattern is invalid for ROLEDN user attr keyword.
if(pattern.startsWith(parentPat)) {
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN
.get(pattern);
throw new AciException(message);
} else {
pattern=pattern.trim();
Pattern pattern1=Pattern.compile(ATTR_NAME);
Matcher matcher=pattern1.matcher(pattern);
//Check if valid attribute type name.
if(!matcher.find() || matcher.groupCount() != 1) {
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME.get(pattern);
throw new AciException(message);
}
numLevels=1;
levels[0]=0;
}
} else parse(pattern);
}
/**
* Performs all parsing of the specified pattern string.
* @param pattern The string pattern containing the inheritance
* information.
* @throws AciException If the pattern is invalid.
*/
private void parse (String pattern) throws AciException {
pattern=pattern.trim();
/**
* Check if we have a "parent[" string.
*/
if(pattern.startsWith(parentPat)) {
numLevels=0;
levels[0]=0;
String p=pattern.substring(parentPat.length());
/**
* Format needs to be parent[XX].attribute -- everything after the
* '.' is the attribute type.
*/
String[] toks=p.split("\\.");
if(toks.length != 2) {
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN
.get(pattern);
throw new AciException(message);
}
Pattern pattern1=Pattern.compile(ATTR_NAME);
Matcher matcher=pattern1.matcher(toks[1]);
//Check if valid attribute type name.
if(!matcher.find() || matcher.groupCount() != 1) {
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME.get(toks[1]);
throw new AciException(message);
}
attrTypeStr=toks[1];
StringTokenizer tok=new StringTokenizer(toks[0],"],",false);
while(tok.hasMoreTokens()) {
String v=tok.nextToken();
/**
* Everything between the brackets must be an integer or it's
* an error.
*/
try {
if(numLevels < MAX_LEVELS) {
levels[numLevels++]=Integer.decode(v);
} else {
LocalizableMessage message =
WARN_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED.get(pattern, MAX_LEVELS);
throw new AciException(message);
}
} catch (NumberFormatException ex) {
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_INHERITANCE_VALUE.get(pattern);
throw new AciException(message);
}
}
} else {
attrTypeStr=pattern;
if(pattern.startsWith(NULL_LDAP_URL)) {
try {
LDAPURL url=LDAPURL.decode(pattern, true);
LinkedHashSet<String>attrs=url.getAttributes();
if(attrs.size() != 1) {
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_USERATTR_ATTR_URL.get(pattern);
throw new AciException(message);
}
baseDN=url.getBaseDN();
if(baseDN.isRootDN()){
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_USERATTR_BASEDN_URL.get(pattern);
throw new AciException(message);
}
attrTypeStr=attrs.iterator().next();
} catch (DirectoryException ex) {
LocalizableMessage message = WARN_ACI_SYNTAX_INVALID_USERATTR_URL.get(
ex.getMessageObject());
throw new AciException(message);
}
}
numLevels=1;
levels[0]=0;
}
}
/**
* Returns the number of levels counted.
* @return The number of levels.
*/
public int getNumLevels() {
return numLevels;
}
/**
* Returns an array of levels, where levels are integers.
* @return Return an array of levels.
*/
public int[] getLevels() {
int[] levelsCopy = new int[levels.length];
System.arraycopy(levels, 0, levelsCopy, 0, levels.length);
return levelsCopy;
}
/**
* Return the attribute type.
* @return The attribute type.
*/
public AttributeType getAttributeType() {
final String attrName = attrTypeStr.toLowerCase();
AttributeType attrType = DirectoryServer.getAttributeType(attrName);
if(attrType == null)
{
attrType = DirectoryServer.getDefaultAttributeType(attrName);
}
return attrType;
}
/**
* Return the string representation of the attribute type.
* @return The attribute type string.
*/
public String getAttrTypeStr() {
return attrTypeStr;
}
/**
* Return the DN that groupdn must be under.
*
* @return DN that groupdn must be under.
*/
public DN getBaseDN() {
return baseDN;
}
}