diff --git a/api/src/main/java/fitconnect/api/package-info.java b/api/src/main/java/fitconnect/api/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..3d1d7dbf95230aceed34057abcd4067247088bf7 --- /dev/null +++ b/api/src/main/java/fitconnect/api/package-info.java @@ -0,0 +1,11 @@ +/** + * This module is providing the internal sdk api + * <p> + * + * </p> + * + * @since 1.0 + * @author FitConnect + * @version 1.0 + */ +package fitconnect.api; \ No newline at end of file diff --git a/client/src/main/java/de/fitconnect/client/ClientFactory.java b/client/src/main/java/de/fitconnect/client/ClientFactory.java index 1bf87706bdbc32f63d4d4277ecffd383d4d0a3f4..428157db878fbfcdc35b21f75b17c67df1a51dac 100644 --- a/client/src/main/java/de/fitconnect/client/ClientFactory.java +++ b/client/src/main/java/de/fitconnect/client/ClientFactory.java @@ -8,7 +8,7 @@ import fitconnect.api.services.validation.CertificateValidator; import fitconnect.api.services.validation.MetadataValidator; import fitconnect.impl.SubmissionSender; import fitconnect.impl.SubmissionSubscriber; -import fitconnect.impl.auth.FitCoAuthService; +import fitconnect.impl.auth.MonoPublisherOAuthService; import fitconnect.impl.crypto.JWECryptoService; import fitconnect.impl.validation.KeyValidator; import fitconnect.impl.validation.MetadataSubmissionValidator; @@ -38,7 +38,7 @@ public class ClientFactory { return new JWECryptoService(); } - private static FitCoAuthService getAuthService() { - return new FitCoAuthService(HttpClient.newHttpClient(), TOKEN_URL); + private static MonoPublisherOAuthService getAuthService() { + return new MonoPublisherOAuthService(TOKEN_URL); } } diff --git a/client/src/main/java/de/fitconnect/client/FitConnectClient.java b/client/src/main/java/de/fitconnect/client/SenderClient.java similarity index 75% rename from client/src/main/java/de/fitconnect/client/FitConnectClient.java rename to client/src/main/java/de/fitconnect/client/SenderClient.java index 9ff95f54fb0d6b104af9f4724c631232af64e5da..0153195570da0c76bd1b011ab387c209ef7b921c 100644 --- a/client/src/main/java/de/fitconnect/client/FitConnectClient.java +++ b/client/src/main/java/de/fitconnect/client/SenderClient.java @@ -13,30 +13,30 @@ import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; -public class FitConnectClient { +public class SenderClient { - private static final Logger logger = SdkLogger.customLogger(FitConnectClient.class); + private static final Logger logger = SdkLogger.customLogger(SenderClient.class); private final Sender sender; private Optional<OAuthToken> token = Optional.empty(); - public FitConnectClient(){ + public SenderClient(){ this.sender = ClientFactory.submissionSender(); } - public FitConnectClient authenticate(String clientId, String secret, String...scope){ + public SenderClient authenticate(String clientId, String secret, String...scope){ this.token = sender.retrieveOAuthToken(clientId,secret,scope); return this; } - public FitConnectClient createSubmission(final Submission submission){ + public SenderClient createSubmission(final Submission submission){ checkIfAuthenticated(); // TODO implement sendSubmission logger.log(Level.INFO, "created new submission"); return this; } - public FitConnectClient sendSubmission(final Metadata metadata, final Data data){ + public SenderClient sendSubmission(final Metadata metadata, final Data data){ checkIfAuthenticated(); // TODO implement logger.log(Level.INFO, "successfully sent submission"); @@ -44,14 +44,14 @@ public class FitConnectClient { return this; } - public FitConnectClient uploadAttachments(final List<Attachment> attachments){ + public SenderClient uploadAttachments(final List<Attachment> attachments){ checkIfAuthenticated(); // TODO implement logger.log(Level.INFO, "uploaded " + attachments.size() + " attachments"); return this; } - public FitConnectClient printToken(){ + public SenderClient printToken(){ checkIfAuthenticated(); logger.log(Level.INFO, "retrieved access token: " + this.token.get().getAccessToken()); return this; @@ -59,7 +59,7 @@ public class FitConnectClient { private void checkIfAuthenticated() { if(token.isEmpty()){ - throw new IllegalStateException("not authenticated, please authenticate first with authenticate(client, secret)"); + throw new IllegalStateException("not authenticated, please authenticate first"); } } diff --git a/client/src/main/java/de/fitconnect/client/TestRunner.java b/client/src/main/java/de/fitconnect/client/TestRunner.java index 8d9f175b0d16f38dcff70288ab33c602af554160..2f95ebec3b7d9f65110e9ba244b6fbf303b96363 100644 --- a/client/src/main/java/de/fitconnect/client/TestRunner.java +++ b/client/src/main/java/de/fitconnect/client/TestRunner.java @@ -13,7 +13,7 @@ public class TestRunner { var clientId = "781f6213-0f0f-4a79-9372-e7187ffda98b"; var secret = "PnzR8Vbmhpv_VwTkT34wponqXWK8WBm-LADlryYdV4o"; - FitConnectClient client = new FitConnectClient(); + SenderClient client = new SenderClient(); // sample high -level- api calls to send a submission client.authenticate(clientId,secret) diff --git a/impl/pom.xml b/impl/pom.xml index def6e1125c2871f0a3d0d72ed9f0bdfacb00101b..3608d6846373577c01781757c417eb250bc1b20d 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -32,6 +32,10 @@ <groupId>com.github.erosb</groupId> <artifactId>everit-json-schema</artifactId> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> + </dependency> </dependencies> diff --git a/impl/src/main/java/fitconnect/impl/SubmissionSender.java b/impl/src/main/java/fitconnect/impl/SubmissionSender.java index dc441e79cc203a3e0551891a812a6628d553b775..ecbb4ff5481267e2d24a13c0c09846f671a4cbee 100644 --- a/impl/src/main/java/fitconnect/impl/SubmissionSender.java +++ b/impl/src/main/java/fitconnect/impl/SubmissionSender.java @@ -13,7 +13,7 @@ import fitconnect.api.exceptions.EncryptionException; import fitconnect.impl.logger.SdkLogger; import fitconnect.api.services.validation.CertificateValidator; import fitconnect.api.domain.validation.ValidationResult; -import fitconnect.impl.auth.FitCoAuthService; +import fitconnect.impl.auth.MonoPublisherOAuthService; import java.nio.charset.StandardCharsets; import java.util.List; @@ -24,7 +24,7 @@ import java.util.logging.Logger; public class SubmissionSender implements Sender { - private static final Logger logger = SdkLogger.defaultLogger(FitCoAuthService.class); + private static final Logger logger = SdkLogger.defaultLogger(MonoPublisherOAuthService.class); private final OAuthService authService; private final CertificateValidator certificateValidator; diff --git a/impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java b/impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java index 4e0c68c3381c7766b98b8a89f6521da9fdcca202..0159508a404460c8d3a6bd271a585ae85ce6412b 100644 --- a/impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java +++ b/impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java @@ -13,7 +13,7 @@ import fitconnect.api.exceptions.DecryptionException; import fitconnect.impl.logger.SdkLogger; import fitconnect.api.services.validation.MetadataValidator; import fitconnect.api.domain.validation.ValidationResult; -import fitconnect.impl.auth.FitCoAuthService; +import fitconnect.impl.auth.MonoPublisherOAuthService; import java.util.Optional; import java.util.logging.Level; @@ -22,7 +22,7 @@ import java.util.logging.Logger; public class SubmissionSubscriber implements Subscriber { - private static final Logger logger = SdkLogger.defaultLogger(FitCoAuthService.class); + private static final Logger logger = SdkLogger.defaultLogger(MonoPublisherOAuthService.class); private final OAuthService authService; private final CryptoService cryptoService; diff --git a/impl/src/main/java/fitconnect/impl/auth/FitCoAuthService.java b/impl/src/main/java/fitconnect/impl/auth/FitCoAuthService.java deleted file mode 100644 index 4b73d3d466c08424e3d6976fe079642e4fbe901d..0000000000000000000000000000000000000000 --- a/impl/src/main/java/fitconnect/impl/auth/FitCoAuthService.java +++ /dev/null @@ -1,70 +0,0 @@ -package fitconnect.impl.auth; - -import com.fasterxml.jackson.databind.ObjectMapper; -import fitconnect.api.services.auth.OAuthService; -import fitconnect.api.domain.auth.OAuthToken; -import fitconnect.api.exceptions.AuthenticationException; -import fitconnect.impl.logger.SdkLogger; - -import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.util.Arrays; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static java.util.stream.Collectors.joining; - -public class FitCoAuthService implements OAuthService { - - private static final Logger logger = SdkLogger.defaultLogger(FitCoAuthService.class); - private static final ObjectMapper mapper = new ObjectMapper(); - - private final HttpClient client; - private final String tokenUrl; - - public FitCoAuthService(final HttpClient client, final String tokenUrl) { - this.client = client; - this.tokenUrl = tokenUrl; - } - - @Override - public OAuthToken authenticate(String clientId, String clientSecret, String... scope) throws AuthenticationException { - final String requestBody = buildRequestBody(clientId, clientSecret, scope); - try { - return performTokenRequest(requestBody); - } catch (IOException | InterruptedException e) { - logger.log(Level.SEVERE, "error retrieving access token", e); - throw new AuthenticationException(e.getMessage(),e); - } - } - - private String buildRequestBody(String clientId, String clientSecret, String... scope) { - var data = new HashMap<String, String>() {{ - put("grant_type", "client_credentials"); - put("client_id", clientId); - put("client_secret", clientSecret); - }}; - - Arrays.stream(scope).forEach(s -> data.put("scope", s)); - - return data.entrySet() - .stream() - .map(e -> e.getKey() + "=" + e.getValue()) - .collect(joining("&")); - } - - private OAuthToken performTokenRequest(final String requestBody) throws IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .header("Accept", "application/json") - .header("Content-Type","application/x-www-form-urlencoded;charset=UTF-8") - .uri(URI.create(tokenUrl)) - .POST(HttpRequest.BodyPublishers.ofString(requestBody)) - .build(); - var responseBody = client.send(request, HttpResponse.BodyHandlers.ofString()).body(); - return mapper.readValue(responseBody,OAuthToken.class); - } -} diff --git a/impl/src/main/java/fitconnect/impl/auth/MonoPublisherOAuthService.java b/impl/src/main/java/fitconnect/impl/auth/MonoPublisherOAuthService.java new file mode 100644 index 0000000000000000000000000000000000000000..3981b148a320e37f37cef74f78fb385dcfe8362f --- /dev/null +++ b/impl/src/main/java/fitconnect/impl/auth/MonoPublisherOAuthService.java @@ -0,0 +1,68 @@ +package fitconnect.impl.auth; + +import fitconnect.api.domain.auth.OAuthToken; +import fitconnect.api.exceptions.AuthenticationException; +import fitconnect.api.services.auth.OAuthService; +import fitconnect.impl.logger.SdkLogger; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Logger; + +import static java.util.stream.Collectors.joining; + +public class MonoPublisherOAuthService implements OAuthService { + + private static final Logger logger = SdkLogger.defaultLogger(MonoPublisherOAuthService.class); + + private final String tokenUrl; + + public MonoPublisherOAuthService(final String tokenUrl) { + this.tokenUrl = tokenUrl; + } + + @Override + public OAuthToken authenticate(String clientId, String clientSecret, String... scope) throws AuthenticationException { + final String requestBody = buildRequestBody(clientId, clientSecret, scope); + + return performTokenRequestAsync(requestBody).block(); + } + + private String buildRequestBody(String clientId, String clientSecret, String... scope) { + var data = new HashMap<String, String>() {{ + put("grant_type", "client_credentials"); + put("client_id", clientId); + put("client_secret", clientSecret); + }}; + + Arrays.stream(scope).forEach(s -> data.put("scope", s)); + + return data.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(joining("&")); + } + + // TODO generalize HTTP requests in separate common service + private Mono<OAuthToken> performTokenRequestAsync(final String requestBody){ + return WebClient.builder() + .defaultHeaders(this::setHeaders) + .build() + .post() + .uri(tokenUrl) + .bodyValue(requestBody) + .retrieve() + .bodyToMono(OAuthToken.class); + } + + private void setHeaders(HttpHeaders headers) { + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + headers.setAcceptCharset(List.of(StandardCharsets.UTF_8)); + } + +} diff --git a/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java b/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java index e282aff6b581dc416c8d05cd89e97f3dc13b67f1..2d82a917237d8021e3848b6c543dee4e198f741d 100644 --- a/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java +++ b/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java @@ -1,11 +1,10 @@ package fitconnect.impl.auth; -import fitconnect.api.services.Sender; import fitconnect.api.domain.auth.OAuthToken; +import fitconnect.api.services.Sender; import fitconnect.impl.SubmissionSender; import org.junit.jupiter.api.Test; -import java.net.http.HttpClient; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; @@ -21,8 +20,7 @@ class OAuthTokenIntegrationTest { var secret = "PnzR8Vbmhpv_VwTkT34wponqXWK8WBm-LADlryYdV4o"; var scope = "send:region:DE"; - var httpClient = HttpClient.newHttpClient(); - var authService = new FitCoAuthService(httpClient, tokenUrl); + var authService = new MonoPublisherOAuthService(tokenUrl); final Sender sender = new SubmissionSender(authService, null, null); // When diff --git a/pom.xml b/pom.xml index 0981ba0ec154a88281f995b5ccccc5e52d74e321..ead23af0314ac163cbaa821b086c3321aa3eef06 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,11 @@ <artifactId>everit-json-schema</artifactId> <version>1.14.1</version> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> + <version>2.7.0</version> + </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId>