io.castle.client.internal.backend.OkRestApiBackend Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of castle-java Show documentation
Show all versions of castle-java Show documentation
Castle adds real-time monitoring of your authentication stack, instantly notifying you and your users
on potential account hijacks.
package io.castle.client.internal.backend;
import com.google.common.collect.ImmutableMap;
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.*;
import java.io.IOException;
public class OkRestApiBackend implements RestApi {
public static final String METHOD_DELETE = "DELETE";
public static final String METHOD_POST = "POST";
public static final String METHOD_PUT = "PUT";
public static final String METHOD_GET = "GET";
private final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private final OkHttpClient client;
private final CastleGsonModel model;
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, json.toString());
}
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();
JsonParser jsonParser = model.getJsonParser();
VerdictTransportModel transport = gson.fromJson(jsonResponse, VerdictTransportModel.class);
if (transport != null && transport.getAction() != null) {
return VerdictBuilder.fromTransport(transport, jsonParser.parse(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);
}
@Override
public CastleResponse put(String path) {
return makeRequest(path, null, METHOD_PUT);
}
@Override
public CastleResponse put(String path, ImmutableMap
© 2015 - 2025 Weber Informatics LLC | Privacy Policy