4141import io .cdap .cdap .etl .proto .connection .SampleResponse ;
4242import io .cdap .cdap .features .Feature ;
4343import io .cdap .cdap .internal .io .SchemaTypeAdapter ;
44+ import io .cdap .cdap .proto .element .EntityType ;
4445import io .cdap .cdap .proto .id .NamespaceId ;
46+ import io .cdap .cdap .proto .security .StandardPermission ;
47+ import io .cdap .cdap .security .spi .authorization .ContextAccessEnforcer ;
4548import io .cdap .wrangler .PropertyIds ;
4649import io .cdap .wrangler .RequestExtractor ;
4750import io .cdap .wrangler .api .DirectiveConfig ;
5861import io .cdap .wrangler .parser .MigrateToV2 ;
5962import io .cdap .wrangler .parser .RecipeCompiler ;
6063import io .cdap .wrangler .proto .BadRequestException ;
64+ import io .cdap .wrangler .proto .id .WorkspaceEntityId ;
6165import io .cdap .wrangler .proto .recipe .v2 .Recipe ;
6266import io .cdap .wrangler .proto .recipe .v2 .RecipeId ;
6367import io .cdap .wrangler .proto .workspace .v2 .Artifact ;
@@ -121,6 +125,7 @@ public class WorkspaceHandler extends AbstractDirectiveHandler {
121125 private WorkspaceStore wsStore ;
122126 private RecipeStore recipeStore ;
123127 private ConnectionDiscoverer discoverer ;
128+ private ContextAccessEnforcer contextAccessEnforcer ;
124129
125130 // Injected by CDAP
126131 @ SuppressWarnings ("unused" )
@@ -132,6 +137,7 @@ public void initialize(SystemHttpServiceContext context) throws Exception {
132137 wsStore = new WorkspaceStore (context );
133138 recipeStore = new RecipeStore (context );
134139 discoverer = new ConnectionDiscoverer (context );
140+ contextAccessEnforcer = context .getContextAccessEnforcer ();
135141 }
136142
137143 @ POST
@@ -144,6 +150,10 @@ public void createWorkspace(HttpServiceRequest request, HttpServiceResponder res
144150 throw new BadRequestException ("Creating workspace in system namespace is currently not supported" );
145151 }
146152
153+ WorkspaceId wsId = new WorkspaceId (ns );
154+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
155+ StandardPermission .CREATE );
156+
147157 WorkspaceCreationRequest creationRequest =
148158 GSON .fromJson (StandardCharsets .UTF_8 .decode (request .getContent ()).toString (), WorkspaceCreationRequest .class );
149159
@@ -171,7 +181,6 @@ public void createWorkspace(HttpServiceRequest request, HttpServiceResponder res
171181 return new StageSpec (plugin .getSchema (), pluginSpec );
172182 }).collect (Collectors .toSet ()), detail .getSupportedSampleTypes (), sampleRequest );
173183
174- WorkspaceId wsId = new WorkspaceId (ns );
175184 long now = System .currentTimeMillis ();
176185 Workspace workspace = Workspace .builder (generateWorkspaceName (wsId , creationRequest .getSampleRequest ().getPath ()),
177186 wsId .getWorkspaceId ())
@@ -190,6 +199,8 @@ public void listWorkspaces(HttpServiceRequest request, HttpServiceResponder resp
190199 if (ns .getName ().equalsIgnoreCase (NamespaceId .SYSTEM .getNamespace ())) {
191200 throw new BadRequestException ("Listing workspaces in system namespace is currently not supported" );
192201 }
202+ contextAccessEnforcer .enforceOnParent (EntityType .SYSTEM_APP_ENTITY , new NamespaceId (ns .getName ()),
203+ StandardPermission .LIST );
193204 responder .sendString (GSON .toJson (new ServiceResponse <>(wsStore .listWorkspaces (ns ))));
194205 });
195206 }
@@ -204,7 +215,10 @@ public void getWorkspace(HttpServiceRequest request, HttpServiceResponder respon
204215 if (ns .getName ().equalsIgnoreCase (NamespaceId .SYSTEM .getNamespace ())) {
205216 throw new BadRequestException ("Getting workspace in system namespace is currently not supported" );
206217 }
207- responder .sendString (GSON .toJson (wsStore .getWorkspace (new WorkspaceId (ns , workspaceId ))));
218+ WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
219+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
220+ StandardPermission .GET );
221+ responder .sendString (GSON .toJson (wsStore .getWorkspace (wsId )));
208222 });
209223 }
210224
@@ -221,11 +235,13 @@ public void updateWorkspace(HttpServiceRequest request, HttpServiceResponder res
221235 if (ns .getName ().equalsIgnoreCase (NamespaceId .SYSTEM .getNamespace ())) {
222236 throw new BadRequestException ("Updating workspace in system namespace is currently not supported" );
223237 }
238+ WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
239+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
240+ StandardPermission .UPDATE );
224241
225242 WorkspaceUpdateRequest updateRequest =
226243 GSON .fromJson (StandardCharsets .UTF_8 .decode (request .getContent ()).toString (), WorkspaceUpdateRequest .class );
227244
228- WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
229245 Workspace newWorkspace = Workspace .builder (wsStore .getWorkspace (wsId ))
230246 .setDirectives (updateRequest .getDirectives ())
231247 .setInsights (updateRequest .getInsights ())
@@ -250,6 +266,9 @@ public void resampleWorkspace(HttpServiceRequest request, HttpServiceResponder r
250266 }
251267
252268 WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
269+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
270+ StandardPermission .UPDATE );
271+
253272 Workspace currentWorkspace = wsStore .getWorkspace (wsId );
254273
255274 String connectionName = currentWorkspace .getSampleSpec () == null ? null :
@@ -294,7 +313,10 @@ public void deleteWorkspace(HttpServiceRequest request, HttpServiceResponder res
294313 if (ns .getName ().equalsIgnoreCase (NamespaceId .SYSTEM .getNamespace ())) {
295314 throw new BadRequestException ("Deleting workspace in system namespace is currently not supported" );
296315 }
297- wsStore .deleteWorkspace (new WorkspaceId (ns , workspaceId ));
316+ WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
317+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
318+ StandardPermission .DELETE );
319+ wsStore .deleteWorkspace (wsId );
298320 responder .sendStatus (HttpURLConnection .HTTP_OK );
299321 });
300322 }
@@ -312,6 +334,10 @@ public void upload(HttpServiceRequest request, HttpServiceResponder responder,
312334 throw new BadRequestException ("Uploading data in system namespace is currently not supported" );
313335 }
314336
337+ WorkspaceId id = new WorkspaceId (ns );
338+ contextAccessEnforcer .enforce (new WorkspaceEntityId (id .getNamespace ().getName (), id .getWorkspaceId ()),
339+ StandardPermission .CREATE );
340+
315341 String name = request .getHeader (PropertyIds .FILE_NAME );
316342 if (name == null ) {
317343 throw new BadRequestException ("Name must be provided in the 'file' header" );
@@ -335,7 +361,6 @@ public void upload(HttpServiceRequest request, HttpServiceResponder responder,
335361 sample .add (new Row (COLUMN_NAME , line ));
336362 }
337363
338- WorkspaceId id = new WorkspaceId (ns );
339364 long now = System .currentTimeMillis ();
340365 Workspace workspace = Workspace .builder (name , id .getWorkspaceId ())
341366 .setCreatedTimeMillis (now ).setUpdatedTimeMillis (now ).build ();
@@ -360,9 +385,11 @@ public void execute(HttpServiceRequest request, HttpServiceResponder responder,
360385 @ PathParam ("id" ) String workspaceId ) {
361386 respond (responder , namespace , ns -> {
362387 validateNamespace (ns , "Executing directives in system namespace is currently not supported" );
388+ WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
389+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
390+ StandardPermission .USE );
363391
364- DirectiveExecutionResponse response = execute (ns , request , new WorkspaceId (ns , workspaceId ),
365- null );
392+ DirectiveExecutionResponse response = execute (ns , request , wsId , null );
366393 responder .sendJson (response );
367394 });
368395 }
@@ -406,6 +433,8 @@ public void specification(HttpServiceRequest request, HttpServiceResponder respo
406433 composite .reload (namespace );
407434
408435 WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
436+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
437+ StandardPermission .GET );
409438 WorkspaceDetail detail = wsStore .getWorkspaceDetail (wsId );
410439 List <String > directives = new ArrayList <>(detail .getWorkspace ().getDirectives ());
411440 UserDirectivesCollector userDirectivesCollector = new UserDirectivesCollector ();
@@ -448,12 +477,13 @@ public void applyRecipe(HttpServiceRequest request, HttpServiceResponder respond
448477 @ PathParam ("recipe-id" ) String recipeIdString ) {
449478 respond (responder , namespace , ns -> {
450479 validateNamespace (ns , "Executing directives in system namespace is currently not supported" );
451-
480+ WorkspaceId wsId = new WorkspaceId (ns , workspaceId );
481+ contextAccessEnforcer .enforce (new WorkspaceEntityId (wsId .getNamespace ().getName (), wsId .getWorkspaceId ()),
482+ StandardPermission .USE );
452483 RecipeId recipeId = RecipeId .builder (ns ).setRecipeId (recipeIdString ).build ();
453484 Recipe recipe = recipeStore .getRecipeById (recipeId );
454485
455- DirectiveExecutionResponse response = execute (ns , request , new WorkspaceId (ns , workspaceId ),
456- recipe .getDirectives ());
486+ DirectiveExecutionResponse response = execute (ns , request , wsId , recipe .getDirectives ());
457487 responder .sendJson (response );
458488 });
459489 }
0 commit comments