Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP refactor java http api #700

Draft
wants to merge 1 commit into
base: java/http_api
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion java/src/main/java/de/gdata/vaas/IVaas.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ public interface IVaas {
VaasVerdict forStream(InputStream stream, long contentLength, ForStreamOptions options) throws InterruptedException, ExecutionException, IOException, VaasAuthenticationException;
CompletableFuture<VaasVerdict> forFileAsync(Path file) throws IOException, InterruptedException, VaasAuthenticationException, NoSuchAlgorithmException;
CompletableFuture<VaasVerdict> forFileAsync(Path file, ForFileOptions options) throws IOException, InterruptedException, VaasAuthenticationException, NoSuchAlgorithmException;
VaasVerdict forFile(Path file) throws NoSuchAlgorithmException, InterruptedException, ExecutionException, IOException, VaasAuthenticationException;

VaasVerdict forFile(Path file) throws NoSuchAlgorithmException, InterruptedException, ExecutionException,
IOException, VaasAuthenticationException;

VaasVerdict forFile(Path file, ForFileOptions options) throws NoSuchAlgorithmException, InterruptedException, ExecutionException, IOException, VaasAuthenticationException;
CompletableFuture<VaasVerdict> forUrlAsync(URL url) throws IOException, InterruptedException, VaasAuthenticationException;
CompletableFuture<VaasVerdict> forUrlAsync(URL url, ForUrlOptions options) throws IOException, InterruptedException, VaasAuthenticationException;
Expand Down
9 changes: 5 additions & 4 deletions java/src/main/java/de/gdata/vaas/Sha256.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.Getter;
import lombok.NonNull;
import org.jetbrains.annotations.NotNull;

import java.io.FileInputStream;
import java.io.IOException;
Expand All @@ -11,14 +12,14 @@
import java.security.NoSuchAlgorithmException;
import java.util.regex.Pattern;

@Getter
public class Sha256 {
private static Pattern pattern = Pattern.compile("^[A-Fa-f0-9]{64}$");
private static final Pattern pattern = Pattern.compile("^[A-Fa-f0-9]{64}$");

@NonNull
@Getter
private String value;
private final String value;

public Sha256(String sha256) {
public Sha256(@NotNull String sha256) {
var matcher = pattern.matcher(sha256);

if (!matcher.find()) {
Expand Down
34 changes: 18 additions & 16 deletions java/src/main/java/de/gdata/vaas/Vaas.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package de.gdata.vaas;

import de.gdata.vaas.authentication.IAuthenticator;
import de.gdata.vaas.exceptions.VaasAuthenticationException;
import de.gdata.vaas.exceptions.VaasClientException;
import de.gdata.vaas.exceptions.VaasServerException;
import de.gdata.vaas.messages.*;
import de.gdata.vaas.options.ForFileOptions;
import de.gdata.vaas.options.ForSha256Options;
import de.gdata.vaas.options.ForStreamOptions;
import de.gdata.vaas.options.ForUrlOptions;
import de.gdata.vaas.exceptions.*;
import de.gdata.vaas.authentication.*;
import lombok.Getter;
import lombok.NonNull;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -66,11 +68,6 @@ private static <T, R> Function<T, CompletableFuture<R>> handleException(
};
}

@FunctionalInterface
interface ThrowingFunction<T, R> {
R apply(T t) throws Exception;
}

private static String encodeParams(Map<String, String> params) {
StringBuilder encodedParams = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
Expand Down Expand Up @@ -137,7 +134,7 @@ private HttpRequest.Builder CreateHttpRequestBuilderWithHeaders(URI uri, String
*
* @param sha256 the SHA-256 hash to retrieve the verdict for
* @return a {@link CompletableFuture} containing the {@link VaasVerdict} for
* the hash
* the hash
* @throws IOException If an I/O error occurs during the
* request.
* @throws InterruptedException If the operation is interrupted.
Expand All @@ -160,7 +157,7 @@ public CompletableFuture<VaasVerdict> forSha256Async(Sha256 sha256)
* @param options The options to customize the request, such as using the cache
* and hash lookup.
* @return a {@link CompletableFuture} containing the {@link VaasVerdict} for
* the hash
* the hash
* @throws IOException If an I/O error occurs during the
* request.
* @throws InterruptedException If the operation is interrupted.
Expand Down Expand Up @@ -228,7 +225,7 @@ public VaasVerdict forSha256(Sha256 sha256, ForSha256Options options)
*
* @param file the {@link Path} to the file to be processed
* @return a {@link CompletableFuture} containing the {@link VaasVerdict} for
* the file
* the file
* @throws IOException if an I/O error occurs
* @throws InterruptedException if the operation is interrupted
* @throws VaasAuthenticationException if authentication fails
Expand All @@ -254,7 +251,7 @@ public CompletableFuture<VaasVerdict> forFileAsync(Path file)
* @param options The options to customize the request, such as using the cache
* and hash lookup.
* @return a {@link CompletableFuture} containing the {@link VaasVerdict} for
* the file
* the file
* @throws IOException if an I/O error occurs
* @throws InterruptedException if the operation is interrupted
* @throws VaasAuthenticationException if authentication fails
Expand Down Expand Up @@ -377,7 +374,7 @@ public CompletableFuture<VaasVerdict> forStreamAsync(InputStream stream, long co
*/
@Override
public CompletableFuture<VaasVerdict> forStreamAsync(InputStream inputStream, long contentLength,
ForStreamOptions options) throws IOException, InterruptedException, VaasAuthenticationException {
ForStreamOptions options) throws IOException, InterruptedException, VaasAuthenticationException {
var params = Map.of("useHashLookup", String.valueOf(options.isUseHashLookup()));

var filesUri = this.config.getUrl() + "/files?" + encodeParams(params);
Expand Down Expand Up @@ -449,8 +446,8 @@ public VaasVerdict forStream(InputStream stream, long contentLength, ForStreamOp
*
* @param url the URL to retrieve the verdict for
* @return a {@link CompletableFuture} containing the {@link VaasVerdict} for
* the
* URL
* the
* URL
* @throws IOException If an I/O error occurs during the
* request.
* @throws InterruptedException If the operation is interrupted.
Expand All @@ -472,8 +469,8 @@ public CompletableFuture<VaasVerdict> forUrlAsync(URL url)
* @param options The options to customize the request, such as using hash
* lookup.
* @return a {@link CompletableFuture} containing the {@link VaasVerdict} for
* the
* URL
* the
* URL
* @throws IOException If an I/O error occurs during the
* request.
* @throws InterruptedException If the operation is interrupted.
Expand Down Expand Up @@ -550,4 +547,9 @@ public VaasVerdict forUrl(URL url, ForUrlOptions options)
throws InterruptedException, ExecutionException, IOException, VaasAuthenticationException {
return forUrlAsync(url, options).get();
}

@FunctionalInterface
interface ThrowingFunction<T, R> {
R apply(T t) throws Exception;
}
}
11 changes: 5 additions & 6 deletions java/src/main/java/de/gdata/vaas/VaasConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,32 @@
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;

import java.net.URI;
import java.net.URISyntaxException;

@Setter
@Getter
public class VaasConfig {
@Getter
@Setter
@NonNull
private URI url;

@Getter
@Setter
long defaultTimeoutInMs = 120000;

public VaasConfig() throws URISyntaxException {
this(new URI("https://gateway.production.vaas.gdatasecurity.de"));
}

public VaasConfig(URI url) {
public VaasConfig(@NotNull URI url) {
this.url = url;
}

public VaasConfig(long defaultTimeoutInMs) throws URISyntaxException {
this(new URI("https://gateway.production.vaas.gdatasecurity.de"), defaultTimeoutInMs);
}

public VaasConfig(URI url, long defaultTimeoutInMs) {
public VaasConfig(@NotNull URI url, long defaultTimeoutInMs) {
this.url = url;
this.defaultTimeoutInMs = defaultTimeoutInMs;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,96 +1,58 @@
package de.gdata.vaas.authentication;

import com.google.gson.JsonParser;

import de.gdata.vaas.exceptions.VaasAuthenticationException;
import lombok.Getter;
import lombok.NonNull;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Getter
public class ClientCredentialsGrantAuthenticator implements IAuthenticator {

@Getter
private final String clientId;
@Getter
private final String clientSecret;

@NonNull
private final URI tokenEndpoint;

private final HttpClient httpClient;
private String cachedToken;
private Instant tokenExpiry;


public ClientCredentialsGrantAuthenticator(String clientId, String clientSecret, @NotNull URI tokenEndpoint) {
this.tokenEndpoint = tokenEndpoint;
private final ClientCredentialsTokenReceiver tokenReceiver;

/**
* The authenticator for the client credentials grant type if you have a client id and client secret.
*
* @param clientId The client id
* @param clientSecret The client secret
* @param tokenUrl The optional token url. Defaults to the G DATA production URL
* @param httpClient Your optional custom http client.
*/
public ClientCredentialsGrantAuthenticator(@NotNull String clientId, @NotNull String clientSecret, @NotNull URI tokenUrl, @NotNull HttpClient httpClient) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.httpClient = HttpClient.newHttpClient();
this.tokenReceiver = new ClientCredentialsTokenReceiver(this, tokenUrl, httpClient);
}

public ClientCredentialsGrantAuthenticator(String clientId, String clientSecret, @NotNull URI tokenEndpoint, HttpClient httpClient) {
this.tokenEndpoint = tokenEndpoint;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.httpClient = httpClient;
/**
* The authenticator for the client credentials grant type if you have a client id and client secret.
*
* @param clientId The client id
* @param clientSecret The client secret
* @param tokenUrl The optional token url. Defaults to the G DATA production URL
*/
public ClientCredentialsGrantAuthenticator(@NotNull String clientId, @NotNull String clientSecret, @NotNull URI tokenUrl) {
this(clientId, clientSecret, tokenUrl, HttpClient.newHttpClient());
}

public ClientCredentialsGrantAuthenticator(String clientId, String clientSecret)
throws URISyntaxException {
/**
* The authenticator for the client credentials grant type if you have a client id and client secret.
*
* @param clientId The client id
* @param clientSecret The client secret
*/
public ClientCredentialsGrantAuthenticator(@NotNull String clientId, @NotNull String clientSecret) throws URISyntaxException {
this(clientId, clientSecret, new URI("https://account.gdata.de/realms/vaas-production/protocol/openid-connect/token"));
}

private String encodeValue(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}

public synchronized String getToken() throws IOException, InterruptedException, VaasAuthenticationException {
if (cachedToken != null && tokenExpiry != null && Instant.now().isBefore(tokenExpiry)) {
return cachedToken;
}

Map<String, String> requestParams = new HashMap<>();
requestParams.put("client_id", this.clientId);
requestParams.put("grant_type", "client_credentials");
requestParams.put("client_secret", this.clientSecret);
var uriWithParameters = requestParams.keySet().stream()
.map(key -> {
return key + "=" + encodeValue(requestParams.get(key));
})
.collect(Collectors.joining("&"));
var request = HttpRequest
.newBuilder(tokenEndpoint)
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(uriWithParameters))
.build();

var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

if (response.statusCode() != 200) {
throw new VaasAuthenticationException();
}

var bodyJsonObject = JsonParser.parseString(response.body()).getAsJsonObject();
var tokenJsonElement = bodyJsonObject.get("access_token");
var expiresInJsonElement = bodyJsonObject.get("expires_in");

cachedToken = tokenJsonElement.getAsString();
int expiresIn = expiresInJsonElement.getAsInt();
tokenExpiry = Instant.now().plusSeconds(expiresIn);

return cachedToken;
@Override
public String getToken() throws VaasAuthenticationException {
return tokenReceiver.getToken();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package de.gdata.vaas.authentication;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.nio.charset.StandardCharsets;

class ClientCredentialsTokenReceiver extends TokenReceiver {

private final ClientCredentialsGrantAuthenticator authenticator;

public ClientCredentialsTokenReceiver(ClientCredentialsGrantAuthenticator authenticator, URI tokenUrl, HttpClient httpClient) {
super(authenticator, tokenUrl, httpClient);
this.authenticator = authenticator;
}

public ClientCredentialsTokenReceiver(ClientCredentialsGrantAuthenticator authenticator, URI tokenUrl) {
super(authenticator, tokenUrl);
this.authenticator = authenticator;
}

public ClientCredentialsTokenReceiver(ClientCredentialsGrantAuthenticator authenticator) throws URISyntaxException {
super(authenticator);
this.authenticator = authenticator;
}

@Override
protected String tokenRequestToForm() {
return "client_id=" + URLEncoder.encode(authenticator.getClientId(), StandardCharsets.UTF_8) +
"&client_secret=" + URLEncoder.encode(authenticator.getClientSecret(), StandardCharsets.UTF_8) +
"&grant_type=client_credentials";
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package de.gdata.vaas.authentication;

import java.io.IOException;

import de.gdata.vaas.exceptions.VaasAuthenticationException;

import java.io.IOException;

public interface IAuthenticator {
public String getToken() throws IOException, InterruptedException, VaasAuthenticationException;
String getToken() throws IOException, InterruptedException, VaasAuthenticationException;
}
Loading