From 17f5f109d1bdc680dd55d79ed98c2314e20ecf1c Mon Sep 17 00:00:00 2001 From: Sina Madani Date: Mon, 2 Dec 2024 17:28:23 +0000 Subject: [PATCH] refactor: Use Header auth in SmsClient (#555) * Use Header auth in Send SMS and NI v1 Basic Insight endpoints * Remove UnsupportedEncodingException catch block * .gitignore BugRepro and use template instead * Check for package updates monthly --- .github/dependabot.yml | 2 +- .gitignore | 3 +- .../com/vonage/client/AbstractMethod.java | 28 ++++------- .../client/auth/ApiKeyHeaderAuthMethod.java | 2 + .../vonage/client/insight/InsightClient.java | 12 +++-- .../java/com/vonage/client/sms/SmsClient.java | 3 +- src/test/java/BugRepro.java.template | 29 +++++++++++ .../com/vonage/client/AbstractMethodTest.java | 8 ++-- src/test/java/com/vonage/client/BugRepro.java | 48 ------------------- .../client/insight/InsightClientTest.java | 21 ++++++++ .../insight/InsightEndpointTestSpec.java | 10 ---- .../client/sms/SmsEndpointTestSpec.java | 4 +- 12 files changed, 80 insertions(+), 90 deletions(-) create mode 100644 src/test/java/BugRepro.java.template delete mode 100644 src/test/java/com/vonage/client/BugRepro.java diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 31701f90a..164c5635d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ updates: - package-ecosystem: 'maven' directory: '/' schedule: - interval: 'weekly' + interval: 'monthly' commit-message: prefix: 'build' ignore: diff --git a/.gitignore b/.gitignore index 7da56e3be..40db39a70 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ dependency-reduced-pom.xml /javadoc /test.properties archive/ -binvalid_application_key.pem +bin/ gradle.properties vonage-sdk.jar publishing @@ -21,3 +21,4 @@ out/ .DS_Store pom.xml.releaseBackup pom.xml.versionsBackup +src/test/java/BugRepro.java diff --git a/src/main/java/com/vonage/client/AbstractMethod.java b/src/main/java/com/vonage/client/AbstractMethod.java index 932493056..e2e5367ca 100644 --- a/src/main/java/com/vonage/client/AbstractMethod.java +++ b/src/main/java/com/vonage/client/AbstractMethod.java @@ -22,7 +22,6 @@ import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.AbstractMap; import java.util.Set; @@ -71,25 +70,20 @@ protected ResultT postProcessParsedResponse(ResultT response) { */ @Override public ResultT execute(RequestT request) throws VonageResponseParseException, VonageClientException { - try { - HttpUriRequest httpRequest = applyAuth(makeRequest(request)) - .setHeader("User-Agent", httpWrapper.getUserAgent()) - .setCharset(StandardCharsets.UTF_8).build(); + HttpUriRequest httpRequest = applyAuth(makeRequest(request)) + .setHeader("User-Agent", httpWrapper.getUserAgent()) + .setCharset(StandardCharsets.UTF_8).build(); - try (CloseableHttpResponse response = httpWrapper.getHttpClient().execute(httpRequest)) { - try { - return postProcessParsedResponse(parseResponse(response)); - } - catch (IOException iox) { - throw new VonageResponseParseException(iox); - } + try (CloseableHttpResponse response = httpWrapper.getHttpClient().execute(httpRequest)) { + try { + return postProcessParsedResponse(parseResponse(response)); } catch (IOException iox) { - throw new VonageMethodFailedException("Something went wrong while executing the HTTP request.", iox); + throw new VonageResponseParseException(iox); } } - catch (UnsupportedEncodingException uex) { - throw new VonageUnexpectedException("UTF-8 encoding is not supported by this JVM.", uex); + catch (IOException iox) { + throw new VonageMethodFailedException("Something went wrong while executing the HTTP request.", iox); } } @@ -140,10 +134,8 @@ protected AuthMethod getAuthMethod() throws VonageUnexpectedException { * @param request A RequestT representing input to the REST call to be made * * @return A ResultT representing the response from the executed REST call - * - * @throws UnsupportedEncodingException if UTF-8 encoding is not supported by the JVM */ - protected abstract RequestBuilder makeRequest(RequestT request) throws UnsupportedEncodingException; + protected abstract RequestBuilder makeRequest(RequestT request); /** * Construct a ResultT representing the contents of the HTTP response returned from the Vonage Voice API. diff --git a/src/main/java/com/vonage/client/auth/ApiKeyHeaderAuthMethod.java b/src/main/java/com/vonage/client/auth/ApiKeyHeaderAuthMethod.java index 6d268d82e..786d5c5aa 100644 --- a/src/main/java/com/vonage/client/auth/ApiKeyHeaderAuthMethod.java +++ b/src/main/java/com/vonage/client/auth/ApiKeyHeaderAuthMethod.java @@ -41,7 +41,9 @@ public String getApiKey() { * Converts this to a {@linkplain QueryParamsAuthMethod}. * * @return A new {@linkplain ApiKeyQueryParamsAuthMethod} with this object's API key and secret. + * @deprecated This will be removed in a future release. */ + @Deprecated public QueryParamsAuthMethod asQueryParams() { return new ApiKeyQueryParamsAuthMethod(apiKey, apiSecret); } diff --git a/src/main/java/com/vonage/client/insight/InsightClient.java b/src/main/java/com/vonage/client/insight/InsightClient.java index a7c8e4115..0cab1b930 100644 --- a/src/main/java/com/vonage/client/insight/InsightClient.java +++ b/src/main/java/com/vonage/client/insight/InsightClient.java @@ -16,7 +16,9 @@ package com.vonage.client.insight; import com.vonage.client.*; +import com.vonage.client.auth.ApiKeyHeaderAuthMethod; import com.vonage.client.auth.ApiKeyQueryParamsAuthMethod; +import com.vonage.client.auth.AuthMethod; import com.vonage.client.auth.SignatureAuthMethod; import com.vonage.client.common.HttpMethod; import java.util.function.Function; @@ -38,10 +40,10 @@ public class InsightClient { public InsightClient(HttpWrapper wrapper) { @SuppressWarnings("unchecked") final class Endpoint extends DynamicEndpoint { - Endpoint(Function pathGetter, R... type) { + Endpoint(Function pathGetter, Class auth, R... type) { super(DynamicEndpoint. builder(type) .wrapper(wrapper).requestMethod(HttpMethod.POST) - .authMethod(SignatureAuthMethod.class, ApiKeyQueryParamsAuthMethod.class) + .authMethod(SignatureAuthMethod.class, auth) .pathGetter((de, req) -> { String base = de.getHttpWrapper().getHttpConfig().getApiBaseUri(); return base + "/ni/" + pathGetter.apply(req) + "/json"; @@ -50,9 +52,9 @@ final class Endpoint extends DynamicEndpoint { } } - basic = new Endpoint<>(req -> "basic"); - standard = new Endpoint<>(req -> "standard"); - advanced = new Endpoint<>(req -> "advanced" + (req.isAsync() ? "/async" : "")); + basic = new Endpoint<>(req -> "basic", ApiKeyHeaderAuthMethod.class); + standard = new Endpoint<>(req -> "standard", ApiKeyQueryParamsAuthMethod.class); + advanced = new Endpoint<>(req -> "advanced" + (req.isAsync() ? "/async" : ""), ApiKeyQueryParamsAuthMethod.class); } /** diff --git a/src/main/java/com/vonage/client/sms/SmsClient.java b/src/main/java/com/vonage/client/sms/SmsClient.java index 423e0979c..8a9a53c20 100644 --- a/src/main/java/com/vonage/client/sms/SmsClient.java +++ b/src/main/java/com/vonage/client/sms/SmsClient.java @@ -16,6 +16,7 @@ package com.vonage.client.sms; import com.vonage.client.*; +import com.vonage.client.auth.ApiKeyHeaderAuthMethod; import com.vonage.client.auth.ApiKeyQueryParamsAuthMethod; import com.vonage.client.auth.SignatureAuthMethod; import com.vonage.client.common.HttpMethod; @@ -40,7 +41,7 @@ class Endpoint extends DynamicEndpoint { Endpoint() { super(DynamicEndpoint. builder(SmsSubmissionResponse.class) .wrapper(wrapper).requestMethod(HttpMethod.POST) - .authMethod(SignatureAuthMethod.class, ApiKeyQueryParamsAuthMethod.class) + .authMethod(SignatureAuthMethod.class, ApiKeyHeaderAuthMethod.class) .urlFormEncodedContentType(true).pathGetter((de, req) -> de.getHttpWrapper().getHttpConfig().getRestBaseUri() + "/sms/json" ) diff --git a/src/test/java/BugRepro.java.template b/src/test/java/BugRepro.java.template new file mode 100644 index 000000000..7816737ce --- /dev/null +++ b/src/test/java/BugRepro.java.template @@ -0,0 +1,29 @@ +import com.vonage.client.*; +import java.util.*; + +/** + * Convenience class for debugging / live testing. You should copy this file and remove the + * `.template` extension from the filename to make it usable. + */ +public class BugRepro { + public static void main(String[] args) throws Throwable { + String TO_NUMBER = System.getenv("TO_NUMBER"); + + VonageClient client = VonageClient.builder() + .httpConfig(HttpConfig.builder().timeoutMillis(12_000).build()) + .apiKey(System.getenv("VONAGE_API_KEY")) + .apiSecret(System.getenv("VONAGE_API_SECRET")) + .applicationId(System.getenv("VONAGE_APPLICATION_ID")) + .privateKeyPath(System.getenv("VONAGE_PRIVATE_KEY_PATH")) + .build(); + + try { + // Debug code here + + System.out.println("Success"); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/src/test/java/com/vonage/client/AbstractMethodTest.java b/src/test/java/com/vonage/client/AbstractMethodTest.java index fc67a351f..9699e7e4a 100644 --- a/src/test/java/com/vonage/client/AbstractMethodTest.java +++ b/src/test/java/com/vonage/client/AbstractMethodTest.java @@ -63,7 +63,7 @@ protected Set> getAcceptableAuthMethods() { } @Override - public RequestBuilder makeRequest(String request) throws UnsupportedEncodingException { + public RequestBuilder makeRequest(String request) { return RequestBuilder.get(request); } @@ -119,7 +119,7 @@ public void setUp() throws Exception { when(mockWrapper.getAuthCollection()).thenReturn(mockAuthMethods); } - ConcreteMethod mockJsonResponse(String json, boolean failing) throws Exception { + ConcreteMethod mockJsonResponse(String json, boolean failing) { ConcreteMethod method = spy(failing ? new ConcreteMethodFailingParse(mockWrapper) : new ConcreteMethod(mockWrapper) ); @@ -311,8 +311,8 @@ protected AuthMethod getAuthMethod() throws VonageUnexpectedException { } @Override - public RequestBuilder makeRequest(String request) throws UnsupportedEncodingException { - return builder.setEntity(new StringEntity(request)); + public RequestBuilder makeRequest(String request) { + return builder.setEntity(new StringEntity(request, ContentType.TEXT_PLAIN)); } } return new LocalMethod(); diff --git a/src/test/java/com/vonage/client/BugRepro.java b/src/test/java/com/vonage/client/BugRepro.java deleted file mode 100644 index 3f1e92c07..000000000 --- a/src/test/java/com/vonage/client/BugRepro.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2024 Vonage - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.vonage.client; - -/** - * Convenience class for debugging / live testing. - */ -public class BugRepro { - public static void main(String[] args) throws Throwable { - String TO_NUMBER = System.getenv("TO_NUMBER"); - - VonageClient client = VonageClient.builder() - .httpConfig(HttpConfig.builder().timeoutMillis(12_000).build()) - .apiKey(System.getenv("VONAGE_API_KEY")) - .apiSecret(System.getenv("VONAGE_API_SECRET")) - .applicationId(System.getenv("VONAGE_APPLICATION_ID")) - .privateKeyPath(System.getenv("VONAGE_PRIVATE_KEY_PATH")) - .build(); - - try { - // Debug code here - - System.out.println("Success"); - } - catch (Exception ex) { - ex.printStackTrace(); - } - } -} diff --git a/src/test/java/com/vonage/client/insight/InsightClientTest.java b/src/test/java/com/vonage/client/insight/InsightClientTest.java index ebda8d5e9..759ca57f1 100644 --- a/src/test/java/com/vonage/client/insight/InsightClientTest.java +++ b/src/test/java/com/vonage/client/insight/InsightClientTest.java @@ -17,10 +17,16 @@ import com.vonage.client.AbstractClientTest; import com.vonage.client.RestEndpoint; +import com.vonage.client.auth.ApiKeyHeaderAuthMethod; +import com.vonage.client.auth.ApiKeyQueryParamsAuthMethod; +import com.vonage.client.auth.AuthMethod; +import com.vonage.client.auth.SignatureAuthMethod; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; import java.math.BigDecimal; +import java.util.Collection; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; public class InsightClientTest extends AbstractClientTest { @@ -222,6 +228,11 @@ protected RestEndpoint endpoint() { return client.basic; } + @Override + protected Collection> expectedAuthMethods() { + return List.of(SignatureAuthMethod.class, ApiKeyHeaderAuthMethod.class); + } + @Override protected String expectedEndpointUri(BasicInsightRequest request) { return "/ni/basic/json"; @@ -254,6 +265,11 @@ protected RestEndpoint endpoint return client.standard; } + @Override + protected Collection> expectedAuthMethods() { + return List.of(SignatureAuthMethod.class, ApiKeyQueryParamsAuthMethod.class); + } + @Override protected String expectedEndpointUri(StandardInsightRequest request) { return "/ni/standard/json"; @@ -288,6 +304,11 @@ protected RestEndpoint endpoint return client.advanced; } + @Override + protected Collection> expectedAuthMethods() { + return List.of(SignatureAuthMethod.class, ApiKeyQueryParamsAuthMethod.class); + } + @Override protected String expectedEndpointUri(AdvancedInsightRequest request) { return request.isAsync() ? "/ni/advanced/async/json" : "/ni/advanced/json"; diff --git a/src/test/java/com/vonage/client/insight/InsightEndpointTestSpec.java b/src/test/java/com/vonage/client/insight/InsightEndpointTestSpec.java index 4e317c6e6..e0241c8fd 100644 --- a/src/test/java/com/vonage/client/insight/InsightEndpointTestSpec.java +++ b/src/test/java/com/vonage/client/insight/InsightEndpointTestSpec.java @@ -17,21 +17,11 @@ import com.vonage.client.DynamicEndpointTestSpec; import com.vonage.client.VonageApiResponseException; -import com.vonage.client.auth.ApiKeyQueryParamsAuthMethod; -import com.vonage.client.auth.AuthMethod; -import com.vonage.client.auth.SignatureAuthMethod; import com.vonage.client.common.HttpMethod; -import java.util.Arrays; -import java.util.Collection; import java.util.Map; abstract class InsightEndpointTestSpec extends DynamicEndpointTestSpec { - @Override - protected Collection> expectedAuthMethods() { - return Arrays.asList(SignatureAuthMethod.class, ApiKeyQueryParamsAuthMethod.class); - } - @Override protected Class expectedResponseExceptionType() { return VonageApiResponseException.class; diff --git a/src/test/java/com/vonage/client/sms/SmsEndpointTestSpec.java b/src/test/java/com/vonage/client/sms/SmsEndpointTestSpec.java index 54c19ae26..2d3533508 100644 --- a/src/test/java/com/vonage/client/sms/SmsEndpointTestSpec.java +++ b/src/test/java/com/vonage/client/sms/SmsEndpointTestSpec.java @@ -18,7 +18,7 @@ import com.vonage.client.DynamicEndpointTestSpec; import com.vonage.client.RestEndpoint; import com.vonage.client.VonageApiResponseException; -import com.vonage.client.auth.ApiKeyQueryParamsAuthMethod; +import com.vonage.client.auth.ApiKeyHeaderAuthMethod; import com.vonage.client.auth.AuthMethod; import com.vonage.client.auth.SignatureAuthMethod; import com.vonage.client.common.HttpMethod; @@ -47,7 +47,7 @@ protected HttpMethod expectedHttpMethod() { @Override protected Collection> expectedAuthMethods() { - return Arrays.asList(SignatureAuthMethod.class, ApiKeyQueryParamsAuthMethod.class); + return Arrays.asList(SignatureAuthMethod.class, ApiKeyHeaderAuthMethod.class); } @Override