Skip to content

Commit

Permalink
Revert "Revert "feat(multiple-auth): add support for multiple auth (#79
Browse files Browse the repository at this point in the history
…)" (#84)"

This reverts commit d4af1f8.
  • Loading branch information
sufyankhanrao committed Dec 8, 2023
1 parent e0c0e13 commit 078c234
Show file tree
Hide file tree
Showing 13 changed files with 1,033 additions and 85 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@ Core lib's Maven group ID is `io.apimatic`, and its artifact ID is `core`.
|-------------------------------------------------------------------------|--------------------------------------------------------------------|
| [`ApiCall`](./src/main/java/io/apimatic/core/ApiCall.java) | An API call, or API request, is a message sent to a server asking an API to provide a service or information |
| [`Parameter`](./src/main/java/io/apimatic/core/Parameter.java) | HTTP parameters consist of a type, a name, and a value. These parameters appear in the header and body of an HTTP request. |
| [`ErrorCase`](./src/main/java/io/apimatic/core/ErrorCase.java) | A class is responsible to generate the SDK Exception |
| [`ErrorCase`](./src/main/java/io/apimatic/core/ErrorCase.java) | A class which is responsible to generate the SDK Exception |
| [`GlobalConfiguration`](./src/main/java/io/apimatic/core/GlobalConfiguration.java) | A class which hold the global configuration properties to make a successful Api Call |
| [`HttpRequest`](./src/main/java/io/apimatic/core/HttpRequest.java) | An HTTP request is made by a client, to a named host, which is located on a server |
| [`ResponseHandler`](./src/main/java/io/apimatic/core/ResponseHandler.java) | Handler that encapsulates the process of generating a response object from a Response |
| [`HttpLogger`](./src/main/java/io/apimatic/core/logger/HttpLogger.java) | A class to log the Http events. |
| [`AuthBuilder`](./src/main/java/io/apimatic/core/authentication/AuthBuilder.java) | A class to build and validate provided combination of auth schemes. |
| [`AuthCredential`](./src/main/java/io/apimatic/core/authentication/AuthCredential.java) | A parent class of [`HeaderAuth`](./src/main/java/io/apimatic/core/authentication/HeaderAuth.java) and [`QueryAuth`](./src/main/java/io/apimatic/core/authentication/QueryAuth.java) to hold the common implementation for header and query parameters |
| [`HeaderAuth`](./src/main/java/io/apimatic/core/authentication/HeaderAuth.java) | A class supports HTTP authentication through HTTP Headers |
| [`QueryAuth`](./src/main/java/io/apimatic/core/authentication/QueryAuth.java) | A class supports HTTP authentication through query parameters |
| [`AuthGroup`](./src/main/java/io/apimatic/core/authentication/multiple/AuthGroup.java) | A parent class of [`And`](./src/main/java/io/apimatic/core/authentication/multiple/And.java) and [`Or`](./src/main/java/io/apimatic/core/authentication/multiple/Or.java) to hold the common functionality of multiple auth |
| [`And`](./src/main/java/io/apimatic/core/authentication/multiple/And.java) | A class to hold the algorithm for `And` combination of auth schemes|
| [`Or`](./src/main/java/io/apimatic/core/authentication/multiple/Or.java) | A class to hold the algorithm for `Or` combination of auth schemes |
| [`Single`](./src/main/java/io/apimatic/core/authentication/multiple/Single.java) | A class to hold the logic for single auth scheme, it is used as leaf node for auth combination or it could be used directly to apply one auth only to the http request |
| [`CoreHttpClientConfiguration`](./src/main/java/io/apimatic/core/configurations/http/client/CoreHttpClientConfiguration.java) | To hold HTTP Client Configuration |
| [`ApiLoggingConfiguration`](./src/main/java/io/apimatic/core/configurations/http/client/ApiLoggingConfiguration.java) | To hold logging configuration |
| [`EndpointConfiguration`](./src/main/java/io/apimatic/core/configurations/http/request/EndpointConfiguration.java) | The configuration for an endpoint |
Expand Down
74 changes: 49 additions & 25 deletions src/main/java/io/apimatic/core/HttpRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import io.apimatic.core.authentication.AuthBuilder;
import io.apimatic.core.exceptions.AuthValidationException;
import io.apimatic.core.types.http.request.MultipartFileWrapper;
import io.apimatic.core.types.http.request.MultipartWrapper;
import io.apimatic.core.utilities.CoreHelper;
Expand Down Expand Up @@ -55,7 +57,7 @@ public final class HttpRequest {
* @param server
* @param path
* @param httpMethod
* @param authenticationKey
* @param authentication
* @param queryParams
* @param templateParams
* @param headerParams
Expand All @@ -65,16 +67,18 @@ public final class HttpRequest {
* @param bodySerializer
* @param bodyParameters
* @param arraySerializationFormat
* @param isSingleAuth
* @throws IOException
*/
private HttpRequest(final GlobalConfiguration coreConfig, final String server,
final String path, final Method httpMethod, final String authenticationKey,
final String path, final Method httpMethod, final Authentication authentication,
final Map<String, Object> queryParams,
final Map<String, SimpleEntry<Object, Boolean>> templateParams,
final Map<String, List<String>> headerParams, final Set<Parameter> formParams,
final Map<String, Object> formParameters, final Object body,
final Serializer bodySerializer, final Map<String, Object> bodyParameters,
final ArraySerializationFormat arraySerializationFormat) throws IOException {
final ArraySerializationFormat arraySerializationFormat,
final boolean isSingleAuth) throws IOException {
this.coreConfig = coreConfig;
this.compatibilityFactory = coreConfig.getCompatibilityFactory();
urlBuilder = getStringBuilder(server, path);
Expand All @@ -86,7 +90,7 @@ private HttpRequest(final GlobalConfiguration coreConfig, final String server,
coreHttpRequest =
buildRequest(httpMethod, bodyValue, addHeaders(headerParams), queryParams,
formFields, arraySerializationFormat);
applyAuthentication(authenticationKey);
applyAuthentication(authentication, isSingleAuth);
}

/**
Expand All @@ -96,21 +100,6 @@ public Request getCoreHttpRequest() {
return coreHttpRequest;
}

private void applyAuthentication(String authenticationKey) {
if (authenticationKey == null) {
return;
}

Map<String, Authentication> authentications = coreConfig.getAuthentications();
if (authentications != null) {
Authentication authManager = authentications.get(authenticationKey);
if (authManager != null) {
authManager.validate();
authManager.apply(coreHttpRequest);
}
}
}

private Request buildRequest(
Method httpMethod, Object body, HttpHeaders headerParams,
Map<String, Object> queryParams, List<SimpleEntry<String, Object>> formFields,
Expand All @@ -124,6 +113,22 @@ private Request buildRequest(
queryParams, formFields);
}

private void applyAuthentication(Authentication authentication, boolean isSingleAuth) {
if (authentication != null) {
authentication.validate();
if (!authentication.isValid() && !isSingleAuth) {
throw new AuthValidationException(authentication.getErrorMessage());
}

// The following block should be removed with the next major version release.
if (isSingleAuth && authentication.getErrorMessage() != null) {
throw new AuthValidationException(authentication.getErrorMessage());
}

authentication.apply(coreHttpRequest);
}
}

/**
* @param formParams
* @param optionalFormParamaters
Expand Down Expand Up @@ -239,9 +244,15 @@ public static class Builder {
private Method httpMethod;

/**
* A authentication key string.
* An auth builder for the request.
*/
private AuthBuilder authBuilder = new AuthBuilder();

/**
* Flag to use for backward compatibility.
* It should be removed with the next major version release.
*/
private String authenticationKey;
private boolean isSingleAuth = false;

/**
* A map of query parameters.
Expand Down Expand Up @@ -325,12 +336,23 @@ public Builder httpMethod(Method httpMethod) {
}

/**
* Setter for requiresAuth.
* Setter for authentication key.
* @param authenticationKey string value for authenticationKey.
* @return Builder.
*/
public Builder authenticationKey(String authenticationKey) {
this.authenticationKey = authenticationKey;
authBuilder = authBuilder.add(authenticationKey);
isSingleAuth = true;
return this;
}

/**
* Setter for Authentication Builder, used for authenticating the request.
* @param consumer the builder consumer for authentication.
* @return Builder.
*/
public Builder withAuth(Consumer<AuthBuilder> consumer) {
consumer.accept(authBuilder);
return this;
}

Expand Down Expand Up @@ -472,10 +494,12 @@ public Builder arraySerializationFormat(ArraySerializationFormat arraySerializat
* @throws IOException Signals that an I/O exception of some sort has occurred.
*/
public Request build(GlobalConfiguration coreConfig) throws IOException {
Authentication authentication = authBuilder.build(coreConfig.getAuthentications());
HttpRequest coreRequest =
new HttpRequest(coreConfig, server, path, httpMethod, authenticationKey,
new HttpRequest(coreConfig, server, path, httpMethod, authentication,
queryParams, templateParams, headerParams, formParams, formParamaters,
body, bodySerializer, bodyParameters, arraySerializationFormat);
body, bodySerializer, bodyParameters, arraySerializationFormat,
isSingleAuth);
Request coreHttpRequest = coreRequest.getCoreHttpRequest();

if (coreConfig.getHttpCallback() != null) {
Expand Down
139 changes: 139 additions & 0 deletions src/main/java/io/apimatic/core/authentication/AuthBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package io.apimatic.core.authentication;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import io.apimatic.core.authentication.multiple.And;
import io.apimatic.core.authentication.multiple.Or;
import io.apimatic.core.authentication.multiple.Single;
import io.apimatic.coreinterfaces.authentication.Authentication;

/**
* A builder for authentication.
*/
public class AuthBuilder {

/**
* Constant for AND group identifier.
*/
private static final String AND = "AND";

/**
* Constant for OR group identifier.
*/
private static final String OR = "OR";

/**
* Holds nested combination of authentication.
*/
private Map<String, List<AuthBuilder>> authBuilders;

/**
* Holds the authentication keys, must belong to the provided authentication managers.
*/
private List<String> authKeys;

/**
* Default constructor.
*/
public AuthBuilder() {
authBuilders = new HashMap<String, List<AuthBuilder>>();
authBuilders.put(AND, new ArrayList<AuthBuilder>());
authBuilders.put(OR, new ArrayList<AuthBuilder>());
authKeys = new ArrayList<String>();
}

/**
* Registers the authentication key to the builder.
* @param authKey A key pointing to some authentication in the provided auth managers.
* @return {@link AuthBuilder} The instance of the current builder.
*/
public AuthBuilder add(String authKey) {
authKeys.add(authKey);
return this;
}

/**
* Registers the and group for authentication.
* @param action A consumer for the nested builder.
* @return {@link AuthBuilder} The instance of the current builder.
*/
public AuthBuilder and(Consumer<AuthBuilder> action) {
AuthBuilder authBuilder = new AuthBuilder();
action.accept(authBuilder);
authBuilders.get(AND).add(authBuilder);
return this;
}

/**
* Registers the or group for authentication.
* @param action A consumer for the nested builder.
* @return {@link AuthBuilder} The instance of the current builder.
*/
public AuthBuilder or(Consumer<AuthBuilder> action) {
AuthBuilder authBuilder = new AuthBuilder();
action.accept(authBuilder);
authBuilders.get(OR).add(authBuilder);
return this;
}

/**
* Builds and validates the authentication using registered authentication keys.
* @param authManagers The map of authentication managers.
* @return {@link Authentication} The validated instance of authentication.
*/
public Authentication build(Map<String, Authentication> authManagers) {
if (authManagers == null || authManagers.isEmpty()) {
return null;
}

if (authBuilders.get(AND).isEmpty() && authBuilders.get(OR).isEmpty()
&& authKeys.isEmpty()) {
return null;
}

Authentication mappedAuth = null;
if (authBuilders.get(AND).isEmpty() && authBuilders.get(OR).isEmpty()
&& !authKeys.isEmpty()) {
mappedAuth = new Single(authManagers.get(authKeys.get(0)));
return mappedAuth;
}

for (AuthBuilder authBuilder : authBuilders.get(AND)) {
mappedAuth = new And(authBuilder.buildAuthGroup(authManagers));
}

for (AuthBuilder authBuilder : authBuilders.get(OR)) {
mappedAuth = new Or(authBuilder.buildAuthGroup(authManagers));
}

return mappedAuth;
}

/**
* Builds the nested authentication groups.
* @param authManagers The map of authentication managers.
* @return List<{@link Authentication}> The converted instance of nested authentications.
*/
private List<Authentication> buildAuthGroup(Map<String, Authentication> authManagers) {
List<Authentication> auths = new ArrayList<Authentication>();

authKeys.forEach(authKey -> {
if (authManagers.containsKey(authKey)) {
auths.add(new Single(authManagers.get(authKey)));
}
});

authBuilders.get(AND).forEach(authBuilder -> {
auths.add(new And(authBuilder.buildAuthGroup(authManagers)));
});

authBuilders.get(OR).forEach(authBuilder -> {
auths.add(new Or(authBuilder.buildAuthGroup(authManagers)));
});

return auths;
}
}
52 changes: 52 additions & 0 deletions src/main/java/io/apimatic/core/authentication/AuthCredential.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.apimatic.core.authentication;

import java.util.HashMap;
import java.util.Map;
import io.apimatic.coreinterfaces.authentication.Authentication;

/**
* Handles and validates the Authentication parameters.
*/
public abstract class AuthCredential extends Authentication {

/**
* A map of authentication parameters.
*/
private Map<String, String> authParams = new HashMap<>();

/**
* @param authParams Map of authentication parameters.
*/
public AuthCredential(final Map<String, String> authParams) {
this.authParams = authParams;
}

/**
* Getter for the map of authentication parameters.
* @return Map&lt;String, String&gt; The map of authentication parameters.
*/
public Map<String, String> getAuthParams() {
return authParams;
}

/**
* Validates the credentials for authentication.
*/
public void validate() {
// Check for null keys or values
boolean hasNullKeyOrValue = authParams.entrySet().stream()
.anyMatch(entry -> entry.getKey() == null
|| entry.getKey() == ""
|| entry.getValue() == null
|| entry.getValue() == "");

if (hasNullKeyOrValue) {
setErrorMessage("[Auth key and value cannot be null]");
setValidity(false);
return;
}

setValidity(true);
}

}
Loading

0 comments on commit 078c234

Please sign in to comment.