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

zehnder pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new da66ce29a4 fix(#3372): Fix time range selector test (#3373)
da66ce29a4 is described below

commit da66ce29a4f74ad1f1810366f3cdea6101074508
Author: Philipp Zehnder <[email protected]>
AuthorDate: Fri Dec 20 14:19:38 2024 +0100

    fix(#3372): Fix time range selector test (#3373)
    
    * fix(#3372): Try to reproduce ci error
    
    * fix(#3372): Only activate one test in GitHub action
    
    * fix(#3372): Only activate one test in GitHub action
    
    * fix(#3372): get localized time independent of time zone
    
    * fix(#3372): Change pr build validation
    
    * fix(#3372): Added further changes to the API and provided two more tests
    
    * fix(#3372): Remove Adapter Exception from AdapterMasterManagementTest
    
    * fix(#3372): Fix to save data view configurations
    
    * fix(#3372): Fix delete adapter tests
    
    * fix(#3372): Extract method to validate sidebar entries
    
    * fix(#3372): WIP share adapter test
    
    * fix(#3372): Change tests to share adapters
    
    * fix(#3372): Change tests to share pipelines
    
    * fix(#3372): Add test for pipeline users
    
    * fix(#3372): Fix test testGroupManagement
---
 .../management/AdapterMasterManagement.java        |  18 +--
 .../management/AdapterMasterManagementTest.java    |  19 +--
 .../apache/streampipes/rest/ResetManagement.java   |  50 +++----
 .../rest/impl/AdapterMonitoringResource.java       |  42 +++++-
 .../streampipes/rest/impl/PipelineMonitoring.java  |  33 ++++-
 .../streampipes/rest/impl/PipelineResource.java    |  43 ++++--
 .../rest/impl/connect/AbstractAdapterResource.java |  15 ++
 .../rest/impl/connect/AdapterResource.java         | 152 +++++++++++++--------
 .../rest/impl/connect/CompactAdapterResource.java  |   6 +-
 .../rest/impl/connect/DescriptionResource.java     |   6 +
 .../rest/impl/connect/GuessResource.java           |  12 ++
 .../impl/connect/RuntimeResolvableResource.java    |   2 +
 .../rest/impl/connect/UnitResource.java            |   7 +-
 .../rest/security/SpPermissionEvaluator.java       |  76 ++++++++---
 ui/cypress/support/utils/GeneralUtils.ts           |   7 +
 ui/cypress/support/utils/UserUtils.ts              |  19 +++
 ui/cypress/support/utils/connect/ConnectUtils.ts   |   9 +-
 ui/cypress/support/utils/pipeline/PipelineBtns.ts  |   8 ++
 ui/cypress/support/utils/pipeline/PipelineUtils.ts |  39 +++++-
 .../PipelineBtns.ts => user/PermissionUtils.ts}    |  27 +++-
 .../support/utils/userInput/StaticPropertyUtils.ts |  10 +-
 .../deleteAdapterWithMultipleUsers.smoke.spec.ts   |  75 ----------
 .../connect/enhancedAdapterDeletion.smoke.spec.ts  |  43 ++++++
 .../tests/datalake/timeRangeSelectors.spec.ts      |   5 +-
 .../pipeline/multiUser/pipelineMultiUserSupport.ts |  49 +++++++
 .../tests/pipeline/pipelineTest.smoke.spec.ts      |  23 +---
 .../pipeline/updatePipelineTest.smoke.spec.ts      |  23 +---
 .../userManagement/testGroupManagement.spec.ts     |  16 +--
 .../userManagement/testUserRoleConnect.spec.ts     |  67 ++++-----
 .../userManagement/testUserRolePipeline.spec.ts    | 116 ++++++++--------
 .../testVariousUserRoles.smoke.spec.ts             |  31 +----
 .../components/sp-table/sp-table.component.html    |   6 +-
 .../existing-adapters.component.html               |   1 +
 .../object-permission-dialog.component.html        |   9 +-
 .../object-permission-dialog.component.ts          |   2 +-
 .../pipeline-overview.component.html               |   4 +-
 36 files changed, 657 insertions(+), 413 deletions(-)

diff --git 
a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
 
b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
index 5c42478431..79310b96b1 100644
--- 
a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
+++ 
b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/AdapterMasterManagement.java
@@ -97,7 +97,7 @@ public class AdapterMasterManagement {
     var storedDescription = new SourcesManagement()
         .createAdapterDataStream(adapterDescription, streamId);
     storedDescription.setCorrespondingAdapterId(adapterId);
-    installDataSource(storedDescription, principalSid, true);
+    installDataSource(storedDescription, principalSid);
     LOG.info("Install source (source URL: {} in backend", 
adapterDescription.getElementId());
   }
 
@@ -141,15 +141,8 @@ public class AdapterMasterManagement {
     LOG.info("Successfully deleted data stream: " + 
adapter.getCorrespondingDataStreamElementId());
   }
 
-  public List<AdapterDescription> getAllAdapterInstances() throws 
AdapterException {
-
-    List<AdapterDescription> allAdapters = adapterInstanceStorage.findAll();
-
-    if (allAdapters == null) {
-      throw new AdapterException("Could not get all adapters");
-    }
-
-    return allAdapters;
+  public List<AdapterDescription> getAllAdapterInstances() {
+    return adapterInstanceStorage.findAll();
   }
 
   public void stopStreamAdapter(String elementId) throws AdapterException {
@@ -198,11 +191,10 @@ public class AdapterMasterManagement {
 
   private void installDataSource(
       SpDataStream stream,
-      String principalSid,
-      boolean publicElement
+      String principalSid
   ) throws AdapterException {
     try {
-      new DataStreamVerifier(stream).verifyAndAdd(principalSid, publicElement);
+      new DataStreamVerifier(stream).verifyAndAdd(principalSid, false);
     } catch (SepaParseException e) {
       LOG.error("Error while installing data source: {}", 
stream.getElementId(), e);
       throw new AdapterException();
diff --git 
a/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
 
b/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
index e1e18324ce..e8095649b8 100644
--- 
a/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
+++ 
b/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/AdapterMasterManagementTest.java
@@ -71,7 +71,7 @@ public class AdapterMasterManagementTest {
   }
 
   @Test
-  public void getAllAdapters_Success() throws AdapterException {
+  public void getAllAdapters_Success() {
     var adapterDescriptions = List.of(new AdapterDescription());
     var adapterStorage = mock(AdapterInstanceStorageImpl.class);
     var resourceManager = mock(AdapterResourceManager.class);
@@ -90,21 +90,4 @@ public class AdapterMasterManagementTest {
     Assertions.assertEquals(1, result.size());
   }
 
-  @Test
-  public void getAllAdapters_Fail() {
-    var adapterStorage = mock(AdapterInstanceStorageImpl.class);
-    var resourceManager = mock(AdapterResourceManager.class);
-    when(adapterStorage.findAll()).thenReturn(null);
-
-    var adapterMasterManagement =
-        new AdapterMasterManagement(
-            adapterStorage,
-            resourceManager,
-            null,
-            AdapterMetricsManager.INSTANCE.getAdapterMetrics()
-        );
-
-    assertThrows(AdapterException.class, 
adapterMasterManagement::getAllAdapterInstances);
-
-  }
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
index caca0dac6c..0c88e461b6 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
@@ -108,24 +108,20 @@ public class ResetManagement {
   private static void stopAndDeleteAllAdapters() {
     AdapterMasterManagement adapterMasterManagement = new 
AdapterMasterManagement(
         StorageDispatcher.INSTANCE.getNoSqlStore()
-            .getAdapterInstanceStorage(),
+                                  .getAdapterInstanceStorage(),
         new SpResourceManager().manageAdapters(),
         new SpResourceManager().manageDataStreams(),
         AdapterMetricsManager.INSTANCE.getAdapterMetrics()
     );
 
-    try {
-      List<AdapterDescription> allAdapters = 
adapterMasterManagement.getAllAdapterInstances();
-      allAdapters.forEach(adapterDescription -> {
-        try {
-          
adapterMasterManagement.deleteAdapter(adapterDescription.getElementId());
-        } catch (AdapterException e) {
-          logger.error("Failed to delete adapter with id: " + 
adapterDescription.getElementId(), e);
-        }
-      });
-    } catch (AdapterException e) {
-      logger.error("Failed to load all adapter descriptions", e);
-    }
+    List<AdapterDescription> allAdapters = 
adapterMasterManagement.getAllAdapterInstances();
+    allAdapters.forEach(adapterDescription -> {
+      try {
+        
adapterMasterManagement.deleteAdapter(adapterDescription.getElementId());
+      } catch (AdapterException e) {
+        logger.error("Failed to delete adapter with id: " + 
adapterDescription.getElementId(), e);
+      }
+    });
   }
 
   private static void deleteAllFiles() {
@@ -154,37 +150,37 @@ public class ResetManagement {
   private static void removeAllDataViewWidgets() {
     var widgetStorage =
         StorageDispatcher.INSTANCE.getNoSqlStore()
-            .getDataExplorerWidgetStorage();
+                                  .getDataExplorerWidgetStorage();
     widgetStorage.findAll()
-        .forEach(widget -> 
widgetStorage.deleteElementById(widget.getElementId()));
+                 .forEach(widget -> 
widgetStorage.deleteElementById(widget.getElementId()));
   }
 
   private static void removeAllDataViews() {
     var dataLakeDashboardStorage =
         StorageDispatcher.INSTANCE.getNoSqlStore()
-            .getDataExplorerDashboardStorage();
+                                  .getDataExplorerDashboardStorage();
     dataLakeDashboardStorage.findAll()
-        .forEach(dashboard -> 
dataLakeDashboardStorage.deleteElementById(dashboard.getElementId()));
+                            .forEach(dashboard -> 
dataLakeDashboardStorage.deleteElementById(dashboard.getElementId()));
   }
 
   private static void removeAllDashboardWidgets() {
     var dashboardWidgetStorage =
         StorageDispatcher.INSTANCE.getNoSqlStore()
-            .getDashboardWidgetStorage();
+                                  .getDashboardWidgetStorage();
     dashboardWidgetStorage.findAll()
-        .forEach(widget -> 
dashboardWidgetStorage.deleteElementById(widget.getElementId()));
+                          .forEach(widget -> 
dashboardWidgetStorage.deleteElementById(widget.getElementId()));
   }
 
   private static void removeAllDashboards() {
     var dashboardStorage = StorageDispatcher.INSTANCE.getNoSqlStore()
-        .getDashboardStorage();
+                                                     .getDashboardStorage();
     dashboardStorage.findAll()
-        .forEach(dashboard -> 
dashboardStorage.deleteElementById(dashboard.getElementId()));
+                    .forEach(dashboard -> 
dashboardStorage.deleteElementById(dashboard.getElementId()));
   }
 
   private static void removeAllAssets(String username) {
     IGenericStorage genericStorage = StorageDispatcher.INSTANCE.getNoSqlStore()
-        .getGenericStorage();
+                                                               
.getGenericStorage();
     try {
       for (Map<String, Object> asset : 
genericStorage.findAll("asset-management")) {
         genericStorage.delete((String) asset.get("_id"), (String) 
asset.get("_rev"));
@@ -211,13 +207,19 @@ public class ResetManagement {
         "asset-management",
         "asset-sites"
     );
-    var genericStorage = 
StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage();
+    var genericStorage = StorageDispatcher.INSTANCE.getNoSqlStore()
+                                                   .getGenericStorage();
 
     appDocTypesToDelete.forEach(docType -> {
       try {
         var allDocs = genericStorage.findAll(docType);
         for (var doc : allDocs) {
-          genericStorage.delete(doc.get("_id").toString(), 
doc.get("_rev").toString());
+          genericStorage.delete(
+              doc.get("_id")
+                 .toString(),
+              doc.get("_rev")
+                 .toString()
+          );
         }
       } catch (IOException e) {
         throw new RuntimeException(e);
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AdapterMonitoringResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AdapterMonitoringResource.java
index 8260c4c9c6..0d7363f781 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AdapterMonitoringResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AdapterMonitoringResource.java
@@ -21,11 +21,13 @@ package org.apache.streampipes.rest.impl;
 
 import 
org.apache.streampipes.manager.monitoring.pipeline.ExtensionsLogProvider;
 import 
org.apache.streampipes.manager.monitoring.pipeline.ExtensionsServiceLogExecutor;
+import org.apache.streampipes.model.client.user.DefaultPrivilege;
 import org.apache.streampipes.model.monitoring.SpLogEntry;
 import org.apache.streampipes.model.monitoring.SpMetricsEntry;
 
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -39,21 +41,51 @@ import java.util.Map;
 @RequestMapping("/api/v2/adapter-monitoring")
 public class AdapterMonitoringResource extends AbstractMonitoringResource {
 
-  @GetMapping(path = "adapter/{elementId}/logs", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  public ResponseEntity<List<SpLogEntry>> 
getLogInfoForAdapter(@PathVariable("elementId") String elementId) {
+  @GetMapping(
+      path = "adapter/{elementId}/logs",
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @PreAuthorize("this.hasReadAuthority() and hasPermission('#elementId', 
'READ')")
+  public ResponseEntity<List<SpLogEntry>> getLogInfoForAdapter(
+      @PathVariable("elementId") String elementId
+  ) {
     return 
ok(ExtensionsLogProvider.INSTANCE.getLogInfosForResource(elementId));
   }
 
-  @GetMapping(path = "adapter/{elementId}/metrics", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  public ResponseEntity<SpMetricsEntry> 
getMetricsInfoForAdapter(@PathVariable("elementId") String elementId) {
+  @GetMapping(
+      path = "adapter/{elementId}/metrics",
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @PreAuthorize("this.hasReadAuthority() and hasPermission('#elementId', 
'READ')")
+  public ResponseEntity<SpMetricsEntry> getMetricsInfoForAdapter(
+      @PathVariable("elementId") String elementId
+  ) {
     return 
ok(ExtensionsLogProvider.INSTANCE.getMetricInfosForResource(elementId));
   }
 
-  @GetMapping(path = "metrics", produces = MediaType.APPLICATION_JSON_VALUE)
+  @GetMapping(
+      path = "metrics",
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @PreAuthorize("this.hasReadAuthority() and hasPermission('#elementId', 
'READ')")
   public ResponseEntity<Map<String, SpMetricsEntry>> getMetricsInfos(
       @RequestParam(value = "filter") List<String> elementIds
   ) {
     new ExtensionsServiceLogExecutor().triggerUpdate();
     return 
ok(ExtensionsLogProvider.INSTANCE.getMetricsInfoForResources(elementIds));
   }
+
+  /**
+   * required by Spring expression
+   */
+  public boolean hasReadAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_READ_ADAPTER_VALUE);
+  }
+
+  /**
+   * required by Spring expression
+   */
+  public boolean hasWriteAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_WRITE_ADAPTER_VALUE);
+  }
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineMonitoring.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineMonitoring.java
index f772754391..135bf5f938 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineMonitoring.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineMonitoring.java
@@ -19,11 +19,13 @@ package org.apache.streampipes.rest.impl;
 
 import 
org.apache.streampipes.manager.monitoring.pipeline.ExtensionsLogProvider;
 import 
org.apache.streampipes.manager.monitoring.pipeline.ExtensionsServiceLogExecutor;
+import org.apache.streampipes.model.client.user.DefaultPrivilege;
 import org.apache.streampipes.model.monitoring.SpLogEntry;
 import org.apache.streampipes.model.monitoring.SpMetricsEntry;
 
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -37,20 +39,43 @@ import java.util.Map;
 @RequestMapping("/api/v2/pipeline-monitoring")
 public class PipelineMonitoring extends AbstractMonitoringResource {
 
-  @GetMapping(value = "/pipeline/{pipelineId}/logs", produces = 
MediaType.APPLICATION_JSON_VALUE)
+  @GetMapping(
+      value = "/pipeline/{pipelineId}/logs",
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @PreAuthorize("this.hasReadAuthority() and hasPermission('#pipelineId', 
'READ')")
   public ResponseEntity<Map<String, List<SpLogEntry>>> getLogInfoForPipeline(
-      @PathVariable("pipelineId") String pipelineId) {
+      @PathVariable("pipelineId") String pipelineId
+  ) {
     return 
ok(ExtensionsLogProvider.INSTANCE.getLogInfosForPipeline(pipelineId));
   }
 
-  @GetMapping(value = "/pipeline/{pipelineId}/metrics", produces = 
MediaType.APPLICATION_JSON_VALUE)
+  @GetMapping(
+      value = "/pipeline/{pipelineId}/metrics",
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @PreAuthorize("this.hasReadAuthority() and hasPermission('#pipelineId', 
'READ')")
   public ResponseEntity<Map<String, SpMetricsEntry>> getMetricsInfoForPipeline(
       @PathVariable("pipelineId") String pipelineId,
-      @RequestParam(value = "forceUpdate", required = false, defaultValue = 
"false") boolean forceUpdate) {
+      @RequestParam(value = "forceUpdate", required = false, defaultValue = 
"false") boolean forceUpdate
+  ) {
     if (forceUpdate) {
       new ExtensionsServiceLogExecutor().triggerUpdate();
     }
     return 
ok(ExtensionsLogProvider.INSTANCE.getMetricInfosForPipeline(pipelineId));
   }
 
+  /**
+   * required by Spring expression
+   */
+  public boolean hasReadAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_READ_PIPELINE_VALUE);
+  }
+
+  /**
+   * required by Spring expression
+   */
+  public boolean hasWriteAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_WRITE_PIPELINE_VALUE);
+  }
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java
index d2dbdf5676..b897a9d599 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java
@@ -25,6 +25,7 @@ import 
org.apache.streampipes.manager.pipeline.PipelineManager;
 import 
org.apache.streampipes.manager.pipeline.compact.CompactPipelineManagement;
 import org.apache.streampipes.manager.recommender.ElementRecommender;
 import org.apache.streampipes.manager.storage.PipelineStorageService;
+import org.apache.streampipes.model.client.user.DefaultPrivilege;
 import org.apache.streampipes.model.message.ErrorMessage;
 import org.apache.streampipes.model.message.Message;
 import org.apache.streampipes.model.message.Notification;
@@ -37,7 +38,6 @@ import 
org.apache.streampipes.model.pipeline.PipelineElementRecommendationMessag
 import org.apache.streampipes.model.pipeline.PipelineOperationStatus;
 import org.apache.streampipes.model.pipeline.compact.CompactPipeline;
 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.rest.shared.exception.SpNotificationException;
 import org.apache.streampipes.storage.management.StorageDispatcher;
@@ -95,7 +95,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
               mediaType = "application/json",
               array = @ArraySchema(schema = @Schema(implementation = 
Pipeline.class))
           )})})
-  @PreAuthorize(AuthConstants.HAS_READ_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasReadAuthority()")
   @PostFilter("hasPermission(filterObject.pipelineId, 'READ')")
   public List<Pipeline> get() {
     return PipelineManager.getAllPipelines();
@@ -105,7 +105,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       path = "{pipelineId}/status",
       produces = MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Get the pipeline status of a given pipeline", tags = 
{"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_READ_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasReadAuthority()")
   public List<PipelineStatusMessage> 
getPipelineStatus(@PathVariable("pipelineId") String pipelineId) {
     return PipelineStatusManager.getPipelineStatus(pipelineId, 5);
   }
@@ -114,15 +114,15 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       path = "/{pipelineId}",
       produces = MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Delete a pipeline with a given id", tags = 
{"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
-  public Message removeOwn(@PathVariable("pipelineId") String pipelineId) {
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#pipelineId', 
'WRITE')")
+  public Message delete(@PathVariable("pipelineId") String pipelineId) {
     PipelineManager.deletePipeline(pipelineId);
     return Notifications.success("Pipeline deleted");
   }
 
   @GetMapping(path = "/{pipelineId}", produces = 
MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Get a specific pipeline with the given id", tags = 
{"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_READ_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasReadAuthority() and hasPermission('#pipelineId', 
'READ')")
   public ResponseEntity<Pipeline> getElement(@PathVariable("pipelineId") 
String pipelineId) {
     Pipeline foundPipeline = PipelineManager.getPipeline(pipelineId);
 
@@ -135,7 +135,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
 
   @GetMapping(path = "/{pipelineId}/start", produces = 
MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Start the pipeline with the given id", tags = 
{"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#pipelineId', 
'WRITE')")
   public ResponseEntity<?> start(@PathVariable("pipelineId") String 
pipelineId) {
     try {
       PipelineOperationStatus status = 
PipelineManager.startPipeline(pipelineId);
@@ -149,7 +149,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
 
   @GetMapping(path = "/{pipelineId}/stop", produces = 
MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Stop the pipeline with the given id", tags = 
{"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#pipelineId', 
'WRITE')")
   public ResponseEntity<?> stop(@PathVariable("pipelineId") String pipelineId,
                                 @RequestParam(value = "forceStop", 
defaultValue = "false") boolean forceStop) {
     try {
@@ -166,7 +166,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Store a new pipeline", tags = {"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<SuccessMessage> addPipeline(@RequestBody Pipeline 
pipeline) {
 
     String pipelineId = PipelineManager.addPipeline(getAuthenticatedUserSid(), 
pipeline);
@@ -180,7 +180,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Convert a pipeline to the compact model", tags = 
{"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<CompactPipeline> convertToCompactPipeline(@RequestBody 
Pipeline pipeline) {
     return ok(compactPipelineManagement.convertPipeline(pipeline));
   }
@@ -190,7 +190,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
   @Hidden
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority()")
   @PostAuthorize("hasPermission(returnObject, 'READ')")
   public PipelineElementRecommendationMessage recommend(@RequestBody Pipeline 
pipeline,
                                                         @PathVariable("recId") 
String baseRecElement) {
@@ -221,7 +221,7 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
   @Hidden
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> validatePipeline(@RequestBody Pipeline pipeline) {
     try {
       return ok(new PipelineVerificationHandlerV2(pipeline).verifyPipeline());
@@ -238,8 +238,8 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       produces = MediaType.APPLICATION_JSON_VALUE,
       consumes = MediaType.APPLICATION_JSON_VALUE)
   @Operation(summary = "Update an existing pipeline", tags = {"Pipeline"})
-  @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE)
-  public ResponseEntity<SuccessMessage> 
overwritePipeline(@PathVariable("pipelineId") String pipelineId,
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#pipelineId', 
'WRITE')")
+  public ResponseEntity<SuccessMessage> 
updatePipeline(@PathVariable("pipelineId") String pipelineId,
                                                           @RequestBody 
Pipeline pipeline) {
     Pipeline storedPipeline = getPipelineStorage().getElementById(pipelineId);
     if (!storedPipeline.isRunning()) {
@@ -264,10 +264,23 @@ public class PipelineResource extends 
AbstractAuthGuardedRestResource {
       "Pipeline"}, responses = {@ApiResponse(content = {
         @Content(mediaType = "application/json",
           array = @ArraySchema(schema = @Schema(implementation = 
Pipeline.class)))})})
-  @PreAuthorize(AuthConstants.HAS_READ_PIPELINE_PRIVILEGE)
+  @PreAuthorize("this.hasReadAuthority()")
   @PostFilter("hasPermission(filterObject.pipelineId, 'READ')")
   public List<Pipeline> 
getPipelinesContainingElement(@PathVariable("elementId") String elementId) {
     return PipelineManager.getPipelinesContainingElements(elementId);
   }
 
+  /**
+   * required by Spring expression
+   */
+  public boolean hasReadAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_READ_PIPELINE_VALUE);
+  }
+
+  /**
+   * required by Spring expression
+   */
+  public boolean hasWriteAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_WRITE_PIPELINE_VALUE);
+  }
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AbstractAdapterResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AbstractAdapterResource.java
index c9623a4df1..dcdd800b6a 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AbstractAdapterResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AbstractAdapterResource.java
@@ -17,6 +17,7 @@
  */
 package org.apache.streampipes.rest.impl.connect;
 
+import org.apache.streampipes.model.client.user.DefaultPrivilege;
 import 
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 
 import java.util.function.Supplier;
@@ -28,4 +29,18 @@ public class AbstractAdapterResource<T> extends 
AbstractAuthGuardedRestResource
   public AbstractAdapterResource(Supplier<T> managementServiceSupplier) {
     this.managementService = managementServiceSupplier.get();
   }
+
+  /**
+   * required by Spring expression
+   */
+  public boolean hasReadAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_READ_ADAPTER_VALUE);
+  }
+
+  /**
+   * required by Spring expression
+   */
+  public boolean hasWriteAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_WRITE_ADAPTER_VALUE);
+  }
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
index 372769a792..b0a7b2c8e6 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
@@ -36,6 +36,7 @@ import org.apache.streampipes.model.util.ElementIdGenerator;
 import org.apache.streampipes.resource.management.PermissionResourceManager;
 import org.apache.streampipes.resource.management.SpResourceManager;
 import org.apache.streampipes.rest.security.AuthConstants;
+import org.apache.streampipes.rest.security.SpPermissionEvaluator;
 import org.apache.streampipes.rest.shared.constants.SpMediaType;
 import org.apache.streampipes.storage.api.IPipelineStorage;
 import org.apache.streampipes.storage.management.StorageDispatcher;
@@ -46,6 +47,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PostFilter;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -70,7 +72,7 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
   public AdapterResource() {
     super(() -> new AdapterMasterManagement(
         StorageDispatcher.INSTANCE.getNoSqlStore()
-            .getAdapterInstanceStorage(),
+                                  .getAdapterInstanceStorage(),
         new SpResourceManager().manageAdapters(),
         new SpResourceManager().manageDataStreams(),
         AdapterMetricsManager.INSTANCE.getAdapterMetrics()
@@ -78,7 +80,7 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
   }
 
   @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<? extends Message> addAdapter(@RequestBody 
AdapterDescription adapterDescription) {
     var principalSid = getAuthenticatedUserSid();
     var username = getAuthenticatedUsername();
@@ -102,14 +104,14 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
       SpMediaType.YAML,
       SpMediaType.YML
   })
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> convertToCompactAdapter(@RequestBody 
AdapterDescription adapterDescription)
       throws Exception {
     return ok(new 
CompactAdapterManagement(List.of()).convertToCompactAdapter(adapterDescription));
   }
 
   @PutMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = 
MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority() and 
hasPermission('#adapterDescription.elementId', 'WRITE')")
   public ResponseEntity<? extends Message> updateAdapter(@RequestBody 
AdapterDescription adapterDescription) {
     var updateManager = new AdapterUpdateManagement(managementService);
     try {
@@ -123,7 +125,7 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
   }
 
   @PutMapping(path = "pipeline-migration-preflight", consumes = 
MediaType.APPLICATION_JSON_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE)
+              produces = MediaType.APPLICATION_JSON_VALUE)
   @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
   public ResponseEntity<List<PipelineUpdateInfo>> 
performPipelineMigrationPreflight(
       @RequestBody AdapterDescription adapterDescription
@@ -135,60 +137,87 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
   }
 
   @GetMapping(path = "/{id}", produces = {MediaType.APPLICATION_JSON_VALUE, 
SpMediaType.YAML, SpMediaType.YML})
-  @PreAuthorize(AuthConstants.HAS_READ_ADAPTER_PRIVILEGE)
-  public ResponseEntity<?> getAdapter(@PathVariable("id") String adapterId,
-                                      @RequestParam(value = "output",
-                                          defaultValue = "full",
-                                          required = false) String outputMode) 
{
+  @PreAuthorize("this.hasReadAuthority()")
+  public ResponseEntity<?> getAdapter(
+      @PathVariable("id") String elementId,
+      @RequestParam(value = "output",
+                    defaultValue = "full",
+                    required = false) String outputMode
+  ) {
 
     try {
-      AdapterDescription adapterDescription = getAdapterDescription(adapterId);
+      var adapterDescription = getAdapterDescription(elementId);
+
+      // This check is done here because the adapter permission is checked 
based on the corresponding data stream
+      // and not based on the element id
+      if (!checkAdapterReadPermission(adapterDescription)) {
+        LOG.error("User is not allowed to read adapter {}", elementId);
+        return ResponseEntity.status(HttpStatus.SC_UNAUTHORIZED)
+                             .build();
+      }
+
       if (outputMode.equalsIgnoreCase("compact")) {
         return ok(toCompactAdapterDescription(adapterDescription));
       } else {
         return ok(adapterDescription);
       }
     } catch (AdapterException e) {
-      LOG.error("Error while getting adapter with id {}", adapterId, e);
+      LOG.error("Error while getting adapter with id {}", elementId, e);
       return fail();
     } catch (Exception e) {
-      LOG.error("Error while transforming adapter {}", adapterId, e);
+      LOG.error("Error while transforming adapter {}", elementId, e);
       return fail();
     }
   }
 
+  /**
+   * Checks if the current user has the permission to read the adapter
+   */
+  private boolean checkAdapterReadPermission(AdapterDescription 
adapterDescription) {
+    var spPermissionEvaluator = new SpPermissionEvaluator();
+    var authentication = SecurityContextHolder.getContext()
+                                              .getAuthentication();
+    return spPermissionEvaluator.hasPermission(
+        authentication,
+        adapterDescription.getCorrespondingDataStreamElementId(),
+        "READ"
+    );
+  }
+
   @PostMapping(path = "/{id}/stop", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
-  public ResponseEntity<?> stopAdapter(@PathVariable("id") String adapterId) {
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#elementId', 
'WRITE')")
+  public ResponseEntity<?> stopAdapter(@PathVariable("id") String elementId) {
     try {
-      managementService.stopStreamAdapter(adapterId);
+      managementService.stopStreamAdapter(elementId);
       return ok(Notifications.success("Adapter started"));
     } catch (AdapterException e) {
-      LOG.error("Could not stop adapter with id {}", adapterId, e);
+      LOG.error("Could not stop adapter with id {}", elementId, e);
       return serverError(SpLogMessage.from(e));
     }
   }
 
   @PostMapping(path = "/{id}/start", produces = 
MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
-  public ResponseEntity<?> startAdapter(@PathVariable("id") String adapterId) {
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#elementId', 
'WRITE')")
+  public ResponseEntity<?> startAdapter(@PathVariable("id") String elementId) {
     try {
-      managementService.startStreamAdapter(adapterId);
+      managementService.startStreamAdapter(elementId);
       return ok(Notifications.success("Adapter stopped"));
     } catch (AdapterException e) {
-      LOG.error("Could not start adapter with id {}", adapterId, e);
+      LOG.error("Could not start adapter with id {}", elementId, e);
       return serverError(SpLogMessage.from(e));
     }
   }
 
   @DeleteMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
-  public ResponseEntity<?> deleteAdapter(@PathVariable("id") String elementId,
-                                         @RequestParam(value = 
"deleteAssociatedPipelines", defaultValue = "false")
-                                         boolean deleteAssociatedPipelines) {
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#elementId', 
'WRITE')")
+  public ResponseEntity<?> deleteAdapter(
+      @PathVariable("id") String elementId,
+      @RequestParam(value = "deleteAssociatedPipelines", defaultValue = 
"false")
+      boolean deleteAssociatedPipelines
+  ) {
     List<String> pipelinesUsingAdapter = getPipelinesUsingAdapter(elementId);
     IPipelineStorage pipelineStorageAPI = 
StorageDispatcher.INSTANCE.getNoSqlStore()
-        .getPipelineStorageAPI();
+                                                                    
.getPipelineStorageAPI();
 
     if (pipelinesUsingAdapter.isEmpty()) {
       try {
@@ -202,22 +231,40 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
       List<String> namesOfPipelinesUsingAdapter = pipelinesUsingAdapter
           .stream()
           .map(pipelineId -> pipelineStorageAPI.getElementById(
-                  pipelineId)
-              .getName())
+                                                   pipelineId)
+                                               .getName())
           .collect(Collectors.toList());
       return ResponseEntity.status(HttpStatus.SC_CONFLICT)
-          .body(String.join(", ", namesOfPipelinesUsingAdapter));
+                           .body(String.join(", ", 
namesOfPipelinesUsingAdapter));
     } else {
       PermissionResourceManager permissionResourceManager = new 
PermissionResourceManager();
       // find out the names of pipelines that have an owner and the owner is 
not the current user
-      List<String> namesOfPipelinesNotOwnedByUser = 
pipelinesUsingAdapter.stream().filter(pipelineId ->
-              
!permissionResourceManager.findForObjectId(pipelineId).stream().findFirst().map(Permission::getOwnerSid)
-                  // if a pipeline has no owner, pretend the owner is the user 
so the user can delete it
-                  
.orElse(this.getAuthenticatedUserSid()).equals(this.getAuthenticatedUserSid()))
-          .map(pipelineId -> 
pipelineStorageAPI.getElementById(pipelineId).getName()).collect(Collectors.toList());
-      boolean isAdmin = 
SecurityContextHolder.getContext().getAuthentication().getAuthorities().stream()
-          .anyMatch(r -> r.getAuthority().equals(
-              DefaultRole.ROLE_ADMIN.name()));
+      List<String> namesOfPipelinesNotOwnedByUser = pipelinesUsingAdapter
+          .stream()
+          .filter(pipelineId ->
+                      !permissionResourceManager.findForObjectId(
+                                                    pipelineId)
+                                                .stream()
+                                                .findFirst()
+                                                .map(
+                                                    Permission::getOwnerSid)
+                                                // if a pipeline has no owner, 
pretend the owner
+                                                // is the user so the user can 
delete it
+                                                .orElse(
+                                                    
this.getAuthenticatedUserSid())
+                                                .equals(
+                                                    
this.getAuthenticatedUserSid()))
+          .map(pipelineId -> pipelineStorageAPI.getElementById(
+                                                   pipelineId)
+                                               .getName())
+          .collect(Collectors.toList());
+      boolean isAdmin = SecurityContextHolder.getContext()
+                                             .getAuthentication()
+                                             .getAuthorities()
+                                             .stream()
+                                             .anyMatch(r -> r.getAuthority()
+                                                             .equals(
+                                                                 
DefaultRole.ROLE_ADMIN.name()));
       // if the user is admin or owns all pipelines using this adapter,
       // the user can delete all associated pipelines and this adapter
       if (isAdmin || namesOfPipelinesNotOwnedByUser.isEmpty()) {
@@ -228,34 +275,31 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
           }
           managementService.deleteAdapter(elementId);
           return ok(Notifications.success("Adapter with id: " + elementId
-              + " and all pipelines using the adapter are deleted."));
+                                              + " and all pipelines using the 
adapter are deleted."));
         } catch (Exception e) {
-          LOG.error("Error while deleting adapter with id "
-              + elementId + " and all pipelines using the adapter", e);
+          LOG.error(
+              "Error while deleting adapter with id "
+                  + elementId + " and all pipelines using the adapter", e
+          );
           return ok(Notifications.error(e.getMessage()));
         }
       } else {
         // otherwise, hint the user the names of pipelines using the adapter 
but not owned by the user
         return ResponseEntity.status(HttpStatus.SC_CONFLICT)
-            .body(String.join(", ", namesOfPipelinesNotOwnedByUser));
+                             .body(String.join(", ", 
namesOfPipelinesNotOwnedByUser));
       }
     }
   }
 
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
-  @PreAuthorize(AuthConstants.HAS_READ_ADAPTER_PRIVILEGE)
-  public ResponseEntity<?> getAllAdapters() {
-    try {
-      return ok(managementService.getAllAdapterInstances());
-    } catch (AdapterException e) {
-      LOG.error("Error while getting all adapters", e);
-      return ResponseEntity.status(500)
-          .build();
-    }
+  @PreAuthorize("this.hasReadAuthority()")
+  @PostFilter("hasPermission(filterObject.correspondingDataStreamElementId, 
'READ')")
+  public List<AdapterDescription> getAllAdapters() {
+    return managementService.getAllAdapterInstances();
   }
 
-  private AdapterDescription getAdapterDescription(String adapterId) throws 
AdapterException {
-    return managementService.getAdapter(adapterId);
+  private AdapterDescription getAdapterDescription(String elementId) throws 
AdapterException {
+    return managementService.getAdapter(elementId);
   }
 
   private CompactAdapter toCompactAdapterDescription(AdapterDescription 
adapterDescription) throws Exception {
@@ -264,8 +308,8 @@ public class AdapterResource extends 
AbstractAdapterResource<AdapterMasterManage
 
   private List<String> getPipelinesUsingAdapter(String adapterId) {
     return StorageDispatcher.INSTANCE.getNoSqlStore()
-        .getPipelineStorageAPI()
-        .getPipelinesUsingAdapter(adapterId);
+                                     .getPipelineStorageAPI()
+                                     .getPipelinesUsingAdapter(adapterId);
   }
 
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
index 0e51f00927..89912db3d8 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java
@@ -30,7 +30,6 @@ import 
org.apache.streampipes.model.connect.adapter.AdapterDescription;
 import org.apache.streampipes.model.connect.adapter.compact.CompactAdapter;
 import org.apache.streampipes.model.message.Notifications;
 import org.apache.streampipes.resource.management.SpResourceManager;
-import org.apache.streampipes.rest.security.AuthConstants;
 import org.apache.streampipes.rest.shared.constants.SpMediaType;
 import org.apache.streampipes.rest.shared.exception.BadRequestException;
 import org.apache.streampipes.storage.management.StorageDispatcher;
@@ -75,7 +74,7 @@ public class CompactAdapterResource extends 
AbstractAdapterResource<AdapterMaste
           SpMediaType.YAML
       }
   )
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> addAdapterCompact(
       @RequestBody CompactAdapter compactAdapter
   ) throws Exception {
@@ -129,7 +128,7 @@ public class CompactAdapterResource extends 
AbstractAdapterResource<AdapterMaste
           "application/yml"
       }
   )
-  @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE)
+  @PreAuthorize("this.hasWriteAuthority() and hasPermission('#elementId', 
'WRITE')")
   public ResponseEntity<?> updateAdapterCompact(
       @PathVariable("id") String elementId,
       @RequestBody CompactAdapter compactAdapter
@@ -164,4 +163,5 @@ public class CompactAdapterResource extends 
AbstractAdapterResource<AdapterMaste
     var generators = adapterGenerationSteps.getGenerators();
     return new 
CompactAdapterManagement(generators).convertToAdapterDescription(compactAdapter,
 existingAdapter);
   }
+
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java
index 7d8f562034..d26eaf951a 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java
@@ -31,6 +31,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 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;
@@ -53,6 +54,7 @@ public class DescriptionResource extends 
AbstractAdapterResource<DescriptionMana
   }
 
   @GetMapping(path = "/adapters", produces = MediaType.APPLICATION_JSON_VALUE)
+  @PreAuthorize("this.hasReadAuthority()")
   public ResponseEntity<List<AdapterDescription>> getAdapters() {
     List<AdapterDescription> result = managementService.getAdapters();
 
@@ -60,6 +62,7 @@ public class DescriptionResource extends 
AbstractAdapterResource<DescriptionMana
   }
 
   @GetMapping(path = "/{id}/assets", produces = "application/zip")
+  @PreAuthorize("this.hasReadAuthority()")
   public ResponseEntity<?> getAdapterAssets(@PathVariable("id") String id) {
     try {
       String result = null;
@@ -87,6 +90,7 @@ public class DescriptionResource extends 
AbstractAdapterResource<DescriptionMana
   }
 
   @GetMapping(path = "/{id}/assets/icon", produces = "image/png")
+  @PreAuthorize("this.hasReadAuthority()")
   public ResponseEntity<?> getAdapterIconAsset(@PathVariable("id") String id) {
     try {
 
@@ -115,6 +119,7 @@ public class DescriptionResource extends 
AbstractAdapterResource<DescriptionMana
   }
 
   @GetMapping(path = "/{id}/assets/documentation", produces = 
MediaType.TEXT_PLAIN_VALUE)
+  @PreAuthorize("this.hasReadAuthority()")
   public ResponseEntity<?> getAdapterDocumentationAsset(@PathVariable("id") 
String id) {
     try {
       String result = null;
@@ -142,6 +147,7 @@ public class DescriptionResource extends 
AbstractAdapterResource<DescriptionMana
   }
 
   @DeleteMapping(path = "{adapterId}")
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> deleteAdapter(@PathVariable("adapterId") String 
adapterId) {
     try {
       this.managementService.deleteAdapterDescription(adapterId);
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
index ddb51a9a92..f49dfaa7c9 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
@@ -22,6 +22,7 @@ import 
org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableExce
 import org.apache.streampipes.commons.exceptions.connect.ParseException;
 import org.apache.streampipes.connect.management.management.GuessManagement;
 import 
org.apache.streampipes.extensions.api.connect.exception.WorkerAdapterException;
+import org.apache.streampipes.model.client.user.DefaultPrivilege;
 import org.apache.streampipes.model.connect.adapter.AdapterDescription;
 import org.apache.streampipes.model.connect.guess.AdapterEventPreview;
 import org.apache.streampipes.model.connect.guess.GuessSchema;
@@ -32,6 +33,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 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;
@@ -53,6 +55,7 @@ public class GuessResource extends 
AbstractAdapterResource<GuessManagement> {
       path = "/schema",
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> guessSchema(@RequestBody AdapterDescription 
adapterDescription) {
 
     try {
@@ -74,6 +77,7 @@ public class GuessResource extends 
AbstractAdapterResource<GuessManagement> {
       path = "/schema/preview",
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> getAdapterEventPreview(@RequestBody 
AdapterEventPreview previewRequest) {
     try {
       return ok(managementService.performAdapterEventPreview(previewRequest));
@@ -81,5 +85,13 @@ public class GuessResource extends 
AbstractAdapterResource<GuessManagement> {
       return badRequest();
     }
   }
+
+  /**
+   * required by Spring expression
+   */
+  public boolean hasWriteAuthority() {
+    return 
isAdminOrHasAnyAuthority(DefaultPrivilege.Constants.PRIVILEGE_WRITE_ADAPTER_VALUE);
+  }
+
 }
 
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
index ce66dbeed8..cf30a41758 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
@@ -38,6 +38,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -67,6 +68,7 @@ public class RuntimeResolvableResource extends 
AbstractAdapterResource<WorkerAdm
       path = "{id}/configurations",
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
+  @PreAuthorize("this.hasWriteAuthority()")
   public ResponseEntity<?> fetchConfigurations(@PathVariable("id") String 
appId,
                                                @RequestBody 
RuntimeOptionsRequest runtimeOptionsRequest) {
 
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/UnitResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/UnitResource.java
index 1efb585e82..db2edcdd6c 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/UnitResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/UnitResource.java
@@ -26,6 +26,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -48,6 +49,7 @@ public class UnitResource extends 
AbstractAdapterResource<UnitMasterManagement>
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
   )
+  @PreAuthorize("this.hasReadAuthority()")
   public ResponseEntity<?> getFittingUnits(@RequestBody UnitDescription 
unitDescription) {
     try {
       String resultingJson = 
managementService.getFittingUnits(unitDescription);
@@ -59,8 +61,9 @@ public class UnitResource extends 
AbstractAdapterResource<UnitMasterManagement>
   }
 
   @GetMapping(path = "/units",
-      produces = MediaType.APPLICATION_JSON_VALUE)
-  public ResponseEntity<List<UnitDescription>> getAllUnits(){
+              produces = MediaType.APPLICATION_JSON_VALUE)
+  @PreAuthorize("this.hasReadAuthority()")
+  public ResponseEntity<List<UnitDescription>> getAllUnits() {
     List<UnitDescription> unitDescriptions = 
managementService.getAllUnitDescriptions();
     return ok(unitDescriptions);
   }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/security/SpPermissionEvaluator.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/security/SpPermissionEvaluator.java
index 08ee86cc46..86c0a74d80 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/security/SpPermissionEvaluator.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/security/SpPermissionEvaluator.java
@@ -35,39 +35,71 @@ import java.util.function.Predicate;
 @Configuration
 public class SpPermissionEvaluator implements PermissionEvaluator {
 
+  /**
+   * Evaluates whether the user has the necessary permissions for a given 
resource.
+   *
+   * @param authentication     The authentication object containing the user's 
credentials.
+   * @param targetDomainObject The resource being accessed, which can be an 
instance of
+   *                           PipelineElementRecommendationMessage or a 
String representing the resource ID.
+   * @param permission         Is not used in this implementation.
+   * @return true if the user has the necessary permissions, false otherwise.
+   */
   @Override
-  public boolean hasPermission(Authentication auth, Object o, Object 
permission) {
-    PrincipalUserDetails<?> userDetails = getUserDetails(auth);
-    if (o instanceof PipelineElementRecommendationMessage) {
-      return isAdmin(userDetails) || filterRecommendation(auth, 
(PipelineElementRecommendationMessage) o);
+  public boolean hasPermission(
+      Authentication authentication,
+      Object targetDomainObject,
+      Object permission
+  ) {
+    PrincipalUserDetails<?> userDetails = getUserDetails(authentication);
+    if (targetDomainObject instanceof PipelineElementRecommendationMessage) {
+      return isAdmin(userDetails) || filterRecommendation(
+          authentication,
+          (PipelineElementRecommendationMessage) targetDomainObject
+      );
     } else {
-      String objectInstanceId = (String) o;
+      String objectInstanceId = (String) targetDomainObject;
       if (isAdmin(userDetails)) {
         return true;
       }
-      return hasPermission(auth, objectInstanceId);
+      return hasPermission(authentication, objectInstanceId);
     }
   }
 
-  private boolean filterRecommendation(Authentication auth, 
PipelineElementRecommendationMessage message) {
-    Predicate<PipelineElementRecommendation> isForbidden = r -> 
!hasPermission(auth, r.getElementId());
-    message.getPossibleElements().removeIf(isForbidden);
-
-    return true;
-  }
-
+  /**
+   * Evaluates whether the user has the necessary permissions for a given 
resource.
+   *
+   * @param authentication The authentication object containing the user's 
credentials.
+   * @param targetId       The ID of the resource being accessed.
+   * @param targetType     Is not used in this implementation.
+   * @param permission     Is not used in this implementation.
+   * @return true if the user has the necessary permissions, false otherwise.
+   */
   @Override
-  public boolean hasPermission(Authentication auth, Serializable serializable, 
String s, Object permission) {
-    PrincipalUserDetails<?> userDetails = getUserDetails(auth);
+  public boolean hasPermission(
+      Authentication authentication,
+      Serializable targetId,
+      String targetType,
+      Object permission
+  ) {
+    PrincipalUserDetails<?> userDetails = getUserDetails(authentication);
     if (isAdmin(userDetails)) {
       return true;
     }
-    return hasPermission(auth, serializable.toString());
+    return hasPermission(authentication, targetId.toString());
+  }
+
+  private boolean filterRecommendation(Authentication auth, 
PipelineElementRecommendationMessage message) {
+    Predicate<PipelineElementRecommendation> isForbidden = r -> 
!hasPermission(auth, r.getElementId());
+    message.getPossibleElements()
+           .removeIf(isForbidden);
+
+    return true;
   }
 
   private boolean hasPermission(Authentication auth, String objectInstanceId) {
     return isPublicElement(objectInstanceId)
-        || 
getUserDetails(auth).getAllObjectPermissions().contains(objectInstanceId);
+        || getUserDetails(auth).getAllObjectPermissions()
+                               .contains(objectInstanceId);
   }
 
   private PrincipalUserDetails<?> getUserDetails(Authentication 
authentication) {
@@ -76,14 +108,18 @@ public class SpPermissionEvaluator implements 
PermissionEvaluator {
 
   private boolean isPublicElement(String objectInstanceId) {
     List<Permission> permissions =
-        
StorageDispatcher.INSTANCE.getNoSqlStore().getPermissionStorage().getUserPermissionsForObject(objectInstanceId);
-    return permissions.size() > 0 && permissions.get(0).isPublicElement();
+        StorageDispatcher.INSTANCE.getNoSqlStore()
+                                  .getPermissionStorage()
+                                  
.getUserPermissionsForObject(objectInstanceId);
+    return permissions.size() > 0 && permissions.get(0)
+                                                .isPublicElement();
   }
 
   private boolean isAdmin(PrincipalUserDetails<?> userDetails) {
     return userDetails
         .getAuthorities()
         .stream()
-        .anyMatch(a -> 
a.getAuthority().equals(DefaultRole.Constants.ROLE_ADMIN_VALUE));
+        .anyMatch(a -> a.getAuthority()
+                        .equals(DefaultRole.Constants.ROLE_ADMIN_VALUE));
   }
 }
diff --git a/ui/cypress/support/utils/GeneralUtils.ts 
b/ui/cypress/support/utils/GeneralUtils.ts
index 8db505e32b..9b0186b1f6 100644
--- a/ui/cypress/support/utils/GeneralUtils.ts
+++ b/ui/cypress/support/utils/GeneralUtils.ts
@@ -20,4 +20,11 @@ export class GeneralUtils {
     public static tab(identifier: string) {
         return cy.dataCy(`tab-${identifier}`).click();
     }
+
+    public static validateAmountOfNavigationIcons(expected: number) {
+        cy.dataCy('navigation-icon', { timeout: 10000 }).should(
+            'have.length',
+            expected,
+        );
+    }
 }
diff --git a/ui/cypress/support/utils/UserUtils.ts 
b/ui/cypress/support/utils/UserUtils.ts
index b91f046f07..3f966450db 100644
--- a/ui/cypress/support/utils/UserUtils.ts
+++ b/ui/cypress/support/utils/UserUtils.ts
@@ -62,6 +62,25 @@ export class UserUtils {
         cy.dataCy('sp-element-edit-user-save').click();
     }
 
+    /**
+     * Create a new user with the specified roles and a default password to 
the system.
+     *
+     * @param name - The name of the user to be added.
+     * @param roles - The roles to be assigned to the new user.
+     */
+    public static createUser(name: string, ...roles: UserRole[]): User {
+        const userBuilder = 
UserBuilder.create(`${name}@streampipes.apache.org`)
+            .setName(name)
+            .setPassword('default');
+
+        roles.forEach(role => userBuilder.addRole(role));
+
+        const user = userBuilder.build();
+
+        this.addUser(user);
+        return user;
+    }
+
     public static switchUser(user: User) {
         cy.logout();
         cy.visit('#/login');
diff --git a/ui/cypress/support/utils/connect/ConnectUtils.ts 
b/ui/cypress/support/utils/connect/ConnectUtils.ts
index 0a0eae22c1..52d2ec6c88 100644
--- a/ui/cypress/support/utils/connect/ConnectUtils.ts
+++ b/ui/cypress/support/utils/connect/ConnectUtils.ts
@@ -440,6 +440,13 @@ export class ConnectUtils {
 
     public static checkAmountOfAdapters(amount: number) {
         ConnectUtils.goToConnect();
-        ConnectBtns.deleteAdapter().should('have.length', amount);
+        if (amount === 0) {
+            // The wait is needed because the default value is the 
no-table-entries element.
+            // It must be waited till the data is loaded. Once a better 
solution is found, this can be removed.
+            cy.wait(1000);
+            cy.dataCy('no-table-entries').should('be.visible');
+        } else {
+            ConnectBtns.deleteAdapter().should('have.length', amount);
+        }
     }
 }
diff --git a/ui/cypress/support/utils/pipeline/PipelineBtns.ts 
b/ui/cypress/support/utils/pipeline/PipelineBtns.ts
index 6ace82220f..faece471a5 100644
--- a/ui/cypress/support/utils/pipeline/PipelineBtns.ts
+++ b/ui/cypress/support/utils/pipeline/PipelineBtns.ts
@@ -17,6 +17,14 @@
  */
 
 export class PipelineBtns {
+    public static statusPipeline() {
+        return cy.dataCy('status-pipeline-green', { timeout: 10000 });
+    }
+
+    public static stopPipeline() {
+        return cy.dataCy('stop-pipeline-button', { timeout: 10000 });
+    }
+
     public static deletePipeline() {
         return cy.dataCy('delete-pipeline', { timeout: 10000 });
     }
diff --git a/ui/cypress/support/utils/pipeline/PipelineUtils.ts 
b/ui/cypress/support/utils/pipeline/PipelineUtils.ts
index 0fa9ce4443..2b50f512c0 100644
--- a/ui/cypress/support/utils/pipeline/PipelineUtils.ts
+++ b/ui/cypress/support/utils/pipeline/PipelineUtils.ts
@@ -21,6 +21,9 @@ import { StaticPropertyUtils } from 
'../userInput/StaticPropertyUtils';
 import { OutputStrategyUtils } from '../OutputStrategyUtils';
 import { PipelineElementInput } from '../../model/PipelineElementInput';
 import { PipelineBtns } from './PipelineBtns';
+import { ConnectUtils } from '../connect/ConnectUtils';
+import { PipelineBuilder } from '../../builder/PipelineBuilder';
+import { PipelineElementBuilder } from '../../builder/PipelineElementBuilder';
 
 export class PipelineUtils {
     public static addPipeline(pipelineInput: PipelineInput) {
@@ -33,6 +36,32 @@ export class PipelineUtils {
         PipelineUtils.startPipeline(pipelineInput);
     }
 
+    /**
+     * This method adds a sample adapter and pipeline
+     */
+    public static addSampleAdapterAndPipeline() {
+        const adapterName = 'simulator';
+
+        ConnectUtils.addMachineDataSimulator(adapterName);
+
+        const pipelineInput = PipelineBuilder.create('Pipeline Test')
+            .addSource(adapterName)
+            .addProcessingElement(
+                PipelineElementBuilder.create('field_renamer')
+                    .addInput('drop-down', 'convert-property', 'timestamp')
+                    .addInput('input', 'field-name', 't')
+                    .build(),
+            )
+            .addSink(
+                PipelineElementBuilder.create('data_lake')
+                    .addInput('input', 'db_measurement', 'demo')
+                    .build(),
+            )
+            .build();
+
+        PipelineUtils.addPipeline(pipelineInput);
+    }
+
     public static editPipeline() {
         cy.dataCy('modify-pipeline-btn').first().click();
     }
@@ -133,7 +162,15 @@ export class PipelineUtils {
 
     public static checkAmountOfPipelinesPipeline(amount: number) {
         PipelineUtils.goToPipelines();
-        PipelineBtns.deletePipeline().should('have.length', amount);
+
+        if (amount === 0) {
+            // The wait is needed because the default value is the 
no-table-entries element.
+            // It must be waited till the data is loaded. Once a better 
solution is found, this can be removed.
+            cy.wait(1000);
+            cy.dataCy('no-table-entries').should('be.visible');
+        } else {
+            PipelineBtns.statusPipeline().should('have.length', amount);
+        }
     }
 
     public static deletePipeline() {
diff --git a/ui/cypress/support/utils/pipeline/PipelineBtns.ts 
b/ui/cypress/support/utils/user/PermissionUtils.ts
similarity index 52%
copy from ui/cypress/support/utils/pipeline/PipelineBtns.ts
copy to ui/cypress/support/utils/user/PermissionUtils.ts
index 6ace82220f..9907c56acc 100644
--- a/ui/cypress/support/utils/pipeline/PipelineBtns.ts
+++ b/ui/cypress/support/utils/user/PermissionUtils.ts
@@ -16,8 +16,29 @@
  *
  */
 
-export class PipelineBtns {
-    public static deletePipeline() {
-        return cy.dataCy('delete-pipeline', { timeout: 10000 });
+import { StaticPropertyUtils } from '../userInput/StaticPropertyUtils';
+
+export class PermissionUtils {
+    public static openManagePermissions() {
+        cy.dataCy('open-manage-permissions').click();
+    }
+
+    public static markElementAsPublic() {
+        PermissionUtils.openManagePermissions();
+        StaticPropertyUtils.clickCheckbox('permission-public-element');
+        PermissionUtils.save();
+    }
+
+    public static authorizeUser(email: string) {
+        PermissionUtils.openManagePermissions();
+
+        cy.dataCy('authorized-user').type(email);
+        cy.get(`[data-cy="user-option-${email}"]`).click();
+
+        PermissionUtils.save();
+    }
+
+    public static save() {
+        cy.dataCy('sp-manage-permissions-save').click();
     }
 }
diff --git a/ui/cypress/support/utils/userInput/StaticPropertyUtils.ts 
b/ui/cypress/support/utils/userInput/StaticPropertyUtils.ts
index 34b84673f3..acc1a5eaf4 100644
--- a/ui/cypress/support/utils/userInput/StaticPropertyUtils.ts
+++ b/ui/cypress/support/utils/userInput/StaticPropertyUtils.ts
@@ -24,7 +24,7 @@ export class StaticPropertyUtils {
         // Configure Properties
         configs.forEach(config => {
             if (config.type === 'checkbox') {
-                this.clickCheckbox(config);
+                this.clickCheckbox(config.selector);
             } else if (config.type === 'button') {
                 cy.dataCy(config.selector, { timeout: 2000 }).click();
             } else if (config.type === 'drop-down') {
@@ -65,8 +65,12 @@ export class StaticPropertyUtils {
         });
     }
 
-    private static clickCheckbox(input: UserInput) {
-        this.clickSelectionInput(input.selector, '.mdc-checkbox');
+    /**
+     * This method can be used to check a mat checkbox
+     * @param selector
+     */
+    public static clickCheckbox(selector: string) {
+        this.clickSelectionInput(selector, '.mdc-checkbox');
     }
 
     private static clickRadio(input: UserInput) {
diff --git 
a/ui/cypress/tests/connect/deleteAdapterWithMultipleUsers.smoke.spec.ts 
b/ui/cypress/tests/connect/deleteAdapterWithMultipleUsers.smoke.spec.ts
deleted file mode 100644
index a11332ac9e..0000000000
--- a/ui/cypress/tests/connect/deleteAdapterWithMultipleUsers.smoke.spec.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- *
- */
-
-import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
-import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
-import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
-import { UserUtils } from '../../support/utils/UserUtils';
-import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
-
-const adapterName = 'simulator';
-
-const pipelineInput = PipelineBuilder.create('Pipeline Test')
-    .addSource(adapterName)
-    .addProcessingElement(
-        PipelineElementBuilder.create('field_renamer')
-            .addInput('drop-down', 'convert-property', 'timestamp')
-            .addInput('input', 'field-name', 't')
-            .build(),
-    )
-    .addSink(
-        PipelineElementBuilder.create('data_lake')
-            .addInput('input', 'db_measurement', 'demo')
-            .build(),
-    )
-    .build();
-
-describe('Test Enhanced Adapter Deletion', () => {
-    beforeEach('Setup Test', () => {
-        cy.initStreamPipesTest();
-        UserUtils.addUser(UserUtils.userWithAdapterAndPipelineAdminRights);
-    });
-
-    it('Test Delete Adapter and Associated Pipelines', () => {
-        ConnectUtils.addMachineDataSimulator(adapterName, false);
-        PipelineUtils.addPipeline(pipelineInput);
-
-        ConnectUtils.deleteAdapterAndAssociatedPipelines();
-    });
-
-    it('Test Admin Should Be Able to Delete Adapter and Not Owned Associated 
Pipelines', () => {
-        // Let the user create the adapter and the pipeline
-        ConnectUtils.addMachineDataSimulator(adapterName, false);
-        PipelineUtils.addPipeline(pipelineInput);
-
-        // Then let the admin delete them
-        UserUtils.switchUser(UserUtils.adminUser);
-        ConnectUtils.deleteAdapterAndAssociatedPipelines(true);
-    });
-
-    it('Test Delete Adapter and Associated Pipelines Permission Denied', () => 
{
-        // Let the admin create the adapter and the pipeline
-        UserUtils.switchUser(UserUtils.adminUser);
-        ConnectUtils.addMachineDataSimulator(adapterName, false);
-        PipelineUtils.addPipeline(pipelineInput);
-
-        // Then the user shouldn't be able to delete them
-        UserUtils.switchUser(UserUtils.userWithAdapterAndPipelineAdminRights);
-        ConnectUtils.deleteAdapterAndAssociatedPipelinesPermissionDenied();
-    });
-});
diff --git a/ui/cypress/tests/connect/enhancedAdapterDeletion.smoke.spec.ts 
b/ui/cypress/tests/connect/enhancedAdapterDeletion.smoke.spec.ts
new file mode 100644
index 0000000000..e10fd81873
--- /dev/null
+++ b/ui/cypress/tests/connect/enhancedAdapterDeletion.smoke.spec.ts
@@ -0,0 +1,43 @@
+/*
+ *  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.
+ *
+ */
+
+import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
+import { UserUtils } from '../../support/utils/UserUtils';
+import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
+
+describe('Test Enhanced Adapter Deletion', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+        UserUtils.addUser(UserUtils.userWithAdapterAndPipelineAdminRights);
+    });
+
+    it('Test Delete Adapter and Associated Pipelines', () => {
+        PipelineUtils.addSampleAdapterAndPipeline();
+
+        ConnectUtils.deleteAdapterAndAssociatedPipelines();
+    });
+
+    it('Test Admin Should Be Able to Delete Adapter and Not Owned Associated 
Pipelines', () => {
+        // Let the user create the adapter and the pipeline
+        PipelineUtils.addSampleAdapterAndPipeline();
+
+        // Then let the admin delete them
+        UserUtils.switchUser(UserUtils.adminUser);
+        ConnectUtils.deleteAdapterAndAssociatedPipelines(true);
+    });
+});
diff --git a/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts 
b/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
index 21a1604fb3..71f2356ed9 100644
--- a/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
+++ b/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
@@ -123,7 +123,10 @@ function getLocalizedDateString(date: Date) {
 }
 
 function getLocalizedTimeString(date: Date) {
-    return date.toLocaleTimeString().slice(0, 8);
+    const hours = String(date.getHours()).padStart(2, '0');
+    const minutes = String(date.getMinutes()).padStart(2, '0');
+    const seconds = String(date.getSeconds()).padStart(2, '0');
+    return `${hours}:${minutes}:${seconds}`;
 }
 
 function parseTimeStringToSeconds(timeString: string) {
diff --git a/ui/cypress/tests/pipeline/multiUser/pipelineMultiUserSupport.ts 
b/ui/cypress/tests/pipeline/multiUser/pipelineMultiUserSupport.ts
new file mode 100644
index 0000000000..31f61716e4
--- /dev/null
+++ b/ui/cypress/tests/pipeline/multiUser/pipelineMultiUserSupport.ts
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ */
+
+import { UserUtils } from '../../../support/utils/UserUtils';
+import { UserRole } from '../../../../src/app/_enums/user-role.enum';
+import { PipelineUtils } from '../../../support/utils/pipeline/PipelineUtils';
+
+describe('Test Pipeline Multi User support', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+    });
+
+    it('Test with pipeline admin account', () => {
+        testPipelineNotShownForOtherUsers(UserRole.ROLE_PIPELINE_ADMIN);
+    });
+
+    it('Test with pipeline user account', () => {
+        testPipelineNotShownForOtherUsers(UserRole.ROLE_PIPELINE_USER);
+    });
+
+    /**
+     * This function validates that the pipeline is only shown to
+     * the user who created it
+     */
+    function testPipelineNotShownForOtherUsers(userRole: UserRole) {
+        const pipelineAdminUser = UserUtils.createUser('user1', userRole);
+
+        PipelineUtils.addSampleAdapterAndPipeline();
+
+        UserUtils.switchUser(pipelineAdminUser);
+
+        PipelineUtils.checkAmountOfPipelinesPipeline(0);
+    }
+});
diff --git a/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts 
b/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts
index 010f7695f9..f17be7abc5 100644
--- a/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts
+++ b/ui/cypress/tests/pipeline/pipelineTest.smoke.spec.ts
@@ -16,36 +16,15 @@
  *
  */
 
-import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
 import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
-import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
-import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
-
-const adapterName = 'simulator';
 
 describe('Test Random Data Simulator Stream Adapter', () => {
     beforeEach('Setup Test', () => {
         cy.initStreamPipesTest();
-        ConnectUtils.addMachineDataSimulator(adapterName);
     });
 
     it('Perform Test', () => {
-        const pipelineInput = PipelineBuilder.create('Pipeline Test')
-            .addSource(adapterName)
-            .addProcessingElement(
-                PipelineElementBuilder.create('field_renamer')
-                    .addInput('drop-down', 'convert-property', 'timestamp')
-                    .addInput('input', 'field-name', 't')
-                    .build(),
-            )
-            .addSink(
-                PipelineElementBuilder.create('data_lake')
-                    .addInput('input', 'db_measurement', 'demo')
-                    .build(),
-            )
-            .build();
-
-        PipelineUtils.addPipeline(pipelineInput);
+        PipelineUtils.addSampleAdapterAndPipeline();
         PipelineUtils.deletePipeline();
     });
 });
diff --git a/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts 
b/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts
index 5de2359906..f1ff02d0c9 100644
--- a/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts
+++ b/ui/cypress/tests/pipeline/updatePipelineTest.smoke.spec.ts
@@ -16,36 +16,15 @@
  *
  */
 
-import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
 import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
-import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
-import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
-
-const adapterName = 'simulator';
 
 describe('Test update of running pipeline', () => {
     beforeEach('Setup Test', () => {
         cy.initStreamPipesTest();
-        ConnectUtils.addMachineDataSimulator(adapterName);
     });
 
     it('Perform Test', () => {
-        const pipelineInput = PipelineBuilder.create('Pipeline Test')
-            .addSource(adapterName)
-            .addProcessingElement(
-                PipelineElementBuilder.create('field_renamer')
-                    .addInput('drop-down', 'convert-property', 'timestamp')
-                    .addInput('input', 'field-name', 't')
-                    .build(),
-            )
-            .addSink(
-                PipelineElementBuilder.create('data_lake')
-                    .addInput('input', 'db_measurement', 'demo')
-                    .build(),
-            )
-            .build();
-
-        PipelineUtils.addPipeline(pipelineInput);
+        PipelineUtils.addSampleAdapterAndPipeline();
         PipelineUtils.editPipeline();
         cy.wait(1000);
         PipelineUtils.startPipeline();
diff --git a/ui/cypress/tests/userManagement/testGroupManagement.spec.ts 
b/ui/cypress/tests/userManagement/testGroupManagement.spec.ts
index 03d7159568..4c62669b2b 100644
--- a/ui/cypress/tests/userManagement/testGroupManagement.spec.ts
+++ b/ui/cypress/tests/userManagement/testGroupManagement.spec.ts
@@ -23,6 +23,8 @@ import { ConnectUtils } from 
'../../support/utils/connect/ConnectUtils';
 import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
 import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
 import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
+import { GeneralUtils } from '../../support/utils/GeneralUtils';
+import { PermissionUtils } from '../../support/utils/user/PermissionUtils';
 
 describe('Test Group Management for Pipelines', () => {
     beforeEach('Setup Test', () => {
@@ -94,18 +96,15 @@ describe('Test Group Management for Pipelines', () => {
 
         // Add user group to pipeline
         PipelineUtils.goToPipelines();
-        cy.dataCy('share').click();
+        PermissionUtils.openManagePermissions();
         cy.get('label').contains('Authorized Groups').click();
         cy.get('mat-option').contains('User_Group').click();
-        cy.dataCy('sp-element-edit-user-save').click();
+        PermissionUtils.save();
 
         // Login as first user which belongs to user group with pipeline admin 
role
         UserUtils.switchUser(user);
 
-        cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-            'have.length',
-            4,
-        );
+        GeneralUtils.validateAmountOfNavigationIcons(4);
 
         // Check if pipeline is visible
         PipelineUtils.goToPipelines();
@@ -121,10 +120,7 @@ describe('Test Group Management for Pipelines', () => {
         // Login as user2
         UserUtils.switchUser(user2);
 
-        cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-            'have.length',
-            3,
-        );
+        GeneralUtils.validateAmountOfNavigationIcons(3);
 
         // Check if pipeline is invisible to user2
         PipelineUtils.goToPipelines();
diff --git a/ui/cypress/tests/userManagement/testUserRoleConnect.spec.ts 
b/ui/cypress/tests/userManagement/testUserRoleConnect.spec.ts
index 5b0dace368..04290d02ca 100644
--- a/ui/cypress/tests/userManagement/testUserRoleConnect.spec.ts
+++ b/ui/cypress/tests/userManagement/testUserRoleConnect.spec.ts
@@ -15,48 +15,53 @@
  *  limitations under the License.
  *
  */
-import { UserBuilder } from '../../support/builder/UserBuilder';
 import { UserRole } from '../../../src/app/_enums/user-role.enum';
 import { UserUtils } from '../../support/utils/UserUtils';
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
-import { ConnectBtns } from '../../support/utils/connect/ConnectBtns';
+import { PermissionUtils } from '../../support/utils/user/PermissionUtils';
+import { GeneralUtils } from '../../support/utils/GeneralUtils';
 
 describe('Test User Roles for Connect', () => {
+    var connectAdminUser;
     beforeEach('Setup Test', () => {
         cy.initStreamPipesTest();
+        connectAdminUser = UserUtils.createUser(
+            'user',
+            UserRole.ROLE_CONNECT_ADMIN,
+        );
         ConnectUtils.addMachineDataSimulator('simulator');
     });
 
-    it('Perform Test', () => {
-        // Add connect admin user
-        const connect_admin = UserBuilder.create('[email protected]')
-            .setName('connect_admin')
-            .setPassword('password')
-            .addRole(UserRole.ROLE_CONNECT_ADMIN)
-            .build();
-        UserUtils.addUser(connect_admin);
-
-        // Login as user and check if connect is visible to user
-        UserUtils.switchUser(connect_admin);
-
-        cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-            'have.length',
-            3,
-        );
+    it('Connect admin should not see adapters of other users', () => {
+        UserUtils.switchUser(connectAdminUser);
 
-        ConnectUtils.goToConnect();
-        cy.dataCy('all-adapters-table', { timeout: 10000 }).should(
-            'have.length',
-            1,
-        );
-        cy.dataCy('all-adapters-table', { timeout: 10000 }).should(
-            'contain',
-            'simulator',
-        );
+        GeneralUtils.validateAmountOfNavigationIcons(3);
+
+        // Validate that no adapter is visible
+        ConnectUtils.checkAmountOfAdapters(0);
+    });
+
+    it('Connect admin should see public adapters of other users', () => {
+        // Set adapter to public
+        PermissionUtils.markElementAsPublic();
+
+        UserUtils.switchUser(connectAdminUser);
+
+        GeneralUtils.validateAmountOfNavigationIcons(3);
+
+        // Validate that adapter is visible
+        ConnectUtils.checkAmountOfAdapters(1);
+    });
+
+    it('Connect admin should see shared adapters of other users', () => {
+        // Share adapter with user
+        PermissionUtils.authorizeUser(connectAdminUser.email);
+
+        UserUtils.switchUser(connectAdminUser);
+
+        GeneralUtils.validateAmountOfNavigationIcons(3);
 
-        // validate that adapter can be stopped and edited
-        ConnectBtns.stopAdapter().click();
-        ConnectBtns.editAdapter().should('not.be.disabled');
-        ConnectBtns.editAdapter().click();
+        // Validate that adapter is visible
+        ConnectUtils.checkAmountOfAdapters(1);
     });
 });
diff --git a/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts 
b/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts
index 94d83418ff..3c690ffe92 100644
--- a/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts
+++ b/ui/cypress/tests/userManagement/testUserRolePipeline.spec.ts
@@ -16,88 +16,90 @@
  *
  */
 
-import { UserBuilder } from '../../support/builder/UserBuilder';
 import { UserRole } from '../../../src/app/_enums/user-role.enum';
 import { UserUtils } from '../../support/utils/UserUtils';
 import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
 import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils';
-import { PipelineElementBuilder } from 
'../../support/builder/PipelineElementBuilder';
-import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
+import { GeneralUtils } from '../../support/utils/GeneralUtils';
+import { PermissionUtils } from '../../support/utils/user/PermissionUtils';
+import { PipelineBtns } from '../../support/utils/pipeline/PipelineBtns';
 
 describe('Test User Roles for Pipelines', () => {
     beforeEach('Setup Test', () => {
         cy.initStreamPipesTest();
-        ConnectUtils.addMachineDataSimulator('simulator');
-        const pipelineInput = PipelineBuilder.create('Pipeline Test')
-            .addSource('simulator')
-            .addProcessingElement(
-                PipelineElementBuilder.create('field_renamer')
-                    .addInput('drop-down', 'convert-property', 'timestamp')
-                    .addInput('input', 'field-name', 't')
-                    .build(),
-            )
-            .addSink(
-                PipelineElementBuilder.create('data_lake')
-                    .addInput('input', 'db_measurement', 'demo')
-                    .build(),
-            )
-            .build();
-
-        PipelineUtils.addPipeline(pipelineInput);
+        // Create a machine data simulator with a sample pipeline for the tests
+        ConnectUtils.addMachineDataSimulator('simulator', true);
     });
 
-    it('Perform Test', () => {
-        // Add new user
-        UserUtils.goToUserConfiguration();
-
-        cy.dataCy('user-accounts-table-row', { timeout: 10000 }).should(
-            'have.length',
-            1,
+    it('Pipeline admin should not see pipelines of other users', () => {
+        const newUser = UserUtils.createUser(
+            'user',
+            UserRole.ROLE_PIPELINE_ADMIN,
         );
 
-        const email = '[email protected]';
-        const name = 'test_user';
-        const user = UserBuilder.create(email)
-            .setName(name)
-            .setPassword(name)
-            .addRole(UserRole.ROLE_PIPELINE_USER)
-            .build();
+        // Login as user and check if pipeline is visible to user
+        UserUtils.switchUser(newUser);
+
+        GeneralUtils.validateAmountOfNavigationIcons(4);
 
-        UserUtils.addUser(user);
+        PipelineUtils.goToPipelines();
+        PipelineUtils.checkAmountOfPipelinesPipeline(0);
+    });
 
-        // Check if user is added successfully
-        cy.dataCy('user-accounts-table-row', { timeout: 10000 }).should(
-            'have.length',
-            2,
+    it('Pipeline admin should see public pipelines of other users', () => {
+        const newUser = UserUtils.createUser(
+            'user',
+            UserRole.ROLE_PIPELINE_ADMIN,
         );
 
         // Add new authorized user to pipeline
         PipelineUtils.goToPipelines();
-        cy.dataCy('share').click();
-        cy.get('label').contains('Authorized Users').click();
-        cy.get('mat-option').contains(email).click();
-        cy.dataCy('sp-element-edit-user-save').click();
+        PermissionUtils.markElementAsPublic();
 
         // Login as user and check if pipeline is visible to user
-        UserUtils.switchUser(user);
+        UserUtils.switchUser(newUser);
+
+        PipelineUtils.goToPipelines();
+        PipelineUtils.checkAmountOfPipelinesPipeline(1);
+    });
 
-        cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-            'have.length',
-            3,
+    it(' Pipeline admin should see shared pipelines of other users', () => {
+        const newUser = UserUtils.createUser(
+            'user',
+            UserRole.ROLE_PIPELINE_ADMIN,
         );
 
+        // Add new authorized user to pipeline
         PipelineUtils.goToPipelines();
-        cy.dataCy('all-pipelines-table', { timeout: 10000 }).should(
-            'have.length',
-            1,
-        );
-        cy.dataCy('all-pipelines-table', { timeout: 10000 }).should(
-            'contain',
-            'Pipeline Test',
+        PermissionUtils.markElementAsPublic();
+        PermissionUtils.authorizeUser(newUser.email);
+
+        // Login as user and check if pipeline is visible to user
+        UserUtils.switchUser(newUser);
+
+        PipelineUtils.goToPipelines();
+        PipelineUtils.checkAmountOfPipelinesPipeline(1);
+    });
+
+    it(' Pipeline user should see shared pipelines of other users but not be 
able to edit them', () => {
+        const newUser = UserUtils.createUser(
+            'user',
+            UserRole.ROLE_PIPELINE_USER,
         );
 
-        // Delete user
-        UserUtils.switchUser(UserUtils.adminUser);
-        UserUtils.deleteUser(user);
+        // Add new authorized user to pipeline
+        PipelineUtils.goToPipelines();
+        // PermissionUtils.markElementAsPublic();
+        PermissionUtils.authorizeUser(newUser.email);
+
+        // Login as user and check if pipeline is visible to user
+        UserUtils.switchUser(newUser);
+
+        PipelineUtils.goToPipelines();
+        PipelineUtils.checkAmountOfPipelinesPipeline(1);
+
+        // A pipeline user should not be able to stop the pipeline or delete it
+        PipelineBtns.deletePipeline().should('not.exist');
+        PipelineBtns.stopPipeline().should('be.disabled');
     });
 });
diff --git a/ui/cypress/tests/userManagement/testVariousUserRoles.smoke.spec.ts 
b/ui/cypress/tests/userManagement/testVariousUserRoles.smoke.spec.ts
index 34e4624d63..4c00e01667 100644
--- a/ui/cypress/tests/userManagement/testVariousUserRoles.smoke.spec.ts
+++ b/ui/cypress/tests/userManagement/testVariousUserRoles.smoke.spec.ts
@@ -19,6 +19,7 @@
 import { UserBuilder } from '../../support/builder/UserBuilder';
 import { UserRole } from '../../../src/app/_enums/user-role.enum';
 import { UserUtils } from '../../support/utils/UserUtils';
+import { GeneralUtils } from '../../support/utils/GeneralUtils';
 
 const testedRoles = [
     UserRole.ROLE_PIPELINE_ADMIN,
@@ -38,10 +39,7 @@ for (var i = 0; i < testedRoles.length; i++) {
         it('Perform Test', () => {
             // Add new user
             UserUtils.goToUserConfiguration();
-            cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-                'have.length',
-                8,
-            );
+            GeneralUtils.validateAmountOfNavigationIcons(8);
 
             cy.dataCy('user-accounts-table-row', { timeout: 10000 }).should(
                 'have.length',
@@ -68,30 +66,15 @@ for (var i = 0; i < testedRoles.length; i++) {
 
             // Check if every role displays correct navigation menu
             if (testRole == UserRole.ROLE_PIPELINE_ADMIN) {
-                cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-                    'have.length',
-                    4,
-                );
+                GeneralUtils.validateAmountOfNavigationIcons(4);
             } else if (testRole == UserRole.ROLE_DASHBOARD_ADMIN) {
-                cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-                    'have.length',
-                    4,
-                );
+                GeneralUtils.validateAmountOfNavigationIcons(4);
             } else if (testRole == UserRole.ROLE_DATA_EXPLORER_ADMIN) {
-                cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-                    'have.length',
-                    4,
-                );
+                GeneralUtils.validateAmountOfNavigationIcons(4);
             } else if (testRole == UserRole.ROLE_CONNECT_ADMIN) {
-                cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-                    'have.length',
-                    3,
-                );
+                GeneralUtils.validateAmountOfNavigationIcons(3);
             } else if (testRole == UserRole.ROLE_ASSET_ADMIN) {
-                cy.dataCy('navigation-icon', { timeout: 10000 }).should(
-                    'have.length',
-                    3,
-                );
+                GeneralUtils.validateAmountOfNavigationIcons(3);
             }
 
             // Login as admin and delete user
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-table/sp-table.component.html
 
b/ui/projects/streampipes/shared-ui/src/lib/components/sp-table/sp-table.component.html
index 5e8302acb3..52024357ff 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-table/sp-table.component.html
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/sp-table/sp-table.component.html
@@ -24,7 +24,11 @@
         <tr mat-row *matRowDef="let row; columns: columns"></tr>
 
         <tr class="mat-row" *matNoDataRow>
-            <td class="mat-cell" [colSpan]="columns.length">
+            <td
+                data-cy="no-table-entries"
+                class="mat-cell"
+                [colSpan]="columns.length"
+            >
                 No entries available.
             </td>
         </tr>
diff --git 
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
 
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
index 5c1b11994c..6147d2cf9c 100644
--- 
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
+++ 
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
@@ -258,6 +258,7 @@
                                     mat-icon-button
                                     matTooltip="Manage permissions"
                                     matTooltipPosition="above"
+                                    data-cy="open-manage-permissions"
                                     *ngIf="isAdmin"
                                     (click)="showPermissionsDialog(adapter)"
                                 >
diff --git 
a/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.html
 
b/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.html
index cf16da3273..ba806e1b7b 100644
--- 
a/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.html
+++ 
b/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.html
@@ -33,7 +33,10 @@
                             >
                         </mat-select>
                     </mat-form-field>
-                    <mat-checkbox formControlName="publicElement">
+                    <mat-checkbox
+                        data-cy="permission-public-element"
+                        formControlName="publicElement"
+                    >
                         Public Element
                     </mat-checkbox>
                 </div>
@@ -66,6 +69,7 @@
                                 [matChipInputSeparatorKeyCodes]="
                                     separatorKeysCodes
                                 "
+                                data-cy="authorized-user"
                                 (matChipInputTokenEnd)="addUser($event)"
                             />
                         </mat-chip-grid>
@@ -76,6 +80,7 @@
                             <mat-option
                                 *ngFor="let user of filteredUsers | async"
                                 [value]="user"
+                                [attr.data-cy]="'user-option-' + user.username"
                             >
                                 {{ user.username }}
                             </mat-option>
@@ -140,7 +145,7 @@
                 (click)="save()"
                 style="margin-right: 10px"
                 [disabled]="!parentForm.valid"
-                data-cy="sp-element-edit-user-save"
+                data-cy="sp-manage-permissions-save"
             >
                 <i class="material-icons">save</i><span>&nbsp;Save</span>
             </button>
diff --git 
a/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.ts
 
b/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.ts
index 1f21a19d03..dc9e66c336 100644
--- 
a/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.ts
+++ 
b/ui/src/app/core-ui/object-permission-dialog/object-permission-dialog.component.ts
@@ -231,7 +231,7 @@ export class ObjectPermissionDialogComponent implements 
OnInit {
 
     private addUserToSelection(authority: PermissionEntry) {
         const user = this.allUsers.find(u => u.principalId === authority.sid);
-        this.grantedUserAuthorities.push(user);
+        user && this.grantedUserAuthorities.push(user);
     }
 
     private addGroupToSelection(authority: PermissionEntry) {
diff --git 
a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
 
b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
index f9918daaa0..1c1bf59463 100644
--- 
a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
+++ 
b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
@@ -28,6 +28,7 @@
             <div>
                 <div fxLayout="row" fxLayoutAlign="start center" 
fxFlex="150px">
                     <div
+                        data-cy="status-pipeline-green"
                         *ngIf="
                             pipeline.running && pipeline.healthStatus === 'OK'
                         "
@@ -116,6 +117,7 @@
                 mat-icon-button
                 matTooltip="Stop pipeline"
                 matTooltipPosition="above"
+                data-cy="stop-pipeline-button"
                 (click)="
                     pipelineOperationsService.stopPipeline(
                         pipeline._id,
@@ -192,7 +194,7 @@
                             refreshPipelinesEmitter
                         )
                     "
-                    data-cy="share"
+                    data-cy="open-manage-permissions"
                 >
                     <i class="material-icons">share</i>
                 </button>

Reply via email to