diff options
author | vasraz <vasyl.razinkov@est.tech> | 2022-10-14 13:35:39 +0100 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2022-10-18 08:27:16 +0000 |
commit | ddb9d5a7637b382be9ac7a96ad023a983c41c342 (patch) | |
tree | 4e551d6ce4348aed56f42b021bbe4fcfccc3cd15 | |
parent | ccab3629426bdc6a87ca6102db3fdb23d4419b3e (diff) |
Fix security risk 'Improper Input Validation'
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Change-Id: I6a52148aec3b567db43ec57109214e52d106f73c
Issue-ID: SDC-4189
42 files changed, 1297 insertions, 529 deletions
diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml index 532ee3ecac..75f8904519 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 @@ -2411,7 +2411,7 @@ errors: # %1 - property name code: 400, message: 'Error: Invalid Content. %1 has invalid format.', - messageId: "SVC4723" + messageId: "SVC4731" } #---------SVC4734------------------------------ # %1 - list of validation errors @@ -2822,6 +2822,13 @@ errors: message: "Capability '%1' not found in '%2' '%3'." messageId: "SVC4186" + #---------SVC4001------------------------------ + NOT_PERMITTED_SPECIAL_CHARS: { + code: 406, + message: 'Error: HTML elements not permitted in field values.', + messageId: "SVC4001" + } + # %1 - The data type Uid DATA_TYPE_NOT_FOUND: code: 404 diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/templates/default/BE-configuration.yaml.erb b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/templates/default/BE-configuration.yaml.erb index 5706a16553..9a2437c2c1 100644 --- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/templates/default/BE-configuration.yaml.erb +++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/templates/default/BE-configuration.yaml.erb @@ -1293,5 +1293,8 @@ externalCsarStore: #This configuration specifies the delimiter used to differentiate instance name and count componentInstanceCounterDelimiter: " " +# Comma separated list of excluded URLs by the DataValidatorFilter +dataValidatorFilterExcludedUrls: "/healthCheck,/followed,/authorize" + #Space separated list of permitted ancestors permittedAncestors: <%= @permittedAncestors %> diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ByActionStatusComponentException.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ByActionStatusComponentException.java index e973fe4bf3..bd0e6bb20c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ByActionStatusComponentException.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ByActionStatusComponentException.java @@ -20,12 +20,14 @@ package org.openecomp.sdc.be.components.impl.exceptions; import java.util.Arrays; +import lombok.Getter; import org.openecomp.sdc.be.components.impl.ResponseFormatManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.exception.ResponseFormat; public class ByActionStatusComponentException extends ComponentException { + @Getter private final ActionStatus actionStatus; private final String[] params; @@ -35,10 +37,6 @@ public class ByActionStatusComponentException extends ComponentException { this.params = params.clone(); } - public ActionStatus getActionStatus() { - return actionStatus; - } - public String[] getParams() { return params.clone(); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BeRestrictionAccessFilter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BeRestrictionAccessFilter.java index e40dfe408f..0e8f9452be 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BeRestrictionAccessFilter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/BeRestrictionAccessFilter.java @@ -33,7 +33,7 @@ import org.springframework.stereotype.Component; @Component("beRestrictionAccessFilter") public class BeRestrictionAccessFilter extends RestrictionAccessFilter { - private static final Logger log = Logger.getLogger(RestrictionAccessFilter.class.getName()); + private static final Logger log = Logger.getLogger(BeRestrictionAccessFilter.class.getName()); public BeRestrictionAccessFilter(FilterConfiguration configuration, ThreadLocalUtils threadLocalUtils, PortalClient portalClient) { super(configuration, threadLocalUtils, portalClient); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/DataValidatorFilter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/DataValidatorFilter.java new file mode 100644 index 0000000000..2cdbf93d48 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/DataValidatorFilter.java @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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 java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.common.filters.DataValidatorFilterAbstract; +import org.openecomp.sdc.common.util.DataValidator; +import org.openecomp.sdc.exception.NotAllowedSpecialCharsException; + +/** + * Implement DataValidatorFilter for back-end. + * Extends {@link DataValidatorFilterAbstract} + */ +public class DataValidatorFilter extends DataValidatorFilterAbstract { + + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { + try { + super.doFilter(request, response, chain); + } catch (NotAllowedSpecialCharsException e) { + throw new ByActionStatusComponentException(ActionStatus.NOT_PERMITTED_SPECIAL_CHARS); + } + } + + @Override + protected List<String> getDataValidatorFilterExcludedUrls() { + final String dataValidatorFilterExcludedUrls = ConfigurationManager.getConfigurationManager().getConfiguration() + .getDataValidatorFilterExcludedUrls(); + if (StringUtils.isNotBlank(dataValidatorFilterExcludedUrls)) { + return Arrays.asList(dataValidatorFilterExcludedUrls.split(",")); + } + return new ArrayList<>(); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/GatewayFilter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/GatewayFilter.java index c5f0881caa..b675ec9a6e 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/filters/GatewayFilter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/filters/GatewayFilter.java @@ -44,7 +44,7 @@ import org.springframework.stereotype.Component; @Component("gatewayFilter") public class GatewayFilter implements Filter { - private static final Logger log = Logger.getLogger(BeServletFilter.class); + private static final Logger log = Logger.getLogger(GatewayFilter.class); private Configuration.CookieConfig authCookieConf; private Configuration config; @Autowired diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java index 7bec5d5f09..7c9101df82 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java @@ -321,10 +321,8 @@ public class BeGenericServlet extends BasicServlet { protected String propertyToJson(Map.Entry<String, PropertyDefinition> property) { JSONObject root = new JSONObject(); - String propertyName = property.getKey(); PropertyDefinition propertyDefinition = property.getValue(); - JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition); - root.put(propertyName, propertyDefinitionO); + root.put(property.getKey(), getPropertyDefinitionJSONObject(propertyDefinition)); propertyDefinition.getType(); return root.toString(); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/StorageExceptionMapper.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/StorageExceptionMapper.java index 18e5a15497..f89a1348db 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/StorageExceptionMapper.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/StorageExceptionMapper.java @@ -35,7 +35,7 @@ import org.springframework.stereotype.Component; @Provider public class StorageExceptionMapper implements ExceptionMapper<StorageException> { - private static final Logger log = Logger.getLogger(DefaultExceptionMapper.class); + private static final Logger log = Logger.getLogger(StorageExceptionMapper.class); private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private final ComponentsUtils componentsUtils; diff --git a/catalog-be/src/main/resources/config/configuration.yaml b/catalog-be/src/main/resources/config/configuration.yaml index c34d6742a1..820034eca2 100644 --- a/catalog-be/src/main/resources/config/configuration.yaml +++ b/catalog-be/src/main/resources/config/configuration.yaml @@ -930,3 +930,6 @@ directives: #Space separated list of permitted ancestors permittedAncestors: "" + +# Comma separated list of excluded URLs by the DataValidatorFilter +dataValidatorFilterExcludedUrls: "/healthCheck,/followed,/authorize" diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml index 0081525647..0830dda7b4 100644 --- a/catalog-be/src/main/resources/config/error-configuration.yaml +++ b/catalog-be/src/main/resources/config/error-configuration.yaml @@ -2411,7 +2411,7 @@ errors: # %1 - property name code: 400, message: 'Error: Invalid Content. %1 has invalid format.', - messageId: "SVC4723" + messageId: "SVC4731" } #---------SVC4734------------------------------ # %1 - list of validation errors @@ -2822,6 +2822,13 @@ errors: message: "Capability '%1' not found in '%2' '%3'." messageId: "SVC4186" + #---------SVC4001------------------------------ + NOT_PERMITTED_SPECIAL_CHARS: { + code: 406, + message: 'Error: HTML elements not permitted in field values.', + messageId: "SVC4001" + } + # %1 - The data type Uid DATA_TYPE_NOT_FOUND: code: 404 diff --git a/catalog-be/src/main/webapp/WEB-INF/web.xml b/catalog-be/src/main/webapp/WEB-INF/web.xml index 7cbfd1a920..9761b38043 100644 --- a/catalog-be/src/main/webapp/WEB-INF/web.xml +++ b/catalog-be/src/main/webapp/WEB-INF/web.xml @@ -20,6 +20,7 @@ org.glassfish.jersey.media.multipart.MultiPartFeature, org.openecomp.sdc.be.filters.BasicAuthenticationFilter, org.openecomp.sdc.be.filters.BeServletFilter, + org.openecomp.sdc.be.filters.DataValidatorFilter, org.openecomp.sdc.be.filters.ComponentsAvailabilityFilter, org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature, org.openecomp.sdc.be.servlets.exception.DefaultExceptionMapper, @@ -59,6 +60,7 @@ <param-value> org.glassfish.jersey.media.multipart.MultiPartFeature, org.openecomp.sdc.be.filters.BeServletFilter, + org.openecomp.sdc.be.filters.DataValidatorFilter, org.openecomp.sdc.be.filters.ComponentsAvailabilityFilter, org.openecomp.sdc.be.servlets.exception.DefaultExceptionMapper, org.openecomp.sdc.be.servlets.exception.ComponentExceptionMapper, @@ -149,6 +151,18 @@ <url-pattern>/sdc/*</url-pattern> </filter-mapping> + <filter> + <filter-name>dataValidatorFilter</filter-name> + <filter-class> + org.openecomp.sdc.be.filters.DataValidatorFilter + </filter-class> + </filter> + <filter-mapping> + <filter-name>dataValidatorFilter</filter-name> + <url-pattern>/sdc2/rest/*</url-pattern> + <url-pattern>/sdc/*</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/servlets/utils/DataValidatorTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/utils/DataValidatorTest.java new file mode 100644 index 0000000000..8804e49b4b --- /dev/null +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/utils/DataValidatorTest.java @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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.servlets.utils; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.common.util.DataValidator; +import org.openecomp.sdc.common.util.SecureString; + +@ExtendWith(MockitoExtension.class) +class DataValidatorTest { + + @InjectMocks + private DataValidator dataValidator; + + @Test + void isValidSecureString() { + final SecureString secureString = new SecureString("<script>alert(“XSS”);</script>"); + assertFalse(dataValidator.isValid(secureString)); + } + + @Test + void isValidEPUser() { + final User user = new User(); + user.setEmail("“><script>alert(“XSS”)</script>"); + user.setUserId("<IMG SRC=”javascript:alert(‘XSS’);”>"); + user.setFirstName("<IMG SRC=javascript:alert(‘XSS’)> "); + assertFalse(dataValidator.isValid(user)); + } + +} 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 2c7c724af7..55297f9e13 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 @@ -22,7 +22,7 @@ package org.openecomp.sdc.be.dao.api; public enum ActionStatus { OK, ACCEPTED, CREATED, NO_CONTENT, GENERAL_ERROR, NOT_ALLOWED, MISSING_INFORMATION, RESTRICTED_OPERATION, - RESTRICTED_ACCESS, INVALID_CONTENT, INVALID_PROPERTY_VALUES, NOT_SUPPORTED, INVALID_ARTIFACT_LABEL_NAME, + RESTRICTED_ACCESS, INVALID_CONTENT, INVALID_PROPERTY_VALUES, NOT_SUPPORTED, INVALID_ARTIFACT_LABEL_NAME, NOT_PERMITTED_SPECIAL_CHARS, // User related USER_ALREADY_EXIST, USER_INACTIVE, USER_NOT_FOUND, USER_HAS_ACTIVE_ELEMENTS, INVALID_EMAIL_ADDRESS, INVALID_ROLE, DELETE_USER_ADMIN_CONFLICT, UPDATE_USER_ADMIN_CONFLICT, CANNOT_DELETE_USER_WITH_ACTIVE_ELEMENTS, CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS, INVALID_USER_ID, USER_DEFINED, // CapabilityType related diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/filters/DataValidatorFilter.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/filters/DataValidatorFilter.java new file mode 100644 index 0000000000..5b82a3c15c --- /dev/null +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/filters/DataValidatorFilter.java @@ -0,0 +1,70 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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.fe.filters; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.openecomp.sdc.common.filters.DataValidatorFilterAbstract; +import org.openecomp.sdc.exception.NotAllowedSpecialCharsException; +import org.openecomp.sdc.fe.config.Configuration; +import org.openecomp.sdc.fe.config.ConfigurationManager; + +/** + * Implement DataValidatorFilter for front-end. + * Extends {@link DataValidatorFilterAbstract} + */ +public class DataValidatorFilter extends DataValidatorFilterAbstract { + + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) + throws IOException, ServletException, NotAllowedSpecialCharsException { + try { + super.doFilter(request, response, chain); + } catch (final NotAllowedSpecialCharsException e) { + // error handing to show 'Error: Special characters not allowed.' + ((HttpServletResponse) response).sendError(400, DataValidatorFilter.ERROR_SPECIAL_CHARACTERS_NOT_ALLOWED); + } + + } + + @Override + protected List<String> getDataValidatorFilterExcludedUrls() { + final ConfigurationManager configurationManager = ConfigurationManager.getConfigurationManager(); + if (configurationManager != null) { + final Configuration configuration = configurationManager.getConfiguration(); + if (configuration != null) { + final String dataValidatorFilterExcludedUrls = configuration.getDataValidatorFilterExcludedUrls(); + if (StringUtils.isNotBlank(dataValidatorFilterExcludedUrls)) { + return Arrays.asList(dataValidatorFilterExcludedUrls.split(",")); + } + } + } + return new ArrayList<>(); + } +} diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/User.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/User.java index 7b83dae731..72dc4aa7aa 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/User.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/User.java @@ -20,35 +20,44 @@ package org.openecomp.sdc.be.model; import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.openecomp.sdc.be.dao.utils.UserStatusEnum; -import org.openecomp.sdc.be.resources.data.UserData; +import org.openecomp.sdc.common.util.NoHtml; @JsonInclude +@NoArgsConstructor +@Getter +@Setter +@ToString +@EqualsAndHashCode public class User { public static final String FORCE_DELETE_HEADER_FLAG = "FORCE_DELETE"; + @NoHtml private String firstName; + @NoHtml private String lastName; + @NoHtml private String userId; + @NoHtml private String email; + @NoHtml private String role; private Long lastLoginTime; + @ToString.Exclude + @EqualsAndHashCode.Exclude private UserStatusEnum status = UserStatusEnum.ACTIVE; - public User() { - } - public User(String userId) { this.userId = userId; } - public User(UserData userDate) { - this(userDate.getFirstName(), userDate.getLastName(), userDate.getUserId(), userDate.getEmail(), userDate.getRole(), - userDate.getLastLoginTime()); - } - public User(String firstName, String lastName, String userId, String emailAddress, String role, Long lastLoginTime) { this.firstName = firstName; this.lastName = lastName; @@ -74,46 +83,6 @@ public class User { this.lastLoginTime = other.getLastLoginTime(); } - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getRole() { - return role; - } - - public void setRole(String role) { - this.role = role; - } - public String getFullName() { return this.getFirstName() + " " + this.getLastName(); } @@ -123,95 +92,4 @@ public class User { this.lastLoginTime = now.getMillis(); } - public Long getLastLoginTime() { - return this.lastLoginTime; - } - - public void setLastLoginTime(Long time) { - this.lastLoginTime = time; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((userId == null) ? 0 : userId.hashCode()); - result = prime * result + ((email == null) ? 0 : email.hashCode()); - result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); - result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); - result = prime * result + ((role == null) ? 0 : role.hashCode()); - result = prime * result + ((lastLoginTime == null) ? 0 : lastLoginTime.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - User other = (User) obj; - if (userId == null) { - if (other.userId != null) { - return false; - } - } else if (!userId.equals(other.userId)) { - return false; - } - if (email == null) { - if (other.email != null) { - return false; - } - } else if (!email.equals(other.email)) { - return false; - } - if (firstName == null) { - if (other.firstName != null) { - return false; - } - } else if (!firstName.equals(other.firstName)) { - return false; - } - if (lastName == null) { - if (other.lastName != null) { - return false; - } - } else if (!lastName.equals(other.lastName)) { - return false; - } - if (role == null) { - if (other.role != null) { - return false; - } - } else if (!role.equals(other.role)) { - return false; - } - if (lastLoginTime == null) { - if (other.lastLoginTime != null) { - return false; - } - } else if (!lastLoginTime.equals(other.lastLoginTime)) { - return false; - } - return true; - } - - public UserStatusEnum getStatus() { - return status; - } - - public void setStatus(UserStatusEnum status) { - this.status = status; - } - - @Override - public String toString() { - return "User [firstName=" + firstName + ", lastName=" + lastName + ", userId=" + userId + ", email=" + email + ", role=" + role - + ", last login time=" + lastLoginTime + "]"; - } } diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/UserTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/UserTest.java index 13684e154c..50fcd41d93 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/UserTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/UserTest.java @@ -7,9 +7,9 @@ * 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. @@ -23,228 +23,226 @@ package org.openecomp.sdc.be.model; import org.junit.Assert; import org.junit.Test; import org.openecomp.sdc.be.dao.utils.UserStatusEnum; -import org.openecomp.sdc.be.resources.data.UserData; public class UserTest { - private User createTestSubject() { - return new User(); - } - - @Test - public void testCtor() throws Exception { - new User(new User()); - new User(new UserData()); - new User("mock", "mock", "mock", "mock", "mock", 0L); - } - - @Test - public void testCopyData() throws Exception { - User testSubject; - User other = null; - - // default test - testSubject = createTestSubject(); - testSubject.copyData(other); - testSubject.copyData(new User()); - } - - @Test - public void testGetFirstName() throws Exception { - User testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getFirstName(); - } - - @Test - public void testSetFirstName() throws Exception { - User testSubject; - String firstName = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setFirstName(firstName); - } - - @Test - public void testGetLastName() throws Exception { - User testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getLastName(); - } - - @Test - public void testSetLastName() throws Exception { - User testSubject; - String lastName = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setLastName(lastName); - } - - @Test - public void testGetUserId() throws Exception { - User testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getUserId(); - } - - @Test - public void testSetUserId() throws Exception { - User testSubject; - String userId = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setUserId(userId); - } - - @Test - public void testGetEmail() throws Exception { - User testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getEmail(); - } - - @Test - public void testSetEmail() throws Exception { - User testSubject; - String email = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setEmail(email); - } - - @Test - public void testGetRole() throws Exception { - User testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getRole(); - } - - @Test - public void testSetRole() throws Exception { - User testSubject; - String role = ""; - - // default test - testSubject = createTestSubject(); - testSubject.setRole(role); - } - - @Test - public void testGetFullName() throws Exception { - User testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getFullName(); - } - - @Test - public void testSetLastLoginTime() throws Exception { - User testSubject; - - // default test - testSubject = createTestSubject(); - testSubject.setLastLoginTime(); - } - - @Test - public void testSetLastLoginTime_1() throws Exception { - User testSubject; - Long time = null; - - // default test - testSubject = createTestSubject(); - testSubject.setLastLoginTime(time); - } - - @Test - public void testGetLastLoginTime() throws Exception { - User testSubject; - Long result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getLastLoginTime(); - } - - @Test - public void testHashCode() throws Exception { - User testSubject; - int result; - - // default test - testSubject = createTestSubject(); - result = testSubject.hashCode(); - } - - @Test - public void testEquals() throws Exception { - User testSubject; - Object obj = null; - boolean result; - - // test 1 - testSubject = createTestSubject(); - result = testSubject.equals(obj); - Assert.assertEquals(false, result); - - result = testSubject.equals(new Object()); - Assert.assertEquals(false, result); - - result = testSubject.equals(testSubject); - Assert.assertEquals(true, result); - result = testSubject.equals(createTestSubject()); - Assert.assertEquals(true, result); - } - - @Test - public void testGetStatus() throws Exception { - User testSubject; - UserStatusEnum result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getStatus(); - } - - @Test - public void testSetStatus() throws Exception { - User testSubject; - UserStatusEnum status = null; - - // default test - testSubject = createTestSubject(); - testSubject.setStatus(status); - } - - @Test - public void testToString() throws Exception { - User testSubject; - String result; - - // default test - testSubject = createTestSubject(); - result = testSubject.toString(); - } + private User createTestSubject() { + return new User(); + } + + @Test + public void testCtor() throws Exception { + new User(new User()); + new User("mock", "mock", "mock", "mock", "mock", 0L); + } + + @Test + public void testCopyData() throws Exception { + User testSubject; + User other = null; + + // default test + testSubject = createTestSubject(); + testSubject.copyData(other); + testSubject.copyData(new User()); + } + + @Test + public void testGetFirstName() throws Exception { + User testSubject; + String result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getFirstName(); + } + + @Test + public void testSetFirstName() throws Exception { + User testSubject; + String firstName = ""; + + // default test + testSubject = createTestSubject(); + testSubject.setFirstName(firstName); + } + + @Test + public void testGetLastName() throws Exception { + User testSubject; + String result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getLastName(); + } + + @Test + public void testSetLastName() throws Exception { + User testSubject; + String lastName = ""; + + // default test + testSubject = createTestSubject(); + testSubject.setLastName(lastName); + } + + @Test + public void testGetUserId() throws Exception { + User testSubject; + String result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getUserId(); + } + + @Test + public void testSetUserId() throws Exception { + User testSubject; + String userId = ""; + + // default test + testSubject = createTestSubject(); + testSubject.setUserId(userId); + } + + @Test + public void testGetEmail() throws Exception { + User testSubject; + String result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getEmail(); + } + + @Test + public void testSetEmail() throws Exception { + User testSubject; + String email = ""; + + // default test + testSubject = createTestSubject(); + testSubject.setEmail(email); + } + + @Test + public void testGetRole() throws Exception { + User testSubject; + String result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getRole(); + } + + @Test + public void testSetRole() throws Exception { + User testSubject; + String role = ""; + + // default test + testSubject = createTestSubject(); + testSubject.setRole(role); + } + + @Test + public void testGetFullName() throws Exception { + User testSubject; + String result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getFullName(); + } + + @Test + public void testSetLastLoginTime() throws Exception { + User testSubject; + + // default test + testSubject = createTestSubject(); + testSubject.setLastLoginTime(); + } + + @Test + public void testSetLastLoginTime_1() throws Exception { + User testSubject; + Long time = null; + + // default test + testSubject = createTestSubject(); + testSubject.setLastLoginTime(time); + } + + @Test + public void testGetLastLoginTime() throws Exception { + User testSubject; + Long result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getLastLoginTime(); + } + + @Test + public void testHashCode() throws Exception { + User testSubject; + int result; + + // default test + testSubject = createTestSubject(); + result = testSubject.hashCode(); + } + + @Test + public void testEquals() throws Exception { + User testSubject; + Object obj = null; + boolean result; + + // test 1 + testSubject = createTestSubject(); + result = testSubject.equals(obj); + Assert.assertEquals(false, result); + + result = testSubject.equals(new Object()); + Assert.assertEquals(false, result); + + result = testSubject.equals(testSubject); + Assert.assertEquals(true, result); + result = testSubject.equals(createTestSubject()); + Assert.assertEquals(true, result); + } + + @Test + public void testGetStatus() throws Exception { + User testSubject; + UserStatusEnum result; + + // default test + testSubject = createTestSubject(); + result = testSubject.getStatus(); + } + + @Test + public void testSetStatus() throws Exception { + User testSubject; + UserStatusEnum status = null; + + // default test + testSubject = createTestSubject(); + testSubject.setStatus(status); + } + + @Test + public void testToString() throws Exception { + User testSubject; + String result; + + // default test + testSubject = createTestSubject(); + result = testSubject.toString(); + } } diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/edit-name-modal/edit-name-modal.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/edit-name-modal/edit-name-modal.component.html index 75ee2d520f..3b6575c3aa 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/edit-name-modal/edit-name-modal.component.html +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/edit-name-modal/edit-name-modal.component.html @@ -23,6 +23,6 @@ testId="instanceName"></sdc-input> <sdc-validation [validateElement]="updateNameInput" (validityChanged)="validityChanged($event)"> <sdc-required-validator message="Name is required."></sdc-required-validator> - <sdc-regex-validator message="Special characters not allowed." [pattern]="pattern"></sdc-regex-validator> + <sdc-regex-validator message="HTML elements not permitted in field values." [pattern]="pattern"></sdc-regex-validator> </sdc-validation> </div>
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html index d5b9d9e9b2..9d38195237 100644 --- a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html +++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html @@ -7,7 +7,7 @@ [placeHolder]="'Enter Name'"> </sdc-input> <sdc-validation [validateElement]="heatName"> - <sdc-regex-validator [message]="'Special characters not allowed.'" [pattern]="pattern"></sdc-regex-validator> + <sdc-regex-validator [message]="'HTML elements not permitted in field values.'" [pattern]="pattern"></sdc-regex-validator> </sdc-validation> </div> <div class="edit-module-name-label module-name" data-tests-id="'popover-module-name'" sdc-tooltip [tooltip-text]="selectModule.moduleName">{{selectModule.moduleName}}</div> diff --git a/catalog-ui/src/assets/languages/en_US.json b/catalog-ui/src/assets/languages/en_US.json index c3a6bc9a4c..fc5445a6c3 100644 --- a/catalog-ui/src/assets/languages/en_US.json +++ b/catalog-ui/src/assets/languages/en_US.json @@ -4,7 +4,7 @@ "VALIDATION_ERROR_MAX_LENGTH": "Max length {{max}} characters.", "VALIDATION_ERROR_MIN_LENGTH": "Min length {{min}} characters.", "VALIDATION_ERROR_REQUIRED": "{{field}} is required.", - "VALIDATION_ERROR_SPECIAL_CHARS_NOT_ALLOWED": "Special characters not allowed.", + "VALIDATION_ERROR_SPECIAL_CHARS_NOT_ALLOWED": "HTML elements not permitted in field values.", "LABEL_MAX_SIZE_XX": "Max size is up to {{size}}", "LABEL_ALL_FIELDS_ARE_MANDATORY": "All fields are mandatory.", "VALIDATION_ERROR_BOOLEAN": "Value should be 'TRUE' or 'FALSE'.", @@ -168,7 +168,7 @@ "NEW_SERVICE_RESOURCE_ERROR_MAX_LENGTH_128": "Max length 128 characters.", "NEW_SERVICE_RESOURCE_ERROR_MAX_LENGTH_1024": "Max length 1024 characters.", "NEW_SERVICE_RESOURCE_ERROR_NAME_EXISTS": "Name already exists.", - "NEW_SERVICE_RESOURCE_ERROR_SPECIAL_CHARS": "Special characters not allowed.", + "NEW_SERVICE_RESOURCE_ERROR_SPECIAL_CHARS": "HTML elements not permitted in field values.", "NEW_SERVICE_RESOURCE_ERROR_CATEGORY_REQUIRED": "category is required.", "NEW_SERVICE_RESOURCE_ERROR_CATEGORY_NOT_VALID": "Category not valid for base type.", "NEW_SERVICE_RESOURCE_ERROR_CONTACT_REQUIRED": "Contact is required.", diff --git a/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java b/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java index da849f385c..f2bad701df 100644 --- a/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java +++ b/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java @@ -147,6 +147,7 @@ public class Configuration extends BasicConfiguration { private ExternalCsarStore externalCsarStore; private CsarFormat csarFormat; private String componentInstanceCounterDelimiter; + private String dataValidatorFilterExcludedUrls; // Comma separated list of excluded URLs by the DataValidatorFilter private String permittedAncestors; // Space separated list of permitted ancestors @SuppressWarnings("unchecked") diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/filters/DataValidatorFilterAbstract.java b/common-app-api/src/main/java/org/openecomp/sdc/common/filters/DataValidatorFilterAbstract.java new file mode 100644 index 0000000000..44c0cbb791 --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/filters/DataValidatorFilterAbstract.java @@ -0,0 +1,158 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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.filters; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +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.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.HttpMethod; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.openecomp.sdc.common.util.DataValidator; +import org.openecomp.sdc.common.util.SecureString; +import org.openecomp.sdc.exception.NotAllowedSpecialCharsException; + +/** + * Provides mechanism to filter request according to {@link DataValidator} and {@code dataValidatorFilterExcludedUrlsList}. + */ +public abstract class DataValidatorFilterAbstract implements Filter { + + protected static final String DATA_VALIDATOR_FILTER_EXCLUDED_URLS = "dataValidatorFilterExcludedUrls"; + protected static final String ERROR_SPECIAL_CHARACTERS_NOT_ALLOWED = "Error: HTML elements not permitted in field values."; + private DataValidator dataValidator; + + @Override + public void init(final FilterConfig filterConfig) throws ServletException { + dataValidator = new DataValidator(); + } + + @Override + public void destroy() { + dataValidator = null; + } + + @Override + public void doFilter(ServletRequest request, final ServletResponse response, final FilterChain chain) + throws IOException, ServletException { + if (isExcluded(((HttpServletRequest) request).getRequestURI()) || !isPostOrPut(((HttpServletRequest) request).getMethod())) { + chain.doFilter(request, response); + } else { + if (!skipCheckBody((HttpServletRequest) request)) { + request = new RequestWrapper((HttpServletRequest) request); + } + if (isValid((HttpServletRequest) request)) { + chain.doFilter(request, response); + } else { + throw new NotAllowedSpecialCharsException(); + } + } + } + + private boolean isPostOrPut(final String method) { + return method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT); + } + + private boolean isExcluded(final String path) { + final List<String> dataValidatorFilterExcludedUrlsList = getDataValidatorFilterExcludedUrls(); + return CollectionUtils.isNotEmpty(dataValidatorFilterExcludedUrlsList) + && dataValidatorFilterExcludedUrlsList.stream().anyMatch(s -> path.trim().contains(s.trim())); + } + + protected abstract List<String> getDataValidatorFilterExcludedUrls(); + + private boolean skipCheckBody(final HttpServletRequest requestWrapper) { + final String contentType = requestWrapper.getContentType(); + return StringUtils.isNotEmpty(contentType) && contentType.contains("multipart/form-data"); + } + + private boolean isValid(final HttpServletRequest request) { + final boolean skipCheckBody = skipCheckBody(request); + return (skipCheckBody || checkBody((RequestWrapper) request)) + && checkHeaders(request) + && checkCookies(request) + && checkParameters(request) + && checkQuery(request); + } + + private boolean checkParameters(final HttpServletRequest httpRequest) { + final Iterator<String> parameterNamesIterator = httpRequest.getParameterNames().asIterator(); + while (parameterNamesIterator.hasNext()) { + final String parameterName = parameterNamesIterator.next(); + final String parameter = httpRequest.getParameter(parameterName); + if (!dataValidator.isValid(new SecureString(parameter))) { + return false; + } + final String[] parameterValues = httpRequest.getParameterValues(parameterName); + if (parameterValues != null) { + for (final String parameterValue : parameterValues) { + if (!dataValidator.isValid(new SecureString(parameterValue))) { + return false; + } + } + } + } + return true; + } + + private boolean checkHeaders(final HttpServletRequest httpRequest) { + final Iterator<String> headerNamesIterator = httpRequest.getHeaderNames().asIterator(); + while (headerNamesIterator.hasNext()) { + final String headerName = headerNamesIterator.next(); + final String header = httpRequest.getHeader(headerName); + if (!dataValidator.isValid(new SecureString(header))) { + return false; + } + } + return true; + } + + private boolean checkCookies(final HttpServletRequest httpRequest) { + final Cookie[] cookies = httpRequest.getCookies(); + if (cookies != null) { + for (final Cookie cookie : cookies) { + if (!dataValidator.isValid(new SecureString(cookie.getValue()))) { + return false; + } + } + } + return true; + } + + private boolean checkQuery(final HttpServletRequest httpRequest) { + final String queryString = httpRequest.getQueryString(); + return StringUtils.isEmpty(queryString) || dataValidator.isValid(new SecureString(queryString)); + } + + private boolean checkBody(final RequestWrapper httpRequest) { + final String body = httpRequest.getBody(); + return StringUtils.isEmpty(body) || dataValidator.isValid(new SecureString(body)); + } + +} + diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/filters/RequestWrapper.java b/common-app-api/src/main/java/org/openecomp/sdc/common/filters/RequestWrapper.java new file mode 100644 index 0000000000..79ef42d230 --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/filters/RequestWrapper.java @@ -0,0 +1,107 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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.filters; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import lombok.Getter; +import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode; +import org.openecomp.sdc.common.log.wrappers.Logger; + +/** + * Provides mechanism to wrap request's InputStream and read it more than once. + */ +public class RequestWrapper extends HttpServletRequestWrapper { + + private static final Logger LOGGER = Logger.getLogger(RequestWrapper.class); + + @Getter + private final String body; + + public RequestWrapper(final HttpServletRequest request) throws IOException { + //So that other request method behave just like before + super(request); + + final StringBuilder stringBuilder = new StringBuilder(); + try (final InputStream inputStream = request.getInputStream(); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { + final char[] charBuffer = new char[128]; + int bytesRead; + while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { + stringBuilder.append(charBuffer, 0, bytesRead); + } + } catch (IOException ex) { + LOGGER.warn(EcompLoggerErrorCode.UNKNOWN_ERROR, RequestWrapper.class.getName(), "Failed to read InputStream from request", ex); + throw ex; + } + //Store request body content in 'body' variable + body = stringBuilder.toString(); + } + + @Override + public String getParameter(final String name) { + if (body.contains(name) && super.getParameter(name) == null) { + final String[] split = body.split("&"); + return Arrays.stream(split).filter(s -> s.contains(name)).findFirst().get().replace(name + '=', ""); + } else { + return super.getParameter(name); + } + } + + @Override + public ServletInputStream getInputStream() { + final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(final ReadListener readListener) { + // Nothing to override + } + + public int read() { + return byteArrayInputStream.read(); + } + }; + } + + @Override + public BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(this.getInputStream())); + } + +} diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/servlets/BasicServlet.java b/common-app-api/src/main/java/org/openecomp/sdc/common/servlets/BasicServlet.java index 658f0955b2..baee9464fa 100644 --- a/common-app-api/src/main/java/org/openecomp/sdc/common/servlets/BasicServlet.java +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/servlets/BasicServlet.java @@ -24,5 +24,5 @@ import com.google.gson.GsonBuilder; public abstract class BasicServlet { - protected Gson gson = new GsonBuilder().setPrettyPrinting().create(); + protected final Gson gson = new GsonBuilder().setPrettyPrinting().create(); } diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/util/DataValidator.java b/common-app-api/src/main/java/org/openecomp/sdc/common/util/DataValidator.java new file mode 100644 index 0000000000..58b4a87997 --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/util/DataValidator.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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 java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +/** + * Provides mechanism to validate input for Constraint Violations. For more info see {@link ValidatorFactory}, {@link ConstraintViolation}, + * {@link Validator}. + */ +public class DataValidator { + + private final ValidatorFactory validatorFactory; + + public DataValidator() { + validatorFactory = Validation.buildDefaultValidatorFactory(); + } + + private <E> Set<ConstraintViolation<E>> getConstraintViolations(E classToValid) { + final Validator validator = validatorFactory.getValidator(); + return validator.validate(classToValid); + } + + /** + * Validates input for Constraint Violations + * + * @param classToValid - class to validate + * @param <E> + * @return true if input is valid, false if not + */ + public <E> boolean isValid(E classToValid) { + return getConstraintViolations(classToValid).isEmpty(); + } + +} diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/util/NoHtml.java b/common-app-api/src/main/java/org/openecomp/sdc/common/util/NoHtml.java new file mode 100644 index 0000000000..f1e9d6dbfd --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/util/NoHtml.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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 static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.validation.Constraint; +import javax.validation.Payload; + +/** + * Provides mechanism to annotate METHOD and/or FIELD to be validated by {@link NoHtmlValidator}. + */ +@Documented +@Constraint(validatedBy = NoHtmlValidator.class) +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface NoHtml { + + String message() default "Unsafe html content"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/util/NoHtmlValidator.java b/common-app-api/src/main/java/org/openecomp/sdc/common/util/NoHtmlValidator.java new file mode 100644 index 0000000000..38d4e7d79b --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/util/NoHtmlValidator.java @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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 javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import org.jsoup.Jsoup; +import org.jsoup.safety.Safelist; + +/** + * Provides mechanism to check if code annotated with {@link NoHtml} contains no html. + */ +public class NoHtmlValidator implements ConstraintValidator<NoHtml, String> { + + @Override + public boolean isValid(String value, ConstraintValidatorContext ctx) { + return value == null || Jsoup.isValid(value, Safelist.none()); + } +} diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/util/SecureString.java b/common-app-api/src/main/java/org/openecomp/sdc/common/util/SecureString.java new file mode 100644 index 0000000000..97afcb547e --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/util/SecureString.java @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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 lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Provides wrapper for string to be checked by {@link DataValidator}. + */ +@Getter +@AllArgsConstructor +public class SecureString { + + @NoHtml + private String data; + +} diff --git a/common-app-api/src/main/java/org/openecomp/sdc/exception/NotAllowedSpecialCharsException.java b/common-app-api/src/main/java/org/openecomp/sdc/exception/NotAllowedSpecialCharsException.java new file mode 100644 index 0000000000..39a59ae7eb --- /dev/null +++ b/common-app-api/src/main/java/org/openecomp/sdc/exception/NotAllowedSpecialCharsException.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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.exception; + + +import lombok.Getter; + +@Getter +public class NotAllowedSpecialCharsException extends RuntimeException { + + private static final String ERROR_SPECIAL_CHARACTERS_NOT_ALLOWED = "Error: HTML elements not permitted in field values."; + private final String errorId; + private final String message; + + public NotAllowedSpecialCharsException() { + this.errorId = "NOT_PERMITTED_SPECIAL_CHARS"; + this.message = ERROR_SPECIAL_CHARACTERS_NOT_ALLOWED; + } + +} diff --git a/common-app-api/src/main/java/org/openecomp/sdc/fe/config/Configuration.java b/common-app-api/src/main/java/org/openecomp/sdc/fe/config/Configuration.java index 279f183324..4c97a4aa40 100644 --- a/common-app-api/src/main/java/org/openecomp/sdc/fe/config/Configuration.java +++ b/common-app-api/src/main/java/org/openecomp/sdc/fe/config/Configuration.java @@ -75,6 +75,7 @@ public class Configuration extends BasicConfiguration { private List<List<String>> identificationHeaderFields; private List<List<String>> optionalHeaderFields; private List<String> forwardHeaderFields; + private String dataValidatorFilterExcludedUrls; // Comma separated list of excluded URLs by the DataValidatorFilter private String permittedAncestors; // Space separated list of permitted ancestors public Integer getHealthCheckSocketTimeoutInMs(int defaultVal) { diff --git a/docs/configuration.rst b/docs/configuration.rst index 20d164bfa6..5de8edebdd 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -976,6 +976,9 @@ BE-configuration.yaml definedResourceNamespace: - org.openecomp.resource. + # Comma separated list of excluded URLs by the DataValidatorFilter + dataValidatorFilterExcludedUrls: "/healthCheck,/followed,/authorize" + BE-distribution-engine-configuration.yaml ***************************************** @@ -1341,6 +1344,9 @@ FE-configuration.yaml # What is the interval of the statistics collection probeIntervalInSeconds: 15 + # Comma separated list of excluded URLs by the DataValidatorFilter + dataValidatorFilterExcludedUrls: "/healthCheck,/followed,/authorize" + FE-plugins-configuration.yaml ***************************** diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/notifications-fe/src/main/webapp/WEB-INF/web.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/notifications-fe/src/main/webapp/WEB-INF/web.xml index b51399ca54..f0291cb060 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/notifications-fe/src/main/webapp/WEB-INF/web.xml +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/notifications-fe/src/main/webapp/WEB-INF/web.xml @@ -15,6 +15,15 @@ </listener> <filter> + <filter-name>dataValidatorFilter</filter-name> + <filter-class>org.openecomp.sdc.common.filters.DataValidatorFilter</filter-class> + </filter> + <filter-mapping> + <filter-name>dataValidatorFilter</filter-name> + <url-pattern>/v1.0/*</url-pattern> + </filter-mapping> + + <filter> <filter-name>contentSecurityPolicyHeaderFilter</filter-name> <filter-class>org.openecomp.sdc.common.filters.ContentSecurityPolicyHeaderFilter</filter-class> <async-supported>true</async-supported> @@ -54,6 +63,7 @@ <filter-name>RestrictionAccessFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> + <!-- Spring WS Mapping --> <servlet> <servlet-name>spring-mapper</servlet-name> @@ -62,10 +72,13 @@ </servlet-class> <load-on-startup>1</load-on-startup> </servlet> + <servlet-mapping> + <servlet-name>spring-mapper</servlet-name> + <url-pattern>/ws/*</url-pattern> + </servlet-mapping> <!-- CXF --> <servlet> <servlet-name>CXFServlet</servlet-name> - <display-name>CXF Servlet</display-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> @@ -87,19 +100,14 @@ </init-param> <load-on-startup>1</load-on-startup> </servlet> + <servlet-mapping> + <servlet-name>CXFServlet</servlet-name> + <url-pattern>/*</url-pattern> + </servlet-mapping> <context-param> <param-name>org.eclipse.jetty.servlet.Default.dirAllowed</param-name> <param-value>false</param-value> </context-param> - <servlet-mapping> - <servlet-name>spring-mapper</servlet-name> - <url-pattern>/ws/*</url-pattern> - </servlet-mapping> - <servlet-mapping> - <servlet-name>CXFServlet</servlet-name> - <url-pattern>/*</url-pattern> - </servlet-mapping> - </web-app> diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml index 9c2aa51a28..15251436d6 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml @@ -104,4 +104,4 @@ </jaxrs:outInterceptors> </jaxrs:server> -</beans>
\ No newline at end of file +</beans> 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 eb8bd9e93f..31400f878e 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 @@ -25,8 +25,18 @@ </listener> <filter> + <filter-name>dataValidatorFilter</filter-name> + <filter-class>org.openecomp.sdc.common.filters.DataValidatorFilter</filter-class> + </filter> + <filter-mapping> + <filter-name>dataValidatorFilter</filter-name> + <url-pattern>/v1.0/*</url-pattern> + </filter-mapping> + + <filter> <filter-name>contentSecurityPolicyHeaderFilter</filter-name> - <filter-class>org.openecomp.sdc.common.filters.ContentSecurityPolicyHeaderFilter</filter-class> + <filter-class>org.openecomp.sdc.common.filters.ContentSecurityPolicyHeaderFilter + </filter-class> <async-supported>true</async-supported> </filter> <filter-mapping> @@ -41,9 +51,6 @@ <filter-mapping> <filter-name>PermissionsFilter</filter-name> <url-pattern>/v1.0/vendor-license-models/*</url-pattern> - </filter-mapping> - <filter-mapping> - <filter-name>PermissionsFilter</filter-name> <url-pattern>/v1.0/vendor-software-products/*</url-pattern> </filter-mapping> @@ -63,6 +70,10 @@ <param-value>*</param-value> </init-param> </filter> + <filter-mapping> + <filter-name>cross-origin</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> <filter> <filter-name>RestrictionAccessFilter</filter-name> @@ -73,34 +84,34 @@ <filter-name>RestrictionAccessFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> + <filter> <filter-name>BasicAuth</filter-name> <filter-class>org.openecomp.server.filters.BasicAuthenticationFilter</filter-class> </filter> - <filter> - <filter-name>AuthN</filter-name> - <filter-class>org.openecomp.server.filters.ActionAuthenticationFilter</filter-class> - </filter> - <filter> - <filter-name>AuthZ</filter-name> - <filter-class>org.openecomp.server.filters.ActionAuthorizationFilter</filter-class> - </filter> - <filter-mapping> - <filter-name>cross-origin</filter-name> - <url-pattern>/*</url-pattern> - </filter-mapping> <filter-mapping> <filter-name>BasicAuth</filter-name> <url-pattern>/1.0/*</url-pattern> </filter-mapping> + + <filter> + <filter-name>AuthN</filter-name> + <filter-class>org.openecomp.server.filters.ActionAuthenticationFilter</filter-class> + </filter> <filter-mapping> <filter-name>AuthN</filter-name> <url-pattern>/workflow/v1.0/actions/*</url-pattern> </filter-mapping> + + <filter> + <filter-name>AuthZ</filter-name> + <filter-class>org.openecomp.server.filters.ActionAuthorizationFilter</filter-class> + </filter> <filter-mapping> <filter-name>AuthZ</filter-name> <url-pattern>/workflow/v1.0/actions/*</url-pattern> </filter-mapping> + <filter> <filter-name>SessionContextFilter</filter-name> <filter-class>org.openecomp.server.filters.OnboardingSessionContextFilter</filter-class> @@ -109,6 +120,7 @@ <filter-name>SessionContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> + <!-- Spring WS Mapping --> <servlet> <servlet-name>spring-mapper</servlet-name> @@ -117,6 +129,10 @@ </servlet-class> <load-on-startup>1</load-on-startup> </servlet> + <servlet-mapping> + <servlet-name>spring-mapper</servlet-name> + <url-pattern>/ws/*</url-pattern> + </servlet-mapping> <!-- CXF --> <servlet> <servlet-name>CXFServlet</servlet-name> @@ -142,10 +158,6 @@ <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> - <servlet-name>spring-mapper</servlet-name> - <url-pattern>/ws/*</url-pattern> - </servlet-mapping> - <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> diff --git a/openecomp-be/dist/sdc-onboard-backend-docker/artifacts/chef-repo/cookbooks/sdc-onboard-backend/templates/default/configuration.yaml.erb b/openecomp-be/dist/sdc-onboard-backend-docker/artifacts/chef-repo/cookbooks/sdc-onboard-backend/templates/default/configuration.yaml.erb index 93e0be9467..142977c078 100644 --- a/openecomp-be/dist/sdc-onboard-backend-docker/artifacts/chef-repo/cookbooks/sdc-onboard-backend/templates/default/configuration.yaml.erb +++ b/openecomp-be/dist/sdc-onboard-backend-docker/artifacts/chef-repo/cookbooks/sdc-onboard-backend/templates/default/configuration.yaml.erb @@ -72,3 +72,6 @@ externalCsarStore: #Space separated list of permitted ancestors permittedAncestors: <%= @permittedAncestors %> + +# Comma separated list of excluded URLs by the DataValidatorFilter +dataValidatorFilterExcludedUrls: "/healthCheck,/followed,/authorize" diff --git a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/DefaultExceptionMapper.java b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/DefaultExceptionMapper.java index a059434709..4ad6fd7874 100644 --- a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/DefaultExceptionMapper.java +++ b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/DefaultExceptionMapper.java @@ -16,10 +16,12 @@ package org.openecomp.sdc.common.errors; import com.fasterxml.jackson.databind.JsonMappingException; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import javax.servlet.http.HttpServletResponse; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.Path; @@ -29,8 +31,12 @@ import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.ExceptionMapper; import org.apache.commons.collections4.CollectionUtils; import org.hibernate.validator.internal.engine.path.PathImpl; +import org.onap.sdc.security.RepresentationUtils; import org.openecomp.core.utilities.file.FileUtils; import org.openecomp.core.utilities.json.JsonUtil; +import org.openecomp.sdc.exception.NotAllowedSpecialCharsException; +import org.openecomp.sdc.exception.ResponseFormat; +import org.openecomp.sdc.exception.ServiceException; import org.openecomp.sdc.logging.api.Logger; import org.openecomp.sdc.logging.api.LoggerFactory; @@ -113,4 +119,14 @@ public class DefaultExceptionMapper implements ExceptionMapper<Exception> { private Object toEntity(final Status status, final ErrorCode code) { return new ErrorCodeAndMessage(status, code); } + + public void writeToResponse(final NotAllowedSpecialCharsException e, final HttpServletResponse httpResponse) throws IOException { + final ResponseFormat responseFormat = new ResponseFormat(400); + responseFormat.setServiceException(new ServiceException(e.getErrorId(), e.getMessage(), new String[0])); + httpResponse.setStatus(responseFormat.getStatus()); + httpResponse.setContentType("application/json"); + httpResponse.setCharacterEncoding("UTF-8"); + httpResponse.getWriter().write(RepresentationUtils.toRepresentation(responseFormat.getRequestError())); + } + } diff --git a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/filters/DataValidatorFilter.java b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/filters/DataValidatorFilter.java new file mode 100644 index 0000000000..6e3f665762 --- /dev/null +++ b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/filters/DataValidatorFilter.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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.filters; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.openecomp.sdc.common.CommonConfigurationManager; +import org.openecomp.sdc.common.errors.DefaultExceptionMapper; +import org.openecomp.sdc.exception.NotAllowedSpecialCharsException; + +/** + * Implements DataValidatorFilter for onboarding. + * Extends {@link DataValidatorFilterAbstract} + */ +public class DataValidatorFilter extends DataValidatorFilterAbstract { + + private final DefaultExceptionMapper defaultExceptionMapper; + + public DataValidatorFilter() { + defaultExceptionMapper = new DefaultExceptionMapper(); + } + + @Override + public void doFilter(final ServletRequest request, ServletResponse response, final FilterChain chain) + throws IOException, ServletException, NotAllowedSpecialCharsException { + try { + super.doFilter(request, response, chain); + } catch (final NotAllowedSpecialCharsException e) { + defaultExceptionMapper.writeToResponse(e, (HttpServletResponse) response); + } + } + + @Override + protected List<String> getDataValidatorFilterExcludedUrls() { + final CommonConfigurationManager commonConfigurationManager = CommonConfigurationManager.getInstance(); + if (commonConfigurationManager != null) { + final String dataValidatorFilterExcludedUrls = commonConfigurationManager.getConfigValue(DATA_VALIDATOR_FILTER_EXCLUDED_URLS, ""); + if (StringUtils.isNotBlank(dataValidatorFilterExcludedUrls)) { + return Arrays.asList(dataValidatorFilterExcludedUrls.split(",")); + } + } + return new ArrayList<>(); + } + +} diff --git a/openecomp-be/tools/migration/README b/openecomp-be/tools/migration/README index 2245aafb99..74f62f5050 100644 --- a/openecomp-be/tools/migration/README +++ b/openecomp-be/tools/migration/README @@ -42,7 +42,7 @@ Usage - The migration result will be listed in a CSV file: upgradereport.csv "None" is an indication that the VSP was not in a checkout status prior to the upgrade. - Exmample for a valid output: + Example for a valid output: Name: VSP-OK, Id: 9DB0E1563B22481D911ECD33989E1FDD, Vendor: ABC, locked by: None, status not started Service VSP-OK was tested and does not need a migration diff --git a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/DataValidatorFilter.java b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/DataValidatorFilter.java new file mode 100644 index 0000000000..a226faf0eb --- /dev/null +++ b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/DataValidatorFilter.java @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2022 Nordix Foundation. 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.webseal.simulator; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.openecomp.sdc.common.filters.DataValidatorFilterAbstract; +import org.openecomp.sdc.exception.NotAllowedSpecialCharsException; +import org.openecomp.sdc.webseal.simulator.conf.Conf; + +/** + * Implement DataValidatorFilter for webseal. + * Extends {@link DataValidatorFilterAbstract} + */ +public class DataValidatorFilter extends DataValidatorFilterAbstract { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException, NotAllowedSpecialCharsException { + try { + super.doFilter(request, response, chain); + } catch (final NotAllowedSpecialCharsException e) { + // error handing to show 'Error: Special characters not allowed.' + ((HttpServletResponse) response).sendError(400, ERROR_SPECIAL_CHARACTERS_NOT_ALLOWED); + } + } + + @Override + protected List<String> getDataValidatorFilterExcludedUrls() { + String dataValidatorFilterExcludedUrls = Conf.getInstance().getDataValidatorFilterExcludedUrls(); + if (StringUtils.isNotBlank(dataValidatorFilterExcludedUrls)) { + return Arrays.asList(dataValidatorFilterExcludedUrls.split(",")); + } + return new ArrayList<>(); + } +} diff --git a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java index 32d8c2916d..292f4a30d4 100644 --- a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java +++ b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java @@ -113,7 +113,7 @@ public class Login extends HttpServlet { } @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { String userId = request.getParameter("userId"); String password = request.getParameter("password"); diff --git a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java index 7aa48e62cf..e8c4631c65 100644 --- a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java +++ b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java @@ -7,9 +7,9 @@ * 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. @@ -20,126 +20,129 @@ package org.openecomp.sdc.webseal.simulator; -import org.apache.commons.io.IOUtils; -import org.openecomp.sdc.webseal.simulator.conf.Conf; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.*; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; +import org.openecomp.sdc.webseal.simulator.conf.Conf; public class RequestsClient extends HttpServlet { - private static final long serialVersionUID = 1L; - - @Override - protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { - - String adminId = request.getParameter("adminId") != null ? request.getParameter("adminId") : "jh0003"; - String createAll = request.getParameter("all"); - String url = Conf.getInstance().getFeHost() + "/sdc1/feProxy/rest/v1/user"; - - PrintWriter writer = response.getWriter(); - - int resultCode; - - if ("true".equals(createAll)) { - Map<String, User> users = Conf.getInstance().getUsers(); - for (User user : users.values()) { - resultCode = createUser(response, user.getUserId(), user.getRole().toUpperCase(), user.getFirstName(), user.getLastName(), user.getEmail(), url, adminId); - writer.println("User "+ user.getFirstName() + " " + user.getLastName() + getResultMessage(resultCode) + "<br>"); - } - } else { - String userId = request.getParameter("userId"); - String role = request.getParameter("role").toUpperCase(); - String firstName = request.getParameter("firstName"); - String lastName = request.getParameter("lastName"); - String email = request.getParameter("email"); - - resultCode = createUser(response, userId, role, firstName, lastName, email, url, adminId); - - writer.println("User "+ firstName + " " + lastName +getResultMessage(resultCode)); - } - - - - } - - private String getResultMessage(int resultCode){ - return 201 == resultCode? " created successfuly":" not created ("+ resultCode +")"; - } - - private int createUser(final HttpServletResponse response, String userId, String role, String firstName, String lastName, String email, String url, String adminId) throws IOException { - response.setContentType("text/html"); - - String body = "{\"firstName\":\"" + firstName + "\", \"lastName\":\"" + lastName + "\", \"userId\":\"" + userId + "\", \"email\":\"" + email + "\",\"role\":\"" + role + "\"}"; - - HashMap<String, String> headers = new HashMap<String, String>(); - headers.put("Content-Type", "application/json"); - headers.put("USER_ID", adminId); - return sendHttpPost(url, body, headers); - } - - private int sendHttpPost(String url, String body, Map<String, String> headers) throws IOException { - - String responseString = ""; - URL obj = new URL(url); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - - // add request method - con.setRequestMethod("POST"); - - // add request headers - if (headers != null) { - for (Entry<String, String> header : headers.entrySet()) { - String key = header.getKey(); - String value = header.getValue(); - con.setRequestProperty(key, value); - } - } - - // Send post request - if (body != null) { - con.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(con.getOutputStream()); - wr.writeBytes(body); - wr.flush(); - wr.close(); - } - - int responseCode = con.getResponseCode(); - // logger.debug("Send POST http request, url: {}", url); - // logger.debug("Response Code: {}", responseCode); - - StringBuilder response = new StringBuilder(); - try { - BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); - String inputLine; - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - } catch (Exception e) { - // logger.debug("response body is null"); - } - - String result; - - try { - result = IOUtils.toString(con.getErrorStream()); - response.append(result); - } catch (Exception e2) { - } - - con.disconnect(); - return responseCode; - - } + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException { + + String adminId = request.getParameter("adminId") != null ? request.getParameter("adminId") : "jh0003"; + String createAll = request.getParameter("all"); + String url = Conf.getInstance().getFeHost() + "/sdc1/feProxy/rest/v1/user"; + + PrintWriter writer = response.getWriter(); + + int resultCode; + + if ("true".equals(createAll)) { + Map<String, User> users = Conf.getInstance().getUsers(); + for (User user : users.values()) { + resultCode = createUser(response, user.getUserId(), user.getRole().toUpperCase(), user.getFirstName(), user.getLastName(), + user.getEmail(), url, adminId); + writer.println("User " + user.getFirstName() + " " + user.getLastName() + getResultMessage(resultCode) + "<br>"); + } + } else { + String userId = request.getParameter("userId"); + String role = request.getParameter("role").toUpperCase(); + String firstName = request.getParameter("firstName"); + String lastName = request.getParameter("lastName"); + String email = request.getParameter("email"); + + resultCode = createUser(response, userId, role, firstName, lastName, email, url, adminId); + + writer.println("User " + firstName + " " + lastName + getResultMessage(resultCode)); + } + + } + + private String getResultMessage(int resultCode) { + return 201 == resultCode ? " created successfuly" : " not created (" + resultCode + ")"; + } + + private int createUser(final HttpServletResponse response, String userId, String role, String firstName, String lastName, String email, + String url, String adminId) throws IOException { + response.setContentType("text/html"); + + String body = "{\"firstName\":\"" + firstName + "\", \"lastName\":\"" + lastName + "\", \"userId\":\"" + userId + "\", \"email\":\"" + email + + "\",\"role\":\"" + role + "\"}"; + + HashMap<String, String> headers = new HashMap<String, String>(); + headers.put("Content-Type", "application/json"); + headers.put("USER_ID", adminId); + return sendHttpPost(url, body, headers); + } + + private int sendHttpPost(String url, String body, Map<String, String> headers) throws IOException { + + String responseString = ""; + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + // add request method + con.setRequestMethod("POST"); + + // add request headers + if (headers != null) { + for (Entry<String, String> header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + } + + // Send post request + if (body != null) { + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.writeBytes(body); + wr.flush(); + wr.close(); + } + + int responseCode = con.getResponseCode(); + // logger.debug("Send POST http request, url: {}", url); + // logger.debug("Response Code: {}", responseCode); + + StringBuilder response = new StringBuilder(); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + // logger.debug("response body is null"); + } + + String result; + + try { + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + } catch (Exception e2) { + } + + con.disconnect(); + return responseCode; + + } } diff --git a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/conf/Conf.java b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/conf/Conf.java index eb498c975e..3ce7f23da7 100644 --- a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/conf/Conf.java +++ b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/conf/Conf.java @@ -39,6 +39,7 @@ public class Conf { private Map<String, User> users = new HashMap<String, User>(); private String portalCookieName; private String permittedAncestors; // Space separated list of permitted ancestors + private String dataValidatorFilterExcludedUrls; // Comma separated list of excluded URLs by the DataValidatorFilter private Conf() { initConf(); diff --git a/utils/webseal-simulator/src/main/webapp/WEB-INF/web.xml b/utils/webseal-simulator/src/main/webapp/WEB-INF/web.xml index c23e265aae..08a32221b0 100644 --- a/utils/webseal-simulator/src/main/webapp/WEB-INF/web.xml +++ b/utils/webseal-simulator/src/main/webapp/WEB-INF/web.xml @@ -39,6 +39,16 @@ </servlet-mapping> <filter> + <filter-name>dataValidatorFilter</filter-name> + <filter-class>org.openecomp.sdc.webseal.simulator.DataValidatorFilter</filter-class> + </filter> + <filter-mapping> + <filter-name>dataValidatorFilter</filter-name> + <url-pattern>/login</url-pattern> + <url-pattern>/create</url-pattern> + </filter-mapping> + + <filter> <filter-name>contentSecurityPolicyHeaderFilter</filter-name> <filter-class>org.openecomp.sdc.webseal.simulator.ContentSecurityPolicyHeaderFilter</filter-class> <async-supported>true</async-supported> |