From b4d41862b891168c473e6f0d0e410337801b059f Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 12 Oct 2021 18:05:54 +0200 Subject: [PATCH] Cleanup code in akamai module (#2317) --- akamai/pom.xml | 5 + .../extensions/akamai/HashAlgorithm.java | 77 ++++ .../extensions/akamai/NetStorageAction.java | 176 -------- .../akamai/NetStorageCmsSigner.java | 44 +- .../extensions/akamai/NetStorageRequest.java | 186 ++++++++ .../extensions/akamai/NetStorageSender.java | 244 +++-------- .../extensions/akamai/NetStorageUtils.java | 110 +---- .../akamai/NetStorageCmsSignerTest.java | 7 +- .../akamai/NetStorageSenderTest.java | 403 +++++++++++++++++- .../resources/Http/Responses/deleteAction.txt | 4 + .../resources/Http/Responses/dirAction.txt | 4 + .../Http/Responses/downloadAction.txt | 4 + .../response => Http/Responses}/duAction.txt | 0 .../resources/Http/Responses/mkdirAction.txt | 4 + .../resources/Http/Responses/mtimeAction.txt | 4 + .../resources/Http/Responses/renameAction.txt | 4 + .../resources/Http/Responses/rmdirAction.txt | 4 + .../resources/Http/Responses/uploadAction.txt | 6 + .../Http/Responses/uploadActionMD5.txt | 6 + .../Http/Responses/uploadActionSHA1.txt | 6 + .../Http/Responses/uploadActionSHA256.txt | 6 + .../nn/adapterframework/ftp/FtpSession.java | 4 +- .../adapterframework/http/HttpSenderBase.java | 4 +- .../nn/adapterframework/stream/Message.java | 2 +- .../http/HttpResponseMock.java | 16 +- .../http/HttpSenderTestBase.java | 2 +- .../Responses}/binaryHttpPostJSON.txt | 0 .../Responses}/binaryHttpPostPDF.txt | 0 .../Responses}/binaryHttpPutJSON.txt | 0 .../Responses}/parametersToSkip.txt | 0 .../Responses}/paramsWithoutValue.txt | 0 .../Responses}/simpleMockedHttpCharset.txt | 0 .../Responses}/simpleMockedHttpGet.txt | 0 .../simpleMockedHttpGetEncodeMessage.txt | 0 .../simpleMockedHttpGetWithContentType.txt | 0 ...MockedHttpGetWithContentTypeAndCharset.txt | 0 .../simpleMockedHttpGetWithParams.txt | 0 ...simpleMockedHttpGetWithUrlParamAndPath.txt | 0 .../simpleMockedHttpGetWithoutPRC.txt | 0 .../Responses}/simpleMockedHttpMtom.txt | 0 .../Responses}/simpleMockedHttpMultipart.txt | 0 .../Responses}/simpleMockedHttpPatch.txt | 0 .../Responses}/simpleMockedHttpPost.txt | 0 ...simpleMockedHttpPostAppendParamsToBody.txt | 0 ...HttpPostAppendParamsToBodyAndEmptyBody.txt | 0 .../simpleMockedHttpPostEncodeMessage.txt | 0 .../Responses}/simpleMockedHttpPostJSON.txt | 0 .../simpleMockedHttpPostUrlEncoded.txt | 0 .../Responses}/simpleMockedHttpPut.txt | 0 .../Responses}/simpleMockedHttpPutJSON.txt | 0 .../Responses}/simpleMockedMultipartHttp1.txt | 0 .../Responses}/simpleMockedMultipartHttp2.txt | 0 .../Responses}/simpleMockedMultipartHttp3.txt | 0 .../Responses}/simpleMockedMultipartMtom1.txt | 0 .../Responses}/simpleMockedMultipartMtom2.txt | 0 .../Responses}/simpleMockedMultipartMtom3.txt | 0 .../Responses}/simpleMockedRestGet.txt | 0 .../Responses}/simpleMockedRestPost.txt | 0 .../Responses}/simpleMockedWss.txt | 0 .../Responses}/simpleMockedWssMtom.txt | 0 .../Responses}/simpleMockedWssMultipart.txt | 0 .../Responses}/simpleMockedWssMultipart2.txt | 0 .../simpleMockedWssMultipartMtom.txt | 0 .../Responses}/simpleMockedWssSoapAction.txt | 0 .../specialCharactersDoubleEscaped.txt | 0 .../specialCharactersInURLParam.txt | 0 .../frankdoc/model/FrankAttribute.java | 2 +- pom.xml | 4 + 68 files changed, 831 insertions(+), 507 deletions(-) create mode 100644 akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/HashAlgorithm.java delete mode 100644 akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageAction.java create mode 100644 akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageRequest.java create mode 100644 akamai/src/test/resources/Http/Responses/deleteAction.txt create mode 100644 akamai/src/test/resources/Http/Responses/dirAction.txt create mode 100644 akamai/src/test/resources/Http/Responses/downloadAction.txt rename akamai/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/duAction.txt (100%) create mode 100644 akamai/src/test/resources/Http/Responses/mkdirAction.txt create mode 100644 akamai/src/test/resources/Http/Responses/mtimeAction.txt create mode 100644 akamai/src/test/resources/Http/Responses/renameAction.txt create mode 100644 akamai/src/test/resources/Http/Responses/rmdirAction.txt create mode 100644 akamai/src/test/resources/Http/Responses/uploadAction.txt create mode 100644 akamai/src/test/resources/Http/Responses/uploadActionMD5.txt create mode 100644 akamai/src/test/resources/Http/Responses/uploadActionSHA1.txt create mode 100644 akamai/src/test/resources/Http/Responses/uploadActionSHA256.txt rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/binaryHttpPostJSON.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/binaryHttpPostPDF.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/binaryHttpPutJSON.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/parametersToSkip.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/paramsWithoutValue.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpCharset.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpGet.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpGetEncodeMessage.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpGetWithContentType.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpGetWithContentTypeAndCharset.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpGetWithParams.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpGetWithUrlParamAndPath.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpGetWithoutPRC.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpMtom.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpMultipart.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPatch.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPost.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPostAppendParamsToBody.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPostAppendParamsToBodyAndEmptyBody.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPostEncodeMessage.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPostJSON.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPostUrlEncoded.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPut.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedHttpPutJSON.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedMultipartHttp1.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedMultipartHttp2.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedMultipartHttp3.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedMultipartMtom1.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedMultipartMtom2.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedMultipartMtom3.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedRestGet.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedRestPost.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedWss.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedWssMtom.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedWssMultipart.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedWssMultipart2.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedWssMultipartMtom.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/simpleMockedWssSoapAction.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/specialCharactersDoubleEscaped.txt (100%) rename core/src/test/resources/{nl/nn/adapterframework/http/response => Http/Responses}/specialCharactersInURLParam.txt (100%) diff --git a/akamai/pom.xml b/akamai/pom.xml index d8f169ca84e..cebf52c474b 100644 --- a/akamai/pom.xml +++ b/akamai/pom.xml @@ -15,6 +15,11 @@ org.ibissource ibis-adapterframework-core + + org.projectlombok + lombok + + javax.servlet javax.servlet-api diff --git a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/HashAlgorithm.java b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/HashAlgorithm.java new file mode 100644 index 00000000000..8fb09f67067 --- /dev/null +++ b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/HashAlgorithm.java @@ -0,0 +1,77 @@ +/* + Copyright 2021 WeAreFrank! + + 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 nl.nn.adapterframework.extensions.akamai; + +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import lombok.Getter; +import nl.nn.adapterframework.stream.Message; +import nl.nn.adapterframework.util.Misc; + +/** + * An enum of the hash algorithms. Currently supported hashes include MD5; SHA1; SHA256 + * + * The string representation matches the java {@link java.security.MessageDigest#getInstance(String)} canonical names. + * + * @author Niels Meijer + */ +public enum HashAlgorithm { + MD5("MD5"), SHA1("SHA-1"), SHA256("SHA-256"); + + /** + * Algorithm name as defined in {@link java.security.MessageDigest#getInstance(String)} + */ + private @Getter final String algorithm; + + private HashAlgorithm(final String algorithm) { + this.algorithm = algorithm; + } + + public String computeHash(Message file) throws IOException { + byte[] fileBytes = file.asByteArray(); + if (fileBytes == null) { + throw new IllegalStateException("unable to compute hash over null message"); + } + + byte[] checksum = computeHash(fileBytes, this); + if(checksum != null) { + return Misc.asHex(checksum); + } + + throw new IllegalStateException("error computing checksum"); + } + + /** + * Computes the hash of a given InputStream. This is a wrapper over the MessageDigest crypto functions. + * + * @param srcBytes to generate a hash over + * @param hashAlgorithm the Algorithm to use to compute the hash + * @return a byte[] representation of the hash. If the InputStream is a null object + * then null will be returned. If the InputStream is empty an empty byte[] {} will be returned. + */ + private static byte[] computeHash(byte[] srcBytes, HashAlgorithm hashAlgorithm) { + try { + MessageDigest digest = MessageDigest.getInstance(hashAlgorithm.getAlgorithm()); + + return digest.digest(srcBytes); + } catch (NoSuchAlgorithmException e) { + //no-op. This will never happen since we are using an enum to limit the hash algorithms + throw new IllegalArgumentException("This should never happen! We are using an enum!", e); + } + } +} \ No newline at end of file diff --git a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageAction.java b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageAction.java deleted file mode 100644 index 7484e619bde..00000000000 --- a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageAction.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - Copyright 2017 Nationale-Nederlanden, 2021 WeAreFrank! - - 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 nl.nn.adapterframework.extensions.akamai; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import nl.nn.adapterframework.core.SenderException; -import nl.nn.adapterframework.extensions.akamai.NetStorageUtils.HashAlgorithm; -import nl.nn.adapterframework.http.HttpSenderBase.HttpMethod; -import nl.nn.adapterframework.parameters.ParameterValueList; -import nl.nn.adapterframework.util.Misc; - -/** - * @author Niels Meijer - */ -public class NetStorageAction { - private int version = 1; - private HttpMethod method = null; - private InputStream fileStream = null; - private byte[] fileBytes = null; - private String action = null; - private String hashAlgorithm = null; - private Map actionHeader = new HashMap<>(); - - public NetStorageAction(String action) { - this.action = action; - actionHeader.put("action", action); - if(action.equals("dir")) { - method = HttpMethod.GET; - } - if(action.equals("du")) { - method = HttpMethod.GET; - } - if(action.equals("delete")) { - method = HttpMethod.PUT; - } - if(action.equals("upload")) { - method = HttpMethod.PUT; - } - if(action.equals("mkdir")) { - method = HttpMethod.PUT; - } - if(action.equals("rmdir")) { - method = HttpMethod.POST; - } - if(action.equals("rename")) { - method = HttpMethod.POST; - } - if(action.equals("mtime")) { - method = HttpMethod.POST; - } - if(action.equals("download")) { - method = HttpMethod.GET; - } - } - - public HttpMethod getMethod() { - return method; - } - - public boolean requiresFileParam() { - return action.equals("upload"); - } - - public String compileHeader() { - if(getMethod() == HttpMethod.GET) { - actionHeader.put("format", "xml"); - } - actionHeader.put("version", version+""); - - return NetStorageUtils.convertMapAsQueryParams(actionHeader); - } - - public void setVersion(int version) { - this.version = version; - } - - public void mapParameters(ParameterValueList pvl) throws SenderException { - if(requiresFileParam()) { - Object paramValue = pvl.getParameterValue("file").getValue(); - if(paramValue instanceof InputStream) - fileStream = (InputStream) paramValue; - else if(paramValue instanceof byte[]) - fileBytes = (byte[]) paramValue; - else - throw new SenderException("expected InputStream or ByteArray but got ["+paramValue.getClass().getName()+"] instead"); - - String md5 = null; - String sha1 = null; - String sha256 = null; - if(pvl.parameterExists("md5")) { - md5 = pvl.getParameterValue("md5").asStringValue(null); - } - - if(pvl.parameterExists("sha1")) { - sha1 = pvl.getParameterValue("sha1").asStringValue(null); - } - - if(pvl.parameterExists("sha256")) { - sha256 = pvl.getParameterValue("sha256").asStringValue(null); - } - - if(hashAlgorithm != null) { - try { - if(fileStream != null) - fileBytes = Misc.streamToBytes(fileStream); - - if(md5 == null && hashAlgorithm.equals("MD5")) { - byte[] checksum = NetStorageUtils.computeHash(fileBytes, HashAlgorithm.MD5); - if(checksum != null) - md5 = NetStorageUtils.convertByteArrayToHexString(checksum); - } - if(sha1 == null && hashAlgorithm.equals("SHA1")) { - byte[] checksum = NetStorageUtils.computeHash(fileBytes, HashAlgorithm.SHA1); - if(checksum != null) - sha1 = NetStorageUtils.convertByteArrayToHexString(checksum); - } - if(sha256 == null && hashAlgorithm.equals("SHA256")) { - byte[] checksum = NetStorageUtils.computeHash(fileBytes, HashAlgorithm.SHA256); - if(checksum != null) - sha256 = NetStorageUtils.convertByteArrayToHexString(checksum); - } - fileStream = new ByteArrayInputStream(fileBytes); - } - catch (Exception e) { - throw new SenderException("error while calculating ["+hashAlgorithm+"] hash", e); - } - } - if(md5 != null) - actionHeader.put("md5", md5); - if(sha1 != null) - actionHeader.put("sha1", sha1); - if(sha256 != null) - actionHeader.put("sha256", sha256); - - if(pvl.parameterExists("size")) { - int size = pvl.getParameterValue("size").asIntegerValue(0); - actionHeader.put("size", size+""); - } - } - - if(pvl.parameterExists("mtime")) { - long mtime = pvl.getParameterValue("mtime").asLongValue(-1L); - actionHeader.put("mtime", mtime+""); - } - } - - public InputStream getFile() { - return fileStream; - } - - public String getName() { - return action; - } - - public void setHashAlgorithm(String hashAlgorithm) { - this.hashAlgorithm = hashAlgorithm; - } - -} diff --git a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSigner.java b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSigner.java index bac96dd80d9..f825191a3a2 100644 --- a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSigner.java +++ b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSigner.java @@ -22,6 +22,7 @@ import java.util.Random; import nl.nn.adapterframework.extensions.akamai.NetStorageUtils.KeyedHashAlgorithm; +import nl.nn.adapterframework.util.CredentialFactory; /** @@ -70,8 +71,7 @@ public KeyedHashAlgorithm getAlgorithm() { private URI uri; private String nonce; private String accessToken; - private NetStorageAction action; - private SignType signVersion; + private SignType signType; /** * Primary invocation for an API communication. This constructor is used for convenience when not uploading content @@ -79,10 +79,9 @@ public KeyedHashAlgorithm getAlgorithm() { * @param uri the url to interact with (eg: http://example.akamaihd.net/254462 ) * @param nonce provisioned nonce from the Luna portal * @param accessToken the associated accessToken generated by the portal - * @param action the set of action parameters to be sent in the API request */ - public NetStorageCmsSigner(URI uri, String nonce, String accessToken, NetStorageAction action) { - this(uri, nonce, accessToken, action, SignType.HMACSHA256); + public NetStorageCmsSigner(URI uri, String nonce, String accessToken) { + this(uri, nonce, accessToken, SignType.HMACSHA256); } /** @@ -91,32 +90,26 @@ public NetStorageCmsSigner(URI uri, String nonce, String accessToken, NetStorage * @param uri the url to interact with (eg: http://example.akamaihd.net/254462 ) * @param nonce provisioned nonce from the Luna portal * @param accessToken the associated accessToken generated by the portal - * @param action the set of action parameters to be sent in the API request - * @param signVersion the base64 encoded signature algorithm + * @param signType the base64 encoded signature algorithm */ - public NetStorageCmsSigner(URI uri, String nonce, String accessToken, NetStorageAction action, SignType signVersion) { + public NetStorageCmsSigner(URI uri, String nonce, String accessToken, SignType signType) { this.uri = uri; this.nonce = nonce; this.accessToken = accessToken; - this.action = action; - this.signVersion = signVersion; - } - - public SignType getSignVersion() { - return signVersion; + this.signType = signType; } - public void setSignVersion(SignType signVersion) { - this.signVersion = signVersion; + public NetStorageCmsSigner(URI uri, CredentialFactory accessTokenCf, SignType signType) { + this(uri, accessTokenCf.getUsername(), accessTokenCf.getPassword(), signType); } /** * Computes the value for the the X-Akamai-ACS-Action: header. This is an url query-string encoded separated * list of parameters in the form of name=value&name2=value2. - * - * @return an url encoded query string of name-value pairs from the {@link nl.nn.adapterframework.extensions.akamai.NetStorageAction} + * @param action the set of action parameters to be sent in the API request + * @return an url encoded query string of name-value pairs from the {@link nl.nn.adapterframework.extensions.akamai.NetStorageRequest} */ - protected String getActionHeaderValue() { + protected String getActionHeaderValue(NetStorageRequest action) { return action.compileHeader(); } @@ -132,7 +125,7 @@ protected String getAuthDataHeaderValue() { return String.format( "%d, 0.0.0.0, 0.0.0.0, %d, %d, %s", - this.getSignVersion().getValue(), + signType.getValue(), currentTime.getTime()/1000, rand, nonce); @@ -143,7 +136,7 @@ protected String getAuthDataHeaderValue() { * encoded representation of the hash as required by the spec. The api server will compute this same hash to validate * the request * - * @param action action header values {@link #getActionHeaderValue()} + * @param action action header values {@link #getActionHeaderValue(NetStorageRequest)} * @param authData data header values {@link #getAuthDataHeaderValue()} * @return a base64 encoded return string */ @@ -154,18 +147,19 @@ protected String getAuthSignHeaderValue(String action, String authData) { uri.getPath(), NetStorageCmsSigner.ACTION_HEADER.toLowerCase(), action); - byte[] hash = NetStorageUtils.computeKeyedHash(signData.getBytes(), accessToken, this.getSignVersion().getAlgorithm()); + byte[] hash = NetStorageUtils.computeKeyedHash(signData.getBytes(), accessToken, signType.getAlgorithm()); return NetStorageUtils.encodeBase64(hash); } /** * Assembles the HTTP Headers necessary for API communication + * @param netStorageAction the set of action parameters to be sent in the API request * @return Map of name-value pairs representing HTTP Headers and values. */ - public Map computeHeaders() { - final Map headers = new HashMap(3); - final String action = getActionHeaderValue(); + public Map computeHeaders(NetStorageRequest netStorageAction) { + final Map headers = new HashMap<>(3); + final String action = getActionHeaderValue(netStorageAction); final String authData = getAuthDataHeaderValue(); final String authSign = getAuthSignHeaderValue(action, authData); diff --git a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageRequest.java b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageRequest.java new file mode 100644 index 00000000000..8a07b1f5724 --- /dev/null +++ b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageRequest.java @@ -0,0 +1,186 @@ +/* + Copyright 2017 Nationale-Nederlanden, 2021 WeAreFrank! + + 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 nl.nn.adapterframework.extensions.akamai; + +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +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.entity.ByteArrayEntity; +import org.apache.http.entity.InputStreamEntity; +import org.apache.logging.log4j.Logger; + +import lombok.Setter; +import nl.nn.adapterframework.core.SenderException; +import nl.nn.adapterframework.extensions.akamai.NetStorageSender.Action; +import nl.nn.adapterframework.http.HttpSenderBase.HttpMethod; +import nl.nn.adapterframework.parameters.ParameterValueList; +import nl.nn.adapterframework.stream.Message; +import nl.nn.adapterframework.util.EnumUtils; +import nl.nn.adapterframework.util.LogUtil; + +/** + * @author Niels Meijer + */ +public class NetStorageRequest { + private Logger log = LogUtil.getLogger(NetStorageRequest.class); + + private int version = 1; + private Message file = null; + private Action action = null; + private @Setter HashAlgorithm hashAlgorithm = null; + private Map actionHeader = new HashMap<>(); + private HttpRequestBase method; + + protected NetStorageRequest(Action action) { + this(null, action); + } + + public NetStorageRequest(URI uri, Action action) { + this.action = action; + actionHeader.put("action", action.name().toLowerCase()); + + switch (action) { + case DIR: + case DU: + case DOWNLOAD: + method = new HttpGet(uri); + break; + case DELETE: + case UPLOAD: + case MKDIR: + method = new HttpPut(uri); + break; + case RMDIR: + case RENAME: + case MTIME: + method = new HttpPost(uri); + break; + default: + throw new NotImplementedException("unknown action ["+action+"]"); + } + } + + public String compileHeader() { + if(method instanceof HttpGet) { + actionHeader.put("format", "xml"); + } + actionHeader.put("version", version+""); + + return NetStorageUtils.convertMapAsQueryParams(actionHeader); + } + + public void setVersion(int version) { + this.version = version; + } + + public void mapParameters(ParameterValueList pvl) throws SenderException { + if(action == Action.UPLOAD && pvl.parameterExists(NetStorageSender.FILE_PARAM_KEY)) { + Object paramValue = pvl.getParameterValue(NetStorageSender.FILE_PARAM_KEY).getValue(); + file = Message.asMessage(paramValue); + if(Message.isEmpty(file)) { + throw new SenderException("no file specified"); + } + + if(hashAlgorithm != null) { + try { + generateHash(pvl); + } + catch (IOException e) { + throw new SenderException("error while calculating ["+hashAlgorithm+"] hash", e); + } + } + + try { + setEntity(file); + } catch (IOException e) { + throw new SenderException("unable to parse file", e); + } + + if(pvl.parameterExists("size")) { + int size = pvl.getParameterValue("size").asIntegerValue(0); + actionHeader.put("size", size+""); + } + } + + if(action == Action.RENAME && pvl.parameterExists(NetStorageSender.DESTINATION_PARAM_KEY)) { + String destination = pvl.getParameterValue(NetStorageSender.DESTINATION_PARAM_KEY).asStringValue(null); + actionHeader.put("destination", destination); + } + + if(pvl.parameterExists(NetStorageSender.MTIME_PARAM_KEY)) { + long mtime = pvl.getParameterValue(NetStorageSender.MTIME_PARAM_KEY).asLongValue(-1L); + actionHeader.put("mtime", mtime+""); + } + } + + private void generateHash(ParameterValueList pvl) throws IOException { + String hash = null; + String algorithm = hashAlgorithm.name().toLowerCase(); + if(pvl.parameterExists(NetStorageSender.HASHVALUE_PARAM_KEY)) { + hash = pvl.getParameterValue(NetStorageSender.HASHVALUE_PARAM_KEY).asStringValue(null); + } + else if(pvl.parameterExists(algorithm)) { //backwards compatibility + hash = pvl.getParameterValue(algorithm).asStringValue(null); + } + else { + hash = hashAlgorithm.computeHash(file); + } + + if(StringUtils.isNotEmpty(hash)) { + actionHeader.put(algorithm, hash); + } + } + + public HttpMethod getMethodType() { + return EnumUtils.parse(HttpMethod.class, method.getMethod()); + } + + private void setEntity(Message file) throws IOException { + HttpEntity entity = toEntity(file); + ((HttpEntityEnclosingRequestBase) method).setEntity(entity); + } + + private HttpEntity toEntity(Message file) throws IOException { + if(file.requiresStream()) { + return new InputStreamEntity(file.asInputStream()); + } + return new ByteArrayEntity(file.asByteArray()); + } + + public void sign(NetStorageCmsSigner signer) { + Map headers = signer.computeHeaders(this); + + for (Map.Entry entry : headers.entrySet()) { + if(log.isDebugEnabled()) log.debug("append header ["+ entry.getKey() +"] with value ["+ entry.getValue() +"]"); + + method.setHeader(entry.getKey(), entry.getValue()); + } + } + + public HttpRequestBase build() { + return method; + } +} diff --git a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageSender.java b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageSender.java index bb988dfcc46..60293c02390 100644 --- a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageSender.java +++ b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageSender.java @@ -21,25 +21,19 @@ import java.net.URISyntaxException; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.Date; -import java.util.List; import java.util.Locale; -import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpEntity; -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.utils.URIBuilder; -import org.apache.http.entity.InputStreamEntity; import org.apache.logging.log4j.Logger; +import lombok.Getter; import nl.nn.adapterframework.configuration.ConfigurationException; +import nl.nn.adapterframework.configuration.ConfigurationWarnings; import nl.nn.adapterframework.core.PipeLineSession; import nl.nn.adapterframework.core.SenderException; import nl.nn.adapterframework.core.TimeOutException; @@ -62,33 +56,38 @@ * *

See {@link nl.nn.adapterframework.http.HttpSenderBase} for more arguments and parameters!

* - *

Parameters:

- *

Some actions require specific parameters to be set. Optional parameters for the upload action are: md5, sha1, sha256 and mtime.

* - *

AuthAlias: (WebSphere based application servers)

+ *

AuthAlias:

*

If you do not want to specify the nonce and the accesstoken used to authenticate with Akamai, you can use the authalias property. The username represents the nonce and the password the accesstoken.

* + * @ff.parameters Some actions require specific parameters to be set. Optional parameters for the upload action are: md5, sha1, sha256 and mtime. * * @author Niels Meijer * @since 7.0-B4 */ public class NetStorageSender extends HttpSenderBase { private Logger log = LogUtil.getLogger(NetStorageSender.class); - private String URL_PARAM_KEY = "urlParameter"; - - private String action = null; - private List actions = Arrays.asList("du", "dir", "delete", "upload", "mkdir", "rmdir", "rename", "mtime", "download"); - private String url = null; - private String nonce = null; - private int signVersion = 5; - private int actionVersion = 1; - private String hashAlgorithm = null; - private List hashAlgorithms = Arrays.asList("MD5", "SHA1", "SHA256"); - private String rootDir = null; - - private String authAlias; - private String cpCode = null; - private String accessToken = null; + private static final String URL_PARAM_KEY = "urlParameter"; + public static final String DESTINATION_PARAM_KEY = "destination"; + public static final String FILE_PARAM_KEY = "file"; + public static final String MTIME_PARAM_KEY = "mtime"; + public static final String HASHVALUE_PARAM_KEY = "hashValue"; + + private @Getter Action action = null; + public enum Action { + DU, DIR, DELETE, UPLOAD, MKDIR, RMDIR, RENAME, MTIME, DOWNLOAD; + } + + private @Getter int signVersion = 5; + private @Getter int actionVersion = 1; + private @Getter String rootDir = null; + + private HashAlgorithm hashAlgorithm = null; + + private @Getter String cpCode = null; + private @Getter String authAlias = null; + private @Getter String nonce = null; + private @Getter String accessToken = null; private CredentialFactory accessTokenCf = null; @Override @@ -105,28 +104,38 @@ public void configure() throws ConfigurationException { //Safety checks if(getAction() == null) throw new ConfigurationException(getLogPrefix()+"action must be specified"); - if(!actions.contains(getAction())) - throw new ConfigurationException(getLogPrefix()+"unknown or invalid action ["+getAction()+"] supported actions are "+actions.toString()+""); if(getCpCode() == null) throw new ConfigurationException(getLogPrefix()+"cpCode must be specified"); if(!getUrl().startsWith("http")) throw new ConfigurationException(getLogPrefix()+"url must be start with http(s)"); - if(hashAlgorithm != null && !hashAlgorithms.contains(hashAlgorithm)) - throw new ConfigurationException(getLogPrefix()+"unknown authenticationMethod ["+hashAlgorithm+"] supported methods are "+hashAlgorithms.toString()+""); - if(getSignVersion() < 3 || getSignVersion() > 5) throw new ConfigurationException(getLogPrefix()+"signVersion must be either 3, 4 or 5"); ParameterList parameterList = getParameterList(); - if(getAction().equals("upload") && parameterList.findParameter("file") == null) + if(getAction() == Action.UPLOAD && parameterList.findParameter(FILE_PARAM_KEY) == null) { throw new ConfigurationException(getLogPrefix()+"the upload action requires a file parameter to be present"); - if(getAction().equals("rename") && parameterList.findParameter("destination") == null) + } + if(getAction() == Action.RENAME && parameterList.findParameter(DESTINATION_PARAM_KEY) == null) { throw new ConfigurationException(getLogPrefix()+"the rename action requires a destination parameter to be present"); - if(getAction().equals("mtime") && parameterList.findParameter("mtime") == null) + } + if(getAction() == Action.MTIME && parameterList.findParameter(MTIME_PARAM_KEY) == null) { throw new ConfigurationException(getLogPrefix()+"the mtime action requires a mtime parameter to be present"); + } + + //check if md5/sha1/sha256 -> geef deprecated warning + parse hashAlgorithme + //hashValue parameterList + for(HashAlgorithm algorithm : HashAlgorithm.values()) { + String simpleName = algorithm.name().toLowerCase(); + Parameter hashValue = parameterList.findParameter(simpleName); + + if(hashValue != null) { + setHashAlgorithm(algorithm); + ConfigurationWarnings.add(this, log, "deprecated parameter ["+simpleName+"]: please use attribute [hashAlgorithm] in combination with parameter ["+HASHVALUE_PARAM_KEY+"]"); + } + } accessTokenCf = new CredentialFactory(getAuthAlias(), getNonce(), getAccessToken()); } @@ -161,7 +170,7 @@ public Message sendMessage(Message message, PipeLineSession session) throws Send try { path = message.asString(); } catch (IOException e) { - throw new SenderException(getLogPrefix(),e); + throw new SenderException(getLogPrefix(), e); } //Store the input in the PipeLineSession, so it can be resolved as ParameterValue. //See {@link HttpSenderBase#getURI getURI(..)} how this is resolved @@ -173,70 +182,21 @@ public Message sendMessage(Message message, PipeLineSession session) throws Send @Override public HttpRequestBase getMethod(URI uri, Message message, ParameterValueList parameters, PipeLineSession session) throws SenderException { + NetStorageRequest request = new NetStorageRequest(uri, getAction()); + request.setVersion(actionVersion); + request.setHashAlgorithm(hashAlgorithm); - NetStorageAction netStorageAction = new NetStorageAction(getAction()); - netStorageAction.setVersion(actionVersion); - netStorageAction.setHashAlgorithm(hashAlgorithm); - - if(parameters != null) - netStorageAction.mapParameters(parameters); - - try { - setMethodType(netStorageAction.getMethod()); - log.debug("opening ["+netStorageAction.getMethod()+"] connection to ["+url+"] with action ["+getAction()+"]"); - - NetStorageCmsSigner signer = new NetStorageCmsSigner(uri, accessTokenCf.getUsername(), accessTokenCf.getPassword(), netStorageAction, getSignType()); - Map headers = signer.computeHeaders(); - - if (getHttpMethod() == HttpMethod.GET) { - HttpGet method = new HttpGet(uri); - for (Map.Entry entry : headers.entrySet()) { - log.debug("append header ["+ entry.getKey() +"] with value ["+ entry.getValue() +"]"); - - method.setHeader(entry.getKey(), entry.getValue()); - } - log.debug(getLogPrefix()+"HttpSender constructed GET-method ["+method.getURI()+"] query ["+method.getURI().getQuery()+"] "); - - return method; - } - else if (getHttpMethod() == HttpMethod.PUT) { - HttpPut method = new HttpPut(uri); - - for (Map.Entry entry : headers.entrySet()) { - log.debug("append header ["+ entry.getKey() +"] with value ["+ entry.getValue() +"]"); - - method.setHeader(entry.getKey(), entry.getValue()); - } - log.debug(getLogPrefix()+"HttpSender constructed GET-method ["+method.getURI()+"] query ["+method.getURI().getQuery()+"] "); - - if(netStorageAction.getFile() != null) { - HttpEntity entity = new InputStreamEntity(netStorageAction.getFile()); - method.setEntity(entity); - } - return method; - } - else if (getHttpMethod() == HttpMethod.POST) { - HttpPost method = new HttpPost(uri); - - for (Map.Entry entry : headers.entrySet()) { - log.debug("append header ["+ entry.getKey() +"] with value ["+ entry.getValue() +"]"); + if(parameters != null) { + request.mapParameters(parameters); + } - method.setHeader(entry.getKey(), entry.getValue()); - } - log.debug(getLogPrefix()+"HttpSender constructed GET-method ["+method.getURI()+"] query ["+method.getURI().getQuery()+"] "); + setMethodType(request.getMethodType()); //For logging purposes + if(log.isDebugEnabled()) log.debug("opening ["+request.getMethodType()+"] connection to ["+uri+"] with action ["+getAction()+"]"); - if(netStorageAction.getFile() != null) { - HttpEntity entity = new InputStreamEntity(netStorageAction.getFile()); - method.setEntity(entity); - } - return method; - } + NetStorageCmsSigner signer = new NetStorageCmsSigner(uri, accessTokenCf, getSignType()); + request.sign(signer); - } - catch (Exception e) { - throw new SenderException(e); - } - return null; + return request.build(); } @Override @@ -338,70 +298,32 @@ public String getResponseBodyAsString(HttpResponseHandler responseHandler, boole return responseBody; } - /** - * Only works in combination with the UPLOAD action. If set, and not - * specified as parameter, the sender will sign the file to be uploaded. - * NOTE: if the file input is a Stream this will put the file in memory! - * @param hashAlgorithm supports 3 types; md5, sha1, sha256 - */ - @IbisDoc({"only works in combination with the upload action. if set, and not specified as parameter, the sender will sign the file to be uploaded. possible values: md5, sha1, sha256.
note: if the file input is a stream this will put the file in memory!", ""}) - public void setHashAlgorithm(String hashAlgorithm) { - this.hashAlgorithm = hashAlgorithm.toUpperCase(); - } - - /** - * NetStorage action to be used - * @param action delete, dir, download, du, mkdir, mtime, rename, - * rmdir, upload - * @IbisDoc.required - */ - @IbisDoc({"possible values: delete, dir, download, du, mkdir, mtime, rename, rmdir, upload", ""}) - public void setAction(String action) { - this.action = action.toLowerCase(); + /** Only works in combination with the UPLOAD action. If set, and not specified as parameter, the sender will sign the file to be uploaded.*/ + public void setHashAlgorithm(HashAlgorithm hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; } - public String getAction() { - return action; + /** NetStorage action to be used */ + public void setAction(Action action) { + this.action = action; } - /** - * At the time of writing, NetStorage only supports version 1 - * @param actionVersion - * @IbisDoc.default 1 - */ - @IbisDoc({"akamai currently only supports action version 1!", "1"}) + /** At the time of writing, NetStorage only supports version 1 + * @ff.default 1 */ public void setActionVersion(int actionVersion) { this.actionVersion = actionVersion; } - /** - * NetStorage CP Code - * @param cpCode of the storage group - * @IbisDoc.optional - */ - @IbisDoc({"the cp code to be used", ""}) + /** NetStorage CP Code of the storage group */ public void setCpCode(String cpCode) { this.cpCode = cpCode; } - public String getCpCode() { - return cpCode; - } - - /** - * @param url the base URL for NetStorage (without CpCode) - * @IbisDoc.required - */ - @IbisDoc({"the destination, aka akamai host. only the hostname is allowed; eq. xyz-nsu.akamaihd.net", ""}) + /** The destination URL for the Akamai NetStorage. (Only the hostname, without CpCode; eq. xyz-nsu.akamaihd.net) */ @Override public void setUrl(String url) { if(!url.endsWith("/")) url += "/"; - this.url = url; - } - - @Override - public String getUrl() { - return url; + super.setUrl(url); } /** @@ -413,23 +335,14 @@ public void setNonce(String nonce) { this.nonce = nonce; } - public String getNonce() { - return nonce; - } - /** * Version to validate queries made to NetStorage backend. * @param signVersion supports 3 types; 3:MD5, 4:SHA1, 5: SHA256 - * @IbisDoc.default 5 (SHA256) */ @IbisDoc({"the version used to sign the authentication headers. possible values: 3 (md5), 4 (sha1), 5 (sha256)", "5"}) public void setSignVersion(int signVersion) { this.signVersion = signVersion; } - - public int getSignVersion() { - return signVersion; - } public SignType getSignType() { if(getSignVersion() == 3) return SignType.HMACMD5; @@ -448,24 +361,12 @@ public void setAccessToken(String accessToken) { this.accessToken = accessToken; } - public String getAccessToken() { - return accessToken; - } - @Override public String getPhysicalDestinationName() { return "URL ["+getUrl()+"] cpCode ["+getCpCode()+"] action ["+getAction()+"]"; } - public String getRootDir() { - return rootDir; - } - /** - * rootDirectory on top of the url + cpCode - * @param rootDir - * @IbisDoc.optional - */ - @IbisDoc({"optional root directory", ""}) + /** Root directory (appended to the url + cpCode) */ public void setRootDir(String rootDir) { if(!rootDir.startsWith("/")) rootDir = "/" + rootDir; if(rootDir.endsWith("/")) @@ -473,15 +374,8 @@ public void setRootDir(String rootDir) { this.rootDir = rootDir; } - @Override - public String getAuthAlias() { - return authAlias; - } - /** - * @param authAlias to contain the Nonce (username) and AccessToken (password) - */ - @IbisDoc({"alias used to obtain credentials for nonce (username) and accesstoken (password)", ""}) - @Override + /** Alias used to obtain credentials for nonce (username) and accesstoken (password) */ + @Override //Overridden to prevent the super class from setting credentials public void setAuthAlias(String authAlias) { this.authAlias = authAlias; } diff --git a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageUtils.java b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageUtils.java index 817e9a06b11..cec454bfe38 100644 --- a/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageUtils.java +++ b/akamai/src/main/java/nl/nn/adapterframework/extensions/akamai/NetStorageUtils.java @@ -1,4 +1,5 @@ /* + * Copyright 2021 WeAreFrank! * Copyright 2017 Nationale-Nederlanden * Copyright 2014 Akamai Technologies http://developer.akamai.com. * @@ -16,13 +17,8 @@ */ package nl.nn.adapterframework.extensions.akamai; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.Map; import java.util.TreeSet; @@ -40,30 +36,6 @@ */ public class NetStorageUtils { - /** - * An enum of the hash algorithms supported by {@link #computeHash(java.io.InputStream, nl.nn.adapterframework.extensions.akamai.NetStorageUtils.HashAlgorithm)} - * Currently supported hashes include MD5; SHA1; SHA256 - * - * The string representation matches the java {@link java.security.MessageDigest#getInstance(String)} canonical names. - */ - public enum HashAlgorithm { - MD5("MD5"), SHA1("SHA-1"), SHA256("SHA-256"); - - /** - * Algorithm name as defined in - * {@link java.security.MessageDigest#getInstance(String)} - */ - private final String algorithm; - - private HashAlgorithm(final String algorithm) { - this.algorithm = algorithm; - } - - public String getAlgorithm() { - return this.algorithm; - } - } - /** * An enum of the keyed-hash algorithms supported by {@link #computeKeyedHash(byte[], String, nl.nn.adapterframework.extensions.akamai.NetStorageUtils.KeyedHashAlgorithm)} * Currently supported hashes include HMAC-MD5; HMAC-SHA1; HMAC-SHA256 @@ -89,71 +61,6 @@ public String getAlgorithm() { } } - /** - * Computes the hash of a given InputStream. This is a wrapper over the MessageDigest crypto functions. - * - * @param srcStream a source stream. This will be wrapped in a {@link java.io.BufferedInputStream} - * in case the source stream is not buffered - * @param hashAlgorithm the Algorithm to use to compute the hash - * @return a byte[] representation of the hash. If the InputStream is a null object - * then null will be returned. If the InputStream is empty an empty byte[] {} will be returned. - * @throws IOException If there is a problem with the InputStream during the compute of the hash - */ - public static byte[] computeHash(InputStream srcStream, HashAlgorithm hashAlgorithm) throws IOException { - if (srcStream == null) return null; - - try { - MessageDigest digest = MessageDigest.getInstance(hashAlgorithm.getAlgorithm()); - InputStream inputStream = new BufferedInputStream(srcStream); - byte[] buff = new byte[1024 ^ 2]; - - int size; - while ((size = inputStream.read(buff)) != -1) - digest.update(buff, 0, size); - - return digest.digest(); - } catch (NoSuchAlgorithmException e) { - //no-op. This will never happen since we are using an enum to limit the hash algorithms - throw new IllegalArgumentException("This should never happen! We are using an enum!", e); - } - } - - /** - * Computes the hash of a given InputStream. This is a wrapper over the MessageDigest crypto functions. - * - * @param srcBytes to generate a hash over - * @param hashAlgorithm the Algorithm to use to compute the hash - * @return a byte[] representation of the hash. If the InputStream is a null object - * then null will be returned. If the InputStream is empty an empty byte[] {} will be returned. - * @throws IOException If there is a problem with the InputStream during the compute of the hash - */ - public static byte[] computeHash(byte[] srcBytes, HashAlgorithm hashAlgorithm) throws IOException { - if (srcBytes == null) return null; - - try { - MessageDigest digest = MessageDigest.getInstance(hashAlgorithm.getAlgorithm()); - - return digest.digest(srcBytes); - } catch (NoSuchAlgorithmException e) { - //no-op. This will never happen since we are using an enum to limit the hash algorithms - throw new IllegalArgumentException("This should never happen! We are using an enum!", e); - } - } - - /** - * Converts a bytearray to a hexString - * TODO move this to Misc!? - * @param arrayBytes the input to convert - * @return a string with the converted input - */ - public static String convertByteArrayToHexString(byte[] arrayBytes) { - StringBuffer stringBuffer = new StringBuffer(); - for (int i = 0; i < arrayBytes.length; i++) { - stringBuffer.append(Integer.toString((arrayBytes[i] & 0xff) + 0x100, 16).substring(1)); - } - return stringBuffer.toString(); - } - /** * Computes the HMAC hash of a given byte[]. This is a wrapper over the Mac crypto functions. * @param data byte[] of content to hash @@ -173,21 +80,6 @@ public static byte[] computeKeyedHash(byte[] data, String key, KeyedHashAlgorith } } - /** - * Hex encoding wrapper for a byte array. The output will be 2 character padded - * string in lower case. - * @param value a byte array to encode. The assumption is that the string to encode - * is small enough to be held in memory without streaming the encoding - * @return a 2 character zero padded string in lower case - */ - public static String encodeHex(byte[] value) { - if (value == null) return null; - StringBuilder str = new StringBuilder(); - for (byte aValue : value) str.append(String.format("%02x", aValue)); - - return str.toString(); - } - /** * Lookup table for base64 encoding. */ diff --git a/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSignerTest.java b/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSignerTest.java index edd55772411..7b64f53146d 100644 --- a/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSignerTest.java +++ b/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageCmsSignerTest.java @@ -24,6 +24,7 @@ import org.apache.commons.codec.binary.Base64; import org.junit.Test; +import nl.nn.adapterframework.extensions.akamai.NetStorageSender.Action; import nl.nn.adapterframework.extensions.akamai.NetStorageUtils.KeyedHashAlgorithm; public class NetStorageCmsSignerTest { @@ -31,14 +32,14 @@ public class NetStorageCmsSignerTest { @Test public void vaidateDataAndSignHeader() throws URISyntaxException { URI uri = new URI("http://127.0.0.1/cpCode123/path"); - NetStorageAction action = new NetStorageAction("du"); - NetStorageCmsSigner signer = new NetStorageCmsSigner(uri, "myNonce", "accessToken", action) { + NetStorageRequest action = new NetStorageRequest(Action.DU); + NetStorageCmsSigner signer = new NetStorageCmsSigner(uri, "myNonce", "accessToken") { @Override protected String getAuthDataHeaderValue() { return "much auth value"; } }; - Map headers = signer.computeHeaders(); + Map headers = signer.computeHeaders(action); String sign = headers.get(NetStorageCmsSigner.AUTH_SIGN_HEADER); assertEquals("w8k5LZTRNKubFvWIqUEgcTrDZhPCo48PeHX45zxSlBU=", sign); diff --git a/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageSenderTest.java b/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageSenderTest.java index 99523d1da31..c811e2ecd6c 100644 --- a/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageSenderTest.java +++ b/akamai/src/test/java/nl/nn/adapterframework/extensions/akamai/NetStorageSenderTest.java @@ -24,9 +24,10 @@ import nl.nn.adapterframework.core.PipeLineSession; import nl.nn.adapterframework.core.SenderException; +import nl.nn.adapterframework.extensions.akamai.NetStorageSender.Action; import nl.nn.adapterframework.http.HttpResponseHandler; -import nl.nn.adapterframework.http.HttpSenderBase.HttpMethod; import nl.nn.adapterframework.http.HttpSenderTestBase; +import nl.nn.adapterframework.parameters.Parameter; import nl.nn.adapterframework.stream.Message; import nl.nn.adapterframework.util.AppConstants; @@ -51,7 +52,6 @@ public Message extractResult(HttpResponseHandler responseHandler, PipeLineSessio @Override public NetStorageSender getSender() throws Exception { NetStorageSender sender = super.getSender(false); - sender.setAction("du"); sender.setCpCode("cpCode123"); sender.setNonce("myNonce"); sender.setAccessToken(null); //As long as this is NULL, X-Akamai-ACS-Auth-Sign will be NULL @@ -61,6 +61,7 @@ public NetStorageSender getSender() throws Exception { @Test public void testContentType() throws Throwable { NetStorageSender sender = getSender(); + sender.setAction(Action.DU); sender.configure(); assertNull("no content-type should be present", sender.getFullContentType()); } @@ -68,13 +69,12 @@ public void testContentType() throws Throwable { @Test public void duAction() throws Throwable { NetStorageSender sender = getSender(); + sender.setAction(Action.DU); Message input = new Message("my/special/path/"); //Last slash should be removed! try { PipeLineSession pls = new PipeLineSession(session); - sender.setMethodType(HttpMethod.GET); - sender.configure(); sender.open(); @@ -92,14 +92,13 @@ public void duAction() throws Throwable { @Test public void duActionWithRootDir() throws Throwable { NetStorageSender sender = getSender(); + sender.setAction(Action.DU); sender.setRootDir("/my/special/"); //Start and end with a slash! Message input = new Message("path/"); //Last slash should be removed! try { PipeLineSession pls = new PipeLineSession(session); - sender.setMethodType(HttpMethod.GET); - sender.configure(); sender.open(); @@ -113,4 +112,396 @@ public void duActionWithRootDir() throws Throwable { } } } + + @Test + public void dirAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.DIR); + Message input = new Message("my/special/path/"); + + try { + PipeLineSession pls = new PipeLineSession(session); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("dirAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void deleteAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.DELETE); + Message input = new Message("my/special/path/"); + + try { + PipeLineSession pls = new PipeLineSession(session); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("deleteAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void uploadAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.UPLOAD); + Message input = new Message("my/special/path/"); + + Parameter param = new Parameter(); + param.setName("file"); + param.setSessionKey("fileMessage"); + sender.addParameter(param); + try { + Message file = new Message(""); + PipeLineSession pls = new PipeLineSession(session); + pls.put("fileMessage", file); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("uploadAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void uploadActionWithMD5Hash() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.UPLOAD); + sender.setHashAlgorithm(HashAlgorithm.MD5); + Message input = new Message("my/special/path/"); + + Parameter param = new Parameter(); + param.setName("file"); + param.setSessionKey("fileMessage"); + sender.addParameter(param); + try { + Message file = new Message(""); + PipeLineSession pls = new PipeLineSession(session); + pls.put("fileMessage", file); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("uploadActionMD5.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void uploadActionWithCustomMD5Hash() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.UPLOAD); + sender.setHashAlgorithm(HashAlgorithm.MD5); + Message input = new Message("my/special/path/"); + + Parameter hashParam = new Parameter(); + hashParam.setName("md5"); + hashParam.setValue("a1658c154b6af0fba9d93aa86e5be06f");//Matches response file but uses a different input message + sender.addParameter(hashParam); + + Parameter param = new Parameter(); + param.setName("file"); + param.setSessionKey("fileMessage"); + sender.addParameter(param); + try { + Message file = new Message("----"); + PipeLineSession pls = new PipeLineSession(session); + pls.put("fileMessage", file); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("uploadActionMD5.txt"), result.replace("----", "").trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void uploadActionWithSHA1Hash() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.UPLOAD); + sender.setHashAlgorithm(HashAlgorithm.SHA1); + Message input = new Message("my/special/path/"); + + Parameter param = new Parameter(); + param.setName("file"); + param.setSessionKey("fileMessage"); + sender.addParameter(param); + try { + Message file = new Message(""); + PipeLineSession pls = new PipeLineSession(session); + pls.put("fileMessage", file); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("uploadActionSHA1.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void uploadActionWithCustomSHA1Hash() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.UPLOAD); + sender.setHashAlgorithm(HashAlgorithm.SHA1); + Message input = new Message("my/special/path/"); + + Parameter hashParam = new Parameter(); + hashParam.setName("sha1"); + hashParam.setValue("51e8bbf813bdbcede109d13b863a58132e80b2e2");//Matches response file but uses a different input message + sender.addParameter(hashParam); + + Parameter param = new Parameter(); + param.setName("file"); + param.setSessionKey("fileMessage"); + sender.addParameter(param); + try { + Message file = new Message("----"); + PipeLineSession pls = new PipeLineSession(session); + pls.put("fileMessage", file); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("uploadActionSHA1.txt"), result.replace("----", "").trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void uploadActionWithSHA256Hash() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.UPLOAD); + sender.setHashAlgorithm(HashAlgorithm.SHA256); + Message input = new Message("my/special/path/"); + + Parameter param = new Parameter(); + param.setName("file"); + param.setSessionKey("fileMessage"); + sender.addParameter(param); + try { + Message file = new Message(""); + PipeLineSession pls = new PipeLineSession(session); + pls.put("fileMessage", file); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("uploadActionSHA256.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void uploadActionWithCustomSHA256Hash() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.UPLOAD); + Message input = new Message("my/special/path/"); + + Parameter hashParam = new Parameter(); + hashParam.setName("sha256"); + hashParam.setValue("71d1503b5afba60e212a46e4112fba56503e281224957ad8dee6034ad25f12dc"); //Matches response file but uses a different input message + sender.addParameter(hashParam); + + Parameter param = new Parameter(); + param.setName("file"); + param.setSessionKey("fileMessage"); + sender.addParameter(param); + try { + Message file = new Message("----"); + PipeLineSession pls = new PipeLineSession(session); + pls.put("fileMessage", file); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("uploadActionSHA256.txt"), result.replace("----", "").trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void mkdirAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.MKDIR); + Message input = new Message("my/special/path/"); + + try { + PipeLineSession pls = new PipeLineSession(session); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("mkdirAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void rmdirAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.RMDIR); + Message input = new Message("my/special/path/"); + + try { + PipeLineSession pls = new PipeLineSession(session); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("rmdirAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void renameAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.RENAME); + Message input = new Message("my/special/path/file1.txt"); + + Parameter param = new Parameter(); + param.setName("destination"); + param.setValue("my/other/special/path/file2.txt"); + sender.addParameter(param); + try { + PipeLineSession pls = new PipeLineSession(session); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("renameAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void mtimeAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.MTIME); + Message input = new Message("my/special/path/"); + + Parameter param = new Parameter(); + param.setName("mtime"); + param.setValue("1633945058"); + sender.addParameter(param); + try { + PipeLineSession pls = new PipeLineSession(session); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("mtimeAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } + + @Test + public void downloadAction() throws Throwable { + NetStorageSender sender = getSender(); + sender.setAction(Action.DOWNLOAD); + Message input = new Message("my/special/path/"); + + try { + PipeLineSession pls = new PipeLineSession(session); + + sender.configure(); + sender.open(); + + String result = sender.sendMessage(input, pls).asString(); + assertEqualsIgnoreCRLF(getFile("downloadAction.txt"), result.trim()); + } catch (SenderException e) { + throw e.getCause(); + } finally { + if (sender != null) { + sender.close(); + } + } + } } \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/deleteAction.txt b/akamai/src/test/resources/Http/Responses/deleteAction.txt new file mode 100644 index 00000000000..1e6091e718f --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/deleteAction.txt @@ -0,0 +1,4 @@ +PUT http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=delete&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/dirAction.txt b/akamai/src/test/resources/Http/Responses/dirAction.txt new file mode 100644 index 00000000000..7a8f21255cf --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/dirAction.txt @@ -0,0 +1,4 @@ +GET http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=dir&format=xml&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/downloadAction.txt b/akamai/src/test/resources/Http/Responses/downloadAction.txt new file mode 100644 index 00000000000..f5c94a9eb77 --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/downloadAction.txt @@ -0,0 +1,4 @@ +GET http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=download&format=xml&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null \ No newline at end of file diff --git a/akamai/src/test/resources/nl/nn/adapterframework/http/response/duAction.txt b/akamai/src/test/resources/Http/Responses/duAction.txt similarity index 100% rename from akamai/src/test/resources/nl/nn/adapterframework/http/response/duAction.txt rename to akamai/src/test/resources/Http/Responses/duAction.txt diff --git a/akamai/src/test/resources/Http/Responses/mkdirAction.txt b/akamai/src/test/resources/Http/Responses/mkdirAction.txt new file mode 100644 index 00000000000..cc78f18c3e1 --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/mkdirAction.txt @@ -0,0 +1,4 @@ +PUT http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=mkdir&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/mtimeAction.txt b/akamai/src/test/resources/Http/Responses/mtimeAction.txt new file mode 100644 index 00000000000..f1b75879f93 --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/mtimeAction.txt @@ -0,0 +1,4 @@ +POST http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=mtime&mtime=1633945058&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/renameAction.txt b/akamai/src/test/resources/Http/Responses/renameAction.txt new file mode 100644 index 00000000000..52d5e357143 --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/renameAction.txt @@ -0,0 +1,4 @@ +POST http://127.0.0.1/cpCode123/my/special/path/file1.txt HTTP/1.1 +X-Akamai-ACS-Action: action=rename&destination=my%2Fother%2Fspecial%2Fpath%2Ffile2.txt&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/rmdirAction.txt b/akamai/src/test/resources/Http/Responses/rmdirAction.txt new file mode 100644 index 00000000000..77281d42a43 --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/rmdirAction.txt @@ -0,0 +1,4 @@ +POST http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=rmdir&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/uploadAction.txt b/akamai/src/test/resources/Http/Responses/uploadAction.txt new file mode 100644 index 00000000000..5a3e63fd415 --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/uploadAction.txt @@ -0,0 +1,6 @@ +PUT http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=upload&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null + + \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/uploadActionMD5.txt b/akamai/src/test/resources/Http/Responses/uploadActionMD5.txt new file mode 100644 index 00000000000..7fc5b73f97a --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/uploadActionMD5.txt @@ -0,0 +1,6 @@ +PUT http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=upload&md5=a1658c154b6af0fba9d93aa86e5be06f&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null + + \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/uploadActionSHA1.txt b/akamai/src/test/resources/Http/Responses/uploadActionSHA1.txt new file mode 100644 index 00000000000..8d11ee79a6f --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/uploadActionSHA1.txt @@ -0,0 +1,6 @@ +PUT http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=upload&sha1=51e8bbf813bdbcede109d13b863a58132e80b2e2&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null + + \ No newline at end of file diff --git a/akamai/src/test/resources/Http/Responses/uploadActionSHA256.txt b/akamai/src/test/resources/Http/Responses/uploadActionSHA256.txt new file mode 100644 index 00000000000..72f2d418eb5 --- /dev/null +++ b/akamai/src/test/resources/Http/Responses/uploadActionSHA256.txt @@ -0,0 +1,6 @@ +PUT http://127.0.0.1/cpCode123/my/special/path HTTP/1.1 +X-Akamai-ACS-Action: action=upload&sha256=71d1503b5afba60e212a46e4112fba56503e281224957ad8dee6034ad25f12dc&version=1 +X-Akamai-ACS-Auth-Data: 5, 0.0.0.0, 0.0.0.0, timestamp, timestamp, myNonce +X-Akamai-ACS-Auth-Sign: null + + \ No newline at end of file diff --git a/core/src/main/java/nl/nn/adapterframework/ftp/FtpSession.java b/core/src/main/java/nl/nn/adapterframework/ftp/FtpSession.java index e8292c48ac9..7073534b48a 100644 --- a/core/src/main/java/nl/nn/adapterframework/ftp/FtpSession.java +++ b/core/src/main/java/nl/nn/adapterframework/ftp/FtpSession.java @@ -1009,8 +1009,8 @@ public boolean isAllowSelfSignedCertificates() { } /** - * The CertificateExpiredException is ignored when set to true - * @IbisDoc.default false + * CertificateExpiredExceptions are ignored when set to true + * @ff.default false */ @IbisDoc({"57", "when true, the certificateExpiredException is ignored", "false"}) public void setIgnoreCertificateExpiredException(boolean b) { diff --git a/core/src/main/java/nl/nn/adapterframework/http/HttpSenderBase.java b/core/src/main/java/nl/nn/adapterframework/http/HttpSenderBase.java index eeb3ff0fe4c..807e5e3c7cf 100644 --- a/core/src/main/java/nl/nn/adapterframework/http/HttpSenderBase.java +++ b/core/src/main/java/nl/nn/adapterframework/http/HttpSenderBase.java @@ -1043,8 +1043,8 @@ public boolean isAllowSelfSignedCertificates() { } /** - * The CertificateExpiredException is ignored when set to true - * @IbisDoc.default false + * CertificateExpiredExceptions are ignored when set to true + * @ff.default false */ @IbisDoc({"57", "when true, the certificateExpiredException is ignored", "false"}) public void setIgnoreCertificateExpiredException(boolean b) { diff --git a/core/src/main/java/nl/nn/adapterframework/stream/Message.java b/core/src/main/java/nl/nn/adapterframework/stream/Message.java index dd5de6e58b2..4cd82330e3e 100644 --- a/core/src/main/java/nl/nn/adapterframework/stream/Message.java +++ b/core/src/main/java/nl/nn/adapterframework/stream/Message.java @@ -147,7 +147,7 @@ private void preserve(boolean deepPreserve) throws IOException { } /** - * @Deprecated Please avoid the use of the raw object. + * @deprecated Please avoid the use of the raw object. */ @Deprecated public Object asObject() { diff --git a/core/src/test/java/nl/nn/adapterframework/http/HttpResponseMock.java b/core/src/test/java/nl/nn/adapterframework/http/HttpResponseMock.java index 61e963096ba..9774359a686 100644 --- a/core/src/test/java/nl/nn/adapterframework/http/HttpResponseMock.java +++ b/core/src/test/java/nl/nn/adapterframework/http/HttpResponseMock.java @@ -151,7 +151,8 @@ public InputStream doPost(HttpHost host, HttpPost request, HttpContext context) String content = new String(baos.toByteArray()); content = content.replaceAll(boundary, "IGNORE"); response.append(content); - } else { + } + else if(entity != null) { Header contentTypeHeader = request.getEntity().getContentType(); if(contentTypeHeader != null) { response.append(contentTypeHeader.getName() + ": " + contentTypeHeader.getValue() + lineSeparator); @@ -176,13 +177,16 @@ public InputStream doPut(HttpHost host, HttpPut request, HttpContext context) th appendHeaders(request, response); - Header contentTypeHeader = request.getEntity().getContentType(); - if(contentTypeHeader != null) { - response.append(contentTypeHeader.getName() + ": " + contentTypeHeader.getValue() + lineSeparator); + if(request.getEntity() != null) { //If an entity is present + Header contentTypeHeader = request.getEntity().getContentType(); + if(contentTypeHeader != null) { + response.append(contentTypeHeader.getName() + ": " + contentTypeHeader.getValue() + lineSeparator); + } + + response.append(lineSeparator); + response.append(EntityUtils.toString(request.getEntity())); } - response.append(lineSeparator); - response.append(EntityUtils.toString(request.getEntity())); return new ByteArrayInputStream(response.toString().getBytes()); } diff --git a/core/src/test/java/nl/nn/adapterframework/http/HttpSenderTestBase.java b/core/src/test/java/nl/nn/adapterframework/http/HttpSenderTestBase.java index c69111a8a5d..642949c84d4 100644 --- a/core/src/test/java/nl/nn/adapterframework/http/HttpSenderTestBase.java +++ b/core/src/test/java/nl/nn/adapterframework/http/HttpSenderTestBase.java @@ -30,7 +30,7 @@ import nl.nn.adapterframework.testutil.TestFileUtils; public abstract class HttpSenderTestBase extends SenderTestBase { - private final String BASEDIR = "/nl/nn/adapterframework/http/response/"; + private final String BASEDIR = "/Http/Responses/"; public S getSender() throws Exception { return getSender(true); diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/binaryHttpPostJSON.txt b/core/src/test/resources/Http/Responses/binaryHttpPostJSON.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/binaryHttpPostJSON.txt rename to core/src/test/resources/Http/Responses/binaryHttpPostJSON.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/binaryHttpPostPDF.txt b/core/src/test/resources/Http/Responses/binaryHttpPostPDF.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/binaryHttpPostPDF.txt rename to core/src/test/resources/Http/Responses/binaryHttpPostPDF.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/binaryHttpPutJSON.txt b/core/src/test/resources/Http/Responses/binaryHttpPutJSON.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/binaryHttpPutJSON.txt rename to core/src/test/resources/Http/Responses/binaryHttpPutJSON.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/parametersToSkip.txt b/core/src/test/resources/Http/Responses/parametersToSkip.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/parametersToSkip.txt rename to core/src/test/resources/Http/Responses/parametersToSkip.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/paramsWithoutValue.txt b/core/src/test/resources/Http/Responses/paramsWithoutValue.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/paramsWithoutValue.txt rename to core/src/test/resources/Http/Responses/paramsWithoutValue.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpCharset.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpCharset.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpCharset.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpCharset.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGet.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpGet.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGet.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpGet.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetEncodeMessage.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpGetEncodeMessage.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetEncodeMessage.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpGetEncodeMessage.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithContentType.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpGetWithContentType.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithContentType.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpGetWithContentType.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithContentTypeAndCharset.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpGetWithContentTypeAndCharset.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithContentTypeAndCharset.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpGetWithContentTypeAndCharset.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithParams.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpGetWithParams.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithParams.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpGetWithParams.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithUrlParamAndPath.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpGetWithUrlParamAndPath.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithUrlParamAndPath.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpGetWithUrlParamAndPath.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithoutPRC.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpGetWithoutPRC.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpGetWithoutPRC.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpGetWithoutPRC.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpMtom.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpMtom.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpMtom.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpMtom.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpMultipart.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpMultipart.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpMultipart.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpMultipart.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPatch.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPatch.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPatch.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPatch.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPost.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPost.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPost.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPost.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostAppendParamsToBody.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPostAppendParamsToBody.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostAppendParamsToBody.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPostAppendParamsToBody.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostAppendParamsToBodyAndEmptyBody.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPostAppendParamsToBodyAndEmptyBody.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostAppendParamsToBodyAndEmptyBody.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPostAppendParamsToBodyAndEmptyBody.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostEncodeMessage.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPostEncodeMessage.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostEncodeMessage.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPostEncodeMessage.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostJSON.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPostJSON.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostJSON.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPostJSON.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostUrlEncoded.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPostUrlEncoded.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPostUrlEncoded.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPostUrlEncoded.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPut.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPut.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPut.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPut.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPutJSON.txt b/core/src/test/resources/Http/Responses/simpleMockedHttpPutJSON.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedHttpPutJSON.txt rename to core/src/test/resources/Http/Responses/simpleMockedHttpPutJSON.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartHttp1.txt b/core/src/test/resources/Http/Responses/simpleMockedMultipartHttp1.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartHttp1.txt rename to core/src/test/resources/Http/Responses/simpleMockedMultipartHttp1.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartHttp2.txt b/core/src/test/resources/Http/Responses/simpleMockedMultipartHttp2.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartHttp2.txt rename to core/src/test/resources/Http/Responses/simpleMockedMultipartHttp2.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartHttp3.txt b/core/src/test/resources/Http/Responses/simpleMockedMultipartHttp3.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartHttp3.txt rename to core/src/test/resources/Http/Responses/simpleMockedMultipartHttp3.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartMtom1.txt b/core/src/test/resources/Http/Responses/simpleMockedMultipartMtom1.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartMtom1.txt rename to core/src/test/resources/Http/Responses/simpleMockedMultipartMtom1.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartMtom2.txt b/core/src/test/resources/Http/Responses/simpleMockedMultipartMtom2.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartMtom2.txt rename to core/src/test/resources/Http/Responses/simpleMockedMultipartMtom2.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartMtom3.txt b/core/src/test/resources/Http/Responses/simpleMockedMultipartMtom3.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedMultipartMtom3.txt rename to core/src/test/resources/Http/Responses/simpleMockedMultipartMtom3.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedRestGet.txt b/core/src/test/resources/Http/Responses/simpleMockedRestGet.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedRestGet.txt rename to core/src/test/resources/Http/Responses/simpleMockedRestGet.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedRestPost.txt b/core/src/test/resources/Http/Responses/simpleMockedRestPost.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedRestPost.txt rename to core/src/test/resources/Http/Responses/simpleMockedRestPost.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWss.txt b/core/src/test/resources/Http/Responses/simpleMockedWss.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWss.txt rename to core/src/test/resources/Http/Responses/simpleMockedWss.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMtom.txt b/core/src/test/resources/Http/Responses/simpleMockedWssMtom.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMtom.txt rename to core/src/test/resources/Http/Responses/simpleMockedWssMtom.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMultipart.txt b/core/src/test/resources/Http/Responses/simpleMockedWssMultipart.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMultipart.txt rename to core/src/test/resources/Http/Responses/simpleMockedWssMultipart.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMultipart2.txt b/core/src/test/resources/Http/Responses/simpleMockedWssMultipart2.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMultipart2.txt rename to core/src/test/resources/Http/Responses/simpleMockedWssMultipart2.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMultipartMtom.txt b/core/src/test/resources/Http/Responses/simpleMockedWssMultipartMtom.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssMultipartMtom.txt rename to core/src/test/resources/Http/Responses/simpleMockedWssMultipartMtom.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssSoapAction.txt b/core/src/test/resources/Http/Responses/simpleMockedWssSoapAction.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/simpleMockedWssSoapAction.txt rename to core/src/test/resources/Http/Responses/simpleMockedWssSoapAction.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/specialCharactersDoubleEscaped.txt b/core/src/test/resources/Http/Responses/specialCharactersDoubleEscaped.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/specialCharactersDoubleEscaped.txt rename to core/src/test/resources/Http/Responses/specialCharactersDoubleEscaped.txt diff --git a/core/src/test/resources/nl/nn/adapterframework/http/response/specialCharactersInURLParam.txt b/core/src/test/resources/Http/Responses/specialCharactersInURLParam.txt similarity index 100% rename from core/src/test/resources/nl/nn/adapterframework/http/response/specialCharactersInURLParam.txt rename to core/src/test/resources/Http/Responses/specialCharactersInURLParam.txt diff --git a/frankDoc/src/main/java/nl/nn/adapterframework/frankdoc/model/FrankAttribute.java b/frankDoc/src/main/java/nl/nn/adapterframework/frankdoc/model/FrankAttribute.java index 3a20796687c..bf31b106ff2 100644 --- a/frankDoc/src/main/java/nl/nn/adapterframework/frankdoc/model/FrankAttribute.java +++ b/frankDoc/src/main/java/nl/nn/adapterframework/frankdoc/model/FrankAttribute.java @@ -54,7 +54,7 @@ public String toString() { * These annotations should cause attributes to not exist. If an attribute should * not exist, then it also should not be inherited. */ - private @Getter(onMethod = @__(@Override)) @Setter(AccessLevel.PACKAGE) boolean excluded = false; + private @Getter @Setter(AccessLevel.PACKAGE) boolean excluded = false; public FrankAttribute(String name, FrankElement attributeOwner) { super(attributeOwner); diff --git a/pom.xml b/pom.xml index b807fa99394..f5d11f9e290 100644 --- a/pom.xml +++ b/pom.xml @@ -434,6 +434,10 @@ a Default element + + ff.ignoreTypeMembership + X + true