1313
1414import java .io .IOException ;
1515import java .nio .file .Path ;
16- import java .util .Arrays ;
1716import java .util .Collections ;
1817import java .util .Objects ;
1918
3029import org .opensearch .client .Client ;
3130import org .opensearch .client .node .NodeClient ;
3231import org .opensearch .cluster .service .ClusterService ;
33- import org .opensearch .common .bytes .BytesReference ;
3432import org .opensearch .common .settings .Settings ;
3533import org .opensearch .common .util .concurrent .ThreadContext .StoredContext ;
3634import org .opensearch .common .xcontent .XContentHelper ;
4745import org .opensearch .rest .RestStatus ;
4846import org .opensearch .security .DefaultObjectMapper ;
4947import org .opensearch .security .action .configupdate .ConfigUpdateAction ;
50- import org .opensearch .security .action .configupdate .ConfigUpdateNodeResponse ;
5148import org .opensearch .security .action .configupdate .ConfigUpdateRequest ;
5249import org .opensearch .security .action .configupdate .ConfigUpdateResponse ;
5350import org .opensearch .security .auditlog .AuditLog ;
5451import org .opensearch .security .configuration .AdminDNs ;
5552import org .opensearch .security .configuration .ConfigurationRepository ;
56- import org .opensearch .security .dlic .rest .validation .AbstractConfigurationValidator ;
57- import org .opensearch .security .dlic .rest .validation .AbstractConfigurationValidator .ErrorType ;
53+ import org .opensearch .security .dlic .rest .validation .RequestContentValidator ;
5854import org .opensearch .security .privileges .PrivilegesEvaluator ;
5955import org .opensearch .security .securityconf .DynamicConfigFactory ;
6056import org .opensearch .security .securityconf .impl .CType ;
6864
6965public abstract class AbstractApiAction extends BaseRestHandler {
7066
71- protected final Logger log = LogManager .getLogger (this . getClass () );
67+ private final static Logger LOGGER = LogManager .getLogger (AbstractApiAction . class );
7268
7369 protected final ConfigurationRepository cl ;
7470 protected final ClusterService cs ;
@@ -119,7 +115,7 @@ protected AbstractApiAction(
119115 this .auditLog = auditLog ;
120116 }
121117
122- protected abstract AbstractConfigurationValidator getValidator ( RestRequest request , BytesReference ref , Object ... params );
118+ protected abstract RequestContentValidator createValidator ( final Object ... params );
123119
124120 protected abstract String getResourceName ();
125121
@@ -128,25 +124,22 @@ protected AbstractApiAction(
128124 protected void handleApiRequest (final RestChannel channel , final RestRequest request , final Client client ) throws IOException {
129125
130126 try {
131- // validate additional settings, if any
132- AbstractConfigurationValidator validator = getValidator (request , request .content ());
133- if (!validator .validate ()) {
134- request .params ().clear ();
135- badRequestResponse (channel , validator );
136- return ;
137- }
138127 switch (request .method ()) {
139128 case DELETE :
140- handleDelete (channel , request , client , validator . getContentAsNode () );
129+ handleDelete (channel , request , client , null );
141130 break ;
142131 case POST :
143- handlePost (channel , request , client , validator .getContentAsNode ());
132+ createValidator ().validate (request )
133+ .valid (jsonContent -> handlePost (channel , request , client , jsonContent ))
134+ .error (toXContent -> requestContentInvalid (request , channel , toXContent ));
144135 break ;
145136 case PUT :
146- handlePut (channel , request , client , validator .getContentAsNode ());
137+ createValidator ().validate (request )
138+ .valid (jsonContent -> handlePut (channel , request , client , jsonContent ))
139+ .error (toXContent -> requestContentInvalid (request , channel , toXContent ));
147140 break ;
148141 case GET :
149- handleGet (channel , request , client , validator . getContentAsNode () );
142+ handleGet (channel , request , client , null );
150143 break ;
151144 default :
152145 throw new IllegalArgumentException (request .method () + " not supported" );
@@ -160,6 +153,11 @@ protected void handleApiRequest(final RestChannel channel, final RestRequest req
160153 }
161154 }
162155
156+ protected void requestContentInvalid (final RestRequest request , final RestChannel channel , final ToXContent toXContent ) {
157+ request .params ().clear ();
158+ badRequestResponse (channel , toXContent );
159+ }
160+
163161 protected void handleDelete (final RestChannel channel , final RestRequest request , final Client client , final JsonNode content )
164162 throws IOException {
165163 final String name = request .param ("name" );
@@ -200,16 +198,12 @@ public void onResponse(IndexResponse response) {
200198
201199 protected void handlePut (final RestChannel channel , final RestRequest request , final Client client , final JsonNode content )
202200 throws IOException {
203-
204201 final String name = request .param ("name" );
205-
206202 if (name == null || name .length () == 0 ) {
207203 badRequestResponse (channel , "No " + getResourceName () + " specified." );
208204 return ;
209205 }
210-
211206 final SecurityDynamicConfiguration <?> existingConfiguration = load (getConfigName (), false );
212-
213207 if (existingConfiguration .getSeqNo () < 0 ) {
214208 forbidden (
215209 channel ,
@@ -227,8 +221,8 @@ protected void handlePut(final RestChannel channel, final RestRequest request, f
227221 return ;
228222 }
229223
230- if (log .isTraceEnabled () && content != null ) {
231- log .trace (content .toString ());
224+ if (LOGGER .isTraceEnabled () && content != null ) {
225+ LOGGER .trace (content .toString ());
232226 }
233227
234228 boolean existed = existingConfiguration .exists (name );
@@ -274,28 +268,21 @@ protected boolean hasPermissionsToCreate(
274268 }
275269
276270 protected void handleGet (final RestChannel channel , RestRequest request , Client client , final JsonNode content ) throws IOException {
277-
278271 final String resourcename = request .param ("name" );
279-
280272 final SecurityDynamicConfiguration <?> configuration = load (getConfigName (), true );
281273 filter (configuration );
282-
283274 // no specific resource requested, return complete config
284275 if (resourcename == null || resourcename .length () == 0 ) {
285276
286277 successResponse (channel , configuration );
287278 return ;
288279 }
289-
290280 if (!configuration .exists (resourcename )) {
291281 notFound (channel , "Resource '" + resourcename + "' not found." );
292282 return ;
293283 }
294-
295284 configuration .removeOthers (resourcename );
296285 successResponse (channel , configuration );
297-
298- return ;
299286 }
300287
301288 protected final SecurityDynamicConfiguration <?> load (final CType config , boolean logComplianceEvent ) {
@@ -305,15 +292,6 @@ protected final SecurityDynamicConfiguration<?> load(final CType config, boolean
305292 return DynamicConfigFactory .addStatics (loaded );
306293 }
307294
308- protected final SecurityDynamicConfiguration <?> load (final CType config , boolean logComplianceEvent , boolean acceptInvalid ) {
309- SecurityDynamicConfiguration <?> loaded = cl .getConfigurationsFromIndex (
310- Collections .singleton (config ),
311- logComplianceEvent ,
312- acceptInvalid
313- ).get (config ).deepClone ();
314- return DynamicConfigFactory .addStatics (loaded );
315- }
316-
317295 protected boolean ensureIndexExists () {
318296 if (!cs .state ().metadata ().hasConcreteIndex (this .securityIndexName )) {
319297 return false ;
@@ -434,7 +412,7 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie
434412
435413 // check if .opendistro_security index has been initialized
436414 if (!ensureIndexExists ()) {
437- return channel -> internalErrorResponse (channel , ErrorType . SECURITY_NOT_INITIALIZED .getMessage ());
415+ return channel -> internalErrorResponse (channel , RequestContentValidator . ValidationError . SECURITY_NOT_INITIALIZED .message ());
438416 }
439417
440418 // check if request is authorized
@@ -443,7 +421,7 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie
443421 final User user = (User ) threadPool .getThreadContext ().getTransient (ConfigConstants .OPENDISTRO_SECURITY_USER );
444422 final String userName = user == null ? null : user .getName ();
445423 if (authError != null ) {
446- log .error ("No permission to access REST API: " + authError );
424+ LOGGER .error ("No permission to access REST API: " + authError );
447425 auditLog .logMissingPrivileges (authError , userName , request );
448426 // for rest request
449427 request .params ().clear ();
@@ -465,7 +443,7 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie
465443
466444 handleApiRequest (channel , request , client );
467445 } catch (Exception e ) {
468- log .error ("Error processing request {}" , request , e );
446+ LOGGER .error ("Error processing request {}" , request , e );
469447 try {
470448 channel .sendResponse (new BytesRestResponse (channel , e ));
471449 } catch (IOException ioe ) {
@@ -475,37 +453,6 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie
475453 });
476454 }
477455
478- protected boolean checkConfigUpdateResponse (final ConfigUpdateResponse response ) {
479-
480- final int nodeCount = cs .state ().getNodes ().getNodes ().size ();
481- final int expectedConfigCount = 1 ;
482-
483- boolean success = response .getNodes ().size () == nodeCount ;
484- if (!success ) {
485- log .error ("Expected " + nodeCount + " nodes to return response, but got only " + response .getNodes ().size ());
486- }
487-
488- for (final String nodeId : response .getNodesMap ().keySet ()) {
489- final ConfigUpdateNodeResponse node = response .getNodesMap ().get (nodeId );
490- final boolean successNode = node .getUpdatedConfigTypes () != null && node .getUpdatedConfigTypes ().length == expectedConfigCount ;
491-
492- if (!successNode ) {
493- log .error (
494- "Expected "
495- + expectedConfigCount
496- + " config types for node "
497- + nodeId
498- + " but got only "
499- + Arrays .toString (node .getUpdatedConfigTypes ())
500- );
501- }
502-
503- success = success && successNode ;
504- }
505-
506- return success ;
507- }
508-
509456 protected static XContentBuilder convertToJson (RestChannel channel , ToXContent toxContent ) {
510457 try {
511458 XContentBuilder builder = channel .newBuilder ();
@@ -541,12 +488,12 @@ protected void successResponse(RestChannel channel) {
541488 channel .sendResponse (new BytesRestResponse (RestStatus .OK , builder ));
542489 } catch (IOException e ) {
543490 internalErrorResponse (channel , "Unable to fetch license: " + e .getMessage ());
544- log .error ("Cannot fetch convert license to XContent due to" , e );
491+ LOGGER .error ("Cannot fetch convert license to XContent due to" , e );
545492 }
546493 }
547494
548- protected void badRequestResponse (RestChannel channel , AbstractConfigurationValidator validator ) {
549- channel .sendResponse (new BytesRestResponse (RestStatus .BAD_REQUEST , validator . errorsAsXContent (channel )));
495+ protected void badRequestResponse (RestChannel channel , ToXContent validationResult ) {
496+ channel .sendResponse (new BytesRestResponse (RestStatus .BAD_REQUEST , convertToJson (channel , validationResult )));
550497 }
551498
552499 protected void successResponse (RestChannel channel , String message ) {
@@ -573,10 +520,6 @@ protected void internalErrorResponse(RestChannel channel, String message) {
573520 response (channel , RestStatus .INTERNAL_SERVER_ERROR , message );
574521 }
575522
576- protected void unprocessable (RestChannel channel , String message ) {
577- response (channel , RestStatus .UNPROCESSABLE_ENTITY , message );
578- }
579-
580523 protected void conflict (RestChannel channel , String message ) {
581524 response (channel , RestStatus .CONFLICT , message );
582525 }
0 commit comments