use of com.unboundid.ldap.matchingrules.MatchingRule in project ldapsdk by pingidentity.
the class EntryValidator method checkAttribute.
/**
* Checks the provided attribute to determine whether it appears to be valid.
*
* @param attr The attribute to examine.
* @param requiredAttrs The set of attribute types which are required to be
* included in the entry.
* @param optionalAttrs The set of attribute types which may optionally be
* included in the entry.
* @param invalidReasons A list to which messages may be added which provide
* information about why the entry is invalid. It may
* be {@code null} if this information is not needed.
*
* @return {@code true} if the attribute passed all of the checks and appears
* to be valid, or {@code false} if it failed any of the checks.
*/
private boolean checkAttribute(@NotNull final Attribute attr, @NotNull final Set<AttributeTypeDefinition> requiredAttrs, @NotNull final Set<AttributeTypeDefinition> optionalAttrs, @Nullable final List<String> invalidReasons) {
boolean entryValid = true;
final AttributeTypeDefinition d = schema.getAttributeType(attr.getBaseName());
if (d == null) {
if (checkUndefinedAttributes) {
entryValid = false;
updateCount(attr.getBaseName(), undefinedAttributes);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_UNDEFINED_ATTR.get(attr.getBaseName()));
}
}
return entryValid;
}
if (checkProhibitedAttributes && (!d.isOperational())) {
if (!(requiredAttrs.contains(d) || optionalAttrs.contains(d))) {
entryValid = false;
updateCount(d.getNameOrOID(), prohibitedAttributes);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_NOT_ALLOWED.get(d.getNameOrOID()));
}
}
}
final ASN1OctetString[] rawValues = attr.getRawValues();
if (checkSingleValuedAttributes && d.isSingleValued() && (rawValues.length > 1)) {
entryValid = false;
updateCount(d.getNameOrOID(), singleValueViolations);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_HAS_MULTIPLE_VALUES.get(d.getNameOrOID()));
}
}
if (checkAttributeSyntax) {
if (!ignoreSyntaxViolationTypes.contains(d)) {
final MatchingRule r = MatchingRule.selectEqualityMatchingRule(d.getNameOrOID(), schema);
final Map<String, String[]> extensions = d.getExtensions();
for (final ASN1OctetString v : rawValues) {
try {
r.normalize(v);
} catch (final LDAPException le) {
Debug.debugException(le);
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_INVALID_SYNTAX.get(v.stringValue(), d.getNameOrOID(), StaticUtils.getExceptionMessage(le)));
}
}
// If the attribute type definition includes an X-ALLOWED-VALUE
// extension, then make sure the value is in that set.
final String[] allowedValues = extensions.get("X-ALLOWED-VALUE");
if (allowedValues != null) {
boolean isAllowed = false;
for (final String allowedValue : allowedValues) {
try {
if (r.valuesMatch(v, new ASN1OctetString(allowedValue))) {
isAllowed = true;
break;
}
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (!isAllowed) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_NOT_ALLOWED.get(v.stringValue(), d.getNameOrOID()));
}
}
}
// If the attribute type definition includes an X-VALUE-REGEX
// extension, then make sure the value matches one of those regexes.
final String[] valueRegexes = extensions.get("X-VALUE-REGEX");
if (valueRegexes != null) {
boolean matchesRegex = false;
for (final String regex : valueRegexes) {
try {
final Pattern pattern = Pattern.compile(regex);
if (pattern.matcher(v.stringValue()).matches()) {
matchesRegex = true;
break;
}
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (!matchesRegex) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_NOT_ALLOWED_BY_REGEX.get(v.stringValue(), d.getNameOrOID()));
}
}
}
// If the attribute type definition includes an X-MIN-VALUE-LENGTH
// extension, then make sure the value is long enough.
final String[] minValueLengths = extensions.get("X-MIN-VALUE-LENGTH");
if (minValueLengths != null) {
int minLength = 0;
for (final String s : minValueLengths) {
try {
minLength = Math.max(minLength, Integer.parseInt(s));
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (v.stringValue().length() < minLength) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_SHORTER_THAN_MIN_LENGTH.get(v.stringValue(), d.getNameOrOID(), minLength));
}
}
}
// If the attribute type definition includes an X-MAX-VALUE-LENGTH
// extension, then make sure the value is short enough.
final String[] maxValueLengths = extensions.get("X-MAX-VALUE-LENGTH");
if (maxValueLengths != null) {
int maxLength = Integer.MAX_VALUE;
for (final String s : maxValueLengths) {
try {
maxLength = Math.min(maxLength, Integer.parseInt(s));
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (v.stringValue().length() > maxLength) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_LONGER_THAN_MAX_LENGTH.get(v.stringValue(), d.getNameOrOID(), maxLength));
}
}
}
// If the attribute type definition includes an X-MIN-INT-VALUE
// extension, then make sure the value is large enough.
final String[] minIntValues = extensions.get("X-MIN-INT-VALUE");
if (minIntValues != null) {
try {
final long longValue = Long.parseLong(v.stringValue());
long minAllowedValue = 0L;
for (final String s : minIntValues) {
try {
minAllowedValue = Math.max(minAllowedValue, Long.parseLong(s));
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (longValue < minAllowedValue) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_INT_TOO_SMALL.get(longValue, d.getNameOrOID(), minAllowedValue));
}
}
} catch (final Exception e) {
Debug.debugException(e);
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_NOT_INT.get(v.stringValue(), d.getNameOrOID(), "X-MIN-INT-VALUE"));
}
}
}
// If the attribute type definition includes an X-MAX-INT-VALUE
// extension, then make sure the value is large enough.
final String[] maxIntValues = extensions.get("X-MAX-INT-VALUE");
if (maxIntValues != null) {
try {
final long longValue = Long.parseLong(v.stringValue());
long maxAllowedValue = Long.MAX_VALUE;
for (final String s : maxIntValues) {
try {
maxAllowedValue = Math.min(maxAllowedValue, Long.parseLong(s));
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (longValue > maxAllowedValue) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_INT_TOO_LARGE.get(longValue, d.getNameOrOID(), maxAllowedValue));
}
}
} catch (final Exception e) {
Debug.debugException(e);
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_ATTR_VALUE_NOT_INT.get(v.stringValue(), d.getNameOrOID(), "X-MAX-INT-VALUE"));
}
}
}
}
// If the attribute type definition includes an X-MIN-VALUE-COUNT
// extension, then make sure the value has enough values.
final String[] minValueCounts = extensions.get("X-MIN-VALUE-COUNT");
if (minValueCounts != null) {
int minValueCount = 0;
for (final String s : minValueCounts) {
try {
minValueCount = Math.max(minValueCount, Integer.parseInt(s));
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (rawValues.length < minValueCount) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_TOO_FEW_VALUES.get(rawValues.length, d.getNameOrOID(), minValueCount));
}
}
}
// If the attribute type definition includes an X-MAX-VALUE-COUNT
// extension, then make sure the value has enough values.
final String[] maxValueCounts = extensions.get("X-MAX-VALUE-COUNT");
if (maxValueCounts != null) {
int maxValueCount = Integer.MAX_VALUE;
for (final String s : maxValueCounts) {
try {
maxValueCount = Math.min(maxValueCount, Integer.parseInt(s));
} catch (final Exception e) {
Debug.debugException(e);
}
}
if (rawValues.length > maxValueCount) {
entryValid = false;
updateCount(d.getNameOrOID(), attributesViolatingSyntax);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_TOO_MANY_VALUES.get(rawValues.length, d.getNameOrOID(), maxValueCount));
}
}
}
}
}
return entryValid;
}
use of com.unboundid.ldap.matchingrules.MatchingRule in project ldapsdk by pingidentity.
the class EntryValidator method checkRDN.
/**
* Ensures that the provided RDN is acceptable. It will ensure that all
* attributes are defined in the schema and allowed for the entry, and that
* the entry optionally conforms to the associated name form.
*
* @param rdn The RDN to examine.
* @param entry The entry to examine.
* @param requiredAttrs The set of attribute types which are required to be
* included in the entry.
* @param optionalAttrs The set of attribute types which may optionally be
* included in the entry.
* @param nameForm The name for to use to make the determination, if
* defined.
* @param invalidReasons A list to which messages may be added which provide
* information about why the entry is invalid. It may
* be {@code null} if this information is not needed.
*
* @return {@code true} if the entry passes all checks performed by this
* method, or {@code false} if not.
*/
private boolean checkRDN(@NotNull final RDN rdn, @NotNull final Entry entry, @NotNull final Set<AttributeTypeDefinition> requiredAttrs, @NotNull final Set<AttributeTypeDefinition> optionalAttrs, @Nullable final NameFormDefinition nameForm, @Nullable final List<String> invalidReasons) {
final HashSet<AttributeTypeDefinition> nfReqAttrs = new HashSet<>(StaticUtils.computeMapCapacity(5));
final HashSet<AttributeTypeDefinition> nfAllowedAttrs = new HashSet<>(StaticUtils.computeMapCapacity(5));
if (nameForm != null) {
for (final String s : nameForm.getRequiredAttributes()) {
final AttributeTypeDefinition d = schema.getAttributeType(s);
if (d != null) {
nfReqAttrs.add(d);
}
}
nfAllowedAttrs.addAll(nfReqAttrs);
for (final String s : nameForm.getOptionalAttributes()) {
final AttributeTypeDefinition d = schema.getAttributeType(s);
if (d != null) {
nfAllowedAttrs.add(d);
}
}
}
boolean entryValid = true;
final String[] attributeNames = rdn.getAttributeNames();
final byte[][] attributeValues = rdn.getByteArrayAttributeValues();
for (int i = 0; i < attributeNames.length; i++) {
final String name = attributeNames[i];
if (checkEntryMissingRDNValues) {
final byte[] value = attributeValues[i];
final MatchingRule matchingRule = MatchingRule.selectEqualityMatchingRule(name, schema);
if (!entry.hasAttributeValue(name, value, matchingRule)) {
entryValid = false;
entriesMissingRDNValues.incrementAndGet();
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_MISSING_RDN_VALUE.get(rdn.getAttributeValues()[i], name));
}
}
}
final AttributeTypeDefinition d = schema.getAttributeType(name);
if (d == null) {
if (checkUndefinedAttributes) {
entryValid = false;
updateCount(name, undefinedAttributes);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_RDN_ATTR_NOT_DEFINED.get(name));
}
}
} else {
if (checkProhibitedAttributes && (!(requiredAttrs.contains(d) || optionalAttrs.contains(d) || d.isOperational()))) {
entryValid = false;
updateCount(d.getNameOrOID(), prohibitedAttributes);
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_RDN_ATTR_NOT_ALLOWED_IN_ENTRY.get(d.getNameOrOID()));
}
}
if (checkNameForms && (nameForm != null)) {
if (!nfReqAttrs.remove(d)) {
if (!nfAllowedAttrs.contains(d)) {
if (entryValid) {
entryValid = false;
nameFormViolations.incrementAndGet();
}
if (invalidReasons != null) {
invalidReasons.add(ERR_ENTRY_RDN_ATTR_NOT_ALLOWED_BY_NF.get(name));
}
}
}
}
}
}
if (checkNameForms && (!nfReqAttrs.isEmpty())) {
if (entryValid) {
entryValid = false;
nameFormViolations.incrementAndGet();
}
if (invalidReasons != null) {
for (final AttributeTypeDefinition d : nfReqAttrs) {
invalidReasons.add(ERR_ENTRY_RDN_MISSING_REQUIRED_ATTR.get(d.getNameOrOID()));
}
}
}
return entryValid;
}
use of com.unboundid.ldap.matchingrules.MatchingRule in project ldapsdk by pingidentity.
the class Attribute method readFrom.
/**
* Reads and decodes an attribute from the provided ASN.1 stream reader.
*
* @param reader The ASN.1 stream reader from which to read the attribute.
* @param schema The schema to use to select the appropriate matching rule
* for this attribute. It may be {@code null} if the default
* matching rule should be selected.
*
* @return The decoded attribute.
*
* @throws LDAPException If a problem occurs while trying to read or decode
* the attribute.
*/
@NotNull()
public static Attribute readFrom(@NotNull final ASN1StreamReader reader, @Nullable final Schema schema) throws LDAPException {
try {
Validator.ensureNotNull(reader.beginSequence());
final String attrName = reader.readString();
Validator.ensureNotNull(attrName);
final MatchingRule matchingRule = MatchingRule.selectEqualityMatchingRule(attrName, schema);
final ArrayList<ASN1OctetString> valueList = new ArrayList<>(10);
final ASN1StreamReaderSet valueSet = reader.beginSet();
while (valueSet.hasMoreElements()) {
valueList.add(new ASN1OctetString(reader.readBytes()));
}
final ASN1OctetString[] values = new ASN1OctetString[valueList.size()];
valueList.toArray(values);
return new Attribute(attrName, matchingRule, values);
} catch (final Exception e) {
Debug.debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR, ERR_ATTR_CANNOT_DECODE.get(StaticUtils.getExceptionMessage(e)), e);
}
}
use of com.unboundid.ldap.matchingrules.MatchingRule in project ldapsdk by pingidentity.
the class Filter method matchesEntry.
/**
* Indicates whether this filter matches the provided entry. Note that this
* is a best-guess effort and may not be completely accurate in all cases.
* If provided, the given schema will be used in an attempt to determine the
* appropriate matching rule for making the determinations, but some corner
* cases may not be handled accurately. Neither approximate matching nor
* extensible matching are currently supported.
*
* @param entry The entry for which to make the determination. It must not
* be {@code null}.
* @param schema The schema to use when making the determination. If this
* is {@code null}, then all matching will be performed using
* a case-ignore matching rule.
*
* @return {@code true} if this filter appears to match the provided entry,
* or {@code false} if not.
*
* @throws LDAPException If a problem occurs while trying to make the
* determination.
*/
public boolean matchesEntry(@NotNull final Entry entry, @Nullable final Schema schema) throws LDAPException {
Validator.ensureNotNull(entry);
switch(filterType) {
case FILTER_TYPE_AND:
for (final Filter f : filterComps) {
try {
if (!f.matchesEntry(entry, schema)) {
return false;
}
} catch (final Exception e) {
Debug.debugException(e);
return false;
}
}
return true;
case FILTER_TYPE_OR:
for (final Filter f : filterComps) {
try {
if (f.matchesEntry(entry, schema)) {
return true;
}
} catch (final Exception e) {
Debug.debugException(e);
}
}
return false;
case FILTER_TYPE_NOT:
return (!notComp.matchesEntry(entry, schema));
case FILTER_TYPE_EQUALITY:
Attribute a = entry.getAttribute(attrName, schema);
if (a == null) {
return false;
}
MatchingRule matchingRule = MatchingRule.selectEqualityMatchingRule(attrName, schema);
return matchingRule.matchesAnyValue(assertionValue, a.getRawValues());
case FILTER_TYPE_SUBSTRING:
a = entry.getAttribute(attrName, schema);
if (a == null) {
return false;
}
matchingRule = MatchingRule.selectSubstringMatchingRule(attrName, schema);
for (final ASN1OctetString v : a.getRawValues()) {
if (matchingRule.matchesSubstring(v, subInitial, subAny, subFinal)) {
return true;
}
}
return false;
case FILTER_TYPE_GREATER_OR_EQUAL:
a = entry.getAttribute(attrName, schema);
if (a == null) {
return false;
}
matchingRule = MatchingRule.selectOrderingMatchingRule(attrName, schema);
for (final ASN1OctetString v : a.getRawValues()) {
if (matchingRule.compareValues(v, assertionValue) >= 0) {
return true;
}
}
return false;
case FILTER_TYPE_LESS_OR_EQUAL:
a = entry.getAttribute(attrName, schema);
if (a == null) {
return false;
}
matchingRule = MatchingRule.selectOrderingMatchingRule(attrName, schema);
for (final ASN1OctetString v : a.getRawValues()) {
if (matchingRule.compareValues(v, assertionValue) <= 0) {
return true;
}
}
return false;
case FILTER_TYPE_PRESENCE:
return (entry.hasAttribute(attrName));
case FILTER_TYPE_APPROXIMATE_MATCH:
throw new LDAPException(ResultCode.NOT_SUPPORTED, ERR_FILTER_APPROXIMATE_MATCHING_NOT_SUPPORTED.get());
case FILTER_TYPE_EXTENSIBLE_MATCH:
return extensibleMatchFilterMatchesEntry(entry, schema);
default:
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_FILTER_INVALID_TYPE.get());
}
}
use of com.unboundid.ldap.matchingrules.MatchingRule in project ldapsdk by pingidentity.
the class EntrySorter method compare.
/**
* Compares the provided entries to determine the order in which they should
* be placed in a sorted list.
*
* @param e1 The first entry to be compared.
* @param e2 The second entry to be compared.
*
* @return A negative value if the first entry should be ordered before the
* second, a positive value if the first entry should be ordered
* after the second, or zero if the entries should have an equivalent
* order.
*/
@Override()
public int compare(@NotNull final Entry e1, @NotNull final Entry e2) {
DN parsedDN1 = null;
DN parsedDN2 = null;
if (sortByHierarchy) {
try {
parsedDN1 = e1.getParsedDN();
parsedDN2 = e2.getParsedDN();
if (parsedDN1.isAncestorOf(parsedDN2, false)) {
return -1;
} else if (parsedDN2.isAncestorOf(parsedDN1, false)) {
return 1;
}
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
for (final SortKey k : sortKeys) {
final String attrName = k.getAttributeName();
final Attribute a1 = e1.getAttribute(attrName);
final Attribute a2 = e2.getAttribute(attrName);
if ((a1 == null) || (!a1.hasValue())) {
if ((a2 == null) || (!a2.hasValue())) {
// attribute.
continue;
} else {
// The first entry should be ordered after the second.
return 1;
}
} else {
if ((a2 == null) || (!a2.hasValue())) {
// first entry should be ordered before the second.
return -1;
}
}
final MatchingRule matchingRule = MatchingRule.selectOrderingMatchingRule(attrName, k.getMatchingRuleID(), schema);
if (k.reverseOrder()) {
// Find the largest value for each attribute, and pick the larger of the
// two.
ASN1OctetString v1 = null;
for (final ASN1OctetString s : a1.getRawValues()) {
if (v1 == null) {
v1 = s;
} else {
try {
if (matchingRule.compareValues(s, v1) > 0) {
v1 = s;
}
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
}
ASN1OctetString v2 = null;
for (final ASN1OctetString s : a2.getRawValues()) {
if (v2 == null) {
v2 = s;
} else {
try {
if (matchingRule.compareValues(s, v2) > 0) {
v2 = s;
}
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
}
try {
final int value = matchingRule.compareValues(v2, v1);
if (value != 0) {
return value;
}
} catch (final LDAPException le) {
Debug.debugException(le);
}
} else {
// Find the smallest value for each attribute, and pick the larger of
// the two.
ASN1OctetString v1 = null;
for (final ASN1OctetString s : a1.getRawValues()) {
if (v1 == null) {
v1 = s;
} else {
try {
if (matchingRule.compareValues(s, v1) < 0) {
v1 = s;
}
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
}
ASN1OctetString v2 = null;
for (final ASN1OctetString s : a2.getRawValues()) {
if (v2 == null) {
v2 = s;
} else {
try {
if (matchingRule.compareValues(s, v2) < 0) {
v2 = s;
}
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
}
try {
final int value = matchingRule.compareValues(v1, v2);
if (value != 0) {
return value;
}
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
}
// sort attributes. Compare the DNs as a last resort.
try {
if (parsedDN1 == null) {
parsedDN1 = e1.getParsedDN();
}
if (parsedDN2 == null) {
parsedDN2 = e2.getParsedDN();
}
return parsedDN1.compareTo(parsedDN2);
} catch (final LDAPException le) {
Debug.debugException(le);
final String lowerDN1 = StaticUtils.toLowerCase(e1.getDN());
final String lowerDN2 = StaticUtils.toLowerCase(e2.getDN());
return lowerDN1.compareTo(lowerDN2);
}
}
Aggregations