aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-be/src/main
diff options
context:
space:
mode:
authorKartik Hegde <kh00735564@techmahindra.com>2022-11-12 14:29:11 +0530
committerKartik Hegde <kh00735564@techmahindra.com>2022-12-21 12:04:30 +0000
commitcf04a1a714ef4a1df973929dc750232b4d67d7b4 (patch)
treeedd2e6e5074ba58efb98663a1ea1851208895fff /catalog-be/src/main
parentf995db01ee95606b6cded82822a73435ebc190c8 (diff)
Multitenancy in SDC
Issue-ID: SDC-4215 Change-Id: Ie24ba38acc9f1998d4a7e722e8f98456dab9201d Signed-off-by: Kartik Hegde <kh00735564@techmahindra.com>
Diffstat (limited to 'catalog-be/src/main')
-rw-r--r--catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml8
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/catalog/impl/ComponentMessage.java3
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java1
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java2
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java1
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportManager.java1
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportParseLogic.java3
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/filters/MultitenancyFilter.java270
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java24
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java47
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java41
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java1
-rw-r--r--catalog-be/src/main/resources/config/error-configuration.yaml8
-rw-r--r--catalog-be/src/main/webapp/WEB-INF/keycloak.json11
-rw-r--r--catalog-be/src/main/webapp/WEB-INF/web.xml12
15 files changed, 409 insertions, 24 deletions
diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
index 32bbf73e9d..a9df460cf2 100644
--- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
+++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
@@ -2822,6 +2822,14 @@ errors:
message: "Capability '%1' not found in '%2' '%3'."
messageId: "SVC4186"
+ #---------SVC4950-----------------------------
+ MISSING_TENANT_NAME: {
+ code: 400,
+ message: "Error: Missing Tenant name.",
+ messageId: "SVC4950"
+ }
+
+
#---------SVC4001------------------------------
NOT_PERMITTED_SPECIAL_CHARS: {
code: 406,
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/catalog/impl/ComponentMessage.java b/catalog-be/src/main/java/org/openecomp/sdc/be/catalog/impl/ComponentMessage.java
index 69a04e1df5..34e2add887 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/catalog/impl/ComponentMessage.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/catalog/impl/ComponentMessage.java
@@ -85,6 +85,9 @@ public class ComponentMessage extends CatalogComponent implements IComponentMess
setIsHighestVersion(component.isHighestVersion()); // isHighestVersion
setDescription(component.getDescription()); // description
+
+ setTenant(component.getTenant()); // tenant
+
if (component.getTags() != null) {
setTags(component.getTags()); // tags
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java
index 9c2c070c74..51444a2cc1 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java
@@ -797,6 +797,7 @@ public final class ImportUtils {
public static final String ESCAPED_DOUBLE_QUOTE = "\"";
public static final String QUOTE = "'";
public static final String VF_DESCRIPTION = "Nested VF in service";
+ public static final String TENANT = "tenant";
private Constants() {
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java
index cb57ab3b12..619a923b48 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java
@@ -1411,6 +1411,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
resourceMetaData.setIcon(ImportUtils.Constants.DEFAULT_ICON);
resourceMetaData.setContactId(user.getUserId());
resourceMetaData.setVendorName(resourceVf.getVendorName());
+ resourceMetaData.setTenant(resourceVf.getTenant());
resourceMetaData.setVendorRelease(resourceVf.getVendorRelease());
resourceMetaData.setModel(resourceVf.getModel());
// Setting tag
@@ -1444,6 +1445,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic {
cvfc.setContactId(csarInfo.getModifier().getUserId());
cvfc.setCreatorUserId(csarInfo.getModifier().getUserId());
cvfc.setVendorName(resourceVf.getVendorName());
+ cvfc.setTenant(resourceVf.getTenant());
cvfc.setVendorRelease(resourceVf.getVendorRelease());
cvfc.setModel(resourceVf.getModel());
cvfc.setResourceVendorModelNumber(resourceVf.getResourceVendorModelNumber());
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java
index 79b3c961f7..076dd50655 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java
@@ -330,6 +330,7 @@ public class ResourceImportManager {
resource.setIcon(resourceMetaData.getResourceIconPath());
resource.setResourceVendorModelNumber(resourceMetaData.getResourceVendorModelNumber());
resource.setResourceType(ResourceTypeEnum.valueOf(resourceMetaData.getResourceType()));
+ resource.setTenant(resourceMetaData.getTenant());
if (resourceMetaData.getVendorName() != null) {
resource.setVendorName(resourceMetaData.getVendorName());
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportManager.java
index 6f10aaea9c..595603ec07 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportManager.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportManager.java
@@ -62,6 +62,7 @@ public class ServiceImportManager {
public void populateServiceMetadata(UploadServiceInfo serviceMetaData, Service service) {
if (service != null && serviceMetaData != null) {
service.setDescription(serviceMetaData.getDescription());
+ service.setTenant(serviceMetaData.getTenant());
service.setTags(serviceMetaData.getTags());
service.setCategories(serviceMetaData.getCategories());
service.setContactId(serviceMetaData.getContactId());
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportParseLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportParseLogic.java
index 43b88fd63e..41babdfba5 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportParseLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportParseLogic.java
@@ -917,6 +917,7 @@ public class ServiceImportParseLogic {
cvfc.setContactId(csarInfo.getModifier().getUserId());
cvfc.setCreatorUserId(csarInfo.getModifier().getUserId());
cvfc.setVendorName(resourceVf.getVendorName());
+ cvfc.setTenant(resourceVf.getTenant());
cvfc.setVendorRelease(resourceVf.getVendorRelease());
cvfc.setResourceVendorModelNumber(resourceVf.getResourceVendorModelNumber());
cvfc.setToscaResourceName(buildNestedToscaResourceName(ResourceTypeEnum.VF.name(), csarInfo.getVfResourceName(), nodeName).getLeft());
@@ -982,6 +983,7 @@ public class ServiceImportParseLogic {
resourceMetaData.setIcon(ImportUtils.Constants.DEFAULT_ICON);
resourceMetaData.setContactId(user.getUserId());
resourceMetaData.setVendorName(resourceVf.getVendorName());
+ resourceMetaData.setTenant(resourceVf.getTenant());
resourceMetaData.setVendorRelease(resourceVf.getVendorRelease());
// Setting tag
List<String> tags = new ArrayList<>();
@@ -1306,6 +1308,7 @@ public class ServiceImportParseLogic {
cvfc.setContactId(csarInfo.getModifier().getUserId());
cvfc.setCreatorUserId(csarInfo.getModifier().getUserId());
cvfc.setVendorName("cmri");
+ cvfc.setTenant("tenant");
cvfc.setVendorRelease("1.0");
cvfc.setResourceVendorModelNumber("");
cvfc.setToscaResourceName(buildNestedToscaResourceName(ResourceTypeEnum.VF.name(), csarInfo.getVfResourceName(), nodeName).getLeft());
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/MultitenancyFilter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/MultitenancyFilter.java
new file mode 100644
index 0000000000..45dbbad587
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/MultitenancyFilter.java
@@ -0,0 +1,270 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2022 Tech-Mahindra Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.filters;
+
+import org.keycloak.adapters.*;
+import org.keycloak.adapters.servlet.FilterRequestAuthenticator;
+import org.keycloak.adapters.servlet.OIDCFilterSessionStore;
+import org.keycloak.adapters.servlet.OIDCServletHttpFacade;
+import org.keycloak.adapters.spi.*;
+import org.openecomp.sdc.common.util.Multitenancy;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+
+public class MultitenancyFilter implements Filter {
+
+ private static final Logger log = Logger.getLogger("" + MultitenancyFilter.class);
+
+ public static final String SKIP_PATTERN_PARAM = "keycloak.config.skipPattern";
+
+ public static final String ID_MAPPER_PARAM = "keycloak.config.idMapper";
+
+ public static final String CONFIG_RESOLVER_PARAM = "keycloak.config.resolver";
+
+ public static final String CONFIG_FILE_PARAM = "keycloak.config.file";
+
+ public static final String CONFIG_PATH_PARAM = "keycloak.config.path";
+
+ protected AdapterDeploymentContext deploymentContext;
+
+ protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
+
+ protected NodesRegistrationManagement nodesRegistrationManagement;
+
+ protected Pattern skipPattern;
+
+ private final KeycloakConfigResolver definedConfigResolver;
+
+ boolean keycloak;
+
+ String path = "/WEB-INF/keycloak.json";
+
+ /**
+ * Constructor that can be used to define a {@code KeycloakConfigResolver} that will be used at initialization to
+ * provide the {@code KeycloakDeployment}.
+ * @param definedConfigResolver the resolver
+ */
+ public MultitenancyFilter(KeycloakConfigResolver definedConfigResolver) {
+ this.definedConfigResolver = definedConfigResolver;
+ }
+
+ public MultitenancyFilter() {
+ this(null);
+ }
+
+ @Override
+ public void init(final FilterConfig filterConfig) throws ServletException {
+ String skipPatternDefinition = filterConfig.getInitParameter(SKIP_PATTERN_PARAM);
+ if (skipPatternDefinition != null) {
+ skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
+ }
+
+ String idMapperClassName = filterConfig.getInitParameter(ID_MAPPER_PARAM);
+ if (idMapperClassName != null) {
+ try {
+ final Class<?> idMapperClass = getClass().getClassLoader().loadClass(idMapperClassName);
+ final Constructor<?> idMapperConstructor = idMapperClass.getDeclaredConstructor();
+ Object idMapperInstance = null;
+ // for KEYCLOAK-13745 test
+ if (idMapperConstructor.getModifiers() == Modifier.PRIVATE) {
+ idMapperInstance = idMapperClass.getMethod("getInstance").invoke(null);
+ } else {
+ idMapperInstance = idMapperConstructor.newInstance();
+ }
+ if(idMapperInstance instanceof SessionIdMapper) {
+ this.idMapper = (SessionIdMapper) idMapperInstance;
+ } else {
+ log.log(Level.WARNING, "SessionIdMapper class {0} is not instance of org.keycloak.adapters.spi.SessionIdMapper", idMapperClassName);
+ }
+ } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ log.log(Level.WARNING, "SessionIdMapper class could not be instanced", e);
+ }
+ }
+
+ if (definedConfigResolver != null) {
+ deploymentContext = new AdapterDeploymentContext(definedConfigResolver);
+ log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", definedConfigResolver.getClass());
+ } else {
+ String configResolverClass = filterConfig.getInitParameter(CONFIG_RESOLVER_PARAM);
+ if (configResolverClass != null) {
+ try {
+ KeycloakConfigResolver configResolver = (KeycloakConfigResolver) getClass().getClassLoader().loadClass(configResolverClass).getDeclaredConstructor().newInstance();
+ deploymentContext = new AdapterDeploymentContext(configResolver);
+ log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
+ } catch (Exception ex) {
+ log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is not configured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
+ deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
+ }
+ } else {
+ String fp = filterConfig.getInitParameter(CONFIG_FILE_PARAM);
+ InputStream is = null;
+ if (fp != null) {
+ try {
+ is = new FileInputStream(fp);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ String pathParam = filterConfig.getInitParameter(CONFIG_PATH_PARAM);
+ if (pathParam != null) path = pathParam;
+ is = filterConfig.getServletContext().getResourceAsStream(path);
+ }
+ KeycloakDeployment kd = createKeycloakDeploymentFrom(is);
+ deploymentContext = new AdapterDeploymentContext(kd);
+ log.fine("Keycloak is using a per-deployment configuration.");
+ }
+ }
+ filterConfig.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
+ nodesRegistrationManagement = new NodesRegistrationManagement();
+ }
+
+ private KeycloakDeployment createKeycloakDeploymentFrom(InputStream is) {
+ if (is == null) {
+ log.fine("No adapter configuration. Keycloak is not configured and will deny all requests.");
+ return new KeycloakDeployment();
+ }
+ return KeycloakDeploymentBuilder.build(is);
+ }
+
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
+ log.fine("Keycloak OIDC Filter");
+ Multitenancy keyaccess= new Multitenancy();
+ keycloak= keyaccess.multiTenancyCheck();
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ if (!keycloak) {
+ chain.doFilter(req, res);
+ return;
+ }
+
+ if (shouldSkip(request)) {
+ chain.doFilter(req, res);
+ return;
+ }
+
+ OIDCServletHttpFacade facade = new OIDCServletHttpFacade(request, response);
+ KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
+ if (deployment == null || !deployment.isConfigured()) {
+ response.sendError(403);
+ log.fine("deployment not configured");
+ return;
+ }
+
+ PreAuthActionsHandler preActions = new PreAuthActionsHandler(new org.openecomp.sdc.be.filters.MultitenancyFilter.IdMapperUserSessionManagement(), deploymentContext, facade);
+
+ if (preActions.handleRequest()) {
+ return;
+ }
+
+
+ nodesRegistrationManagement.tryRegister(deployment);
+ OIDCFilterSessionStore tokenStore = new OIDCFilterSessionStore(request, facade, 100000, deployment, idMapper);
+ tokenStore.checkCurrentToken();
+
+
+ FilterRequestAuthenticator authenticator = new FilterRequestAuthenticator(deployment, tokenStore, facade, request, 8443);
+ AuthOutcome outcome = authenticator.authenticate();
+ if (outcome == AuthOutcome.AUTHENTICATED) {
+ log.fine("AUTHENTICATED");
+ if (facade.isEnded()) {
+ return;
+ }
+ AuthenticatedActionsHandler actions = new AuthenticatedActionsHandler(deployment, facade);
+ if (actions.handledRequest()) {
+ return;
+ } else {
+ HttpServletRequestWrapper wrapper = tokenStore.buildWrapper();
+ chain.doFilter(wrapper, res);
+ return;
+ }
+ }
+ AuthChallenge challenge = authenticator.getChallenge();
+ if (challenge != null) {
+ log.fine("challenge");
+ challenge.challenge(facade);
+ return;
+ }
+ response.sendError(403);
+
+ }
+
+ /**
+ * Decides whether this {@link Filter} should skip the given {@link HttpServletRequest} based on the configured {@link org.keycloak.adapters.servlet.KeycloakOIDCFilter#skipPattern}.
+ * Patterns are matched against the {@link HttpServletRequest#getRequestURI() requestURI} of a request without the context-path.
+ * A request for {@code /myapp/index.html} would be tested with {@code /index.html} against the skip pattern.
+ * Skipped requests will not be processed further by {@link org.keycloak.adapters.servlet.KeycloakOIDCFilter} and immediately delegated to the {@link FilterChain}.
+ *
+ * @param request the request to check
+ * @return {@code true} if the request should not be handled,
+ * {@code false} otherwise.
+ */
+ private boolean shouldSkip(HttpServletRequest request) {
+
+ if (skipPattern == null) {
+ return false;
+ }
+
+ String requestPath = request.getRequestURI().substring(request.getContextPath().length());
+ return skipPattern.matcher(requestPath).matches();
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+
+ private class IdMapperUserSessionManagement implements UserSessionManagement {
+ @Override
+ public void logoutAll() {
+ if (idMapper != null) {
+ idMapper.clear();
+ }
+ }
+
+ @Override
+ public void logoutHttpSessions(List<String> ids) {
+ log.fine("**************** logoutHttpSessions");
+ for (String id : ids) {
+ idMapper.removeSession(id);
+ }
+
+ }
+ }
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java
index 5e4085cf33..578319208c 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ElementServlet.java
@@ -33,6 +33,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@@ -79,9 +81,10 @@ import org.openecomp.sdc.be.ui.model.UiCategories;
import org.openecomp.sdc.be.user.UserBusinessLogic;
import org.openecomp.sdc.common.api.Constants;
import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.openecomp.sdc.common.util.Multitenancy;
import org.openecomp.sdc.exception.ResponseFormat;
import org.springframework.stereotype.Controller;
-
+import org.keycloak.representations.AccessToken;
@Path("/v1/")
/**
*
@@ -522,8 +525,23 @@ public class ElementServlet extends BeGenericServlet {
log.debug("failed to get followed resources services ");
return buildErrorResponse(followedResourcesServices.right().value());
}
- Object data = RepresentationUtils.toRepresentation(followedResourcesServices.left().value());
- return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), data);
+ Multitenancy keyaccess= new Multitenancy();
+ if (keyaccess.multiTenancyCheck()) {
+ AccessToken.Access realmAccess = keyaccess.getAccessToken(request).getRealmAccess();
+ Set<String> realmroles = realmAccess.getRoles();
+ Map<String, List<? extends Component>> dataResponse = new HashMap<>();
+ followedResourcesServices.left().value().entrySet().stream()
+ .forEach(component->{component.setValue(component.getValue().stream().filter(cm->realmroles.stream()
+ .anyMatch(role->cm.getTenant().equals(role))).collect(Collectors.toList()));
+ dataResponse.put(component.getKey(), component.getValue());
+ });
+ Object data = RepresentationUtils.toRepresentation(dataResponse);
+ return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), data);
+ }
+ else{
+ Object data = RepresentationUtils.toRepresentation(followedResourcesServices.left().value());
+ return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), data);
+ }
} catch (Exception e) {
BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Followed Resources / Services Categories");
log.debug("Getting followed resources/services failed with exception", e);
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java
index d84e40c3d8..08f26fff4a 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java
@@ -35,6 +35,7 @@ import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@@ -56,6 +57,7 @@ import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.json.JSONException;
import org.json.JSONObject;
+import org.keycloak.representations.AccessToken;
import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
import org.openecomp.sdc.be.components.impl.CsarValidationUtils;
import org.openecomp.sdc.be.components.impl.ImportUtils;
@@ -87,6 +89,7 @@ import org.openecomp.sdc.common.log.wrappers.Logger;
import org.openecomp.sdc.common.util.ValidationUtils;
import org.openecomp.sdc.common.zip.exception.ZipException;
import org.openecomp.sdc.exception.ResponseFormat;
+import org.openecomp.sdc.common.util.Multitenancy;
import org.springframework.stereotype.Controller;
@Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
@@ -115,11 +118,12 @@ public class ResourcesServlet extends AbstractValidationsServlet {
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Operation(description = "Create Resource", method = "POST", summary = "Returns created resource", responses = {
- @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
- @ApiResponse(responseCode = "201", description = "Resource created"),
- @ApiResponse(responseCode = "403", description = "Restricted operation"),
- @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
- @ApiResponse(responseCode = "409", description = "Resource already exist")})
+ @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
+ @ApiResponse(responseCode = "201", description = "Resource created"),
+ @ApiResponse(responseCode = "403", description = "Restricted operation"),
+ @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+ @ApiResponse(responseCode = "409", description = "Resource already exist"),
+ @ApiResponse(responseCode = "401", description = "Unauthorized Tenant")})
@PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
public Response createResource(@Parameter(description = "Resource object to be created", required = true) String data,
@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId)
@@ -148,14 +152,33 @@ public class ResourcesServlet extends AbstractValidationsServlet {
response = buildErrorResponse(convertResponse.right().value());
return response;
}
+ Multitenancy keyaccess = new Multitenancy();
Resource resource = convertResponse.left().value();
- Resource createdResource = resourceBusinessLogic.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, modifier, null, null);
- Object representation = RepresentationUtils.toRepresentation(createdResource);
- response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
- responseWrapper.setInnerElement(response);
- loggerSupportability
- .log(LoggerSupportabilityActions.CREATE_RESOURCE, resource.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
- "Resource successfully created user {}", userId);
+ if (keyaccess.multiTenancyCheck())
+ {
+ AccessToken.Access realmAccess = keyaccess.getAccessToken(request).getRealmAccess();
+ Set<String> realmroles = realmAccess.getRoles();
+ boolean match = realmroles.contains(resource.getTenant());
+ if (match) {
+ Resource createdResource = resourceBusinessLogic.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, modifier, null, null);
+ Object representation = RepresentationUtils.toRepresentation(createdResource);
+ response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
+ responseWrapper.setInnerElement(response);
+ loggerSupportability
+ .log(LoggerSupportabilityActions.CREATE_RESOURCE, resource.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
+ "Resource successfully created user {}", userId);
+ } else {
+ return Response.status(401, "Unauthorized Tenant").build();
+ }
+ } else {
+ Resource createdResource = resourceBusinessLogic.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, modifier, null, null);
+ Object representation = RepresentationUtils.toRepresentation(createdResource);
+ response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
+ responseWrapper.setInnerElement(response);
+ loggerSupportability
+ .log(LoggerSupportabilityActions.CREATE_RESOURCE, resource.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
+ "Resource successfully created user {}", userId);
+ }
}
return responseWrapper.getInnerElement();
} catch (final IOException | ZipException e) {
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java
index fcac7dce35..3c2b72be2a 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java
@@ -41,6 +41,7 @@ import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@@ -92,10 +93,11 @@ import org.openecomp.sdc.common.log.elements.LoggerSupportability;
import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
import org.openecomp.sdc.common.log.enums.StatusCode;
import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.openecomp.sdc.common.util.Multitenancy;
import org.openecomp.sdc.common.zip.exception.ZipException;
import org.openecomp.sdc.exception.ResponseFormat;
import org.springframework.stereotype.Controller;
-
+import org.keycloak.representations.AccessToken;
@Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
@Path("/v1/catalog")
@Server(url = "/sdc2/rest")
@@ -127,7 +129,8 @@ public class ServiceServlet extends AbstractValidationsServlet {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Service.class)))),
@ApiResponse(responseCode = "201", description = "Service created"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
@ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
- @ApiResponse(responseCode = "409", description = "Service already exist")})
+ @ApiResponse(responseCode = "409", description = "Service already exist"),
+ @ApiResponse(responseCode = "401", description = "Unauthorized Tenant")})
@PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
public Response createService(@Parameter(description = "Service object to be created", required = true) String data,
@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
@@ -141,15 +144,35 @@ public class ServiceServlet extends AbstractValidationsServlet {
if (convertResponse.isRight()) {
throw new ByResponseFormatComponentException(convertResponse.right().value());
}
+ Multitenancy keyaccess = new Multitenancy();
Service service = convertResponse.left().value();
- Either<Service, ResponseFormat> actionResponse = serviceBusinessLogic.createService(service, modifier);
- if (actionResponse.isRight()) {
- log.debug("Failed to create service");
- throw new ByResponseFormatComponentException(actionResponse.right().value());
+ if (keyaccess.multiTenancyCheck()) {
+ AccessToken.Access realmAccess = keyaccess.getAccessToken(request).getRealmAccess();
+ Set<String> realmroles = realmAccess.getRoles();
+ boolean match = realmroles.contains(service.getTenant());
+ if (match) {
+ Either<Service, ResponseFormat> actionResponse = serviceBusinessLogic.createService(service, modifier);
+ if (actionResponse.isRight()) {
+ log.debug("Failed to create service");
+ throw new ByResponseFormatComponentException(actionResponse.right().value());
+ }
+ loggerSupportability.log(LoggerSupportabilityActions.CREATE_SERVICE, service.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
+ "Service {} has been created by user {} ", service.getName(), userId);
+ return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.left().value());
+ } else {
+ log.debug("Unauthorized Tenant");
+ return Response.status(401, "Unauthorized Tenant").build();
+ }
+ } else {
+ Either<Service, ResponseFormat> actionResponse = serviceBusinessLogic.createService(service, modifier);
+ if (actionResponse.isRight()) {
+ log.debug("Failed to create service");
+ throw new ByResponseFormatComponentException(actionResponse.right().value());
+ }
+ loggerSupportability.log(LoggerSupportabilityActions.CREATE_SERVICE, service.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
+ "Service {} has been created by user {} ", service.getName(), userId);
+ return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.left().value());
}
- loggerSupportability.log(LoggerSupportabilityActions.CREATE_SERVICE, service.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
- "Service {} has been created by user {} ", service.getName(), userId);
- return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.left().value());
}
public Either<Service, ResponseFormat> parseToService(String serviceJson, User user) {
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
index ff6d015d62..68795e1003 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
@@ -546,6 +546,7 @@ public class ToscaExportHandler {
}
toscaMetadata.put(JsonPresentationFields.SUB_CATEGORY.getPresentation(), categoryDefinition.getSubcategories().get(0).getName());
toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR.getPresentation(), resource.getVendorName());
+ toscaMetadata.put(JsonPresentationFields.TENANT.getPresentation(), resource.getTenant());
toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_RELEASE.getPresentation(), resource.getVendorRelease());
toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_MODEL_NUMBER.getPresentation(), resource.getResourceVendorModelNumber());
break;
diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml
index 6bed75ef2e..c53efc21b1 100644
--- a/catalog-be/src/main/resources/config/error-configuration.yaml
+++ b/catalog-be/src/main/resources/config/error-configuration.yaml
@@ -2822,6 +2822,14 @@ errors:
message: "Capability '%1' not found in '%2' '%3'."
messageId: "SVC4186"
+
+#---------SVC4950-----------------------------
+ MISSING_TENANT_NAME: {
+ code: 400,
+ message: "Error: Missing Tenant name.",
+ messageId: "SVC4950"
+ }
+
#---------SVC4001------------------------------
NOT_PERMITTED_SPECIAL_CHARS: {
code: 406,
diff --git a/catalog-be/src/main/webapp/WEB-INF/keycloak.json b/catalog-be/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000000..d037661aec
--- /dev/null
+++ b/catalog-be/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,11 @@
+{
+"realm": "sdc",
+"auth-server-url": "http://10.32.243.37:31613/",
+"ssl-required": "external",
+"resource": "sdc-app",
+"public-client":true,
+"bearer-only":true,
+"use-resource-role-mappings": true,
+"principal-attribute":"preferred_username",
+"confidential-port": 0
+}
diff --git a/catalog-be/src/main/webapp/WEB-INF/web.xml b/catalog-be/src/main/webapp/WEB-INF/web.xml
index 9761b38043..8bd981164c 100644
--- a/catalog-be/src/main/webapp/WEB-INF/web.xml
+++ b/catalog-be/src/main/webapp/WEB-INF/web.xml
@@ -163,6 +163,18 @@
<url-pattern>/sdc/*</url-pattern>
</filter-mapping>
+ <filter>
+ <filter-name>MultitenancyFilter</filter-name>
+ <filter-class>org.openecomp.sdc.be.filters.MultitenancyFilter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>MultitenancyFilter</filter-name>
+ <url-pattern>/keycloak/*</url-pattern>
+ <url-pattern>/sdc2/rest/v1/catalog/resources/*</url-pattern>
+ <url-pattern>/sdc2/rest/v1/catalog/services/*</url-pattern>
+ <url-pattern> /sdc2/rest/v1/followed</url-pattern>
+ </filter-mapping>
+
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>
<location>/sdc2/rest/v1/catalog/handleException/</location>