This is an automated email from the ASF dual-hosted git repository.

SvenO3 pushed a commit to branch 
improve-rest-authorizations-for-different-ressources
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to 
refs/heads/improve-rest-authorizations-for-different-ressources by this push:
     new d38c38f07e Add new resource for function state
d38c38f07e is described below

commit d38c38f07e438795d4d8235f6ce5e320e6a1c46a
Author: Sven Oehler <[email protected]>
AuthorDate: Thu Jul 2 16:24:43 2026 +0200

    Add new resource for function state
---
 .../apache/streampipes/commons/constants/Envs.java |  1 +
 .../commons/environment/DefaultEnvironment.java    |  5 ++
 .../commons/environment/Environment.java           |  2 +
 .../streampipes/rest/impl/EmailResource.java       |  7 +++
 .../FunctionStateEndpointsEnabledCondition.java    | 34 +++++++++++++
 ...onsResource.java => FunctionStateResource.java} | 57 ++--------------------
 .../streampipes/rest/impl/FunctionsResource.java   | 53 --------------------
 7 files changed, 53 insertions(+), 106 deletions(-)

diff --git 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
index 3cb48ac964..bcd0da514b 100644
--- 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
+++ 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
@@ -48,6 +48,7 @@ public enum Envs {
   SP_OAUTH_ENABLED("SP_OAUTH_ENABLED", "false"),
   SP_OAUTH_REDIRECT_URI("SP_OAUTH_REDIRECT_URI"),
   SP_RESET_ENDPOINT_ENABLED("SP_RESET_ENDPOINT_ENABLED", "false"),
+  SP_FUNCTION_STATE_ENDPOINTS_ENABLED("SP_FUNCTION_STATE_ENDPOINTS_ENABLED", 
"false"),
   SP_DEBUG("SP_DEBUG", "false"),
   SP_MAX_WAIT_TIME_AT_SHUTDOWN("SP_MAX_WAIT_TIME_AT_SHUTDOWN"),
 
diff --git 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/DefaultEnvironment.java
 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/DefaultEnvironment.java
index e0e00d694c..54efba1e33 100644
--- 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/DefaultEnvironment.java
+++ 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/DefaultEnvironment.java
@@ -197,6 +197,11 @@ public class DefaultEnvironment implements Environment {
     return new BooleanEnvironmentVariable(Envs.SP_RESET_ENDPOINT_ENABLED);
   }
 
+  @Override
+  public BooleanEnvironmentVariable getFunctionStateEndpointsEnabled() {
+    return new 
BooleanEnvironmentVariable(Envs.SP_FUNCTION_STATE_ENDPOINTS_ENABLED);
+  }
+
   @Override
   public List<OAuthConfiguration> getOAuthConfigurations() {
     return new OAuthConfigurationParser().parse(System.getenv());
diff --git 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/Environment.java
 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/Environment.java
index c1d50e3057..7045cb46c8 100644
--- 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/Environment.java
+++ 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/Environment.java
@@ -104,6 +104,8 @@ public interface Environment {
 
   BooleanEnvironmentVariable getResetEndpointEnabled();
 
+  BooleanEnvironmentVariable getFunctionStateEndpointsEnabled();
+
   List<OAuthConfiguration> getOAuthConfigurations();
 
   // Messaging
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/EmailResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/EmailResource.java
index 78dec7ee41..c443613ce0 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/EmailResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/EmailResource.java
@@ -18,12 +18,14 @@
 package org.apache.streampipes.rest.impl;
 
 import org.apache.streampipes.mail.MailSender;
+import org.apache.streampipes.model.client.user.DefaultPrivilege;
 import org.apache.streampipes.model.mail.SpEmail;
 import 
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 import org.apache.streampipes.storage.api.system.ISpCoreConfigurationStorage;
 
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -40,6 +42,7 @@ public class EmailResource extends 
AbstractAuthGuardedRestResource {
   }
 
   @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> sendEmail(@RequestBody SpEmail email) {
     var configuration = configurationStorage.get();
     if (configuration.getEmailConfig().isEmailConfigured()) {
@@ -54,4 +57,8 @@ public class EmailResource extends 
AbstractAuthGuardedRestResource {
           "Could not send email - no valid mail configuration provided in 
StreamPipes (go to settings -> mail)");
     }
   }
+
+  public boolean hasWriteAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_WRITE_PIPELINE_VALUE);
+  }
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionStateEndpointsEnabledCondition.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionStateEndpointsEnabledCondition.java
new file mode 100644
index 0000000000..f56fef23bd
--- /dev/null
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionStateEndpointsEnabledCondition.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.rest.impl;
+
+import org.apache.streampipes.commons.environment.Environments;
+
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+public class FunctionStateEndpointsEnabledCondition implements Condition {
+
+  @Override
+  public boolean matches(ConditionContext context,
+                         AnnotatedTypeMetadata metadata) {
+    return 
Environments.getEnvironment().getFunctionStateEndpointsEnabled().getValueOrDefault();
+  }
+}
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionsResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionStateResource.java
similarity index 58%
copy from 
streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionsResource.java
copy to 
streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionStateResource.java
index 7d4df9b8ea..933b591731 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionsResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionStateResource.java
@@ -18,87 +18,38 @@
 
 package org.apache.streampipes.rest.impl;
 
-import org.apache.streampipes.loadbalance.pipeline.ExtensionsLogProvider;
-import org.apache.streampipes.manager.function.FunctionRegistrationService;
-import org.apache.streampipes.model.function.FunctionDefinition;
 import org.apache.streampipes.model.function.FunctionState;
 import org.apache.streampipes.model.message.Notifications;
 import org.apache.streampipes.model.message.SuccessMessage;
-import org.apache.streampipes.model.monitoring.SpLogEntry;
-import org.apache.streampipes.model.monitoring.SpMetricsEntry;
 import 
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
-import org.apache.streampipes.rest.security.AuthConstants;
 import org.apache.streampipes.rest.shared.exception.SpMessageException;
 import org.apache.streampipes.storage.api.function.IFunctionStateStorage;
 
+import org.springframework.context.annotation.Conditional;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 
 @RestController
 @RequestMapping("/api/v2/functions")
-public class FunctionsResource extends AbstractAuthGuardedRestResource {
+@Conditional(FunctionStateEndpointsEnabledCondition.class)
+public class FunctionStateResource extends AbstractAuthGuardedRestResource {
 
   private final IFunctionStateStorage functionStateStorage;
 
-  public FunctionsResource(IFunctionStateStorage functionStateStorage) {
+  public FunctionStateResource(IFunctionStateStorage functionStateStorage) {
     this.functionStateStorage = functionStateStorage;
   }
 
-  @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
-  public ResponseEntity<Collection<FunctionDefinition>> getActiveFunctions() {
-    return ok(FunctionRegistrationService.INSTANCE.getAllFunctions());
-  }
-
-  @GetMapping(path = "{functionId}", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
-  public ResponseEntity<FunctionDefinition> 
getFunction(@PathVariable("functionId") String functionId) {
-    return ok(FunctionRegistrationService.INSTANCE.getFunction(functionId));
-  }
-
-  @PostMapping(
-      produces = MediaType.APPLICATION_JSON_VALUE,
-      consumes = MediaType.APPLICATION_JSON_VALUE
-  )
-  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
-  public ResponseEntity<SuccessMessage> registerFunctions(@RequestBody 
List<FunctionDefinition> functions) {
-    functions.forEach(FunctionRegistrationService.INSTANCE::registerFunction);
-    return ok(Notifications.success("Function successfully registered"));
-  }
-
-  @DeleteMapping(path = "{functionId}", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
-  public ResponseEntity<SuccessMessage> 
deregisterFunction(@PathVariable("functionId") String functionId) {
-    FunctionRegistrationService.INSTANCE.deregisterFunction(functionId);
-    return ok(Notifications.success("Function successfully deregistered"));
-  }
-
-  @GetMapping(path = "{functionId}/metrics", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
-  public ResponseEntity<SpMetricsEntry> 
getFunctionMetrics(@PathVariable("functionId") String functionId) {
-    return 
ok(ExtensionsLogProvider.INSTANCE.getMetricInfosForResource(functionId));
-  }
-
-  @GetMapping(path = "{functionId}/logs")
-  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
-  public ResponseEntity<List<SpLogEntry>> 
getFunctionLogs(@PathVariable("functionId") String functionId) {
-    return 
ok(ExtensionsLogProvider.INSTANCE.getLogInfosForResource(functionId));
-  }
-
   @GetMapping(path = "{functionId}/state", produces = 
MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Map<String, Object>> 
getFunctionState(@PathVariable("functionId") String functionId) {
     var functionState = functionStateStorage.getElementById(functionId);
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionsResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionsResource.java
index 7d4df9b8ea..8f4dd48cca 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionsResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/FunctionsResource.java
@@ -21,17 +21,13 @@ package org.apache.streampipes.rest.impl;
 import org.apache.streampipes.loadbalance.pipeline.ExtensionsLogProvider;
 import org.apache.streampipes.manager.function.FunctionRegistrationService;
 import org.apache.streampipes.model.function.FunctionDefinition;
-import org.apache.streampipes.model.function.FunctionState;
 import org.apache.streampipes.model.message.Notifications;
 import org.apache.streampipes.model.message.SuccessMessage;
 import org.apache.streampipes.model.monitoring.SpLogEntry;
 import org.apache.streampipes.model.monitoring.SpMetricsEntry;
 import 
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 import org.apache.streampipes.rest.security.AuthConstants;
-import org.apache.streampipes.rest.shared.exception.SpMessageException;
-import org.apache.streampipes.storage.api.function.IFunctionStateStorage;
 
-import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -39,25 +35,17 @@ import 
org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 
 @RestController
 @RequestMapping("/api/v2/functions")
 public class FunctionsResource extends AbstractAuthGuardedRestResource {
 
-  private final IFunctionStateStorage functionStateStorage;
-
-  public FunctionsResource(IFunctionStateStorage functionStateStorage) {
-    this.functionStateStorage = functionStateStorage;
-  }
-
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
   @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
   public ResponseEntity<Collection<FunctionDefinition>> getActiveFunctions() {
@@ -98,45 +86,4 @@ public class FunctionsResource extends 
AbstractAuthGuardedRestResource {
   public ResponseEntity<List<SpLogEntry>> 
getFunctionLogs(@PathVariable("functionId") String functionId) {
     return 
ok(ExtensionsLogProvider.INSTANCE.getLogInfosForResource(functionId));
   }
-
-  @GetMapping(path = "{functionId}/state", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  public ResponseEntity<Map<String, Object>> 
getFunctionState(@PathVariable("functionId") String functionId) {
-    var functionState = functionStateStorage.getElementById(functionId);
-    if (functionState != null) {
-      return ok(functionState.getState());
-    } else {
-      throw new SpMessageException(HttpStatus.NOT_FOUND, 
Notifications.error("Function state not found"));
-    }
-  }
-
-  @PutMapping(
-      path = "{functionId}/state",
-      produces = MediaType.APPLICATION_JSON_VALUE,
-      consumes = MediaType.APPLICATION_JSON_VALUE
-  )
-  public ResponseEntity<SuccessMessage> 
persistFunctionState(@PathVariable("functionId") String functionId,
-                                                             @RequestBody 
Map<String, Object> state) {
-    var existingFunctionState = 
functionStateStorage.getElementById(functionId);
-
-    if (existingFunctionState != null) {
-      existingFunctionState.setState(state);
-      functionStateStorage.updateElement(existingFunctionState);
-    } else {
-      functionStateStorage.persist(new FunctionState(functionId, state));
-    }
-
-    return ok(Notifications.success("Function state successfully persisted"));
-  }
-
-  @DeleteMapping(path = "{functionId}/state", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  public ResponseEntity<SuccessMessage> 
deleteFunctionState(@PathVariable("functionId") String functionId) {
-    var existingFunctionState = 
functionStateStorage.getElementById(functionId);
-
-    if (existingFunctionState == null) {
-      throw new SpMessageException(HttpStatus.NOT_FOUND, 
Notifications.error("Function state not found"));
-    }
-
-    functionStateStorage.deleteElementById(functionId);
-    return ok(Notifications.success("Function state successfully deleted"));
-  }
 }

Reply via email to