Skip to content

Commit

Permalink
Some tests and and improvements to squidex builder.
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianStehle committed Aug 11, 2023
1 parent 85a7f4b commit 7f49ecc
Show file tree
Hide file tree
Showing 13 changed files with 470 additions and 18 deletions.
17 changes: 15 additions & 2 deletions .fernignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Specify files that shouldn't be modified by Fern

README.md

# Wrappers
**/AccessToken.java
**/AuthInterceptor.java
**/InMemoryTokenStore.java
**/SquidexApiClient.java
**/SquidexApiClientBuilder.java
**/TokenStore.java

# Workflows
.github/workflows/check-updates.yml
.github/workflows/test.yml

#tests
src/test/
37 changes: 37 additions & 0 deletions src/main/java/com/squidex/api/AccessToken.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.squidex.api;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.Instant;

public final class AccessToken {
private final String accessToken;
private final int expiresIn;
private final Instant expiresAt;

@JsonCreator()
public AccessToken(
@JsonProperty("access_token")String accessToken,
@JsonProperty("expires_in")int expiresIn) {
this.accessToken = accessToken;
this.expiresIn = expiresIn;
this.expiresAt = Instant.now().plusSeconds(expiresIn);
}


public String getAccessToken() {
return accessToken;
}


public int getExpiresIn() {
return expiresIn;
}

@JsonIgnore()
public Instant getExpiresAt() {
return expiresAt;
}
}
84 changes: 84 additions & 0 deletions src/main/java/com/squidex/api/AuthInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.squidex.api;

import com.squidex.api.core.Environment;
import com.squidex.api.core.ObjectMappers;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.time.Instant;
import java.util.Objects;

public final class AuthInterceptor implements Interceptor {
private final Environment environment;
private final String clientId;
private final String clientSecret;
private final TokenStore tokenStore;
private final OkHttpClient httpClient;

public AuthInterceptor(OkHttpClient httpClient, Environment environment, String clientId, String clientSecret, TokenStore tokenStore) {
this.httpClient = httpClient;
this.environment = environment;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tokenStore = tokenStore;
}

@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Request originalRequest = chain.request();

AccessToken token = this.tokenStore.get();
if (token != null && token.getExpiresAt().isBefore(Instant.now())) {
// The token has been expired, therefore also remove it from the store for other calls.
token = null;
this.tokenStore.clear();
}

if (token == null) {
token = acquireToken();
this.tokenStore.set(token);
}

Request requestWithHeader = originalRequest.newBuilder()
.header("Authorization", "Bearer " + token.getAccessToken())
.build();

Response response = chain.proceed(requestWithHeader);
if (response.code() == 401) {
this.tokenStore.clear();

return intercept(chain);
}

return response;
}

private AccessToken acquireToken() throws IOException {
RequestBody formBody = new FormBody.Builder()
.add("grant_type", "client_credentials")
.add("client_id", this.clientId)
.add("client_secret", this.clientSecret)
.add("scope", "squidex-api")
.build();

HttpUrl tokenUrl = Objects.requireNonNull(HttpUrl.parse(this.environment.getUrl()))
.newBuilder()
.addPathSegments("identity-server/connect/token")
.build();

Request tokenRequest = new Request.Builder()
.url(tokenUrl.url())
.post(formBody)
.build();

AccessToken token;
try (Response response = this.httpClient.newCall(tokenRequest).execute()) {
assert response.body() != null;
token = ObjectMappers.JSON_MAPPER.readValue(response.body().string(), AccessToken.class);
}

return token;
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/squidex/api/InMemoryTokenStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.squidex.api;

public class InMemoryTokenStore implements TokenStore {
private AccessToken currentToken;

@Override
public AccessToken get() {
return this.currentToken;
}

@Override
public void set(AccessToken token) {
this.currentToken = token;
}

@Override
public void clear() {
this.currentToken = null;
}
}
102 changes: 95 additions & 7 deletions src/main/java/com/squidex/api/SquidexApiClientBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@

import com.squidex.api.core.ClientOptions;
import com.squidex.api.core.Environment;
import okhttp3.OkHttpClient;

import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

public final class SquidexApiClientBuilder {
private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder();
private final ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder();

private Environment environment = Environment.DEFAULT;

public SquidexApiClientBuilder token(String token) {
this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + token);
return this;
}
private String clientId;
private String clientSecret;
private TokenStore tokenStore;
private OkHttpClient httpClient;
private boolean trustAllCerts;

public SquidexApiClientBuilder environment(Environment environment) {
this.environment = environment;
Expand All @@ -23,13 +28,96 @@ public SquidexApiClientBuilder url(String url) {
return this;
}

public SquidexApiClientBuilder clientId(String clientId) {
this.clientId = clientId;
return this;
}

public String clientId() {
return this.clientId;
}

public SquidexApiClientBuilder clientSecret(String clientSecret) {
this.clientSecret = clientSecret;
return this;
}

public String clientSecret() {
return this.clientSecret;
}

public SquidexApiClientBuilder tokenStore(TokenStore tokenStore) {
this.tokenStore = tokenStore;
return this;
}

public SquidexApiClientBuilder httpClient(OkHttpClient httpClient) {
this.httpClient = httpClient;
return this;
}

public SquidexApiClientBuilder appName(String appName) {
clientOptionsBuilder.appName(appName);
this.clientOptionsBuilder.appName(appName);
return this;
}

public SquidexApiClientBuilder trustAllCerts() {
this.trustAllCerts = true;
return this;
}

public SquidexApiClient build() {
clientOptionsBuilder.environment(this.environment);

if (this.tokenStore == null) {
this.tokenStore = new InMemoryTokenStore();
}

if (this.httpClient == null) {
this.httpClient = new OkHttpClient();
}

if (this.trustAllCerts) {
X509TrustManager trustAllCerts = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}

@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}

@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
};

try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] { trustAllCerts }, new java.security.SecureRandom());

