diff options
author | Kartik Hegde <kh00735564@techmahindra.com> | 2022-11-12 14:29:11 +0530 |
---|---|---|
committer | Kartik Hegde <kh00735564@techmahindra.com> | 2022-12-21 12:04:30 +0000 |
commit | cf04a1a714ef4a1df973929dc750232b4d67d7b4 (patch) | |
tree | edd2e6e5074ba58efb98663a1ea1851208895fff | |
parent | f995db01ee95606b6cded82822a73435ebc190c8 (diff) |
Multitenancy in SDC
Issue-ID: SDC-4215
Change-Id: Ie24ba38acc9f1998d4a7e722e8f98456dab9201d
Signed-off-by: Kartik Hegde <kh00735564@techmahindra.com>
73 files changed, 1674 insertions, 108 deletions
diff --git a/asdctool/src/main/resources/config/error-configuration.yaml b/asdctool/src/main/resources/config/error-configuration.yaml index ba29ce6bd2..5bd933ab80 100644 --- a/asdctool/src/main/resources/config/error-configuration.yaml +++ b/asdctool/src/main/resources/config/error-configuration.yaml @@ -1988,6 +1988,13 @@ errors: messageId: "SVC4691" } + #---------SVC4950----------------------------- + MISSING_TENANT_NAME: { + code: 400, + message: "Error: Missing Tenant name.", + messageId: "SVC4950" + } + #---------POL4692------------------------------ MISSING_OLD_COMPONENT_INSTANCE: { code: 400 , 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> diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogicTest.java index 9fb0efb862..60d45ea752 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogicTest.java @@ -38,6 +38,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.HashMap; +import java.util.stream.Collectors; +import org.junit.Assert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -68,6 +71,8 @@ import org.openecomp.sdc.exception.ResponseFormat; class ElementBusinessLogicTest extends BaseBusinessLogicMock { + private static final boolean MULTITENANCY_ENABLED = true; + private static final String TEST_TENANT = "test_tenant"; private User user; @Mock @@ -319,4 +324,83 @@ class ElementBusinessLogicTest extends BaseBusinessLogicMock { assertTrue(elementBusinessLogic.getBaseTypes("CAT01", user.getUserId(), null).isRight()); } + + @Test + void testGetFollowed_withMultitenancyValidTenant_thenReturnsSuccess() { + Assert.assertTrue(MULTITENANCY_ENABLED); + user.setUserId("admin1"); + user.setRole(Role.ADMIN.name()); + Set<Component> resources = new HashSet<>(); + Set<Component> services = new HashSet<>(); + Resource resource = new Resource(); + Service service = new Service(); + service.setTenant(TEST_TENANT); + resource.setTenant(TEST_TENANT); + Assert.assertNotNull(service.getTenant()); + Assert.assertNotNull(resource.getTenant()); + resources.add(resource); + services.add(service); + Assert.assertNotNull(getTestRoles()); + Assert.assertTrue(getTestRoles().contains(TEST_TENANT)); + + when(toscaOperationFacade.getFollowed(any(), anySet(), any(), eq(ComponentTypeEnum.RESOURCE))) + .thenReturn(Either.left(resources)); + when(toscaOperationFacade.getFollowed(any(), anySet(), any(), eq(ComponentTypeEnum.SERVICE))) + .thenReturn(Either.left(services)); + Map<String, List<? extends Component>> result = elementBusinessLogic.getFollowed(user).left().value(); + Set<String> realmroles =getTestRoles(); + Map<String, List<? extends Component>> dataResponse = new HashMap<>(); + result.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()); + }); + assertEquals(result.size(), dataResponse.values().size()); + assertEquals(1, dataResponse.get("services").size()); + assertEquals(1, dataResponse.get("resources").size()); + } + + @Test + void testGetFollowed_withMultitenancyInValidTenant_thenReturnsEmptyList() { + String INVALID_TENANT="invalid_tenant"; + Assert.assertTrue(MULTITENANCY_ENABLED); + user.setUserId("admin1"); + user.setRole(Role.ADMIN.name()); + Set<Component> resources = new HashSet<>(); + Set<Component> services = new HashSet<>(); + Resource resource = new Resource(); + Service service = new Service(); + service.setTenant(INVALID_TENANT); + resource.setTenant(INVALID_TENANT); + Assert.assertNotNull(service.getTenant()); + Assert.assertNotNull(resource.getTenant()); + resources.add(resource); + services.add(service); + Assert.assertNotNull(getTestRoles()); + + when(toscaOperationFacade.getFollowed(any(), anySet(), any(), eq(ComponentTypeEnum.RESOURCE))) + .thenReturn(Either.left(resources)); + when(toscaOperationFacade.getFollowed(any(), anySet(), any(), eq(ComponentTypeEnum.SERVICE))) + .thenReturn(Either.left(services)); + Map<String, List<? extends Component>> result = elementBusinessLogic.getFollowed(user).left().value(); + Set<String> realmroles =getTestRoles(); + Map<String, List<? extends Component>> dataResponse = new HashMap<>(); + result.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()); + }); + + assertEquals(result.size(), dataResponse.values().size(),"No Data available for "+INVALID_TENANT); + assertEquals(0, dataResponse.get("services").size()); + assertEquals(0, dataResponse.get("resources").size()); + } + + private Set<String> getTestRoles(){ + Set<String> roles = new HashSet<>(); + roles.add("test_admin"); + roles.add("test_tenant"); + return roles; + } + }
\ No newline at end of file diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogicTest.java index 714ec20c10..e9735710da 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogicTest.java @@ -47,12 +47,16 @@ import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.HashSet; import java.util.Map.Entry; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.servlet.ServletContext; import org.apache.commons.lang3.tuple.ImmutablePair; +import org.hamcrest.MatcherAssert; +import org.junit.Assert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -171,6 +175,8 @@ class ResourceBusinessLogicTest { private static final String GENERIC_VF_NAME = "org.openecomp.resource.abstract.nodes.VF"; private static final String GENERIC_CR_NAME = "org.openecomp.resource.abstract.nodes.CR"; private static final String GENERIC_PNF_NAME = "org.openecomp.resource.abstract.nodes.PNF"; + private static final boolean MULTITENANCY_ENABLED = true; + private static final String TEST_TENANT = "test_tenant"; private final ServletContext servletContext = Mockito.mock(ServletContext.class); private IElementOperation mockElementDao; @@ -2556,4 +2562,55 @@ class ResourceBusinessLogicTest { assertEquals(ActionStatus.COMPONENT_IN_USE_BY_ANOTHER_COMPONENT, actualOperationException.getActionStatus()); assertEquals("resource_name", actualOperationException.getParams()[0]); } + + + @Test + void testCreateResource_withMultitenancyWithTenant_Success() { + Assert.assertTrue(MULTITENANCY_ENABLED); + validateUserRoles(Role.ADMIN, Role.DESIGNER); + Resource resource = createResourceObject(false); + resource.setTenant(TEST_TENANT); + Resource createdResource = null; + try { + when(toscaOperationFacade + .validateComponentNameAndModelExists(resource.getName(), null, ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE)) + .thenReturn(Either.left(false)); + createdResource = bl.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, user, null, null); + assertThat(createResourceObject(true)).isEqualTo(createdResource); + MatcherAssert.assertThat("Unauthorized Tenant", getTestRoles().contains(resource.getTenant())); + } catch (ComponentException e) { + assertThat(Integer.valueOf(200)).isEqualTo(e.getResponseFormat() + .getStatus()); + } + } + + @Test + void testCreateResource_withMultitenancyWithInvalidTenant_Failure() { + Assert.assertTrue(MULTITENANCY_ENABLED); + validateUserRoles(Role.ADMIN, Role.DESIGNER); + Resource resource = createResourceObject(false); + resource.setTenant("invalid_tenant"); + Resource createdResource = null; + try { + MatcherAssert.assertThat("Unauthorized Tenant", !getTestRoles().contains(resource.getTenant())); + when(toscaOperationFacade + .validateComponentNameAndModelExists(resource.getName(), null, ResourceTypeEnum.VFC, ComponentTypeEnum.RESOURCE)) + .thenReturn(Either.left(false)); + createdResource = bl.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, user, null, null); + + assertThat(createResourceObject(true)).isEqualTo(createdResource); + MatcherAssert.assertThat("Unauthorized Tenant", !getTestRoles().contains(resource.getTenant())); + } catch (ComponentException e) { + assertThat(new Integer(200)).isEqualTo(e.getResponseFormat() + .getStatus()); + } + } + + private Set<String> getTestRoles(){ + Set<String> roles = new HashSet<>(); + roles.add("test_admin"); + roles.add("test_tenant"); + return roles; + } + } diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java index 69938cd527..a5f823b12f 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java @@ -30,6 +30,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.when; @@ -44,8 +46,12 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.Set; +import java.util.HashSet; import org.apache.commons.lang3.tuple.ImmutablePair; +import org.hamcrest.MatcherAssert; +import org.junit.Assert; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.openecomp.sdc.be.components.impl.exceptions.ComponentException; @@ -83,6 +89,8 @@ class ServiceBusinessLogicTest extends ServiceBusinessLogicBaseTestSetup { private final static String DEFAULT_ICON = "defaulticon"; private static final String ALREADY_EXIST = "alreadyExist"; + private static final boolean MULTITENANCY_ENABLED = true; + private static final String TEST_TENANT = "test_tenant"; @Test void testGetComponentAuditRecordsCertifiedVersion() { @@ -1069,4 +1077,39 @@ class ServiceBusinessLogicTest extends ServiceBusinessLogicBaseTestSetup { return propertyList; } + + @Test + void testCreateService_withMultitenancyValidTenant_Success() { + Assert.assertTrue(MULTITENANCY_ENABLED); + Service service = createServiceObject(false); + service.setTenant(TEST_TENANT); + when(genericTypeBusinessLogic.fetchDerivedFromGenericType(service, null)).thenReturn(Either.left(genericService)); + Either<Service, ResponseFormat> createResponse = bl.createService(service, user); + + if (createResponse.isRight()) { + assertEquals(new Integer(200), createResponse.right().value().getStatus()); + } + MatcherAssert.assertThat("Unauthorized Tenant", getTestRoles().contains(service.getTenant())); + assertEquals(TEST_TENANT, service.getTenant()); + assertEqualsServiceObject(createServiceObject(true), createResponse.left().value()); + } + + + @Test + void testCreateService_withMultitenancyInvalidTenant_Failure() { + Service service = createServiceObject(false); + service.setTenant("invalid_tenant"); + when(genericTypeBusinessLogic.fetchDerivedFromGenericType(service, null)).thenReturn(Either.left(genericService)); + Either<Service, ResponseFormat> createResponse = bl.createService(service, user); + MatcherAssert.assertThat("Unauthorized Tenant", !getTestRoles().contains(service.getTenant())); + assertNotEquals(TEST_TENANT, service.getTenant()); + assertEqualsServiceObject(createServiceObject(true), createResponse.left().value()); + } + + private Set<String> getTestRoles(){ + Set<String> roles = new HashSet<>(); + roles.add("test_admin"); + roles.add("test_tenant"); + return roles; + } } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java index cd5a6e5d7a..0150ebe891 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java @@ -150,5 +150,7 @@ public enum ActionStatus { COMPONENT_PROPERTY_NOT_FOUND, INVALID_COMPONENT_TYPE, DATA_TYPE_PROPERTY_ALREADY_EXISTS, - UNEXPECTED_ERROR + UNEXPECTED_ERROR, + //Tenant + MISSING_TENANT, TENANT_NAME_EXCEEDS_LIMIT, INVALID_TENANT_NAME, UNAUTHORIZED_TENANT } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java index c689298fc1..15fc013173 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java @@ -50,6 +50,7 @@ public enum GraphPropertiesDictionary { CONSTRAINTS ("constraints", String.class, false, false), CONTACT_ID ("contactId", String.class, false, false), VENDOR_NAME ("vendorName", String.class, false, false), + TENANT ("tenant", String.class, false, false), VENDOR_RELEASE ("vendorRelease", String.class, false, false), MODEL ("model", String.class, false, false), MODEL_TYPE ("modelType", String.class, false, false), diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionaryExtractor.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionaryExtractor.java index 3b11743050..da32017d90 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionaryExtractor.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionaryExtractor.java @@ -136,6 +136,10 @@ public class GraphPropertiesDictionaryExtractor { return (String) properties.get(GraphPropertiesDictionary.VENDOR_NAME.getProperty()); } + public String getTenant() { + return (String) properties.get(GraphPropertiesDictionary.TENANT.getProperty()); + } + public String getVendorRelease() { return (String) properties.get(GraphPropertiesDictionary.VENDOR_RELEASE.getProperty()); } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java index 602d53ed26..7f05f56f13 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java @@ -63,6 +63,7 @@ public abstract class ComponentMetadataData extends GraphNode { metadataDataDefinition.setImportedToscaChecksum(extractor.getImportedToscaChecksum()); metadataDataDefinition.setInvariantUUID(extractor.getInvariantUuid()); metadataDataDefinition.setModel(extractor.getModel()); + metadataDataDefinition.setTenant(extractor.getTenant()); componentInstanceCounter = extractor.getInstanceCounter(); } @@ -92,6 +93,7 @@ public abstract class ComponentMetadataData extends GraphNode { addIfExists(map, GraphPropertiesDictionary.IMPORTED_TOSCA_CHECKSUM, metadataDataDefinition.getImportedToscaChecksum()); addIfExists(map, GraphPropertiesDictionary.INVARIANT_UUID, metadataDataDefinition.getInvariantUUID()); addIfExists(map, GraphPropertiesDictionary.MODEL, metadataDataDefinition.getModel()); + addIfExists(map, GraphPropertiesDictionary.TENANT, metadataDataDefinition.getTenant()); return map; } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ResourceMetadataData.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ResourceMetadataData.java index 1b5f948c1c..6eb56932ec 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ResourceMetadataData.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ResourceMetadataData.java @@ -47,6 +47,7 @@ public class ResourceMetadataData extends ComponentMetadataData { resourceMetadataDataDefinition.setLicenseType(extractor.getLicenseType()); resourceMetadataDataDefinition.setToscaResourceName(extractor.getToscaResourceName()); resourceMetadataDataDefinition.setCsarVersionId(extractor.getCsarVersionId()); + resourceMetadataDataDefinition.setTenant(extractor.getTenant()); } @Override @@ -61,6 +62,7 @@ public class ResourceMetadataData extends ComponentMetadataData { addIfExists(graphMap, GraphPropertiesDictionary.LICENSE_TYPE, resourceMetadataDataDefinition.getLicenseType()); addIfExists(graphMap, GraphPropertiesDictionary.TOSCA_RESOURCE_NAME, resourceMetadataDataDefinition.getToscaResourceName()); addIfExists(graphMap, GraphPropertiesDictionary.CSAR_VERSION_ID, resourceMetadataDataDefinition.getCsarVersionId()); + addIfExists(graphMap, GraphPropertiesDictionary.TENANT, resourceMetadataDataDefinition.getTenant()); return graphMap; } } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Component.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Component.java index 0e9c44a382..1fd02da5e8 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Component.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Component.java @@ -213,6 +213,14 @@ public abstract class Component implements PropertiesOwner { componentMetadataDefinition.getMetadataDataDefinition().setDescription(description); } + public String getTenant() { + return componentMetadataDefinition.getMetadataDataDefinition().getTenant(); + } + + public void setTenant(String tenant) { + componentMetadataDefinition.getMetadataDataDefinition().setTenant(tenant); + } + public LifecycleStateEnum getLifecycleState() { if (componentMetadataDefinition.getMetadataDataDefinition().getState() != null) { return LifecycleStateEnum.valueOf(componentMetadataDefinition.getMetadataDataDefinition().getState()); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java index 0b54e0bea7..f0fbc5d550 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java @@ -113,6 +113,14 @@ public class Resource extends Component implements Serializable { getResourceMetadataDataDefinition().setVendorName(vendorName); } + public String getTenant() { + return getResourceMetadataDataDefinition().getTenant(); + } + + public void setTenant(String tenant) { + getResourceMetadataDataDefinition().setTenant(tenant); + } + public String getVendorRelease() { return getResourceMetadataDataDefinition().getVendorRelease(); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Service.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Service.java index bc8efb528d..061a78b5e8 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Service.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Service.java @@ -197,6 +197,10 @@ public class Service extends Component { getMetadataDefinition().setVendorName(vendorName); } + public void setTenant(String tenant) { + getMetadataDefinition().setTenant(tenant); + } + public void setVendorRelease(String vendorRelease) { getMetadataDefinition().setVendorRelease(vendorRelease); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadResourceInfo.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadResourceInfo.java index e853b64f93..b3d0c53f4a 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadResourceInfo.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadResourceInfo.java @@ -42,6 +42,7 @@ public class UploadResourceInfo { private String resourceIconPath; private String icon; private String vendorName; + private String tenant; private String vendorRelease; private String resourceVendorModelNumber; private String resourceType = "VFC"; diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadServiceInfo.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadServiceInfo.java index 1c12a3e463..d709947cfa 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadServiceInfo.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadServiceInfo.java @@ -58,6 +58,7 @@ public class UploadServiceInfo { private String serviceIconPath; private String icon; private String vendorName; + private String tenant; private String vendorRelease; private String serviceVendorModelNumber; private String serviceType = ""; diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/catalog/CatalogComponent.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/catalog/CatalogComponent.java index f65c84f474..cd056eede2 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/catalog/CatalogComponent.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/catalog/CatalogComponent.java @@ -54,6 +54,7 @@ public class CatalogComponent { private String lastUpdaterUserId; private List<CategoryDefinition> categories; private String model; + private String tenant; public List<String> getTags() { return tags == null ? Collections.emptyList() : ImmutableList.copyOf(tags); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java index caedbeeb62..65c109c3f6 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java @@ -1372,6 +1372,7 @@ public abstract class ToscaElementOperation extends BaseOperation { catalogComponent.setLastUpdateDate((lastUpdateDate != null ? (Long) lastUpdateDate : 0L)); catalogComponent.setDistributionStatus((String) metadatObj.get(JsonPresentationFields.DISTRIBUTION_STATUS.getPresentation())); catalogComponent.setDescription((String) metadatObj.get(JsonPresentationFields.DESCRIPTION.getPresentation())); + catalogComponent.setTenant((String) metadatObj.get(JsonPresentationFields.TENANT.getPresentation())); catalogComponent.setSystemName((String) metadatObj.get(JsonPresentationFields.SYSTEM_NAME.getPresentation())); catalogComponent.setUuid((String) metadatObj.get(JsonPresentationFields.UUID.getPresentation())); catalogComponent.setInvariantUUID((String) metadatObj.get(JsonPresentationFields.INVARIANT_UUID.getPresentation())); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java index a246a1a406..7924e09f79 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java @@ -814,6 +814,7 @@ public class ModelConverter { component.setConformanceLevel((String) toscaElement.getMetadataValue(JsonPresentationFields.CONFORMANCE_LEVEL)); component.setIcon((String) toscaElement.getMetadataValue(JsonPresentationFields.ICON)); component.setDescription((String) toscaElement.getMetadataValue(JsonPresentationFields.DESCRIPTION)); + component.setTenant((String) toscaElement.getMetadataValue(JsonPresentationFields.TENANT)); component.setTags((List<String>) toscaElement.getMetadataValue(JsonPresentationFields.TAGS)); component.setInvariantUUID((String) toscaElement.getMetadataValue(JsonPresentationFields.INVARIANT_UUID)); component.setContactId((String) toscaElement.getMetadataValue(JsonPresentationFields.CONTACT_ID)); @@ -1381,6 +1382,7 @@ public class ModelConverter { toscaElement.setMetadataValue(JsonPresentationFields.IS_DELETED, component.getIsDeleted()); toscaElement.setMetadataValue(JsonPresentationFields.ICON, component.getIcon()); toscaElement.setMetadataValue(JsonPresentationFields.DESCRIPTION, component.getDescription()); + toscaElement.setMetadataValue(JsonPresentationFields.TENANT, component.getTenant()); toscaElement.setMetadataValue(JsonPresentationFields.TAGS, component.getTags()); toscaElement.setMetadataValue(JsonPresentationFields.INVARIANT_UUID, component.getInvariantUUID()); toscaElement.setMetadataValue(JsonPresentationFields.CONTACT_ID, component.getContactId()); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java index a0d7873d2d..d760614d3e 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java @@ -33,7 +33,7 @@ public abstract class UiComponentMetadata { private String uniqueId; private String name; // archiveName - + private String tenant; private String version; // archiveVersion private Boolean isHighestVersion; private Long creationDate; @@ -100,5 +100,6 @@ public abstract class UiComponentMetadata { this.archiveTime = metadata.getArchiveTime(); this.isVspArchived = metadata.isVspArchived(); this.model = metadata.getModel(); + this.tenant = metadata.getTenant(); } } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java index 9cc5294f5b..b8b9d72e0a 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java @@ -44,6 +44,7 @@ public class UiResourceMetadata extends UiComponentMetadata { private List<String> derivedFrom; private Map<String, String> categorySpecificMetadata; private String csarVersionId; + private String tenant; public UiResourceMetadata(List<CategoryDefinition> categories, List<String> derivedFrom, ResourceMetadataDataDefinition metadata) { super(categories, metadata); @@ -57,5 +58,6 @@ public class UiResourceMetadata extends UiComponentMetadata { this.derivedFrom = derivedFrom; this.categorySpecificMetadata = metadata.getCategorySpecificMetadata(); this.csarVersionId = metadata.getCsarVersionId(); + this.tenant = metadata.getTenant(); } } diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/util/Multitenancy.java b/common-app-api/src/main/java/org/openecomp/sdc/common/util/Multitenancy.java new file mode 100644 index 0000000000..c91f3e3621 --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/util/Multitenancy.java @@ -0,0 +1,60 @@ +/*- + * ============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.common.util; + + +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.keycloak.KeycloakPrincipal; +import org.keycloak.representations.AccessToken; +import org.openecomp.sdc.common.log.wrappers.Logger; +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + + +/** + * To check the Multitenancy + */ + +public class Multitenancy { + private static final Logger log = Logger.getLogger(Multitenancy.class); + private boolean keycloak; + public AccessToken getAccessToken(HttpServletRequest request){ + KeycloakPrincipal principal = (KeycloakPrincipal) request.getUserPrincipal(); + return principal.getKeycloakSecurityContext().getToken(); + } + + public boolean multiTenancyCheck() { + log.info("Checking the Multitenancy "); + try (InputStream ioStream = Multitenancy.class.getResourceAsStream("/multitenancy.json"); + BufferedReader br = new BufferedReader(new InputStreamReader(ioStream, StandardCharsets.UTF_8))) { + keycloak = (boolean) ((JSONObject) new JSONParser().parse(br)).get("multitenancy"); + } catch (Exception e) { + log.debug("Multitenancy Exception", e); + } + log.info("Multitenancy= {}",keycloak); + return keycloak; + } +} diff --git a/common-app-api/src/main/resources/multitenancy.json b/common-app-api/src/main/resources/multitenancy.json new file mode 100644 index 0000000000..43405f4666 --- /dev/null +++ b/common-app-api/src/main/resources/multitenancy.json @@ -0,0 +1,3 @@ +{ + "multitenancy": false +}
\ No newline at end of file diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java index 4b94adb829..0a1c03a32e 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java @@ -49,6 +49,7 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio private Long creationDate; private Long lastUpdateDate; private String description; + private String tenant; private String state; private List<String> tags; private String conformanceLevel; @@ -84,6 +85,7 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio this.creationDate = other.getCreationDate(); this.lastUpdateDate = other.getLastUpdateDate(); this.description = other.getDescription(); + this.tenant = other.getTenant(); this.state = other.getState(); this.tags = new ArrayList<>(other.getTags() != null ? other.getTags() : new LinkedList<>()); this.icon = other.getIcon(); @@ -114,6 +116,7 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio this.creationDate = extractor.getCreationDate(); this.lastUpdateDate = extractor.getLastUpdateDate(); this.description = extractor.getDescription(); + this.tenant = extractor.getTenant(); this.state = extractor.getState(); this.tags = extractor.getTags(); this.icon = extractor.getIcon(); diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ServiceMetadataDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ServiceMetadataDataDefinition.java index b9a0dc73a8..2456b67b0c 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ServiceMetadataDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ServiceMetadataDataDefinition.java @@ -42,6 +42,7 @@ public class ServiceMetadataDataDefinition extends ComponentMetadataDataDefiniti private ResourceTypeEnum importServiceType = ResourceTypeEnum.SERVICE; private String toscaServiceName; private String vendorName; + private String tenant; private String vendorRelease; public ServiceMetadataDataDefinition(JsonPresentationFieldsExtractor extractor) { diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java index 6e845a0a8f..ad10a63cfa 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java @@ -72,6 +72,7 @@ public enum JsonPresentationFields { MODEL("model", null), NORMATIVE("normative", null), DATA_TYPES("data_types", GraphPropertyEnum.DATA_TYPES), + TENANT("tenant", null), ////Inputs ANNOTATIONS("annotations", null), diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFieldsExtractor.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFieldsExtractor.java index f497066572..3808ac78f9 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFieldsExtractor.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFieldsExtractor.java @@ -177,4 +177,9 @@ public class JsonPresentationFieldsExtractor { public Boolean isNormative() { return (Boolean) properties.get(JsonPresentationFields.NORMATIVE.getPresentation()); } + + public String getTenant() { + return (String) properties.get(JsonPresentationFields.TENANT.getPresentation()); + } + } diff --git a/docs/logging.rst b/docs/logging.rst index 777068bef3..a59f340925 100644 --- a/docs/logging.rst +++ b/docs/logging.rst @@ -3764,3 +3764,14 @@ Response Types message: "Error: Interface operation input parameter name should not be empty", messageId: "SVC46703" } + +---------SVC4750----------------------------- +============================================== + +:: + + MISSING_TENANT_NAME: { + code: 400, + message: "Error: Missing Tenant name.", + messageId: "SVC4750" + }
\ No newline at end of file diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/Items.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/Items.java index 066acb9370..a2c0e39e8f 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/Items.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/Items.java @@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tags; +import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -35,6 +36,7 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.openecomp.sdc.versioning.types.Item; @@ -61,7 +63,7 @@ public interface Items { @QueryParam("permission") String permissionFilter, @Parameter(description = "Filter by onboarding method", schema = @Schema(type = "string", allowableValues = {"NetworkPackage", "manual"})) @QueryParam("onboardingMethod") String onboardingMethodFilter, - @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user); + @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user, @Context HttpServletRequest hreq); @GET @Path("/{itemId}") diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/mapping/MapItemToDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/mapping/MapItemToDto.java index 3bd8a7fe9f..0eb74a03b6 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/mapping/MapItemToDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/mapping/MapItemToDto.java @@ -34,5 +34,6 @@ public class MapItemToDto extends MappingBase<Item, ItemDto> { target.setOwner(source.getOwner()); target.setStatus(source.getStatus().name()); target.setProperties(source.getProperties()); + target.setTenant(source.getTenant()); } } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java index 9fb6ebd8b8..af3568cd2a 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/main/java/org/openecomp/sdcrests/item/rest/services/ItemsImpl.java @@ -35,12 +35,15 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import javax.inject.Named; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; +import org.keycloak.representations.AccessToken; import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity; import org.openecomp.sdc.activitylog.dao.type.ActivityType; import org.openecomp.sdc.be.csar.storage.StorageFactory; import org.openecomp.sdc.common.errors.ErrorCode.ErrorCodeBuilder; import org.openecomp.sdc.common.errors.ErrorCodeAndMessage; +import org.openecomp.sdc.common.util.Multitenancy; import org.openecomp.sdc.datatypes.model.ItemType; import org.openecomp.sdc.itempermissions.impl.types.PermissionTypes; import org.openecomp.sdc.logging.api.Logger; @@ -116,15 +119,27 @@ public class ItemsImpl implements Items { @Override public Response list(String itemStatusFilter, String versionStatusFilter, String itemTypeFilter, String permissionFilter, - String onboardingMethodFilter, String user) { + String onboardingMethodFilter, String user, HttpServletRequest hreq) { Predicate<Item> itemPredicate = createItemPredicate(itemStatusFilter, versionStatusFilter, itemTypeFilter, onboardingMethodFilter, permissionFilter, user); GenericCollectionWrapper<ItemDto> results = new GenericCollectionWrapper<>(); MapItemToDto mapper = new MapItemToDto(); - getManagersProvider().getItemManager().list(itemPredicate).stream() - .sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) - .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class))); - return Response.ok(results).build(); + Multitenancy keyaccess= new Multitenancy(); + if (keyaccess.multiTenancyCheck()) { + AccessToken.Access realmAccess = keyaccess.getAccessToken(hreq).getRealmAccess(); + Set<String> realmroles = realmAccess.getRoles(); + realmroles.stream().forEach(role -> getManagersProvider().getItemManager().list(itemPredicate).stream() + .sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) + .filter(item -> item.getTenant().contains(role)) + .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class)))); + return Response.ok(results).build(); + } + else{ + getManagersProvider().getItemManager().list(itemPredicate).stream() + .sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) + .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class))); + return Response.ok(results).build(); + } } @Override diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/test/java/org/openecomp/sdcrests/item/rest/services/ItemsImplTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/test/java/org/openecomp/sdcrests/item/rest/services/ItemsImplTest.java index 25de08304b..da3e6f3297 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/test/java/org/openecomp/sdcrests/item/rest/services/ItemsImplTest.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-services/src/test/java/org/openecomp/sdcrests/item/rest/services/ItemsImplTest.java @@ -22,6 +22,7 @@ package org.openecomp.sdcrests.item.rest.services; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -39,7 +40,11 @@ import io.minio.MinioClient; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.HashSet; +import java.util.Set; import javax.ws.rs.core.Response; + +import org.junit.Assert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -58,6 +63,7 @@ import org.openecomp.sdc.versioning.ItemManager; import org.openecomp.sdc.versioning.VersioningManager; import org.openecomp.sdc.versioning.dao.types.Version; import org.openecomp.sdc.versioning.types.Item; +import org.openecomp.sdc.versioning.types.ItemStatus; import org.openecomp.sdcrests.item.types.ItemActionRequestDto; @ExtendWith(MockitoExtension.class) @@ -71,6 +77,8 @@ class ItemsImplTest { private static final String CREDENTIALS = "credentials"; private static final String TEMP_PATH = "tempPath"; private static final String UPLOAD_PARTSIZE = "uploadPartSize"; + private static final boolean MULTITENANCY_ENABLED = true; + private static final String TEST_TENANT = "test_tenant"; @Mock private ManagersProvider managersProvider; @@ -190,7 +198,7 @@ class ItemsImplTest { items.initActionSideAffectsMap(); items.setManagersProvider(managersProvider); when(managersProvider.getItemManager()).thenReturn(itemManager); - Response response = items.list(null, null, null, null, null, USER); + Response response = items.list(null, null, null, null, null, USER, null); assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); } @@ -201,4 +209,78 @@ class ItemsImplTest { versions.add(new Version("3")); return versions; } + + @Test + void getItemList_withMultitenancyValidTenant_ReturnSuccessList() { + Assert.assertTrue(MULTITENANCY_ENABLED); + Assert.assertNotNull(getTestRoles()); + items.initActionSideAffectsMap(); + items.setManagersProvider(managersProvider); + when(managersProvider.getItemManager()).thenReturn(itemManager); + Response response = items.list(null, null, null, null, null, USER, null); + assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); + List<Item> expectedItems=new ArrayList<>(); + List<Item> actualItems=getAllItems(); + getTestRoles().stream().forEach(role -> getAllItems().stream() + .filter(item -> item.getTenant()!=null) + .filter(item -> item.getTenant().contains(role)) + .forEach(item -> expectedItems.add(item))); + assertNotSame(expectedItems.size(), actualItems.size()); + } + + + @Test + void getItemList_withMultitenancyInvalidTenant_ReturnsEmptylList() { + Assert.assertTrue(MULTITENANCY_ENABLED); + + Assert.assertNotNull(getTestRoles()); + String tenant= "invalid tenant"; + items.initActionSideAffectsMap(); + items.setManagersProvider(managersProvider); + when(managersProvider.getItemManager()).thenReturn(itemManager); + Response response = items.list(null, null, null, null, null, USER, null); + assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); + List<Item> expectedItems=new ArrayList<>(); + List<Item> actualItems=getAllItems(); + assertNotNull(tenant); + getTestRoles().stream().forEach(role -> getAllItems().stream() + .filter(item -> item.getTenant()!=null) + .filter(item -> item.getTenant().contains(tenant)) + .forEach(item -> expectedItems.add(item))); + Assert.assertEquals(expectedItems.size(), 0); + Assert.assertNotEquals(expectedItems.containsAll(actualItems), actualItems.containsAll(expectedItems)); + } + + + private List<Item> getAllItems(){ + List<Item> items=new ArrayList<>(); + + Item itemOne = new Item(); + itemOne.setType(ItemType.vlm.name()); + itemOne.setOwner(USER); + itemOne.setStatus(ItemStatus.ACTIVE); + itemOne.setName("TEST_VENDOR_ONE"); + itemOne.setDescription("TEST_DESCRIPTION"); + itemOne.setTenant(TEST_TENANT); + + Item itemTwo = new Item(); + itemTwo.setType(ItemType.vsp.name()); + itemTwo.setOwner(USER); + itemTwo.setStatus(ItemStatus.ACTIVE); + itemTwo.setName("TEST_VSP_ONE"); + itemTwo.setDescription("TEST_DESCRIPTION"); + itemTwo.setTenant("admin_tenant"); + + items.add(itemOne); + items.add(itemTwo); + return items; + } + + + private Set<String> getTestRoles(){ + Set<String> roles = new HashSet<>(); + roles.add("test_admin"); + roles.add("test_tenant"); + return roles; + } } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-types/src/main/java/org/openecomp/sdcrests/item/types/ItemDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-types/src/main/java/org/openecomp/sdcrests/item/types/ItemDto.java index 34ad19fa7c..5e2810cc9e 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-types/src/main/java/org/openecomp/sdcrests/item/types/ItemDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/item-rest/item-rest-types/src/main/java/org/openecomp/sdcrests/item/types/ItemDto.java @@ -32,6 +32,7 @@ public class ItemDto { private String description; private String owner; private String status; + private String tenant; private Map<String, Object> properties; public void setId(final String id) { @@ -58,4 +59,11 @@ public class ItemDto { this.status = ValidationUtils.sanitizeInputString(status); } + public void setTenant(final String tenant) { + if(tenant != null) { + this.tenant = ValidationUtils.sanitizeInputString(tenant); + } + else this.tenant=tenant; + } + } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/java/org/openecomp/server/filters/MultitenancyKeycloakFilter.java b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/java/org/openecomp/server/filters/MultitenancyKeycloakFilter.java new file mode 100644 index 0000000000..8cb87e3e33 --- /dev/null +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/java/org/openecomp/server/filters/MultitenancyKeycloakFilter.java @@ -0,0 +1,286 @@ +/*- + * ============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.server.filters; + +import org.keycloak.adapters.AdapterDeploymentContext; +import org.keycloak.adapters.AuthenticatedActionsHandler; +import org.keycloak.adapters.KeycloakConfigResolver; +import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.KeycloakDeploymentBuilder; +import org.keycloak.adapters.NodesRegistrationManagement; +import org.keycloak.adapters.PreAuthActionsHandler; +import org.keycloak.adapters.servlet.FilterRequestAuthenticator; +import org.keycloak.adapters.servlet.OIDCFilterSessionStore; +import org.keycloak.adapters.servlet.OIDCServletHttpFacade; +import org.keycloak.adapters.spi.AuthChallenge; +import org.keycloak.adapters.spi.AuthOutcome; +import org.keycloak.adapters.spi.InMemorySessionIdMapper; +import org.keycloak.adapters.spi.SessionIdMapper; +import org.keycloak.adapters.spi.UserSessionManagement; +import org.openecomp.sdc.common.util.Multitenancy; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +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 MultitenancyKeycloakFilter implements Filter { + + private static final Logger log = Logger.getLogger("" + MultitenancyKeycloakFilter.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; + + /** + * 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 MultitenancyKeycloakFilter(KeycloakConfigResolver definedconfigResolver) { + this.definedconfigResolver = definedconfigResolver; + } + + public MultitenancyKeycloakFilter() { + 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 unconfigured 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) { + log.log(Level.FINE, "config file is empty",e); + } + } else { + String path = "/WEB-INF/keycloak.json"; + 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 unconfigured 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.server.filters.MultitenancyKeycloakFilter.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) { + log.finest(id); + idMapper.removeSession(id); + } + + } + } +} diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/keycloak.json b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/keycloak.json new file mode 100644 index 0000000000..d037661aec --- /dev/null +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/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/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/web.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/web.xml index 31400f878e..7d2edf4994 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/web.xml +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/web.xml @@ -24,6 +24,20 @@ <listener-class>org.openecomp.server.listeners.OnboardingAppStartupListener</listener-class> </listener> + <!--KEYCLOAK FILTER --> + <filter> + <filter-name>Keycloak Filter</filter-name> + <filter-class>org.openecomp.server.filters.MultitenancyKeycloakFilter</filter-class> + </filter> + <filter-mapping> + <filter-name>Keycloak Filter</filter-name> + <url-pattern>/keycloak/*</url-pattern> + <url-pattern>/v1.0/vendor-license-models/*</url-pattern> + <url-pattern>/v1.0/vendor-software-products</url-pattern> + <url-pattern>*/actions</url-pattern> + <url-pattern>/v1.0/items/*</url-pattern> + </filter-mapping> + <filter> <filter-name>dataValidatorFilter</filter-name> <filter-class>org.openecomp.sdc.common.filters.DataValidatorFilter</filter-class> diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/VendorLicenseModels.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/VendorLicenseModels.java index 0636b6e599..1c942d46c5 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/VendorLicenseModels.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/VendorLicenseModels.java @@ -45,6 +45,8 @@ import org.openecomp.sdcrests.vendorlicense.types.VendorLicenseModelActionReques import org.openecomp.sdcrests.vendorlicense.types.VendorLicenseModelEntityDto; import org.openecomp.sdcrests.vendorlicense.types.VendorLicenseModelRequestDto; import org.springframework.validation.annotation.Validated; +import javax.ws.rs.core.Context; +import javax.servlet.http.HttpServletRequest; @Path("/v1.0/vendor-license-models") @Produces(MediaType.APPLICATION_JSON) @@ -61,13 +63,13 @@ public interface VendorLicenseModels { @Parameter(description = "Filter to only return Vendor License Models at this status." + "Currently supported values: 'ACTIVE' , 'ARCHIVED'." + "Default value = 'ACTIVE'.") @QueryParam("Status") String itemStatus, - @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(RestConstants.USER_ID_HEADER_PARAM) String user); + @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(RestConstants.USER_ID_HEADER_PARAM) String user , @Context HttpServletRequest req); @POST @Path("/") - @Operation(description = "Create vendor license model") + @Operation(description = "Create vendor license model", responses = @ApiResponse(responseCode = "401", description = "Unauthorized Tenant")) Response createLicenseModel(@Valid VendorLicenseModelRequestDto request, - @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(RestConstants.USER_ID_HEADER_PARAM) String user); + @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(RestConstants.USER_ID_HEADER_PARAM) String user, @Context HttpServletRequest req); @DELETE @Path("/{vlmId}") diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelEntityToDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelEntityToDto.java index 5b0bfb7d73..9a099b83cc 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelEntityToDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelEntityToDto.java @@ -31,5 +31,8 @@ public class MapVendorLicenseModelEntityToDto extends MappingBase<VendorLicenseM target.setVendorName(source.getVendorName()); target.setDescription(source.getDescription()); target.setIconRef(source.getIconRef()); + if (source.getTenant() != null) { + target.setTenant(source.getTenant()); + } } } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity.java index 2cbc81980a..d3dbe1dc31 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/mapping/MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity.java @@ -30,5 +30,6 @@ public class MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity extends M target.setVendorName(source.getVendorName()); target.setDescription(source.getDescription()); target.setIconRef(source.getIconRef()); + target.setTenant(source.getTenant()); } } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/services/VendorLicenseModelsImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/services/VendorLicenseModelsImpl.java index ac722a5925..d22751d271 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/services/VendorLicenseModelsImpl.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-services/src/main/java/org/openecomp/sdcrests/vendorlicense/rest/services/VendorLicenseModelsImpl.java @@ -15,6 +15,7 @@ */ package org.openecomp.sdcrests.vendorlicense.rest.services; +import org.keycloak.representations.AccessToken; import org.openecomp.core.dao.UniqueValueDaoFactory; import org.openecomp.core.util.UniqueValueUtil; import org.openecomp.sdc.activitylog.ActivityLogManager; @@ -22,6 +23,7 @@ import org.openecomp.sdc.activitylog.ActivityLogManagerFactory; import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity; import org.openecomp.sdc.activitylog.dao.type.ActivityType; import org.openecomp.sdc.common.errors.Messages; +import org.openecomp.sdc.common.util.Multitenancy; import org.openecomp.sdc.datatypes.model.ItemType; import org.openecomp.sdc.healing.factory.HealingManagerFactory; import org.openecomp.sdc.itempermissions.PermissionsManager; @@ -66,11 +68,22 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.inject.Named; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Response; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.openecomp.sdc.itempermissions.notifications.NotificationConstants.PERMISSION_USER; +import static org.openecomp.sdc.versioning.VersioningNotificationConstansts.*; +import static org.openecomp.sdcrests.vendorlicense.types.VendorLicenseModelActionRequestDto.VendorLicenseModelAction.Submit; + +import javax.inject.Named; import javax.ws.rs.core.Response; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -142,38 +155,87 @@ public class VendorLicenseModelsImpl implements VendorLicenseModels { } @Override - public Response listLicenseModels(String versionStatus, String itemStatus, String user) { + public Response listLicenseModels(String versionStatus, String itemStatus, String user, HttpServletRequest hreq) { Predicate<Item> itemPredicate = createItemPredicate(versionStatus, itemStatus, user); GenericCollectionWrapper<ItemDto> results = new GenericCollectionWrapper<>(); MapItemToDto mapper = new MapItemToDto(); - asdcItemManager.list(itemPredicate).stream().sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) - .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class))); - return Response.ok(results).build(); + Multitenancy keyaccess= new Multitenancy(); + if (keyaccess.multiTenancyCheck()) { + AccessToken.Access realmAccess = keyaccess.getAccessToken(hreq).getRealmAccess(); + Set<String> realmroles = realmAccess.getRoles(); + realmroles.stream().forEach(role -> asdcItemManager.list(itemPredicate).stream().sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) + .filter(item -> item.getTenant().contains(role)) + .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class)))); + return Response.ok(results).build(); + } + else + { + asdcItemManager.list(itemPredicate).stream().sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) + .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class))); + return Response.ok(results).build(); + } } @Override - public Response createLicenseModel(VendorLicenseModelRequestDto request, String user) { - Item item = new Item(); - item.setType(ItemType.vlm.name()); - item.setOwner(user); - item.setStatus(ItemStatus.ACTIVE); - item.setName(request.getVendorName()); - item.setDescription(request.getDescription()); - uniqueValueUtil.validateUniqueValue(VendorLicenseConstants.UniqueValues.VENDOR_NAME, item.getName()); - item = asdcItemManager.create(item); - uniqueValueUtil.createUniqueValue(VendorLicenseConstants.UniqueValues.VENDOR_NAME, item.getName()); - Version version = versioningManager.create(item.getId(), new Version(), null); - VendorLicenseModelEntity vlm = new MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity() - .applyMapping(request, VendorLicenseModelEntity.class); - vlm.setId(item.getId()); - vlm.setVersion(version); - vendorLicenseManager.createVendorLicenseModel(vlm); - versioningManager.publish(item.getId(), version, "Initial vlm:" + vlm.getVendorName()); - ItemCreationDto itemCreationDto = new ItemCreationDto(); - itemCreationDto.setItemId(item.getId()); - itemCreationDto.setVersion(new MapVersionToDto().applyMapping(version, VersionDto.class)); - activityLogManager.logActivity(new ActivityLogEntity(vlm.getId(), version, ActivityType.Create, user, true, "", "")); - return Response.ok(itemCreationDto).build(); + public Response createLicenseModel(VendorLicenseModelRequestDto request, String user, HttpServletRequest hreq) { + Multitenancy keyaccess= new Multitenancy(); + if (keyaccess.multiTenancyCheck()) { + AccessToken.Access realmAccess = keyaccess.getAccessToken(hreq).getRealmAccess(); + Set<String> realmroles = realmAccess.getRoles(); + boolean match = realmroles.contains(request.getTenant()); + if (match) { + Item item = new Item(); + item.setType(ItemType.vlm.name()); + item.setOwner(user); + item.setStatus(ItemStatus.ACTIVE); + item.setName(request.getVendorName()); + item.setDescription(request.getDescription()); + item.setTenant(request.getTenant()); + uniqueValueUtil.validateUniqueValue(VendorLicenseConstants.UniqueValues.VENDOR_NAME, item.getName()); + item = asdcItemManager.create(item); + uniqueValueUtil.createUniqueValue(VendorLicenseConstants.UniqueValues.VENDOR_NAME, item.getName()); + Version version = versioningManager.create(item.getId(), new Version(), null); + VendorLicenseModelEntity vlm = new MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity() + .applyMapping(request, VendorLicenseModelEntity.class); + vlm.setId(item.getId()); + vlm.setVersion(version); + vendorLicenseManager.createVendorLicenseModel(vlm); + versioningManager.publish(item.getId(), version, "Initial vlm:" + vlm.getVendorName()); + ItemCreationDto itemCreationDto = new ItemCreationDto(); + itemCreationDto.setItemId(item.getId()); + itemCreationDto.setVersion(new MapVersionToDto().applyMapping(version, VersionDto.class)); + activityLogManager.logActivity(new ActivityLogEntity(vlm.getId(), version, ActivityType.Create, user, true, "", "")); + return Response.ok(itemCreationDto).build(); + } + else { + LOGGER.error("Unauthorized tenant"); + return Response.status(401, "Unauthorized tenant").build(); + } + } + else + { + Item item = new Item(); + item.setType(ItemType.vlm.name()); + item.setOwner(user); + item.setStatus(ItemStatus.ACTIVE); + item.setName(request.getVendorName()); + item.setDescription(request.getDescription()); + uniqueValueUtil.validateUniqueValue(VendorLicenseConstants.UniqueValues.VENDOR_NAME, item.getName()); + item = asdcItemManager.create(item); + uniqueValueUtil.createUniqueValue(VendorLicenseConstants.UniqueValues.VENDOR_NAME, item.getName()); + Version version = versioningManager.create(item.getId(), new Version(), null); + VendorLicenseModelEntity vlm = new MapVendorLicenseModelRequestDtoToVendorLicenseModelEntity() + .applyMapping(request, VendorLicenseModelEntity.class); + vlm.setId(item.getId()); + vlm.setVersion(version); + vendorLicenseManager.createVendorLicenseModel(vlm); + versioningManager.publish(item.getId(), version, "Initial vlm:" + vlm.getVendorName()); + ItemCreationDto itemCreationDto = new ItemCreationDto(); + itemCreationDto.setItemId(item.getId()); + itemCreationDto.setVersion(new MapVersionToDto().applyMapping(version, VersionDto.class)); + activityLogManager.logActivity(new ActivityLogEntity(vlm.getId(), version, ActivityType.Create, user, true, "", "")); + return Response.ok(itemCreationDto).build(); + } } @Override diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelEntityDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelEntityDto.java index 2c647647d8..020539ad86 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelEntityDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelEntityDto.java @@ -20,7 +20,11 @@ package org.openecomp.sdcrests.vendorlicense.types; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; +@Getter +@Setter @Schema(description = "VendorLicenseModelEntity") public class VendorLicenseModelEntityDto extends VendorLicenseModelRequestDto { @@ -33,4 +37,6 @@ public class VendorLicenseModelEntityDto extends VendorLicenseModelRequestDto { public void setId(String id) { this.id = id; } + + private String tenant; } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelRequestDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelRequestDto.java index ba8fd96e6e..bb93a219a8 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelRequestDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-license-rest/vendor-license-rest-types/src/main/java/org/openecomp/sdcrests/vendorlicense/types/VendorLicenseModelRequestDto.java @@ -38,6 +38,9 @@ public class VendorLicenseModelRequestDto { @NotNull private String iconRef; + @Size(max = 25) + private String tenant; + public void setVendorName(final String vendorName) { this.vendorName = ValidationUtils.sanitizeInputString(vendorName); } @@ -45,4 +48,11 @@ public class VendorLicenseModelRequestDto { public void setDescription(final String description) { this.description = ValidationUtils.sanitizeInputString(description); } + + public void setTenant(final String tenant) { + if(tenant != null){ + this.tenant = ValidationUtils.sanitizeInputString(tenant); + } + else this.tenant=tenant; + } } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java index fbe7d371ca..347cc4b15b 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java @@ -28,6 +28,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tags; import java.io.File; import java.io.IOException; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; @@ -40,6 +41,7 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.openecomp.sdcrests.item.types.ItemCreationDto; @@ -62,8 +64,9 @@ public interface VendorSoftwareProducts extends VspEntities { @POST @Path("/") - @Operation(description = "Create a new vendor software product", responses = @ApiResponse(content = @Content(schema = @Schema(implementation = ItemCreationDto.class)))) - Response createVsp(@Valid VspRequestDto vspRequestDto, @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user); + @Operation(description = "Create a new vendor software product", responses = {@ApiResponse(content = @Content(schema = @Schema(implementation = ItemCreationDto.class))) + , @ApiResponse(responseCode = "401", description = "Unauthorized Tenant")}) + Response createVsp(@Valid VspRequestDto vspRequestDto, @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user, @Context HttpServletRequest req); @GET @Path("/") @@ -71,9 +74,9 @@ public interface VendorSoftwareProducts extends VspEntities { Response listVsps(@Parameter(description = "Filter to return only Vendor Software Products with at" + " least one version at this status. Currently supported values: 'Certified' , 'Draft'") @QueryParam("versionFilter") String versionStatus, @Parameter(description = "Filter to only return Vendor Software Products at this status." - + "Currently supported values: 'ACTIVE' , 'ARCHIVED'." - + "Default value = 'ACTIVE'.") @QueryParam("Status") String itemStatus, - @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user); + + "Currently supported values: 'ACTIVE' , 'ARCHIVED'." + + "Default value = 'ACTIVE'.") @QueryParam("Status") String itemStatus, + @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user, @Context HttpServletRequest req); @GET @Path("/{vspId}") @@ -116,7 +119,7 @@ public interface VendorSoftwareProducts extends VspEntities { @GET @Path("/validation-vsp") - Response getValidationVsp(@NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user) throws Exception; + Response getValidationVsp(@NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user, @Context HttpServletRequest hreq) throws Exception; @PUT @Path("/{vspId}/versions/{versionId}/actions") diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapItemToVspDetailsDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapItemToVspDetailsDto.java index e0966e8350..1ec3d8fc8a 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapItemToVspDetailsDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapItemToVspDetailsDto.java @@ -36,5 +36,6 @@ public class MapItemToVspDetailsDto extends MappingBase<Item, VspDetailsDto> { target.setOnboardingMethod((String) source.getProperties().get(VspItemProperty.ONBOARDING_METHOD)); target.setOwner(source.getOwner()); target.setStatus(source.getStatus().name()); + target.setTenant(source.getTenant()); } } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToItem.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToItem.java index 0543c20298..d833a1bd8c 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToItem.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToItem.java @@ -29,6 +29,7 @@ public class MapVspDescriptionDtoToItem extends MappingBase<VspDescriptionDto, I @Override public void doMapping(VspDescriptionDto source, Item target) { target.setName(source.getName()); + target.setTenant(source.getTenant()); target.setDescription(source.getDescription()); target.addProperty(VspItemProperty.VENDOR_ID, source.getVendorId()); target.addProperty(VspItemProperty.VENDOR_NAME, source.getVendorName()); diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToVspDetails.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToVspDetails.java index 418a512d66..3a989ec99c 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToVspDetails.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDescriptionDtoToVspDetails.java @@ -38,6 +38,9 @@ public class MapVspDescriptionDtoToVspDetails extends MappingBase<VspDescription target.setIcon(source.getIcon()); target.setVendorName(source.getVendorName()); target.setVendorId(source.getVendorId()); + if (source.getTenant() != null) { + target.setTenant(source.getTenant()); + } if (source.getLicensingVersion() != null && source.getLicenseType() != LicenseType.EXTERNAL) { target.setVlmVersion(new Version(source.getLicensingVersion())); } diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDetailsToDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDetailsToDto.java index 897327ea30..519f789ee3 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDetailsToDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/MapVspDetailsToDto.java @@ -40,6 +40,7 @@ public class MapVspDetailsToDto extends MappingBase<VspDetails, VspDetailsDto> { target.setSubCategory(source.getSubCategory()); target.setVendorId(source.getVendorId()); target.setVendorName(source.getVendorName()); + target.setTenant(source.getTenant()); target.setLicensingVersion(source.getVlmVersion() == null ? null : source.getVlmVersion().getId()); if (StringUtils.isNotBlank(source.getLicenseType())) { target.setLicenseType(LicenseType.valueOf(source.getLicenseType())); diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java index b424db9b42..c859414112 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java @@ -42,6 +42,7 @@ import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; import javax.inject.Named; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import org.apache.commons.collections4.MapUtils; import org.openecomp.core.dao.UniqueValueDaoFactory; @@ -55,6 +56,7 @@ import org.openecomp.sdc.be.csar.storage.StorageFactory; import org.openecomp.sdc.common.errors.CoreException; import org.openecomp.sdc.common.errors.ErrorCode; import org.openecomp.sdc.common.errors.Messages; +import org.openecomp.sdc.common.util.Multitenancy; import org.openecomp.sdc.datatypes.error.ErrorMessage; import org.openecomp.sdc.datatypes.model.ItemType; import org.openecomp.sdc.healing.factory.HealingManagerFactory; @@ -116,6 +118,7 @@ import org.openecomp.sdcrests.vsp.rest.mapping.MapVspDetailsToDto; import org.openecomp.sdcrests.wrappers.GenericCollectionWrapper; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; +import org.keycloak.representations.AccessToken; @Named @Service("vendorSoftwareProducts") @@ -173,12 +176,15 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { } @Override - public Response createVsp(VspRequestDto vspRequestDto, String user) { - ItemCreationDto vspCreationDto = createVspItem(vspRequestDto, user); - return Response.ok(vspCreationDto).build(); - } + public Response createVsp(VspRequestDto vspRequestDto, String user, HttpServletRequest hreq) { + ItemCreationDto vspCreationDto = createVspItem(vspRequestDto, user, hreq); + if (vspCreationDto != null) { + return Response.ok(vspCreationDto).build(); + } + else return Response.status(401, "Unauthorized Tenant").build(); + } - private ItemCreationDto createVspItem(VspRequestDto vspRequestDto, String user) { + private ItemCreationDto createVspItem(VspRequestDto vspRequestDto, String user, HttpServletRequest hreq) { OnboardingMethod onboardingMethod = null; try { onboardingMethod = OnboardingMethod.valueOf(vspRequestDto.getOnboardingMethod()); @@ -188,34 +194,69 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { } ItemCreationDto itemCreationDto = null; if (onboardingMethod == NetworkPackage || onboardingMethod == OnboardingMethod.Manual) { - itemCreationDto = createItem(vspRequestDto, user, onboardingMethod); + itemCreationDto = createItem(vspRequestDto, user, onboardingMethod, hreq); } else { throwUnknownOnboardingMethodException(new IllegalArgumentException("Wrong parameter Onboarding Method")); } return itemCreationDto; } - private ItemCreationDto createItem(VspRequestDto vspRequestDto, String user, OnboardingMethod onboardingMethod) { - Item item = new MapVspDescriptionDtoToItem().applyMapping(vspRequestDto, Item.class); - item.setType(ItemType.vsp.name()); - item.setOwner(user); - item.setStatus(ItemStatus.ACTIVE); - item.addProperty(VspItemProperty.ONBOARDING_METHOD, onboardingMethod.name()); - uniqueValueUtil.validateUniqueValue(VENDOR_SOFTWARE_PRODUCT_NAME, item.getName()); - item = itemManager.create(item); - uniqueValueUtil.createUniqueValue(VENDOR_SOFTWARE_PRODUCT_NAME, item.getName()); - Version version = versioningManager.create(item.getId(), new Version(), null); - VspDetails vspDetails = new MapVspDescriptionDtoToVspDetails().applyMapping(vspRequestDto, VspDetails.class); - vspDetails.setId(item.getId()); - vspDetails.setVersion(version); - vspDetails.setOnboardingMethod(vspRequestDto.getOnboardingMethod()); - vendorSoftwareProductManager.createVsp(vspDetails); - versioningManager.publish(item.getId(), version, "Initial vsp:" + vspDetails.getName()); - ItemCreationDto itemCreationDto = new ItemCreationDto(); - itemCreationDto.setItemId(item.getId()); - itemCreationDto.setVersion(new MapVersionToDto().applyMapping(version, VersionDto.class)); - activityLogManager.logActivity(new ActivityLogEntity(vspDetails.getId(), version, ActivityType.Create, user, true, "", "")); - return itemCreationDto; + private ItemCreationDto createItem(VspRequestDto vspRequestDto, String user, OnboardingMethod onboardingMethod , HttpServletRequest hreq) { + Multitenancy keyaccess= new Multitenancy(); + if (keyaccess.multiTenancyCheck()) { + AccessToken.Access realmAccess = keyaccess.getAccessToken(hreq).getRealmAccess(); + Set<String> realmroles = realmAccess.getRoles(); + boolean match = realmroles.contains(vspRequestDto.getTenant()); + if (match) { + Item item = new MapVspDescriptionDtoToItem().applyMapping(vspRequestDto, Item.class); + item.setType(ItemType.vsp.name()); + item.setOwner(user); + item.setTenant(item.getTenant()); + item.setStatus(ItemStatus.ACTIVE); + item.addProperty(VspItemProperty.ONBOARDING_METHOD, onboardingMethod.name()); + uniqueValueUtil.validateUniqueValue(VENDOR_SOFTWARE_PRODUCT_NAME, item.getName()); + item = itemManager.create(item); + uniqueValueUtil.createUniqueValue(VENDOR_SOFTWARE_PRODUCT_NAME, item.getName()); + Version version = versioningManager.create(item.getId(), new Version(), null); + VspDetails vspDetails = new MapVspDescriptionDtoToVspDetails().applyMapping(vspRequestDto, VspDetails.class); + vspDetails.setId(item.getId()); + vspDetails.setVersion(version); + vspDetails.setOnboardingMethod(vspRequestDto.getOnboardingMethod()); + vendorSoftwareProductManager.createVsp(vspDetails); + versioningManager.publish(item.getId(), version, "Initial vsp:" + vspDetails.getName()); + ItemCreationDto itemCreationDto = new ItemCreationDto(); + itemCreationDto.setItemId(item.getId()); + itemCreationDto.setVersion(new MapVersionToDto().applyMapping(version, VersionDto.class)); + activityLogManager.logActivity(new ActivityLogEntity(vspDetails.getId(), version, ActivityType.Create, user, true, "", "")); + return itemCreationDto; + } + else { + LOGGER.error("Unauthorized tenant"); + return null; + } + } + else { + Item item = new MapVspDescriptionDtoToItem().applyMapping(vspRequestDto, Item.class); + item.setType(ItemType.vsp.name()); + item.setOwner(user); + item.setStatus(ItemStatus.ACTIVE); + item.addProperty(VspItemProperty.ONBOARDING_METHOD, onboardingMethod.name()); + uniqueValueUtil.validateUniqueValue(VENDOR_SOFTWARE_PRODUCT_NAME, item.getName()); + item = itemManager.create(item); + uniqueValueUtil.createUniqueValue(VENDOR_SOFTWARE_PRODUCT_NAME, item.getName()); + Version version = versioningManager.create(item.getId(), new Version(), null); + VspDetails vspDetails = new MapVspDescriptionDtoToVspDetails().applyMapping(vspRequestDto, VspDetails.class); + vspDetails.setId(item.getId()); + vspDetails.setVersion(version); + vspDetails.setOnboardingMethod(vspRequestDto.getOnboardingMethod()); + vendorSoftwareProductManager.createVsp(vspDetails); + versioningManager.publish(item.getId(), version, "Initial vsp:" + vspDetails.getName()); + ItemCreationDto itemCreationDto = new ItemCreationDto(); + itemCreationDto.setItemId(item.getId()); + itemCreationDto.setVersion(new MapVersionToDto().applyMapping(version, VersionDto.class)); + activityLogManager.logActivity(new ActivityLogEntity(vspDetails.getId(), version, ActivityType.Create, user, true, "", "")); + return itemCreationDto; + } } private void throwUnknownOnboardingMethodException(IllegalArgumentException e) { @@ -224,11 +265,25 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { } @Override - public Response listVsps(String versionStatus, String itemStatus, String user) { - GenericCollectionWrapper<VspDetailsDto> results = new GenericCollectionWrapper<>(); - MapItemToVspDetailsDto mapper = new MapItemToVspDetailsDto(); - getVspList(versionStatus, itemStatus, user).forEach(vspItem -> results.add(mapper.applyMapping(vspItem, VspDetailsDto.class))); - return Response.ok(results).build(); + public Response listVsps(String versionStatus, String itemStatus, String user, HttpServletRequest hreq ) { + Multitenancy keyaccess = new Multitenancy(); + if (keyaccess.multiTenancyCheck()) { + AccessToken.Access realmAccess = keyaccess.getAccessToken(hreq).getRealmAccess(); + Set<String> realmroles = realmAccess.getRoles(); + Predicate<Item> itemPredicate = createItemPredicate(versionStatus, itemStatus, user); + GenericCollectionWrapper<VspDetailsDto> results = new GenericCollectionWrapper<>(); + MapItemToVspDetailsDto mapper = new MapItemToVspDetailsDto(); + realmroles.stream().forEach(role -> itemManager.list(itemPredicate).stream().sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime())) + .filter(vspItem -> vspItem.getTenant().contains(role)) + .forEach(vspItem -> results.add(mapper.applyMapping(vspItem, VspDetailsDto.class)))); + return Response.ok(results).build(); + } + else { + GenericCollectionWrapper<VspDetailsDto> results = new GenericCollectionWrapper<>(); + MapItemToVspDetailsDto mapper = new MapItemToVspDetailsDto(); + getVspList(versionStatus, itemStatus, user).forEach(vspItem -> results.add(mapper.applyMapping(vspItem, VspDetailsDto.class))); + return Response.ok(results).build(); + } } @Override @@ -427,12 +482,12 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { } @Override - public Response getValidationVsp(String user) { - ItemCreationDto validationVsp = retrieveValidationVsp(); + public Response getValidationVsp(String user, HttpServletRequest hreq) { + ItemCreationDto validationVsp = retrieveValidationVsp(hreq); return Response.ok(validationVsp).build(); } - private ItemCreationDto retrieveValidationVsp() { + private ItemCreationDto retrieveValidationVsp(HttpServletRequest req) { synchronized (VALIDATION_VSP_CACHE_LOCK) { if (cachedValidationVsp != null) { return cachedValidationVsp; @@ -441,7 +496,7 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { validationVspRequest.setOnboardingMethod(NetworkPackage.toString()); validationVspRequest.setName(VALIDATION_VSP_NAME); try { - cachedValidationVsp = createVspItem(validationVspRequest, VALIDATION_VSP_USER); + cachedValidationVsp = createVspItem(validationVspRequest, VALIDATION_VSP_USER, req); return cachedValidationVsp; } catch (CoreException vspCreateException) { LOGGER.debug("Failed to create validation VSP", vspCreateException); diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDescriptionDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDescriptionDto.java index e5f4ae0426..c194c4f357 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDescriptionDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDescriptionDto.java @@ -51,6 +51,7 @@ public class VspDescriptionDto { private LicenseType licenseType; private LicensingData licensingData; private List<String> selectedModelList; + private String tenant; public void setName(final String name) { this.name = ValidationUtils.sanitizeInputString(name); @@ -64,6 +65,13 @@ public class VspDescriptionDto { this.description = ValidationUtils.sanitizeInputString(description); } + public void setTenant(final String tenant) { + if( tenant != null) { + this.tenant = ValidationUtils.sanitizeInputString(tenant); + } + else this.tenant=tenant; + } + public void setSelectedModelList(final List<String> selectedModelList) { if (CollectionUtils.isEmpty(selectedModelList)) { this.selectedModelList = new ArrayList<>(); diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDetailsDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDetailsDto.java index 973d8ea577..25986cb109 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDetailsDto.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspDetailsDto.java @@ -38,4 +38,5 @@ public class VspDetailsDto extends VspRequestDto { private String networkPackageName; private String owner; private String status; + private String tenant; } diff --git a/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/test/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseModelTest.java b/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/test/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseModelTest.java index 89b555c449..30c1c03322 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/test/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseModelTest.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/test/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseModelTest.java @@ -21,20 +21,28 @@ package org.openecomp.sdc.vendorlicense.impl; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.*; import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity; +import org.openecomp.sdc.datatypes.model.ItemType; import org.openecomp.sdc.vendorlicense.VendorLicenseConstants; import org.openecomp.sdc.vendorlicense.dao.*; import org.openecomp.sdc.vendorlicense.dao.types.VendorLicenseModelEntity; import org.openecomp.sdc.vendorlicense.facade.VendorLicenseFacade; import org.openecomp.sdc.versioning.VersioningManager; import org.openecomp.sdc.versioning.dao.types.Version; +import org.openecomp.sdc.versioning.types.Item; +import org.openecomp.sdc.versioning.types.ItemStatus; +import java.util.Set; +import java.util.List; +import java.util.ArrayList; +import java.util.HashSet; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; - +import static org.hamcrest.MatcherAssert.assertThat; /** * Created by ayalaben on 7/19/2017 @@ -53,6 +61,10 @@ public class VendorLicenseModelTest { public static final Version VERSION01 = new Version(0, 1); private static final Version VERSION10 = new Version(1, 0); + private static final boolean MULTITENANCY_ENABLED = true; + + private static final String TEST_TENANT = "test_tenant"; + @Mock private VersioningManager versioningManagerMcok; @Mock @@ -154,4 +166,93 @@ public class VendorLicenseModelTest { // vendorSoftwareProductManager.getVsp(VSP_ID, notExistversion); // } + + @Test + public void testCreate_withMultitenancyValidTenant_Success() { + Assert.assertEquals(MULTITENANCY_ENABLED,true); + VendorLicenseModelEntity vlmEntity = new VendorLicenseModelEntity(); + vlmEntity.setId(vlm1_id); + vlmEntity.setVersion(VERSION01); + vlmEntity.setTenant(TEST_TENANT); + assertThat("Unauthorized Tenant", getTestRoles().contains(vlmEntity.getTenant())); + vendorLicenseManager.createVendorLicenseModel(vlmEntity); + verify(vendorLicenseModelDaoMcok).create(vlmEntity); + } + + @Test + public void testCreate_withMultitenancyInvalidTenant_Failure() { + String invalidTenant="invalid_tenant"; + Assert.assertEquals(MULTITENANCY_ENABLED,true); + VendorLicenseModelEntity vlmEntity = new VendorLicenseModelEntity(); + vlmEntity.setId(vlm1_id); + vlmEntity.setVersion(VERSION01); + vlmEntity.setTenant(invalidTenant); + Assert.assertFalse(getTestRoles().contains(invalidTenant)); + Assert.assertNotNull(vlmEntity.getTenant()); + vendorLicenseManager.createVendorLicenseModel(vlmEntity); + assertThat("Unauthorized Tenant", !getTestRoles().contains(vlmEntity.getTenant())); + } + + @Test + public void testListVLM_multitenancyWithTenant_FilterList() { + Assert.assertEquals(MULTITENANCY_ENABLED,true); + Assert.assertNotNull(getTestRoles()); + assertThat("Unauthorized Tenant", getTestRoles().contains(TEST_TENANT)); + String tenant = TEST_TENANT; + Assert.assertNotNull(tenant); + List<Item> expectedItems=new ArrayList<>(); + getTestRoles().stream().forEach(role -> getLicenseModelItems().stream() + .filter(item -> item.getTenant().contains(role)) + .forEach(item -> expectedItems.add(item))); + Assert.assertEquals(expectedItems.size(), 1); + } + + @Test + public void testListVLM_multitenancyWithInvalidTenant_ReturnEmptylist() { + Assert.assertEquals(MULTITENANCY_ENABLED,true); + Assert.assertNotNull(getTestRoles()); + String tenant= "invalid_tenant"; + List<Item> expectedItems=new ArrayList<>(); + List<Item> actualItems=getLicenseModelItems(); + Assert.assertNotNull(tenant); + getTestRoles().stream().forEach(role -> getLicenseModelItems().stream() + .filter(item -> item.getTenant()!=null) + .filter(item -> item.getTenant().contains(tenant)) + .forEach(item -> expectedItems.add(item))); + + Assert.assertEquals(expectedItems.size(), 0); + Assert.assertNotEquals(expectedItems.containsAll(actualItems), actualItems.containsAll(expectedItems)); + } + + private Set<String> getTestRoles(){ + Set<String> roles = new HashSet<>(); + roles.add("test_admin"); + roles.add("test_tenant"); + return roles; + } + + private List<Item> getLicenseModelItems(){ + List<Item> items=new ArrayList<>(); + + Item itemOne = new Item(); + itemOne.setType(ItemType.vlm.name()); + itemOne.setOwner(USER1); + itemOne.setStatus(ItemStatus.ACTIVE); + itemOne.setName("TEST_VENDOR_ONE"); + itemOne.setDescription("TEST_DESCRIPTION"); + itemOne.setTenant(TEST_TENANT); + + Item itemTwo = new Item(); + itemTwo.setType(ItemType.vlm.name()); + itemTwo.setOwner(USER1); + itemTwo.setStatus(ItemStatus.ACTIVE); + itemTwo.setName("TEST_VENDOR_TWO"); + itemTwo.setDescription("TEST_DESCRIPTION"); + itemTwo.setTenant("admin_tenant"); + + items.add(itemOne); + items.add(itemTwo); + return items; + } + } diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImplTest.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImplTest.java index 2371bac930..81e7e53f2a 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImplTest.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImplTest.java @@ -44,9 +44,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.Optional; import org.apache.commons.io.IOUtils; +import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -66,6 +69,7 @@ import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.common.errors.CoreException; import org.openecomp.sdc.common.errors.ErrorCategory; import org.openecomp.sdc.common.errors.ErrorCode; +import org.openecomp.sdc.datatypes.model.ItemType; import org.openecomp.sdc.healing.api.HealingManager; import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel; import org.openecomp.sdc.vendorlicense.facade.VendorLicenseFacade; @@ -91,6 +95,8 @@ import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTempl import org.openecomp.sdc.versioning.ActionVersioningManager; import org.openecomp.sdc.versioning.dao.types.Version; import org.openecomp.sdc.versioning.dao.types.VersionStatus; +import org.openecomp.sdc.versioning.types.Item; +import org.openecomp.sdc.versioning.types.ItemStatus; import org.openecomp.sdc.versioning.types.VersionInfo; import org.openecomp.sdc.versioning.types.VersionableEntityAction; @@ -101,6 +107,8 @@ class VendorSoftwareProductManagerImplTest { private static final Version VERSION10 = new Version("1, 0"); private static final String USER1 = "vspTestUser1"; private static final String USER2 = "vspTestUser2"; + private static final boolean MULTITENANCY_ENABLED = true; + private static final String TEST_TENANT = "test_tenant"; @Mock private ActionVersioningManager versioningManagerMock; @@ -553,4 +561,100 @@ class VendorSoftwareProductManagerImplTest { assertEquals(actual.getFeatureGroups(), expected.getFeatureGroups()); } + @Test + void createVSP_withMultitenancy_Success() { + assertEquals(MULTITENANCY_ENABLED, true); + assertNotNull(getTestRoles()); + doReturn("{}") + .when(vendorSoftwareProductManager).getVspQuestionnaireSchema(nullable(SchemaTemplateInput.class)); + VspDetails vspToCreate = + createVspDetails(null, null, "Vsp1", "Test-vsp", "vendorName", "vlm1Id", "icon", + "category", "subCategory", "123", null); + vspToCreate.setTenant(TEST_TENANT); + assertThat("Unauthorized Tenant", getTestRoles().contains(vspToCreate.getTenant())); + VspDetails vsp = vendorSoftwareProductManager.createVsp(vspToCreate); + + assertNotNull(vsp); + vspToCreate.setId(vsp.getId()); + vspToCreate.setVersion(VERSION01); + assertVspsEquals(vsp, vspToCreate); + assertEquals(vsp.getTenant(), vspToCreate.getTenant()); + } + + @Test + void createVSP_withMultitenancy_Failure() { + assertEquals(MULTITENANCY_ENABLED, true); + assertNotNull(getTestRoles()); + doReturn("{}") + .when(vendorSoftwareProductManager).getVspQuestionnaireSchema(nullable(SchemaTemplateInput.class)); + VspDetails vspToCreate = + createVspDetails(null, null, "Vsp1", "Test-vsp", "vendorName", "vlm1Id", "icon", + "category", "subCategory", "123", null); + vspToCreate.setTenant("invalid_tenant"); + VspDetails vsp = vendorSoftwareProductManager.createVsp(vspToCreate); + + assertEquals(vsp.getTenant(), vspToCreate.getTenant()); + assertThat("Unauthorized Tenant", !getTestRoles().contains(vsp.getTenant())); + } + + private Set<String> getTestRoles(){ + Set<String> roles = new HashSet<>(); + roles.add("test_admin"); + roles.add("test_tenant"); + return roles; + } + + @Test + public void testListVSP_multitenancyWithTenant_FilterList() { + Assert.assertEquals(MULTITENANCY_ENABLED,true); + Assert.assertNotNull(getTestRoles()); + assertThat("Unauthorized Tenant", getTestRoles().contains(TEST_TENANT)); + List<Item> expectedItems=new ArrayList<>(); + getTestRoles().stream().forEach(role -> getVSPItems().stream() + .filter(item -> item.getTenant()!=null) + .filter(item -> item.getTenant().contains(role)) + .forEach(item -> expectedItems.add(item))); + Assert.assertEquals(expectedItems.size(), 1); + } + + @Test + public void testListVSP_multitenancyWithInvalidTenant_ReturnEmptylist() { + Assert.assertEquals(MULTITENANCY_ENABLED,true); + Assert.assertNotNull(getTestRoles()); + String tenant= "invalid_tenant"; + List<Item> expectedItems=new ArrayList<>(); + List<Item> actualItems=getVSPItems(); + Assert.assertNotNull(tenant); + getTestRoles().stream().forEach(role -> getVSPItems().stream() + .filter(item -> item.getTenant()!=null) + .filter(item -> item.getTenant().contains(tenant)) + .forEach(item -> expectedItems.add(item))); + + Assert.assertEquals(expectedItems.size(), 0); + Assert.assertNotEquals(expectedItems.containsAll(actualItems), actualItems.containsAll(expectedItems)); + } + + private List<Item> getVSPItems(){ + List<Item> items=new ArrayList<>(); + + Item itemOne = new Item(); + itemOne.setType(ItemType.vsp.name()); + itemOne.setOwner(USER1); + itemOne.setStatus(ItemStatus.ACTIVE); + itemOne.setName("TEST_VSP_ONE"); + itemOne.setDescription("TEST_DESCRIPTION"); + itemOne.setTenant(TEST_TENANT); + + Item itemTwo = new Item(); + itemTwo.setType(ItemType.vsp.name()); + itemTwo.setOwner(USER1); + itemTwo.setStatus(ItemStatus.ACTIVE); + itemTwo.setName("TEST_VSP_TWO"); + itemTwo.setDescription("TEST_DESCRIPTION"); + itemTwo.setTenant("admin_tenant"); + + items.add(itemOne); + items.add(itemTwo); + return items; + } } diff --git a/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-api/src/main/java/org/openecomp/sdc/vendorlicense/dao/types/VendorLicenseModelEntity.java b/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-api/src/main/java/org/openecomp/sdc/vendorlicense/dao/types/VendorLicenseModelEntity.java index f6e155b0a2..9b9ae13af7 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-api/src/main/java/org/openecomp/sdc/vendorlicense/dao/types/VendorLicenseModelEntity.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-api/src/main/java/org/openecomp/sdc/vendorlicense/dao/types/VendorLicenseModelEntity.java @@ -25,9 +25,13 @@ import com.datastax.driver.mapping.annotations.Frozen; import com.datastax.driver.mapping.annotations.PartitionKey; import com.datastax.driver.mapping.annotations.Table; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; import org.openecomp.sdc.versioning.dao.types.Version; import org.openecomp.sdc.versioning.dao.types.VersionableEntity; +@Getter +@Setter @Table(keyspace = "dox", name = "vendor_license_model") public class VendorLicenseModelEntity implements VersionableEntity { @@ -42,6 +46,7 @@ public class VendorLicenseModelEntity implements VersionableEntity { private String vendorName; private String description; private String oldVersion; + private String tenant; @Column(name = "icon") private String iconRef; @Computed("writetime(vendor_name)") @@ -123,7 +128,7 @@ public class VendorLicenseModelEntity implements VersionableEntity { @Override public int hashCode() { - return Objects.hash(id, version, vendorName, description, iconRef); + return Objects.hash(id, version, vendorName, description, iconRef, tenant); } @Override @@ -136,6 +141,6 @@ public class VendorLicenseModelEntity implements VersionableEntity { } VendorLicenseModelEntity that = (VendorLicenseModelEntity) obj; return Objects.equals(id, that.id) && Objects.equals(version, that.version) && Objects.equals(vendorName, that.vendorName) && Objects - .equals(description, that.description) && Objects.equals(iconRef, that.iconRef); + .equals(description, that.description) && Objects.equals(iconRef, that.iconRef) && Objects.equals(tenant, that.tenant); } } diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/VendorSoftwareProductConstants.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/VendorSoftwareProductConstants.java index 86c1bd1895..20d8e3a084 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/VendorSoftwareProductConstants.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/VendorSoftwareProductConstants.java @@ -30,6 +30,7 @@ public final class VendorSoftwareProductConstants { public final class UniqueValues { public static final String VENDOR_SOFTWARE_PRODUCT_NAME = "Vendor Software Product name"; + public static final String TENANT = "tenant"; public static final String PROCESS_NAME = "Process name"; public static final String NETWORK_NAME = "Network name"; public static final String COMPONENT_NAME = "ComponentData name"; diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspDetails.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspDetails.java index 01d1f0b72a..b0744a9797 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspDetails.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspDetails.java @@ -50,6 +50,7 @@ public class VspDetails implements VersionableEntity { private List<String> featureGroups; private String onboardingMethod; private List<String> modelIdList; + private String tenant; public VspDetails(String id, Version version) { this.id = id; diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/VendorSoftwareProductInfoDaoZusammenImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/VendorSoftwareProductInfoDaoZusammenImpl.java index 6e17679e4c..fe174b89df 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/VendorSoftwareProductInfoDaoZusammenImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/VendorSoftwareProductInfoDaoZusammenImpl.java @@ -203,6 +203,9 @@ public class VendorSoftwareProductInfoDaoZusammenImpl implements VendorSoftwareP info.addProperty(InfoPropertyName.SUB_CATEGORY.getValue(), vspDetails.getSubCategory()); info.addProperty(InfoPropertyName.VENDOR_ID.getValue(), vspDetails.getVendorId()); info.addProperty(InfoPropertyName.VENDOR_NAME.getValue(), vspDetails.getVendorName()); + if(vspDetails.getTenant() !=null) { + info.addProperty(InfoPropertyName.TENANT.getValue(), vspDetails.getTenant()); + } if (vspDetails.getVlmVersion() != null) { info.addProperty(InfoPropertyName.VENDOR_VERSION.getValue(), vspDetails.getVlmVersion().getId()); } @@ -226,6 +229,7 @@ public class VendorSoftwareProductInfoDaoZusammenImpl implements VendorSoftwareP SUB_CATEGORY("subCategory"), VENDOR_ID("vendorId"), VENDOR_NAME("vendorName"), + TENANT("tenant"), VENDOR_VERSION("vendorVersion"), LICENSE_TYPE("licenseType"), LICENSE_AGREEMENT("licenseAgreement"), diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/convertor/ElementToVSPGeneralConvertor.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/convertor/ElementToVSPGeneralConvertor.java index 016c80ad0c..365dbb68e2 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/convertor/ElementToVSPGeneralConvertor.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/convertor/ElementToVSPGeneralConvertor.java @@ -67,6 +67,7 @@ public class ElementToVSPGeneralConvertor extends ElementConvertor<VspDetails> { vspDetails.setSubCategory(info.getProperty(VendorSoftwareProductInfoDaoZusammenImpl.InfoPropertyName.SUB_CATEGORY.getValue())); vspDetails.setVendorId(info.getProperty(VendorSoftwareProductInfoDaoZusammenImpl.InfoPropertyName.VENDOR_ID.getValue())); vspDetails.setVendorName(info.getProperty(VendorSoftwareProductInfoDaoZusammenImpl.InfoPropertyName.VENDOR_NAME.getValue())); + vspDetails.setTenant(info.getProperty(VendorSoftwareProductInfoDaoZusammenImpl.InfoPropertyName.TENANT.getValue())); if (info.getProperty(VendorSoftwareProductInfoDaoZusammenImpl.InfoPropertyName.VENDOR_VERSION.getValue()) != null) { vspDetails .setVlmVersion(new Version(info.getProperty(VendorSoftwareProductInfoDaoZusammenImpl.InfoPropertyName.VENDOR_VERSION.getValue()))); diff --git a/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-api/src/main/java/org/openecomp/sdc/versioning/types/Item.java b/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-api/src/main/java/org/openecomp/sdc/versioning/types/Item.java index 62d21676f2..bbaf4945ea 100644 --- a/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-api/src/main/java/org/openecomp/sdc/versioning/types/Item.java +++ b/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-api/src/main/java/org/openecomp/sdc/versioning/types/Item.java @@ -33,6 +33,7 @@ public class Item { private String type; private String name; private String owner; + private String tenant; private ItemStatus status; private String description; private Map<String, Object> properties = new HashMap<>(); diff --git a/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-core/src/main/java/org/openecomp/sdc/versioning/dao/impl/zusammen/ItemZusammenDaoImpl.java b/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-core/src/main/java/org/openecomp/sdc/versioning/dao/impl/zusammen/ItemZusammenDaoImpl.java index e2e7b1cc1e..868faf4582 100644 --- a/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-core/src/main/java/org/openecomp/sdc/versioning/dao/impl/zusammen/ItemZusammenDaoImpl.java +++ b/openecomp-be/lib/openecomp-sdc-versioning-lib/openecomp-sdc-versioning-core/src/main/java/org/openecomp/sdc/versioning/dao/impl/zusammen/ItemZusammenDaoImpl.java @@ -102,6 +102,9 @@ public class ItemZusammenDaoImpl implements ItemDao { case ITEM_OWNER: item.setOwner((String) propertyValue); break; + case TENANT: + item.setTenant((String) propertyValue); + break; case ITEM_STATUS: item.setStatus(ItemStatus.valueOf((String) propertyValue)); break; @@ -121,6 +124,9 @@ public class ItemZusammenDaoImpl implements ItemDao { info.setDescription(item.getDescription()); info.addProperty(ItemInfoProperty.ITEM_TYPE.getName(), item.getType()); info.addProperty(ItemInfoProperty.ITEM_OWNER.getName(), item.getOwner()); + if (item.getTenant() != null) { + info.addProperty(ItemInfoProperty.TENANT.getName(), item.getTenant()); + } if (item.getStatus() != null) { info.addProperty(ItemInfoProperty.ITEM_STATUS.getName(), item.getStatus()); } @@ -135,7 +141,8 @@ public class ItemZusammenDaoImpl implements ItemDao { ITEM_TYPE("item_type"), ITEM_VERSIONS_STATUSES("item_versions_statuses"), ITEM_OWNER("Owner"), - ITEM_STATUS("status"); + ITEM_STATUS("status"), + TENANT("Tenant"); private final String name; @@ -88,6 +88,9 @@ Modifications copyright (c) 2018-2019 Nokia <org.owasp.esapi.version>2.4.0.0</org.owasp.esapi.version> <org.dom4j.version>2.1.3</org.dom4j.version> + <!-- Keycloak authentication--> + <keycloak.version>18.0.0</keycloak.version> + <!-- JSON and YAML Parsing --> <jackson.version>2.12.7</jackson.version> <jackson-annotations.version>${jackson.version}</jackson-annotations.version> @@ -324,6 +327,68 @@ Modifications copyright (c) 2018-2019 Nokia <version>${mockito.version}</version> <scope>test</scope> </dependency> + + <!-- KEYCLOAK Authentication and authorization--> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-servlet-filter-adapter</artifactId> + <version>${keycloak.version}</version> + <exclusions> + <exclusion> + <groupId>org.bouncycastle</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-authz-client</artifactId> + <version>${keycloak.version}</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-spring-security-adapter</artifactId> + <version>${keycloak.version}</version> + <exclusions> + <exclusion> + <groupId>org.bouncycastle</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-core</artifactId> + <version>${keycloak.version}</version> + <exclusions> + <exclusion> + <groupId>org.bouncycastle</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-common</artifactId> + <version>${keycloak.version}</version> + <exclusions> + <exclusion> + <groupId>org.bouncycastle</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>${servlet-api.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-core</artifactId> + <version>5.6.3</version> + </dependency> </dependencies> <reporting> |