Skip to content

Commit ff18284

Browse files
committed
update FilteredIgnoredSourceDocValues
1 parent d26a685 commit ff18284

File tree

1 file changed

+80
-51
lines changed
  • x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol

1 file changed

+80
-51
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/FieldSubsetReader.java

Lines changed: 80 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,16 @@
3636
import org.apache.lucene.util.automaton.CharacterRunAutomaton;
3737
import org.elasticsearch.common.bytes.BytesArray;
3838
import org.elasticsearch.common.bytes.BytesReference;
39+
import org.elasticsearch.common.io.stream.ByteArrayStreamInput;
40+
import org.elasticsearch.common.io.stream.BytesStreamOutput;
3941
import org.elasticsearch.common.logging.LoggerMessageFormat;
4042
import org.elasticsearch.common.lucene.index.SequentialStoredFieldsLeafReader;
4143
import org.elasticsearch.common.xcontent.XContentHelper;
4244
import org.elasticsearch.core.Tuple;
4345
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
4446
import org.elasticsearch.index.mapper.IgnoreMalformedStoredValues;
4547
import org.elasticsearch.index.mapper.IgnoredSourceFieldMapper;
48+
import org.elasticsearch.index.mapper.MultiValuedBinaryDocValuesField;
4649
import org.elasticsearch.index.mapper.SourceFieldMapper;
4750
import org.elasticsearch.index.mapper.TextFamilyFieldType;
4851
import org.elasticsearch.transport.Transports;
@@ -306,7 +309,19 @@ public NumericDocValues getNumericDocValues(String field) throws IOException {
306309

307310
@Override
308311
public BinaryDocValues getBinaryDocValues(String field) throws IOException {
309-
return hasField(field) ? super.getBinaryDocValues(field) : null;
312+
if (hasField(field) == false) {
313+
return null;
314+
}
315+
BinaryDocValues dv = super.getBinaryDocValues(field);
316+
if (dv != null
317+
&& IgnoredSourceFieldMapper.NAME.equals(field)
318+
&& ignoredSourceFormat == IgnoredSourceFieldMapper.IgnoredSourceFormat.DOC_VALUES_IGNORED_SOURCE) {
319+
NumericDocValues originalCounts = super.getNumericDocValues(
320+
field + MultiValuedBinaryDocValuesField.SeparateCount.COUNT_FIELD_SUFFIX
321+
);
322+
return new FilteredIgnoredSourceDocValues(dv, originalCounts);
323+
}
324+
return dv;
310325
}
311326

312327
@Override
@@ -321,74 +336,88 @@ public SortedNumericDocValues getSortedNumericDocValues(String field) throws IOE
321336

322337
@Override
323338
public SortedSetDocValues getSortedSetDocValues(String field) throws IOException {
324-
if (hasField(field) == false) {
325-
return null;
326-
}
327-
SortedSetDocValues dv = super.getSortedSetDocValues(field);
328-
if (dv != null
329-
&& IgnoredSourceFieldMapper.NAME.equals(field)
330-
&& ignoredSourceFormat == IgnoredSourceFieldMapper.IgnoredSourceFormat.DOC_VALUES_IGNORED_SOURCE) {
331-
return new FilteredIgnoredSourceDocValues(dv);
332-
}
333-
return dv;
339+
return hasField(field) ? super.getSortedSetDocValues(field) : null;
334340
}
335341

336342
/**
337-
* Wraps {@link SortedSetDocValues} for the {@code _ignored_source} field to apply field-level security filtering.
338-
* Per-document values are decoded, filtered through the DLS field automaton, and re-encoded so that callers
339-
* only observe field values the current user is authorised to see.
343+
* Wraps {@link BinaryDocValues} for the {@code _ignored_source} field to apply field-level security filtering.
344+
* Per-document values are decoded from the {@link MultiValuedBinaryDocValuesField.SeparateCount} multi-value
345+
* binary format, filtered through the DLS field automaton, and re-encoded in the
346+
* {@link MultiValuedBinaryDocValuesField.IntegratedCount} format so that callers only observe field values
347+
* the current user is authorised to see. Returning the integrated-count format allows the caller to treat
348+
* the counts numeric field as absent, avoiding stale count mismatches after filtering.
340349
*/
341-
private class FilteredIgnoredSourceDocValues extends SortedSetDocValues {
342-
private final SortedSetDocValues in;
343-
private List<BytesRef> filteredValues;
344-
private int pos;
350+
private class FilteredIgnoredSourceDocValues extends BinaryDocValues {
351+
private final BinaryDocValues in;
352+
private final NumericDocValues originalCounts;
353+
private BytesRef filteredValue;
345354

346-
FilteredIgnoredSourceDocValues(SortedSetDocValues in) {
355+
FilteredIgnoredSourceDocValues(BinaryDocValues in, NumericDocValues originalCounts) {
347356
this.in = in;
357+
this.originalCounts = originalCounts;
348358
}
349359

350360
@Override
351361
public boolean advanceExact(int target) throws IOException {
362+
filteredValue = null;
352363
if (in.advanceExact(target) == false) {
353364
return false;
354365
}
355-
filteredValues = new ArrayList<>();
356-
int count = in.docValueCount();
357-
for (int i = 0; i < count; i++) {
358-
long ord = in.nextOrd();
359-
BytesRef encoded = in.lookupOrd(ord);
360-
BytesRef filtered = ignoredSourceFormat.filterValue(encoded, v -> filter(v, filter, 0));
361-
if (filtered != null) {
362-
filteredValues.add(BytesRef.deepCopyOf(filtered));
366+
BytesRef bytes = in.binaryValue();
367+
List<BytesRef> filteredValues = new ArrayList<>();
368+
if (originalCounts != null) {
369+
boolean countsAdvanced = originalCounts.advanceExact(target);
370+
assert countsAdvanced;
371+
int count = Math.toIntExact(originalCounts.longValue());
372+
if (count == 1) {
373+
BytesRef filtered = ignoredSourceFormat.filterValue(bytes, v -> filter(v, filter, 0));
374+
if (filtered != null) {
375+
filteredValues.add(BytesRef.deepCopyOf(filtered));
376+
}
377+
} else {
378+
ByteArrayStreamInput input = new ByteArrayStreamInput();
379+
input.reset(bytes.bytes, bytes.offset, bytes.length);
380+
for (int i = 0; i < count; i++) {
381+
int len = input.readVInt();
382+
BytesRef value = new BytesRef(bytes.bytes, input.getPosition(), len);
383+
input.setPosition(input.getPosition() + len);
384+
BytesRef filtered = ignoredSourceFormat.filterValue(value, v -> filter(v, filter, 0));
385+
if (filtered != null) {
386+
filteredValues.add(BytesRef.deepCopyOf(filtered));
387+
}
388+
}
389+
}
390+
} else {
391+
ByteArrayStreamInput input = new ByteArrayStreamInput();
392+
input.reset(bytes.bytes, bytes.offset, bytes.length);
393+
int count = input.readVInt();
394+
for (int i = 0; i < count; i++) {
395+
int len = input.readVInt();
396+
BytesRef value = new BytesRef(bytes.bytes, input.getPosition(), len);
397+
input.setPosition(input.getPosition() + len);
398+
BytesRef filtered = ignoredSourceFormat.filterValue(value, v -> filter(v, filter, 0));
399+
if (filtered != null) {
400+
filteredValues.add(BytesRef.deepCopyOf(filtered));
401+
}
363402
}
364403
}
365-
pos = -1;
366-
return filteredValues.isEmpty() == false;
367-
}
368-
369-
@Override
370-
public int docValueCount() {
371-
return filteredValues == null ? 0 : filteredValues.size();
372-
}
373-
374-
/**
375-
* Returns a sequential local index (0-based) into {@link #filteredValues}, not a global ordinal.
376-
* Callers must pass the returned value directly to {@link #lookupOrd(long)}.
377-
*/
378-
@Override
379-
public long nextOrd() throws IOException {
380-
return ++pos;
381-
}
382-
383-
/** Returns the pre-filtered value at the given local index returned by {@link #nextOrd()}. */
384-
@Override
385-
public BytesRef lookupOrd(long ord) throws IOException {
386-
return filteredValues.get((int) ord);
404+
if (filteredValues.isEmpty()) {
405+
return false;
406+
}
407+
try (BytesStreamOutput out = new BytesStreamOutput()) {
408+
out.writeVInt(filteredValues.size());
409+
for (BytesRef val : filteredValues) {
410+
out.writeVInt(val.length);
411+
out.writeBytes(val.bytes, val.offset, val.length);
412+
}
413+
filteredValue = out.bytes().toBytesRef();
414+
}
415+
return true;
387416
}
388417

389418
@Override
390-
public long getValueCount() {
391-
return filteredValues == null ? 0 : filteredValues.size();
419+
public BytesRef binaryValue() {
420+
return filteredValue;
392421
}
393422

394423
@Override

0 commit comments

Comments
 (0)