this.httpClient = this.httpClient.newBuilder()
.sslSocketFactory(sslContext.getSocketFactory(), trustAllCerts)
.build();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException(e);
}
}

AuthInterceptor interceptor = new AuthInterceptor(
this.httpClient,
this.environment,
this.clientId,
this.clientSecret,
this.tokenStore);

this.httpClient = this.httpClient.newBuilder()
.addInterceptor(interceptor)
.build();

clientOptionsBuilder.httpClient(this.httpClient);

return new SquidexApiClient(clientOptionsBuilder.build());
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/squidex/api/TokenStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.squidex.api;

public interface TokenStore {
AccessToken get();

void set(AccessToken token);

void clear();
}

13 changes: 12 additions & 1 deletion src/main/java/com/squidex/api/core/ClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public static Builder builder() {
public static final class Builder {
private Environment environment;

private OkHttpClient httpClient;

private final Map<String, String> headers = new HashMap<>();

private final Map<String, Supplier<String>> headerSuppliers = new HashMap<>();
Expand All @@ -93,8 +95,17 @@ public Builder appName(String appName) {
return this;
}

public Builder httpClient(OkHttpClient httpClient) {
this.httpClient = httpClient;
return this;
}

public ClientOptions build() {
return new ClientOptions(environment, headers, headerSuppliers, new OkHttpClient(), this.appName);
if (this.httpClient == null) {
this.httpClient = new OkHttpClient();
}

return new ClientOptions(environment, headers, headerSuppliers, this.httpClient, this.appName);
}
}
}
38 changes: 38 additions & 0 deletions src/test/java/com/squidex/api/SchemasTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.squidex.api;

import com.squidex.api.resources.schemas.requests.CreateSchemaDto;
import com.squidex.api.types.*;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.*;

public class SchemasTests extends TestBase {
private final SquidexApiClient client = Utils.getClient().client();

@Test
public void should_create_and_fetch_schema() {
CreateSchemaDto request = CreateSchemaDto.builder()
.name("schema-%s".formatted(UUID.randomUUID()))
.fields(Collections.singletonList(
UpsertSchemaFieldDto.builder()
.name("field1")
.properties(FieldPropertiesDto.string(StringFieldPropertiesDto.builder().build()))
.build()
)
)
.isPublished(true)
.build();

SchemaDto createdSchema = client.schemas().postSchema(request);

SchemaDto schema = client.schemas().getSchema(createdSchema.getId());
assertFalse(createdSchema.getFields().isEmpty());
assertEquals(createdSchema.getName(), schema.getName());
assertEquals(createdSchema.getFields().get(0), schema.getFields().get(0));
assertEquals(SchemaType.DEFAULT, schema.getType());
assertTrue(schema.getIsPublished());
}
}
8 changes: 8 additions & 0 deletions src/test/java/com/squidex/api/TestBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.squidex.api;

import org.junit.jupiter.api.extension.RegisterExtension;

public abstract class TestBase {
@RegisterExtension
static TestSetup staticExtension = new TestSetup();
}
8 changes: 0 additions & 8 deletions src/test/java/com/squidex/api/TestClient.java

This file was deleted.

Loading

0 comments on commit 7f49ecc

Please sign in to comment.