This is an automated email from the ASF dual-hosted git repository. riemer pushed a commit to branch STREAMPIPES-426 in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
commit df6d25b72ef06062a72c4a56b4ae5fa8132842be Author: Dominik Riemer <[email protected]> AuthorDate: Sun Oct 17 22:51:19 2021 +0200 [STREAMPIPES-426] Add initial draft of permission management --- .../streampipes/commons/random/UUIDGenerator.java | 19 +--- .../streampipes/model/client/user/Group.java | 13 ++- .../streampipes/model/client/user/Permission.java | 104 +++++++++++++++++++++ .../model/client/user/PermissionBuilder.java | 51 ++++++++++ .../streampipes/model/client/user/Principal.java | 12 +++ .../streampipes/model/client/user/Privilege.java | 52 ++++------- .../apache/streampipes/model/client/user/Role.java | 6 +- .../manager/permission/PermissionManager.java | 24 ++--- .../manager/pipeline/PipelineManager.java | 20 +++- .../manager/setup/CouchDbInstallationStep.java | 18 +++- .../base/impl/AbstractAuthGuardedRestResource.java | 11 +++ .../streampipes/rest/impl/PipelineResource.java | 8 +- .../org/apache/streampipes/rest/impl/Version.java | 4 +- .../rest/impl/security/AuthConstants.java | 1 + .../rest/impl/security/SpPermissionEvaluator.java | 13 ++- .../streampipes/storage/api/INoSqlStorage.java | 2 + .../storage/api/IPermissionStorage.java | 27 +++--- .../streampipes/storage/api/IUserStorage.java | 6 +- .../storage/couchdb/CouchDbStorageManager.java | 5 + .../storage/couchdb/dao/AbstractDao.java | 28 ++---- .../couchdb/dao/{AbstractDao.java => CrudDao.java} | 22 ++--- .../dao/{FindAllCommand.java => CrudViewDao.java} | 19 ++-- .../storage/couchdb/dao/FindAllCommand.java | 10 +- .../couchdb/impl/PermissionStorageImpl.java | 76 +++++++++++++++ .../storage/couchdb/impl/UserGroupStorageImpl.java | 18 ++-- .../storage/couchdb/impl/UserStorage.java | 41 +++----- .../management/model/PrincipalUserDetails.java | 11 ++- ...Builder.java => GrantedAuthoritiesBuilder.java} | 4 +- .../management/util/GrantedPermissionsBuilder.java | 44 ++++----- 29 files changed, 464 insertions(+), 205 deletions(-) diff --git a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/random/UUIDGenerator.java similarity index 63% copy from streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java copy to streampipes-commons/src/main/java/org/apache/streampipes/commons/random/UUIDGenerator.java index c42e0a4..5c0eb06 100644 --- a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java +++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/random/UUIDGenerator.java @@ -15,22 +15,13 @@ * limitations under the License. * */ -package org.apache.streampipes.rest.core.base.impl; +package org.apache.streampipes.commons.random; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.SecurityContext; +import java.util.UUID; -public class AbstractAuthGuardedRestResource extends AbstractRestResource { +public class UUIDGenerator { - @Context - protected SecurityContext securityContext; - - protected boolean isAuthenticated() { - return this.securityContext.getUserPrincipal() != null; - } - - protected String getAuthenticatedUsername() { - return this.securityContext.getUserPrincipal().getName(); + public static String generateUuid() { + return UUID.randomUUID().toString().replace("-", ""); } - } diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java index 8ee6e90..8b319f0 100644 --- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java +++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java @@ -17,11 +17,11 @@ */ package org.apache.streampipes.model.client.user; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.gson.annotations.SerializedName; import org.apache.streampipes.model.shared.annotation.TsModel; import java.util.HashSet; -import java.util.List; import java.util.Set; @TsModel @@ -30,6 +30,9 @@ public class Group { protected @SerializedName("_id") String groupId; protected @SerializedName("_rev") String rev; + @JsonIgnore + private String $type = "group"; + private String groupName; private Set<Role> roles; @@ -69,4 +72,12 @@ public class Group { public void setRoles(Set<Role> roles) { this.roles = roles; } + + public String get$type() { + return $type; + } + + public void set$type(String $type) { + this.$type = $type; + } } diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Permission.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Permission.java new file mode 100644 index 0000000..2c0f2cb --- /dev/null +++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Permission.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.model.client.user; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.List; + +public class Permission { + + protected @SerializedName("_id") String permissionId; + protected @SerializedName("_rev") String rev; + + @JsonIgnore + private String $type = "permission"; + + private String objectInstanceId; + private String objectClassName; + + private String ownerSid; + + private List<String> allowedSids; + + public Permission() { + this.allowedSids = new ArrayList<>(); + } + + public String getPermissionId() { + return permissionId; + } + + public void setPermissionId(String permissionId) { + this.permissionId = permissionId; + } + + public String getRev() { + return rev; + } + + public void setRev(String rev) { + this.rev = rev; + } + + public String getObjectInstanceId() { + return objectInstanceId; + } + + public void setObjectInstanceId(String objectInstanceId) { + this.objectInstanceId = objectInstanceId; + } + + public String getObjectClassName() { + return objectClassName; + } + + public void setObjectClassName(String objectClassName) { + this.objectClassName = objectClassName; + } + + public String getOwnerSid() { + return ownerSid; + } + + public void setOwnerSid(String ownerSid) { + this.ownerSid = ownerSid; + } + + public void addAllowedSid(String sid) { + this.allowedSids.add(sid); + } + + public List<String> getAllowedSids() { + return allowedSids; + } + + public void setAllowedSids(List<String> allowedSids) { + this.allowedSids = allowedSids; + } + + public String get$type() { + return $type; + } + + public void set$type(String $type) { + this.$type = $type; + } +} diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/PermissionBuilder.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/PermissionBuilder.java new file mode 100644 index 0000000..70da030 --- /dev/null +++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/PermissionBuilder.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.model.client.user; + +public class PermissionBuilder { + + private Permission permission; + + public static PermissionBuilder create(String objectInstanceId, + Class<?> objectInstanceClass, + String ownerSid) { + return new PermissionBuilder( + objectInstanceId, + objectInstanceClass, + ownerSid + ); + } + + private PermissionBuilder(String objectInstanceId, + Class<?> objectInstanceClass, + String ownerSid) { + this.permission = new Permission(); + this.permission.setObjectInstanceId(objectInstanceId); + this.permission.setObjectClassName(objectInstanceClass.getCanonicalName()); + this.permission.setOwnerSid(ownerSid); + } + + public PermissionBuilder with(String sid) { + this.permission.addAllowedSid(sid); + return this; + } + + public Permission build() { + return permission; + } +} diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Principal.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Principal.java index 777556a..0c06b40 100644 --- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Principal.java +++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Principal.java @@ -18,6 +18,7 @@ package org.apache.streampipes.model.client.user; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.gson.annotations.SerializedName; import java.util.ArrayList; @@ -30,6 +31,9 @@ public abstract class Principal { protected @SerializedName("_id") String principalId; protected @SerializedName("_rev") String rev; + @JsonIgnore + private String $type = "principal"; + private boolean accountEnabled; private boolean accountLocked; private boolean accountExpired; @@ -189,4 +193,12 @@ public abstract class Principal { public void setObjectPermissions(Set<String> objectPermissions) { this.objectPermissions = objectPermissions; } + + public String get$type() { + return $type; + } + + public void set$type(String $type) { + this.$type = $type; + } } diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Privilege.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Privilege.java index 4170e31..5950ba0 100644 --- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Privilege.java +++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Privilege.java @@ -22,58 +22,50 @@ import org.apache.streampipes.model.shared.annotation.TsModel; @TsModel public enum Privilege { // Pipelines - PRIVILEGE_CREATE_PIPELINE(Constants.PRIVILEGE_CREATE_PIPELINE_VALUE), PRIVILEGE_READ_PIPELINE(Constants.PRIVILEGE_READ_PIPELINE_VALUE), - PRIVILEGE_UPDATE_PIPELINE(Constants.PRIVILEGE_UPDATE_PIPELINE_VALUE), + PRIVILEGE_WRITE_PIPELINE(Constants.PRIVILEGE_WRITE_PIPELINE_VALUE), PRIVILEGE_DELETE_PIPELINE(Constants.PRIVILEGE_DELETE_PIPELINE_VALUE), // Adapters - PRIVILEGE_CREATE_ADAPTER(Constants.PRIVILEGE_CREATE_ADAPTER_VALUE), PRIVILEGE_READ_ADAPTER(Constants.PRIVILEGE_READ_ADAPTER_VALUE), - PRIVILEGE_UPDATE_ADAPTER(Constants.PRIVILEGE_UPDATE_ADAPTER_VALUE), + PRIVILEGE_WRITE_ADAPTER(Constants.PRIVILEGE_WRITE_ADAPTER_VALUE), PRIVILEGE_DELETE_ADAPTER(Constants.PRIVILEGE_DELETE_ADAPTER_VALUE), // Pipeline Elements - PRIVILEGE_CREATE_PIPELINE_ELEMENT(Constants.PRIVILEGE_CREATE_PIPELINE_ELEMENT_VALUE), PRIVILEGE_READ_PIPELINE_ELEMENT(Constants.PRIVILEGE_READ_PIPELINE_ELEMENT_VALUE), - PRIVILEGE_UPDATE_PIPELINE_ELEMENT(Constants.PRIVILEGE_UPDATE_PIPELINE_ELEMENT_VALUE), + PRIVILEGE_WRITE_PIPELINE_ELEMENT(Constants.PRIVILEGE_WRITE_PIPELINE_ELEMENT_VALUE), PRIVILEGE_DELETE_PIPELINE_ELEMENT(Constants.PRIVILEGE_DELETE_PIPELINE_ELEMENT_VALUE), // Dashboard - PRIVILEGE_CREATE_DASHBOARD(Constants.PRIVILEGE_CREATE_DASHBOARD_VALUE), PRIVILEGE_READ_DASHBOARD(Constants.PRIVILEGE_READ_DASHBOARD_VALUE), - PRIVILEGE_UPDATE_DASHBOARD(Constants.PRIVILEGE_UPDATE_DASHBOARD_VALUE), + PRIVILEGE_WRITE_DASHBOARD(Constants.PRIVILEGE_WRITE_DASHBOARD_VALUE), PRIVILEGE_DELETE_DASHBOARD(Constants.PRIVILEGE_DELETE_DASHBOARD_VALUE), // Dashboard widget - PRIVILEGE_CREATE_DASHBOARD_WIDGET(Constants.PRIVILEGE_CREATE_DASHBOARD_WIDGET_VALUE), PRIVILEGE_READ_DASHBOARD_WIDGET(Constants.PRIVILEGE_READ_DASHBOARD_WIDGET_VALUE), - PRIVILEGE_UPDATE_DASHBOARD_WIDGET(Constants.PRIVILEGE_UPDATE_DASHBOARD_WIDGET_VALUE), + PRIVILEGE_WRITE_DASHBOARD_WIDGET(Constants.PRIVILEGE_WRITE_DASHBOARD_WIDGET_VALUE), PRIVILEGE_DELETE_DASHBOARD_WIDGET(Constants.PRIVILEGE_DELETE_DASHBOARD_WIDGET_VALUE), // Data Explorer view - PRIVILEGE_CREATE_DATA_EXPLORER_VIEW(Constants.PRIVILEGE_CREATE_DATA_EXPLORER_VIEW_VALUE), PRIVILEGE_READ_DATA_EXPLORER_VIEW(Constants.PRIVILEGE_READ_DATA_EXPLORER_VIEW_VALUE), - PRIVILEGE_UPDATE_DATA_EXPLORER_VIEW(Constants.PRIVILEGE_UPDATE_DATA_EXPLORER_VIEW_VALUE), + PRIVILEGE_WRITE_DATA_EXPLORER_VIEW(Constants.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW_VALUE), PRIVILEGE_DELETE_DATA_EXPLORER_VIEW(Constants.PRIVILEGE_DELETE_DATA_EXPLORER_VIEW_VALUE), // Data Explorer widget - PRIVILEGE_CREATE_DATA_EXPLORER_WIDGET(Constants.PRIVILEGE_CREATE_DATA_EXPLORER_WIDGET_VALUE), PRIVILEGE_READ_DATA_EXPLORER_WIDGET(Constants.PRIVILEGE_READ_DATA_EXPLORER_WIDGET_VALUE), - PRIVILEGE_UPDATE_DATA_EXPLORER_WIDGET(Constants.PRIVILEGE_UPDATE_DATA_EXPLORER_WIDGET_VALUE), + PRIVILEGE_WRITE_DATA_EXPLORER_WIDGET(Constants.PRIVILEGE_WRITE_DATA_EXPLORER_WIDGET_VALUE), PRIVILEGE_DELETE_DATA_EXPLORER_WIDGET(Constants.PRIVILEGE_DELETE_DATA_EXPLORER_WIDGET_VALUE), // Apps PRIVILEGE_READ_APPS(Constants.PRIVILEGE_READ_APPS_VALUE), - PRIVILEGE_UPDATE_APPS(Constants.PRIVILEGE_UPDATE_APPS_VALUE), + PRIVILEGE_WRITE_APPS(Constants.PRIVILEGE_WRITE_APPS_VALUE), // NOTIFICATIONS PRIVILEGE_READ_NOTIFICATIONS(Constants.PRIVILEGE_READ_NOTIFICATIONS_VALUE), // FILES PRIVILEGE_READ_FILES(Constants.PRIVILEGE_READ_FILES_VALUE), - PRIVILEGE_CREATE_FILES(Constants.PRIVILEGE_CREATE_FILES_VALUE), - PRIVILEGE_UPDATE_FILES(Constants.PRIVILEGE_UPDATE_FILES_VALUE), + PRIVILEGE_WRITE_FILES(Constants.PRIVILEGE_WRITE_FILES_VALUE), PRIVILEGE_DELETE_FILES(Constants.PRIVILEGE_DELETE_FILES_VALUE); private String privilegeString; @@ -83,49 +75,41 @@ public enum Privilege { } public static final class Constants { - public static final String PRIVILEGE_CREATE_PIPELINE_VALUE = "PRIVILEGE_CREATE_PIPELINE"; public static final String PRIVILEGE_READ_PIPELINE_VALUE = "PRIVILEGE_READ_PIPELINE"; - public static final String PRIVILEGE_UPDATE_PIPELINE_VALUE = "PRIVILEGE_UPDATE_PIPELINE"; + public static final String PRIVILEGE_WRITE_PIPELINE_VALUE = "PRIVILEGE_WRITE_PIPELINE"; public static final String PRIVILEGE_DELETE_PIPELINE_VALUE = "PRIVILEGE_DELETE_PIPELINE"; - public static final String PRIVILEGE_CREATE_ADAPTER_VALUE = "PRIVILEGE_CREATE_ADAPTER"; public static final String PRIVILEGE_READ_ADAPTER_VALUE = "PRIVILEGE_READ_ADAPTER"; - public static final String PRIVILEGE_UPDATE_ADAPTER_VALUE = "PRIVILEGE_UPDATE_ADAPTER"; + public static final String PRIVILEGE_WRITE_ADAPTER_VALUE = "PRIVILEGE_WRITE_ADAPTER"; public static final String PRIVILEGE_DELETE_ADAPTER_VALUE = "PRIVILEGE_DELETE_ADAPTER"; - public static final String PRIVILEGE_CREATE_PIPELINE_ELEMENT_VALUE = "PRIVILEGE_CREATE_PIPELINE_ELEMENT"; public static final String PRIVILEGE_READ_PIPELINE_ELEMENT_VALUE = "PRIVILEGE_READ_PIPELINE_ELEMENT"; - public static final String PRIVILEGE_UPDATE_PIPELINE_ELEMENT_VALUE = "PRIVILEGE_UPDATE_PIPELINE_ELEMENT"; + public static final String PRIVILEGE_WRITE_PIPELINE_ELEMENT_VALUE = "PRIVILEGE_WRITE_PIPELINE_ELEMENT"; public static final String PRIVILEGE_DELETE_PIPELINE_ELEMENT_VALUE = "PRIVILEGE_DELETE_PIPELINE_ELEMENT"; - public static final String PRIVILEGE_CREATE_DASHBOARD_VALUE = "PRIVILEGE_CREATE_DASHBOARD"; public static final String PRIVILEGE_READ_DASHBOARD_VALUE = "PRIVILEGE_READ_DASHBOARD"; - public static final String PRIVILEGE_UPDATE_DASHBOARD_VALUE = "PRIVILEGE_UPDATE_DASHBOARD"; + public static final String PRIVILEGE_WRITE_DASHBOARD_VALUE = "PRIVILEGE_WRITE_DASHBOARD"; public static final String PRIVILEGE_DELETE_DASHBOARD_VALUE = "PRIVILEGE_DELETE_DASHBOARD"; - public static final String PRIVILEGE_CREATE_DASHBOARD_WIDGET_VALUE = "PRIVILEGE_CREATE_DASHBOARD_WIDGET"; public static final String PRIVILEGE_READ_DASHBOARD_WIDGET_VALUE = "PRIVILEGE_READ_DASHBOARD_WIDGET"; - public static final String PRIVILEGE_UPDATE_DASHBOARD_WIDGET_VALUE = "PRIVILEGE_UPDATE_DASHBOARD_WIDGET"; + public static final String PRIVILEGE_WRITE_DASHBOARD_WIDGET_VALUE = "PRIVILEGE_WRITE_DASHBOARD_WIDGET"; public static final String PRIVILEGE_DELETE_DASHBOARD_WIDGET_VALUE = "PRIVILEGE_DELETE_DASHBOARD_WIDGET"; - public static final String PRIVILEGE_CREATE_DATA_EXPLORER_VIEW_VALUE = "PRIVILEGE_CREATE_DATA_EXPLORER_VIEW"; public static final String PRIVILEGE_READ_DATA_EXPLORER_VIEW_VALUE = "PRIVILEGE_READ_DATA_EXPLORER_VIEW"; - public static final String PRIVILEGE_UPDATE_DATA_EXPLORER_VIEW_VALUE = "PRIVILEGE_UPDATE_DATA_EXPLORER_VIEW"; + public static final String PRIVILEGE_WRITE_DATA_EXPLORER_VIEW_VALUE = "PRIVILEGE_WRITE_DATA_EXPLORER_VIEW"; public static final String PRIVILEGE_DELETE_DATA_EXPLORER_VIEW_VALUE = "PRIVILEGE_DELETE_DATA_EXPLORER_VIEW"; - public static final String PRIVILEGE_CREATE_DATA_EXPLORER_WIDGET_VALUE = "PRIVILEGE_CREATE_DATA_EXPLORER_WIDGET"; public static final String PRIVILEGE_READ_DATA_EXPLORER_WIDGET_VALUE = "PRIVILEGE_READ_DATA_EXPLORER_WIDGET"; - public static final String PRIVILEGE_UPDATE_DATA_EXPLORER_WIDGET_VALUE = "PRIVILEGE_UPDATE_DATA_EXPLORER_WIDGET"; + public static final String PRIVILEGE_WRITE_DATA_EXPLORER_WIDGET_VALUE = "PRIVILEGE_WRITE_DATA_EXPLORER_WIDGET"; public static final String PRIVILEGE_DELETE_DATA_EXPLORER_WIDGET_VALUE = "PRIVILEGE_DELETE_DATA_EXPLORER_WIDGET"; public static final String PRIVILEGE_READ_APPS_VALUE = "PRIVILEGE_READ_APPS"; - public static final String PRIVILEGE_UPDATE_APPS_VALUE = "PRIVILEGE_UPDATE_APPS"; + public static final String PRIVILEGE_WRITE_APPS_VALUE = "PRIVILEGE_WRITE_APPS"; public static final String PRIVILEGE_READ_NOTIFICATIONS_VALUE = "PRIVILEGE_READ_NOTIFICATIONS"; public static final String PRIVILEGE_READ_FILES_VALUE = "PRIVILEGE_READ_FILES"; - public static final String PRIVILEGE_CREATE_FILES_VALUE = "PRIVILEGE_CREATE_FILES"; - public static final String PRIVILEGE_UPDATE_FILES_VALUE = "PRIVILEGE_UPDATE_FILES"; + public static final String PRIVILEGE_WRITE_FILES_VALUE = "PRIVILEGE_WRITE_FILES"; public static final String PRIVILEGE_DELETE_FILES_VALUE = "PRIVILEGE_DELETE_FILES"; } } diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java index 11c5c2a..58adc39 100644 --- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java +++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java @@ -30,17 +30,15 @@ public enum Role { ROLE_PIPELINE_ADMIN( Constants.ROLE_PIPELINE_ADMIN_VALUE, - Privilege.PRIVILEGE_CREATE_PIPELINE, Privilege.PRIVILEGE_READ_PIPELINE, - Privilege.PRIVILEGE_UPDATE_PIPELINE, + Privilege.PRIVILEGE_WRITE_PIPELINE, Privilege.PRIVILEGE_DELETE_PIPELINE ), ROLE_DASHBOARD_ADMIN( Constants.ROLE_DASHBOARD_ADMIN_VALUE, - Privilege.PRIVILEGE_CREATE_DASHBOARD, Privilege.PRIVILEGE_READ_DASHBOARD, - Privilege.PRIVILEGE_UPDATE_DASHBOARD, + Privilege.PRIVILEGE_WRITE_DASHBOARD, Privilege.PRIVILEGE_DELETE_DASHBOARD ), diff --git a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/permission/PermissionManager.java similarity index 61% copy from streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java copy to streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/permission/PermissionManager.java index c42e0a4..0472dc7 100644 --- a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/permission/PermissionManager.java @@ -15,22 +15,18 @@ * limitations under the License. * */ -package org.apache.streampipes.rest.core.base.impl; +package org.apache.streampipes.manager.permission; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.SecurityContext; +import org.apache.streampipes.model.client.user.Permission; +import org.apache.streampipes.model.client.user.PermissionBuilder; +import org.apache.streampipes.model.pipeline.Pipeline; -public class AbstractAuthGuardedRestResource extends AbstractRestResource { +public class PermissionManager { - @Context - protected SecurityContext securityContext; - - protected boolean isAuthenticated() { - return this.securityContext.getUserPrincipal() != null; - } - - protected String getAuthenticatedUsername() { - return this.securityContext.getUserPrincipal().getName(); + public Permission makePermission(Pipeline pipeline, + String ownerSid) { + return PermissionBuilder + .create(pipeline.getPipelineId(), pipeline.getClass(), ownerSid) + .build(); } - } diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/PipelineManager.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/PipelineManager.java index 2e3172f..c1a0680 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/PipelineManager.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/PipelineManager.java @@ -18,16 +18,19 @@ package org.apache.streampipes.manager.pipeline; +import org.apache.streampipes.commons.random.UUIDGenerator; import org.apache.streampipes.manager.operations.Operations; +import org.apache.streampipes.manager.permission.PermissionManager; import org.apache.streampipes.manager.storage.UserManagementService; +import org.apache.streampipes.model.client.user.Permission; import org.apache.streampipes.model.pipeline.Pipeline; import org.apache.streampipes.model.pipeline.PipelineOperationStatus; +import org.apache.streampipes.storage.api.IPermissionStorage; import org.apache.streampipes.storage.api.IPipelineStorage; import org.apache.streampipes.storage.management.StorageDispatcher; import java.util.Date; import java.util.List; -import java.util.UUID; public class PipelineManager { @@ -59,17 +62,20 @@ public class PipelineManager { /** * Adds a new pipeline for the user with the username to the storage - * @param username + * @param principalSid the ID of the owner principal * @param pipeline * @return the pipelineId */ - public static String addPipeline(String username, Pipeline pipeline) { + public static String addPipeline(String principalSid, Pipeline pipeline) { // call by reference bad smell - String pipelineId = UUID.randomUUID().toString(); - preparePipelineBasics(username, pipeline, pipelineId); + String pipelineId = UUIDGenerator.generateUuid(); + preparePipelineBasics(principalSid, pipeline, pipelineId); Operations.storePipeline(pipeline); + Permission permission = new PermissionManager().makePermission(pipeline, principalSid); + getPermissionStorage().addPermission(permission); + return pipelineId; } @@ -121,4 +127,8 @@ public class PipelineManager { private static IPipelineStorage getPipelineStorage() { return StorageDispatcher.INSTANCE.getNoSqlStore().getPipelineStorageAPI(); } + + private static IPermissionStorage getPermissionStorage() { + return StorageDispatcher.INSTANCE.getNoSqlStore().getPermissionStorage(); + } } diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java index 7143075..c1a05f8 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java @@ -142,17 +142,29 @@ public class CouchDbInstallationStep extends InstallationStep { Map<String, MapReduce> views = new HashMap<>(); MapReduce passwordFunction = new MapReduce(); - passwordFunction.setMap("function(doc) { if(doc.username && doc.principalType === 'USER_ACCOUNT' && doc.password) { emit(doc.username, doc.password); } }"); + passwordFunction.setMap("function(doc) { if(doc.properties.username && doc.properties.principalType === 'USER_ACCOUNT' && doc.properties.password) { emit(doc.properties.username, doc.properties.password); } }"); MapReduce usernameFunction = new MapReduce(); - usernameFunction.setMap("function(doc) { if(doc.username) { emit(doc.username, doc); } }"); + usernameFunction.setMap("function(doc) { if(doc.properties.username) { emit(doc.properties.username, doc); } }"); + + MapReduce permissionFunction = new MapReduce(); + permissionFunction.setMap("function(doc) { if(doc.$type === 'permission') { emit(doc._id, doc); } }"); + + MapReduce groupFunction = new MapReduce(); + groupFunction.setMap("function(doc) { if(doc.$type === 'group') { emit(doc._id, doc); } }"); MapReduce tokenFunction = new MapReduce(); - tokenFunction.setMap("function(doc) { if (doc.userApiTokens) { doc.userApiTokens.forEach(function(token) { emit(token.hashedToken, doc.email); });}}"); + tokenFunction.setMap("function(doc) { if (doc.properties.userApiTokens) { doc.properties.userApiTokens.forEach(function(token) { emit(token.properties.hashedToken, doc.properties.email); });}}"); + + MapReduce userPermissionFunction = new MapReduce(); + userPermissionFunction.setMap("function(doc) { if (doc.$type === 'permission') {emit(doc.ownerSid, doc); for(var i = 0; i < doc.allowedSids.length; i++) {emit(doc.allowedSids[i],doc)}}}"); views.put("password", passwordFunction); views.put("username", usernameFunction); + views.put("groups", groupFunction); + views.put("permissions", permissionFunction); views.put("token", tokenFunction); + views.put("userpermissions", userPermissionFunction); userDocument.setViews(views); Response resp = Utils.getCouchDbUserClient().design().synchronizeWithDb(userDocument); diff --git a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java b/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java index c42e0a4..1e24ff5 100644 --- a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java +++ b/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java @@ -17,6 +17,9 @@ */ package org.apache.streampipes.rest.core.base.impl; +import org.apache.streampipes.user.management.model.PrincipalUserDetails; +import org.springframework.security.core.context.SecurityContextHolder; + import javax.ws.rs.core.Context; import javax.ws.rs.core.SecurityContext; @@ -33,4 +36,12 @@ public class AbstractAuthGuardedRestResource extends AbstractRestResource { return this.securityContext.getUserPrincipal().getName(); } + protected PrincipalUserDetails<?> getPrincipal() { + return (PrincipalUserDetails<?>) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + + protected String getAuthenticatedUserSid() { + return getPrincipal().getDetails().getPrincipalId(); + } + } 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 d741409..55345c1 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 @@ -42,6 +42,7 @@ import org.apache.streampipes.rest.impl.security.AuthConstants; import org.apache.streampipes.rest.shared.annotation.JacksonSerialized; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Component; @@ -68,11 +69,10 @@ public class PipelineResource extends AbstractAuthGuardedRestResource { mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = Pipeline.class))) })}) - @PreAuthorize(AuthConstants.IS_ADMIN_ROLE) + @PreAuthorize(AuthConstants.HAS_READ_PIPELINE_PRIVILEGE) + @PostFilter("hasPermission(filterObject.pipelineId, 'READ')") public List<Pipeline> getOwn() { return PipelineManager.getAllPipelines(); - //return ok(PipelineManager.getOwnPipelines(getAuthenticatedUsername())); - } @GET @@ -165,7 +165,7 @@ public class PipelineResource extends AbstractAuthGuardedRestResource { @PreAuthorize(AuthConstants.HAS_CREATE_PIPELINE_PRIVILEGE) public Response addPipeline(Pipeline pipeline) { - String pipelineId = PipelineManager.addPipeline(getAuthenticatedUsername(), pipeline); + String pipelineId = PipelineManager.addPipeline(getAuthenticatedUserSid(), pipeline); SuccessMessage message = Notifications.success("Pipeline stored"); message.addNotification(new Notification("id", pipelineId)); return ok(message); diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Version.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Version.java index 733b434..d56851b 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Version.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Version.java @@ -19,7 +19,7 @@ package org.apache.streampipes.rest.impl; import org.apache.streampipes.manager.info.SystemInfoProvider; import org.apache.streampipes.manager.info.VersionInfoProvider; -import org.apache.streampipes.rest.core.base.impl.AbstractRestResource; +import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -28,7 +28,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @Path("/v2/info") -public class Version extends AbstractRestResource { +public class Version extends AbstractAuthGuardedRestResource { @GET @Path("/versions") diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/AuthConstants.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/AuthConstants.java index 7ee6da7..f457f47 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/AuthConstants.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/AuthConstants.java @@ -43,5 +43,6 @@ public class AuthConstants { public static final String HAS_UPDATE_PIPELINE_PRIVILEGE = BS + IS_ADMIN_ROLE + OR + HAS_ANY_AUTHORITY + PRIVILEGE_UPDATE_PIPELINE_VALUE + Q + BE2; public static final String HAS_DELETE_PIPELINE_PRIVILEGE = BS + IS_ADMIN_ROLE + OR + HAS_ANY_AUTHORITY + PRIVILEGE_DELETE_PIPELINE_VALUE + Q + BE2; + public static final String IS_AUTHENTICATED = "isAuthenticated()"; } diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/SpPermissionEvaluator.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/SpPermissionEvaluator.java index 6769d51..d33c153 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/SpPermissionEvaluator.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/security/SpPermissionEvaluator.java @@ -17,6 +17,7 @@ */ package org.apache.streampipes.rest.impl.security; +import org.apache.streampipes.user.management.model.PrincipalUserDetails; import org.springframework.context.annotation.Configuration; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; @@ -27,14 +28,18 @@ import java.io.Serializable; public class SpPermissionEvaluator implements PermissionEvaluator { @Override - public boolean hasPermission(Authentication authentication, Object o, Object o1) { + public boolean hasPermission(Authentication authentication, Object o, Object permission) { + String objectInstanceId = (String) o; - return true; + return getUserDetails(authentication).getAllObjectPermissions().contains(objectInstanceId); } @Override - public boolean hasPermission(Authentication authentication, Serializable serializable, String s, Object o) { + public boolean hasPermission(Authentication authentication, Serializable serializable, String s, Object permission) { + return getUserDetails(authentication).getAllObjectPermissions().contains(serializable.toString()); + } - return true; + private PrincipalUserDetails<?> getUserDetails(Authentication authentication) { + return (PrincipalUserDetails<?>) authentication.getPrincipal(); } } diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java index e2ce843..8b99e42 100644 --- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java +++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java @@ -65,4 +65,6 @@ public interface INoSqlStorage { IPipelineElementDescriptionStorageCache getPipelineElementDescriptionStorage(); + IPermissionStorage getPermissionStorage(); + } diff --git a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPermissionStorage.java similarity index 62% copy from streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java copy to streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPermissionStorage.java index c42e0a4..65ac07c 100644 --- a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractAuthGuardedRestResource.java +++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPermissionStorage.java @@ -15,22 +15,25 @@ * limitations under the License. * */ -package org.apache.streampipes.rest.core.base.impl; +package org.apache.streampipes.storage.api; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.SecurityContext; +import org.apache.streampipes.model.client.user.Permission; -public class AbstractAuthGuardedRestResource extends AbstractRestResource { +import java.util.List; +import java.util.Set; - @Context - protected SecurityContext securityContext; +public interface IPermissionStorage { - protected boolean isAuthenticated() { - return this.securityContext.getUserPrincipal() != null; - } + List<Permission> getAllPermissions(); - protected String getAuthenticatedUsername() { - return this.securityContext.getUserPrincipal().getName(); - } + Permission getPermissionById(String permissionId); + + void addPermission(Permission permission); + + void updatePermission(Permission permission); + + void deletePermission(String permissionId); + + Set<String> getObjectPermissions(List<String> sids); } diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserStorage.java index d7f996a..be374cf 100644 --- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserStorage.java +++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserStorage.java @@ -17,13 +17,12 @@ */ package org.apache.streampipes.storage.api; -import org.apache.streampipes.model.client.user.Principal; -import org.apache.streampipes.model.client.user.ServiceAccount; -import org.apache.streampipes.model.client.user.UserAccount; +import org.apache.streampipes.model.client.user.*; import java.util.List; public interface IUserStorage { + List<Principal> getAllUsers(); List<UserAccount> getAllUserAccounts(); @@ -47,4 +46,5 @@ public interface IUserStorage { void deleteUser(String principalId); Principal getUserById(String principalId); + } diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java index e47f3fa..dba767e 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java @@ -135,4 +135,9 @@ public enum CouchDbStorageManager implements INoSqlStorage { public IPipelineElementDescriptionStorageCache getPipelineElementDescriptionStorage() { return new PipelineElementDescriptionStorageImpl(); } + + @Override + public IPermissionStorage getPermissionStorage() { + return new PermissionStorageImpl(); + } } diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java index 5f88886..2e26b30 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java @@ -24,47 +24,39 @@ import java.util.List; import java.util.Optional; import java.util.function.Supplier; -public class AbstractDao<T> { +public class AbstractDao<T> extends CrudDao { + + private static final String ALL_DOCS = "_all_docs"; - protected Supplier<CouchDbClient> couchDbClientSupplier; protected Class<T> clazz; public AbstractDao(Supplier<CouchDbClient> couchDbClientSupplier, Class<T> clazz) { - this.couchDbClientSupplier = couchDbClientSupplier; + super(couchDbClientSupplier); this.clazz = clazz; } public Tuple2<Boolean, String> persist(T objToPersist) { - DbCommand<Tuple2<Boolean, String>, T> cmd = new PersistCommand<>(couchDbClientSupplier, - objToPersist, - clazz); - return cmd.execute(); + return persist(objToPersist, clazz); } public Boolean delete(String key) { - DbCommand<Boolean, T> cmd = new DeleteCommand<>(couchDbClientSupplier, key, clazz); - return cmd.execute(); + return delete(key, clazz); } public Boolean update(T objToUpdate) { - DbCommand<Boolean, T> cmd = new UpdateCommand<>(couchDbClientSupplier, objToUpdate, clazz); - return cmd.execute(); + return update(objToUpdate, clazz); } public Optional<T> find(String id) { - DbCommand<Optional<T>, T> cmd = new FindCommand<>(couchDbClientSupplier, id, clazz); - return cmd.execute(); + return find(id, clazz); } public List<T> findAll() { - DbCommand<List<T>, T> cmd = new FindAllCommand<>(couchDbClientSupplier, clazz); - return cmd.execute(); + return findAll(ALL_DOCS, clazz); } public T findWithNullIfEmpty(String id) { - DbCommand<Optional<T>, T> cmd = new FindCommand<>(couchDbClientSupplier, id, clazz); - return cmd.execute().orElse(null); + return findWithNullIfEmpty(id, clazz); } - } diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/CrudDao.java similarity index 79% copy from streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java copy to streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/CrudDao.java index 5f88886..05e8c16 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/CrudDao.java @@ -24,47 +24,43 @@ import java.util.List; import java.util.Optional; import java.util.function.Supplier; -public class AbstractDao<T> { +public class CrudDao { protected Supplier<CouchDbClient> couchDbClientSupplier; - protected Class<T> clazz; - public AbstractDao(Supplier<CouchDbClient> couchDbClientSupplier, Class<T> clazz) { + public CrudDao(Supplier<CouchDbClient> couchDbClientSupplier) { this.couchDbClientSupplier = couchDbClientSupplier; - this.clazz = clazz; } - public Tuple2<Boolean, String> persist(T objToPersist) { + public <T> Tuple2<Boolean, String> persist(T objToPersist, Class<T> clazz) { DbCommand<Tuple2<Boolean, String>, T> cmd = new PersistCommand<>(couchDbClientSupplier, objToPersist, clazz); return cmd.execute(); } - public Boolean delete(String key) { + public <T> Boolean delete(String key, Class<T> clazz) { DbCommand<Boolean, T> cmd = new DeleteCommand<>(couchDbClientSupplier, key, clazz); return cmd.execute(); } - public Boolean update(T objToUpdate) { + public <T> Boolean update(T objToUpdate, Class<T> clazz) { DbCommand<Boolean, T> cmd = new UpdateCommand<>(couchDbClientSupplier, objToUpdate, clazz); return cmd.execute(); } - public Optional<T> find(String id) { + public <T> Optional<T> find(String id, Class<T> clazz) { DbCommand<Optional<T>, T> cmd = new FindCommand<>(couchDbClientSupplier, id, clazz); return cmd.execute(); } - public List<T> findAll() { - DbCommand<List<T>, T> cmd = new FindAllCommand<>(couchDbClientSupplier, clazz); + public <T> List<T> findAll(String viewName, Class<T> clazz) { + DbCommand<List<T>, T> cmd = new FindAllCommand<>(couchDbClientSupplier, clazz, viewName); return cmd.execute(); } - public T findWithNullIfEmpty(String id) { + public <T> T findWithNullIfEmpty(String id, Class<T> clazz) { DbCommand<Optional<T>, T> cmd = new FindCommand<>(couchDbClientSupplier, id, clazz); return cmd.execute().orElse(null); } - - } diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/FindAllCommand.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/CrudViewDao.java similarity index 71% copy from streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/FindAllCommand.java copy to streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/CrudViewDao.java index b5830ba..5f61635 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/FindAllCommand.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/CrudViewDao.java @@ -19,22 +19,23 @@ package org.apache.streampipes.storage.couchdb.dao; import org.lightcouch.CouchDbClient; -import java.util.Collections; import java.util.List; import java.util.function.Supplier; -public class FindAllCommand<T> extends DbCommand<List<T>, T> { +public class CrudViewDao extends CrudDao { - public FindAllCommand(Supplier<CouchDbClient> couchDbClient, Class<T> clazz) { - super(couchDbClient, clazz); + public CrudViewDao(Supplier<CouchDbClient> couchDbClientSupplier) { + super(couchDbClientSupplier); } - @Override - protected List<T> executeCommand(CouchDbClient couchDbClient) { - List<T> allResults = couchDbClient.view("_all_docs") + public <T> List<T> findByKey(String viewName, + String key, + Class<T> clazz) { + return couchDbClientSupplier + .get() + .view(viewName) + .key(key) .includeDocs(true) .query(clazz); - - return allResults != null ? allResults : Collections.emptyList(); } } diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/FindAllCommand.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/FindAllCommand.java index b5830ba..186dd64 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/FindAllCommand.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/FindAllCommand.java @@ -25,13 +25,19 @@ import java.util.function.Supplier; public class FindAllCommand<T> extends DbCommand<List<T>, T> { - public FindAllCommand(Supplier<CouchDbClient> couchDbClient, Class<T> clazz) { + private String viewName; + + public FindAllCommand(Supplier<CouchDbClient> couchDbClient, + Class<T> clazz, + String viewName) { super(couchDbClient, clazz); + this.viewName = viewName; } @Override protected List<T> executeCommand(CouchDbClient couchDbClient) { - List<T> allResults = couchDbClient.view("_all_docs") + List<T> allResults = couchDbClient + .view(viewName) .includeDocs(true) .query(clazz); diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PermissionStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PermissionStorageImpl.java new file mode 100644 index 0000000..b518c4a --- /dev/null +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PermissionStorageImpl.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.storage.couchdb.impl; + +import org.apache.streampipes.model.client.user.Permission; +import org.apache.streampipes.storage.api.IPermissionStorage; +import org.apache.streampipes.storage.couchdb.dao.CrudDao; +import org.apache.streampipes.storage.couchdb.utils.Utils; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class PermissionStorageImpl extends CrudDao implements IPermissionStorage { + + private String viewName = "users/permissions"; + + public PermissionStorageImpl() { + super(Utils::getCouchDbUserClient); + } + + @Override + public List<Permission> getAllPermissions() { + return findAll(viewName, Permission.class); + } + + @Override + public Permission getPermissionById(String permissionId) { + return findWithNullIfEmpty(permissionId, Permission.class); + } + + @Override + public void addPermission(Permission permission) { + persist(permission, Permission.class); + } + + @Override + public void updatePermission(Permission permission) { + update(permission, Permission.class); + } + + @Override + public void deletePermission(String permissionId) { + delete(permissionId, Permission.class); + } + + public Set<String> getObjectPermissions(List<String> principalSids) { + List<Permission> objectInstanceSids = couchDbClientSupplier + .get() + .view("users/userpermissions") + .keys(principalSids) + .includeDocs(true) + .query(Permission.class); + + return toPermissionSet(objectInstanceSids); + } + + private Set<String> toPermissionSet(List<Permission> permissions) { + return permissions.stream().map(Permission::getObjectInstanceId).collect(Collectors.toSet()); + } +} diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java index ef1db56..992f773 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java @@ -19,40 +19,42 @@ package org.apache.streampipes.storage.couchdb.impl; import org.apache.streampipes.model.client.user.Group; import org.apache.streampipes.storage.api.IUserGroupStorage; -import org.apache.streampipes.storage.couchdb.dao.AbstractDao; +import org.apache.streampipes.storage.couchdb.dao.CrudDao; import org.apache.streampipes.storage.couchdb.utils.Utils; import java.util.List; -public class UserGroupStorageImpl extends AbstractDao<Group> implements IUserGroupStorage { +public class UserGroupStorageImpl extends CrudDao implements IUserGroupStorage { + + private static final String viewName = "users/groups"; public UserGroupStorageImpl() { - super(Utils::getCouchDbUserGroupStorage, Group.class); + super(Utils::getCouchDbUserClient); } @Override public List<Group> getAll() { - return findAll(); + return findAll(viewName, Group.class); } @Override public void createElement(Group element) { - persist(element); + persist(element, Group.class); } @Override public Group getElementById(String s) { - return findWithNullIfEmpty(s); + return findWithNullIfEmpty(s, Group.class); } @Override public Group updateElement(Group element) { - update(element); + update(element, Group.class); return getElementById(element.getGroupId()); } @Override public void deleteElement(Group element) { - delete(element.getGroupId()); + delete(element.getGroupId(), Group.class); } } diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserStorage.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserStorage.java index 5e1b157..a9e8c40 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserStorage.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserStorage.java @@ -22,13 +22,11 @@ import org.apache.streampipes.model.client.user.Principal; import org.apache.streampipes.model.client.user.ServiceAccount; import org.apache.streampipes.model.client.user.UserAccount; import org.apache.streampipes.storage.api.IUserStorage; -import org.apache.streampipes.storage.couchdb.dao.AbstractDao; +import org.apache.streampipes.storage.couchdb.dao.CrudViewDao; import org.apache.streampipes.storage.couchdb.utils.Utils; -import org.lightcouch.CouchDbClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -36,22 +34,18 @@ import java.util.stream.Collectors; * User Storage. * Handles operations on user including user-specified pipelines. */ -public class UserStorage extends AbstractDao<Principal> implements IUserStorage { +public class UserStorage extends CrudViewDao implements IUserStorage { - Logger LOG = LoggerFactory.getLogger(UserStorage.class); + private static final Logger LOG = LoggerFactory.getLogger(UserStorage.class); + private static final String viewName = "users/username"; public UserStorage() { - super(Utils::getCouchDbUserClient, Principal.class); + super(Utils::getCouchDbUserClient); } @Override public List<Principal> getAllUsers() { - List<Principal> users = couchDbClientSupplier - .get() - .view("users/username") - .includeDocs(true) - .query(Principal.class); - return new ArrayList<>(users); + return findAll(viewName, Principal.class); } @Override @@ -74,13 +68,7 @@ public class UserStorage extends AbstractDao<Principal> implements IUserStorage @Override public Principal getUser(String username) { - // TODO improve - CouchDbClient couchDbClient = couchDbClientSupplier.get(); - List<Principal> users = couchDbClient - .view("users/username") - .key(username) - .includeDocs(true) - .query(Principal.class); + List<Principal> users = findByKey(viewName, username, Principal.class); if (users.size() != 1) { LOG.error("None or to many users with matching username"); } @@ -99,12 +87,12 @@ public class UserStorage extends AbstractDao<Principal> implements IUserStorage @Override public void storeUser(Principal user) { - persist(user); + persist(user, Principal.class); } @Override public void updateUser(Principal user) { - update(user); + update(user, Principal.class); } @Override @@ -122,24 +110,19 @@ public class UserStorage extends AbstractDao<Principal> implements IUserStorage */ @Override public boolean checkUser(String username) { - List<Principal> users = couchDbClientSupplier - .get() - .view("users/username") - .key(username) - .includeDocs(true) - .query(Principal.class); + List<Principal> users = findByKey(viewName, username, Principal.class); return users.size() == 1; } @Override public void deleteUser(String principalId) { - delete(principalId); + delete(principalId, Principal.class); } @Override public Principal getUserById(String principalId) { - return findWithNullIfEmpty(principalId); + return findWithNullIfEmpty(principalId, Principal.class); } } diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/model/PrincipalUserDetails.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/model/PrincipalUserDetails.java index 6810f6a..fc4e20c 100644 --- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/model/PrincipalUserDetails.java +++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/model/PrincipalUserDetails.java @@ -19,7 +19,8 @@ package org.apache.streampipes.user.management.model; import com.fasterxml.jackson.annotation.JsonIgnore; import org.apache.streampipes.model.client.user.Principal; -import org.apache.streampipes.user.management.util.AuthorityBuilder; +import org.apache.streampipes.user.management.util.GrantedAuthoritiesBuilder; +import org.apache.streampipes.user.management.util.GrantedPermissionsBuilder; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -31,10 +32,12 @@ public abstract class PrincipalUserDetails<T extends Principal> implements UserD protected T details; private Set<String> allAuthorities; + private Set<String> allObjectPermissions; public PrincipalUserDetails(T details) { this.details = details; - this.allAuthorities = new AuthorityBuilder(details).buildAllAuthorities(); + this.allAuthorities = new GrantedAuthoritiesBuilder(details).buildAllAuthorities(); + this.allObjectPermissions = new GrantedPermissionsBuilder(details).buildAllPermissions(); } public T getDetails() { @@ -76,4 +79,8 @@ public abstract class PrincipalUserDetails<T extends Principal> implements UserD return allAuthorities.stream().map(r -> (GrantedAuthority) () -> r).collect(Collectors.toList()); } + @JsonIgnore + public Set<String> getAllObjectPermissions() { + return allObjectPermissions; + } } diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/AuthorityBuilder.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/GrantedAuthoritiesBuilder.java similarity index 95% rename from streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/AuthorityBuilder.java rename to streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/GrantedAuthoritiesBuilder.java index 9d9e13c..0eb2d5c 100644 --- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/AuthorityBuilder.java +++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/GrantedAuthoritiesBuilder.java @@ -24,12 +24,12 @@ import org.apache.streampipes.storage.management.StorageDispatcher; import java.util.HashSet; import java.util.Set; -public class AuthorityBuilder { +public class GrantedAuthoritiesBuilder { private Set<String> allAuthorities; private Principal principal; - public AuthorityBuilder(Principal principal) { + public GrantedAuthoritiesBuilder(Principal principal) { this.allAuthorities = new HashSet<>(); this.principal = principal; } diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserStorage.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/GrantedPermissionsBuilder.java similarity index 53% copy from streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserStorage.java copy to streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/GrantedPermissionsBuilder.java index d7f996a..fa1d673 100644 --- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserStorage.java +++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/GrantedPermissionsBuilder.java @@ -15,36 +15,36 @@ * limitations under the License. * */ -package org.apache.streampipes.storage.api; +package org.apache.streampipes.user.management.util; import org.apache.streampipes.model.client.user.Principal; -import org.apache.streampipes.model.client.user.ServiceAccount; -import org.apache.streampipes.model.client.user.UserAccount; +import org.apache.streampipes.storage.management.StorageDispatcher; -import java.util.List; +import java.util.ArrayList; +import java.util.Set; -public interface IUserStorage { - List<Principal> getAllUsers(); +public class GrantedPermissionsBuilder { - List<UserAccount> getAllUserAccounts(); + private Principal principal; - List<ServiceAccount> getAllServiceAccounts(); + public GrantedPermissionsBuilder(Principal principal) { + this.principal = principal; + } - Principal getUser(String username); + public Set<String> buildAllPermissions() { + Set<String> sids = extractSids(); - UserAccount getUserAccount(String username); + return StorageDispatcher + .INSTANCE + .getNoSqlStore() + .getPermissionStorage() + .getObjectPermissions(new ArrayList<>(sids)); + } - ServiceAccount getServiceAccount(String username); + private Set<String> extractSids() { + Set<String> groupSids = principal.getGroups(); + groupSids.add(principal.getPrincipalId()); - void storeUser(Principal user); - - void updateUser(Principal user); - - boolean emailExists(String email); - - boolean checkUser(String username); - - void deleteUser(String principalId); - - Principal getUserById(String principalId); + return groupSids; + } }
