issue #11 - Refactor CfDnsClient with a simplified CfDnsClientBuilder for authentication and configuration. Update tests and README for new builder. Added authtification with apiToken
This commit is contained in:
@@ -29,7 +29,7 @@ This guide comes without any warranty. Use at your own risk. The author is not r
|
|||||||
|
|
||||||
The project has its own maven repository. It can be added to the `pom.xml`:
|
The project has its own maven repository. It can be added to the `pom.xml`:
|
||||||
|
|
||||||
```xml
|
```xml<p>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>gitlab-cloudflare</id>
|
<id>gitlab-cloudflare</id>
|
||||||
@@ -51,13 +51,13 @@ The dependency is:
|
|||||||
|
|
||||||
- 0.2.0:
|
- 0.2.0:
|
||||||
- de-lombok the source jar
|
- de-lombok the source jar
|
||||||
- **New Fluent API**: Added chainable method interface for more readable DNS operations (
|
|
||||||
`client.zone().record()...`)
|
|
||||||
- **Breaking Change**: `emptyResultThrowsException` default changed from `true` to `false`. Now applies to both
|
- **Breaking Change**: `emptyResultThrowsException` default changed from `true` to `false`. Now applies to both
|
||||||
single and multiple result requests. Empty results will be returned by default without throwing exceptions.
|
single and multiple result requests. Empty results will be returned by default without throwing exceptions.
|
||||||
- API method names refactored for consistency: `zoneListAll` → `zoneList`, `zoneInfo` → `zoneGet`, `sldListAll` →
|
- API method names refactored for consistency: `zoneListAll` → `zoneList`, `zoneInfo` → `zoneGet`, `sldListAll` →
|
||||||
`recordList`
|
`recordList`
|
||||||
- RecordEntity getter methods renamed for clarity: `getName()` → `getSld()`
|
- RecordEntity getter methods renamed for clarity: `getName()` → `getSld()`
|
||||||
|
- **New Fluent API**: Changed the initialization of the client(`new CfDnsClientBuilder().withApiTokenAuth("your-api-token").build()`) and added chainable method interface for more readable DNS operations (
|
||||||
|
`client.zone().record()...`)
|
||||||
- Code quality improvements: eliminated duplication in batch operations, improved type safety in HTTP methods,
|
- Code quality improvements: eliminated duplication in batch operations, improved type safety in HTTP methods,
|
||||||
optimized string concatenation, removed mutable setters from CfDnsClient
|
optimized string concatenation, removed mutable setters from CfDnsClient
|
||||||
- Enhanced type validation in `RecordEntity.build()` with better error messages
|
- Enhanced type validation in `RecordEntity.build()` with better error messages
|
||||||
@@ -89,10 +89,18 @@ the [javadoc of the CfDnsClient](https://cloudflaredns-java-f4ee3a.gitlab.io/api
|
|||||||
|
|
||||||
### Instantiation of `CfDnsClient`
|
### Instantiation of `CfDnsClient`
|
||||||
|
|
||||||
|
#### With API Token (recommended):
|
||||||
```java
|
```java
|
||||||
CfDnsClient cfDnsClient = new CfDnsClient(
|
CfDnsClient cfDnsClient = new CfDnsClientBuilder()
|
||||||
"email@example.com", "yourApiKey"
|
.withApiTokenAuth("your-api-token")
|
||||||
);
|
.build();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### With Email/Key (legacy):
|
||||||
|
```java
|
||||||
|
CfDnsClient cfDnsClient = new CfDnsClientBuilder()
|
||||||
|
.withEmailKeyAuth("email@example.com", "yourApiKey")
|
||||||
|
.build();
|
||||||
```
|
```
|
||||||
|
|
||||||
### `zoneList`
|
### `zoneList`
|
||||||
@@ -390,7 +398,9 @@ client.zone("example.com")
|
|||||||
### Complete Example
|
### Complete Example
|
||||||
|
|
||||||
```java
|
```java
|
||||||
CfDnsClient client = new CfDnsClient("email@example.com", "yourApiKey");
|
CfDnsClient client = new CfDnsClientBuilder()
|
||||||
|
.withApiTokenAuth("your-api-token")
|
||||||
|
.build();
|
||||||
|
|
||||||
// Create a new record
|
// Create a new record
|
||||||
client.zone("example.com")
|
client.zone("example.com")
|
||||||
@@ -425,7 +435,10 @@ The `CfDnsClient` provides internal error-handling mechanisms through exceptions
|
|||||||
To enable exception throwing for empty results:
|
To enable exception throwing for empty results:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
CfDnsClient client = new CfDnsClient(true, "email@example.com", "yourApiKey");
|
CfDnsClient client = new CfDnsClientBuilder()
|
||||||
|
.withApiTokenAuth("your-api-token")
|
||||||
|
.withEmptyResultThrowsException(true)
|
||||||
|
.build();
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example:
|
## Example:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package codes.thischwa.cf;
|
package codes.thischwa.cf;
|
||||||
|
|
||||||
import codes.thischwa.cf.auth.CfAuth;
|
|
||||||
import codes.thischwa.cf.model.AbstractResponse;
|
import codes.thischwa.cf.model.AbstractResponse;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
@@ -31,7 +30,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
abstract class CfBasicHttpClient {
|
abstract class CfBasicHttpClient {
|
||||||
|
|
||||||
private final String baseUrl;
|
private final String baseUrl;
|
||||||
private final CfAuth auth;
|
private final CfDnsClientBuilder.CfAuth auth;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +39,7 @@ abstract class CfBasicHttpClient {
|
|||||||
* @param baseUrl the base URL for the Cloudflare API
|
* @param baseUrl the base URL for the Cloudflare API
|
||||||
* @param auth the authentication mechanism to use
|
* @param auth the authentication mechanism to use
|
||||||
*/
|
*/
|
||||||
CfBasicHttpClient(@NotNull String baseUrl, @NotNull CfAuth auth) {
|
CfBasicHttpClient(@NotNull String baseUrl, @NotNull CfDnsClientBuilder.CfAuth auth) {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.objectMapper = JsonConf.initObjectMapper();
|
this.objectMapper = JsonConf.initObjectMapper();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package codes.thischwa.cf;
|
package codes.thischwa.cf;
|
||||||
|
|
||||||
import codes.thischwa.cf.auth.CfAuth;
|
|
||||||
import codes.thischwa.cf.fluent.ZoneOperations;
|
import codes.thischwa.cf.fluent.ZoneOperations;
|
||||||
import codes.thischwa.cf.fluent.ZoneOperationsImpl;
|
import codes.thischwa.cf.fluent.ZoneOperationsImpl;
|
||||||
import codes.thischwa.cf.model.AbstractResponse;
|
import codes.thischwa.cf.model.AbstractResponse;
|
||||||
@@ -30,7 +29,9 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
* <p>Example with API token authentication (recommended):
|
* <p>Example with API token authentication (recommended):
|
||||||
* <pre><code>
|
* <pre><code>
|
||||||
* // Create a new CfDnsClient instance with API token
|
* // Create a new CfDnsClient instance with API token
|
||||||
* CfDnsClient cfDnsClient = new CfDnsClient(CfAuthBuilder.build("your-api-token"));
|
* CfDnsClient cfDnsClient = new CfDnsClientBuilder()
|
||||||
|
* .withApiTokenAuth("your-api-token")
|
||||||
|
* .build();
|
||||||
*
|
*
|
||||||
* // Retrieve a zone
|
* // Retrieve a zone
|
||||||
* ZoneEntity zone = cfDnsClient.zoneGet("example.com");
|
* ZoneEntity zone = cfDnsClient.zoneGet("example.com");
|
||||||
@@ -49,63 +50,35 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
*
|
*
|
||||||
* <p>Example with email/key authentication (legacy):
|
* <p>Example with email/key authentication (legacy):
|
||||||
* <pre><code>
|
* <pre><code>
|
||||||
* CfDnsClient cfDnsClient = new CfDnsClient(
|
* CfDnsClient cfDnsClient = new CfDnsClientBuilder()
|
||||||
* CfAuthBuilder.build("email@example.com", "your-api-key")
|
* .withEmailKeyAuth("email@example.com", "your-api-key")
|
||||||
* );
|
* .build();
|
||||||
* </code></pre>
|
* </code></pre>
|
||||||
*
|
*
|
||||||
* <p>Example with exception throwing enabled:
|
* <p>Example with exception throwing enabled:
|
||||||
* <pre><code>
|
* <pre><code>
|
||||||
* // Throws exception when results are empty
|
* // Throws exception when results are empty
|
||||||
* CfDnsClient cfDnsClient = new CfDnsClient(true, CfAuthBuilder.build("your-api-token"));
|
* CfDnsClient cfDnsClient = new CfDnsClientBuilder()
|
||||||
|
* .withApiTokenAuth("your-api-token")
|
||||||
|
* .withEmptyResultThrowsException(true)
|
||||||
|
* .build();
|
||||||
* </code></pre>
|
* </code></pre>
|
||||||
*
|
*
|
||||||
* <p>Example with custom base URL:
|
* <p>Example with custom base URL:
|
||||||
* <pre><code>
|
* <pre><code>
|
||||||
* CfAuth auth = CfAuthBuilder.build("your-api-token");
|
* CfDnsClient cfDnsClient = new CfDnsClientBuilder()
|
||||||
* auth.setBaseUrl("https://custom-api.example.com");
|
* .withApiTokenAuth("your-api-token")
|
||||||
* CfDnsClient cfDnsClient = new CfDnsClient(auth);
|
* .withBaseUrl("https://custom-api.example.com")
|
||||||
|
* .build();
|
||||||
* </code></pre>
|
* </code></pre>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CfDnsClient extends CfBasicHttpClient {
|
public class CfDnsClient extends CfBasicHttpClient {
|
||||||
|
|
||||||
public static final String DEFAULT_BASEURL = "https://api.cloudflare.com/client/v4";
|
|
||||||
private final ResponseValidator responseValidator;
|
private final ResponseValidator responseValidator;
|
||||||
|
|
||||||
private final boolean emptyResultThrowsException;
|
private final boolean emptyResultThrowsException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new instance of {@code CfDnsClient} with default configuration.
|
|
||||||
*
|
|
||||||
* @param auth The authentication mechanism to use (ApiTokenAuth or EmailKeyAuth)
|
|
||||||
*/
|
|
||||||
public CfDnsClient(CfAuth auth) {
|
|
||||||
this(false, DEFAULT_BASEURL, auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new instance of {@code CfDnsClient}.
|
|
||||||
*
|
|
||||||
* @param baseUrl The base URL of the Cloudflare API to be used for requests.
|
|
||||||
* @param auth The authentication mechanism to use (ApiTokenAuth or EmailKeyAuth)
|
|
||||||
*/
|
|
||||||
public CfDnsClient(String baseUrl, CfAuth auth) {
|
|
||||||
this(false, baseUrl, auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new instance of {@code CfDnsClient}.
|
|
||||||
*
|
|
||||||
* @param emptyResultThrowsException A boolean value indicating whether an exception should be
|
|
||||||
* thrown when the result is empty. Applies to both single and
|
|
||||||
* multiple result requests. Default is false.
|
|
||||||
* @param auth The authentication mechanism to use (ApiTokenAuth or EmailKeyAuth)
|
|
||||||
*/
|
|
||||||
public CfDnsClient(boolean emptyResultThrowsException, CfAuth auth) {
|
|
||||||
this(emptyResultThrowsException, DEFAULT_BASEURL, auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance of {@code CfDnsClient}.
|
* Constructs a new instance of {@code CfDnsClient}.
|
||||||
*
|
*
|
||||||
@@ -115,7 +88,7 @@ public class CfDnsClient extends CfBasicHttpClient {
|
|||||||
* @param baseUrl The base URL for the Cloudflare API endpoint.
|
* @param baseUrl The base URL for the Cloudflare API endpoint.
|
||||||
* @param auth The authentication mechanism to use (ApiTokenAuth or EmailKeyAuth)
|
* @param auth The authentication mechanism to use (ApiTokenAuth or EmailKeyAuth)
|
||||||
*/
|
*/
|
||||||
public CfDnsClient(boolean emptyResultThrowsException, String baseUrl, CfAuth auth) {
|
CfDnsClient(boolean emptyResultThrowsException, String baseUrl, CfDnsClientBuilder.CfAuth auth) {
|
||||||
super(baseUrl, auth);
|
super(baseUrl, auth);
|
||||||
this.responseValidator = new ResponseValidator(emptyResultThrowsException);
|
this.responseValidator = new ResponseValidator(emptyResultThrowsException);
|
||||||
this.emptyResultThrowsException = emptyResultThrowsException;
|
this.emptyResultThrowsException = emptyResultThrowsException;
|
||||||
@@ -514,4 +487,5 @@ public class CfDnsClient extends CfBasicHttpClient {
|
|||||||
throws CloudflareApiException {
|
throws CloudflareApiException {
|
||||||
responseValidator.validate(resp, singleResultExpected);
|
responseValidator.validate(resp, singleResultExpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
package codes.thischwa.cf;
|
||||||
|
|
||||||
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder class for configuring and creating instances of {@link CfDnsClient}.
|
||||||
|
* This class provides a fluent API for customizing the client settings,
|
||||||
|
* such as the base URL and authentication mechanism.
|
||||||
|
*/
|
||||||
|
public class CfDnsClientBuilder {
|
||||||
|
|
||||||
|
public static final String DEFAULT_BASEURL = "https://api.cloudflare.com/client/v4";
|
||||||
|
private boolean emptyResultThrowsException;
|
||||||
|
private CfAuth auth;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of `CfDnsClientBuilder`.
|
||||||
|
*
|
||||||
|
* <p>This class serves as a builder for creating and configuring instances of a CfDnsClient. It provides
|
||||||
|
* a fluent API to set various optional configurations, such as API authentication methods and base
|
||||||
|
* URL, before constructing the client.
|
||||||
|
*
|
||||||
|
* <p>By using this constructor, you can initiate the building process with default settings, which can
|
||||||
|
* later be overridden using the provided builder methods.
|
||||||
|
*/
|
||||||
|
public CfDnsClientBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures whether an exception should be thrown when an empty result is encountered
|
||||||
|
* during operations performed by the `CfDnsClient`.
|
||||||
|
*
|
||||||
|
* @param emptyResultThrowsException a boolean flag indicating if an exception should be thrown
|
||||||
|
* when an empty result is returned. If set to `true`, operations
|
||||||
|
* that result in an empty response will throw an exception;
|
||||||
|
* otherwise, they will not.
|
||||||
|
* @return the current instance of {@code CfDnsClientBuilder}, allowing for method chaining
|
||||||
|
* to further configure the builder.
|
||||||
|
*/
|
||||||
|
public CfDnsClientBuilder withEmptyResultThrowsException(boolean emptyResultThrowsException) {
|
||||||
|
this.emptyResultThrowsException = emptyResultThrowsException;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the base URL to be used by the {@code CfDnsClient}.
|
||||||
|
* This method allows configuring the base URL for API requests, overriding any default value.
|
||||||
|
*
|
||||||
|
* @param baseUrl the base URL to be used for API requests
|
||||||
|
* @return the current instance of {@code CfDnsClientBuilder}, enabling method chaining
|
||||||
|
*/
|
||||||
|
public CfDnsClientBuilder withBaseUrl(String baseUrl) {
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the authentication method for the {@code CfDnsClient} to use an API token.
|
||||||
|
* This is the recommended way to authenticate with the Cloudflare API, as it provides
|
||||||
|
* enhanced security and ease of use compared to other authentication mechanisms.
|
||||||
|
*
|
||||||
|
* @param apiToken the Cloudflare API token. This token is required for authenticating
|
||||||
|
* API requests and must not be null or blank.
|
||||||
|
* @return the current instance of {@code CfDnsClientBuilder}, allowing for method chaining
|
||||||
|
* to further configure the builder.
|
||||||
|
* @throws IllegalArgumentException if the {@code apiToken} is null or blank.
|
||||||
|
*/
|
||||||
|
public CfDnsClientBuilder withApiTokenAuth(String apiToken) {
|
||||||
|
this.auth = new ApiTokenAuth(apiToken);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the authentication method for the {@code CfDnsClient} to use an email and API key.
|
||||||
|
* This approach uses the legacy authentication mechanism provided by Cloudflare, where requests
|
||||||
|
* are authenticated with a combination of an account's email address and API key.
|
||||||
|
*
|
||||||
|
* @param authEmail the email address associated with the Cloudflare account. This must not be null or blank.
|
||||||
|
* @param authKey the API key of the Cloudflare account. This must not be null or blank.
|
||||||
|
* @return the current instance of {@code CfDnsClientBuilder}, allowing for method chaining
|
||||||
|
* to further configure the builder.
|
||||||
|
* @throws IllegalArgumentException if {@code authEmail} or {@code authKey} is null or blank.
|
||||||
|
*/
|
||||||
|
public CfDnsClientBuilder withEmailKeyAuth(String authEmail, String authKey) {
|
||||||
|
this.auth = new EmailKeyAuth(authEmail, authKey);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and returns a configured instance of {@code CfDnsClient}.
|
||||||
|
*
|
||||||
|
* <p>The method constructs a new {@code CfDnsClient} object based on the
|
||||||
|
* options set in the {@code CfDnsClientBuilder}. If no base URL has been
|
||||||
|
* explicitly configured, a default base URL will be used.
|
||||||
|
*
|
||||||
|
* @return a new instance of {@code CfDnsClient} configured with the
|
||||||
|
* specified options such as base URL, authentication details,
|
||||||
|
* and the exception-handling policy for empty results.
|
||||||
|
*/
|
||||||
|
public CfDnsClient build() {
|
||||||
|
String url = baseUrl == null ? DEFAULT_BASEURL : baseUrl;
|
||||||
|
return new CfDnsClient(emptyResultThrowsException, url, auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for Cloudflare authentication mechanisms.
|
||||||
|
* Implementations of this interface provide different methods of authentication
|
||||||
|
* with the Cloudflare API (e.g., API token, email/key combination).
|
||||||
|
*/
|
||||||
|
interface CfAuth {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies authentication headers to the given HTTP request.
|
||||||
|
*
|
||||||
|
* @param request the HTTP request to authenticate
|
||||||
|
*/
|
||||||
|
void applyAuth(ClassicHttpRequest request);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication mechanism using Cloudflare API token.
|
||||||
|
* This is the recommended authentication method for the Cloudflare API.
|
||||||
|
*/
|
||||||
|
static class ApiTokenAuth implements CfAuth {
|
||||||
|
|
||||||
|
private final String apiToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new API token authentication object.
|
||||||
|
*
|
||||||
|
* @param apiToken the Cloudflare API token
|
||||||
|
* @throws IllegalArgumentException if the API token is null or blank
|
||||||
|
*/
|
||||||
|
ApiTokenAuth(@NotNull String apiToken) {
|
||||||
|
if (apiToken.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("API token must not be null or blank!");
|
||||||
|
}
|
||||||
|
this.apiToken = apiToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyAuth(ClassicHttpRequest request) {
|
||||||
|
request.addHeader("Authorization", "Bearer " + apiToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication mechanism using Cloudflare account email and API key.
|
||||||
|
* This is the legacy authentication method for the Cloudflare API.
|
||||||
|
*/
|
||||||
|
static class EmailKeyAuth implements CfAuth {
|
||||||
|
|
||||||
|
private final String authEmail;
|
||||||
|
private final String authKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new email/key authentication object.
|
||||||
|
*
|
||||||
|
* @param authEmail the email address associated with the Cloudflare account
|
||||||
|
* @param authKey the API key of the Cloudflare account
|
||||||
|
* @throws IllegalArgumentException if email or key is null or blank
|
||||||
|
*/
|
||||||
|
EmailKeyAuth(@NotNull String authEmail, @NotNull String authKey) {
|
||||||
|
if (authEmail.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("Authentication email must not be null or blank!");
|
||||||
|
}
|
||||||
|
if (authKey.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("Authentication key must not be null or blank!");
|
||||||
|
}
|
||||||
|
this.authEmail = authEmail;
|
||||||
|
this.authKey = authKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyAuth(ClassicHttpRequest request) {
|
||||||
|
request.addHeader("X-Auth-Email", authEmail);
|
||||||
|
request.addHeader("X-Auth-Key", authKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package codes.thischwa.cf.auth;
|
|
||||||
|
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authentication mechanism using Cloudflare API token.
|
|
||||||
* This is the recommended authentication method for the Cloudflare API.
|
|
||||||
*/
|
|
||||||
public class ApiTokenAuth implements CfAuth {
|
|
||||||
|
|
||||||
private final String apiToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new API token authentication object.
|
|
||||||
*
|
|
||||||
* @param apiToken the Cloudflare API token
|
|
||||||
* @throws IllegalArgumentException if the API token is null or blank
|
|
||||||
*/
|
|
||||||
public ApiTokenAuth(@NotNull String apiToken) {
|
|
||||||
if (apiToken.isBlank()) {
|
|
||||||
throw new IllegalArgumentException("API token must not be null or blank!");
|
|
||||||
}
|
|
||||||
this.apiToken = apiToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyAuth(ClassicHttpRequest request) {
|
|
||||||
request.addHeader("Authorization", "Bearer " + apiToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package codes.thischwa.cf.auth;
|
|
||||||
|
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for Cloudflare authentication mechanisms.
|
|
||||||
* Implementations of this interface provide different methods of authentication
|
|
||||||
* with the Cloudflare API (e.g., API token, email/key combination).
|
|
||||||
*/
|
|
||||||
public interface CfAuth {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies authentication headers to the given HTTP request.
|
|
||||||
*
|
|
||||||
* @param request the HTTP request to authenticate
|
|
||||||
*/
|
|
||||||
void applyAuth(ClassicHttpRequest request);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package codes.thischwa.cf.auth;
|
|
||||||
|
|
||||||
public class CfAuthBuilder {
|
|
||||||
|
|
||||||
public static ApiTokenAuth build(String apiToken) {
|
|
||||||
return new ApiTokenAuth(apiToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EmailKeyAuth build(String authEmail, String authKey) {
|
|
||||||
return new EmailKeyAuth(authEmail, authKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package codes.thischwa.cf.auth;
|
|
||||||
|
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authentication mechanism using Cloudflare account email and API key.
|
|
||||||
* This is the legacy authentication method for the Cloudflare API.
|
|
||||||
*/
|
|
||||||
public class EmailKeyAuth implements CfAuth {
|
|
||||||
|
|
||||||
private final String authEmail;
|
|
||||||
private final String authKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new email/key authentication object.
|
|
||||||
*
|
|
||||||
* @param authEmail the email address associated with the Cloudflare account
|
|
||||||
* @param authKey the API key of the Cloudflare account
|
|
||||||
* @throws IllegalArgumentException if email or key is null or blank
|
|
||||||
*/
|
|
||||||
public EmailKeyAuth(@NotNull String authEmail, @NotNull String authKey) {
|
|
||||||
if (authEmail.isBlank()) {
|
|
||||||
throw new IllegalArgumentException("Authentication email must not be null or blank!");
|
|
||||||
}
|
|
||||||
if (authKey.isBlank()) {
|
|
||||||
throw new IllegalArgumentException("Authentication key must not be null or blank!");
|
|
||||||
}
|
|
||||||
this.authEmail = authEmail;
|
|
||||||
this.authKey = authKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyAuth(ClassicHttpRequest request) {
|
|
||||||
request.addHeader("X-Auth-Email", authEmail);
|
|
||||||
request.addHeader("X-Auth-Key", authKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
/**
|
|
||||||
* The authentication package of CloudflareDNS-java.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package codes.thischwa.cf.auth;
|
|
||||||
@@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||||
|
|
||||||
import codes.thischwa.cf.auth.CfAuthBuilder;
|
|
||||||
import codes.thischwa.cf.model.RecordType;
|
import codes.thischwa.cf.model.RecordType;
|
||||||
import codes.thischwa.cf.model.ZoneEntity;
|
import codes.thischwa.cf.model.ZoneEntity;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -31,14 +30,14 @@ public class CfClientPenTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private CfDnsClient newClient() {
|
private CfDnsClient newClient() {
|
||||||
return new CfDnsClient(true, CfAuthBuilder.build(API_TOKEN));
|
return new CfDnsClientBuilder().withEmptyResultThrowsException(true).withApiTokenAuth(API_TOKEN).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Invalid credentials should not authenticate and must throw CloudflareApiException")
|
@DisplayName("Invalid credentials should not authenticate and must throw CloudflareApiException")
|
||||||
void testInvalidCredentialsShouldFail() {
|
void testInvalidCredentialsShouldFail() {
|
||||||
// Use syntactically valid but wrong credentials
|
// Use syntactically valid but wrong credentials
|
||||||
CfDnsClient badClient = new CfDnsClient(CfAuthBuilder.build("invalid@example.com", UUID.randomUUID().toString()));
|
CfDnsClient badClient = new CfDnsClientBuilder().withEmailKeyAuth("invalid@example.com", UUID.randomUUID().toString()).build();
|
||||||
assertThrows(CloudflareApiException.class, badClient::zoneList);
|
assertThrows(CloudflareApiException.class, badClient::zoneList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||||
|
|
||||||
import codes.thischwa.cf.auth.ApiTokenAuth;
|
|
||||||
import codes.thischwa.cf.auth.CfAuthBuilder;
|
|
||||||
import codes.thischwa.cf.auth.EmailKeyAuth;
|
|
||||||
import codes.thischwa.cf.model.BatchEntry;
|
import codes.thischwa.cf.model.BatchEntry;
|
||||||
import codes.thischwa.cf.model.RecordEntity;
|
import codes.thischwa.cf.model.RecordEntity;
|
||||||
import codes.thischwa.cf.model.RecordType;
|
import codes.thischwa.cf.model.RecordType;
|
||||||
@@ -33,7 +30,7 @@ public class CfClientTest {
|
|||||||
|
|
||||||
private static final String API_TOKEN = System.getenv("API_TOKEN");
|
private static final String API_TOKEN = System.getenv("API_TOKEN");
|
||||||
|
|
||||||
private final CfDnsClient client = new CfDnsClient(true, CfAuthBuilder.build(API_TOKEN));
|
private final CfDnsClient client = new CfDnsClientBuilder().withEmptyResultThrowsException(true).withApiTokenAuth(API_TOKEN).build();
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
static void checkEnv() {
|
static void checkEnv() {
|
||||||
@@ -225,16 +222,6 @@ public class CfClientTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void testException() {
|
|
||||||
// Test EmailKeyAuth validation
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new EmailKeyAuth("email", ""));
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new EmailKeyAuth("", "key"));
|
|
||||||
|
|
||||||
// Test ApiTokenAuth validation;
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> new ApiTokenAuth(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testRecordEntityInvalidType() {
|
void testRecordEntityInvalidType() {
|
||||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
|
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
|
||||||
|
|||||||
Reference in New Issue
Block a user