All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.castle.client.internal.config.CastleConfigurationBuilder Maven / Gradle / Ivy

Go to download

Castle adds real-time monitoring of your authentication stack, instantly notifying you and your users on potential account hijacks.

There is a newer version: 2.4.2
Show newest version
package io.castle.client.internal.config;

import com.google.common.base.Joiner;
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;
import java.util.List;

/**
 * Allows to programmatically create and validate a castleConfiguration through a DSL.
 * 

* CastleConfigurationBuilder has methods for creating a castleConfiguration instance from scratch. * Furthermore, there are also methods for creating a configuration from sensible default values. * The fields that can be set in a CastleConfiguration: *

    *
  • timeout *
  • failoverStrategy *
  • whiteListHeaders *
  • blackListHeaders *
  • apiSecret *
  • castleAppId *
  • backendProvider *
* The {@code build} method provides a layer of validation. * It will throw a {@link CastleSdkConfigurationException} if one of the fields is left unset. * {@code apiSecret} and {@code castleAppId} do not have defaults. * A value for the Api Secret should be provided before calling {@code build}. *

How to use Whitelist and Blacklist

* When {@link io.castle.client.Castle#onRequest} is called, whitelisted headers and blacklisted headers are checked. * Headers are only passed to the context if they are in the whitelist, but not in the blacklist. * That is, if a header is in both lists, the blacklisted value takes precedence, and the header is not passed to the * context object. */ public class CastleConfigurationBuilder { /** * Represents the milliseconds after which a request fails. */ 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 blacklisted. */ private List whiteListHeaders; /** * Strings representing headers that should never be passed to the context object. */ private List blackListHeaders; /** * String represented the API secret associated with a Castle account. */ private String apiSecret; /** * String representing an AppID associated with a Castle account. */ private String castleAppId; /** * The HTTP layer chosen to make requests. */ private CastleBackendProvider backendProvider = CastleBackendProvider.OKHTTP; //Unique available backend on the current version /** * Base URL of the API calls. Used for tests, on productions use the default value. */ private String apiBaseUrl; /** * Flag to enable logging of backend HTTP requests. */ private boolean logHttpRequests = false; private CastleConfigurationBuilder() { } /** * Provides a castleConfigurationBuilder with the default values set for all of CastleConfiguration's fields but * apiSecret and castleAppId. *

* Values for {@link CastleConfiguration#apiSecret} and {@link CastleConfiguration#castleAppId} must be provided * before calling {@code build}. * These two fields do not have default values. * * @return a castleConfigurationBuilder with all settings set to the default values, when there exist defaults */ public static CastleConfigurationBuilder defaultConfigBuilder() { CastleConfigurationBuilder builder = new CastleConfigurationBuilder() .withDefaultWhitelist() .withDefaultBlacklist() .withDefaultApiBaseUrl() .withTimeout(500) .withDefaultAuthenticateFailoverStrategy() .withDefaultBackendProvider(); return builder; } /** * Provides a fresh castleConfigurationBuilder. *

* The only default value provided is the timeout, which is set to 500 milliseconds. * * @return a castleConfigurationBuilder with all values set to null, except timeout */ public static CastleConfigurationBuilder aConfigBuilder() { return new CastleConfigurationBuilder(); } /** * Sets the default list of whitelisted headers. *

* The following are the default values: *

    *
  • {@code User-Agent} *
  • {@code Accept-Language} *
  • {@code Accept-Encoding} *
  • {@code Accept-Charset} *
  • {@code Accept} *
  • {@code Accept-Datetime} *
  • {@code X-Forwarded-For} *
  • {@code Forwarded} *
  • {@code X-Forwarded} *
  • {@code X-Real-IP} *
  • {@code REMOTE_ADDR} *
* * @return a castleConfigurationBuilder instance with the default list of whitelisted headers. */ public CastleConfigurationBuilder withDefaultWhitelist() { this.whiteListHeaders = new LinkedList<>(); whiteListHeaders.add("User-Agent"); whiteListHeaders.add("Accept-Language"); whiteListHeaders.add("Accept-Encoding"); whiteListHeaders.add("Accept-Charset"); whiteListHeaders.add("Accept"); whiteListHeaders.add("Accept-Datetime"); whiteListHeaders.add("X-Forwarded-For"); whiteListHeaders.add("Forwarded"); whiteListHeaders.add("X-Forwarded"); whiteListHeaders.add("X-Real-IP"); whiteListHeaders.add("REMOTE_ADDR"); return this; } /** * Sets the default list of blacklisted headers. *

* The default value is a list whose single element is the {@code Cookie} header. * * @return a castleConfigurationBuilder instance with the default list of blacklisted headers */ public CastleConfigurationBuilder withDefaultBlacklist() { this.blackListHeaders = new LinkedList<>(); this.blackListHeaders.add("Cookie"); return this; } /** * Sets the timeout in milliseconds for a request. * * @param timeout milliseconds after which a request times out * @return a castleConfigurationBuilder with a timeout set to a new value */ public CastleConfigurationBuilder withTimeout(int timeout) { this.timeout = 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. *

* The default value is {@code https://api.castle.io/}. * @return a castleConfigurationBuilder with the default value for the Castle API endpoint */ public CastleConfigurationBuilder withDefaultApiBaseUrl() { return this.withApiBaseUrl("https://api.castle.io/"); } /** * Sets the OkHttp backend for all API calls. * * @return a castleConfigurationBuilder with the backend set to okHttp */ public CastleConfigurationBuilder withDefaultBackendProvider() { return this.withBackendProvider(CastleBackendProvider.OKHTTP); } /** * Whitelists a list of strings representing headers that will be passed to the context object from an * {@code HttpServletRequest}. * * @param whitelistedHeaders a list of strings representing headers; case insensitive, not null. * @return a castleConfigurationBuilder with a whitelist of headers for building context objects */ public CastleConfigurationBuilder withWhiteListHeaders(List whitelistedHeaders) { this.whiteListHeaders = whitelistedHeaders; return this; } /** * Whitelists a a comma separated list of string parameters representing headers that will be passed to the context * object from an {@code HttpServletRequest}. * * @param whitelistedHeaders a comma separated list of string parameters representing headers; case insensitive, not * null. * @return a castleConfigurationBuilder with a whitelist of headers for building context objects */ public CastleConfigurationBuilder withWhiteListHeaders(String... whitelistedHeaders) { return withWhiteListHeaders(ImmutableList.copyOf(whitelistedHeaders)); } /** * Blacklists a a comma separated list of string parameters representing headers that will be passed to the context * object from an {@code HttpServletRequest}. * * @param blacklistedHeaders a comma separated list of string parameters representing headers; case insensitive, not * null. * @return a castleConfigurationBuilder with a blacklist of headers for building context objects */ public CastleConfigurationBuilder withBlackListHeaders(String... blacklistedHeaders) { return withBlackListHeaders(ImmutableList.copyOf(blacklistedHeaders)); } /** * Blacklists a list of strings representing headers that will be passed to the context object from an * {@code HttpServletRequest}. * * @param blacklistedHeaders a list of strings representing headers; case insensitive, not null. * @return a castleConfigurationBuilder with a blacklist of headers for building context objects */ public CastleConfigurationBuilder withBlackListHeaders(List blacklistedHeaders) { this.blackListHeaders = blacklistedHeaders; return this; } /** * A string with the API secret associated with a valid Castle account. * * @param apiSecret the API secret of the account calling the Castle API * @return a castleConfigurationBuilder with the API secret set */ public CastleConfigurationBuilder withApiSecret(String apiSecret) { this.apiSecret = apiSecret; return this; } /** * Validates and returns a configuration object, if all required fields have the required values, or an exception * otherwise. *

* Validation consists in checking that no field in the configuration is set tu null. * Furthermore, the build method also makes sure that the API secret is not an empty string. * An additional layer of validation is given further along the line by {@link HeaderNormalizer}, which will ensure * that the provided list of strings can contain both, upper and lower case letters. * This method will not detect wrong headers, API secrets or APP ID's. * * @return a castleConfiguration with all fields set to some meaningful value * @throws CastleSdkConfigurationException if at least one of castleAppId, apiSecret, whiteListHeaders, * blackListHeaders, failoverStrategy, backendProvider is not provided * during the building stage of the * CastleConfiguration instance. */ public CastleConfiguration build() throws CastleSdkConfigurationException { ImmutableList.Builder builder = ImmutableList.builder(); if (apiSecret == null || apiSecret.isEmpty()) { builder.add("The apiSecret for the castleSDK must be provided in the configuration. Read documentation " + "for further details."); } if (whiteListHeaders == null) { builder.add("A whitelist of headers must be provided. If not sure, then use the default values provided " + "by method withDefaultWhitelist. Read documentation for further details."); } if (blackListHeaders == null) { builder.add("A blacklist of headers must be provided. If not sure, then use the default values provided " + "by method withDefaultBlacklist. 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."); } if (apiBaseUrl == null) { builder.add("A apiBaseUrl value must be selected. If not sure, then use the default values provided by method withDefaultApiBaseUrl. Read documentation for further details."); } ImmutableList errorMessages = builder.build(); if (!errorMessages.isEmpty()) { throw new CastleSdkConfigurationException(Joiner.on(System.lineSeparator()).join(errorMessages)); } HeaderNormalizer normalizer = new HeaderNormalizer(); return new CastleConfiguration(apiBaseUrl, timeout, failoverStrategy, normalizer.normalizeList(whiteListHeaders), normalizer.normalizeList(blackListHeaders), apiSecret, castleAppId, backendProvider, logHttpRequests); } /** * Sets a String representing an AppID associated with a Castle account. * * @param castleAppId the AppID for that will be used to make calls to the Castle API * @return a castleConfigurationBuilder with the AppID set */ public CastleConfigurationBuilder withCastleAppId(String castleAppId) { this.castleAppId = castleAppId; return this; } /** * Sets the HTTP layer that will be used for making calls to the Castle REST API. * * @param backendProvider an available backend provider * @return a castleConfigurationBuilder with the chosen backend provider set */ public CastleConfigurationBuilder withBackendProvider(CastleBackendProvider backendProvider) { this.backendProvider = backendProvider; return this; } /** * Sets the endpoint of the Castle API. * * @param apiBaseUrl a string representing the URL of the Castle API endpoint without any relative path * @return a castleConfigurationBuilder with the default value for the Castle API endpoint */ public CastleConfigurationBuilder withApiBaseUrl(String apiBaseUrl) { this.apiBaseUrl = apiBaseUrl; return this; } /** * Flag to enable logging on backend HTTP requests. * * @param logHttpRequests boolean to switch logging on or off. * @return a castleConfigurationBuilder with logging setup set */ public CastleConfigurationBuilder withLogHttpRequests(Boolean logHttpRequests) { this.logHttpRequests = logHttpRequests; return this; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy