From 8c33b7ddcf5b78b759d8e612048419f0f80fbe9c Mon Sep 17 00:00:00 2001 From: Tokuhiro Matsuno Date: Thu, 16 Nov 2023 16:54:34 +0900 Subject: [PATCH] =?UTF-8?q?[BREAKING=20CHANGE]=20Drop=20authentication=20r?= =?UTF-8?q?elated=20arguments=20from=20ChannelA=E2=80=A6=20(#1157)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …ccessTokenClient. The endpoint is not require authenticaiton informantion. --- .../.openapi-generator/FILES | 1 + .../client/ChannelAccessTokenClient.java | 20 +- .../ChannelAccessTokenClientExTest.java | 2 +- .../client/ChannelAccessTokenClientTest.java | 231 ------------------ generator/pom.xml | 4 +- .../resources/line-java-codegen/api.pebble | 4 +- .../line-java-codegen/api_test.pebble | 4 +- .../codegen/LineJavaCodegenGeneratorTest.java | 60 +++-- .../ChannelAccessTokenIntegrationTest.java | 2 +- .../LineBotAutoConfiguration.java | 6 +- 10 files changed, 57 insertions(+), 277 deletions(-) delete mode 100644 clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientTest.java diff --git a/clients/line-channel-access-token-client/.openapi-generator/FILES b/clients/line-channel-access-token-client/.openapi-generator/FILES index c3aabe0b7..f819d7436 100644 --- a/clients/line-channel-access-token-client/.openapi-generator/FILES +++ b/clients/line-channel-access-token-client/.openapi-generator/FILES @@ -5,3 +5,4 @@ src/main/java/com/linecorp/bot/oauth/model/IssueChannelAccessTokenResponse.java src/main/java/com/linecorp/bot/oauth/model/IssueShortLivedChannelAccessTokenResponse.java src/main/java/com/linecorp/bot/oauth/model/IssueStatelessChannelAccessTokenResponse.java src/main/java/com/linecorp/bot/oauth/model/VerifyChannelAccessTokenResponse.java +src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientTest.java diff --git a/clients/line-channel-access-token-client/src/main/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClient.java b/clients/line-channel-access-token-client/src/main/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClient.java index 7152af7ff..aebab4a67 100644 --- a/clients/line-channel-access-token-client/src/main/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClient.java +++ b/clients/line-channel-access-token-client/src/main/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClient.java @@ -20,9 +20,8 @@ */ package com.linecorp.bot.oauth.client; -import com.linecorp.bot.client.base.ApiAuthenticatedClientBuilder; +import com.linecorp.bot.client.base.ApiClientBuilder; import com.linecorp.bot.client.base.Result; -import com.linecorp.bot.client.base.channel.ChannelTokenSupplier; import com.linecorp.bot.oauth.model.ChannelAccessTokenKeyIdsResponse; import com.linecorp.bot.oauth.model.IssueChannelAccessTokenResponse; import com.linecorp.bot.oauth.model.IssueShortLivedChannelAccessTokenResponse; @@ -168,21 +167,10 @@ CompletableFuture> verifyChannelToken( CompletableFuture> verifyChannelTokenByJWT( @Query("access_token") String accessToken); - public static ApiAuthenticatedClientBuilder builder( - String channelToken) { - return new ApiAuthenticatedClientBuilder<>( + public static ApiClientBuilder builder() { + return new ApiClientBuilder<>( URI.create("https://api.line.me"), ChannelAccessTokenClient.class, - new ChannelAccessTokenExceptionBuilder(), - channelToken); - } - - public static ApiAuthenticatedClientBuilder builder( - ChannelTokenSupplier channelTokenSupplier) { - return new ApiAuthenticatedClientBuilder<>( - URI.create("https://api.line.me"), - ChannelAccessTokenClient.class, - new ChannelAccessTokenExceptionBuilder(), - channelTokenSupplier); + new ChannelAccessTokenExceptionBuilder()); } } diff --git a/clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientExTest.java b/clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientExTest.java index e9a32378c..b823643a3 100644 --- a/clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientExTest.java +++ b/clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientExTest.java @@ -60,7 +60,7 @@ public void setUp() { wireMockServer.start(); WireMock.configureFor("localhost", wireMockServer.port()); - target = ChannelAccessTokenClient.builder("MY_ACCESS_TOKEN") + target = ChannelAccessTokenClient.builder() .apiEndPoint(URI.create(wireMockServer.baseUrl())) .build(); } diff --git a/clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientTest.java b/clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientTest.java deleted file mode 100644 index ec0179cda..000000000 --- a/clients/line-channel-access-token-client/src/test/java/com/linecorp/bot/oauth/client/ChannelAccessTokenClientTest.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2023 LINE Corporation - * - * LINE Corporation licenses this file to you 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 com.linecorp.bot.oauth.client; - -import static org.assertj.core.api.Assertions.assertThat; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.delete; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathTemplate; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; - -import com.linecorp.bot.client.base.BlobContent; -import com.linecorp.bot.client.base.UploadFile; - -import java.net.URI; - -import java.util.Map; - - -import com.linecorp.bot.oauth.model.ChannelAccessTokenKeyIdsResponse; -import com.linecorp.bot.oauth.model.ErrorResponse; -import com.linecorp.bot.oauth.model.IssueChannelAccessTokenResponse; -import com.linecorp.bot.oauth.model.IssueShortLivedChannelAccessTokenResponse; -import com.linecorp.bot.oauth.model.IssueStatelessChannelAccessTokenResponse; -import com.linecorp.bot.oauth.model.VerifyChannelAccessTokenResponse; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; -import org.junit.jupiter.api.extension.ExtendWith; -import org.slf4j.bridge.SLF4JBridgeHandler; - -import com.ocadotechnology.gembus.test.Arranger; - -import java.time.LocalDate; -import java.time.OffsetDateTime; - -import com.github.tomakehurst.wiremock.WireMockServer; - -/** -* API tests for ChannelAccessTokenClient -*/ -@Timeout(5) -public class ChannelAccessTokenClientTest { - static { - SLF4JBridgeHandler.removeHandlersForRootLogger(); - SLF4JBridgeHandler.install(); - } - - private WireMockServer wireMockServer; - private ChannelAccessTokenClient api; - - @BeforeEach - public void setUp() { - wireMockServer = new WireMockServer(wireMockConfig().dynamicPort()); - wireMockServer.start(); - configureFor("localhost", wireMockServer.port()); - - - api = ChannelAccessTokenClient.builder("MY_OWN_TOKEN") - .apiEndPoint(URI.create(wireMockServer.baseUrl())) - .build(); - } - - @AfterEach - public void tearDown() { - wireMockServer.stop(); - } - - @Test - public void getsAllValidChannelAccessTokenKeyIdsTest() { - stubFor(get(urlPathTemplate("/oauth2/v2.1/tokens/kid")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String clientAssertionType = Arranger.some(String.class); - String clientAssertion = Arranger.some(String.class); - - ChannelAccessTokenKeyIdsResponse response = api.getsAllValidChannelAccessTokenKeyIds(clientAssertionType, clientAssertion).join().body(); - - assertThat(response).isNotNull(); - // TODO: test validations - } - - @Test - public void issueChannelTokenTest() { - stubFor(post(urlPathTemplate("/v2/oauth/accessToken")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String grantType = Arranger.some(String.class); - String clientId = Arranger.some(String.class); - String clientSecret = Arranger.some(String.class); - - IssueShortLivedChannelAccessTokenResponse response = api.issueChannelToken(grantType, clientId, clientSecret).join().body(); - - assertThat(response).isNotNull(); - // TODO: test validations - } - - @Test - public void issueChannelTokenByJWTTest() { - stubFor(post(urlPathTemplate("/oauth2/v2.1/token")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String grantType = Arranger.some(String.class); - String clientAssertionType = Arranger.some(String.class); - String clientAssertion = Arranger.some(String.class); - - IssueChannelAccessTokenResponse response = api.issueChannelTokenByJWT(grantType, clientAssertionType, clientAssertion).join().body(); - - assertThat(response).isNotNull(); - // TODO: test validations - } - - @Test - public void issueStatelessChannelTokenTest() { - stubFor(post(urlPathTemplate("/oauth2/v3/token")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String grantType = Arranger.some(String.class); - String clientAssertionType = Arranger.some(String.class); - String clientAssertion = Arranger.some(String.class); - String clientId = Arranger.some(String.class); - String clientSecret = Arranger.some(String.class); - - IssueStatelessChannelAccessTokenResponse response = api.issueStatelessChannelToken(grantType, clientAssertionType, clientAssertion, clientId, clientSecret).join().body(); - - assertThat(response).isNotNull(); - // TODO: test validations - } - - @Test - public void revokeChannelTokenTest() { - stubFor(post(urlPathTemplate("/v2/oauth/revoke")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String accessToken = Arranger.some(String.class); - - api.revokeChannelToken(accessToken).join().body(); - - // TODO: test validations - } - - @Test - public void revokeChannelTokenByJWTTest() { - stubFor(post(urlPathTemplate("/oauth2/v2.1/revoke")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String clientId = Arranger.some(String.class); - String clientSecret = Arranger.some(String.class); - String accessToken = Arranger.some(String.class); - - api.revokeChannelTokenByJWT(clientId, clientSecret, accessToken).join().body(); - - // TODO: test validations - } - - @Test - public void verifyChannelTokenTest() { - stubFor(post(urlPathTemplate("/v2/oauth/verify")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String accessToken = Arranger.some(String.class); - - VerifyChannelAccessTokenResponse response = api.verifyChannelToken(accessToken).join().body(); - - assertThat(response).isNotNull(); - // TODO: test validations - } - - @Test - public void verifyChannelTokenByJWTTest() { - stubFor(get(urlPathTemplate("/oauth2/v2.1/verify")).willReturn( - aResponse() - .withStatus(200) - .withHeader("content-type", "application/json") - .withBody("{}"))); - - String accessToken = Arranger.some(String.class); - - VerifyChannelAccessTokenResponse response = api.verifyChannelTokenByJWT(accessToken).join().body(); - - assertThat(response).isNotNull(); - // TODO: test validations - } - -} diff --git a/generator/pom.xml b/generator/pom.xml index 931aed7c1..859d36996 100644 --- a/generator/pom.xml +++ b/generator/pom.xml @@ -100,8 +100,8 @@ maven-compiler-plugin 3.11.0 - 1.8 - 1.8 + 9 + 9 diff --git a/generator/src/main/resources/line-java-codegen/api.pebble b/generator/src/main/resources/line-java-codegen/api.pebble index 9be53ce50..6a9346ea5 100644 --- a/generator/src/main/resources/line-java-codegen/api.pebble +++ b/generator/src/main/resources/line-java-codegen/api.pebble @@ -3,7 +3,7 @@ {# @pebvariable name="package" type="java.lang.String" -#} {# @pebvariable name="generatorClass" type="java.lang.String" -#} {# @pebvariable name="classname" type="java.lang.String" -#} -{# @pebvariable name="authenticated" type="java.lang.Boolean" -#} +{# @pebvariable name="authMethods" type="java.util.ArrayList" -#} {% include "./licenseInfo.pebble" %} package {{ package }}; {% import "./macros/api_param.pebble" %} @@ -71,7 +71,7 @@ public interface {{classname}} { {% endfor %} -{% if authenticated %} +{% if authMethods != null %} public static ApiAuthenticatedClientBuilder<{{classname}}> builder(String channelToken) { return new ApiAuthenticatedClientBuilder<>(URI.create("{{ endpoint(classname) }}"), {{classname}}.class, new {{ exceptionbuilderclassname(classname) }}(), channelToken); } diff --git a/generator/src/main/resources/line-java-codegen/api_test.pebble b/generator/src/main/resources/line-java-codegen/api_test.pebble index f5f90a250..1841c2784 100644 --- a/generator/src/main/resources/line-java-codegen/api_test.pebble +++ b/generator/src/main/resources/line-java-codegen/api_test.pebble @@ -2,7 +2,7 @@ {# @pebvariable name="operations" type="org.openapitools.codegen.model.OperationMap" -#} {# @pebvariable name="generatorClass" type="java.lang.String" -#} {# @pebvariable name="classname" type="java.lang.String" -#} -{# @pebvariable name="authenticated" type="boolean" -#} +{# @pebvariable name="authMethods" type="java.util.ArrayList" -#} {% include "./licenseInfo.pebble" %} package {# @pebvariable name="package" type="java.lang.String" -#}{{package}}; @@ -71,7 +71,7 @@ public class {{classname}}Test { configureFor("localhost", wireMockServer.port()); - api = {{classname}}.builder({% if authenticated %}"MY_OWN_TOKEN"{% endif %}) + api = {{classname}}.builder({% if authMethods != null %}"MY_OWN_TOKEN"{% endif %}) .apiEndPoint(URI.create(wireMockServer.baseUrl())) .build(); } diff --git a/generator/src/test/java/com/linecorp/bot/codegen/LineJavaCodegenGeneratorTest.java b/generator/src/test/java/com/linecorp/bot/codegen/LineJavaCodegenGeneratorTest.java index 353ca8921..d091d0225 100644 --- a/generator/src/test/java/com/linecorp/bot/codegen/LineJavaCodegenGeneratorTest.java +++ b/generator/src/test/java/com/linecorp/bot/codegen/LineJavaCodegenGeneratorTest.java @@ -21,6 +21,13 @@ import org.openapitools.codegen.DefaultGenerator; import org.openapitools.codegen.config.CodegenConfigurator; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Stream; + /*** * This test allows you to easily launch your code generation software under a debugger. * Then run this test under debug mode. You will be able to step through your java code @@ -33,22 +40,39 @@ */ public class LineJavaCodegenGeneratorTest { - // use this test to launch you code generator in the debugger. - // this allows you to easily set break points in MyclientcodegenGenerator. - @Test - public void launchCodeGenerator() { - // to understand how the 'openapi-generator-cli' module is using 'CodegenConfigurator', have a look at the 'Generate' class: - // https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java - final CodegenConfigurator configurator = new CodegenConfigurator() - .addGlobalProperty("modelDocs", "false") - .addGlobalProperty("apiDocs", "false") - .setTemplatingEngineName("pebble") - .setGeneratorName("line-java-codegen") // use this codegen library - .setInputSpec("../line-openapi/shop.yml") // sample OpenAPI file - .setOutputDir("out/line-java-codegen"); // output directory - - final ClientOptInput clientOptInput = configurator.toClientOptInput(); - DefaultGenerator generator = new DefaultGenerator(); - generator.opts(clientOptInput).generate(); - } + @Test + public void shop() throws IOException { + this.generate("shop"); + } + + @Test + public void channel() throws IOException { + this.generate("channel-access-token"); + } + + private void generate(String target) throws IOException { + Path outPath = Paths.get("out/" + target); + if (outPath.toFile().exists()) { + try (Stream stream = Files.walk(outPath)) { + //noinspection ResultOfMethodCallIgnored + stream.map(Path::toFile) + .forEach(File::delete); + } + } + + // to understand how the 'openapi-generator-cli' module is using 'CodegenConfigurator', have a look at the 'Generate' class: + // https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java + final CodegenConfigurator configurator = new CodegenConfigurator() + .addGlobalProperty("modelDocs", "false") + .addGlobalProperty("apiDocs", "false") + .setTemplatingEngineName("pebble") + .setTemplateDir("src/main/resources/line-java-codegen") + .setGeneratorName("line-java-codegen") // use this codegen library + .setInputSpec("../line-openapi/" + target + ".yml") // sample OpenAPI file + .setOutputDir("out/" + target); // output directory + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(); + generator.opts(clientOptInput).generate(); + } } diff --git a/line-bot-integration-test/src/integrationTest/java/com/linecorp/bot/client/ChannelAccessTokenIntegrationTest.java b/line-bot-integration-test/src/integrationTest/java/com/linecorp/bot/client/ChannelAccessTokenIntegrationTest.java index 6208357d1..14855e9b8 100644 --- a/line-bot-integration-test/src/integrationTest/java/com/linecorp/bot/client/ChannelAccessTokenIntegrationTest.java +++ b/line-bot-integration-test/src/integrationTest/java/com/linecorp/bot/client/ChannelAccessTokenIntegrationTest.java @@ -60,7 +60,7 @@ public void setUp() throws IOException, ParseException { this.settings = IntegrationTestSettingsLoader.load(); target = ChannelAccessTokenClient - .builder(settings.token()) + .builder() .apiEndPoint(URI.create(settings.apiEndpoint())) .build(); diff --git a/spring-boot/line-bot-spring-boot-client/src/main/java/com/linecorp/bot/spring/boot/core/configuration/LineBotAutoConfiguration.java b/spring-boot/line-bot-spring-boot-client/src/main/java/com/linecorp/bot/spring/boot/core/configuration/LineBotAutoConfiguration.java index 2b8f88a04..37488bf35 100644 --- a/spring-boot/line-bot-spring-boot-client/src/main/java/com/linecorp/bot/spring/boot/core/configuration/LineBotAutoConfiguration.java +++ b/spring-boot/line-bot-spring-boot-client/src/main/java/com/linecorp/bot/spring/boot/core/configuration/LineBotAutoConfiguration.java @@ -140,11 +140,9 @@ public ManageAudienceClient manageAudienceClient( @Bean @ConditionalOnMissingBean - public ChannelAccessTokenClient channelAccessTokenClient( - final ChannelTokenSupplier channelTokenSupplier - ) { + public ChannelAccessTokenClient channelAccessTokenClient() { return ChannelAccessTokenClient - .builder(channelTokenSupplier) + .builder() .apiEndPoint(lineBotProperties.apiEndPoint()) .connectTimeout(lineBotProperties.connectTimeout()) .readTimeout(lineBotProperties.readTimeout())