Skip to content

Commit

Permalink
Fixes #146 Add a wrapping audit authenticator that support custom
Browse files Browse the repository at this point in the history
IAuthenticator implementations.
  • Loading branch information
Tobias Eriksson committed Mar 19, 2020
1 parent e4578ac commit b3d54e8
Show file tree
Hide file tree
Showing 36 changed files with 997 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException
case WireTags.VALUE_VERSION_0:
auditRecord = readV0(wire);
break;
case WireTags.VALUE_VERSION_1: // NOPMD
case WireTags.VALUE_VERSION_CURRENT:
auditRecord = readV1(wire);
auditRecord = readBitmappedRecord(wire);
break;
default:
throw new IORuntimeException("Unsupported record version: " + version);
Expand Down Expand Up @@ -75,7 +76,7 @@ private StoredAuditRecord readV0(WireIn wire)
.build();
}

private StoredAuditRecord readV1(WireIn wire)
private StoredAuditRecord readBitmappedRecord(WireIn wire)
{
checkV1Type(wire);
int bitmap = wire.read(WireTags.KEY_FIELDS).int32();
Expand All @@ -93,6 +94,7 @@ private StoredAuditRecord readV1(WireIn wire)
fields.ifSelectedRun(Field.STATUS, () -> recordBuilder.withStatus(readStatus(wire)));
fields.ifSelectedRun(Field.OPERATION, () -> recordBuilder.withOperation(wire.read(WireTags.KEY_OPERATION).text()));
fields.ifSelectedRun(Field.OPERATION_NAKED, () -> recordBuilder.withNakedOperation(wire.read(WireTags.KEY_NAKED_OPERATION).text()));
fields.ifSelectedRun(Field.SUBJECT, () -> recordBuilder.withSubject(wire.read(WireTags.KEY_SUBJECT).text()));

return recordBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ public void writeMarshallable(@NotNull WireOut wire)
actualFields.ifSelectedRun(Field.STATUS, () -> wire.write(WireTags.KEY_STATUS).text(auditRecord.getStatus().name()));
actualFields.ifSelectedRun(Field.OPERATION, () -> wire.write(WireTags.KEY_OPERATION).text(auditRecord.getOperation().getOperationString()));
actualFields.ifSelectedRun(Field.OPERATION_NAKED, () -> wire.write(WireTags.KEY_NAKED_OPERATION).text(auditRecord.getOperation().getNakedOperationString()));
actualFields.ifSelectedRun(Field.SUBJECT, () -> wire.write(WireTags.KEY_SUBJECT).text(auditRecord.getSubject().get()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,23 @@ private FieldFilterFlavorAdapter()

static FieldSelector getFieldsAvailableInRecord(AuditRecord auditRecord, FieldSelector configuredFields)
{
FieldSelector fields = auditRecord.getBatchId().isPresent()
? configuredFields
: configuredFields.withoutField(FieldSelector.Field.BATCH_ID);
FieldSelector fields = configuredFields;

return auditRecord.getClientAddress() == null
? fields.withoutField(FieldSelector.Field.CLIENT_IP).withoutField(FieldSelector.Field.CLIENT_PORT)
: fields;
if (!auditRecord.getBatchId().isPresent())
{
fields = fields.withoutField(FieldSelector.Field.BATCH_ID);
}

if (!auditRecord.getSubject().isPresent())
{
fields = fields.withoutField(FieldSelector.Field.SUBJECT);
}

if (auditRecord.getClientAddress() == null)
{
fields = fields.withoutField(FieldSelector.Field.CLIENT_IP).withoutField(FieldSelector.Field.CLIENT_PORT);
}

return fields;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import java.util.List;

import com.google.common.annotations.VisibleForTesting;

public final class FieldSelector
{
/**
Expand All @@ -36,7 +38,8 @@ public enum Field
STATUS(1 << 5),
OPERATION(1 << 6),
OPERATION_NAKED(1 << 7),
TIMESTAMP(1 << 8);
TIMESTAMP(1 << 8),
SUBJECT(1 << 9);

private final int bit;

Expand Down Expand Up @@ -89,6 +92,17 @@ public boolean isSelected(Field field)
return (bitmap & field.getBit()) > 0;
}

/**
* Toggle a field as selected
* @param field the field to select
* @return a new field selector with the field selected
*/
@VisibleForTesting
FieldSelector withField(Field field)
{
return new FieldSelector(bitmap | field.getBit());
}

/**
* Copies this field selector, but without the provided field selected.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ class WireTags
static final String KEY_STATUS = "status";
static final String KEY_OPERATION = "operation";
static final String KEY_NAKED_OPERATION = "naked_operation";
static final String KEY_SUBJECT = "subject";

static final short VALUE_VERSION_0 = 0;
static final short VALUE_VERSION_1 = 1;
static final short VALUE_VERSION_CURRENT = VALUE_VERSION_1;
static final short VALUE_VERSION_2 = 2;
static final short VALUE_VERSION_CURRENT = VALUE_VERSION_2;
static final String VALUE_TYPE_BATCH_ENTRY = "ecaudit-batch";
static final String VALUE_TYPE_SINGLE_ENTRY = "ecaudit-single";
static final String VALUE_TYPE_AUDIT = "ecaudit";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ public interface AuditRecord
Status getStatus();

AuditOperation getOperation();

Optional<String> getSubject();
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class StoredAuditRecord
private final String operation;
private final String nakedOperation;
private final Long timestamp;
private final String subject;

private StoredAuditRecord(Builder builder)
{
Expand All @@ -46,6 +47,7 @@ private StoredAuditRecord(Builder builder)
this.operation = builder.operation;
this.nakedOperation = builder.nakedOperation;
this.timestamp = builder.timestamp;
this.subject = builder.subject;
}

public Optional<Long> getTimestamp()
Expand Down Expand Up @@ -93,6 +95,11 @@ public Optional<String> getNakedOperation()
return Optional.ofNullable(nakedOperation);
}

public Optional<String> getSubject()
{
return Optional.ofNullable(subject);
}

public static Builder builder()
{
return new Builder();
Expand All @@ -109,6 +116,7 @@ public static class Builder
private String operation;
private String nakedOperation;
private Long timestamp;
private String subject;

public Builder withClientAddress(InetAddress clientAddress)
{
Expand Down Expand Up @@ -164,6 +172,12 @@ public Builder withTimestamp(long timestamp)
return this;
}

public Builder withSubject(String subject)
{
this.subject = subject;
return this;
}

public StoredAuditRecord build()
{
return new StoredAuditRecord(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ public void testReadBatchBatch() throws Exception
assertThatRecordIsSame(actualAuditRecord, expectedValues);
}

@Test
public void testReadSubjectMatch() throws Exception
{
RecordValues expectedValues = defaultValues.butWithSubject("bob-subject");

givenNextRecordIs(expectedValues);

readMarshallable.readMarshallable(wireInMock);

StoredAuditRecord actualAuditRecord = readMarshallable.getAuditRecord();

assertThatRecordIsSame(actualAuditRecord, expectedValues);
}

@Test
public void testReuseMarshallable()
{
Expand Down Expand Up @@ -166,9 +180,19 @@ private void givenNextRecordIs(RecordValues values)
when(typeValueMock.text()).thenReturn(values.getType());
when(wireInMock.read(eq("type"))).thenReturn(typeValueMock);

int fieldsBitmap = values.getBatchId() != null ? FieldSelector.DEFAULT_FIELDS.getBitmap() : FieldSelector.DEFAULT_FIELDS.withoutField(Field.BATCH_ID).getBitmap();
FieldSelector selectedFields = FieldSelector.DEFAULT_FIELDS;
if (values.getBatchId() == null)
{
selectedFields = selectedFields.withoutField(Field.BATCH_ID);
}

if (values.getSubject() != null)
{
selectedFields = selectedFields.withField(Field.SUBJECT);
}

ValueIn fieldsValueMock = mock(ValueIn.class);
when(fieldsValueMock.int32()).thenReturn(fieldsBitmap);
when(fieldsValueMock.int32()).thenReturn(selectedFields.getBitmap());
when(wireInMock.read(eq("fields"))).thenReturn(fieldsValueMock);

ValueIn timestampValueMock = mock(ValueIn.class);
Expand Down Expand Up @@ -205,6 +229,13 @@ private void givenNextRecordIs(RecordValues values)
ValueIn operationValueMock = mock(ValueIn.class);
when(operationValueMock.text()).thenReturn(values.getOperation());
when(wireInMock.read(eq("operation"))).thenReturn(operationValueMock);

if (values.getSubject() != null)
{
ValueIn subjectValueMock = mock(ValueIn.class);
when(subjectValueMock.text()).thenReturn(values.getSubject());
when(wireInMock.read(eq("subject"))).thenReturn(subjectValueMock);
}
}

private void assertThatRecordIsSame(StoredAuditRecord actualAuditRecord, RecordValues expectedValues) throws UnknownHostException
Expand All @@ -218,5 +249,6 @@ private void assertThatRecordIsSame(StoredAuditRecord actualAuditRecord, RecordV
assertThat(actualAuditRecord.getNakedOperation()).isEmpty();
assertThat(actualAuditRecord.getUser()).contains(expectedValues.gethUser());
assertThat(actualAuditRecord.getTimestamp()).contains(expectedValues.getTimestamp());
assertThat(actualAuditRecord.getSubject()).isEqualTo(Optional.ofNullable(expectedValues.getSubject()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ public class TestFieldFilterFlavorAdapter
@Test
public void testGetFieldsAvailableInRecord()
{
AuditRecord recordWithoutClientIPAndBatchId = SimpleAuditRecord.builder().build();
AuditRecord recordWithoutOptionals = SimpleAuditRecord.builder().build();

FieldSelector fields = FieldFilterFlavorAdapter.getFieldsAvailableInRecord(recordWithoutClientIPAndBatchId, FieldSelector.ALL_FIELDS);
FieldSelector fields = FieldFilterFlavorAdapter.getFieldsAvailableInRecord(recordWithoutOptionals, FieldSelector.ALL_FIELDS);

assertThat(fields.isSelected(FieldSelector.Field.CLIENT_IP)).isFalse();
assertThat(fields.isSelected(FieldSelector.Field.CLIENT_PORT)).isFalse();
assertThat(fields.isSelected(FieldSelector.Field.BATCH_ID)).isFalse();
assertThat(fields.isSelected(FieldSelector.Field.SUBJECT)).isFalse();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public void testFieldBitOrder()
assertThat(Field.OPERATION.getBit()).isEqualTo(64);
assertThat(Field.OPERATION_NAKED.getBit()).isEqualTo(128);
assertThat(Field.TIMESTAMP.getBit()).isEqualTo(256);
assertThat(Field.SUBJECT.getBit()).isEqualTo(512);
}

@Test
Expand Down Expand Up @@ -84,7 +85,7 @@ public void testAllFieldsSelected()

assertAllFieldsAreSelected(fields);

assertThat(fields.getBitmap()).isEqualTo(511)
assertThat(fields.getBitmap()).isEqualTo(1023)
.isEqualTo(FieldSelector.ALL_FIELDS.getBitmap());
}

Expand Down Expand Up @@ -147,7 +148,7 @@ public void testInvalidBitmapLowerRange()
public void testInvalidBitmapUpperRange()
{
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> FieldSelector.fromBitmap(512)) // Only 9 fields available == Max 9 bits => max bitmap value 2^9 - 1
.isThrownBy(() -> FieldSelector.fromBitmap(1024)) // Only 10 fields available == Max 10 bits => max bitmap value 2^10 - 1
.withMessageContaining("Bitmap value is out of bounds");
}

Expand Down
Loading

0 comments on commit b3d54e8

Please sign in to comment.