@@ -84,6 +84,7 @@ protected interface Actions {
84
84
* {@code plugin-security.policy}. So we may as well have gradle set the property.
85
85
*/
86
86
private static final Path AUDIT_LOG_FILE = lookupAuditLog ();
87
+ private static final Path ROLLED_OVER_AUDIT_LOG_FILE = lookupRolledOverAuditLog ();
87
88
88
89
@ SuppressForbidden (reason ="security doesn't work with mock filesystem" )
89
90
private static Path lookupAuditLog () {
@@ -95,6 +96,16 @@ private static Path lookupAuditLog() {
95
96
}
96
97
return Paths .get (auditLogFileString );
97
98
}
99
+
100
+ @ SuppressForbidden (reason ="security doesn't work with mock filesystem" )
101
+ private static Path lookupRolledOverAuditLog () {
102
+ String auditLogFileString = System .getProperty ("tests.audit.yesterday.logfile" );
103
+ if (null == auditLogFileString ) {
104
+ throw new IllegalStateException ("tests.audit.yesterday.logfile must be set to run this test. It should be automatically "
105
+ + "set by gradle." );
106
+ }
107
+ return Paths .get (auditLogFileString );
108
+ }
98
109
99
110
private static boolean oneTimeSetup = false ;
100
111
private static boolean auditFailure = false ;
@@ -107,7 +118,12 @@ private static Path lookupAuditLog() {
107
118
/**
108
119
* How much of the audit log was written before the test started.
109
120
*/
110
- private long auditLogWrittenBeforeTestStart ;
121
+ private static long auditLogWrittenBeforeTestStart ;
122
+
123
+ /**
124
+ * If the audit log file rolled over. This is a rare case possible only at midnight.
125
+ */
126
+ private static boolean auditFileRolledOver = false ;
111
127
112
128
public SqlSecurityTestCase (Actions actions ) {
113
129
this .actions = actions ;
@@ -164,7 +180,7 @@ public void setInitialAuditLogOffset() {
164
180
return null ;
165
181
}
166
182
if (false == Files .isRegularFile (AUDIT_LOG_FILE )) {
167
- throw new IllegalStateException ("expected tests.audit.logfile [" + AUDIT_LOG_FILE + "]to be a plain file but wasn't" );
183
+ throw new IllegalStateException ("expected tests.audit.logfile [" + AUDIT_LOG_FILE + "] to be a plain file but wasn't" );
168
184
}
169
185
try {
170
186
auditLogWrittenBeforeTestStart = Files .size (AUDIT_LOG_FILE );
@@ -556,51 +572,85 @@ public void assertLogs() throws Exception {
556
572
if (sm != null ) {
557
573
sm .checkPermission (new SpecialPermission ());
558
574
}
559
- BufferedReader logReader = AccessController .doPrivileged ((PrivilegedAction <BufferedReader >) () -> {
575
+
576
+ BufferedReader [] logReaders = new BufferedReader [2 ];
577
+ AccessController .doPrivileged ((PrivilegedAction <Void >) () -> {
560
578
try {
561
- return Files .newBufferedReader (AUDIT_LOG_FILE , StandardCharsets .UTF_8 );
579
+ // the audit log file rolled over during the test
580
+ // and we need to consume the rest of the rolled over file plus the new audit log file
581
+ if (auditFileRolledOver == false && Files .exists (ROLLED_OVER_AUDIT_LOG_FILE )) {
582
+ // once the audit file rolled over, it will stay like this
583
+ auditFileRolledOver = true ;
584
+ // the order in the array matters, as the readers will be used in that order
585
+ logReaders [0 ] = Files .newBufferedReader (ROLLED_OVER_AUDIT_LOG_FILE , StandardCharsets .UTF_8 );
586
+ }
587
+ logReaders [1 ] = Files .newBufferedReader (AUDIT_LOG_FILE , StandardCharsets .UTF_8 );
588
+ return null ;
562
589
} catch (IOException e ) {
563
590
throw new RuntimeException (e );
564
591
}
565
592
});
566
- logReader .skip (auditLogWrittenBeforeTestStart );
593
+
594
+ // The "index" is used as a way of reading from both rolled over file and current audit file in order: rolled over file
595
+ // first, then the audit log file. Very rarely we will read from the rolled over file: when the test happened to run
596
+ // at midnight and the audit file rolled over during the test.
597
+ int index ;
598
+ if (logReaders [0 ] != null ) {
599
+ logReaders [0 ].skip (auditLogWrittenBeforeTestStart );
600
+ // start with the rolled over file first
601
+ index = 0 ;
602
+ } else {
603
+ // the current audit log file reader should always be non-null
604
+ logReaders [1 ].skip (auditLogWrittenBeforeTestStart );
605
+ // start with the current audit logging file
606
+ index = 1 ;
607
+ }
567
608
568
609
List <Map <String , Object >> logs = new ArrayList <>();
569
610
String line ;
570
- while ((line = logReader .readLine ()) != null ) {
571
- try {
572
- final Map <String , Object > log = XContentHelper .convertToMap (JsonXContent .jsonXContent , line , false );
573
- if (false == ("access_denied" .equals (log .get ("event.action" ))
574
- || "access_granted" .equals (log .get ("event.action" )))) {
575
- continue ;
576
- }
577
- assertThat (log .containsKey ("action" ), is (true ));
578
- if (false == (SQL_ACTION_NAME .equals (log .get ("action" ))
579
- || GetIndexAction .NAME .equals (log .get ("action" ))
580
- || FieldCapabilitiesAction .NAME .equals (log .get ("action" )))) {
581
- // TODO we may want to extend this and the assertions to SearchAction.NAME as well
582
- continue ;
611
+ while (index < 2 ) {
612
+ line = logReaders [index ].readLine ();
613
+ // when the end of the file is reached, either stop or move to the next reader
614
+ if (line == null ) {
615
+ if (++index == 2 ) {
616
+ break ;
583
617
}
584
- assertThat (log .containsKey ("user.name" ), is (true ));
585
- List <String > indices = new ArrayList <>();
586
- if (log .containsKey ("indices" )) {
587
- indices = (ArrayList <String >) log .get ("indices" );
588
- if ("test_admin" .equals (log .get ("user.name" ))) {
589
- /*
590
- * Sometimes we accidentally sneak access to the security tables. This is fine,
591
- * SQL drops them from the interface. So we might have access to them, but we
592
- * don't show them.
593
- */
594
- indices .remove (".security" );
595
- indices .remove (".security-6" );
618
+ }
619
+ else {
620
+ try {
621
+ final Map <String , Object > log = XContentHelper .convertToMap (JsonXContent .jsonXContent , line , false );
622
+ if (false == ("access_denied" .equals (log .get ("event.action" ))
623
+ || "access_granted" .equals (log .get ("event.action" )))) {
624
+ continue ;
625
+ }
626
+ assertThat (log .containsKey ("action" ), is (true ));
627
+ if (false == (SQL_ACTION_NAME .equals (log .get ("action" ))
628
+ || GetIndexAction .NAME .equals (log .get ("action" ))
629
+ || FieldCapabilitiesAction .NAME .equals (log .get ("action" )))) {
630
+ // TODO we may want to extend this and the assertions to SearchAction.NAME as well
631
+ continue ;
632
+ }
633
+ assertThat (log .containsKey ("user.name" ), is (true ));
634
+ List <String > indices = new ArrayList <>();
635
+ if (log .containsKey ("indices" )) {
636
+ indices = (ArrayList <String >) log .get ("indices" );
637
+ if ("test_admin" .equals (log .get ("user.name" ))) {
638
+ /*
639
+ * Sometimes we accidentally sneak access to the security tables. This is fine,
640
+ * SQL drops them from the interface. So we might have access to them, but we
641
+ * don't show them.
642
+ */
643
+ indices .remove (".security" );
644
+ indices .remove (".security-6" );
645
+ }
596
646
}
647
+ // Use a sorted list for indices for consistent error reporting
648
+ Collections .sort (indices );
649
+ log .put ("indices" , indices );
650
+ logs .add (log );
651
+ } catch (final ElasticsearchParseException e ) {
652
+ throw new IllegalArgumentException ("Unrecognized log: " + line , e );
597
653
}
598
- // Use a sorted list for indices for consistent error reporting
599
- Collections .sort (indices );
600
- log .put ("indices" , indices );
601
- logs .add (log );
602
- } catch (final ElasticsearchParseException e ) {
603
- throw new IllegalArgumentException ("Unrecognized log: " + line , e );
604
654
}
605
655
}
606
656
List <Map <String , Object >> allLogs = new ArrayList <>(logs );
0 commit comments