use of com.unboundid.util.ByteStringBuffer in project ldapsdk by pingidentity.
the class Filter method create.
/**
* Creates a new search filter from the specified portion of the provided
* string representation.
*
* @param filterString The string representation of the filter to create.
* @param startPos The position of the first character to consider as
* part of the filter.
* @param endPos The position of the last character to consider as
* part of the filter.
* @param depth The current nesting depth for this filter. It should
* be increased by one for each AND, OR, or NOT filter
* encountered, in order to prevent stack overflow
* errors from excessive recursion.
*
* @return The decoded search filter.
*
* @throws LDAPException If the provided string cannot be decoded as a valid
* LDAP search filter.
*/
@NotNull()
private static Filter create(@NotNull final String filterString, final int startPos, final int endPos, final int depth) throws LDAPException {
if (depth > 100) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_TOO_DEEP.get(filterString));
}
final byte filterType;
final Filter[] filterComps;
final Filter notComp;
final String attrName;
final ASN1OctetString assertionValue;
final ASN1OctetString subInitial;
final ASN1OctetString[] subAny;
final ASN1OctetString subFinal;
final String matchingRuleID;
final boolean dnAttributes;
if (startPos >= endPos) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_TOO_SHORT.get(filterString));
}
int l = startPos;
int r = endPos;
// it should be. If so, then strip off the outer parentheses.
if (filterString.charAt(l) == '(') {
if (filterString.charAt(r) == ')') {
l++;
r--;
} else {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_OPEN_WITHOUT_CLOSE.get(filterString, l, r));
}
} else {
// otherwise we'll raise an error.
if (l != 0) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_MISSING_PARENTHESES.get(filterString, filterString.substring(l, r + 1)));
}
}
// '!'. If we find a parenthesis, then that's an error.
switch(filterString.charAt(l)) {
case '&':
filterType = FILTER_TYPE_AND;
filterComps = parseFilterComps(filterString, l + 1, r, depth + 1);
notComp = null;
attrName = null;
assertionValue = null;
subInitial = null;
subAny = NO_SUB_ANY;
subFinal = null;
matchingRuleID = null;
dnAttributes = false;
break;
case '|':
filterType = FILTER_TYPE_OR;
filterComps = parseFilterComps(filterString, l + 1, r, depth + 1);
notComp = null;
attrName = null;
assertionValue = null;
subInitial = null;
subAny = NO_SUB_ANY;
subFinal = null;
matchingRuleID = null;
dnAttributes = false;
break;
case '!':
filterType = FILTER_TYPE_NOT;
filterComps = NO_FILTERS;
notComp = create(filterString, l + 1, r, depth + 1);
attrName = null;
assertionValue = null;
subInitial = null;
subAny = NO_SUB_ANY;
subFinal = null;
matchingRuleID = null;
dnAttributes = false;
break;
case '(':
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_OPEN_PAREN.get(filterString, l));
case ':':
// This must be an extensible matching filter that starts with a
// dnAttributes flag and/or matching rule ID, and we should parse it
// accordingly.
filterType = FILTER_TYPE_EXTENSIBLE_MATCH;
filterComps = NO_FILTERS;
notComp = null;
attrName = null;
subInitial = null;
subAny = NO_SUB_ANY;
subFinal = null;
// The next element must be either the "dn:{matchingruleid}" or just
// "{matchingruleid}", and it must be followed by a colon.
final int dnMRIDStart = ++l;
while ((l <= r) && (filterString.charAt(l) != ':')) {
l++;
}
if (l > r) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_NO_COLON_AFTER_MRID.get(filterString, startPos));
} else if (l == dnMRIDStart) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_EMPTY_MRID.get(filterString, startPos));
}
final String s = filterString.substring(dnMRIDStart, l++);
if (s.equalsIgnoreCase("dn")) {
dnAttributes = true;
// The colon must be followed by the matching rule ID and another
// colon.
final int mrIDStart = l;
while ((l < r) && (filterString.charAt(l) != ':')) {
l++;
}
if (l >= r) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_NO_COLON_AFTER_MRID.get(filterString, startPos));
}
matchingRuleID = filterString.substring(mrIDStart, l);
if (matchingRuleID.isEmpty()) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_EMPTY_MRID.get(filterString, startPos));
}
if ((++l > r) || (filterString.charAt(l) != '=')) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CHAR_AFTER_MRID.get(filterString, startPos, filterString.charAt(l)));
}
} else {
matchingRuleID = s;
dnAttributes = false;
// The colon must be followed by an equal sign.
if ((l > r) || (filterString.charAt(l) != '=')) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_NO_EQUAL_AFTER_MRID.get(filterString, startPos));
}
}
// Now we should be able to read the value, handling any escape
// characters as we go.
l++;
final ByteStringBuffer valueBuffer = new ByteStringBuffer(r - l + 1);
while (l <= r) {
final char c = filterString.charAt(l);
if (c == '\\') {
l = readEscapedHexString(filterString, ++l, valueBuffer);
} else if (c == '(') {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_OPEN_PAREN.get(filterString, l));
} else if (c == ')') {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CLOSE_PAREN.get(filterString, l));
} else {
valueBuffer.append(c);
l++;
}
}
assertionValue = new ASN1OctetString(valueBuffer.toByteArray());
break;
default:
// We know that it's not an AND, OR, or NOT filter, so we can eliminate
// the variables used only for them.
filterComps = NO_FILTERS;
notComp = null;
// We should now be able to read a non-empty attribute name.
final int attrStartPos = l;
int attrEndPos = -1;
byte tempFilterType = 0x00;
boolean filterTypeKnown = false;
boolean equalFound = false;
attrNameLoop: while (l <= r) {
final char c = filterString.charAt(l++);
switch(c) {
case ':':
tempFilterType = FILTER_TYPE_EXTENSIBLE_MATCH;
filterTypeKnown = true;
attrEndPos = l - 1;
break attrNameLoop;
case '>':
tempFilterType = FILTER_TYPE_GREATER_OR_EQUAL;
filterTypeKnown = true;
attrEndPos = l - 1;
if (l <= r) {
if (filterString.charAt(l++) != '=') {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CHAR_AFTER_GT.get(filterString, startPos, filterString.charAt(l - 1)));
}
} else {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_END_AFTER_GT.get(filterString, startPos));
}
break attrNameLoop;
case '<':
tempFilterType = FILTER_TYPE_LESS_OR_EQUAL;
filterTypeKnown = true;
attrEndPos = l - 1;
if (l <= r) {
if (filterString.charAt(l++) != '=') {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CHAR_AFTER_LT.get(filterString, startPos, filterString.charAt(l - 1)));
}
} else {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_END_AFTER_LT.get(filterString, startPos));
}
break attrNameLoop;
case '~':
tempFilterType = FILTER_TYPE_APPROXIMATE_MATCH;
filterTypeKnown = true;
attrEndPos = l - 1;
if (l <= r) {
if (filterString.charAt(l++) != '=') {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CHAR_AFTER_TILDE.get(filterString, startPos, filterString.charAt(l - 1)));
}
} else {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_END_AFTER_TILDE.get(filterString, startPos));
}
break attrNameLoop;
case '=':
// It could be either an equality, presence, or substring filter.
// We'll need to look at the value to determine that.
attrEndPos = l - 1;
equalFound = true;
break attrNameLoop;
}
}
if (attrEndPos <= attrStartPos) {
if (equalFound) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_EMPTY_ATTR_NAME.get(filterString, startPos));
} else {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_NO_EQUAL_SIGN.get(filterString, startPos));
}
}
attrName = filterString.substring(attrStartPos, attrEndPos);
// variables that are specific to extensible matching filters.
if (filterTypeKnown && (tempFilterType == FILTER_TYPE_EXTENSIBLE_MATCH)) {
if (l > r) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_NO_EQUAL_SIGN.get(filterString, startPos));
}
final char c = filterString.charAt(l++);
if (c == '=') {
matchingRuleID = null;
dnAttributes = false;
} else {
// We have either a matching rule ID or a dnAttributes flag, or
// both. Iterate through the filter until we find the equal sign,
// and then figure out what we have from that.
equalFound = false;
final int substrStartPos = l - 1;
while (l <= r) {
if (filterString.charAt(l++) == '=') {
equalFound = true;
break;
}
}
if (!equalFound) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_NO_EQUAL_SIGN.get(filterString, startPos));
}
final String substr = filterString.substring(substrStartPos, l - 1);
final String lowerSubstr = StaticUtils.toLowerCase(substr);
if (!substr.endsWith(":")) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_CANNOT_PARSE_MRID.get(filterString, startPos));
}
if (lowerSubstr.equals("dn:")) {
matchingRuleID = null;
dnAttributes = true;
} else if (lowerSubstr.startsWith("dn:")) {
matchingRuleID = substr.substring(3, substr.length() - 1);
if (matchingRuleID.isEmpty()) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_EMPTY_MRID.get(filterString, startPos));
}
dnAttributes = true;
} else {
matchingRuleID = substr.substring(0, substr.length() - 1);
dnAttributes = false;
if (matchingRuleID.isEmpty()) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_EMPTY_MRID.get(filterString, startPos));
}
}
}
} else {
matchingRuleID = null;
dnAttributes = false;
}
// based on asterisks in the value.
if (l > r) {
assertionValue = new ASN1OctetString();
if (!filterTypeKnown) {
tempFilterType = FILTER_TYPE_EQUALITY;
}
subInitial = null;
subAny = NO_SUB_ANY;
subFinal = null;
} else if (l == r) {
if (filterTypeKnown) {
switch(filterString.charAt(l)) {
case '*':
case '(':
case ')':
case '\\':
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CHAR_IN_AV.get(filterString, startPos, filterString.charAt(l)));
}
assertionValue = new ASN1OctetString(filterString.substring(l, l + 1));
} else {
final char c = filterString.charAt(l);
switch(c) {
case '*':
tempFilterType = FILTER_TYPE_PRESENCE;
assertionValue = null;
break;
case '\\':
case '(':
case ')':
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CHAR_IN_AV.get(filterString, startPos, filterString.charAt(l)));
default:
tempFilterType = FILTER_TYPE_EQUALITY;
assertionValue = new ASN1OctetString(filterString.substring(l, l + 1));
break;
}
}
subInitial = null;
subAny = NO_SUB_ANY;
subFinal = null;
} else {
if (!filterTypeKnown) {
tempFilterType = FILTER_TYPE_EQUALITY;
}
final int valueStartPos = l;
ASN1OctetString tempSubInitial = null;
ASN1OctetString tempSubFinal = null;
final ArrayList<ASN1OctetString> subAnyList = new ArrayList<>(1);
ByteStringBuffer buffer = new ByteStringBuffer(r - l + 1);
while (l <= r) {
final char c = filterString.charAt(l++);
switch(c) {
case '*':
if (filterTypeKnown) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_ASTERISK.get(filterString, startPos));
} else {
if ((l - 1) == valueStartPos) {
// The first character is an asterisk, so there is no
// subInitial.
} else {
if (tempFilterType == FILTER_TYPE_SUBSTRING) {
// right next to each other, which is invalid.
if (buffer.length() == 0) {
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_DOUBLE_ASTERISK.get(filterString, startPos));
} else {
subAnyList.add(new ASN1OctetString(buffer.toByteArray()));
buffer = new ByteStringBuffer(r - l + 1);
}
} else {
// We haven't yet set the filter type, so the buffer must
// contain the subInitial portion. We also know it's not
// empty because of an earlier check.
tempSubInitial = new ASN1OctetString(buffer.toByteArray());
buffer = new ByteStringBuffer(r - l + 1);
}
}
tempFilterType = FILTER_TYPE_SUBSTRING;
}
break;
case '\\':
l = readEscapedHexString(filterString, l, buffer);
break;
case '(':
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_OPEN_PAREN.get(filterString, l));
case ')':
throw new LDAPException(ResultCode.FILTER_ERROR, ERR_FILTER_UNEXPECTED_CLOSE_PAREN.get(filterString, l));
default:
if (Character.isHighSurrogate(c)) {
if (l <= r) {
final char c2 = filterString.charAt(l);
if (Character.isLowSurrogate(c2)) {
l++;
final int codePoint = Character.toCodePoint(c, c2);
buffer.append(new String(new int[] { codePoint }, 0, 1));
break;
}
}
}
buffer.append(c);
break;
}
}
if ((tempFilterType == FILTER_TYPE_SUBSTRING) && (!buffer.isEmpty())) {
// The buffer must contain the subFinal portion.
tempSubFinal = new ASN1OctetString(buffer.toByteArray());
}
subInitial = tempSubInitial;
subAny = subAnyList.toArray(new ASN1OctetString[subAnyList.size()]);
subFinal = tempSubFinal;
if (tempFilterType == FILTER_TYPE_SUBSTRING) {
assertionValue = null;
} else {
assertionValue = new ASN1OctetString(buffer.toByteArray());
}
}
filterType = tempFilterType;
break;
}
if (startPos == 0) {
return new Filter(filterString, filterType, filterComps, notComp, attrName, assertionValue, subInitial, subAny, subFinal, matchingRuleID, dnAttributes);
} else {
return new Filter(filterString.substring(startPos, endPos + 1), filterType, filterComps, notComp, attrName, assertionValue, subInitial, subAny, subFinal, matchingRuleID, dnAttributes);
}
}
use of com.unboundid.util.ByteStringBuffer in project ldapsdk by pingidentity.
the class GSSAPIBindRequest method generateTLSServerEndPointChannelBindingData.
/**
* Generates an appropriate value to use for TLS server endpoint channel
* binding. See RFC 5929 section 4 for a description of this channel binding
* type.
*
* @param connection The connection used to communicate with the server. It
* must not be {@code null}.
*
* @return The bytes that comprise the TLS server endpoint channel binding
* data.
*
* @throws LDAPException If a problem occurs while attempting to generate
* the channel binding data.
*/
@NotNull()
static byte[] generateTLSServerEndPointChannelBindingData(@NotNull final LDAPConnection connection) throws LDAPException {
// Make sure that the connection has an associated SSL session.
final String channelBindingType = GSSAPIChannelBindingType.TLS_SERVER_END_POINT.getName();
final SSLSession sslSession = connection.getSSLSession();
if (sslSession == null) {
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_GSSAPI_TLS_SERVER_CB_NO_SSL_SESSION.get(channelBindingType));
}
// Get the certificate presented by the server during TLS negotiation.
final Certificate[] serverCertificateChain;
try {
serverCertificateChain = sslSession.getPeerCertificates();
} catch (final Exception e) {
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_GSSAPI_TLS_SERVER_CB_CANNOT_GET_PEER_CERTS.get(channelBindingType, StaticUtils.getExceptionMessage(e)), e);
}
if ((serverCertificateChain == null) || (serverCertificateChain.length == 0)) {
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_GSSAPI_TLS_SERVER_CB_NO_CERTS.get(channelBindingType));
}
if (!(serverCertificateChain[0] instanceof X509Certificate)) {
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_GSSAPI_TLS_SERVER_CB_SERVER_CERT_NOT_X509.get(channelBindingType, serverCertificateChain[0].getType()));
}
final X509Certificate serverCertificate = (X509Certificate) serverCertificateChain[0];
// Determine the appropriate digest algorithm to use for generating the
// channel binding data.
final String signatureAlgorithmName = StaticUtils.toUpperCase(serverCertificate.getSigAlgName());
if (signatureAlgorithmName == null) {
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_GSSAPI_TLS_SERVER_CB_NO_SIG_ALG.get(channelBindingType, serverCertificate.getSubjectX500Principal().getName(X500Principal.RFC2253)));
}
final int withPos = signatureAlgorithmName.indexOf("WITH");
if (withPos <= 0) {
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_GSSAPI_TLS_SERVER_CB_CANNOT_DETERMINE_SIG_DIGEST_ALG.get(channelBindingType, serverCertificate.getSigAlgName(), serverCertificate.getSubjectX500Principal().getName(X500Principal.RFC2253)));
}
String digestAlgorithm = signatureAlgorithmName.substring(0, withPos);
switch(digestAlgorithm) {
case "MD5":
case "SHA":
case "SHA1":
case "SHA-1":
// All of these will be overridden to use the SHA-256 algorithm.
digestAlgorithm = "SHA-256";
break;
case "SHA256":
case "SHA-256":
digestAlgorithm = "SHA-256";
break;
case "SHA384":
case "SHA-384":
digestAlgorithm = "SHA-384";
break;
case "SHA512":
case "SHA-512":
digestAlgorithm = "SHA-512";
break;
default:
// Just use the digest algorithm extracted from the certificate.
break;
}
// Generate a digest of the X.509 certificate using the selected digest
// algorithm.
final byte[] digestBytes;
try {
final MessageDigest messageDigest = CryptoHelper.getMessageDigest(digestAlgorithm);
digestBytes = messageDigest.digest(serverCertificate.getEncoded());
} catch (final Exception e) {
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_GSSAPI_TLS_SERVER_CB_CANNOT_DIGEST_CERT.get(channelBindingType, digestAlgorithm, serverCertificate.getSubjectX500Principal().getName(X500Principal.RFC2253), StaticUtils.getExceptionMessage(e)), e);
}
// The channel binding data will be a concatenation of the channel binding
// type, a colon, and the digest bytes.
final ByteStringBuffer buffer = new ByteStringBuffer();
buffer.append(channelBindingType);
buffer.append(':');
buffer.append(digestBytes);
return buffer.toByteArray();
}
use of com.unboundid.util.ByteStringBuffer in project ldapsdk by pingidentity.
the class DN method toMinimallyEncodedString.
/**
* Retrieves a string representation of this DN with minimal encoding for
* special characters. Only those characters specified in RFC 4514 section
* 2.4 will be escaped. No escaping will be used for non-ASCII characters or
* non-printable ASCII characters.
*
* @return A string representation of this DN with minimal encoding for
* special characters.
*/
@NotNull()
public String toMinimallyEncodedString() {
final ByteStringBuffer buffer = new ByteStringBuffer();
toString(buffer, DNEscapingStrategy.MINIMAL);
return buffer.toString();
}
use of com.unboundid.util.ByteStringBuffer in project ldapsdk by pingidentity.
the class DN method toString.
/**
* Appends a string representation of this DN to the provided buffer.
*
* @param buffer The buffer to which the string representation is
* to be appended.
* @param minimizeEncoding Indicates whether to restrict the encoding of
* special characters to the bare minimum required
* by LDAP (as per RFC 4514 section 2.4). If this
* is {@code true}, then only leading and trailing
* spaces, double quotes, plus signs, commas,
* semicolons, greater-than, less-than, and
* backslash characters will be encoded.
*/
public void toString(@NotNull final StringBuilder buffer, final boolean minimizeEncoding) {
final ByteStringBuffer byteStringBuffer = new ByteStringBuffer();
final DNEscapingStrategy escapingStrategy = (minimizeEncoding ? DNEscapingStrategy.MINIMAL : dnEscapingStrategy);
toString(byteStringBuffer, escapingStrategy);
buffer.append(byteStringBuffer.toString());
}
use of com.unboundid.util.ByteStringBuffer in project ldapsdk by pingidentity.
the class FloatingPointLogFieldSyntax method tokenizeEntireValue.
/**
* {@inheritDoc}
*/
@Override()
public void tokenizeEntireValue(@NotNull final Double value, @NotNull final byte[] pepper, @NotNull final ByteStringBuffer buffer) {
// Get the bytes that comprise the bitwise encoding of the provided value.
final long valueBitsLong = Double.doubleToLongBits(value);
final byte[] valueBytes = { (byte) ((valueBitsLong >> 56) & 0xFFL), (byte) ((valueBitsLong >> 48) & 0xFFL), (byte) ((valueBitsLong >> 40) & 0xFFL), (byte) ((valueBitsLong >> 32) & 0xFFL), (byte) ((valueBitsLong >> 24) & 0xFFL), (byte) ((valueBitsLong >> 16) & 0xFFL), (byte) ((valueBitsLong >> 8) & 0xFFL), (byte) (valueBitsLong & 0xFFL) };
// Concatenate the value bytes and the pepper and compute a SHA-256 digest
// of the result.
final byte[] tokenDigest;
final ByteStringBuffer tempBuffer = getTemporaryBuffer();
try {
tempBuffer.append(valueBytes);
tempBuffer.append(pepper);
tokenDigest = sha256(tempBuffer);
} finally {
releaseTemporaryBuffer(tempBuffer);
}
// Use the first four bytes of the token digest to generate a positive
// integer whose string representation is exactly ten digits long. To do
// this, AND the first byte with 0x7F (which will make it positive) and OR
// the first byte with 0x40 (which will ensure that the value will be
// greater than or equal to 1073741824, and we already know that int
// values cannot exceed 2147483647, so that means it will be exactly ten
// digits).
final int fractionalDigitsInt = (((tokenDigest[0] & 0x7F) | 0x40) << 24) | ((tokenDigest[1] & 0xFF) << 16) | ((tokenDigest[2] & 0xFF) << 8) | (tokenDigest[3] & 0xFF);
// Take the last six digits of the string representation of the generated
// integer.
String fractionalDigits = String.valueOf(fractionalDigitsInt).substring(4);
// the tokenized value won't be confused with a redacted value.
if (fractionalDigits.equals("999999")) {
fractionalDigits = "000000";
}
// Finally, generate the tokenized representation. It will be "-999999."
// followed by the fractional digits generated above.
buffer.append("-999999.");
buffer.append(fractionalDigits);
}
Aggregations