@@ -297,7 +297,7 @@
org.codehaus.mojo
versions-maven-plugin
- 2.7
+ 2.18.0
diff --git a/src/main/java/io/castle/client/Castle.java b/src/main/java/io/castle/client/Castle.java
index 61cc4ee9..3b9e06cc 100644
--- a/src/main/java/io/castle/client/Castle.java
+++ b/src/main/java/io/castle/client/Castle.java
@@ -9,6 +9,7 @@
import io.castle.client.internal.config.CastleSdkInternalConfiguration;
import io.castle.client.internal.json.CastleGsonModel;
import io.castle.client.internal.utils.CastleContextBuilder;
+import io.castle.client.internal.utils.Webhook;
import io.castle.client.model.CastleResponse;
import io.castle.client.model.CastleSdkConfigurationException;
import org.slf4j.Logger;
@@ -26,17 +27,16 @@
* Once set the {@code this#instance()} method will return that instance
*/
public class Castle {
- public static final String URL_TRACK = "/v1/track";
- public static final String URL_AUTHENTICATE = "/v1/authenticate";
- public static final String URL_DEVICES = "/v1/devices/";
- public static final String URL_USERS = "/v1/users/";
- public static final String URL_IMPERSONATE = "/v1/impersonate";
public static final String URL_PRIVACY = "/v1/privacy/";
public static final String URL_RISK = "/v1/risk";
public static final String URL_FILTER = "/v1/filter";
public static final String URL_LOG = "/v1/log";
+ public static final String URL_EVENTS = "/v1/events";
- public static final String URL_RECOVER = "/v1/users/%s/recover";
+ /**
+ * Header used by Castle to sign webhook payloads.
+ */
+ public static final String WEBHOOK_SIGNATURE_HEADER = "X-Castle-Signature";
public static final String URL_LISTS = "/v1/lists";
public static final String URL_LISTS_ID = "/v1/lists/%s";
@@ -270,6 +270,38 @@ public String secureUserID(String userId) {
return hashFunction.hashString(userId,com.google.common.base.Charsets.UTF_8).toString();
}
+ /**
+ * Verifies a Castle webhook signature against the raw request body.
+ *
+ * Castle signs every webhook with an HMAC-SHA256 of the raw request body using
+ * the account API secret, base64 encoded and sent in the
+ * {@code X-Castle-Signature} header.
+ *
+ * @param signature the value of the {@code X-Castle-Signature} header
+ * @param body the raw request body bytes
+ * @return {@code true} when the signature matches the computed signature
+ */
+ public boolean verifyWebhookSignature(String signature, byte[] body) {
+ return Webhook.verifySignature(internalConfiguration.getConfiguration().getApiSecret(), body, signature);
+ }
+
+ /**
+ * Verifies a Castle webhook signature for the given servlet request.
+ *
+ * The signature is read from the {@code X-Castle-Signature} header and verified
+ * against the supplied raw request body bytes.
+ *
+ * @param request the incoming webhook request
+ * @param body the raw request body bytes
+ * @return {@code true} when the signature matches the computed signature
+ */
+ public boolean verifyWebhookSignature(HttpServletRequest request, byte[] body) {
+ if (request == null) {
+ return false;
+ }
+ return verifyWebhookSignature(request.getHeader(WEBHOOK_SIGNATURE_HEADER), body);
+ }
+
/**
* Make a GET request to a Castle API endpoint such as /v1/{userId}/devices
*
diff --git a/src/main/java/io/castle/client/api/CastleApi.java b/src/main/java/io/castle/client/api/CastleApi.java
index ae782d8d..1131a0d5 100644
--- a/src/main/java/io/castle/client/api/CastleApi.java
+++ b/src/main/java/io/castle/client/api/CastleApi.java
@@ -48,79 +48,6 @@ public interface CastleApi {
*/
CastleApi mergeContext(Object additionalContext);
- /**
- * Makes a sync POST request to the authenticate endpoint containing all required parameters.
- *
- * Optional parameters (that is, traits and properties) are set to null.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID associated to an authentication attempt
- * @return a verdict that might result from a successful call to the Castle API or from the client's
- * {@link io.castle.client.model.AuthenticateFailoverStrategy}, in case of a failed call
- * @see The docs
- */
- Verdict authenticate(String event, String userId);
-
- /**
- * Makes a sync POST request to the authenticate endpoint containing required and optional parameters.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID associated to an authentication attempt
- * @param properties object for recording additional information connected to the event, takes null
- * @param traits object for recording additional information connected to the user, takes null
- * @return a verdict that might result from a successful call to the Castle API or from the client's
- * {@link io.castle.client.model.AuthenticateFailoverStrategy}, in case of a failed call
- * @see The docs
- */
- Verdict authenticate(String event, String userId, @Nullable Object properties, @Nullable Object traits);
-
- /**
- * Makes a sync POST request to the authenticate endpoint containing required and optional parameters.
- * @param message Event parameters
- * @return a verdict that might result from a successful call to the Castle API or from the client's
- */
- Verdict authenticate(CastleMessage message);
-
- JsonElement buildAuthenticateRequest(CastleMessage request);
-
- Verdict sendAuthenticateRequest(JsonElement request);
-
- void sendAuthenticateRequest(JsonElement request, AsyncCallbackHandler asyncCallbackHandler);
-
- /**
- * Makes an async POST request to the authenticate endpoint containing required and optional parameters.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID associated to an authentication attempt
- * @param properties object for recording additional information connected to the event, takes null
- * @param traits object for recording additional information connected to the user, takes null
- * @param asyncCallbackHandler a user-implemented instance of {@code AsyncCallbackHandler} which specifies
- * how to handle success of failure of authenticate API calls
- * @see The docs
- */
- void authenticateAsync(String event, String userId, @Nullable Object properties, @Nullable Object traits, AsyncCallbackHandler asyncCallbackHandler);
-
- /**
- * Makes an async POST request to the authenticate endpoint containing all required parameters.
- *
- * Optional parameters (that is, traits and properties) are set to null.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID associated to an authentication attempt
- * @param asyncCallbackHandler a user-implemented instance of {@code AsyncCallbackHandler} which specifies
- * how to handle success of failure of authenticate API calls
- * @see The docs
- */
- void authenticateAsync(String event, String userId, AsyncCallbackHandler asyncCallbackHandler);
-
- /**
- * Makes an async POST request to the authenticate endpoint containing required and optional parameters.
- * @param message Event parameters
- * @param asyncCallbackHandler a user-implemented instance of {@code AsyncCallbackHandler} which specifies
- * how to handle success of failure of authenticate API calls
- */
- void authenticateAsync(CastleMessage message, AsyncCallbackHandler asyncCallbackHandler);
-
/**
* Sets the doNotTrack boolean of a new instance of {@code CastleApi}
*
@@ -130,176 +57,56 @@ public interface CastleApi {
*/
CastleApi doNotTrack(boolean doNotTrack);
- /**
- * Makes an async POST request to the track endpoint containing all required parameters.
- *
- * @param event a String representing an event understood by the Castle API
- * @see The docs
- */
- void track(String event);
-
- /**
- * Makes an async POST request to the track endpoint containing all required parameters and a user ID.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID
- * @see The docs
- */
- void track(String event, @Nullable String userId);
-
- /**
- * Makes an async POST request to the track endpoint containing all required parameters and a user ID.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID
- * @param reviewId a String representing a reference to review ID
- * @see The docs
- */
- void track(String event, @Nullable String userId, @Nullable String reviewId);
-
- /**
- * Makes an async POST request to the track endpoint containing required and optional parameters.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID
- * @param reviewId a String representing a reference to review ID
- * @param properties object for recording additional information connected to the event, takes null
- * @see The docs
- */
- void track(String event, @Nullable String userId, @Nullable String reviewId, @Nullable Object properties);
-
- /**
- * Makes an async POST request to the track endpoint containing required and optional parameters.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID
- * @param reviewId a String representing a reference to review ID
- * @param properties object for recording additional information connected to the event, takes null
- * @param traits object for recording additional information about the user like email or name, takes null
- * @see The docs
- */
- void track(String event, @Nullable String userId, @Nullable String reviewId, @Nullable Object properties, @Nullable Object traits);
-
- /**
- * Makes an async POST request to the track endpoint containing required and optional parameters and a custom handler
- * for the async call's success and failure cases.
- *
- * @param event a String representing an event understood by the Castle API
- * @param userId a String representing a user ID
- * @param reviewId a String representing a reference to review ID
- * @param properties object for recording additional information connected to the event, takes null
- * @param traits object for recording additional information about the user like email or name, takes null
- * @param asyncCallbackHandler a user-implemented instance of {@code AsyncCallbackHandler} which specifies
- * how to handle success of failure of authenticate API calls
- * @see The docs
- */
- void track(String event, @Nullable String userId, @Nullable String reviewId, @Nullable Object properties, @Nullable Object traits, AsyncCallbackHandler asyncCallbackHandler);
-
- /**
- * Makes an async POST request to the track endpoint containing required and optional parameters.
- * @param message Event parameters
- */
- void track(CastleMessage message);
-
- JsonElement buildTrackRequest(CastleMessage request);
-
- void sendTrackRequest(JsonElement request);
-
- void sendTrackRequest(JsonElement request, AsyncCallbackHandler asyncCallbackHandler);
+ CastleResponse get(String path);
- /**
- * Makes an async POST request to the track endpoint containing required and optional parameters.
- * @param message Event parameters
- * @param asyncCallbackHandler a user-implemented instance of {@code AsyncCallbackHandler} which specifies
- * how to handle success of failure of authenticate API calls
- */
- void track(CastleMessage message, AsyncCallbackHandler asyncCallbackHandler);
+ CastleResponse post(String path, Object payload);
- /**
- * Makes a DELETE request to the privacy endpoint.
- *
- * @param userId String representing a user id
- * @see The docs
- */
- Boolean removeUser(String userId);
+ CastleResponse put(String path);
- /**
- * Makes a sync POST request to the approve device endpoint.
- *
- * @param deviceToken string representing the device to approve
- * @return device model object
- */
- CastleUserDevice approve(String deviceToken);
+ CastleResponse put(String path, Object payload);
- /**
- * Makes a sync POST request to the report device endpoint.
- *
- * @param deviceToken string representing the device to report
- * @return device model object
- */
- CastleUserDevice report(String deviceToken);
+ CastleResponse delete(String path);
- /**
- * Makes a sync GET request to the user devices endpoint.
- *
- * @param userId user unique ID
- * @return devices model object
- */
- CastleUserDevices userDevices(String userId);
+ CastleResponse delete(String path, Object payload);
/**
- * Makes a sync GET request to the device endpoint.
+ * Makes a sync POST request to the privacy endpoint to request a user's data.
*
- * @param deviceToken string representing the device to report
- * @return device model object
+ * @param payload request parameters
+ * @return a decoded json response
*/
- CastleUserDevice device(String deviceToken);
+ CastleResponse requestUserData(ImmutableMap payload);
/**
- * Makes a sync POST request to the impersonate endpoint.
+ * Makes a sync DELETE request to the privacy endpoint to delete a user's data.
*
- * @param userId user unique ID
- * @return
+ * @param payload request parameters
+ * @return a decoded json response
*/
- CastleSuccess impersonateStart(String userId);
+ CastleResponse deleteUserData(ImmutableMap payload);
/**
- * Makes a sync POST request to the impersonate endpoint.
+ * Makes a sync GET request to the events schema endpoint.
*
- * @param userId user unique ID
- * @param impersonator description of impersonator, e.g., email
- * @return
+ * @return a decoded json response
*/
- CastleSuccess impersonateStart(String userId, String impersonator);
+ CastleResponse eventsSchema();
/**
- * Makes a sync DELETE request to the impersonate endpoint.
+ * Makes a sync POST request to the events query endpoint.
*
- * @param userId user unique ID
- * @return
+ * @param payload query parameters
+ * @return a decoded json response
*/
- CastleSuccess impersonateEnd(String userId);
+ CastleResponse queryEvents(ImmutableMap payload);
/**
- * Makes a sync DELETE request to the impersonate endpoint.
+ * Makes a sync POST request to the events group endpoint.
*
- * @param userId user unique ID
- * @param impersonator description of impersonator, e.g., email
- * @return
+ * @param payload group parameters
+ * @return a decoded json response
*/
- CastleSuccess impersonateEnd(String userId, String impersonator);
-
- CastleResponse get(String path);
-
- CastleResponse post(String path, Object payload);
-
- CastleResponse put(String path);
-
- CastleResponse put(String path, Object payload);
-
- CastleResponse delete(String path);
-
- CastleResponse delete(String path, Object payload);
+ CastleResponse groupEvents(ImmutableMap payload);
/**
* Makes a sync POST request to the risk endpoint.
@@ -451,12 +258,4 @@ public interface CastleApi {
* @return
*/
CastleResponse log(Log payload);
-
- /**
- * Makes a sync PUT request to the recover endpoint.
- *
- * @param userId User ID
- * @return
- */
- CastleResponse recover(String userId);
}
diff --git a/src/main/java/io/castle/client/internal/CastleApiImpl.java b/src/main/java/io/castle/client/internal/CastleApiImpl.java
index aaa96527..46c8be31 100644
--- a/src/main/java/io/castle/client/internal/CastleApiImpl.java
+++ b/src/main/java/io/castle/client/internal/CastleApiImpl.java
@@ -12,7 +12,6 @@
import io.castle.client.internal.utils.CastleContextBuilder;
import io.castle.client.internal.utils.ContextMerge;
import io.castle.client.internal.utils.Timestamp;
-import io.castle.client.internal.utils.VerdictBuilder;
import io.castle.client.model.*;
import io.castle.client.model.generated.*;
import jakarta.servlet.http.HttpServletRequest;
@@ -70,258 +69,79 @@ public CastleApi doNotTrack(boolean doNotTrack) {
}
@Override
- public Verdict authenticate(String event, String userId) {
- return authenticate(event, userId, null, null);
- }
-
- @Override
- public Verdict authenticate(String event, String userId, @Nullable Object properties, @Nullable Object traits) {
- return authenticate(buildMessage(event, userId, properties, traits));
- }
-
- @Override
- public Verdict authenticate(CastleMessage message) {
- JsonElement request = buildAuthenticateRequest(message);
- return sendAuthenticateRequest(request);
- }
-
- @Override
- public JsonElement buildAuthenticateRequest(CastleMessage message) {
- return buildJson(message);
- }
-
- @Override
- public Verdict sendAuthenticateRequest(JsonElement request) {
- Preconditions.checkNotNull(request, "Request json can not be null");
-
- if (doNotTrack) {
- return buildVerdictForDoNotTrack(request.getAsJsonObject().get("user_id").getAsString());
- }
-
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendAuthenticateSync(request);
- }
-
- @Override
- public void sendAuthenticateRequest(JsonElement request, AsyncCallbackHandler asyncCallbackHandler) {
- Preconditions.checkNotNull(request, "Request json can not be null");
-
- if (doNotTrack) {
- asyncCallbackHandler.onResponse(buildVerdictForDoNotTrack(request.getAsJsonObject().get("user_id").getAsString()));
- } else {
- Preconditions.checkNotNull(asyncCallbackHandler, "The async handler can not be null");
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- restApi.sendAuthenticateAsync(request, asyncCallbackHandler);
- }
- }
-
- private Verdict buildVerdictForDoNotTrack(String userId) {
- return VerdictBuilder.failover("Castle set to do not track.")
- .withAction(AuthenticateAction.ALLOW)
- .withUserId(userId)
- .build();
- }
-
- @Override
- public void authenticateAsync(String event, String userId, @Nullable Object properties, @Nullable Object traits, AsyncCallbackHandler asyncCallbackHandler) {
- authenticateAsync(
- buildMessage(event, userId, properties, traits),
- asyncCallbackHandler
- );
- }
-
- @Override
- public void authenticateAsync(String event, String userId, AsyncCallbackHandler asyncCallbackHandler) {
- authenticateAsync(
- CastleMessage.builder(event).userId(userId).build(),
- asyncCallbackHandler
- );
- }
-
- @Override
- public void authenticateAsync(CastleMessage message, AsyncCallbackHandler asyncCallbackHandler) {
- JsonElement request = buildAuthenticateRequest(message);
- sendAuthenticateRequest(request, asyncCallbackHandler);
- }
-
- @Override
- public void track(String event) {
- track(event, null, null, null, null);
- }
-
- @Override
- public void track(String event, String userId) {
- track(event, userId, null, null, null);
- }
-
- @Override
- public void track(String event, @Nullable String userId, @Nullable String reviewId) {
- track(event, userId, reviewId, null, null, null);
- }
-
- @Override
- public void track(String event, String userId, String reviewId, Object properties) {
- track(event, userId, reviewId, properties, null, null);
- }
-
- @Override
- public void track(String event, @Nullable String userId, @Nullable String reviewId, @Nullable Object properties, @Nullable Object traits) {
- track(event, userId, reviewId, properties, traits, null);
- }
-
- @Override
- public void track(String event, @Nullable String userId, @Nullable String reviewId, @Nullable Object properties, @Nullable Object traits, AsyncCallbackHandler asyncCallbackHandler) {
-
- CastleMessage message = buildMessage(event, userId, properties, traits);
-
- if (reviewId != null) {
- message.setReviewId(reviewId);
- }
-
- track(message, asyncCallbackHandler);
- }
-
- @Override
- public void track(CastleMessage message) {
- track(message, null);
- }
-
- @Override
- public JsonElement buildTrackRequest(CastleMessage message) {
- Preconditions.checkNotNull(message.getEvent());
- return buildJson(message);
- }
-
- @Override
- public void sendTrackRequest(JsonElement request) {
- sendTrackRequest(request, null);
- }
-
- @Override
- public void sendTrackRequest(JsonElement request, AsyncCallbackHandler asyncCallbackHandler) {
- Preconditions.checkNotNull(request, "Request json can not be null");
-
- if (doNotTrack) {
- if (asyncCallbackHandler != null) {
- asyncCallbackHandler.onResponse(true);
- }
- return;
- }
-
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- restApi.sendTrackRequest(request, asyncCallbackHandler);
- }
-
- @Override
- public void track(CastleMessage message, @Nullable AsyncCallbackHandler asyncCallbackHandler) {
- JsonElement messageJson = buildTrackRequest(message);
-
- sendTrackRequest(messageJson, asyncCallbackHandler);
- }
-
- @Override
- public Boolean removeUser(String userId) {
- Preconditions.checkNotNull(userId);
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendPrivacyRemoveUser(userId);
- }
-
- @Override
- public CastleUserDevice approve(String deviceToken) {
- Preconditions.checkNotNull(deviceToken);
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendApproveDeviceRequestSync(deviceToken);
- }
-
- @Override
- public CastleUserDevice report(String deviceToken) {
- Preconditions.checkNotNull(deviceToken);
+ public CastleResponse get(String path) {
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendReportDeviceRequestSync(deviceToken);
+ return restApi.get(path);
}
@Override
- public CastleUserDevices userDevices(String userId) {
- Preconditions.checkNotNull(userId);
+ public CastleResponse post(String path, Object payload) {
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendGetUserDevicesRequestSync(userId);
+ return restApi.post(path, payload);
}
@Override
- public CastleUserDevice device(String deviceToken) {
- Preconditions.checkNotNull(deviceToken);
+ public CastleResponse put(String path) {
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendGetUserDeviceRequestSync(deviceToken);
+ return restApi.put(path);
}
@Override
- public CastleSuccess impersonateStart(String userId) {
- Preconditions.checkNotNull(userId);
+ public CastleResponse put(String path, Object payload) {
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendImpersonateStartRequestSync(userId, null, contextJson);
+ return restApi.put(path, payload);
}
@Override
- public CastleSuccess impersonateStart(String userId, String impersonator) {
- Preconditions.checkNotNull(userId);
+ public CastleResponse delete(String path) {
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendImpersonateStartRequestSync(userId, impersonator, contextJson);
+ return restApi.delete(path);
}
@Override
- public CastleSuccess impersonateEnd(String userId) {
- Preconditions.checkNotNull(userId);
+ public CastleResponse delete(String path, Object payload) {
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendImpersonateEndRequestSync(userId, "", contextJson);
+ return restApi.delete(path, payload);
}
- @Override
- public CastleSuccess impersonateEnd(String userId, String impersonator) {
- Preconditions.checkNotNull(userId);
+ public CastleResponse risk(ImmutableMap payload) {
+ Preconditions.checkNotNull(payload);
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.sendImpersonateEndRequestSync(userId, impersonator, contextJson);
+ return restApi.post(Castle.URL_RISK, payload);
}
@Override
- public CastleResponse get(String path) {
+ public CastleResponse requestUserData(ImmutableMap payload) {
+ Preconditions.checkNotNull(payload);
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.get(path);
+ return restApi.post(Castle.URL_PRIVACY + "users", payload);
}
@Override
- public CastleResponse post(String path, Object payload) {
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.post(path, payload);
- }
-
- @Override
- public CastleResponse put(String path) {
+ public CastleResponse deleteUserData(ImmutableMap payload) {
+ Preconditions.checkNotNull(payload);
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.put(path);
+ return restApi.delete(Castle.URL_PRIVACY + "users", payload);
}
@Override
- public CastleResponse put(String path, Object payload) {
+ public CastleResponse eventsSchema() {
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.put(path, payload);
+ return restApi.get(Castle.URL_EVENTS + "/schema");
}
@Override
- public CastleResponse delete(String path) {
+ public CastleResponse queryEvents(ImmutableMap payload) {
+ Preconditions.checkNotNull(payload);
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.delete(path);
+ return restApi.post(Castle.URL_EVENTS + "/query", payload);
}
@Override
- public CastleResponse delete(String path, Object payload) {
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.delete(path, payload);
- }
-
- public CastleResponse risk(ImmutableMap payload) {
+ public CastleResponse groupEvents(ImmutableMap payload) {
Preconditions.checkNotNull(payload);
RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.post(Castle.URL_RISK, payload);
+ return restApi.post(Castle.URL_EVENTS + "/group", payload);
}
@Override
@@ -482,55 +302,4 @@ public CastleResponse log(Log payload) {
return restApi.post(Castle.URL_LOG, payload);
}
- @Override
- public CastleResponse recover(String userId) {
- Preconditions.checkNotNull(userId, "UserId can not be null");
- Preconditions.checkArgument(!userId.isEmpty());
-
- RestApi restApi = configuration.getRestApiFactory().buildBackend();
- return restApi.put(String.format(Castle.URL_RECOVER, userId));
- }
-
- private CastleMessage buildMessage(String event, String userId, @Nullable Object properties, @Nullable Object traits) {
- CastleMessage message = new CastleMessage(event);
-
- message.setUserId(userId);
-
- return setTraitsAndProperties(message, properties, traits);
- }
-
- private CastleMessage setTraitsAndProperties(CastleMessage message, @Nullable Object properties, @Nullable Object traits) {
- if (properties != null) {
- JsonElement propertiesJson = configuration.getModel().getGson().toJsonTree(properties);
- message.setProperties(propertiesJson);
- }
-
- if (traits != null) {
- JsonElement traitsJson = configuration.getModel().getGson().toJsonTree(traits);
- message.setUserTraits(traitsJson);
- }
-
- return message;
- }
-
- private JsonElement buildJson(CastleMessage message) throws CastleRuntimeException {
- JsonObject contextJson;
- // Context can be either from the message or from the instance of this
- // class. Make sure we have one
- CastleContext context = message.getContext();
- if (context == null) {
- contextJson = this.contextJson;
- } else {
- contextJson = configuration.getModel().getGson().toJsonTree(context).getAsJsonObject();
- }
-
- JsonElement messageJson = configuration.getModel().getGson().toJsonTree(message);
- JsonObject messageObj = messageJson.getAsJsonObject();
- messageObj.add("context", contextJson);
-
- // Add sent_at to json
- messageObj.addProperty("sent_at", Timestamp.timestamp());
-
- return messageObj;
- }
}
diff --git a/src/main/java/io/castle/client/internal/backend/OkRestApiBackend.java b/src/main/java/io/castle/client/internal/backend/OkRestApiBackend.java
index 46c77f6c..ad551005 100644
--- a/src/main/java/io/castle/client/internal/backend/OkRestApiBackend.java
+++ b/src/main/java/io/castle/client/internal/backend/OkRestApiBackend.java
@@ -1,12 +1,9 @@
package io.castle.client.internal.backend;
import com.google.gson.*;
-import io.castle.client.Castle;
import io.castle.client.internal.config.CastleConfiguration;
import io.castle.client.internal.json.CastleGsonModel;
import io.castle.client.internal.utils.OkHttpExceptionUtil;
-import io.castle.client.internal.utils.VerdictBuilder;
-import io.castle.client.internal.utils.VerdictTransportModel;
import io.castle.client.model.*;
import okhttp3.*;
@@ -25,224 +22,15 @@ public class OkRestApiBackend implements RestApi {
private final CastleConfiguration configuration;
private final HttpUrl baseUrl;
- private final HttpUrl track;
- private final HttpUrl authenticate;
- private final HttpUrl deviceBase;
- private final HttpUrl userBase;
- private final HttpUrl impersonateBase;
- private final HttpUrl privacyBase;
public OkRestApiBackend(OkHttpClient client, CastleGsonModel model, CastleConfiguration configuration) {
this.baseUrl = HttpUrl.parse(configuration.getApiBaseUrl());
this.client = client;
this.model = model;
this.configuration = configuration;
- this.track = baseUrl.resolve(Castle.URL_TRACK);
- this.authenticate = baseUrl.resolve(Castle.URL_AUTHENTICATE);
- this.deviceBase = baseUrl.resolve(Castle.URL_DEVICES);
- this.userBase = baseUrl.resolve(Castle.URL_USERS);
- this.impersonateBase = baseUrl.resolve(Castle.URL_IMPERSONATE);
- this.privacyBase = baseUrl.resolve(Castle.URL_PRIVACY);
}
@Override
- public void sendTrackRequest(JsonElement payload, final AsyncCallbackHandler asyncCallbackHandler) {
- RequestBody body = buildRequestBody(payload);
- Request request = new Request.Builder()
- .url(track)
- .post(body)
- .build();
- client.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- Castle.logger.error("HTTP layer. Error sending track request.", e);
- if (asyncCallbackHandler != null) {
- asyncCallbackHandler.onException(e);
- }
- }
-
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- try (ResponseBody responseBody = response.body()) {
- if (asyncCallbackHandler != null) {
- asyncCallbackHandler.onResponse(response.isSuccessful());
- }
- }
- }
- });
- }
-
- @Override
- public Verdict sendAuthenticateSync(JsonElement payloadJson) {
- final String userId = getUserIdFromPayload(payloadJson);
-
- RequestBody body = buildRequestBody(payloadJson);
- Request request = new Request.Builder()
- .url(authenticate)
- .post(body)
- .build();
- try (Response response = client.newCall(request).execute()) {
- return extractAuthenticationAction(response, userId);
- } catch (IOException e) {
- Castle.logger.error("HTTP layer. Error sending request.", e);
- if (configuration.getAuthenticateFailoverStrategy().isThrowTimeoutException()) {
- throw OkHttpExceptionUtil.handle(e);
- } else {
- return VerdictBuilder.failover(e.getMessage())
- .withAction(configuration.getAuthenticateFailoverStrategy().getDefaultAction())
- .withUserId(userId)
- .build();
- }
- }
- }
-
- @Override
- public void sendAuthenticateAsync(JsonElement payloadJson, final AsyncCallbackHandler asyncCallbackHandler) {
- final String userId = getUserIdFromPayload(payloadJson);
-
- RequestBody body = buildRequestBody(payloadJson);
- Request request = new Request.Builder()
- .url(authenticate)
- .post(body)
- .build();
- client.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- if (configuration.getAuthenticateFailoverStrategy().isThrowTimeoutException()) {
- asyncCallbackHandler.onException(OkHttpExceptionUtil.handle(e));
- } else {
- asyncCallbackHandler.onResponse(
- VerdictBuilder.failover(e.getMessage())
- .withAction(configuration.getAuthenticateFailoverStrategy().getDefaultAction())
- .withUserId(userId)
- .build()
- );
- }
- }
-
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- try (ResponseBody responseBody = response.body()) {
- asyncCallbackHandler.onResponse(extractAuthenticationAction(response, userId));
- }
- }
- });
- }
-
- private String getUserIdFromPayload(JsonElement payloadJson) {
- final String userId = ((JsonObject) payloadJson).has("user_id") ? ((JsonObject) payloadJson).get("user_id").getAsString() : null;
- if (userId == null) {
- Castle.logger.warn("Authenticate called with user_id null. Is this correct?");
- }
- return userId;
- }
-
- private RequestBody buildRequestBody(JsonElement payloadJson) {
- JsonObject json = payloadJson.getAsJsonObject();
- return RequestBody.create(json.toString(), JSON);
- }
-
- private Verdict extractAuthenticationAction(Response response, String userId) throws IOException {
- String errorReason = response.message();
- String jsonResponse = response.body().string();
-
- if (response.isSuccessful()) {
- Gson gson = model.getGson();
- VerdictTransportModel transport = gson.fromJson(jsonResponse, VerdictTransportModel.class);
- if (transport != null && transport.getAction() != null) {
- return VerdictBuilder.fromTransport(transport, JsonParser.parseString(jsonResponse));
- } else {
- errorReason = "Invalid JSON in response";
- }
- }
-
- if (response.code() >= 500) {
- //Use failover for error backends calls.
- if (!configuration.getAuthenticateFailoverStrategy().isThrowTimeoutException()) {
- Verdict verdict = VerdictBuilder.failover(errorReason)
- .withAction(configuration.getAuthenticateFailoverStrategy().getDefaultAction())
- .withUserId(userId)
- .build();
- return verdict;
- } else {
- throw new CastleApiInternalServerErrorException(response);
- }
- }
-
- // Could not extract Verdict, so fail for client logic space.
- throw new CastleRuntimeException(response);
- }
-
- @Override
- public Boolean sendPrivacyRemoveUser(String userId) {
- Request request = createPrivacyRemoveRequest(userId);
- try (Response response = client.newCall(request).execute()) {
- return extractResponse(response);
- } catch (IOException e) {
- throw OkHttpExceptionUtil.handle(e);
- }
- }
-
- @Override
- public CastleUserDevice sendApproveDeviceRequestSync(String deviceToken) {
- Request request = createApproveDeviceRequest(deviceToken);
- try (Response response = client.newCall(request).execute()) {
- return extractDevice(response);
- } catch (IOException e) {
- throw OkHttpExceptionUtil.handle(e);
- }
- }
-
- @Override
- public CastleUserDevice sendReportDeviceRequestSync(String deviceToken) {
- Request request = createReportDeviceRequest(deviceToken);
- try (Response response = client.newCall(request).execute()) {
- return extractDevice(response);
- } catch (IOException e) {
- throw OkHttpExceptionUtil.handle(e);
- }
- }
-
- @Override
- public CastleUserDevices sendGetUserDevicesRequestSync(String userId) {
- Request request = createGetUserDevicesRequest(userId);
- try (Response response = client.newCall(request).execute()) {
- return extractDevices(response);
- } catch (IOException e) {
- throw OkHttpExceptionUtil.handle(e);
- }
- }
-
- @Override
- public CastleUserDevice sendGetUserDeviceRequestSync(String deviceToken) {
- Request request = createGetUserDeviceRequest(deviceToken);
- try (Response response = client.newCall(request).execute()) {
- return extractDevice(response);
- } catch (IOException e) {
- throw OkHttpExceptionUtil.handle(e);
- }
- }
-
- @Override
- public CastleSuccess sendImpersonateStartRequestSync(String userId, String impersonator, JsonObject contextJson) {
- Request request = createImpersonateStartRequest(userId, impersonator, contextJson);
- try (Response response = client.newCall(request).execute()) {
- return extractSuccess(response);
- } catch (IOException e) {
- throw OkHttpExceptionUtil.handle(e);
- }
- }
-
- @Override
- public CastleSuccess sendImpersonateEndRequestSync(String userId, String impersonator, JsonObject contextJson) {
- Request request = createImpersonateEndRequest(userId, impersonator, contextJson);
- try (Response response = client.newCall(request).execute()) {
- return extractSuccess(response);
- } catch (IOException e) {
- throw OkHttpExceptionUtil.handle(e);
- }
- }
-
public CastleResponse get(String path) {
return makeRequest(path, null, METHOD_GET);
}
@@ -302,118 +90,6 @@ private CastleResponse makeRequest(String path, JsonElement payload, String meth
}
}
- private CastleUserDevice extractDevice(Response response) throws IOException {
- return (CastleUserDevice) extract(response, CastleUserDevice.class);
- }
-
- private CastleUserDevices extractDevices(Response response) throws IOException {
- return (CastleUserDevices) extract(response, CastleUserDevices.class);
- }
-
- private Object extract(Response response, Class clazz) throws IOException {
- if (response.isSuccessful()) {
- String jsonResponse = response.body().string();
- Gson gson = model.getGson();
- return gson.fromJson(jsonResponse, clazz);
- } else if (response.code() == 404) {
- return null;
- }
- OkHttpExceptionUtil.handle(response);
- return null;
- }
-
- private CastleSuccess extractSuccess(Response response) throws IOException {
- if (response.isSuccessful()) {
- if (response.body() != null) {
- String jsonResponse = response.body().string();
- Gson gson = model.getGson();
- return gson.fromJson(jsonResponse, CastleSuccess.class);
- }
- }
- OkHttpExceptionUtil.handle(response);
- return null;
- }
-
- private Boolean extractResponse(Response response) {
- if (response.isSuccessful()) {
- return true;
- } else if (response.code() == 404) {
- return null;
- }
- OkHttpExceptionUtil.handle(response);
- return false;
- }
-
- private CastleUser extractUser(Response response) throws IOException {
- return (CastleUser) extract(response, CastleUser.class);
- }
-
- private Request createApproveDeviceRequest(String deviceToken) {
- HttpUrl approveDeviceUrl = deviceBase.resolve(deviceToken + "/approve");
- return new Request.Builder()
- .url(approveDeviceUrl)
- .put(createEmptyRequestBody())
- .build();
- }
-
- private Request createReportDeviceRequest(String deviceToken) {
- HttpUrl reportDeviceUrl = deviceBase.resolve(deviceToken + "/report");
- return new Request.Builder()
- .url(reportDeviceUrl)
- .put(createEmptyRequestBody())
- .build();
- }
-
- private Request createGetUserDevicesRequest(String userId) {
- HttpUrl getUserDevicesUrl = userBase.resolve(userId + "/devices");
- return new Request.Builder()
- .url(getUserDevicesUrl)
- .get()
- .build();
- }
-
- private Request createGetUserDeviceRequest(String deviceToken) {
- HttpUrl getUserDeviceUrl = deviceBase.resolve(deviceToken);
- return new Request.Builder()
- .url(getUserDeviceUrl)
- .get()
- .build();
- }
-
- private Request createImpersonateStartRequest(String userId, String impersonator, JsonObject contextJson) {
- HttpUrl impersonateUrl = impersonateBase;
-
- ImpersonatePayload payload = new ImpersonatePayload(userId, impersonator, contextJson);
-
- RequestBody body = RequestBody.create(model.getGson().toJson(payload), JSON);
-
- return new Request.Builder()
- .url(impersonateUrl)
- .post(body)
- .build();
- }
-
- private Request createImpersonateEndRequest(String userId, String impersonator, JsonObject contextJson) {
- HttpUrl impersonateUrl = impersonateBase;
-
- ImpersonatePayload payload = new ImpersonatePayload(userId, impersonator, contextJson);
-
- RequestBody body = RequestBody.create(model.getGson().toJson(payload), JSON);
-
- return new Request.Builder()
- .url(impersonateUrl)
- .delete(body)
- .build();
- }
-
- private Request createPrivacyRemoveRequest(String userId) {
- HttpUrl privacyRemoveUrl = privacyBase.resolve("users/" + userId);
- return new Request.Builder()
- .url(privacyRemoveUrl)
- .delete()
- .build();
- }
-
private RequestBody createEmptyRequestBody() {
return RequestBody.create(new byte[0], null);
}
diff --git a/src/main/java/io/castle/client/internal/backend/RestApi.java b/src/main/java/io/castle/client/internal/backend/RestApi.java
index 1c19d081..2c740caa 100644
--- a/src/main/java/io/castle/client/internal/backend/RestApi.java
+++ b/src/main/java/io/castle/client/internal/backend/RestApi.java
@@ -1,91 +1,9 @@
package io.castle.client.internal.backend;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
import io.castle.client.model.*;
public interface RestApi {
- /**
- *
- * @param payloadJson JSON object containing the event properties
- * @param asyncCallbackHandler callback to inform if request was correctly sent
- */
- void sendTrackRequest(JsonElement payloadJson, AsyncCallbackHandler asyncCallbackHandler);
-
- /**
- *
- * @param payloadJson JSON object containing the event properties
- * @return Verdict to be used in login logic
- */
- Verdict sendAuthenticateSync(JsonElement payloadJson);
-
- /**
- *
- * @param payloadJson JSON object containing the event properties
- * @param asyncCallbackHandler callback to inform if request was correctly sent
- */
- void sendAuthenticateAsync(JsonElement payloadJson, AsyncCallbackHandler asyncCallbackHandler);
-
- /**
- * Remove user from Castle (GDPR reasons)
- * @see The docs
- * @param userId user id to be removed
- */
- Boolean sendPrivacyRemoveUser(String userId);
-
- /**
- * Sync call to the approve device endpoint.
- *
- * @param deviceToken string representing the token for the device to get
- * @return a {@code device} with metadata contained in the body of the response
- */
- CastleUserDevice sendApproveDeviceRequestSync(String deviceToken);
-
- /**
- * Sync call to the report device endpoint.
- *
- * @param deviceToken string representing the token for the device to get
- * @return a {@code device} with metadata contained in the body of the response
- */
- CastleUserDevice sendReportDeviceRequestSync(String deviceToken);
-
- /**
- * Sync call to the devices endpoint.
- *
- * @param userId string representing the user to get devices for
- * @return a {@code devices} with metadata contained in the body of the response
- */
- CastleUserDevices sendGetUserDevicesRequestSync(String userId);
-
- /**
- * Sync call to the device endpoint.
- *
- * @param deviceToken string representing the token for the device to get
- * @return a {@code device} with metadata contained in the body of the response
- */
- CastleUserDevice sendGetUserDeviceRequestSync(String deviceToken);
-
- /**
- * Sync call to the impersonate endpoint.
- *
- * @param userId id of the user to impersonate
- * @param impersonator id of the user doing the impersonation
- * @param contextJson context json
- * @return a success message
- */
- CastleSuccess sendImpersonateStartRequestSync(String userId, String impersonator, JsonObject contextJson);
-
- /**
- * Sync call to the impersonate endpoint.
- *
- * @param userId id of the user to stop impersonating
- * @param impersonator id of the user doing the impersonation
- * @param contextJson context json
- * @return a success message
- */
- CastleSuccess sendImpersonateEndRequestSync(String userId, String impersonator, JsonObject contextJson);
-
/**
* Make a GET request to a Castle API endpoint such as /v1/{userId}/devices
*
diff --git a/src/main/java/io/castle/client/internal/config/CastleConfiguration.java b/src/main/java/io/castle/client/internal/config/CastleConfiguration.java
index d4b5f73d..dd884b9e 100644
--- a/src/main/java/io/castle/client/internal/config/CastleConfiguration.java
+++ b/src/main/java/io/castle/client/internal/config/CastleConfiguration.java
@@ -1,7 +1,6 @@
package io.castle.client.internal.config;
import io.castle.client.internal.backend.CastleBackendProvider;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.CastleRuntimeException;
import java.util.List;
@@ -24,11 +23,6 @@ public class CastleConfiguration {
*/
private final int timeout;
- /**
- * Strategy for returning a {@code verdict} when an authenticate call fails.
- */
- private final AuthenticateFailoverStrategy authenticateFailoverStrategy;
-
/**
* List of headers that will get passed to the {@code CastleContext} unless they are denyListed.
*/
@@ -66,10 +60,9 @@ public class CastleConfiguration {
*/
private final int maxRequests;
- public CastleConfiguration(String apiBaseUrl, int timeout, AuthenticateFailoverStrategy authenticateFailoverStrategy, List allowListHeaders, List denyListHeaders, String apiSecret, String castleAppId, CastleBackendProvider backendProvider, boolean logHttpRequests, List ipHeaders, Integer maxRequests) {
+ public CastleConfiguration(String apiBaseUrl, int timeout, List allowListHeaders, List denyListHeaders, String apiSecret, String castleAppId, CastleBackendProvider backendProvider, boolean logHttpRequests, List ipHeaders, Integer maxRequests) {
this.apiBaseUrl = apiBaseUrl;
this.timeout = timeout;
- this.authenticateFailoverStrategy = authenticateFailoverStrategy;
this.allowListHeaders = allowListHeaders;
this.denyListHeaders = denyListHeaders;
this.apiSecret = apiSecret;
@@ -88,10 +81,6 @@ public int getTimeout() {
return timeout;
}
- public AuthenticateFailoverStrategy getAuthenticateFailoverStrategy() {
- return authenticateFailoverStrategy;
- }
-
public List getAllowListHeaders() {
return allowListHeaders;
}
diff --git a/src/main/java/io/castle/client/internal/config/CastleConfigurationBuilder.java b/src/main/java/io/castle/client/internal/config/CastleConfigurationBuilder.java
index ab177de1..43823078 100644
--- a/src/main/java/io/castle/client/internal/config/CastleConfigurationBuilder.java
+++ b/src/main/java/io/castle/client/internal/config/CastleConfigurationBuilder.java
@@ -4,8 +4,6 @@
import com.google.common.collect.ImmutableList;
import io.castle.client.internal.backend.CastleBackendProvider;
import io.castle.client.internal.utils.HeaderNormalizer;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.CastleSdkConfigurationException;
import java.util.LinkedList;
@@ -19,7 +17,6 @@
* The fields that can be set in a CastleConfiguration:
*
* timeout
- * failoverStrategy
* allowListHeaders
* denyListHeaders
* apiSecret
@@ -42,11 +39,6 @@ public class CastleConfigurationBuilder {
*/
private int timeout = 500;
- /**
- * Strategy used when an authenticate call to the Castle API fails.
- */
- private AuthenticateFailoverStrategy failoverStrategy;
-
/**
* Strings representing headers that should be passed to the context object unless they are also denyListed.
*/
@@ -111,7 +103,6 @@ public static CastleConfigurationBuilder defaultConfigBuilder() {
.withDefaultDenyList()
.withDefaultApiBaseUrl()
.withTimeout(500)
- .withDefaultAuthenticateFailoverStrategy()
.withDefaultBackendProvider()
.withMaxRequests(5);
return builder;
@@ -163,29 +154,6 @@ public CastleConfigurationBuilder withTimeout(int timeout) {
return this;
}
- /**
- * Establishes the authentication strategy that will be used in case of a timeout when performing a
- * {@code CastleApi#authenticate} call.
- *
- * @param failoverStrategy strategy to use for failed authenticate API calls; not null.
- * @return a castleConfigurationBuilder with the chosen AuthenticationStrategy set
- */
- public CastleConfigurationBuilder withAuthenticateFailoverStrategy(AuthenticateFailoverStrategy failoverStrategy) {
- this.failoverStrategy = failoverStrategy;
- return this;
- }
-
- /**
- * Sets the failover strategy for the authenticate Castle API call to allow.
- *
- * The authenticate failover strategy for the default configuration is to return {@link AuthenticateAction#ALLOW}.
- *
- * @return a castleConfigurationBuilder with allow as the authenticate failover strategy
- */
- public CastleConfigurationBuilder withDefaultAuthenticateFailoverStrategy() {
- return this.withAuthenticateFailoverStrategy(new AuthenticateFailoverStrategy(AuthenticateAction.ALLOW));
- }
-
/**
* Sets the endpoint of the Castle API to its default value.
*
@@ -292,7 +260,7 @@ public CastleConfigurationBuilder apiSecret(String apiSecret) {
*
* @return a castleConfiguration with all fields set to some meaningful value
* @throws CastleSdkConfigurationException if at least one of castleAppId, apiSecret, allowListHeaders,
- * denyListHeaders, failoverStrategy, backendProvider is not provided
+ * denyListHeaders, backendProvider is not provided
* during the building stage of the
* CastleConfiguration instance.
*/
@@ -310,10 +278,6 @@ public CastleConfiguration build() throws CastleSdkConfigurationException {
builder.add("A denyList of headers must be provided. If not sure, then use the default values provided " +
"by method withDefaultDenyList. Read documentation for further details.");
}
- if (failoverStrategy == null) {
- builder.add("A failover strategy must be provided. If not sure, then use the default values provided " +
- "by method withDefaultAuthenticateFailoverStrategy. Read documentation for further details.");
- }
if (backendProvider == null) {
builder.add("A backend provider must be selected. If not sure, then use the default values provided " +
"by method withDefaultBackendProvider. Read documentation for further details.");
@@ -328,7 +292,6 @@ public CastleConfiguration build() throws CastleSdkConfigurationException {
HeaderNormalizer normalizer = new HeaderNormalizer();
return new CastleConfiguration(apiBaseUrl,
timeout,
- failoverStrategy,
normalizer.normalizeList(allowListHeaders),
normalizer.normalizeList(denyListHeaders),
apiSecret,
diff --git a/src/main/java/io/castle/client/internal/config/ConfigurationLoader.java b/src/main/java/io/castle/client/internal/config/ConfigurationLoader.java
index 30513ab0..e279c51a 100644
--- a/src/main/java/io/castle/client/internal/config/ConfigurationLoader.java
+++ b/src/main/java/io/castle/client/internal/config/ConfigurationLoader.java
@@ -3,8 +3,6 @@
import com.google.common.base.Splitter;
import io.castle.client.Castle;
import io.castle.client.internal.backend.CastleBackendProvider;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.CastleSdkConfigurationException;
import java.io.InputStream;
@@ -130,11 +128,6 @@ public CastleConfigurationBuilder loadConfigurationBuilder() {
"backend_provider",
"CASTLE_SDK_BACKEND_PROVIDER"
);
- String authenticateFailoverStrategyValue = loadConfigurationValue(
- castleConfigurationProperties,
- "failover_strategy",
- "CASTLE_SDK_AUTHENTICATE_FAILOVER_STRATEGY"
- );
String apiBaseUrl = loadConfigurationValue(
castleConfigurationProperties,
"base_url",
@@ -170,19 +163,6 @@ public CastleConfigurationBuilder loadConfigurationBuilder() {
int timeout = Integer.parseInt(timeoutValue);
builder.withTimeout(timeout);
}
- if (authenticateFailoverStrategyValue != null) {
- if (authenticateFailoverStrategyValue.compareTo("throw") == 0) {
- builder.withAuthenticateFailoverStrategy(new AuthenticateFailoverStrategy());
- } else {
- builder.withAuthenticateFailoverStrategy(
- new AuthenticateFailoverStrategy(
- AuthenticateAction.fromAction(authenticateFailoverStrategyValue)
- )
- );
- }
- } else {
- builder.withDefaultAuthenticateFailoverStrategy();
- }
if (backendProviderValue != null) {
builder.withBackendProvider(
CastleBackendProvider.valueOf(backendProviderValue)
diff --git a/src/main/java/io/castle/client/internal/json/AuthenticateActionDeserializer.java b/src/main/java/io/castle/client/internal/json/AuthenticateActionDeserializer.java
deleted file mode 100644
index 05837ac4..00000000
--- a/src/main/java/io/castle/client/internal/json/AuthenticateActionDeserializer.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.castle.client.internal.json;
-
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParseException;
-import io.castle.client.model.AuthenticateAction;
-
-import java.lang.reflect.Type;
-
-public class AuthenticateActionDeserializer implements JsonDeserializer {
- @Override
- public AuthenticateAction deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
- return AuthenticateAction.fromAction(json.getAsString());
- }
-}
diff --git a/src/main/java/io/castle/client/internal/json/CastleGsonModel.java b/src/main/java/io/castle/client/internal/json/CastleGsonModel.java
index ff0b65a0..b25a5967 100644
--- a/src/main/java/io/castle/client/internal/json/CastleGsonModel.java
+++ b/src/main/java/io/castle/client/internal/json/CastleGsonModel.java
@@ -4,10 +4,8 @@
import com.google.gson.internal.bind.util.ISO8601Utils;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
-import io.castle.client.model.AuthenticateAction;
import io.castle.client.model.RiskPolicyType;
import io.castle.client.model.CastleHeaders;
-import io.castle.client.model.CastleMessage;
import io.castle.client.model.generated.BaseChangesetEntry;
import okio.ByteString;
import org.threeten.bp.LocalDate;
@@ -27,9 +25,7 @@ public class CastleGsonModel {
public CastleGsonModel() {
GsonBuilder builder = createGsonBuilder();
builder.registerTypeAdapter(CastleHeaders.class, new CastleHeadersSerializer());
- builder.registerTypeAdapter(CastleMessage.class, new CastleMessageSerializer());
builder.registerTypeAdapter(CastleHeaders.class, new CastleHeadersDeserializer());
- builder.registerTypeAdapter(AuthenticateAction.class, new AuthenticateActionDeserializer());
builder.registerTypeAdapter(RiskPolicyType.class, new RiskPolicyTypeDeserializer());
builder.registerTypeAdapterFactory(ChangesetEntryTypeAdapter.FACTORY);
builder.registerTypeAdapter(BaseChangesetEntry.class, new BaseChangesetEntryDeserializer());
diff --git a/src/main/java/io/castle/client/internal/json/CastleMessageSerializer.java b/src/main/java/io/castle/client/internal/json/CastleMessageSerializer.java
deleted file mode 100644
index 51d819b3..00000000
--- a/src/main/java/io/castle/client/internal/json/CastleMessageSerializer.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package io.castle.client.internal.json;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import com.google.gson.Gson;
-
-import io.castle.client.internal.utils.ContextMerge;
-import io.castle.client.model.CastleMessage;
-
-import java.lang.reflect.Type;
-import java.util.HashMap;
-
-public class CastleMessageSerializer implements JsonSerializer {
-
- private final Gson gson = CastleGsonModel.createGsonBuilder().create();
-
- @Override
- public JsonElement serialize(CastleMessage message, Type typeOfSrc, JsonSerializationContext context) {
- JsonElement root = gson.toJsonTree(message);
- HashMap other = message.getOther();
- if (other == null) {
- return root;
- }
- JsonElement otherJson = context.serialize(message.getOther());
- ContextMerge merger = new ContextMerge();
- return merger.merge(root.getAsJsonObject(), otherJson.getAsJsonObject());
- }
-}
diff --git a/src/main/java/io/castle/client/internal/utils/VerdictBuilder.java b/src/main/java/io/castle/client/internal/utils/VerdictBuilder.java
deleted file mode 100644
index df775030..00000000
--- a/src/main/java/io/castle/client/internal/utils/VerdictBuilder.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package io.castle.client.internal.utils;
-
-import com.google.gson.JsonElement;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.RiskPolicyResult;
-import io.castle.client.model.Verdict;
-
-public class VerdictBuilder {
- private AuthenticateAction action;
- private RiskPolicyResult riskPolicy;
- private String userId;
- private boolean failover;
- private String failoverReason;
- private String deviceToken;
- private JsonElement internal;
- private float risk;
-
- private VerdictBuilder() {
- }
-
- public static VerdictBuilder success() {
- return new VerdictBuilder()
- .withFailover(false);
- }
-
- public static VerdictBuilder failover(String failoverReason) {
- return new VerdictBuilder()
- .withFailover(true)
- .withFailoverReason(failoverReason);
- }
-
- public VerdictBuilder withAction(AuthenticateAction action) {
- this.action = action;
- return this;
- }
-
- public VerdictBuilder withUserId(String userId) {
- this.userId = userId;
- return this;
- }
-
-
- public VerdictBuilder withRiskPolicy(RiskPolicyResult riskPolicy) {
- this.riskPolicy = riskPolicy;
- return this;
- }
-
- public VerdictBuilder withDeviceToken(final String deviceToken) {
- this.deviceToken = deviceToken;
- return this;
- }
-
- public VerdictBuilder withRisk(final float risk) {
- this.risk = risk;
- return this;
- }
-
- public Verdict build() {
- Verdict verdict = new Verdict();
- verdict.setAction(action);
- verdict.setUserId(userId);
- verdict.setFailover(failover);
- verdict.setFailoverReason(failoverReason);
- verdict.setDeviceToken(deviceToken);
- verdict.setRiskPolicy(riskPolicy);
- verdict.setInternal(internal);
- verdict.setRisk(risk);
- return verdict;
- }
-
- public VerdictBuilder withFailover(boolean failover) {
- this.failover = failover;
- return this;
- }
-
- public VerdictBuilder withFailoverReason(String failoverReason) {
- this.failoverReason = failoverReason;
- return this;
- }
-
- public VerdictBuilder withInternal(JsonElement internal) {
- this.internal = internal;
- return this;
- }
-
- public static Verdict fromTransport(VerdictTransportModel transport, JsonElement internal) {
- internal.getAsJsonObject().get("action").getAsString();
- return success()
- .withAction(transport.getAction())
- .withUserId(transport.getUserId())
- .withDeviceToken(transport.getDeviceToken())
- .withRiskPolicy(transport.getRiskPolicy())
- .withRisk(transport.getRisk())
- .withInternal(internal)
- .build();
- }
-}
diff --git a/src/main/java/io/castle/client/internal/utils/VerdictTransportModel.java b/src/main/java/io/castle/client/internal/utils/VerdictTransportModel.java
deleted file mode 100644
index 07dab519..00000000
--- a/src/main/java/io/castle/client/internal/utils/VerdictTransportModel.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package io.castle.client.internal.utils;
-
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.RiskPolicyResult;
-
-public class VerdictTransportModel {
-
- private AuthenticateAction action;
- private RiskPolicyResult riskPolicy;
- private String userId;
- private String deviceToken;
- private float risk;
-
- public AuthenticateAction getAction() {
- return action;
- }
-
- public void setAction(AuthenticateAction action) {
- this.action = action;
- }
-
- public RiskPolicyResult getRiskPolicy() {
- return riskPolicy;
- }
-
- public void setRiskPolicy(RiskPolicyResult riskPolicy) {
- this.riskPolicy = riskPolicy;
- }
-
- public String getUserId() {
- return userId;
- }
-
- public void setUserId(String userId) {
- this.userId = userId;
- }
-
- public String getDeviceToken() {
- return deviceToken;
- }
-
- public float getRisk() {
- return risk;
- }
-
- public void setRisk(float risk) {
- this.risk = risk;
- }
-
-}
diff --git a/src/main/java/io/castle/client/internal/utils/Webhook.java b/src/main/java/io/castle/client/internal/utils/Webhook.java
new file mode 100644
index 00000000..9c6ebf3c
--- /dev/null
+++ b/src/main/java/io/castle/client/internal/utils/Webhook.java
@@ -0,0 +1,56 @@
+package io.castle.client.internal.utils;
+
+import com.google.common.base.Charsets;
+import com.google.common.hash.Hashing;
+import com.google.common.io.BaseEncoding;
+
+import java.security.MessageDigest;
+
+/**
+ * Helper for verifying Castle webhook signatures.
+ *
+ * Castle signs every webhook with an HMAC-SHA256 of the raw request body using the
+ * account API secret. The signature is base64 encoded and delivered in the
+ * {@code X-Castle-Signature} header.
+ */
+public final class Webhook {
+
+ private Webhook() {
+ }
+
+ /**
+ * Computes the base64 encoded HMAC-SHA256 signature for the given body.
+ *
+ * @param secret the account API secret
+ * @param body the raw request body bytes
+ * @return the base64 encoded signature
+ */
+ public static String computeSignature(String secret, byte[] body) {
+ byte[] safeBody = body != null ? body : new byte[0];
+ byte[] hmac = Hashing.hmacSha256(secret.getBytes(Charsets.UTF_8))
+ .hashBytes(safeBody)
+ .asBytes();
+ return BaseEncoding.base64().encode(hmac);
+ }
+
+ /**
+ * Verifies that the supplied signature matches the computed signature for the body.
+ *
+ * The comparison is done in constant time to avoid timing attacks.
+ *
+ * @param secret the account API secret
+ * @param body the raw request body bytes
+ * @param signature the signature received in the {@code X-Castle-Signature} header
+ * @return {@code true} when the signature matches
+ */
+ public static boolean verifySignature(String secret, byte[] body, String signature) {
+ if (secret == null || signature == null) {
+ return false;
+ }
+ String expected = computeSignature(secret, body);
+ return MessageDigest.isEqual(
+ expected.getBytes(Charsets.UTF_8),
+ signature.getBytes(Charsets.UTF_8)
+ );
+ }
+}
diff --git a/src/main/java/io/castle/client/model/AsyncCallbackHandler.java b/src/main/java/io/castle/client/model/AsyncCallbackHandler.java
deleted file mode 100644
index 0286db15..00000000
--- a/src/main/java/io/castle/client/model/AsyncCallbackHandler.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package io.castle.client.model;
-
-/**
- * Callback interface used to handle async requests responses.
- *
- * An implementation of this interface allows the user to handle async request success and failure cases in a custom manner.
- *
- * @param The type of the internal response after execution.
- */
-public interface AsyncCallbackHandler {
- void onResponse(T response);
-
- void onException(Exception exception);
-}
diff --git a/src/main/java/io/castle/client/model/AuthenticateAction.java b/src/main/java/io/castle/client/model/AuthenticateAction.java
deleted file mode 100644
index 7839c701..00000000
--- a/src/main/java/io/castle/client/model/AuthenticateAction.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package io.castle.client.model;
-
-/**
- * Action that needs to be taken after a login attempt.
- *
- * See the documentation for the semantics of each case.
- * It can be null.
- *
- * @see Adaptive authentication
- */
-public enum AuthenticateAction {
- ALLOW, DENY, CHALLENGE;
-
- /**
- * Returns an AuthenticateAction from a string representing its name.
- *
- * @param action string representing the name of the AuthenticateAction, case-insensitive
- * @return the enum value matching the name, or null if it does not match any enum
- */
- public static AuthenticateAction fromAction(String action) {
- for (AuthenticateAction kind : AuthenticateAction.class.getEnumConstants()) {
- if (kind.name().equalsIgnoreCase(action)) {
- return kind;
- }
- }
- return null;
- }
-}
diff --git a/src/main/java/io/castle/client/model/AuthenticateFailoverStrategy.java b/src/main/java/io/castle/client/model/AuthenticateFailoverStrategy.java
deleted file mode 100644
index 294b4600..00000000
--- a/src/main/java/io/castle/client/model/AuthenticateFailoverStrategy.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package io.castle.client.model;
-
-import io.castle.client.api.CastleApi;
-
-/**
- * Stores settings for either using an AuthenticationAction or throwing a TimeoutException,
- * if a Castle API authenticate call fails.
- *
- * If a {@link CastleApi#authenticate} call fails during an authentication attempt, the failover strategy specifies
- * which {@link AuthenticateAction} should be used.
- * Alternatively, a TimeoutException instance could be configured.
- */
-public class AuthenticateFailoverStrategy {
-
- private final AuthenticateAction defaultAction;
- private final boolean throwTimeoutException;
-
- private AuthenticateFailoverStrategy(AuthenticateAction defaultAction, boolean throwTimeoutException) {
- this.defaultAction = defaultAction;
- this.throwTimeoutException = throwTimeoutException;
- }
-
- /**
- * Sets the default authenticationAction for failed requests.
- *
- * @param action the authenticateAction that will be used as a default for failed requests
- */
- public AuthenticateFailoverStrategy(AuthenticateAction action) {
- this(action, false);
- }
-
- /**
- * Creates an authenticationStrategy whose policy is to throw a timeoutException.
- */
- public AuthenticateFailoverStrategy() {
- this(null, true);
- }
-
-
- /**
- * Gets the authenticateAction that this strategy uses for failover.
- *
- * @return the authenticateAction configured as default; null if there is no default AuthenticateAction
- */
- public AuthenticateAction getDefaultAction() {
- return defaultAction;
- }
-
- /**
- * Checks whether the failover strategy is configured to throw a timeoutException.
- *
- * @return true if the failover strategy is set to throw a timeoutException, false otherwise
- */
- public boolean isThrowTimeoutException() {
- return throwTimeoutException;
- }
-}
diff --git a/src/main/java/io/castle/client/model/CastleMessage.java b/src/main/java/io/castle/client/model/CastleMessage.java
deleted file mode 100644
index ec7ba32d..00000000
--- a/src/main/java/io/castle/client/model/CastleMessage.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package io.castle.client.model;
-
-import java.util.HashMap;
-
-import javax.annotation.Nonnull;
-
-public class CastleMessage {
- private transient CastleContext context;
- private String createdAt;
- private String timestamp;
- private String deviceToken;
- @Nonnull private String event;
- /**
- * Collect other attributes that haven't not explicit setters to accommodate for
- * future parameters
- */
- private transient HashMap other;
- private Object properties;
- private String reviewId;
- private String userId;
- private Object userTraits;
-
- /**
- * Initialize a new request payload message
- * @param event Name of the event to send
- */
- public CastleMessage(String event) {
- setEvent(event);
- }
-
- public CastleContext getContext() {
- return context;
- }
-
- public void setContext(CastleContext context) {
- this.context = context;
- }
-
- /**
- * @deprecated use {@link #getTimestamp()} instead.
- */
- @Deprecated
- public String getCreatedAt() {
- return createdAt;
- }
-
- /**
- * @deprecated use {@link #setTimestamp(String)} instead.
- */
- @Deprecated
- public void setCreatedAt(String createdAt) {
- this.createdAt = createdAt;
- }
-
- public String getTimestamp() {
- return timestamp;
- }
-
- public void setTimestamp(String timestamp) {
- this.timestamp = timestamp;
- }
-
- public String getDeviceToken() {
- return deviceToken;
- }
-
- public void setDeviceToken(String deviceToken) {
- this.deviceToken = deviceToken;
- }
-
- @Nonnull
- public String getEvent() {
- return event;
- }
-
- public void setEvent(@Nonnull String event) {
- this.event = event;
- }
-
- public HashMap getOther() {
- if (other == null) {
- this.other = new HashMap();
- }
- return other;
- }
-
- public void setOther(HashMap other) {
- this.other = other;
- }
-
- public Object getProperties() {
- return properties;
- }
-
- public void setProperties(Object properties) {
- this.properties = properties;
- }
-
- public String getReviewId() {
- return reviewId;
- }
-
- public void setReviewId(String reviewId) {
- this.reviewId = reviewId;
- }
-
- public String getUserId() {
- return userId;
- }
-
- public void setUserId(String userId) {
- this.userId = userId;
- }
-
- public Object getUserTraits() {
- return userTraits;
- }
-
- public void setUserTraits(Object userTraits) {
- this.userTraits = userTraits;
- }
-
- public static Builder builder(String event) {
- return new Builder(new CastleMessage(event));
- }
-
- public static class Builder {
- private CastleMessage payload;
-
- public Builder(CastleMessage payload) {
- this.payload = payload;
- }
-
- public CastleMessage build() {
- return payload;
- }
-
- public Builder context(CastleContext context) {
- payload.setContext(context);
- return this;
- }
-
- /**
- * @deprecated use {@link #timestamp(String)} instead.
- */
- @Deprecated
- public Builder createdAt(String createdAt) {
- payload.setCreatedAt(createdAt);
- return this;
- }
-
- public Builder timestamp(String timestamp) {
- payload.setTimestamp(timestamp);
- return this;
- }
-
- public Builder deviceToken(String deviceToken) {
- payload.setDeviceToken(deviceToken);
- return this;
- }
-
- public Builder reviewId(String reviewId) {
- payload.setReviewId(reviewId);
- return this;
- }
-
- public Builder properties(Object properties) {
- if (properties == null) {
- throw new NullPointerException("Null properties");
- }
- payload.setProperties(properties);
- return this;
- }
-
- public Builder other(HashMap other) {
- payload.setOther(other);
- return this;
- }
-
- public Builder put(String key, Object value) {
- payload.getOther().put(key, value);
- return this;
- }
-
- public Builder userId(String userId) {
- payload.setUserId(userId);
- return this;
- }
-
- public Builder userTraits(Object userTraits) {
- if (userTraits == null) {
- throw new NullPointerException("Null userTraits");
- }
- payload.setUserTraits(userTraits);
- return this;
- }
- }
-}
diff --git a/src/main/java/io/castle/client/model/CastleSuccess.java b/src/main/java/io/castle/client/model/CastleSuccess.java
deleted file mode 100644
index 060999d0..00000000
--- a/src/main/java/io/castle/client/model/CastleSuccess.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.castle.client.model;
-
-public class CastleSuccess {
- boolean success;
-
- public boolean isSuccess() {
- return success;
- }
-
- public void setSuccess(boolean success) {
- this.success = success;
- }
-}
diff --git a/src/main/java/io/castle/client/model/CastleUserDevice.java b/src/main/java/io/castle/client/model/CastleUserDevice.java
deleted file mode 100644
index 6e751272..00000000
--- a/src/main/java/io/castle/client/model/CastleUserDevice.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package io.castle.client.model;
-
-/**
- * Model of the device object returned in the body of the response of a device call to the Castle Api.
- */
-public class CastleUserDevice {
- private String token;
- private double risk;
- private String createdAt;
- private String lastSeenAt;
- private String approvedAt;
- private String escalatedAt;
- private String mitigatedAt;
- private CastleUserDeviceContext context;
-
- boolean isCurrentDevice;
-
- public String getToken() {
- return token;
- }
-
- public void setToken(String token) {
- this.token = token;
- }
-
- public double getRisk() {
- return risk;
- }
-
- public void setRisk(double risk) {
- this.risk = risk;
- }
-
- public String getCreatedAt() {
- return createdAt;
- }
-
- public void setCreatedAt(String createdAt) {
- this.createdAt = createdAt;
- }
-
- public String getLastSeenAt() {
- return lastSeenAt;
- }
-
- public void setLastSeenAt(String lastSeenAt) {
- this.lastSeenAt = lastSeenAt;
- }
-
- public String getApprovedAt() {
- return approvedAt;
- }
-
- public void setApprovedAt(String approvedAt) {
- this.approvedAt = approvedAt;
- }
-
- public String getEscalatedAt() {
- return escalatedAt;
- }
-
- public void setEscalatedAt(String escalatedAt) {
- this.escalatedAt = escalatedAt;
- }
-
- public String getMitigatedAt() {
- return mitigatedAt;
- }
-
- public void setMitigatedAt(String mitigatedAt) {
- this.mitigatedAt = mitigatedAt;
- }
-
- public CastleUserDeviceContext getContext() {
- return context;
- }
-
- public void setContext(CastleUserDeviceContext context) {
- this.context = context;
- }
-
- public boolean isCurrentDevice() {
- return isCurrentDevice;
- }
-
- public void setCurrentDevice(boolean currentDevice) {
- isCurrentDevice = currentDevice;
- }
-}
diff --git a/src/main/java/io/castle/client/model/CastleUserDevices.java b/src/main/java/io/castle/client/model/CastleUserDevices.java
deleted file mode 100644
index fbc9399d..00000000
--- a/src/main/java/io/castle/client/model/CastleUserDevices.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package io.castle.client.model;
-
-import com.google.gson.annotations.SerializedName;
-
-import java.util.List;
-
-public class CastleUserDevices {
- private int totalCount;
- @SerializedName("data")
- private List devices;
-
- public int getTotalCount() {
- return totalCount;
- }
-
- public List getDevices() {
- return devices;
- }
-
- public void setDevices(List devices) {
- this.devices = devices;
- this.totalCount = devices != null ? devices.size() : 0;
- }
-}
diff --git a/src/main/java/io/castle/client/model/ImpersonatePayload.java b/src/main/java/io/castle/client/model/ImpersonatePayload.java
deleted file mode 100644
index 161fe525..00000000
--- a/src/main/java/io/castle/client/model/ImpersonatePayload.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package io.castle.client.model;
-
-import com.google.gson.JsonObject;
-
-public class ImpersonatePayload {
- private final String userId;
- private final JsonObject context;
- private final JsonObject properties;
-
- public ImpersonatePayload(String userId, String impersonator, JsonObject contextJson) {
- this.userId = userId;
- this.properties = new JsonObject();
- this.properties.addProperty("impersonator", impersonator);
- this.context = contextJson;
- }
-
- public ImpersonatePayload(String userId, JsonObject contextJson) {
- this.userId = userId;
- this.properties = new JsonObject();
- this.context = contextJson;
- }
-}
diff --git a/src/main/java/io/castle/client/model/Verdict.java b/src/main/java/io/castle/client/model/Verdict.java
deleted file mode 100644
index 8e29681e..00000000
--- a/src/main/java/io/castle/client/model/Verdict.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package io.castle.client.model;
-
-import com.google.gson.JsonElement;
-
-/**
- * Model of the outcome of an authenticate call to the Castle API.
- */
-public class Verdict {
-
- /**
- * AuthenticateAction returned by a call to the CastleAPI, or configured by a failover strategy.
- */
- private AuthenticateAction action;
-
- /**
- * String representing a user ID associated with an authenticate call.
- */
- private String userId;
-
- /**
- * True if the SDK resorted the {@code AuthenticateFailoverStrategy} configured.
- */
- private boolean failover;
-
- /**
- * Explains the reason why the {@code AuthenticateFailoverStrategy} was used.
- */
- private String failoverReason;
-
- /**
- * String representing a device ID associated with an authenticate call.
- */
- private String deviceToken;
-
- /**
- * Float representing risk value associated with an authenticate call.
- */
- private float risk;
-
- /**
- * RiskPolicyResult representing risk policy used for generating this verdict.
- */
- private RiskPolicyResult riskPolicy;
-
- /**
- * JsonElement representing the full response of the server request
- */
- private JsonElement internal;
-
- public AuthenticateAction getAction() {
- return action;
- }
-
- public void setAction(AuthenticateAction action) {
- this.action = action;
- }
-
- public String getUserId() {
- return userId;
- }
-
- public void setUserId(String userId) {
- this.userId = userId;
- }
-
- public boolean isFailover() {
- return failover;
- }
-
- public void setFailover(boolean failover) {
- this.failover = failover;
- }
-
- public String getFailoverReason() {
- return failoverReason;
- }
-
- public void setFailoverReason(String failoverReason) {
- this.failoverReason = failoverReason;
- }
-
- public String getDeviceToken() {
- return deviceToken;
- }
-
- public void setRisk(float risk) {
- this.risk = risk;
- }
-
- public float getRisk() {
- return risk;
- }
-
- public void setDeviceToken(String deviceToken) {
- this.deviceToken = deviceToken;
- }
-
- public void setInternal(JsonElement internal) {
- this.internal = internal;
- }
-
- public RiskPolicyResult getRiskPolicy() {
- return riskPolicy;
- }
-
- public void setRiskPolicy(RiskPolicyResult riskPolicy) {
- this.riskPolicy = riskPolicy;
- }
-
- public JsonElement getInternal() {
- return internal;
- }
-}
diff --git a/src/test/java/io/castle/client/AbstractCastleHttpLayerTest.java b/src/test/java/io/castle/client/AbstractCastleHttpLayerTest.java
index 23303633..338e5094 100644
--- a/src/test/java/io/castle/client/AbstractCastleHttpLayerTest.java
+++ b/src/test/java/io/castle/client/AbstractCastleHttpLayerTest.java
@@ -4,7 +4,6 @@
import io.castle.client.internal.config.CastleConfiguration;
import io.castle.client.internal.config.CastleConfigurationBuilder;
import io.castle.client.internal.config.CastleSdkInternalConfiguration;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.CastleSdkConfigurationException;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockWebServer;
@@ -18,16 +17,10 @@
public abstract class AbstractCastleHttpLayerTest {
- private final AuthenticateFailoverStrategy testAuthenticateFailoverStrategy;
-
Castle sdk;
MockWebServer server;
HttpUrl testServerBaseUrl;
- protected AbstractCastleHttpLayerTest(AuthenticateFailoverStrategy testAuthenticateFailoverStrategy) {
- this.testAuthenticateFailoverStrategy = testAuthenticateFailoverStrategy;
- }
-
@Before
public void prepare() throws NoSuchFieldException, IllegalAccessException, CastleSdkConfigurationException, IOException {
//Given a mocked API server
@@ -45,7 +38,6 @@ public void prepare() throws NoSuchFieldException, IllegalAccessException, Castl
.withAllowListHeaders(configuration.getAllowListHeaders())
.withCastleAppId(configuration.getCastleAppId())
.withBackendProvider(configuration.getBackendProvider())
- .withAuthenticateFailoverStrategy(testAuthenticateFailoverStrategy)
.withTimeout(configuration.getTimeout())
.build();
diff --git a/src/test/java/io/castle/client/CastleAuthenticateHttpTest.java b/src/test/java/io/castle/client/CastleAuthenticateHttpTest.java
deleted file mode 100644
index 4e57ce44..00000000
--- a/src/test/java/io/castle/client/CastleAuthenticateHttpTest.java
+++ /dev/null
@@ -1,541 +0,0 @@
-package io.castle.client;
-
-import com.google.gson.JsonParser;
-import io.castle.client.internal.utils.VerdictBuilder;
-import io.castle.client.model.*;
-import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.utils.SDKVersion;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.Test;
-import org.skyscreamer.jsonassert.JSONAssert;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import com.google.common.collect.ImmutableMap;
-
-import jakarta.servlet.http.HttpServletRequest;
-import java.util.concurrent.atomic.AtomicReference;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleAuthenticateHttpTest extends AbstractCastleHttpLayerTest {
-
- private static final String DENY_RESPONSE = "{\n" +
- " \"action\": \"deny\",\n" +
- " \"user_id\": \"12345\",\n" +
- " \"device_token\": \"abcdefg1234\",\n" +
- " \"risk_policy\": {\n" +
- " \"id\": \"q-rbeMzBTdW2Fd09sbz55A\",\n" +
- " \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\n" +
- " \"name\": \"Block Users from X\",\n" +
- " \"type\": \"bot\"\n" +
- " }\n" +
- "}";
-
- private static final String DENY_RESPONSE_NO_POLICY = "{\n" +
- " \"action\": \"deny\",\n" +
- " \"user_id\": \"12345\",\n" +
- " \"device_token\": \"abcdefg1234\"\n" +
- "}";
-
- public CastleAuthenticateHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test
- public void authenticateAsyncEndpointWithNullUserIdPayload() throws InterruptedException, JSONException {
- // Given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE));
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
- // and an authenticate request is made
- sdk.onRequest(request).authenticateAsync(
- CastleMessage.builder("$login.succeeded").build(),
- handler
- );
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- public void authenticateAsyncEndpontWithPayload() throws InterruptedException, JSONException {
- // Given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE));
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
- // and an authenticate request is made
- sdk.onRequest(request).authenticateAsync(
- CastleMessage.builder("$login.succeeded").userId("12345").build(),
- handler
- );
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void authenticationAsyncEndpointTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE));
- String id = "12345";
- String event = "$login.succeeded";
- String deviceToken = "abcdefg1234";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
- // and an authenticate request is made
- sdk.onRequest(request).authenticateAsync(event, id, handler);
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- String json = "{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}";
-
- JSONAssert.assertEquals(json, body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
-
- RiskPolicyResult riskPolicyResult = new CastleGsonModel().getGson().fromJson("{\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}", RiskPolicyResult.class);
-
- // and
- Verdict expected = VerdictBuilder.success()
- .withAction(AuthenticateAction.DENY)
- .withUserId("12345")
- .withDeviceToken(deviceToken)
- .withRiskPolicy(riskPolicyResult)
- .withInternal(JsonParser.parseString("{\"action\":\"deny\",\"user_id\":\"12345\",\"device_token\":\"abcdefg1234\", \"risk_policy\": {\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}}"))
- .build();
- waitForValueAndVerify(result, expected);
- }
-
- @Test
- public void authenticationAsyncEndpointNoRiskPolicyTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE_NO_POLICY));
- String id = "12345";
- String event = "$login.succeeded";
- String deviceToken = "abcdefg1234";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
- // and an authenticate request is made
- sdk.onRequest(request).authenticateAsync(event, id, handler);
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- String json = "{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}";
-
- JSONAssert.assertEquals(json, body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
-
- // and
- Verdict expected = VerdictBuilder.success()
- .withAction(AuthenticateAction.DENY)
- .withUserId("12345")
- .withDeviceToken(deviceToken)
- .withInternal(JsonParser.parseString("{\"action\":\"deny\",\"user_id\":\"12345\",\"device_token\":\"abcdefg1234\"}"))
- .build();
- waitForValueAndVerify(result, expected);
- }
-
- @Test
- public void authenticationAsyncEndpointWithPropertiesAndTraitsTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE));
- String id = "12345";
- String event = "$login.succeeded";
- String deviceToken = "abcdefg1234";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
- // and an authenticate request is made
- sdk.onRequest(request).authenticateAsync(event, id, ImmutableMap.builder()
- .put("b",0)
- .build(), ImmutableMap.builder()
- .put("y",0)
- .build(), handler);
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"properties\":{\"b\":0},\"user_id\":\"12345\",\"user_traits\":{\"y\":0},\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
-
- RiskPolicyResult riskPolicyResult = new CastleGsonModel().getGson().fromJson("{\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}", RiskPolicyResult.class);
-
- // and
- Verdict expected = VerdictBuilder.success()
- .withAction(AuthenticateAction.DENY)
- .withUserId("12345")
- .withDeviceToken(deviceToken)
- .withRiskPolicy(riskPolicyResult)
- .withInternal(JsonParser.parseString("{\"action\":\"deny\",\"user_id\":\"12345\",\"device_token\":\"abcdefg1234\", \"risk_policy\": {\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}}"))
- .build();
- waitForValueAndVerify(result, expected);
- }
-
-
- @Test
- public void authenticationAsyncEndpointProvideDefaultValueOnTimeoutErrorTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- String id = "12345";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
- // and an authenticate request is made
- sdk.onRequest(request).authenticateAsync(event, id, handler);
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
-
- // and
- Verdict expected = VerdictBuilder.failover("timeout")
- .withAction(AuthenticateAction.CHALLENGE)
- .withUserId(id)
- .build();
-
- verifyFailoverResponse(result, expected, false);
- }
-
-
- @Test
- public void authenticationEndpointDefaultValueOnTimeoutErrorTest() throws InterruptedException, JSONException {
- //given the backed will timeout
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- String id = "12345";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an authenticate request is made
- Verdict verdict = sdk.onRequest(request).authenticate(event, id);
-
- // then
- Verdict expected = VerdictBuilder.failover("timeout")
- .withAction(AuthenticateAction.CHALLENGE)
- .withUserId(id)
- .build();
- verifyFailoverResponse(verdict, expected, false);
-
- // and
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void authenticationEndpointWithPayload() throws InterruptedException, JSONException {
- // Given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE));
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an authenticate request is made
- Verdict verdict = sdk.onRequest(request).authenticate(
- CastleMessage.builder("$login.succeeded").userId("12345").build()
- );
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void authenticationEndpointTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE));
- String id = "12345";
- String event = "$login.succeeded";
- String deviceToken = "abcdefg1234";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an authenticate request is made
- Verdict verdict = sdk.onRequest(request).authenticate(event, id);
-
- RiskPolicyResult riskPolicyResult = new CastleGsonModel().getGson().fromJson("{\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}", RiskPolicyResult.class);
-
- // then
- Verdict expected = VerdictBuilder.success()
- .withAction(AuthenticateAction.DENY)
- .withUserId(id)
- .withDeviceToken(deviceToken)
- .withRiskPolicy(riskPolicyResult)
- .withInternal(JsonParser.parseString("{\"action\":\"deny\",\"user_id\":\"12345\",\"device_token\":\"abcdefg1234\", \"risk_policy\": {\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}}"))
- .build();
- Assertions.assertThat(verdict).usingRecursiveComparison().isEqualTo(expected);
-
- // and
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void authenticationEndpointWithPropertiesAndTraitsTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse().setBody(DENY_RESPONSE));
- String id = "12345";
- String event = "$login.succeeded";
- String deviceToken = "abcdefg1234";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an authenticate request is made
- Verdict verdict = sdk.onRequest(request).authenticate(event, id, ImmutableMap.builder()
- .put("a","valueA")
- .put("b",123456)
- .build(), ImmutableMap.builder()
- .put("x","valueX")
- .put("y",654321)
- .build());
-
- RiskPolicyResult riskPolicyResult = new CastleGsonModel().getGson().fromJson("{\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}", RiskPolicyResult.class);
-
- // then
- Verdict expected = VerdictBuilder.success()
- .withAction(AuthenticateAction.DENY)
- .withUserId(id)
- .withDeviceToken(deviceToken)
- .withRiskPolicy(riskPolicyResult)
- .withInternal(JsonParser.parseString("{\"action\":\"deny\",\"user_id\":\"12345\",\"device_token\":\"abcdefg1234\", \"risk_policy\": {\"id\": \"q-rbeMzBTdW2Fd09sbz55A\", \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\"name\": \"Block Users from X\",\"type\": \"bot\"}}"))
- .build();
- Assertions.assertThat(verdict).usingRecursiveComparison().isEqualTo(expected);
-
- // and
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"properties\":{\"a\":\"valueA\",\"b\":123456},\"user_id\":\"12345\",\"user_traits\":{\"x\":\"valueX\",\"y\":654321},\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test(expected = CastleRuntimeException.class)
- public void authenticationThrowExceptionWhenBackendReturnErrors() throws InterruptedException {
- //given a 403 response from backend
- server.enqueue(new MockResponse().setResponseCode(403));
- String id = "12345";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an authenticate request is made
- Verdict verdict = sdk.onRequest(request).authenticate(event, id, ImmutableMap.builder()
- .put("a","valueA")
- .put("b",123456)
- .build(), null);
-
- // then a exception is send to the client code because of bad response from the castle backend
- }
-
- @Test
- public void authenticationUseDefaultOnBackendErrorTest() throws InterruptedException, JSONException {
- //given a 403 response from backend
- server.enqueue(new MockResponse().setResponseCode(500));
- String id = "12345";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an authenticate request is made
- Verdict verdict = sdk.onRequest(request).authenticate(event, id, ImmutableMap.builder()
- .put("a","valueA")
- .put("b",123456)
- .build(), null);
-
- // then
- Verdict expected = VerdictBuilder.failover("Client Error")
- .withAction(AuthenticateAction.CHALLENGE)
- .withUserId(id)
- .build();
- verifyFailoverResponse(verdict, expected, false);
-
- // and
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"properties\":{\"a\":\"valueA\",\"b\":123456},\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test(expected = CastleRuntimeException.class)
- public void authenticationUseDefaultOnBadResponseFormatTestEmptyCase() throws InterruptedException {
- //given a response do not match the transport contract
- testIlegalJsonForAuthenticate("{}");
-
- }
- @Test(expected = CastleRuntimeException.class)
- public void authenticationUseDefaultOnBadResponseFormatTestInvalidActionUseCase() throws InterruptedException {
- //given a response do not match the transport contract
- testIlegalJsonForAuthenticate("{\"action\":\"action\"}");
-
- }
-
- private void testIlegalJsonForAuthenticate(String illegalJsonBody) {
- server.enqueue(new MockResponse().setBody(illegalJsonBody));
- String id = "12345";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an authenticate request is made
- Verdict verdict = sdk.onRequest(request).authenticate(event, id, ImmutableMap.builder()
- .put("a","valueA")
- .put("b",123456)
- .build(), null);
-
- // then a illegal json failover is provided
- Verdict expected = VerdictBuilder.failover("Illegal json format")
- .withAction(AuthenticateAction.CHALLENGE)
- .withUserId(id)
- .build();
- verifyFailoverResponse(verdict, expected, true);
- }
-
- /**
- * Verify that the async Verdict value match the expected values.
- * The Failover reason depend from the JVM implementation, so we only check that is not null.
- *
- * @param result
- * @param expected
- */
- private void verifyFailoverResponse(AtomicReference result, Verdict expected, boolean expectedExactReasonMatch) {
- Verdict extractedVerdict = waitForValue(result);
- verifyFailoverResponse(extractedVerdict, expected, expectedExactReasonMatch);
- }
-
- /**
- * Sync version of the verification for Verdict
- *
- * @param extractedVerdict
- * @param expected
- */
- private void verifyFailoverResponse(Verdict extractedVerdict, Verdict expected, boolean expectedExactReasonMatch) {
- Assertions.assertThat(extractedVerdict.getAction()).isEqualTo(expected.getAction());
- Assertions.assertThat(extractedVerdict.getUserId()).isEqualTo(expected.getUserId());
- Assertions.assertThat(extractedVerdict.isFailover()).isTrue();
- if (expectedExactReasonMatch) {
- Assertions.assertThat(extractedVerdict.getFailoverReason()).isEqualTo(expected.getFailoverReason());
- } else {
- Assertions.assertThat(extractedVerdict.getFailoverReason()).isNotEmpty();
- }
- }
-}
diff --git a/src/test/java/io/castle/client/CastleDeviceApproveHttpTest.java b/src/test/java/io/castle/client/CastleDeviceApproveHttpTest.java
deleted file mode 100644
index 6809d281..00000000
--- a/src/test/java/io/castle/client/CastleDeviceApproveHttpTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleDeviceApproveHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleDeviceApproveHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void approveDevice() throws InterruptedException {
- MockResponse mockResponse = new MockResponse();
- mockResponse.setBody(DeviceUtils.getDefaultDeviceJSON());
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an report device request is made
- CastleUserDevice device = sdk.onRequest(request).approve("deviceToken");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/devices/deviceToken/approve"), recordedRequest.getRequestUrl());
- Assert.assertEquals("PUT", recordedRequest.getMethod());
-
- // and the correct CastleUserDevice model object is extracted
- CastleUserDevice expected = DeviceUtils.createExpectedDevice();
-
- Assertions.assertThat(device).usingRecursiveComparison().isEqualTo(expected);
- }
-
- @Test(expected = CastleApiTimeoutException.class)
- public void approveDeviceTimeoutTest() {
-
- // given backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- HttpServletRequest request = new MockHttpServletRequest();
- String deviceToken = "deviceToken";
-
- //when a v1/devices/:device_token/approve request is made
- sdk.onRequest(request).approve(deviceToken);
- }
-
- @Test(expected = CastleRuntimeException.class)
- public void testExceptionWithServerError () {
-
- // given a server failure
- server.enqueue(new MockResponse().setResponseCode(500));
- // And a request
- HttpServletRequest request = new MockHttpServletRequest();
- String deviceToken = "deviceToken";
-
- //when a v1/devices/:device_token/approve request is made
- sdk.onRequest(request).approve(deviceToken);
-
- }
-}
diff --git a/src/test/java/io/castle/client/CastleDeviceHttpTest.java b/src/test/java/io/castle/client/CastleDeviceHttpTest.java
deleted file mode 100644
index 8ac91f25..00000000
--- a/src/test/java/io/castle/client/CastleDeviceHttpTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleDeviceHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleDeviceHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void getDevice() throws Exception {
- MockResponse mockResponse = new MockResponse();
- mockResponse.setBody(DeviceUtils.getDefaultDeviceJSON());
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an devices request is made
- CastleUserDevice device = sdk.onRequest(request).device("deviceToken");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/devices/deviceToken"), recordedRequest.getRequestUrl());
-
- // and the correct CastleUserDevice model object is extracted
- CastleUserDevice expected = DeviceUtils.createExpectedDevice();
-
- Assertions.assertThat(device).usingRecursiveComparison().isEqualTo(expected);
- }
-
- @Test(expected = CastleApiTimeoutException.class)
- public void getDeviceTimeoutTest() {
-
- // given backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- HttpServletRequest request = new MockHttpServletRequest();
- String deviceToken = "deviceToken";
-
- //when a v1/devices/:device_token request is made
- sdk.onRequest(request).device(deviceToken);
- }
-
- @Test(expected = CastleRuntimeException.class)
- public void testExceptionWithServerError () {
-
- // given a server failure
- server.enqueue(new MockResponse().setResponseCode(500));
- // And a request
- HttpServletRequest request = new MockHttpServletRequest();
- String deviceToken = "deviceToken";
-
- //when a v1/devices/:device_token request is made
- sdk.onRequest(request).device(deviceToken);
-
- }
-
- @Test
- public void getDeviceNotFoundTest () {
-
- // given a server failure
- server.enqueue(new MockResponse().setResponseCode(404));
- // And a request
- HttpServletRequest request = new MockHttpServletRequest();
- String deviceToken = "deviceToken";
-
- //when a v1/devices/:device_token request is made
- CastleUserDevice userDevice = sdk.onRequest(request).device(deviceToken);
-
- Assert.assertNull(userDevice);
- }
-}
diff --git a/src/test/java/io/castle/client/CastleDeviceReportHttpTest.java b/src/test/java/io/castle/client/CastleDeviceReportHttpTest.java
deleted file mode 100644
index d927a4cb..00000000
--- a/src/test/java/io/castle/client/CastleDeviceReportHttpTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleDeviceReportHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleDeviceReportHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void reportDevice() throws InterruptedException {
- MockResponse mockResponse = new MockResponse();
- mockResponse.setBody(DeviceUtils.getDefaultDeviceJSON());
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an report device request is made
- CastleUserDevice device = sdk.onRequest(request).report("deviceToken");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/devices/deviceToken/report"), recordedRequest.getRequestUrl());
- Assert.assertEquals("PUT", recordedRequest.getMethod());
-
- // and the correct CastleUserDevice model object is extracted
- CastleUserDevice expected = DeviceUtils.createExpectedDevice();
-
- Assertions.assertThat(device).usingRecursiveComparison().isEqualTo(expected);
- }
-
- @Test(expected = CastleApiTimeoutException.class)
- public void reportDeviceTimeoutTest() {
-
- // given backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- HttpServletRequest request = new MockHttpServletRequest();
- String deviceToken = "deviceToken";
-
- //when a v1/devices/:device_token/report request is made
- sdk.onRequest(request).report(deviceToken);
- }
-
- @Test(expected = CastleRuntimeException.class)
- public void testExceptionWithServerError () {
-
- // given a server failure
- server.enqueue(new MockResponse().setResponseCode(500));
- // And a request
- HttpServletRequest request = new MockHttpServletRequest();
- String deviceToken = "deviceToken";
-
- //when a v1/devices/:device_token/report request is made
- sdk.onRequest(request).report(deviceToken);
-
- }
-}
diff --git a/src/test/java/io/castle/client/CastleDevicesHttpTest.java b/src/test/java/io/castle/client/CastleDevicesHttpTest.java
deleted file mode 100644
index 68be962d..00000000
--- a/src/test/java/io/castle/client/CastleDevicesHttpTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleDevicesHttpTest extends AbstractCastleHttpLayerTest {
-
- private CastleGsonModel model = new CastleGsonModel();
-
- public CastleDevicesHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void getDevices() throws Exception {
- MockResponse mockResponse = new MockResponse();
- mockResponse.setBody("{\"total_count\":1,\"data\":[" + DeviceUtils.getDefaultDeviceJSON() + "]}");
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an devices request is made
- CastleUserDevices devices = sdk.onRequest(request).userDevices("userId");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/users/userId/devices"), recordedRequest.getRequestUrl());
-
- // and the correct CastleUserDevice model object is extracted
- CastleUserDevices expected = DeviceUtils.createExpectedDevices();
-
- Assertions.assertThat(devices).usingRecursiveComparison().isEqualTo(expected);
- }
-
- @Test(expected = CastleApiTimeoutException.class)
- public void getDevicesTimeoutTest() {
-
- // given backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- HttpServletRequest request = new MockHttpServletRequest();
- String userId = "userId";
-
- //when a v1/users/:user_id/devices request is made
- sdk.onRequest(request).userDevices(userId);
- }
-
- @Test(expected = CastleRuntimeException.class)
- public void testExceptionWithServerError () {
-
- // given a server failure
- server.enqueue(new MockResponse().setResponseCode(500));
- // And a request
- HttpServletRequest request = new MockHttpServletRequest();
- String userId = "userId";
-
- //when a v1/users/:user_id/devices request is made
- sdk.onRequest(request).userDevices(userId);
-
- }
-
- @Test
- public void getDevicesNotFoundTest () {
-
- // given a server failure
- server.enqueue(new MockResponse().setResponseCode(404));
- // And a request
- HttpServletRequest request = new MockHttpServletRequest();
- String userId = "userId";
-
- //when a v1/users/:user_id/devices request is made
- CastleUserDevices userDevices = sdk.onRequest(request).userDevices(userId);
-
- Assert.assertNull(userDevices);
- }
-}
diff --git a/src/test/java/io/castle/client/CastleEventsHttpTest.java b/src/test/java/io/castle/client/CastleEventsHttpTest.java
new file mode 100644
index 00000000..5c3894e0
--- /dev/null
+++ b/src/test/java/io/castle/client/CastleEventsHttpTest.java
@@ -0,0 +1,70 @@
+package io.castle.client;
+
+import com.google.common.collect.ImmutableMap;
+import io.castle.client.model.CastleResponse;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.assertj.core.api.Assertions;
+import org.json.JSONException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+public class CastleEventsHttpTest extends AbstractCastleHttpLayerTest {
+
+ @Test
+ public void eventsSchema() throws InterruptedException {
+ server.enqueue(new MockResponse().setBody("{}"));
+ HttpServletRequest request = new MockHttpServletRequest();
+
+ CastleResponse response = sdk.onRequest(request).eventsSchema();
+ if (response == null) {
+ Assertions.fail("error on request");
+ }
+
+ RecordedRequest recordedRequest = server.takeRequest();
+ Assert.assertEquals(testServerBaseUrl.resolve("v1/events/schema"), recordedRequest.getRequestUrl());
+ Assert.assertEquals("GET", recordedRequest.getMethod());
+ }
+
+ @Test
+ public void queryEvents() throws InterruptedException, JSONException {
+ server.enqueue(new MockResponse().setBody("{}"));
+ HttpServletRequest request = new MockHttpServletRequest();
+
+ CastleResponse response = sdk.onRequest(request).queryEvents(ImmutableMap.builder()
+ .put("type", "$login")
+ .build());
+ if (response == null) {
+ Assertions.fail("error on request");
+ }
+
+ RecordedRequest recordedRequest = server.takeRequest();
+ String body = recordedRequest.getBody().readUtf8();
+ Assert.assertEquals(testServerBaseUrl.resolve("v1/events/query"), recordedRequest.getRequestUrl());
+ Assert.assertEquals("POST", recordedRequest.getMethod());
+ JSONAssert.assertEquals("{\"type\":\"$login\"}", body, false);
+ }
+
+ @Test
+ public void groupEvents() throws InterruptedException, JSONException {
+ server.enqueue(new MockResponse().setBody("{}"));
+ HttpServletRequest request = new MockHttpServletRequest();
+
+ CastleResponse response = sdk.onRequest(request).groupEvents(ImmutableMap.builder()
+ .put("field", "name")
+ .build());
+ if (response == null) {
+ Assertions.fail("error on request");
+ }
+
+ RecordedRequest recordedRequest = server.takeRequest();
+ String body = recordedRequest.getBody().readUtf8();
+ Assert.assertEquals(testServerBaseUrl.resolve("v1/events/group"), recordedRequest.getRequestUrl());
+ Assert.assertEquals("POST", recordedRequest.getMethod());
+ JSONAssert.assertEquals("{\"field\":\"name\"}", body, false);
+ }
+}
diff --git a/src/test/java/io/castle/client/CastleFilterHttpTest.java b/src/test/java/io/castle/client/CastleFilterHttpTest.java
index 8c2fd85e..04f23a2e 100644
--- a/src/test/java/io/castle/client/CastleFilterHttpTest.java
+++ b/src/test/java/io/castle/client/CastleFilterHttpTest.java
@@ -2,8 +2,6 @@
import com.google.gson.JsonParser;
import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.generated.*;
import jakarta.servlet.http.HttpServletRequest;
import okhttp3.mockwebserver.MockResponse;
@@ -18,10 +16,6 @@
public class CastleFilterHttpTest extends AbstractCastleHttpLayerTest {
- public CastleFilterHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
@Test public void filter() throws InterruptedException {
MockResponse mockResponse = new MockResponse();
mockResponse.setBody("{\n" +
diff --git a/src/test/java/io/castle/client/CastleGenericAPIHttpTest.java b/src/test/java/io/castle/client/CastleGenericAPIHttpTest.java
index a510c887..47f15042 100644
--- a/src/test/java/io/castle/client/CastleGenericAPIHttpTest.java
+++ b/src/test/java/io/castle/client/CastleGenericAPIHttpTest.java
@@ -6,9 +6,7 @@
import io.castle.client.internal.json.CastleGsonModel;
import io.castle.client.internal.utils.CastleContextBuilder;
import io.castle.client.internal.utils.Timestamp;
-import io.castle.client.internal.utils.VerdictBuilder;
import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
import io.castle.client.utils.SDKVersion;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.RecordedRequest;
@@ -39,10 +37,6 @@ public class CastleGenericAPIHttpTest extends AbstractCastleHttpLayerTest {
" }\n" +
"}";
- public CastleGenericAPIHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
@Test
public void postRequest() throws InterruptedException, JSONException {
// Given
diff --git a/src/test/java/io/castle/client/CastleImpersonateEndHttpTest.java b/src/test/java/io/castle/client/CastleImpersonateEndHttpTest.java
deleted file mode 100644
index 8474d69d..00000000
--- a/src/test/java/io/castle/client/CastleImpersonateEndHttpTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleImpersonateEndHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleImpersonateEndHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void impersonateEnd() throws Exception {
- MockResponse mockResponse = new MockResponse();
- mockResponse.setBody("{\"success\":true}");
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an devices request is made
- CastleSuccess result = sdk.onRequest(request).impersonateEnd("userId");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/impersonate"), recordedRequest.getRequestUrl());
- Assert.assertEquals("DELETE", recordedRequest.getMethod());
-
- // and the correct Success model object is extracted
- CastleSuccess expected = new CastleSuccess();
- expected.setSuccess(true);
-
- Assertions.assertThat(result).usingRecursiveComparison().isEqualTo(expected);
- }
-
- @Test(expected = CastleApiTimeoutException.class)
- public void impersonateEndTimeoutTest() {
-
- // given backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- HttpServletRequest request = new MockHttpServletRequest();
- String userId = "userId";
-
- //when a v1/impersonate request is made
- sdk.onRequest(request).impersonateStart(userId);
- }
-}
diff --git a/src/test/java/io/castle/client/CastleImpersonateStartHttpTest.java b/src/test/java/io/castle/client/CastleImpersonateStartHttpTest.java
deleted file mode 100644
index f2cb0eb6..00000000
--- a/src/test/java/io/castle/client/CastleImpersonateStartHttpTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleImpersonateStartHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleImpersonateStartHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void impersonateStart() throws Exception {
- MockResponse mockResponse = new MockResponse();
- mockResponse.setBody("{\"success\":true}");
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an devices request is made
- CastleSuccess result = sdk.onRequest(request).impersonateStart("userId");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/impersonate"), recordedRequest.getRequestUrl());
- Assert.assertEquals("POST", recordedRequest.getMethod());
-
- // and the correct Success model object is extracted
- CastleSuccess expected = new CastleSuccess();
- expected.setSuccess(true);
-
- Assertions.assertThat(result).usingRecursiveComparison().isEqualTo(expected);
- }
-
- @Test(expected = CastleApiTimeoutException.class)
- public void impersonateStartTimeoutTest() {
-
- // given backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- HttpServletRequest request = new MockHttpServletRequest();
- String userId = "userId";
-
- //when a review request is made
- sdk.onRequest(request).impersonateStart(userId);
- }
-}
\ No newline at end of file
diff --git a/src/test/java/io/castle/client/CastleListItemsTest.java b/src/test/java/io/castle/client/CastleListItemsTest.java
index a3c91e91..08537085 100644
--- a/src/test/java/io/castle/client/CastleListItemsTest.java
+++ b/src/test/java/io/castle/client/CastleListItemsTest.java
@@ -1,7 +1,5 @@
package io.castle.client;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.CastleResponse;
import io.castle.client.model.generated.*;
import jakarta.servlet.http.HttpServletRequest;
@@ -18,10 +16,6 @@
public class CastleListItemsTest extends AbstractCastleHttpLayerTest {
- public CastleListItemsTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
@Test
public void createListItem() throws InterruptedException {
MockResponse mockResponse = new MockResponse();
diff --git a/src/test/java/io/castle/client/CastleListsHttpTest.java b/src/test/java/io/castle/client/CastleListsHttpTest.java
index 548be6f8..3275fb2a 100644
--- a/src/test/java/io/castle/client/CastleListsHttpTest.java
+++ b/src/test/java/io/castle/client/CastleListsHttpTest.java
@@ -2,8 +2,6 @@
import com.google.gson.JsonParser;
import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.generated.*;
import jakarta.servlet.http.HttpServletRequest;
import okhttp3.mockwebserver.MockResponse;
@@ -19,10 +17,6 @@
public class CastleListsHttpTest extends AbstractCastleHttpLayerTest {
- public CastleListsHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
@Test
public void updateList() throws InterruptedException {
MockResponse mockResponse = new MockResponse();
diff --git a/src/test/java/io/castle/client/CastleLogHttpTest.java b/src/test/java/io/castle/client/CastleLogHttpTest.java
index d3d1a579..534adadc 100644
--- a/src/test/java/io/castle/client/CastleLogHttpTest.java
+++ b/src/test/java/io/castle/client/CastleLogHttpTest.java
@@ -1,11 +1,8 @@
package io.castle.client;
import com.google.gson.JsonParser;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.CastleResponse;
import io.castle.client.model.generated.*;
-import io.castle.client.utils.DeviceUtils;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.RecordedRequest;
import org.assertj.core.api.Assertions;
@@ -20,10 +17,6 @@
public class CastleLogHttpTest extends AbstractCastleHttpLayerTest {
- public CastleLogHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
@Test public void log() throws InterruptedException {
MockResponse mockResponse = new MockResponse();
mockResponse.setResponseCode(204);
diff --git a/src/test/java/io/castle/client/CastleMergeHttpTest.java b/src/test/java/io/castle/client/CastleMergeHttpTest.java
deleted file mode 100644
index 8323ad55..00000000
--- a/src/test/java/io/castle/client/CastleMergeHttpTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
-import io.castle.client.utils.SDKVersion;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.Test;
-import org.skyscreamer.jsonassert.JSONAssert;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import com.google.common.collect.ImmutableMap;
-
-import jakarta.servlet.http.HttpServletRequest;
-import java.util.concurrent.atomic.AtomicReference;
-import io.castle.client.model.AsyncCallbackHandler;
-import org.assertj.core.api.Assertions;
-
-public class CastleMergeHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleMergeHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test
- public void mergeContextIsSendOnHttp() throws InterruptedException, JSONException {
- // Given
- server.enqueue(new MockResponse().setResponseCode(200));
- String event = "any.valid.event";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And a extra context
- CustomExtraContext customExtraContext = new CustomExtraContext();
- customExtraContext.setAddString("String value");
- customExtraContext.setCondition(true);
- customExtraContext.setValue(10L);
- sdk.onRequest(request).mergeContext(customExtraContext).track(event, null, null, null, ImmutableMap.builder()
- .put("x", "valueX")
- .put("y", 234567)
- .build());
-
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
-
- JSONAssert.assertEquals("{\"event\":\"any.valid.event\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +",\"add_string\":\"String value\",\"condition\":true,\"value\":10},\"user_traits\":{\"x\":\"valueX\",\"y\":234567}}", body, false);
- }
-
- @Test
- public void mergeContextIsNull() throws InterruptedException, JSONException {
- // Given
- server.enqueue(new MockResponse().setResponseCode(200));
- String event = "any.valid.event";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And null context
- sdk.onRequest(request).mergeContext(null).track(event, null, null, null);
-
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
-
- JSONAssert.assertEquals("{\"event\":\"any.valid.event\"}", body, false);
- }
-
- private static class CustomExtraContext {
- private String addString;
- private Boolean condition;
- private Long value;
-
- public String getAddString() {
- return addString;
- }
-
- public void setAddString(String addString) {
- this.addString = addString;
- }
-
- public Boolean getCondition() {
- return condition;
- }
-
- public void setCondition(Boolean condition) {
- this.condition = condition;
- }
-
- public Long getValue() {
- return value;
- }
-
- public void setValue(Long value) {
- this.value = value;
- }
- }
-}
diff --git a/src/test/java/io/castle/client/CastleNoTrackOptionTest.java b/src/test/java/io/castle/client/CastleNoTrackOptionTest.java
deleted file mode 100644
index 144a03f7..00000000
--- a/src/test/java/io/castle/client/CastleNoTrackOptionTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.api.CastleApi;
-import io.castle.client.model.AsyncCallbackHandler;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
-import io.castle.client.model.Verdict;
-import okhttp3.mockwebserver.MockResponse;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-import java.util.concurrent.atomic.AtomicReference;
-
-public class CastleNoTrackOptionTest extends AbstractCastleHttpLayerTest {
-
- public CastleNoTrackOptionTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test
- public void noTrackOptionDisableRequests() throws InterruptedException {
-
- //Given a mock HTTP request is provided
- HttpServletRequest request = new MockHttpServletRequest();
- //And a CastleApi is created with doNotTrack option
- CastleApi castleApi = sdk.onRequest(request).doNotTrack(true);
- // And a custom handler for the async authenticate call
- final AtomicReference authenticateAsyncResult = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- authenticateAsyncResult.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
-
- //When all API call are executed
- castleApi.track("testEvent");
- Verdict verdict = castleApi.authenticate("testEvent", "userId");
- castleApi.authenticateAsync("testEvent", "userId", handler);
-
- //and we await the timeout period to avoid concurrency races
- Thread.sleep(120);
-
- //Then no calls are made to the backend
- Assertions.assertThat(server.getRequestCount()).isEqualTo(0);
- //And the Verdict is the default ALLOW value
- Assert.assertEquals(AuthenticateAction.ALLOW, verdict.getAction());
- Assert.assertEquals("userId", verdict.getUserId());
- Assert.assertEquals(AuthenticateAction.ALLOW, authenticateAsyncResult.get().getAction());
- Assertions.assertThat(authenticateAsyncResult.get().isFailover()).isTrue();
- }
-
- @Test
- public void useCustomTrackHandlerWithNoTrackOptionToDisableRequests() {
- //Given a mock HTTP request is provided
- HttpServletRequest request = new MockHttpServletRequest();
- //And a CastleApi is created with doNotTrack option
- CastleApi castleApi = sdk.onRequest(request).doNotTrack(true);
- // And a custom handler for the async track call
- final AtomicReference trackAsyncResult = new AtomicReference<>();
-
- AsyncCallbackHandler trackHandler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Boolean response) {
- trackAsyncResult.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
-
- }
- };
-
- //When an API call is executed
- castleApi.track(
- "testEvent",
- null,
- null,
- null,
- null,
- trackHandler
- );
-
- //Then no calls are made to the backend
- Assertions.assertThat(server.getRequestCount()).isEqualTo(0);
-
- //And the track call returns and the resulting boolean is true
- Assert.assertTrue(trackAsyncResult.get());
- }
-
- @Test
- public void noTrackOptionCreateAllowFailoverVerdict() {
-
- //Given a mock HTTP request is provided
- HttpServletRequest request = new MockHttpServletRequest();
- //And a CastleApi is created with doNotTrack option
- CastleApi castleApi = sdk.onRequest(request).doNotTrack(true);
- //When authenticate is called
-
- Verdict verdict = castleApi.authenticate("testEvent", "userId");
-
- //Then no calls are made to the backend
- Assertions.assertThat(server.getRequestCount()).isEqualTo(0);
- //And the Verdict is the correct failover value
- Assert.assertEquals(AuthenticateAction.ALLOW, verdict.getAction());
-
- Assertions.assertThat(verdict.getUserId()).isEqualTo("userId");
- Assertions.assertThat(verdict.getAction()).isEqualTo(AuthenticateAction.ALLOW);
- Assertions.assertThat(verdict.getFailoverReason()).isEqualTo("Castle set to do not track.");
- Assertions.assertThat(verdict.isFailover()).isTrue();
- }
-
-
- @Test
- public void trackOptionAllowRequests() throws InterruptedException {
-
- //Given a mock HTTP request is provided
- HttpServletRequest request = new MockHttpServletRequest();
- //And responses are setup on mock server
- server.enqueue(new MockResponse().setResponseCode(200));
- server.enqueue(new MockResponse().setBody(
- "{\n" +
- " \"action\": \"deny\",\n" +
- " \"user_id\": \"12345\"\n" +
- "}"));
- server.enqueue(new MockResponse().setBody(
- "{\n" +
- " \"action\": \"deny\",\n" +
- " \"user_id\": \"12345\"\n" +
- "}"));
- //And a CastleApi is created with doNotTrack option
- CastleApi castleApi = sdk.onRequest(request).doNotTrack(false);
- // And a custom handler for the async authenticate call
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler handler = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("error on request", exception);
- }
- };
-
- //When all API call are executed
- castleApi.track("testEvent");
- server.takeRequest();
- castleApi.authenticate("testEvent", "userId");
- server.takeRequest();
- castleApi.authenticateAsync("testEvent", "userId", handler);
- server.takeRequest();
-
- //Then all the calls are executed
- waitForValue(result);
- Assertions.assertThat(server.getRequestCount()).isEqualTo(3);
- Assert.assertEquals(AuthenticateAction.DENY, result.get().getAction());
- }
-
-}
diff --git a/src/test/java/io/castle/client/CastlePrivacyHttpTest.java b/src/test/java/io/castle/client/CastlePrivacyHttpTest.java
new file mode 100644
index 00000000..25956c2f
--- /dev/null
+++ b/src/test/java/io/castle/client/CastlePrivacyHttpTest.java
@@ -0,0 +1,53 @@
+package io.castle.client;
+
+import com.google.common.collect.ImmutableMap;
+import io.castle.client.model.CastleResponse;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.assertj.core.api.Assertions;
+import org.json.JSONException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+public class CastlePrivacyHttpTest extends AbstractCastleHttpLayerTest {
+
+ @Test
+ public void requestUserData() throws InterruptedException, JSONException {
+ server.enqueue(new MockResponse().setBody("{}"));
+ HttpServletRequest request = new MockHttpServletRequest();
+
+ CastleResponse response = sdk.onRequest(request).requestUserData(ImmutableMap.builder()
+ .put("user_id", "12345")
+ .build());
+ if (response == null) {
+ Assertions.fail("error on request");
+ }
+
+ RecordedRequest recordedRequest = server.takeRequest();
+ String body = recordedRequest.getBody().readUtf8();
+ Assert.assertEquals(testServerBaseUrl.resolve("v1/privacy/users"), recordedRequest.getRequestUrl());
+ Assert.assertEquals("POST", recordedRequest.getMethod());
+ JSONAssert.assertEquals("{\"user_id\":\"12345\"}", body, false);
+ }
+
+ @Test
+ public void deleteUserData() throws InterruptedException, JSONException {
+ server.enqueue(new MockResponse().setBody("{}"));
+ HttpServletRequest request = new MockHttpServletRequest();
+
+ CastleResponse response = sdk.onRequest(request).deleteUserData(ImmutableMap.builder()
+ .put("user_id", "12345")
+ .build());
+ if (response == null) {
+ Assertions.fail("error on request");
+ }
+
+ RecordedRequest recordedRequest = server.takeRequest();
+ Assert.assertEquals(testServerBaseUrl.resolve("v1/privacy/users"), recordedRequest.getRequestUrl());
+ Assert.assertEquals("DELETE", recordedRequest.getMethod());
+ }
+}
diff --git a/src/test/java/io/castle/client/CastleRecoverHttpTest.java b/src/test/java/io/castle/client/CastleRecoverHttpTest.java
deleted file mode 100644
index cdc76bd0..00000000
--- a/src/test/java/io/castle/client/CastleRecoverHttpTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.*;
-import io.castle.client.utils.DeviceUtils;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleRecoverHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleRecoverHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void recoverDevices() throws InterruptedException {
- MockResponse mockResponse = new MockResponse();
- mockResponse.setBody(DeviceUtils.getDefaultDeviceJSON());
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an report device request is made
- CastleResponse response = sdk.onRequest(request).recover("1234");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/users/1234/recover"), recordedRequest.getRequestUrl());
- Assert.assertEquals("PUT", recordedRequest.getMethod());
- }
-}
diff --git a/src/test/java/io/castle/client/CastleRemoveUserHttpTest.java b/src/test/java/io/castle/client/CastleRemoveUserHttpTest.java
deleted file mode 100644
index 06233e8d..00000000
--- a/src/test/java/io/castle/client/CastleRemoveUserHttpTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
-import io.castle.client.model.CastleApiInternalServerErrorException;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-public class CastleRemoveUserHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleRemoveUserHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test
- public void removeUser() throws Exception {
- // Mock a response
- MockResponse mockResponse = new MockResponse();
- mockResponse.setResponseCode(202);
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an privacy remove user request is made
- Boolean response = sdk.onRequest(request).removeUser("user-test-id");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/privacy/users/user-test-id"), recordedRequest.getRequestUrl());
- Assert.assertEquals("DELETE", recordedRequest.getMethod());
- Assert.assertTrue(response);
- }
-
- @Test
- public void removeUserNotFoundTest() throws Exception {
- // Mock a response
- MockResponse mockResponse = new MockResponse();
- mockResponse.setResponseCode(404);
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an privacy remove user request is made
- Boolean response = sdk.onRequest(request).removeUser("user-test-id");
-
- // Then it doesn't throw exception
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals(testServerBaseUrl.resolve("v1/privacy/users/user-test-id"), recordedRequest.getRequestUrl());
- Assert.assertEquals("DELETE", recordedRequest.getMethod());
-
- Assert.assertNull(response);
- }
-
- @Test(expected = CastleApiInternalServerErrorException.class)
- public void removeUserServerError() {
- // Mock a response
- MockResponse mockResponse = new MockResponse();
- mockResponse.setResponseCode(500);
- server.enqueue(mockResponse);
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And a privacy remove user request is made, exception throw
- Boolean response = sdk.onRequest(request).removeUser("user-test-id");
-
- Assert.assertNull(response);
- }
-}
\ No newline at end of file
diff --git a/src/test/java/io/castle/client/CastleRiskHttpTest.java b/src/test/java/io/castle/client/CastleRiskHttpTest.java
index a3bb7a26..59bd2957 100644
--- a/src/test/java/io/castle/client/CastleRiskHttpTest.java
+++ b/src/test/java/io/castle/client/CastleRiskHttpTest.java
@@ -2,8 +2,6 @@
import com.google.gson.JsonParser;
import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.generated.*;
import jakarta.servlet.http.HttpServletRequest;
import okhttp3.mockwebserver.MockResponse;
@@ -18,10 +16,6 @@
public class CastleRiskHttpTest extends AbstractCastleHttpLayerTest {
- public CastleRiskHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
@Test public void risk() throws InterruptedException {
MockResponse mockResponse = new MockResponse();
mockResponse.setBody("{\n" +
diff --git a/src/test/java/io/castle/client/CastleThrowStrategyTest.java b/src/test/java/io/castle/client/CastleThrowStrategyTest.java
deleted file mode 100644
index c5c7df0e..00000000
--- a/src/test/java/io/castle/client/CastleThrowStrategyTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.*;
-import okhttp3.mockwebserver.MockResponse;
-import org.assertj.core.api.Assertions;
-import org.junit.Test;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import jakarta.servlet.http.HttpServletRequest;
-import java.util.concurrent.atomic.AtomicReference;
-
-import static okhttp3.mockwebserver.SocketPolicy.NO_RESPONSE;
-
-public class CastleThrowStrategyTest extends AbstractCastleHttpLayerTest {
-
- public CastleThrowStrategyTest() {
- super(new AuthenticateFailoverStrategy());
- }
-
- @Test(expected = CastleApiTimeoutException.class)
- public void onThrowStrategyAuthenticateThrowCastleRuntimeExceptionWhenNoResponse() {
- // given the throw strategy is setup (see constructor)
- // and backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- // and
- String id = "12345";
- String event = "$login.succeeded";
-
- // and a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // when authenticate request is made
- sdk.onRequest(request).authenticate(event, id);
-
- // then the exception is throw
- }
-
- @Test(expected = CastleApiInternalServerErrorException.class)
- public void onThrowStrategyAuthenticateThrowCastleRuntimeExceptionWhenResponseIs500() {
- // given the throw strategy is setup (see constructor)
- // and backend request timeouts
- server.enqueue(new MockResponse().setResponseCode(500));
- // and
- String id = "12345";
- String event = "$login.succeeded";
-
- // and a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // when authenticate request is made
- Verdict authenticate = sdk.onRequest(request).authenticate(event, id);
-
- // then the exception is throw
- Assertions.fail("A exception should be throw");
- }
-
- @Test
- public void onThrowStrategyAuthenticateAsyncThrowCastleRuntimeException() {
- // given the throw strategy is setup (see constructor)
- // and backend request timeouts
- server.enqueue(new MockResponse().setSocketPolicy(NO_RESPONSE));
- // and
- String id = "12345";
- String event = "$login.succeeded";
-
- // and a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
- // and a async callback is prepared
- final AtomicReference exceptionAtomicReference = new AtomicReference<>();
- AsyncCallbackHandler callback = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Verdict response) {
- Assertions.fail("A exceptions was expected");
- }
-
- @Override
- public void onException(Exception exception) {
- exceptionAtomicReference.set(exception);
- }
- };
- // when authenticate request is made
- sdk.onRequest(request).authenticateAsync(event, id, callback);
-
- // then the exception is throw in the callback
- Exception exception = waitForValue(exceptionAtomicReference);
- Assertions.assertThat(exception)
- .isNotNull()
- .isInstanceOf(CastleRuntimeException.class);
- }
-
-
-}
diff --git a/src/test/java/io/castle/client/CastleTrackHttpTest.java b/src/test/java/io/castle/client/CastleTrackHttpTest.java
deleted file mode 100644
index 9fb036db..00000000
--- a/src/test/java/io/castle/client/CastleTrackHttpTest.java
+++ /dev/null
@@ -1,313 +0,0 @@
-package io.castle.client;
-
-import io.castle.client.model.AsyncCallbackHandler;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
-import io.castle.client.model.CastleContext;
-import io.castle.client.model.CastleHeaders;
-import io.castle.client.utils.SDKVersion;
-import io.castle.client.model.CastleMessage;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.RecordedRequest;
-import okhttp3.mockwebserver.SocketPolicy;
-import org.assertj.core.api.Assertions;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.Test;
-import org.skyscreamer.jsonassert.JSONAssert;
-import org.springframework.mock.web.MockHttpServletRequest;
-
-import com.google.common.collect.ImmutableMap;
-
-import jakarta.servlet.http.HttpServletRequest;
-import java.util.concurrent.atomic.AtomicReference;
-
-public class CastleTrackHttpTest extends AbstractCastleHttpLayerTest {
-
- public CastleTrackHttpTest() {
- super(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE));
- }
-
- @Test public void trackWithManualContext() throws Exception {
- server.enqueue(new MockResponse());
-
-
- // When
- CastleContext context = sdk.contextBuilder()
- .ip("1.1.1.1")
- .userAgent("Mozilla/5.0")
- .clientId("")
- .headers(CastleHeaders.builder()
- .add("User-Agent", "Mozilla/5.0")
- .add("Accept-Language", "sv-se")
- .build()
- )
- .build();
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And a track request is made
- sdk.onRequest(request).track(CastleMessage.builder("$login.succeeded")
- .userId("12345")
- .context(context)
- .build()
- );
-
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"client_id\":\"\",\"ip\":\"1.1.1.1\",\"headers\":{\"User-Agent\":\"Mozilla/5.0\",\"Accept-Language\":\"sv-se\"}," + SDKVersion.getLibraryString() +",\"user_agent\":\"Mozilla/5.0\"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void trackEndpointHttpAuthorize() throws Exception {
- // Given
- Castle.verifySdkConfigurationAndInitialize();
-
- server.enqueue(new MockResponse());
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // And an track request is made
- sdk.onRequest(request).track("$login.successful", "1234");
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- Assert.assertEquals("Basic OnRlc3RfYXBpX3NlY3JldA==", recordedRequest.getHeader("Authorization"));
- }
-
- @Test
- public void trackEndpointWithPaylod() throws InterruptedException, JSONException {
- // Given
- server.enqueue(new MockResponse());
- CastleMessage payload = CastleMessage.builder("$login.succeeded")
- .userId("12345")
- .build();
- HttpServletRequest request = new MockHttpServletRequest();
-
- // When
- sdk.onRequest(request).track(payload);
-
- // Then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void trackEndpointWithUserIDTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse());
- String id = "12345";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an track request is made
- sdk.onRequest(request).track(event, id);
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void trackEndpointWithUserIDAndReviewIdTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse());
- String userId = "12345";
- String reviewId = "r45677";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an track request is made
- sdk.onRequest(request).track(event, userId,reviewId);
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"review_id\":\"r45677\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void trackEndpointWithUserIDAndPropertiesTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse());
- String userId = "12345";
- String reviewId = "r987";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an track request is made
- sdk.onRequest(request).track(event, userId, reviewId, ImmutableMap.builder()
- .put("a","valueA")
- .put("b",123456)
- .build());
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"properties\":{\"a\":\"valueA\",\"b\":123456},\"review_id\":\"r987\",\"user_id\":\"12345\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void trackEndpointWithUserIDAndPropertiesAndTraitTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse());
- String userId = "23456";
- String reviewId = "r987";
- String event = "$login.succeeded";
-
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an track request is made
- sdk.onRequest(request).track(event, userId, reviewId, ImmutableMap.builder()
- .put("a","valueA")
- .put("b",123456)
- .build(), ImmutableMap.builder()
- .put("x", "x value")
- .put("y", 2342)
- .build());
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"$login.succeeded\",\"properties\":{\"a\":\"valueA\",\"b\":123456},\"review_id\":\"r987\",\"user_id\":\"23456\",\"user_traits\":{\"x\":\"x value\",\"y\":2342},\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void trackEndpointWithMinimalInformationTest() throws InterruptedException, JSONException {
- //given
- server.enqueue(new MockResponse());
- String event = "any.valid.event";
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an track request is made
- sdk.onRequest(request).track(event);
-
- // then
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"any.valid.event\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
- }
-
- @Test
- public void trackEndpointAsyncTest() throws InterruptedException {
- //given
- server.enqueue(new MockResponse().setResponseCode(200));
- String event = "any.valid.event";
- // And a mock Request
- HttpServletRequest request = new MockHttpServletRequest();
-
- // and an async track request is made
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler callback = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Boolean response) {
- result.set(response);
- }
-
- @Override
- public void onException(Exception exception) {
- Assertions.fail("No exception expected here");
- }
- };
- sdk.onRequest(request).track(event, null, null, null,null,callback);
-
- // then the callback response is called with true
- Boolean extracted = waitForValue(result);
- Assertions.assertThat(extracted).isTrue();
- }
-
- @Test
- public void trackEndpointTimeoutTest() throws InterruptedException, JSONException {
- // given the backend will timeout
- server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.NO_RESPONSE));
- String event = "any.valid.event";
- // and a mock Request
- final HttpServletRequest request = new MockHttpServletRequest();
-
- // and a async handler is prepared
- final AtomicReference result = new AtomicReference<>();
- AsyncCallbackHandler callback = new AsyncCallbackHandler() {
- @Override
- public void onResponse(Boolean response) {
- Assertions.fail("Request should end with an timeout exception and not result");
- }
-
- @Override
- public void onException(Exception exception) {
- result.set(false);
- }
- };
- // when an track request is made
- sdk.onRequest(request).track(event, null, null, null,null,callback);
-
- // then the track request must be send
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"any.valid.event\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
-
- // and the onException method must be called
- waitForValueAndVerify(result, Boolean.FALSE);
- }
-
- @Test
- public void trackEndpointTimeoutAreIgnoreWhenNoCallbackIsProvidedTest() throws InterruptedException, JSONException {
- // given the backend will timeout
- server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.NO_RESPONSE));
- String event = "any.valid.event";
- // and a mock Request
- final HttpServletRequest request = new MockHttpServletRequest();
-
- // when an track request is made
- sdk.onRequest(request).track(event, null, null, null);
-
- // then the track request must be send
- RecordedRequest recordedRequest = server.takeRequest();
- String body = recordedRequest.getBody().readUtf8();
- JSONAssert.assertEquals("{\"event\":\"any.valid.event\",\"context\":{\"active\":true,\"ip\":\"127.0.0.1\",\"headers\":{\"REMOTE_ADDR\":\"127.0.0.1\"}," + SDKVersion.getLibraryString() +"}}",
- body, false);
-
- Assert.assertTrue(new JSONObject(body).has("sent_at"));
-
- // and no exceptions are thrown in any thread
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/io/castle/client/CastleWebhookTest.java b/src/test/java/io/castle/client/CastleWebhookTest.java
new file mode 100644
index 00000000..c6478a97
--- /dev/null
+++ b/src/test/java/io/castle/client/CastleWebhookTest.java
@@ -0,0 +1,38 @@
+package io.castle.client;
+
+import io.castle.client.internal.utils.Webhook;
+import io.castle.client.model.CastleSdkConfigurationException;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+
+public class CastleWebhookTest {
+
+ private static final String SECRET = "test_api_secret";
+
+ @Test
+ public void verifiesValidSignature() throws CastleSdkConfigurationException {
+ Castle sdk = Castle.verifySdkConfigurationAndInitialize();
+ byte[] body = "{\"type\":\"$review.opened\"}".getBytes(StandardCharsets.UTF_8);
+ String signature = Webhook.computeSignature(SECRET, body);
+
+ Assertions.assertThat(sdk.verifyWebhookSignature(signature, body)).isTrue();
+ }
+
+ @Test
+ public void rejectsInvalidSignature() throws CastleSdkConfigurationException {
+ Castle sdk = Castle.verifySdkConfigurationAndInitialize();
+ byte[] body = "{\"type\":\"$review.opened\"}".getBytes(StandardCharsets.UTF_8);
+
+ Assertions.assertThat(sdk.verifyWebhookSignature("not-the-signature", body)).isFalse();
+ }
+
+ @Test
+ public void rejectsNullSignature() throws CastleSdkConfigurationException {
+ Castle sdk = Castle.verifySdkConfigurationAndInitialize();
+ byte[] body = "{}".getBytes(StandardCharsets.UTF_8);
+
+ Assertions.assertThat(sdk.verifyWebhookSignature((String) null, body)).isFalse();
+ }
+}
diff --git a/src/test/java/io/castle/client/internal/config/ConfigurationLoaderTest.java b/src/test/java/io/castle/client/internal/config/ConfigurationLoaderTest.java
index 25d0ac7d..890a5c1c 100644
--- a/src/test/java/io/castle/client/internal/config/ConfigurationLoaderTest.java
+++ b/src/test/java/io/castle/client/internal/config/ConfigurationLoaderTest.java
@@ -1,7 +1,5 @@
package io.castle.client.internal.config;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.AuthenticateFailoverStrategy;
import io.castle.client.model.CastleRuntimeException;
import io.castle.client.model.CastleSdkConfigurationException;
import org.assertj.core.api.Assertions;
@@ -88,7 +86,6 @@ public void loadFromProperties() throws CastleSdkConfigurationException {
)
.withDefaultBackendProvider()
.withTimeout(100)
- .withAuthenticateFailoverStrategy(new AuthenticateFailoverStrategy(AuthenticateAction.CHALLENGE))
.build();
//Then the value of the timeout should be the one in the properties file castle_sdk.properties
@@ -145,7 +142,6 @@ public void loadFromEnv() throws CastleSdkConfigurationException {
.withApiBaseUrl("https://api.dev.castle.io/v1/")
.withTimeout(700)
.withLogHttpRequests(true)
- .withAuthenticateFailoverStrategy(new AuthenticateFailoverStrategy(AuthenticateAction.DENY))
.build();
testLoad(expectedConfiguration);
@@ -193,7 +189,6 @@ public void loadFailoverThrowStrategyFromEnv() throws CastleSdkConfigurationExce
.defaultConfigBuilder()
.withApiSecret("1234")
.withCastleAppId("test_app_id_env")
- .withAuthenticateFailoverStrategy(new AuthenticateFailoverStrategy())
.build();
// when then
diff --git a/src/test/java/io/castle/client/internal/utils/VerdictTransportModelTest.java b/src/test/java/io/castle/client/internal/utils/VerdictTransportModelTest.java
deleted file mode 100644
index 057c1279..00000000
--- a/src/test/java/io/castle/client/internal/utils/VerdictTransportModelTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.castle.client.internal.utils;
-
-import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.model.AuthenticateAction;
-import io.castle.client.model.RiskPolicyType;
-import org.assertj.core.api.Assertions;
-import org.junit.Test;
-
-public class VerdictTransportModelTest {
-
- @Test
- public void transportProtocolIsWellDeserialized() {
- // given a json input value
- String json = "{\n" +
- " \"action\": \"deny\",\n" +
- " \"user_id\": \"12345\",\n" +
- " \"device_token\": \"abcdefg1234\",\n" +
- " \"risk_policy\": {\n" +
- " \"id\": \"q-rbeMzBTdW2Fd09sbz55A\",\n" +
- " \"revision_id\": \"pke4zqO2TnqVr-NHJOAHEg\",\n" +
- " \"name\": \"Block Users from X\",\n" +
- " \"type\": \"bot\"\n" +
- " }\n" +
- "}";
- // and castle gson model
- CastleGsonModel model = new CastleGsonModel();
-
-
- // when the Verdict transport object is deserialized
- VerdictTransportModel loaded = model.getGson().fromJson(json, VerdictTransportModel.class);
-
- Assertions.assertThat(loaded.getAction()).isEqualTo(AuthenticateAction.DENY);
- Assertions.assertThat(loaded.getDeviceToken()).isEqualTo("abcdefg1234");
- Assertions.assertThat(loaded.getUserId()).isEqualTo("12345");
- Assertions.assertThat(loaded.getRiskPolicy().getId()).isEqualTo("q-rbeMzBTdW2Fd09sbz55A");
- Assertions.assertThat(loaded.getRiskPolicy().getRevisionId()).isEqualTo("pke4zqO2TnqVr-NHJOAHEg");
- Assertions.assertThat(loaded.getRiskPolicy().getName()).isEqualTo("Block Users from X");
- Assertions.assertThat(loaded.getRiskPolicy().getType()).isEqualTo(RiskPolicyType.BOT);
- }
-}
diff --git a/src/test/java/io/castle/client/model/AuthenticationActionTest.java b/src/test/java/io/castle/client/model/AuthenticationActionTest.java
deleted file mode 100644
index 57c1e5d0..00000000
--- a/src/test/java/io/castle/client/model/AuthenticationActionTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package io.castle.client.model;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class AuthenticationActionTest {
-
- @Test
- public void testFromAllow() {
- testFromActionMethod("AllOw", AuthenticateAction.ALLOW);
- }
-
- @Test
- public void testFromDeny() {
- testFromActionMethod("Deny", AuthenticateAction.DENY);
- }
-
- @Test
- public void testFromChallenge() {
- testFromActionMethod("cHallenge", AuthenticateAction.CHALLENGE);
- }
-
- @Test
- public void testFromNull() {
- testFromActionMethod(null, null);
- }
-
- @Test
- public void testFromEmptyString() {
- testFromActionMethod("", null);
- }
-
- @Test
- public void testFromWrongString() {
- testFromActionMethod("getMeANull", null);
- }
-
- private void testFromActionMethod(String from, AuthenticateAction expected) {
-
- AuthenticateAction authenticateAction = AuthenticateAction.fromAction(from);
- Assert.assertEquals(expected, authenticateAction);
-
- }
-
-
-}
diff --git a/src/test/java/io/castle/client/model/CastleConfigurationBuilderTest.java b/src/test/java/io/castle/client/model/CastleConfigurationBuilderTest.java
index 7805885c..053dbb33 100644
--- a/src/test/java/io/castle/client/model/CastleConfigurationBuilderTest.java
+++ b/src/test/java/io/castle/client/model/CastleConfigurationBuilderTest.java
@@ -23,7 +23,6 @@ public void buildDefaultConfiguration() throws CastleSdkConfigurationException {
Assertions.assertThat(config.getDenyListHeaders()).contains("cookie");
Assertions.assertThat(config.getDenyListHeaders()).contains("authorization");
Assertions.assertThat(config.getAllowListHeaders()).isEmpty();
- Assertions.assertThat(config.getAuthenticateFailoverStrategy().getDefaultAction()).isEqualTo(AuthenticateAction.ALLOW);
Assertions.assertThat(config.getTimeout()).isEqualTo(500);
diff --git a/src/test/java/io/castle/client/model/CastleMessageTest.java b/src/test/java/io/castle/client/model/CastleMessageTest.java
deleted file mode 100644
index 1cbbce0e..00000000
--- a/src/test/java/io/castle/client/model/CastleMessageTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package io.castle.client.model;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import io.castle.client.internal.json.CastleGsonModel;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.HashMap;
-
-public class CastleMessageTest {
-
- private CastleGsonModel model = new CastleGsonModel();
-
- @Test
- public void jsonSerialized() {
- // Given
- CastleMessage message = new CastleMessage("event");
- message.setCreatedAt("2018-01-01");
- message.setTimestamp("2018-01-01");
- message.setDeviceToken("1234");
- message.setReviewId("2345");
- message.setProperties(ImmutableMap.builder()
- .put("key", "val")
- .build());
- message.setUserId("3456");
- message.setUserTraits(ImmutableMap.builder()
- .put("key", "val")
- .build());
-
- // When
- String payloadJson = model.getGson().toJson(message);
- String expected = "{\"created_at\":\"2018-01-01\",\"timestamp\":\"2018-01-01\",\"device_token\":\"1234\",\"event\":\"event\",\"properties\":{\"key\":\"val\"},\"review_id\":\"2345\",\"user_id\":\"3456\",\"user_traits\":{\"key\":\"val\"}}";
-
- // Then
- Assertions.assertThat(JsonParser.parseString(payloadJson)).isEqualTo(JsonParser.parseString(expected));
-
- }
-
- @Test
- public void fullBuilderJson() {
- // Given
- CastleMessage message = CastleMessage.builder("event")
- .createdAt("2018-01-01")
- .timestamp("2018-01-01")
- .deviceToken("1234")
- .reviewId("2345")
- .properties(ImmutableMap.builder()
- .put("key", "val")
- .build())
- .userId("3456")
- .userTraits(ImmutableMap.builder()
- .put("key", "val")
- .build())
- .build();
-
- Assert.assertEquals(message.getCreatedAt(), "2018-01-01");
- Assert.assertEquals(message.getDeviceToken(), "1234");
- Assert.assertEquals(message.getReviewId(), "2345");
- Assert.assertEquals(message.getUserId(), "3456");
- Assert.assertEquals(message.getEvent(), "event");
- Assert.assertEquals(message.getUserTraits(), ImmutableMap.builder()
- .put("key", "val")
- .build());
- Assert.assertEquals(message.getProperties(), ImmutableMap.builder()
- .put("key", "val")
- .build());
-
- // When
- String payloadJson = model.getGson().toJson(message);
- String expected = "{\"created_at\":\"2018-01-01\",\"timestamp\":\"2018-01-01\",\"device_token\":\"1234\",\"event\":\"event\",\"properties\":{\"key\":\"val\"},\"review_id\":\"2345\",\"user_id\":\"3456\",\"user_traits\":{\"key\":\"val\"}}";
-
- // Then
- Assertions.assertThat(JsonParser.parseString(payloadJson)).isEqualTo(JsonParser.parseString(expected));
- }
-
- @Test
- public void properties() {
- JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("key", "value");
-
- CastleMessage message = CastleMessage.builder("event")
- .properties(jsonObject)
- .build();
-
- String payloadJson = model.getGson().toJson(message);
- String expected = "{\"event\":\"event\",\"properties\":{\"key\":\"value\"}}";
-
- Assertions.assertThat(JsonParser.parseString(payloadJson)).isEqualTo(JsonParser.parseString(expected));
- }
-
- @Test
- public void otherProperties() {
- CastleMessage message = CastleMessage.builder("event")
- .put("key", "value")
- .build();
-
- String payloadJson = model.getGson().toJson(message);
-
- Assertions.assertThat(payloadJson).isEqualTo("{\"event\":\"event\",\"key\":\"value\"}");
-
- HashMap other = new HashMap();
- other.put("key", "value");
-
- message = CastleMessage.builder("event")
- .other(other)
- .build();
-
- payloadJson = model.getGson().toJson(message);
-
- Assertions.assertThat(payloadJson).isEqualTo("{\"event\":\"event\",\"key\":\"value\"}");
- }
-
- @Test(expected = NullPointerException.class)
- public void propertiesNull() {
- CastleMessage message = CastleMessage.builder("event")
- .properties(null)
- .build();
- }
-
- @Test(expected = NullPointerException.class)
- public void userTraitsNull() {
- CastleMessage message = CastleMessage.builder("event")
- .userTraits(null)
- .build();
- }
-}
diff --git a/src/test/java/io/castle/client/model/CastleUserDeviceContextTest.java b/src/test/java/io/castle/client/model/CastleUserDeviceContextTest.java
deleted file mode 100644
index b46563bf..00000000
--- a/src/test/java/io/castle/client/model/CastleUserDeviceContextTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package io.castle.client.model;
-
-import com.google.gson.JsonParser;
-import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.utils.DeviceUtils;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class CastleUserDeviceContextTest {
- private CastleGsonModel model = new CastleGsonModel();
-
- @Test
- public void jsonSerialized() {
- // Given
- CastleUserDeviceContext deviceContext = new CastleUserDeviceContext();
-
- // When
- String payloadJson = model.getGson().toJson(deviceContext);
-
- // Then
- Assertions.assertThat(payloadJson).isEqualTo("{}");
- }
-
- @Test
- public void fullBuilderJson() {
- // Given
- CastleUserDeviceContext deviceContext = new CastleUserDeviceContext();
- deviceContext.setIp(DeviceUtils.CONTEXT_IP);
- deviceContext.setType(DeviceUtils.CONTEXT_TYPE);
-
- DeviceUserAgent userAgent = new DeviceUserAgent();
- userAgent.setBrowser(DeviceUtils.USER_AGENT_BROWSER);
- userAgent.setDevice(DeviceUtils.USER_AGENT_DEVICE);
- userAgent.setFamily(DeviceUtils.USER_AGENT_FAMILY);
- userAgent.setMobile(DeviceUtils.USER_AGENT_MOBILE);
- userAgent.setOs(DeviceUtils.USER_AGENT_OS);
- userAgent.setPlatform(DeviceUtils.USER_AGENT_PLATFORM);
- userAgent.setRaw(DeviceUtils.USER_AGENT_RAW);
- userAgent.setVersion(DeviceUtils.USER_AGENT_VERSION);
- deviceContext.setUserAgent(userAgent);
-
- // When
- String payloadJson = model.getGson().toJson(deviceContext);
- String expected = "{\"ip\":\"1.1.1.1\",\"user_agent\":{\"raw\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51\",\"browser\":\"Opera\",\"version\":\"54.0.2952\",\"os\":\"Mac OS X 10.13.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Unknown\",\"family\":\"Opera\"},\"type\":\"desktop\"}";
-
- // Then
- Assertions.assertThat(JsonParser.parseString(payloadJson)).isEqualTo(JsonParser.parseString(expected));
-
- Assert.assertEquals(deviceContext.getIp(), DeviceUtils.CONTEXT_IP);
- Assert.assertEquals(deviceContext.getType(), DeviceUtils.CONTEXT_TYPE);
- Assert.assertEquals(deviceContext.getUserAgent(), userAgent);
- }
-}
diff --git a/src/test/java/io/castle/client/model/CastleUserDeviceTest.java b/src/test/java/io/castle/client/model/CastleUserDeviceTest.java
deleted file mode 100644
index 8011231c..00000000
--- a/src/test/java/io/castle/client/model/CastleUserDeviceTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package io.castle.client.model;
-
-import com.google.gson.JsonParser;
-import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.utils.DeviceUtils;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class CastleUserDeviceTest {
-
- private final CastleGsonModel model = new CastleGsonModel();
-
- @Test
- public void jsonSerialized() {
- // Given
- CastleUserDevice device = new CastleUserDevice();
-
- // When
- String payloadJson = model.getGson().toJson(device);
- String expected = "{\"risk\":0.0,\"is_current_device\":false}";
-
- // Then
- Assert.assertEquals(JsonParser.parseString(payloadJson), JsonParser.parseString(expected));
- }
-
- @Test
- public void fullBuilderJson() {
- // Given
- CastleUserDevice device = new CastleUserDevice();
- device.setToken(DeviceUtils.DEVICE_TOKEN);
- device.setCreatedAt(DeviceUtils.DEVICE_CREATED_AT);
- device.setLastSeenAt(DeviceUtils.DEVICE_LAST_SEEN_AT);
- device.setApprovedAt(DeviceUtils.DEVICE_APPROVED_AT);
- device.setEscalatedAt(DeviceUtils.DEVICE_ESCALATED_AT);
- device.setMitigatedAt(DeviceUtils.DEVICE_MITIGATED_AT);
- device.setCurrentDevice(true);
-
- CastleUserDeviceContext deviceContext = new CastleUserDeviceContext();
- deviceContext.setIp(DeviceUtils.CONTEXT_IP);
- deviceContext.setType(DeviceUtils.CONTEXT_TYPE);
-
- DeviceUserAgent userAgent = new DeviceUserAgent();
- userAgent.setBrowser(DeviceUtils.USER_AGENT_BROWSER);
- userAgent.setDevice(DeviceUtils.USER_AGENT_DEVICE);
- userAgent.setFamily(DeviceUtils.USER_AGENT_FAMILY);
- userAgent.setMobile(DeviceUtils.USER_AGENT_MOBILE);
- userAgent.setOs(DeviceUtils.USER_AGENT_OS);
- userAgent.setPlatform(DeviceUtils.USER_AGENT_PLATFORM);
- userAgent.setRaw(DeviceUtils.USER_AGENT_RAW);
- userAgent.setVersion(DeviceUtils.USER_AGENT_VERSION);
- deviceContext.setUserAgent(userAgent);
-
- device.setContext(deviceContext);
-
- // When
- String payloadJson = model.getGson().toJson(device);
- String expected = "{\"token\":\"abcdefg12345\",\"risk\":0.0,\"created_at\":\"2018-06-15T16:36:22.916Z\",\"last_seen_at\":\"2018-07-19T23:09:29.681Z\",\"context\":{\"ip\":\"1.1.1.1\",\"user_agent\":{\"raw\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51\",\"browser\":\"Opera\",\"version\":\"54.0.2952\",\"os\":\"Mac OS X 10.13.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Unknown\",\"family\":\"Opera\"},\"type\":\"desktop\"},\"is_current_device\":true}";
-
- // Then
- Assertions.assertThat(JsonParser.parseString(payloadJson)).isEqualTo(JsonParser.parseString(expected));
-
- Assert.assertEquals(device.getToken(), DeviceUtils.DEVICE_TOKEN);
- Assert.assertEquals(device.getCreatedAt(), DeviceUtils.DEVICE_CREATED_AT);
- Assert.assertEquals(device.getLastSeenAt(), DeviceUtils.DEVICE_LAST_SEEN_AT);
- Assert.assertEquals(device.getApprovedAt(), DeviceUtils.DEVICE_APPROVED_AT);
- Assert.assertEquals(device.getEscalatedAt(), DeviceUtils.DEVICE_ESCALATED_AT);
- Assert.assertEquals(device.getMitigatedAt(), DeviceUtils.DEVICE_MITIGATED_AT);
- Assert.assertTrue(device.isCurrentDevice());
- Assert.assertEquals(device.getContext(), deviceContext);
- }
-}
diff --git a/src/test/java/io/castle/client/model/CastleUserDevicesTest.java b/src/test/java/io/castle/client/model/CastleUserDevicesTest.java
deleted file mode 100644
index a78050b0..00000000
--- a/src/test/java/io/castle/client/model/CastleUserDevicesTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package io.castle.client.model;
-
-import com.google.gson.JsonParser;
-import io.castle.client.internal.json.CastleGsonModel;
-import io.castle.client.utils.DeviceUtils;
-import org.assertj.core.api.Assertions;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class CastleUserDevicesTest {
- private CastleGsonModel model = new CastleGsonModel();
-
- @Test
- public void jsonSerialized() {
- // Given
- CastleUserDevices devices = new CastleUserDevices();
-
- // When
- String payloadJson = model.getGson().toJson(devices);
-
- // Then
- Assertions.assertThat(payloadJson).isEqualTo("{\"total_count\":0}");
- }
-
- @Test
- public void fullBuilderJson() {
- // Given
- CastleUserDevices devices = new CastleUserDevices();
-
- List devicesList = new ArrayList<>();
-
- CastleUserDevice device = new CastleUserDevice();
- device.setToken(DeviceUtils.DEVICE_TOKEN);
- device.setCreatedAt(DeviceUtils.DEVICE_CREATED_AT);
- device.setLastSeenAt(DeviceUtils.DEVICE_LAST_SEEN_AT);
- device.setApprovedAt(DeviceUtils.DEVICE_APPROVED_AT);
- device.setEscalatedAt(DeviceUtils.DEVICE_ESCALATED_AT);
- device.setMitigatedAt(DeviceUtils.DEVICE_MITIGATED_AT);
- device.setCurrentDevice(true);
-
- CastleUserDeviceContext deviceContext = new CastleUserDeviceContext();
- deviceContext.setIp(DeviceUtils.CONTEXT_IP);
- deviceContext.setType(DeviceUtils.CONTEXT_TYPE);
-
- DeviceUserAgent userAgent = new DeviceUserAgent();
- userAgent.setBrowser(DeviceUtils.USER_AGENT_BROWSER);
- userAgent.setDevice(DeviceUtils.USER_AGENT_DEVICE);
- userAgent.setFamily(DeviceUtils.USER_AGENT_FAMILY);
- userAgent.setMobile(DeviceUtils.USER_AGENT_MOBILE);
- userAgent.setOs(DeviceUtils.USER_AGENT_OS);
- userAgent.setPlatform(DeviceUtils.USER_AGENT_PLATFORM);
- userAgent.setRaw(DeviceUtils.USER_AGENT_RAW);
- userAgent.setVersion(DeviceUtils.USER_AGENT_VERSION);
- deviceContext.setUserAgent(userAgent);
-
- device.setContext(deviceContext);
-
- devicesList.add(device);
-
- devices.setDevices(devicesList);
-
- // When
- String payloadJson = model.getGson().toJson(devices);
- String expected = "{\"total_count\":1,\"data\":[{\"token\":\"abcdefg12345\",\"risk\":0.0,\"created_at\":\"2018-06-15T16:36:22.916Z\",\"last_seen_at\":\"2018-07-19T23:09:29.681Z\",\"context\":{\"ip\":\"1.1.1.1\",\"user_agent\":{\"raw\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51\",\"browser\":\"Opera\",\"version\":\"54.0.2952\",\"os\":\"Mac OS X 10.13.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Unknown\",\"family\":\"Opera\"},\"type\":\"desktop\"},\"is_current_device\":true}]}";
-
- // Then
- Assertions.assertThat(JsonParser.parseString(payloadJson)).isEqualTo(JsonParser.parseString(expected));
-
- Assert.assertEquals(devices.getTotalCount(), devicesList.size());
- Assert.assertEquals(devices.getDevices(), devicesList);
-
- devices.setDevices(null);
- Assert.assertEquals(0, devices.getTotalCount());
- }
-}
diff --git a/src/test/java/io/castle/client/utils/DeviceUtils.java b/src/test/java/io/castle/client/utils/DeviceUtils.java
index b1692e68..693be728 100644
--- a/src/test/java/io/castle/client/utils/DeviceUtils.java
+++ b/src/test/java/io/castle/client/utils/DeviceUtils.java
@@ -1,12 +1,5 @@
package io.castle.client.utils;
-import io.castle.client.model.CastleUserDevice;
-import io.castle.client.model.CastleUserDeviceContext;
-import io.castle.client.model.CastleUserDevices;
-import io.castle.client.model.DeviceUserAgent;
-
-import java.util.Collections;
-
public class DeviceUtils {
public static final String DEVICE_TOKEN = "abcdefg12345";
@@ -28,45 +21,4 @@ public class DeviceUtils {
public static final String USER_AGENT_BROWSER = "Opera";
public static final String USER_AGENT_RAW = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51";
public static final boolean USER_AGENT_MOBILE = false;
-
- public static CastleUserDevice createExpectedDevice() {
- CastleUserDevice device = new CastleUserDevice();
- device.setToken(DEVICE_TOKEN);
- device.setRisk(DEVICE_RISK);
- device.setCreatedAt(DEVICE_CREATED_AT);
- device.setLastSeenAt(DEVICE_LAST_SEEN_AT);
- device.setApprovedAt(null);
- device.setEscalatedAt(null);
- device.setMitigatedAt(null);
-
- CastleUserDeviceContext deviceContext = new CastleUserDeviceContext();
- deviceContext.setIp(CONTEXT_IP);
- deviceContext.setType(CONTEXT_TYPE);
-
- DeviceUserAgent userAgent = new DeviceUserAgent();
- userAgent.setFamily(USER_AGENT_FAMILY);
- userAgent.setDevice(USER_AGENT_DEVICE);
- userAgent.setPlatform(USER_AGENT_PLATFORM);
- userAgent.setOs(USER_AGENT_OS);
- userAgent.setVersion(USER_AGENT_VERSION);
- userAgent.setBrowser(USER_AGENT_BROWSER);
- userAgent.setRaw(USER_AGENT_RAW);
- userAgent.setMobile(USER_AGENT_MOBILE);
-
- deviceContext.setUserAgent(userAgent);
-
- device.setContext(deviceContext);
-
- return device;
- }
-
- public static CastleUserDevices createExpectedDevices() {
- CastleUserDevices devices = new CastleUserDevices();
- devices.setDevices(Collections.singletonList(createExpectedDevice()));
- return devices;
- }
-
- public static String getDefaultDeviceJSON() {
- return "{\"token\":\"abcdefg12345\",\"risk\":0.000154,\"created_at\":\"2018-06-15T16:36:22.916Z\",\"last_seen_at\":\"2018-07-19T23:09:29.681Z\",\"approved_at\":null,\"escalated_at\":null,\"mitigated_at\":null,\"context\":{\"ip\":\"1.1.1.1\",\"location\":{\"country_code\":\"US\",\"country\":\"United States\",\"region\":\"New Jersey\",\"region_code\":\"NJ\",\"city\":\"Lyndhurst\",\"lat\":40.7923,\"lon\":-74.1001},\"user_agent\":{\"raw\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51\",\"browser\":\"Opera\",\"version\":\"54.0.2952\",\"os\":\"Mac OS X 10.13.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Unknown\",\"family\":\"Opera\"},\"type\":\"desktop\"}}";
- }
}
diff --git a/src/test/resources/castle_sdk.properties b/src/test/resources/castle_sdk.properties
index c22bb141..2b8d1b56 100644
--- a/src/test/resources/castle_sdk.properties
+++ b/src/test/resources/castle_sdk.properties
@@ -4,5 +4,4 @@ allow_list=TestAllow,User-Agent,Accept-Language,Accept-Encoding,Accept-Charset,A
deny_list=TestDeny,Cookie
timeout=100
backend_provider=OKHTTP
-failover_strategy=CHALLENGE
base_url=https://testing.api.dev.castle/v1/