diff options
Diffstat (limited to 'profiles/http/src/main')
26 files changed, 2333 insertions, 0 deletions
diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/auth/OnapCommandHttpAuthClient.java b/profiles/http/src/main/java/org/onap/cli/fw/http/auth/OnapCommandHttpAuthClient.java new file mode 100644 index 00000000..af02afdd --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/auth/OnapCommandHttpAuthClient.java @@ -0,0 +1,160 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.auth; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.cli.fw.cmd.OnapCommand; +import org.onap.cli.fw.conf.OnapCommandConfig; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.error.OnapCommandInvalidParameterValue; +import org.onap.cli.fw.http.cmd.OnapHttpCommand; +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; +import org.onap.cli.fw.http.connect.HttpInput; +import org.onap.cli.fw.http.connect.HttpResult; +import org.onap.cli.fw.http.connect.OnapHttpConnection; +import org.onap.cli.fw.http.error.OnapCommandHttpFailure; +import org.onap.cli.fw.http.schema.OnapCommandSchemaHttpLoader; +import org.onap.cli.fw.output.OnapCommandResultAttribute; +import org.onap.cli.fw.registrar.OnapCommandRegistrar; +import org.onap.cli.fw.utils.OnapCommandUtils; + +/** + * Oclip Auth client helps to do login and logout. + * + */ +public class OnapCommandHttpAuthClient { + + private OnapHttpCommand cmd = null; + + private OnapHttpConnection http = null; + + public OnapCommandHttpAuthClient(OnapHttpCommand cmd, boolean debug) throws OnapCommandHttpFailure, OnapCommandInvalidParameterValue { + this.cmd = cmd; + this.http = new OnapHttpConnection(debug); + } + + /** + * Login. + * + * @throws OnapCommandException + * exception + */ + public void login() throws OnapCommandException { + + // For development purpose, its introduced and is not supported for production + if (Boolean.parseBoolean(OnapCommandConfig.getPropertyValue(OnapCommandHttpConstants.OPEN_IGNORE_AUTH))) { + return; + } + + OnapCommand login = OnapCommandSchemaHttpLoader.findAuthCommand(this.cmd, "login"); + + OnapCommandUtils.copyParamsFrom(this.cmd, login); + login.execute(); + + //It is safely assumed that all outputs are considered as common http headers. + Map<String, String> headers = new HashMap<>(); + for (OnapCommandResultAttribute attr: login.getResult().getRecords()) { + String headerValue = attr.getValues().get(0); + if (headerValue != null && !headerValue.isEmpty()) { + headers.put(attr.getName(), attr.getValues().get(0)); + } + } + + this.http.setCommonHeaders(headers); + } + + /** + * Logout. + * + * @throws OnapCommandException + * exception + */ + public void logout() throws OnapCommandException { + // For development purpose, its introduced and is not supported for production + if (Boolean.parseBoolean(OnapCommandConfig.getPropertyValue(OnapCommandHttpConstants.OPEN_IGNORE_AUTH))) { + return; + } + + OnapCommand logout = OnapCommandSchemaHttpLoader.findAuthCommand(this.cmd, "logout"); + + OnapCommandUtils.copyParamsFrom(this.cmd, logout); + + logout.execute(); + + this.http.close(); + } + + /** + * Find given service base path. + * + * @throws OnapCommandException + * exception + */ + public String getServiceUrl() throws OnapCommandException { + return this.getServiceUrl(this.cmd); + } + + private String getServiceUrl(OnapHttpCommand cmd) throws OnapCommandException { + if (cmd.getService().isModeDirect()){ + return cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_HOST_URL).getValue().toString(); + } else { //Catalog mode + OnapCommand catalog = OnapCommandRegistrar.getRegistrar().get("catalog"); + + Map<String, String> paramsOverrides = new HashMap<>(); + paramsOverrides.put(OnapCommandHttpConstants.CATALOG_SERVICE_NAME, cmd.getService().getName()); + paramsOverrides.put(OnapCommandHttpConstants.CATALOG_SERVICE_VERSION, cmd.getService().getVersion()); + + OnapCommandUtils.copyParamsFrom(cmd, catalog, paramsOverrides); + + catalog.execute(); + + String hostUrl = catalog.getResult().getRecordsMap().get(OnapCommandHttpConstants.CATALOG_SERVICE_HOST_URL).getValues().get(0); + hostUrl = hostUrl.trim(); + if (hostUrl.endsWith("/")) { + hostUrl = hostUrl.substring(0, hostUrl.length()-1); + } + + String basePath = catalog.getResult().getRecordsMap().get(OnapCommandHttpConstants.CATALOG_SERVICE_BASE_PATH).getValues().get(0); + basePath = basePath.trim(); + if (basePath.startsWith("/")) { + basePath = basePath.substring(1); + } + + return hostUrl + "/" + basePath; + } + } + + + public String getDebugInfo() { + return this.http.getDebugInfo(); + } + + /** + * Http call to external service. + * + * @param input + * http input + * @return http result + * @throws OnapCommandHttpFailure + * exception + */ + public HttpResult run(HttpInput input) throws OnapCommandHttpFailure { + return this.http.request(input); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/auth/OnapCommandHttpService.java b/profiles/http/src/main/java/org/onap/cli/fw/http/auth/OnapCommandHttpService.java new file mode 100644 index 00000000..e2c8007d --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/auth/OnapCommandHttpService.java @@ -0,0 +1,101 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.auth; + +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; + +/** + * Oclip Service as reported in api catalog. + */ +public class OnapCommandHttpService { + /* + * Oclip Service name like aai. + */ + private String serviceName; + + /* + * Oclip Service API version like v1, v2, etc + */ + private String serviceVersion; + + private String basePath; + + /** + * Mode of service consideration. By default, it goes with + * 'catalog' mode, where basePath will be discovered by + * the framework using serviceName and serviceVersion + * Another mode is 'direct', in which bastPath will be + * same as OnapCredentails.ServiceUrl. + */ + private String mode = OnapCommandHttpConstants.MODE_DIRECT; + + private String authType = OnapCommandHttpConstants.AUTH_NONE; + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + this.mode = mode; + } + + public boolean isModeDirect() { + return this.getMode().equals(OnapCommandHttpConstants.MODE_DIRECT); + } + + public String getAuthType() { + return this.authType; + } + + public void setAuthType(String auth) { + this.authType = auth; + } + + public boolean isNoAuth() { + return this.authType.equalsIgnoreCase(OnapCommandHttpConstants.AUTH_NONE); + } + + public String getName() { + return serviceName; + } + + public void setName(String name) { + this.serviceName = name; + } + + public String getVersion() { + return serviceVersion; + } + + public void setVersion(String version) { + this.serviceVersion = version; + } + + public String getBasePath() { + return basePath; + } + + public void setBasePath(String basePath) { + this.basePath = basePath; + } + + @Override + public String toString() { + return this.getName() + " " + this.getVersion(); + } + +}
\ No newline at end of file diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/BasicAuthLoginCommand.java b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/BasicAuthLoginCommand.java new file mode 100644 index 00000000..afab750d --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/BasicAuthLoginCommand.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.cmd; + +import java.util.Map; + +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.impl.auth.BasicScheme; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; +import org.onap.cli.fw.input.OnapCommandParameter; +import org.onap.cli.fw.schema.OnapCommandSchema; + +@OnapCommandSchema(schema = "basic-login.yaml") +public class BasicAuthLoginCommand extends OnapHttpCommand { + + @Override + protected void run() throws OnapCommandException { + + //get the input arguments + Map<String, OnapCommandParameter> paramMap = getParametersMap(); + OnapCommandParameter usernameParam = paramMap.get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME); + String username = usernameParam.getValue().toString(); + OnapCommandParameter usernamePassword = paramMap.get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD); + String password = usernamePassword.getValue().toString(); + + //Execute the command to get token + String authToken = BasicScheme.authenticate(new UsernamePasswordCredentials( + username, password), "UTF-8", false).getValue(); + + //Fill out the result part + this.getResult().getRecordsMap().get(OnapCommandHttpConstants.AUTH_SERVICE_AUTHORIZATION).getValues().add(authToken); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/BasicAuthLogoutCommand.java b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/BasicAuthLogoutCommand.java new file mode 100644 index 00000000..6b54b3e0 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/BasicAuthLogoutCommand.java @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.cmd; + +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.schema.OnapCommandSchema; + +@OnapCommandSchema(schema = "basic-logout.yaml") +public class BasicAuthLogoutCommand extends OnapHttpCommand { + + @Override + protected void run() throws OnapCommandException { + //do nothing // NOSONAR + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/CatalogCommand.java b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/CatalogCommand.java new file mode 100644 index 00000000..2393fe82 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/CatalogCommand.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.cmd; + +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.schema.OnapCommandSchema; + +@OnapCommandSchema(schema = "catalog.yaml") +public class CatalogCommand extends OnapHttpCommand { + + @Override + protected void run() throws OnapCommandException { + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/OnapHttpCommand.java b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/OnapHttpCommand.java new file mode 100644 index 00000000..09ba7449 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/cmd/OnapHttpCommand.java @@ -0,0 +1,203 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.cmd; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.onap.cli.fw.cmd.OnapCommand; +import org.onap.cli.fw.cmd.OnapCommandType; +import org.onap.cli.fw.conf.OnapCommandConfig; +import org.onap.cli.fw.conf.OnapCommandConstants; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.error.OnapCommandExecutionFailed; +import org.onap.cli.fw.http.auth.OnapCommandHttpAuthClient; +import org.onap.cli.fw.http.auth.OnapCommandHttpService; +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; +import org.onap.cli.fw.http.connect.HttpInput; +import org.onap.cli.fw.http.connect.HttpResult; +import org.onap.cli.fw.http.error.OnapCommandFailedMocoGenerate; +import org.onap.cli.fw.http.schema.OnapCommandSchemaHttpLoader; +import org.onap.cli.fw.http.utils.OnapCommandHttpUtils; +import org.onap.cli.fw.output.OnapCommandResultAttribute; +import org.onap.cli.fw.schema.OnapCommandSchema; +import org.onap.cli.fw.utils.OnapCommandUtils; +import org.onap.cli.http.mock.MockJsonGenerator; +import org.onap.cli.http.mock.MockRequest; +import org.onap.cli.http.mock.MockResponse; + +/** + * Oclip http Command. + * + */ +@OnapCommandSchema(type = OnapCommandHttpConstants.HTTP_SCHEMA_PROFILE) +public class OnapHttpCommand extends OnapCommand { + + private HttpInput input = new HttpInput(); + + private List<Integer> successStatusCodes = new ArrayList<>(); + + private Map<String, String> resultMap = new HashMap<>(); + + protected OnapCommandHttpAuthClient authClient; + + private OnapCommandHttpService oclipService = new OnapCommandHttpService(); + + public void setInput(HttpInput input) { + this.input = input; + } + + @Override + public String getSchemaVersion() { + return OnapCommandConstants.OPEN_CLI_SCHEMA_VERSION_VALUE_1_0; + } + + public void setSuccessStatusCodes(List<Integer> successStatusCodes) { + this.successStatusCodes = successStatusCodes; + } + + public void setResultMap(Map<String, String> resultMap) { + this.resultMap = resultMap; + } + + public HttpInput getInput() { + return input; + } + + public List<Integer> getSuccessStatusCodes() { + return successStatusCodes; + } + + public Map<String, String> getResultMap() { + return resultMap; + } + + /* + * Oclip service, this command uses to execute it. + */ + public OnapCommandHttpService getService() { + return this.oclipService; + } + + public void setService(OnapCommandHttpService service) { + this.oclipService = service; + } + + @Override + protected List<String> initializeProfileSchema() throws OnapCommandException { + return OnapCommandSchemaHttpLoader.loadHttpSchema(this, this.getSchemaName(), true, false); + } + + @Override + protected void validate() throws OnapCommandException { + if (! this.isAuthRequired()) { + if (this.getParametersMap().containsKey(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME)) { + this.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setOptional(true); + } + if (this.getParametersMap().containsKey(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD)) { + this.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setOptional(true); + } + } + + super.validate(); + } + + private boolean isAuthRequired() { + return !this.getService().isNoAuth() + && "false".equals(this.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).getValue()) + && this.getInfo().getCommandType().equals(OnapCommandType.CMD); + } + + @Override + protected void run() throws OnapCommandException { + try { + // For auth/catalog type commands, login and logout logic is not required + boolean isAuthRequired = this.isAuthRequired(); + + this.authClient = new OnapCommandHttpAuthClient( + this, + this.getResult().isDebug()); + + if (isAuthRequired) { + this.authClient.login(); + } + + this.processRequest(); + + if (isAuthRequired) { + this.authClient.logout(); + } + + if (this.getResult().isDebug() && authClient != null) { + this.getResult().setDebugInfo(this.authClient.getDebugInfo()); + } + } catch (OnapCommandException e) { + if (this.getResult().isDebug() && authClient != null) { + this.getResult().setDebugInfo(this.authClient.getDebugInfo()); + } + throw e; + } + } + + protected void processRequest() throws OnapCommandException { + + HttpInput httpInput = OnapCommandHttpUtils.populateParameters(this.getParametersMap(), this.getInput()); + httpInput.setUri(this.authClient.getServiceUrl() + httpInput.getUri()); + + HttpResult output = this.authClient.run(httpInput); + + this.getResult().setOutput(output); + if (!this.getSuccessStatusCodes().contains(output.getStatus())) { + throw new OnapCommandExecutionFailed(this.getName(), output.getBody(), output.getStatus()); + } + + Map<String, ArrayList<String>> results = OnapCommandHttpUtils.populateOutputs(this.getResultMap(), output); + results = OnapCommandUtils.populateOutputsFromInputParameters(results, this.getParametersMap()); + + for (OnapCommandResultAttribute attr : this.getResult().getRecords()) { + attr.setValues(results.get(attr.getName())); + } + generateJsonMock(httpInput, output, this.getSchemaName()); + } + + private void generateJsonMock(HttpInput httpInput, HttpResult httpResult, String schemaName) + throws OnapCommandFailedMocoGenerate { + + if (Boolean.parseBoolean(OnapCommandConfig.getPropertyValue(OnapCommandConstants.SAMPLE_GEN_ENABLED))) { + try { + MockRequest mockRequest = new MockRequest(); + mockRequest.setMethod(httpInput.getMethod()); + mockRequest.setUri(httpInput.getUri()); + mockRequest.setHeaders(httpInput.getReqHeaders()); + mockRequest.setJson(httpInput.getBody()); + + MockResponse mockResponse = new MockResponse(); + mockResponse.setStatus(httpResult.getStatus()); + mockResponse.setJson(httpResult.getBody()); + + MockJsonGenerator.generateMocking(mockRequest, mockResponse, + OnapCommandConfig.getPropertyValue(OnapCommandConstants.SAMPLE_GEN_TARGET_FOLDER) + + "/" + schemaName.replace(".yaml", "") + "-moco.json"); + } catch (IOException error) { + throw new OnapCommandFailedMocoGenerate(schemaName, error); + } + } + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/conf/OnapCommandHttpConstants.java b/profiles/http/src/main/java/org/onap/cli/fw/http/conf/OnapCommandHttpConstants.java new file mode 100644 index 00000000..c33d2f27 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/conf/OnapCommandHttpConstants.java @@ -0,0 +1,90 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.conf; + +/** + * OnapCommandHttpConstants. + * + */ +public class OnapCommandHttpConstants { + public static final String CONF = "open-cli-http.properties"; + public static final String OPEN_IGNORE_AUTH = "cli.ignore_auth"; + public static final String HTTP_API_KEY_USE_COOKIES = "cli.http.api_key_use_cookies"; + public static final String HTTP_SECTIONS = "cli.schema.http_sections"; + public static final String HTTP_MANDATORY_SECTIONS = "cli.schema.http_mandatory_sections"; + public static final String HTTP_REQUEST_PARAMS = "cli.schema.http_request_params"; + public static final String HTTP_REQUEST_MANDATORY_PARAMS = "cli.schema.http_request_mandatory_params"; + public static final String HTTP_METHODS = "cli.schema.http_methods"; + //http connection + public static final String SSLCONTEST_TLS = "TLSV1.2"; + public static final String APPLICATION_JSON = "application/json"; + public static final String DEFAULT_PARAMETER_HTTP_FILE_NAME = "default_input_parameters_http.yaml"; + public static final String DEAFULT_PARAMETER_USERNAME = "host-username"; + public static final String DEAFULT_PARAMETER_PASSWORD = "host-password"; + public static final String DEAFULT_PARAMETER_HOST_URL = "host-url"; + public static final String DEFAULT_PARAMETER_NO_AUTH = "no-auth"; + public static final String HTTP_SCHEMA_PROFILE = "http"; + //http + public static final String HTTP = "http"; + public static final String METHOD = "method"; + public static final String SERVICE = "service"; + public static final String VERSION = "version"; + public static final String BASE_PATH = "base_path"; + public static final String AUTH = "auth"; + public static final String AUTH_NONE = "none"; + public static final String AUTH_BASIC = "basic"; + public static final String MODE = "mode"; + public static final String MODE_DIRECT = "direct"; + public static final String MODE_CATALOG = "catalog"; + public static final String REQUEST = "request"; + public static final String URI = "uri"; + public static final String BODY = "body"; + public static final String METHOD_TYPE = "method"; + public static final String POST = "post"; + public static final String GET = "get"; + public static final String DELETE = "delete"; + public static final String PUT = "put"; + public static final String HEAD = "delete"; + public static final String HEADERS = "headers"; + public static final String QUERIES = "queries"; + public static final String COOKIES = "cookies"; + public static final String SUCCESS_CODES = "success_codes"; + public static final String RESULT_MAP = "result_map"; + public static final String SAMPLE_RESPONSE = "sample_response"; + public static final String MULTIPART_ENTITY_NAME = "multipart_entity_name"; + public static final String HTTP_SECTION_EMPTY = "Http Section cann't be null or empty"; + public static final String HTTP_BODY_SECTION_EMPTY = "http body section under 'request:' cann't be null or empty"; + public static final String HTTP_BODY_FAILED_PARSING = "The http body json is failed to parse"; + public static final String HTTP_BODY_JSON_EMPTY = "The http body json cann't be null or empty"; + public static final String HTTP_SUCCESS_CODE_INVALID = "Invalid http success code."; + public static final String HTTP_SAMPLE_RESPONSE_EMPTY = "Sample response cann't be null or empty"; + public static final String HTTP_SAMPLE_RESPONSE_FAILED_PARSING = "The http Sample response json is failed to parse."; + //auth plugin + public static final String AUTH_SERVICE_AUTHORIZATION = "Authorization"; + //catalog plugin + public static final String CATALOG_SERVICE_NAME = "catalog-service-name"; + public static final String CATALOG_SERVICE_VERSION = "catalog-service-version"; + public static final String CATALOG_SERVICE_BASE_PATH = "catalog-service-base-path"; + public static final String CATALOG_SERVICE_HOST_URL = "catalog-service-host-url"; + + public static final String AUTH_VALUES = "cli.schema.auth_values"; + public static final String MODE_VALUES = "cli.schema.mode_values"; + public static final String SERVICE_PARAMS_LIST = "cli.schema.service_params_list"; + public static final String SERVICE_PARAMS_MANDATORY_LIST = "cli.schema.service_params_mandatory_list"; +} + + diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/connect/HttpInput.java b/profiles/http/src/main/java/org/onap/cli/fw/http/connect/HttpInput.java new file mode 100644 index 00000000..722dd12e --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/connect/HttpInput.java @@ -0,0 +1,139 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.connect; + +import java.util.HashMap; +import java.util.Map; + +/** + * Captures HTTP request URI, body and request &query parameters. <br> + */ +public class HttpInput { + + private String reqUri = ""; + + private String reqBody = ""; + + private String reqMethod = ""; + + private String multipartEntityName = ""; + + private Map<String, String> reqHeaders = new HashMap<>(); + + private Map<String, String> reqQueries = new HashMap<>(); + + private Map<String, String> reqCookies = new HashMap<>(); + + private boolean binaryData; + + public String getUri() { + return this.reqUri; + } + + public HttpInput setUri(String uri) { + this.reqUri = uri; + return this; + } + + public String getBody() { + return this.reqBody; + } + + public HttpInput setBody(String body) { + this.reqBody = body; + return this; + } + + public Map<String, String> getReqHeaders() { + return this.reqHeaders; + } + + /** + * header parameter setter. + * + * @param reqHeaders + * header map + * @return HttpInput + */ + public HttpInput setReqHeaders(Map<String, String> reqHeaders) { + if (reqHeaders != null) { + this.reqHeaders = reqHeaders; + } + return this; + } + + public String getMethod() { + return this.reqMethod; + } + + public HttpInput setMethod(String method) { + this.reqMethod = method; + return this; + } + + public String getMultipartEntityName() { + return this.multipartEntityName; + } + + public HttpInput setMultipartEntityName(String multipartEntityName) { + this.multipartEntityName = multipartEntityName; + return this; + } + + public Map<String, String> getReqQueries() { + return reqQueries; + } + + /** + * Request query parameters. + * + * @param reqQueries + * request queries + * @return HttpInput + */ + public HttpInput setReqQueries(Map<String, String> reqQueries) { + if (reqQueries != null) { + this.reqQueries = reqQueries; + } + return this; + } + + public Map<String, String> getReqCookies() { + return reqCookies; + } + + public HttpInput setReqCookies(Map<String, String> reqCookies) { + this.reqCookies = reqCookies; + return this; + } + + public boolean isBinaryData() { + return binaryData; + } + + public void setBinaryData(boolean binaryData) { + this.binaryData = binaryData; + } + + @Override + public String toString() { + return "\nURL: " + this.getUri() + "\nMethod: " + this.getMethod() + "\nRequest Queries: " + + this.getReqQueries() + "\nRequest Body: " + this.getBody() + "\nRequest Headers: " + + this.getReqHeaders().toString() + "\nRequest Cookies: " + this.getReqCookies().toString() + + "\nbinaryData=" + this.binaryData; + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/connect/HttpResult.java b/profiles/http/src/main/java/org/onap/cli/fw/http/connect/HttpResult.java new file mode 100644 index 00000000..42c636c0 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/connect/HttpResult.java @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.connect; + +import java.util.HashMap; +import java.util.Map; + +/** + * Captures HTTP response status, body and headers. <br> + * + */ +public class HttpResult { + + private int status; + + private String resBody; + + private Map<String, String> respHeaders = new HashMap<>(); + + private Map<String, String> respCookies = new HashMap<>(); + + public int getStatus() { + return this.status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getBody() { + return this.resBody; + } + + public void setBody(String body) { + this.resBody = body; + } + + public void setRespHeaders(Map<String, String> respHeaders) { + this.respHeaders = respHeaders; + } + + public Map<String, String> getRespHeaders() { + return this.respHeaders; + } + + public Map<String, String> getRespCookies() { + return respCookies; + } + + public void setRespCookies(Map<String, String> respCookies) { + this.respCookies = respCookies; + } + + public boolean isSuccess() { + return this.getStatus() >= 200 && this.getStatus() <= 300; + } + + @Override + public String toString() { + return "\nHTTP Status: " + this.getStatus() + "\nResponse Body: " + this.getBody() + "\nResponse Headers: " + + this.getRespHeaders() + "\nResponse Cookies: " + this.getRespCookies(); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/connect/OnapHttpConnection.java b/profiles/http/src/main/java/org/onap/cli/fw/http/connect/OnapHttpConnection.java new file mode 100644 index 00000000..a5a75e11 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/connect/OnapHttpConnection.java @@ -0,0 +1,349 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.connect; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.ParseException; +import org.apache.http.client.CookieStore; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.protocol.ClientContext; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.ssl.AllowAllHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.X509HostnameVerifier; +import org.apache.http.cookie.Cookie; +import org.apache.http.entity.StringEntity; +import org.apache.http.entity.mime.MultipartEntity; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.LaxRedirectStrategy; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.impl.cookie.BasicClientCookie; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.apache.http.util.EntityUtils; +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; +import org.onap.cli.fw.http.error.OnapCommandHttpFailure; + +/** + * Helps to make http connection.<br> + */ +public class OnapHttpConnection { + + private HttpClient httpClient = null; + + Map<String, String> mapCommonHeaders = new HashMap<String, String> (); + + protected boolean debug = false; + + private String debugDetails = ""; + + public static class TrustAllX509TrustManager implements X509TrustManager { + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + // No need to implement. + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + // No need to implement. + } + } + + /** + * OnapHttpConnection Constructor. + * + * @param debug + * boolean + * @throws OnapCommandHttpFailure + * exception + */ + public OnapHttpConnection(boolean debug) throws OnapCommandHttpFailure { + this.debug = debug; + } + + private void initHttpClient(boolean isSecured) throws OnapCommandHttpFailure { + if (this.httpClient == null) { + try { + if (isSecured) { + SSLContext sslContext = SSLContext.getInstance(OnapCommandHttpConstants.SSLCONTEST_TLS); + sslContext.init(null, new TrustManager[] { new TrustAllX509TrustManager() }, + new java.security.SecureRandom()); + X509HostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier(); + Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder + .<ConnectionSocketFactory>create() + .register("https", new SSLConnectionSocketFactory(sslContext, hostnameVerifier)).build(); + HttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + + this.httpClient = HttpClients.custom().setConnectionManager(connManager) + .setRedirectStrategy(new LaxRedirectStrategy()).build(); + } else { + this.httpClient = HttpClients.createDefault(); + } + } catch (Exception e) { + throw new OnapCommandHttpFailure(e); + } + } + } + + public String getDebugInfo() { + return this.debugDetails; + } + + private Map<String, String> getHttpHeaders(HttpResponse resp) { + Map<String, String> result = new HashMap<>(); + + Header[] hs = resp.getAllHeaders(); + for (int i = 0; i < hs.length; i++) { + result.put(hs[i].getName(), hs[i].getValue()); + } + + return result; + } + + private String getResponseBody(HttpResponse resp) throws OnapCommandHttpFailure { + if (resp.getEntity() == null) { + return null; + } + try { + String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); + EntityUtils.consume(resp.getEntity()); + return body; + } catch (IOException e) { + throw new OnapCommandHttpFailure(e); + } + } + + private StringEntity getStringEntity(HttpInput input) { + return new StringEntity(input.getBody(), StandardCharsets.UTF_8); + } + + /** + * Post. <br> + * + * @param input + * HttpInput Obj + * @return HttpResult + * @throws OnapCommandHttpFailure + * http failure + */ + public HttpResult post(final HttpInput input) throws OnapCommandHttpFailure { + input.setMethod("post"); + return this.request(input); + } + + /** + * Get. <br> + * + * @param input + * input request + * @return HttpResult + * @throws OnapCommandHttpFailure + * excpetion + */ + public HttpResult get(final HttpInput input) throws OnapCommandHttpFailure { + input.setMethod("get"); + return this.request(input); + } + + /** + * Put. <br> + * + * @param input + * input request + * @return HttpResult + * @throws OnapCommandHttpFailure + * Exception + */ + public HttpResult put(final HttpInput input) throws OnapCommandHttpFailure { + input.setMethod("put"); + return this.request(input); + } + + /** + * Delete. <br> + * + * @param input + * input request + * @return HttpResult + * @throws OnapCommandHttpFailure + * exception + */ + public HttpResult delete(final HttpInput input) throws OnapCommandHttpFailure { + input.setMethod("delete"); + return this.request(input); + } + + public void setCommonHeaders(Map<String, String> headers) { + this.mapCommonHeaders = headers; + } + + private void addCommonHeaders(HttpInput input) { + if (!input.isBinaryData()) { + input.getReqHeaders().put("Content-Type", OnapCommandHttpConstants.APPLICATION_JSON); + } + input.getReqHeaders().put("Accept", OnapCommandHttpConstants.APPLICATION_JSON); + + for (String headerName : this.mapCommonHeaders.keySet()) { + input.getReqHeaders().put(headerName, this.mapCommonHeaders.get(headerName)); + } + } + + private void addCommonCookies(CookieStore cookieStore) { + for (String headerName : this.mapCommonHeaders.keySet()) { + Cookie cookie = new BasicClientCookie(headerName, this.mapCommonHeaders.get(headerName)); + cookieStore.addCookie(cookie); + } + } + + private void updateResultFromCookies(HttpResult result, List<Cookie> cookies) { + for (Cookie cookie : cookies) { + result.getRespCookies().put(cookie.getName(), cookie.getValue()); + } + } + + private String getDomain(String url) { + try { + return new URL(url).getHost(); + } catch (MalformedURLException e) { + // url is always proper !! + return url; + } + } + + private void updateInputFromCookies(HttpInput input, CookieStore cookieStore) { + addCommonCookies(cookieStore); + for (String cookieName : input.getReqCookies().keySet()) { + BasicClientCookie cookie = new BasicClientCookie(cookieName, input.getReqCookies().get(cookieName)); + cookie.setDomain(this.getDomain(input.getUri())); + cookieStore.addCookie(cookie); + } + + } + + /** + * Handles http method requests. + * + * @param input + * HttpInput + * @return HttpResult + * @throws OnapCommandHttpFailure + * exception + */ + public HttpResult request(HttpInput input) throws OnapCommandHttpFailure { + this.addCommonHeaders(input); + + HttpRequestBase requestBase = null; + if ("post".equals(input.getMethod())) { + HttpPost httpPost = new HttpPost(); + if (input.isBinaryData()) { + httpPost.setEntity(getMultipartEntity(input)); + } else { + httpPost.setEntity(this.getStringEntity(input)); + } + requestBase = httpPost; + } else if ("put".equals(input.getMethod())) { + HttpPut httpPut = new HttpPut(); + httpPut.setEntity(this.getStringEntity(input)); + requestBase = httpPut; + } else if ("get".equals(input.getMethod())) { + requestBase = new HttpGet(); + } else if ("delete".equals(input.getMethod())) { + requestBase = new HttpDelete(); + } else { + throw new IllegalArgumentException("Invalid HTTP method"); + } + + requestBase.setURI(URI.create(input.getUri())); + + for (Entry<String, String> h : input.getReqHeaders().entrySet()) { + requestBase.addHeader(h.getKey(), h.getValue()); + } + + HttpResult result = new HttpResult(); + + try { + this.debugDetails = ""; + CookieStore cookieStore = new BasicCookieStore(); + updateInputFromCookies(input, cookieStore); + HttpContext localContext = new BasicHttpContext(); + localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); + + this.initHttpClient(input.getUri().startsWith("https")); + + HttpResponse resp = this.httpClient.execute(requestBase, localContext); + String respContent = this.getResponseBody(resp); + result.setBody(respContent); + result.setStatus(resp.getStatusLine().getStatusCode()); + result.setRespHeaders(this.getHttpHeaders(resp)); + this.updateResultFromCookies(result, cookieStore.getCookies()); + } catch (ParseException | IOException e) { + throw new OnapCommandHttpFailure(e); + } finally { + if (this.debug) { + this.debugDetails = input + "" + result; + } + } + + return result; + } + + public void close() { + this.mapCommonHeaders.clear(); + } + + private HttpEntity getMultipartEntity(HttpInput input) { + FileBody fileBody = new FileBody(new File(input.getBody().trim())); + MultipartEntity multipartEntity = new MultipartEntity(); + String fileName = input.getMultipartEntityName() != "" ? input.getMultipartEntityName() : "upload"; + multipartEntity.addPart(fileName, fileBody); + return multipartEntity; + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandFailedMocoGenerate.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandFailedMocoGenerate.java new file mode 100644 index 00000000..12a645c4 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandFailedMocoGenerate.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * Invalid data for generating moco json . + * + */ +public class OnapCommandFailedMocoGenerate extends OnapCommandException { + + private static final long serialVersionUID = -5386652726982792831L; + + private static final String ERROR_CODE = "0xf002"; + + private static final String ERROR_MSG = "Failed to generate moco json "; + + public OnapCommandFailedMocoGenerate(String cmdName, String error) { + super(ERROR_CODE, ERROR_MSG + cmdName + ", " + error); + } + + public OnapCommandFailedMocoGenerate(String cmdName, Throwable throwable) { + super(ERROR_CODE, ERROR_MSG + cmdName , throwable); + } + +}
\ No newline at end of file diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpFailure.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpFailure.java new file mode 100644 index 00000000..f40ebf45 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpFailure.java @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * Command execution failed. + * + */ +public class OnapCommandHttpFailure extends OnapCommandException { + private static final long serialVersionUID = 488775545436993345L; + + private static final String ERROR_CODE = "0x3001"; + + public OnapCommandHttpFailure(String error, long httpStatus) { + super(ERROR_CODE, error, httpStatus); + } + + public OnapCommandHttpFailure(String error) { + super(ERROR_CODE, error); + } + + public OnapCommandHttpFailure(Throwable throwable) { + super(ERROR_CODE, throwable); + } + + public OnapCommandHttpFailure(Throwable throwable, long httpStatus) { + super(ERROR_CODE, throwable, httpStatus); + } + +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpHeaderNotFound.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpHeaderNotFound.java new file mode 100644 index 00000000..27330fcb --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpHeaderNotFound.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * OnapCommandParameterNotFound. + * + */ +public class OnapCommandHttpHeaderNotFound extends OnapCommandException { + + private static final long serialVersionUID = 6676137916079057963L; + + public OnapCommandHttpHeaderNotFound(String name) { + super("0x3003", "Http header " + name + " is not returned from the service"); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpInvalidResponseBody.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpInvalidResponseBody.java new file mode 100644 index 00000000..90527250 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpInvalidResponseBody.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * OnapCommandParameterNotFound. + * + */ +public class OnapCommandHttpInvalidResponseBody extends OnapCommandException { + + private static final long serialVersionUID = 6676137916079057963L; + + private static final String ERROR_CODE = "0x3004"; + private static final String ERR_MSG = "Http response body does not have json entry "; + + public OnapCommandHttpInvalidResponseBody(String name, String error) { + super(ERROR_CODE, ERR_MSG + name + ", " + error); + } + + public OnapCommandHttpInvalidResponseBody(String name, Throwable throwable) { + super(ERROR_CODE, ERR_MSG + name, throwable); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpInvalidResultMap.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpInvalidResultMap.java new file mode 100644 index 00000000..ae1a113f --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandHttpInvalidResultMap.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import java.util.List; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * Invalid result map in HTTP section. + * + */ +public class OnapCommandHttpInvalidResultMap extends OnapCommandException { + + private static final long serialVersionUID = 6676137916023457963L; + + public OnapCommandHttpInvalidResultMap(List<String> invalidParams) { + super("0x3005", "Invalide result map parameters : " + invalidParams.toString()); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandLoginFailed.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandLoginFailed.java new file mode 100644 index 00000000..0701dbf2 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandLoginFailed.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * Login failed. + * + */ +public class OnapCommandLoginFailed extends OnapCommandException { + + private static final long serialVersionUID = 5518154493762956959L; + + private static final String ERROR_CODE = "0x4001"; + private static final String ERROR_MESSAGE1 = "Login failed"; + + public OnapCommandLoginFailed(String error) { + super(ERROR_CODE, ERROR_MESSAGE1 + ", " + error); + } + + public OnapCommandLoginFailed(String error, int httpStatus) { + super(ERROR_CODE, ERROR_MESSAGE1 + ", " + error, httpStatus); + } + + public OnapCommandLoginFailed(Throwable throwable) { + super(ERROR_CODE, ERROR_MESSAGE1, throwable); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandLogoutFailed.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandLogoutFailed.java new file mode 100644 index 00000000..53a58a25 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandLogoutFailed.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * Logout failed. + * + */ +public class OnapCommandLogoutFailed extends OnapCommandException { + + private static final long serialVersionUID = 1150649507734289032L; + private static final String ERROR_CODE = "0x4002"; + private static final String ERROR_MESSAGE1 = "Logout failed"; + + public OnapCommandLogoutFailed(String error) { + super(ERROR_CODE, ERROR_MESSAGE1 +", " + error); + } + + public OnapCommandLogoutFailed(Throwable throwable) { + super(ERROR_CODE, ERROR_MESSAGE1, throwable); + } + + public OnapCommandLogoutFailed(int statusCode) { + super(ERROR_CODE, ERROR_MESSAGE1, statusCode); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandServiceNotFound.java b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandServiceNotFound.java new file mode 100644 index 00000000..30833019 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/error/OnapCommandServiceNotFound.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import org.onap.cli.fw.error.OnapCommandException; + +/** + * Command not registered in MSB. + * + */ +public class OnapCommandServiceNotFound extends OnapCommandException { + + private static final long serialVersionUID = 8580121615330415065L; + + public OnapCommandServiceNotFound(String service) { + super("0xd001", "Service " + service + " is not found in MSB"); + } +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/schema/OnapCommandSchemaHttpLoader.java b/profiles/http/src/main/java/org/onap/cli/fw/http/schema/OnapCommandSchemaHttpLoader.java new file mode 100644 index 00000000..a7424732 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/schema/OnapCommandSchemaHttpLoader.java @@ -0,0 +1,427 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.schema; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import org.onap.cli.fw.cmd.OnapCommand; +import org.onap.cli.fw.conf.OnapCommandConfig; +import org.onap.cli.fw.conf.OnapCommandConstants; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.error.OnapCommandInvalidSchema; +import org.onap.cli.fw.error.OnapCommandNotFound; +import org.onap.cli.fw.http.auth.OnapCommandHttpService; +import org.onap.cli.fw.http.cmd.OnapHttpCommand; +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; +import org.onap.cli.fw.http.error.OnapCommandHttpInvalidResultMap; +import org.onap.cli.fw.registrar.OnapCommandRegistrar; +import org.onap.cli.fw.schema.OnapCommandSchemaLoader; +import org.onap.cli.fw.utils.OnapCommandUtils; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import net.minidev.json.JSONObject; + +public class OnapCommandSchemaHttpLoader { + + public static List<String> loadHttpSchema(OnapHttpCommand cmd, String schemaName, boolean includeDefault, + boolean validateSchema) throws OnapCommandException { + try { + List<String> errors = new ArrayList<>(); + if (includeDefault) { + Map<String, ?> defaultParameterMap = includeDefault ? + OnapCommandSchemaLoader.validateSchemaVersion(OnapCommandHttpConstants.DEFAULT_PARAMETER_HTTP_FILE_NAME, cmd.getSchemaVersion()) : new HashMap<>(); + + //mrkanag default_parameter is supported only for parameters. + if (defaultParameterMap.containsKey(OnapCommandConstants.INFO)) { + defaultParameterMap.remove(OnapCommandConstants.INFO); + } + + errors.addAll(OnapCommandSchemaLoader.parseSchema(cmd, defaultParameterMap, validateSchema)); + } + + Map<String, List<Map<String, String>>> commandYamlMap = + (Map<String, List<Map<String, String>>>)OnapCommandSchemaLoader.validateSchemaVersion(schemaName, cmd.getSchemaVersion()); + + errors.addAll(parseHttpSchema(cmd, commandYamlMap, validateSchema)); + + return errors; + + } catch (OnapCommandException e) { + throw e; + } catch (Exception e) { + throw new OnapCommandInvalidSchema(schemaName, e); + } + } + + /** + * Load the schema. + * + * @param cmd + * OnapHttpCommand + * @param schemaName + * schema name + * @throws OnapCommandException + * on error + */ + static ArrayList<String> parseHttpSchema(OnapHttpCommand cmd, + final Map<String, ?> values, + boolean validate) throws OnapCommandException { + ArrayList<String> errorList = new ArrayList<>(); + try { + Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP); + + if (valMap != null) { + if (validate) { + OnapCommandUtils.validateTags(errorList, valMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_SECTIONS), + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_MANDATORY_SECTIONS), OnapCommandConstants.PARAMETERS); + errorList.addAll(validateHttpSchemaSection(values)); + } + for (Map.Entry<String, ?> entry1 : valMap.entrySet()) { + String key1 = entry1.getKey(); + + switch (key1) { + case OnapCommandHttpConstants.REQUEST: + Map<String, ?> map = (Map<String, ?>) valMap.get(key1); + + for (Map.Entry<String, ?> entry2 : map.entrySet()) { + try { + String key2 = entry2.getKey(); + + switch (key2) { + case OnapCommandHttpConstants.URI: + Object obj = map.get(key2); + cmd.getInput().setUri(obj.toString()); + break; + case OnapCommandHttpConstants.METHOD_TYPE: + Object method = map.get(key2); + cmd.getInput().setMethod(method.toString()); + break; + case OnapCommandHttpConstants.BODY: + Object body = map.get(key2); + cmd.getInput().setBody(body.toString()); + break; + case OnapCommandHttpConstants.HEADERS: + Map<String, String> head = (Map<String, String>) map.get(key2); + cmd.getInput().setReqHeaders(head); + break; + case OnapCommandHttpConstants.QUERIES: + Map<String, String> query = (Map<String, String>) map.get(key2); + + cmd.getInput().setReqQueries(query); + break; + case OnapCommandHttpConstants.MULTIPART_ENTITY_NAME: + Object multipartEntityName = map.get(key2); + cmd.getInput().setMultipartEntityName(multipartEntityName.toString()); + break; + } + }catch (Exception ex) { + OnapCommandUtils.throwOrCollect(new OnapCommandInvalidSchema(cmd.getSchemaName(), ex), errorList, validate); + } + } + break; + + case OnapCommandHttpConstants.SERVICE: + Map<String, String> serviceMap = (Map<String, String>) valMap.get(key1); + + if (serviceMap != null) { + if (validate) { + OnapCommandUtils.validateTags(errorList, (Map<String, Object>) valMap.get(key1), + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_LIST), + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_MANDATORY_LIST), OnapCommandHttpConstants.SERVICE); + + HashMap<String, String> validationMap = new HashMap<>(); + validationMap.put(OnapCommandHttpConstants.AUTH, OnapCommandHttpConstants.AUTH_VALUES); + validationMap.put(OnapCommandHttpConstants.MODE, OnapCommandHttpConstants.MODE_VALUES); + + for (String secKey : validationMap.keySet()) { + if (serviceMap.containsKey(secKey)) { + Object obj = serviceMap.get(secKey); + if (obj == null) { + errorList.add("Attribute '" + secKey + "' under '" + OnapCommandHttpConstants.SERVICE + "' is empty"); + } else { + String value = String.valueOf(obj); + if (!OnapCommandConfig.getCommaSeparatedList(validationMap.get(secKey)).contains(value)) { + errorList.add("Attribute '" + secKey + "' contains invalid value. Valide values are " + + OnapCommandConfig.getCommaSeparatedList(validationMap.get(key1))); // + } + } + } + } + } + + OnapCommandHttpService srv = new OnapCommandHttpService(); + + for (Map.Entry<String, String> entry : serviceMap.entrySet()) { + String key = entry.getKey(); + + switch (key) { + case OnapCommandConstants.NAME: + srv.setName(serviceMap.get(key)); + break; + + case OnapCommandHttpConstants.VERSION: + srv.setVersion(serviceMap.get(key).toString()); + break; + + case OnapCommandHttpConstants.AUTH: + Object obj = serviceMap.get(key); + srv.setAuthType(obj.toString()); + + //On None type, username, password and no_auth are invalid + if (srv.isNoAuth()) { + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setInclude(false); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setInclude(false); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).setInclude(false); + } + break; + + //mrkanag: from auth command, add the parameters to the command's parameters list + + case OnapCommandHttpConstants.MODE: + Object mode = serviceMap.get(key); + srv.setMode(mode.toString()); + break; + } + } + cmd.setService(srv); + } + break; + + case OnapCommandHttpConstants.SUCCESS_CODES: + if (validate) { + validateHttpSccessCodes(errorList, (List<Object>) valMap.get(key1)); + } + cmd.setSuccessStatusCodes((ArrayList) valMap.get(key1)); + break; + + case OnapCommandHttpConstants.RESULT_MAP: + if (validate) { + validateHttpResultMap(errorList, values); + } + cmd.setResultMap((Map<String, String>) valMap.get(key1)); + break; + + case OnapCommandHttpConstants.SAMPLE_RESPONSE: + // (mrkanag) implement sample response handling + break; + } + } + } + }catch (OnapCommandException e) { + OnapCommandUtils.throwOrCollect(e, errorList, validate); + } + + //Handle the parameters for auth + if (!cmd.getService().isNoAuth()) { + OnapCommand login = OnapCommandSchemaHttpLoader.findAuthCommand(cmd, "login"); + OnapCommandUtils.copyParamSchemasFrom(login, cmd); + } + + return errorList; + } + + public static ArrayList<String> validateHttpSchemaSection(Map<String, ?> values) { + ArrayList<String> errorList = new ArrayList<>(); + Map<String, ?> map = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP); + Map<String, Object> requestMap = (Map<String, Object>) map.get(OnapCommandHttpConstants.REQUEST); + + if (requestMap != null && !requestMap.isEmpty()) { + OnapCommandUtils.validateTags(errorList, requestMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_PARAMS), + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_MANDATORY_PARAMS), OnapCommandHttpConstants.REQUEST); + String method = (String) requestMap.get(OnapCommandHttpConstants.METHOD); + if (method != null && !method.isEmpty()) { + if (!OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).contains(method.toLowerCase())) { + errorList.add("Attribute '" + OnapCommandHttpConstants.METHOD + "' under '" + OnapCommandHttpConstants.REQUEST + "' is invalid, correct types are " + + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).toString()); + } + } else { + errorList.add("Http request method cann't be null or empty"); + } + + Set<String> requestParams = getRequestParams(values); + + Set<String> uriParams = validateHttpUri(errorList, requestMap); + + Set<String> bodyParams = validateHttpBody(errorList, requestMap); + + Set<String> headerParams = validateHttpHeaders(requestMap); + + Set<String> queryParams = validateHttpQueries(requestMap); + + HashSet<String> totoalParams = new HashSet<>(uriParams); + totoalParams.addAll(bodyParams); + totoalParams.addAll(headerParams); + totoalParams.addAll(queryParams); + + List<String> nonDeclaredParams = totoalParams.stream().filter(param -> !requestParams.contains(param)) + .collect(Collectors.toList()); + + nonDeclaredParams.stream().forEach(p -> errorList.add("The parameter '" + p + + "' declared under 'parameters:' section is not mapped into request section.")); + } else { + errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.REQUEST)); + } + return errorList; + } + + public static void validateHttpSccessCodes(List<String> errorList, List<Object> requestSuccessCodes) { + + if (requestSuccessCodes == null || requestSuccessCodes.isEmpty()) { + errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID); + return; + } + + for (Object successCode : requestSuccessCodes) { + Integer code = (Integer) successCode; + if (code < 200 || code >= 300) { + if ( code != 404) { + errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID); + } + } + } + + } + + public static void validateHttpResultMap(List<String> errorList, Map<String, ?> values) throws OnapCommandException { + Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP); + List<Map<String, String>> attributes = (List<Map<String, String>>) ((Map<String, ?>)values.get(OnapCommandConstants.RESULTS)).get(OnapCommandConstants.ATTRIBUTES); + Set<String> resultMapParams = ((Map<String, String>) valMap.get(OnapCommandHttpConstants.RESULT_MAP)).keySet(); + + Set<String> resultAttNames = attributes.stream().map(map -> map.get(OnapCommandConstants.NAME)) + .collect(Collectors.toSet()); + + List<String> invaliResultMapParams = resultMapParams.stream() + .filter(p -> !resultAttNames.contains(p)).collect(Collectors.toList()); + + if (!invaliResultMapParams.isEmpty()) { + OnapCommandUtils.throwOrCollect(new OnapCommandHttpInvalidResultMap(invaliResultMapParams), errorList, true); + } + } + + public static Set<String> validateHttpQueries(Map<String, Object> requestMap) { + Map<String, Object> queries = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.QUERIES); + Set<String> queryParamNames = new HashSet<>(); + if (queries != null) { + for (Entry<String, Object> entry : queries.entrySet()) { + OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), queryParamNames); + } + } + return queryParamNames; + } + + public static Set<String> validateHttpHeaders(Map<String, Object> requestMap) { + + Map<String, Object> headers = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.HEADERS); + Set<String> headerParamNames = new HashSet<>(); + if (headers != null) { + for (Entry<String, Object> entry : headers.entrySet()) { + OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), headerParamNames); + } + } + return headerParamNames; + } + + public static Set<String> validateHttpBody(List<String> errorList, Map<String, Object> requestMap) { + Set<String> bodyParamNames = new HashSet<>(); + Object bodyString = requestMap.get(OnapCommandHttpConstants.BODY); + if (bodyString == null) { + return bodyParamNames; + } + + String body = String.valueOf(bodyString); + JSONObject obj = null; + try { + obj = new ObjectMapper().readValue(body, JSONObject.class); + } catch (IOException e1) { // NOSONAR + errorList.add(OnapCommandHttpConstants.HTTP_BODY_FAILED_PARSING); + } + if (obj == null || "".equals(obj.toString())) { + errorList.add(OnapCommandHttpConstants.HTTP_BODY_JSON_EMPTY); + } + OnapCommandUtils.parseParameters(body, bodyParamNames); + + return bodyParamNames; + } + + public static Set<String> validateHttpUri(List<String> errorList, Map<String, Object> requestMap) { + Set<String> uriParamNames = new HashSet<>(); + String uri = (String) requestMap.get(OnapCommandHttpConstants.URI); + if (uri == null || uri.isEmpty()) { + errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.URI)); + return uriParamNames; + } + OnapCommandUtils.parseParameters(uri, uriParamNames); + return uriParamNames; + } + + public static Set<String> getRequestParams(Map<String, ?> yamlMap) { + + Set<String> set = new HashSet<>(); + + @SuppressWarnings("unchecked") + List<Map<String, Object>> inputParams = (List<Map<String, Object>>) yamlMap.get(OnapCommandConstants.PARAMETERS); + + if (inputParams != null) { + for (Map<String, Object> map : inputParams) { + for (Entry<String, Object> entry : map.entrySet()) { + Object key = entry.getKey(); + + if (OnapCommandConstants.NAME.equals(key)) { + set.add(String.valueOf(entry.getValue())); + break; + } + } + } + } + + return set; + } + + /** + * + * @param authAction login/logout + * @return + * @throws OnapCommandException + */ + public static OnapCommand findAuthCommand(OnapHttpCommand forCmd, String authAction) throws OnapCommandException { + OnapCommand auth = null; + try { + //mrkanag: fix this to discover the auth command by matching info->product & service + auth = OnapCommandRegistrar.getRegistrar().get( + forCmd.getInfo().getService() + "-" + + forCmd.getService().getAuthType() + "-" + authAction, + forCmd.getInfo().getProduct()); + } catch (OnapCommandNotFound e) { + auth = OnapCommandRegistrar.getRegistrar().get( + forCmd.getService().getAuthType() + "-" + authAction, + forCmd.getInfo().getProduct()); + } + + return auth; + } + + +} diff --git a/profiles/http/src/main/java/org/onap/cli/fw/http/utils/OnapCommandHttpUtils.java b/profiles/http/src/main/java/org/onap/cli/fw/http/utils/OnapCommandHttpUtils.java new file mode 100644 index 00000000..e4d2cf06 --- /dev/null +++ b/profiles/http/src/main/java/org/onap/cli/fw/http/utils/OnapCommandHttpUtils.java @@ -0,0 +1,233 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.error.OnapCommandInvalidParameterValue; +import org.onap.cli.fw.error.OnapCommandParameterNotFound; +import org.onap.cli.fw.error.OnapCommandResultEmpty; +import org.onap.cli.fw.error.OnapCommandResultMapProcessingFailed; +import org.onap.cli.fw.http.connect.HttpInput; +import org.onap.cli.fw.http.connect.HttpResult; +import org.onap.cli.fw.http.error.OnapCommandHttpHeaderNotFound; +import org.onap.cli.fw.http.error.OnapCommandHttpInvalidResponseBody; +import org.onap.cli.fw.input.OnapCommandParameter; +import org.onap.cli.fw.input.OnapCommandParameterType; +import org.onap.cli.fw.utils.OnapCommandUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jayway.jsonpath.JsonPath; + +import net.minidev.json.JSONArray; + +public class OnapCommandHttpUtils { + + static Logger LOG = LoggerFactory.getLogger(OnapCommandHttpUtils.class); + + /** + * Set argument to param value. + * + * @param params + * map + * @param input + * HttpInput + * @return HttpInput + * @throws OnapCommandParameterNotFound + * exception + * @throws OnapCommandInvalidParameterValue + * exception + */ + public static HttpInput populateParameters(Map<String, OnapCommandParameter> params, HttpInput input) + throws OnapCommandException { + HttpInput inp = new HttpInput(); + for (OnapCommandParameter param : params.values()) { + if (OnapCommandParameterType.BINARY.equals(param.getParameterType())) { + inp.setBinaryData(true); + break; + } + } + inp.setBody(OnapCommandUtils.replaceLineFromInputParameters(input.getBody(), params)); + inp.setUri(OnapCommandUtils.replaceLineFromInputParameters(input.getUri(), params)); + inp.setMethod(input.getMethod().toLowerCase()); + for (String h : input.getReqHeaders().keySet()) { + String value = input.getReqHeaders().get(h); + inp.getReqHeaders().put(h, OnapCommandUtils.replaceLineFromInputParameters(value, params)); + } + + for (String h : input.getReqQueries().keySet()) { + String value = input.getReqQueries().get(h); + inp.getReqQueries().put(h, OnapCommandUtils.replaceLineFromInputParameters(value, params)); + } + + return inp; + } + + /** + * Populate result. + * + * @param resultMap + * map + * @param resultHttp + * HttpResult + * @return map + * @throws OnapCommandHttpHeaderNotFound + * header not found exception + * @throws OnapCommandHttpInvalidResponseBody + * invalid response body exception + * @throws OnapCommandResultMapProcessingFailed + * map processing failed exception + */ + public static Map<String, ArrayList<String>> populateOutputs(Map<String, String> resultMap, HttpResult resultHttp) + throws OnapCommandException { + Map<String, ArrayList<String>> resultsProcessed = new HashMap<>(); + + for (Entry<String, String> entry : resultMap.entrySet()) { + String key = entry.getKey(); + try { + resultsProcessed.put(key, OnapCommandHttpUtils.replaceLineFromOutputResults(resultMap.get(key), resultHttp)); + } catch(OnapCommandResultEmpty e) { + // pass // NOSONAR + } + } + + return resultsProcessed; + } + + public static ArrayList<String> replaceLineFromOutputResults(String line, HttpResult resultHttp) + throws OnapCommandHttpHeaderNotFound, OnapCommandHttpInvalidResponseBody, + OnapCommandResultMapProcessingFailed, OnapCommandResultEmpty { + String headerProcessedLine = ""; + + ArrayList<String> result = new ArrayList<>(); + if (!line.contains("$b{") && !line.contains("$h{")) { + result.add(line); + return result; + } + + /** + * In case of empty response body [] or {} + **/ + if (resultHttp.getBody().length() <= 2) { + return result; + } + + /** + * Process headers macros : line: $h{abc}-$b{$.[*].xyz} , After processing line will be [abc's + * value]-$b{$.[*].xyz} + **/ + int currentIdx = 0; + while (currentIdx < line.length()) { + int idxS = line.indexOf("$h{", currentIdx); + if (idxS == -1) { + headerProcessedLine += line.substring(currentIdx); + break; + } + int idxE = line.indexOf("}", idxS); + String headerName = line.substring(idxS + 3, idxE); + headerName = headerName.trim(); + if (!resultHttp.getRespHeaders().containsKey(headerName)) { + throw new OnapCommandHttpHeaderNotFound(headerName); + } + String value = resultHttp.getRespHeaders().get(headerName); + + headerProcessedLine += line.substring(currentIdx, idxS) + value; + currentIdx = idxE + 1; + } + + // Process body jsonpath macros + List<Object> values = new ArrayList<>(); + String bodyProcessedPattern = ""; + currentIdx = 0; + int maxRows = 1; // in normal case, only one row will be there + while (currentIdx < headerProcessedLine.length()) { + int idxS = headerProcessedLine.indexOf("$b{", currentIdx); + if (idxS == -1) { + bodyProcessedPattern += headerProcessedLine.substring(currentIdx); + break; + } + int idxE = headerProcessedLine.indexOf("}", idxS); + String jsonPath = headerProcessedLine.substring(idxS + 3, idxE); + jsonPath = jsonPath.trim(); + try { + // JSONArray or String + Object value = JsonPath.read(resultHttp.getBody(), jsonPath); + if (value instanceof JSONArray) { + JSONArray arr = (JSONArray) value; + if (arr.size() > maxRows) { + maxRows = arr.size(); + } + } + bodyProcessedPattern += headerProcessedLine.substring(currentIdx, idxS) + "%s"; + values.add(value); + currentIdx = idxE + 1; + } catch (Exception e) { + throw new OnapCommandHttpInvalidResponseBody(jsonPath, e); + } + } + + if (bodyProcessedPattern.isEmpty()) { + result.add(headerProcessedLine); + return result; + } else { + for (int i = 0; i < maxRows; i++) { + currentIdx = 0; + String bodyProcessedLine = ""; + int positionalIdx = 0; // %s positional idx + while (currentIdx < bodyProcessedPattern.length()) { + int idxS = bodyProcessedPattern.indexOf("%s", currentIdx); + if (idxS == -1) { + bodyProcessedLine += bodyProcessedPattern.substring(currentIdx); + break; + } + int idxE = idxS + 2; // %s + try { + Object value = values.get(positionalIdx); + String valueS = String.valueOf(value); + if (value instanceof JSONArray) { + JSONArray arr = (JSONArray) value; + if (!arr.isEmpty()) { + valueS = arr.get(i).toString(); + } else { + throw new OnapCommandResultEmpty(); + } + } + + bodyProcessedLine += bodyProcessedPattern.substring(currentIdx, idxS) + valueS; + currentIdx = idxE; + positionalIdx++; + } catch (OnapCommandResultEmpty e) { + throw e; + } catch (Exception e) { + throw new OnapCommandResultMapProcessingFailed(line, e); + } + } + result.add(bodyProcessedLine); + } + + return result; + } + } + +} + diff --git a/profiles/http/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand b/profiles/http/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand new file mode 100644 index 00000000..5ce19e66 --- /dev/null +++ b/profiles/http/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand @@ -0,0 +1,4 @@ +org.onap.cli.fw.http.cmd.BasicAuthLoginCommand +org.onap.cli.fw.http.cmd.BasicAuthLogoutCommand +org.onap.cli.fw.http.cmd.CatalogCommand +org.onap.cli.fw.http.cmd.OnapHttpCommand
\ No newline at end of file diff --git a/profiles/http/src/main/resources/open-cli-http.properties b/profiles/http/src/main/resources/open-cli-http.properties new file mode 100644 index 00000000..caeb4a95 --- /dev/null +++ b/profiles/http/src/main/resources/open-cli-http.properties @@ -0,0 +1,18 @@ +cli.ignore_auth=false +cli.http.api_key_use_cookies=true + +#schema validation +#http +cli.schema.http_sections=request,service,success_codes,result_map,sample_response +cli.schema.http_mandatory_sections=request, success_codes + +cli.schema.http_request_params=uri,method,body,headers,queries,multipart_entity_name +cli.schema.http_request_mandatory_params=uri,method + +cli.schema.service_params_list=name,version,auth,mode +cli.schema.service_params_mandatory_list=auth,mode + +cli.schema.http_methods=post,get,delete,put,head + +cli.schema.auth_values=none,basic +cli.schema.mode_values=direct,catalog diff --git a/profiles/http/src/main/resources/open-cli-schema/http/basic-login.yaml b/profiles/http/src/main/resources/open-cli-schema/http/basic-login.yaml new file mode 100644 index 00000000..36473df7 --- /dev/null +++ b/profiles/http/src/main/resources/open-cli-schema/http/basic-login.yaml @@ -0,0 +1,19 @@ +open_cli_schema_version: 1.0 + +name: basic-login + +description: basic login auth command + +info: + product: open-cli + service: basic-auth + type: auth + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +results: + direction: portrait + attributes: + - name: Authorization + description: Authorization + scope: short + type: string diff --git a/profiles/http/src/main/resources/open-cli-schema/http/basic-logout.yaml b/profiles/http/src/main/resources/open-cli-schema/http/basic-logout.yaml new file mode 100644 index 00000000..f4acc0ae --- /dev/null +++ b/profiles/http/src/main/resources/open-cli-schema/http/basic-logout.yaml @@ -0,0 +1,19 @@ +open_cli_schema_version: 1.0 + +name: basic-logout + +description: basic logout auth command + +info: + product: open-cli + service: basic-auth + type: auth + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +parameters: + - name: host-username + is_include: false + - name: host-password + is_include: false + - name: no-auth + is_include: false
\ No newline at end of file diff --git a/profiles/http/src/main/resources/open-cli-schema/http/catalog.yaml b/profiles/http/src/main/resources/open-cli-schema/http/catalog.yaml new file mode 100644 index 00000000..508955f5 --- /dev/null +++ b/profiles/http/src/main/resources/open-cli-schema/http/catalog.yaml @@ -0,0 +1,44 @@ +open_cli_schema_version: 1.0 + +name: catalog + +description: cli catalog command to find the base path for service. + +info: + product: open-cli + service: catalog + type: catalog + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +parameters: + - name: catalog-service-name + type: string + description: service name registered in catalog service + short_option: l + long_option: catalog-service-name + is_optional: false + - name: catalog-service-version + type: string + description: service version registered in catalog service + short_option: i + long_option: catalog-service-version + is_optional: false + - name: host-username + is_include: false + - name: host-password + is_include: false + - name: no-auth + is_include: false +results: + direction: portrait + attributes: + - name: catalog-service-host-url + description: Service connection url + scope: short + type: string + default_value: ${host-url} + - name: catalog-service-base-path + description: service base path, to append with host-url for connecting the service. + scope: short + type: string + default_value: /
\ No newline at end of file diff --git a/profiles/http/src/main/resources/open-cli-schema/http/default_input_parameters_http.yaml b/profiles/http/src/main/resources/open-cli-schema/http/default_input_parameters_http.yaml new file mode 100644 index 00000000..d7fbe03c --- /dev/null +++ b/profiles/http/src/main/resources/open-cli-schema/http/default_input_parameters_http.yaml @@ -0,0 +1,36 @@ +open_cli_schema_version: 1.0 + +info: + product: open-cli + service: default-param + ignore: true + +parameters: + - name: host-username + type: string + description: Host user name + short_option: u + long_option: host-username + default_value: $s{env:OPEN_CLI_HOST_USERNAME} + is_optional: false + - name: host-password + type: string + description: Host user password + short_option: p + long_option: host-password + default_value: $s{env:OPEN_CLI_HOST_PASSWORD} + is_secured: true + is_optional: false + - name: host-url + type: url + description: host url in http(s) + short_option: m + long_option: host-url + is_optional: false + default_value: $s{env:OPEN_CLI_HOST_URL} + - name: no-auth + type: bool + description: whether to authenticate user or not + short_option: a + long_option: no-auth + default_value: false
\ No newline at end of file |