2020import org .elasticsearch .action .support .ActionFilterChain ;
2121import org .elasticsearch .action .support .ContextPreservingActionListener ;
2222import org .elasticsearch .action .support .DestructiveOperations ;
23+ import org .elasticsearch .common .Strings ;
2324import org .elasticsearch .common .util .concurrent .ThreadContext ;
2425import org .elasticsearch .license .LicenseUtils ;
2526import org .elasticsearch .license .XPackLicenseState ;
3334import org .elasticsearch .xpack .core .security .support .Automatons ;
3435import org .elasticsearch .xpack .core .security .user .SystemUser ;
3536import org .elasticsearch .xpack .security .action .SecurityActionMapper ;
37+ import org .elasticsearch .xpack .security .audit .AuditTrailService ;
38+ import org .elasticsearch .xpack .security .audit .AuditUtil ;
3639import org .elasticsearch .xpack .security .authc .AuthenticationService ;
3740import org .elasticsearch .xpack .security .authz .AuthorizationService ;
3841import org .elasticsearch .xpack .security .authz .AuthorizationUtils ;
3942
40- import java .io .IOException ;
4143import java .util .function .Predicate ;
4244
4345public class SecurityActionFilter implements ActionFilter {
@@ -48,17 +50,19 @@ public class SecurityActionFilter implements ActionFilter {
4850
4951 private final AuthenticationService authcService ;
5052 private final AuthorizationService authzService ;
53+ private final AuditTrailService auditTrailService ;
5154 private final SecurityActionMapper actionMapper = new SecurityActionMapper ();
5255 private final XPackLicenseState licenseState ;
5356 private final ThreadContext threadContext ;
5457 private final SecurityContext securityContext ;
5558 private final DestructiveOperations destructiveOperations ;
5659
5760 public SecurityActionFilter (AuthenticationService authcService , AuthorizationService authzService ,
58- XPackLicenseState licenseState , ThreadPool threadPool ,
61+ AuditTrailService auditTrailService , XPackLicenseState licenseState , ThreadPool threadPool ,
5962 SecurityContext securityContext , DestructiveOperations destructiveOperations ) {
6063 this .authcService = authcService ;
6164 this .authzService = authzService ;
65+ this .auditTrailService = auditTrailService ;
6266 this .licenseState = licenseState ;
6367 this .threadContext = threadPool .getThreadContext ();
6468 this .securityContext = securityContext ;
@@ -83,29 +87,19 @@ public <Request extends ActionRequest, Response extends ActionResponse> void app
8387 if (licenseState .isSecurityEnabled ()) {
8488 final ActionListener <Response > contextPreservingListener =
8589 ContextPreservingActionListener .wrapPreservingContext (listener , threadContext );
86- ActionListener <Void > authenticatedListener = ActionListener .wrap (
87- (aVoid ) -> chain .proceed (task , action , request , contextPreservingListener ), contextPreservingListener ::onFailure );
8890 final boolean useSystemUser = AuthorizationUtils .shouldReplaceUserWithSystem (threadContext , action );
8991 try {
9092 if (useSystemUser ) {
9193 securityContext .executeAsUser (SystemUser .INSTANCE , (original ) -> {
92- try {
93- applyInternal (action , request , authenticatedListener );
94- } catch (IOException e ) {
95- listener .onFailure (e );
96- }
94+ applyInternal (task , chain , action , request , contextPreservingListener );
9795 }, Version .CURRENT );
9896 } else if (AuthorizationUtils .shouldSetUserBasedOnActionOrigin (threadContext )) {
9997 AuthorizationUtils .switchUserBasedOnActionOriginAndExecute (threadContext , securityContext , (original ) -> {
100- try {
101- applyInternal (action , request , authenticatedListener );
102- } catch (IOException e ) {
103- listener .onFailure (e );
104- }
98+ applyInternal (task , chain , action , request , contextPreservingListener );
10599 });
106100 } else {
107101 try (ThreadContext .StoredContext ignore = threadContext .newStoredContext (true )) {
108- applyInternal (action , request , authenticatedListener );
102+ applyInternal (task , chain , action , request , contextPreservingListener );
109103 }
110104 }
111105 } catch (Exception e ) {
@@ -130,13 +124,13 @@ public int order() {
130124 return Integer .MIN_VALUE ;
131125 }
132126
133- private <Request extends ActionRequest > void applyInternal (String action , Request request ,
134- ActionListener <Void > listener ) throws IOException {
127+ private <Request extends ActionRequest , Response extends ActionResponse > void applyInternal (Task task ,
128+ ActionFilterChain < Request , Response > chain , String action , Request request , ActionListener <Response > listener ) {
135129 if (CloseIndexAction .NAME .equals (action ) || OpenIndexAction .NAME .equals (action ) || DeleteIndexAction .NAME .equals (action )) {
136130 IndicesRequest indicesRequest = (IndicesRequest ) request ;
137131 try {
138132 destructiveOperations .failDestructive (indicesRequest .indices ());
139- } catch (IllegalArgumentException e ) {
133+ } catch (IllegalArgumentException e ) {
140134 listener .onFailure (e );
141135 return ;
142136 }
@@ -156,7 +150,17 @@ it to the action without an associated user (not via REST or transport - this is
156150 authcService .authenticate (securityAction , request , SystemUser .INSTANCE ,
157151 ActionListener .wrap ((authc ) -> {
158152 if (authc != null ) {
159- authorizeRequest (authc , securityAction , request , listener );
153+ final String requestId = AuditUtil .extractRequestId (threadContext );
154+ assert Strings .hasText (requestId );
155+ authorizeRequest (authc , securityAction , request , ActionListener .delegateFailure (listener ,
156+ (ignore , aVoid ) -> {
157+ chain .proceed (task , action , request , ActionListener .delegateFailure (listener ,
158+ (ignore2 , response ) -> {
159+ auditTrailService .get ().coordinatingActionResponse (requestId , authc , action , request ,
160+ response );
161+ listener .onResponse (response );
162+ }));
163+ }));
160164 } else if (licenseState .isSecurityEnabled () == false ) {
161165 listener .onResponse (null );
162166 } else {
@@ -166,12 +170,11 @@ it to the action without an associated user (not via REST or transport - this is
166170 }
167171
168172 private <Request extends ActionRequest > void authorizeRequest (Authentication authentication , String securityAction , Request request ,
169- ActionListener <Void > listener ) {
173+ ActionListener <Void > listener ) {
170174 if (authentication == null ) {
171175 listener .onFailure (new IllegalArgumentException ("authentication must be non null for authorization" ));
172176 } else {
173- authzService .authorize (authentication , securityAction , request , ActionListener .wrap (ignore -> listener .onResponse (null ),
174- listener ::onFailure ));
177+ authzService .authorize (authentication , securityAction , request , listener );
175178 }
176179 }
177180}
0 commit comments