diff --git a/docs/003_Auth4j.md b/docs/003_Auth4j.md new file mode 100644 index 0000000..a0a6651 --- /dev/null +++ b/docs/003_Auth4j.md @@ -0,0 +1,115 @@ +# Auth4j + +`Auth4j` is a class utility designed to handle various types of authentication mechanisms. It supports Basic, Bearer, API +Key, OAuth2, and OAuth2 Client Credentials authentication types. + +## Features + +- Basic Authentication +- Bearer Token Authentication +- API Key Authentication +- OAuth2 Authentication +- OAuth2 Client Credentials Authentication + +## Usage + +### Basic Authentication + +```java +Auth4j auth = new Auth4j.Builder() + .type(AuthType.BASIC) + .username("yourUsername") + .password("yourPassword") + .build(); + +WrapResponse response = auth.verify(); +if (response.isSuccess()) { + Map headers = auth.getHeaders(); + // Use headers in your HTTP request +} +``` + +### Bearer Token Authentication + +```java +Auth4j auth = new Auth4j.Builder() + .type(AuthType.BEARER) + .token("yourBearerToken") + .build(); + +WrapResponse response = auth.verify(); +if (response.isSuccess()) { + Map headers = auth.getHeaders(); + // Use headers in your HTTP request +} +``` + +### API Key Authentication + +```java +Auth4j auth = new Auth4j.Builder() + .type(AuthType.API_KEY) + .headerNameApiKey("X-API-KEY") + .apiKey("yourApiKey") + .build(); + +WrapResponse response = auth.verify(); +if (response.isSuccess()) { + Map headers = auth.getHeaders(); + // Use headers in your HTTP request +} +``` + +### OAuth2 Authentication + +```java +Auth4j auth = new Auth4j.Builder() + .type(AuthType.OAUTH2) + .accessToken("yourAccessToken") + .build(); + +WrapResponse response = auth.verify(); +if (response.isSuccess()) { + Map headers = auth.getHeaders(); + // Use headers in your HTTP request +} +``` + +### OAuth2 Client Credentials Authentication + +```java +AuthFactory authFactory = new AuthFactory() { + @Override + public String retrieveAccessToken(String clientId, String clientSecret) { + // Implement your logic to retrieve the access token + return "yourAccessToken"; + } +}; + +Auth4j auth = new Auth4j.Builder() + .type(AuthType.OAUTH2_CLIENT_CREDENTIALS) + .factory(authFactory) + .clientId("yourClientId") + .clientSecret("yourClientSecret") + .build(); + +WrapResponse response = auth.verify(); +if (response.isSuccess()) { + Map headers = auth.getHeaders(); + // Use headers in your HTTP request +} +``` + +### Custom Authentication Logic + +To implement custom logic for retrieving the access token in the OAuth2 Client Credentials flow, you can extend the AuthFactory and provide your implementation. + +```java +public class CustomAuthFactory extends AuthFactory { + @Override + public String retrieveAccessToken(String clientId, String clientSecret) { + // Custom logic to retrieve the access token + return "yourAccessToken"; + } +} +``` diff --git a/plugin/src/main/groovy/org/unify4j/common/Auth4j.java b/plugin/src/main/groovy/org/unify4j/common/Auth4j.java new file mode 100644 index 0000000..bdbadb6 --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/common/Auth4j.java @@ -0,0 +1,129 @@ +package org.unify4j.common; + +import org.unify4j.model.builder.HttpWrapBuilder; +import org.unify4j.model.c.HttpHeaders; +import org.unify4j.model.enums.AuthType; +import org.unify4j.model.onlyrd.AbstractAuthClass; +import org.unify4j.model.response.WrapResponse; + +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class Auth4j extends AbstractAuthClass { + protected Auth4j(Builder builder) { + super(builder); + } + + /** + * @return a WrapResponse object containing the response from the Auth manager API, class {@link WrapResponse} + */ + @Override + public WrapResponse verify() { + if (this.type == null) { + return new HttpWrapBuilder<>().badRequest("Auth Type is required").build(); + } + switch (this.type) { + case BASIC: + if (String4j.isEmpty(this.username)) { + return new HttpWrapBuilder<>().badRequest("Username is required").build(); + } + if (String4j.isEmpty(this.password)) { + return new HttpWrapBuilder<>().badRequest("Password is required").build(); + } + break; + case BEARER: + if (String4j.isEmpty(this.token)) { + return new HttpWrapBuilder<>().badRequest("Token is required").build(); + } + break; + case API_KEY: + if (String4j.isEmpty(this.headerNameApiKey)) { + return new HttpWrapBuilder<>().badRequest("Header name API-KEY is required").build(); + } + if (String4j.isEmpty(this.apiKey)) { + return new HttpWrapBuilder<>().badRequest("API-KEY is required").build(); + } + break; + case OAUTH2: + if (String4j.isEmpty(this.accessToken)) { + return new HttpWrapBuilder<>().badRequest("Access-Token is required").build(); + } + break; + case OAUTH2_CLIENT_CREDENTIALS: + if (this.factory == null) { + return new HttpWrapBuilder<>().badRequest("AuthFactory is required for OAUTH2_CLIENT_CREDENTIALS").build(); + } + if (String4j.isEmpty(this.clientId)) { + return new HttpWrapBuilder<>().badRequest("Client-Id is required").build(); + } + if (String4j.isEmpty(this.clientSecret)) { + return new HttpWrapBuilder<>().badRequest("Client-Secret is required").build(); + } + break; + } + return new HttpWrapBuilder<>().ok(null).build(); + } + + /** + * @return map header request, class {@link Map} + */ + @Override + public Map getHeaders() { + WrapResponse verified = this.verify(); + if (!verified.isSuccess()) { + return Collections.emptyMap(); + } + Map header = new HashMap<>(); + switch (this.type) { + case BASIC: + String authValue = Base64.getEncoder().encodeToString(String.format("%s:%s", this.username, this.password).getBytes()); + header.put(HttpHeaders.AUTHORIZATION, String.format("%s %s", String4j.capitalizeEachWords(AuthType.BASIC.name()), authValue)); + break; + case BEARER: + header.put(HttpHeaders.AUTHORIZATION, String.format("%s %s", String4j.capitalizeEachWords(AuthType.BEARER.name()), this.token)); + break; + case API_KEY: + header.put(this.headerNameApiKey, this.apiKey); + break; + case OAUTH2: + header.put(HttpHeaders.AUTHORIZATION, String.format("%s %s", String4j.capitalizeEachWords(AuthType.BEARER.name()), this.accessToken)); + break; + case OAUTH2_CLIENT_CREDENTIALS: + this.accessToken = this.factory.retrieveAccessToken(this.clientId, this.clientSecret); + header.put(HttpHeaders.AUTHORIZATION, String.format("%s %s", String4j.capitalizeEachWords(AuthType.BEARER.name()), this.accessToken)); + break; + default: + throw new IllegalArgumentException(String.format("Unsupported Auth Type: %s", this.type.name())); + } + return header; + } + + /** + * @return the string includes information + */ + @Override + public String toString() { + return String.format("Auth4j { type: %s, username: %s, password: %s, token: %s, api_key: %s, header_name_api_key: %s, client_id: %s, client_secret: %s, access_token: %s, refresh_token: %s }", + this.type, this.username, String4j.isEmpty(this.password) ? "" : "***", this.token, this.apiKey, this.headerNameApiKey, this.clientId, this.clientSecret, this.accessToken, this.refreshToken); + } + + public static class Builder extends AbstractAuthClass.Builder { + /** + * @return new instance Auth, class {@link Auth4j} + */ + @Override + public Auth4j build() { + return new Auth4j(this); + } + + /** + * @return the current self, class {@link Builder} + */ + @Override + protected Builder self() { + return this; + } + } +} diff --git a/plugin/src/main/groovy/org/unify4j/common/Vi4j.java b/plugin/src/main/groovy/org/unify4j/common/Vi4j.java index 96f25c1..566f3e3 100644 --- a/plugin/src/main/groovy/org/unify4j/common/Vi4j.java +++ b/plugin/src/main/groovy/org/unify4j/common/Vi4j.java @@ -244,4 +244,30 @@ public static void throwIfTrue(boolean logic, String message) { throw new IllegalArgumentException(message); } } + + /** + * Throws an IllegalStateException if the provided logic condition is true. + * + * @param logic The boolean condition to evaluate. + * @param message The message to include in the exception if the condition is true. + * @throws IllegalStateException if the logic condition is true. + */ + public static void throwStateIfTrue(boolean logic, String message) { + if (logic) { + throw new IllegalStateException(message); + } + } + + /** + * Throws an IllegalStateException if the provided logic condition is false. + * + * @param logic The boolean condition to evaluate. + * @param message The message to include in the exception if the condition is false. + * @throws IllegalStateException if the logic condition is false. + */ + public static void throwStateIfFalse(boolean logic, String message) { + if (!logic) { + throw new IllegalStateException(message); + } + } } diff --git a/plugin/src/main/groovy/org/unify4j/model/c/HttpHeaders.java b/plugin/src/main/groovy/org/unify4j/model/c/HttpHeaders.java new file mode 100644 index 0000000..72fecc9 --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/model/c/HttpHeaders.java @@ -0,0 +1,1022 @@ +package org.unify4j.model.c; + +import java.io.Serializable; + +@SuppressWarnings({"SpellCheckingInspection"}) +public class HttpHeaders implements Serializable { + + /** + * The HTTP {@code Cache-Control} header field name. + */ + public static final String CACHE_CONTROL = "Cache-Control"; + /** + * The HTTP {@code Content-Length} header field name. + */ + public static final String CONTENT_LENGTH = "Content-Length"; + /** + * The HTTP {@code Content-Type} header field name. + */ + public static final String CONTENT_TYPE = "Content-Type"; + /** + * The HTTP {@code Date} header field name. + */ + public static final String DATE = "Date"; + /** + * The HTTP {@code Pragma} header field name. + */ + public static final String PRAGMA = "Pragma"; + /** + * The HTTP {@code Via} header field name. + */ + public static final String VIA = "Via"; + /** + * The HTTP {@code Warning} header field name. + */ + public static final String WARNING = "Warning"; + + // HTTP Request header fields + + /** + * The HTTP {@code Accept} header field name. + */ + public static final String ACCEPT = "Accept"; + /** + * The HTTP {@code Accept-Charset} header field name. + */ + public static final String ACCEPT_CHARSET = "Accept-Charset"; + /** + * The HTTP {@code Accept-Encoding} header field name. + */ + public static final String ACCEPT_ENCODING = "Accept-Encoding"; + /** + * The HTTP {@code Accept-Language} header field name. + */ + public static final String ACCEPT_LANGUAGE = "Accept-Language"; + /** + * The HTTP {@code Access-Control-Request-Headers} header field name. + */ + public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; + /** + * The HTTP {@code Access-Control-Request-Method} header field name. + */ + public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method"; + /** + * The HTTP {@code Authorization} header field name. + */ + public static final String AUTHORIZATION = "Authorization"; + /** + * The HTTP {@code Connection} header field name. + */ + public static final String CONNECTION = "Connection"; + /** + * The HTTP {@code Cookie} header field name. + */ + public static final String COOKIE = "Cookie"; + /** + * The HTTP {@code + * Cross-Origin-Resource-Policy} header field name. + * + * @since 28.0 + */ + public static final String CROSS_ORIGIN_RESOURCE_POLICY = "Cross-Origin-Resource-Policy"; + /** + * The HTTP {@code Early-Data} header field + * name. + * + * @since 27.0 + */ + public static final String EARLY_DATA = "Early-Data"; + /** + * The HTTP {@code Expect} header field name. + */ + public static final String EXPECT = "Expect"; + /** + * The HTTP {@code From} header field name. + */ + public static final String FROM = "From"; + /** + * The HTTP {@code Forwarded} header field name. + * + * @since 20.0 + */ + public static final String FORWARDED = "Forwarded"; + /** + * The HTTP {@code Follow-Only-When-Prerender-Shown} header field name. + * + * @since 17.0 + */ + public static final String FOLLOW_ONLY_WHEN_PRERENDER_SHOWN = "Follow-Only-When-Prerender-Shown"; + /** + * The HTTP {@code Host} header field name. + */ + public static final String HOST = "Host"; + /** + * The HTTP {@code HTTP2-Settings} + * header field name. + * + * @since 24.0 + */ + public static final String HTTP2_SETTINGS = "HTTP2-Settings"; + /** + * The HTTP {@code If-Match} header field name. + */ + public static final String IF_MATCH = "If-Match"; + /** + * The HTTP {@code If-Modified-Since} header field name. + */ + public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; + /** + * The HTTP {@code If-None-Match} header field name. + */ + public static final String IF_NONE_MATCH = "If-None-Match"; + /** + * The HTTP {@code If-Range} header field name. + */ + public static final String IF_RANGE = "If-Range"; + /** + * The HTTP {@code If-Unmodified-Since} header field name. + */ + public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; + /** + * The HTTP {@code Last-Event-ID} header field name. + */ + public static final String LAST_EVENT_ID = "Last-Event-ID"; + /** + * The HTTP {@code Max-Forwards} header field name. + */ + public static final String MAX_FORWARDS = "Max-Forwards"; + /** + * The HTTP {@code Origin} header field name. + */ + public static final String ORIGIN = "Origin"; + /** + * The HTTP {@code Origin-Isolation} header + * field name. + * + * @since 30.1 + */ + public static final String ORIGIN_ISOLATION = "Origin-Isolation"; + /** + * The HTTP {@code Proxy-Authorization} header field name. + */ + public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; + /** + * The HTTP {@code Range} header field name. + */ + public static final String RANGE = "Range"; + /** + * The HTTP {@code Referer} header field name. + */ + public static final String REFERER = "Referer"; + /** + * The HTTP {@code Referrer-Policy} header + * field name. + * + * @since 23.4 + */ + public static final String REFERRER_POLICY = "Referrer-Policy"; + + /** + * Values for the {@code Referrer-Policy} + * header. + * + * @since 23.4 + */ + public static final class ReferrerPolicyValues { + private ReferrerPolicyValues() { + } + + public static final String NO_REFERRER = "no-referrer"; + public static final String NO_REFFERER_WHEN_DOWNGRADE = "no-referrer-when-downgrade"; + public static final String SAME_ORIGIN = "same-origin"; + public static final String ORIGIN = "origin"; + public static final String STRICT_ORIGIN = "strict-origin"; + public static final String ORIGIN_WHEN_CROSS_ORIGIN = "origin-when-cross-origin"; + public static final String STRICT_ORIGIN_WHEN_CROSS_ORIGIN = "strict-origin-when-cross-origin"; + public static final String UNSAFE_URL = "unsafe-url"; + } + + /** + * The HTTP {@code + * Service-Worker} header field name. + * + * @since 20.0 + */ + public static final String SERVICE_WORKER = "Service-Worker"; + /** + * The HTTP {@code TE} header field name. + */ + public static final String TE = "TE"; + /** + * The HTTP {@code Upgrade} header field name. + */ + public static final String UPGRADE = "Upgrade"; + /** + * The HTTP {@code + * Upgrade-Insecure-Requests} header field name. + * + * @since 28.1 + */ + public static final String UPGRADE_INSECURE_REQUESTS = "Upgrade-Insecure-Requests"; + + /** + * The HTTP {@code User-Agent} header field name. + */ + public static final String USER_AGENT = "User-Agent"; + + // HTTP Response header fields + + /** + * The HTTP {@code Accept-Ranges} header field name. + */ + public static final String ACCEPT_RANGES = "Accept-Ranges"; + /** + * The HTTP {@code Access-Control-Allow-Headers} header field name. + */ + public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; + /** + * The HTTP {@code Access-Control-Allow-Methods} header field name. + */ + public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; + /** + * The HTTP {@code Access-Control-Allow-Origin} header field name. + */ + public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; + /** + * The HTTP {@code + * Access-Control-Allow-Private-Network} header field name. + * + * @since 31.1 + */ + public static final String ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK = "Access-Control-Allow-Private-Network"; + /** + * The HTTP {@code Access-Control-Allow-Credentials} header field name. + */ + public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; + /** + * The HTTP {@code Access-Control-Expose-Headers} header field name. + */ + public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers"; + /** + * The HTTP {@code Access-Control-Max-Age} header field name. + */ + public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age"; + /** + * The HTTP {@code Age} header field name. + */ + public static final String AGE = "Age"; + /** + * The HTTP {@code Allow} header field name. + */ + public static final String ALLOW = "Allow"; + /** + * The HTTP {@code Content-Disposition} header field name. + */ + public static final String CONTENT_DISPOSITION = "Content-Disposition"; + /** + * The HTTP {@code Content-Encoding} header field name. + */ + public static final String CONTENT_ENCODING = "Content-Encoding"; + /** + * The HTTP {@code Content-Language} header field name. + */ + public static final String CONTENT_LANGUAGE = "Content-Language"; + /** + * The HTTP {@code Content-Location} header field name. + */ + public static final String CONTENT_LOCATION = "Content-Location"; + /** + * The HTTP {@code Content-MD5} header field name. + */ + public static final String CONTENT_MD5 = "Content-MD5"; + /** + * The HTTP {@code Content-Range} header field name. + */ + public static final String CONTENT_RANGE = "Content-Range"; + /** + * The HTTP {@code + * Content-Security-Policy} header field name. + * + * @since 15.0 + */ + public static final String CONTENT_SECURITY_POLICY = "Content-Security-Policy"; + /** + * The HTTP + * {@code Content-Security-Policy-Report-Only} header field name. + * + * @since 15.0 + */ + public static final String CONTENT_SECURITY_POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only"; + /** + * The HTTP nonstandard {@code X-Content-Security-Policy} header field name. It was introduced in + * CSP v.1 and used by the Firefox until + * version 23 and the Internet Explorer version 10. Please, use {@link #CONTENT_SECURITY_POLICY} + * to pass the CSP. + * + * @since 20.0 + */ + public static final String X_CONTENT_SECURITY_POLICY = "X-Content-Security-Policy"; + /** + * The HTTP nonstandard {@code X-Content-Security-Policy-Report-Only} header field name. It was + * introduced in CSP v.1 and used by the + * Firefox until version 23 and the Internet Explorer version 10. Please, use {@link + * #CONTENT_SECURITY_POLICY_REPORT_ONLY} to pass the CSP. + * + * @since 20.0 + */ + public static final String X_CONTENT_SECURITY_POLICY_REPORT_ONLY = "X-Content-Security-Policy-Report-Only"; + /** + * The HTTP nonstandard {@code X-WebKit-CSP} header field name. It was introduced in CSP v.1 and used by the Chrome until + * version 25. Please, use {@link #CONTENT_SECURITY_POLICY} to pass the CSP. + * + * @since 20.0 + */ + public static final String X_WEBKIT_CSP = "X-WebKit-CSP"; + /** + * The HTTP nonstandard {@code X-WebKit-CSP-Report-Only} header field name. It was introduced in + * CSP v.1 and used by the Chrome until + * version 25. Please, use {@link #CONTENT_SECURITY_POLICY_REPORT_ONLY} to pass the CSP. + * + * @since 20.0 + */ + public static final String X_WEBKIT_CSP_REPORT_ONLY = "X-WebKit-CSP-Report-Only"; + /** + * The HTTP {@code + * Cross-Origin-Embedder-Policy} header field name. + * + * @since 30.0 + */ + public static final String CROSS_ORIGIN_EMBEDDER_POLICY = "Cross-Origin-Embedder-Policy"; + /** + * The HTTP {@code + * Cross-Origin-Embedder-Policy-Report-Only} header field name. + * + * @since 30.0 + */ + public static final String CROSS_ORIGIN_EMBEDDER_POLICY_REPORT_ONLY = "Cross-Origin-Embedder-Policy-Report-Only"; + /** + * The HTTP Cross-Origin-Opener-Policy header field name. + * + * @since 28.2 + */ + public static final String CROSS_ORIGIN_OPENER_POLICY = "Cross-Origin-Opener-Policy"; + /** + * The HTTP {@code ETag} header field name. + */ + public static final String ETAG = "ETag"; + /** + * The HTTP {@code Expires} header field name. + */ + public static final String EXPIRES = "Expires"; + /** + * The HTTP {@code Last-Modified} header field name. + */ + public static final String LAST_MODIFIED = "Last-Modified"; + /** + * The HTTP {@code Link} header field name. + */ + public static final String LINK = "Link"; + /** + * The HTTP {@code Location} header field name. + */ + public static final String LOCATION = "Location"; + /** + * The HTTP {@code Keep-Alive} header field name. + * + * @since 31.0 + */ + public static final String KEEP_ALIVE = "Keep-Alive"; + /** + * The HTTP {@code + * No-Vary-Seearch} header field name. + * + * @since 32.0.0 + */ + public static final String NO_VARY_SEARCH = "No-Vary-Search"; + /** + * The HTTP {@code Origin-Trial} + * header field name. + * + * @since 27.1 + */ + public static final String ORIGIN_TRIAL = "Origin-Trial"; + /** + * The HTTP {@code P3P} header field name. Limited browser support. + */ + public static final String P3P = "P3P"; + /** + * The HTTP {@code Proxy-Authenticate} header field name. + */ + public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate"; + /** + * The HTTP {@code Refresh} header field name. Non-standard header supported by most browsers. + */ + public static final String REFRESH = "Refresh"; + /** + * The HTTP {@code Report-To} header field name. + * + * @since 27.1 + */ + public static final String REPORT_TO = "Report-To"; + /** + * The HTTP {@code Retry-After} header field name. + */ + public static final String RETRY_AFTER = "Retry-After"; + /** + * The HTTP {@code Server} header field name. + */ + public static final String SERVER = "Server"; + /** + * The HTTP {@code Server-Timing} header field + * name. + * + * @since 23.6 + */ + public static final String SERVER_TIMING = "Server-Timing"; + /** + * The HTTP {@code + * Service-Worker-Allowed} header field name. + * + * @since 20.0 + */ + public static final String SERVICE_WORKER_ALLOWED = "Service-Worker-Allowed"; + /** + * The HTTP {@code Set-Cookie} header field name. + */ + public static final String SET_COOKIE = "Set-Cookie"; + /** + * The HTTP {@code Set-Cookie2} header field name. + */ + public static final String SET_COOKIE2 = "Set-Cookie2"; + + /** + * The HTTP {@code SourceMap} header field name. + * + * @since 27.1 + */ + public static final String SOURCE_MAP = "SourceMap"; + + /** + * The HTTP {@code + * Supports-Loading-Mode} header field name. This can be used to specify, for example, fenced + * frames. + * + * @since 32.0.0 + */ + public static final String SUPPORTS_LOADING_MODE = "Supports-Loading-Mode"; + + /** + * The HTTP {@code + * Strict-Transport-Security} header field name. + * + * @since 15.0 + */ + public static final String STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security"; + /** + * The HTTP {@code + * Timing-Allow-Origin} header field name. + * + * @since 15.0 + */ + public static final String TIMING_ALLOW_ORIGIN = "Timing-Allow-Origin"; + /** + * The HTTP {@code Trailer} header field name. + */ + public static final String TRAILER = "Trailer"; + /** + * The HTTP {@code Transfer-Encoding} header field name. + */ + public static final String TRANSFER_ENCODING = "Transfer-Encoding"; + /** + * The HTTP {@code Vary} header field name. + */ + public static final String VARY = "Vary"; + /** + * The HTTP {@code WWW-Authenticate} header field name. + */ + public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + + // Common, non-standard HTTP header fields + + /** + * The HTTP {@code DNT} header field name. + */ + public static final String DNT = "DNT"; + /** + * The HTTP {@code X-Content-Type-Options} header field name. + */ + public static final String X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options"; + /** + * The HTTP {@code + * X-Device-IP} header field name. Header used for VAST requests to provide the IP address of + * the device on whose behalf the request is being made. + * + * @since 31.0 + */ + public static final String X_DEVICE_IP = "X-Device-IP"; + /** + * The HTTP {@code + * X-Device-Referer} header field name. Header used for VAST requests to provide the {@link + * #REFERER} header value that the on-behalf-of client would have used when making a request + * itself. + * + * @since 31.0 + */ + public static final String X_DEVICE_REFERER = "X-Device-Referer"; + /** + * The HTTP {@code + * X-Device-Accept-Language} header field name. Header used for VAST requests to provide the + * {@link #ACCEPT_LANGUAGE} header value that the on-behalf-of client would have used when making + * a request itself. + * + * @since 31.0 + */ + public static final String X_DEVICE_ACCEPT_LANGUAGE = "X-Device-Accept-Language"; + /** + * The HTTP {@code + * X-Device-Requested-With} header field name. Header used for VAST requests to provide the + * {@link #X_REQUESTED_WITH} header value that the on-behalf-of client would have used when making + * a request itself. + * + * @since 31.0 + */ + public static final String X_DEVICE_REQUESTED_WITH = "X-Device-Requested-With"; + /** + * The HTTP {@code X-Do-Not-Track} header field name. + */ + public static final String X_DO_NOT_TRACK = "X-Do-Not-Track"; + /** + * The HTTP {@code X-Forwarded-For} header field name (superseded by {@code Forwarded}). + */ + public static final String X_FORWARDED_FOR = "X-Forwarded-For"; + /** + * The HTTP {@code X-Forwarded-Proto} header field name. + */ + public static final String X_FORWARDED_PROTO = "X-Forwarded-Proto"; + /** + * The HTTP {@code X-Forwarded-Host} header field name. + * + * @since 20.0 + */ + public static final String X_FORWARDED_HOST = "X-Forwarded-Host"; + /** + * The HTTP {@code X-Forwarded-Port} header field name. + * + * @since 20.0 + */ + public static final String X_FORWARDED_PORT = "X-Forwarded-Port"; + /** + * The HTTP {@code X-Frame-Options} header field name. + */ + public static final String X_FRAME_OPTIONS = "X-Frame-Options"; + /** + * The HTTP {@code X-Powered-By} header field name. + */ + public static final String X_POWERED_BY = "X-Powered-By"; + /** + * The HTTP {@code + * Public-Key-Pins} header field name. + * + * @since 15.0 + */ + public static final String PUBLIC_KEY_PINS = "Public-Key-Pins"; + /** + * The HTTP {@code + * Public-Key-Pins-Report-Only} header field name. + * + * @since 15.0 + */ + public static final String PUBLIC_KEY_PINS_REPORT_ONLY = "Public-Key-Pins-Report-Only"; + /** + * The HTTP {@code X-Request-ID} header field name. + * + * @since 30.1 + */ + public static final String X_REQUEST_ID = "X-Request-ID"; + /** + * The HTTP {@code X-Requested-With} header field name. + */ + public static final String X_REQUESTED_WITH = "X-Requested-With"; + /** + * The HTTP {@code X-User-IP} header field name. + */ + public static final String X_USER_IP = "X-User-IP"; + /** + * The HTTP {@code X-Download-Options} header field name. + * + *

When the new X-Download-Options header is present with the value {@code noopen}, the user is + * prevented from opening a file download directly; instead, they must first save the file + * locally. + * + * @since 24.1 + */ + public static final String X_DOWNLOAD_OPTIONS = "X-Download-Options"; + /** + * The HTTP {@code X-XSS-Protection} header field name. + */ + public static final String X_XSS_PROTECTION = "X-XSS-Protection"; + /** + * The HTTP {@code + * X-DNS-Prefetch-Control} header controls DNS prefetch behavior. Value can be "on" or "off". + * By default, DNS prefetching is "on" for HTTP pages and "off" for HTTPS pages. + */ + public static final String X_DNS_PREFETCH_CONTROL = "X-DNS-Prefetch-Control"; + /** + * The HTTP + * {@code Ping-From} header field name. + * + * @since 19.0 + */ + public static final String PING_FROM = "Ping-From"; + /** + * The HTTP + * {@code Ping-To} header field name. + * + * @since 19.0 + */ + public static final String PING_TO = "Ping-To"; + + /** + * The HTTP {@code + * Purpose} header field name. + * + * @since 28.0 + */ + public static final String PURPOSE = "Purpose"; + /** + * The HTTP {@code + * X-Purpose} header field name. + * + * @since 28.0 + */ + public static final String X_PURPOSE = "X-Purpose"; + /** + * The HTTP {@code + * X-Moz} header field name. + * + * @since 28.0 + */ + public static final String X_MOZ = "X-Moz"; + + /** + * The HTTP {@code + * Device-Memory} header field name. + * + * @since 31.0 + */ + public static final String DEVICE_MEMORY = "Device-Memory"; + + /** + * The HTTP {@code + * Downlink} header field name. + * + * @since 31.0 + */ + public static final String DOWNLINK = "Downlink"; + + /** + * The HTTP {@code + * ECT} header field name. + * + * @since 31.0 + */ + public static final String ECT = "ECT"; + + /** + * The HTTP {@code + * RTT} header field name. + * + * @since 31.0 + */ + public static final String RTT = "RTT"; + + /** + * The HTTP {@code + * Save-Data} header field name. + * + * @since 31.0 + */ + public static final String SAVE_DATA = "Save-Data"; + + /** + * The HTTP {@code + * Viewport-Width} header field name. + * + * @since 31.0 + */ + public static final String VIEWPORT_WIDTH = "Viewport-Width"; + + /** + * The HTTP {@code + * Width} header field name. + * + * @since 31.0 + */ + public static final String WIDTH = "Width"; + + /** + * The HTTP {@code Permissions-Policy} + * header field name. + * + * @since 31.0 + */ + public static final String PERMISSIONS_POLICY = "Permissions-Policy"; + + /** + * The HTTP {@code + * Permissions-Policy-Report-Only} header field name. + * + * @since 33.2.0 + */ + public static final String PERMISSIONS_POLICY_REPORT_ONLY = "Permissions-Policy-Report-Only"; + + /** + * The HTTP {@code + * Sec-CH-Prefers-Color-Scheme} header field name. + * + *

This header is experimental. + * + * @since 31.0 + */ + public static final String SEC_CH_PREFERS_COLOR_SCHEME = "Sec-CH-Prefers-Color-Scheme"; + + /** + * The HTTP {@code + * Accept-CH} header field name. + * + * @since 31.0 + */ + public static final String ACCEPT_CH = "Accept-CH"; + /** + * The HTTP {@code + * Critical-CH} header field name. + * + * @since 31.0 + */ + public static final String CRITICAL_CH = "Critical-CH"; + + /** + * The HTTP {@code Sec-CH-UA} + * header field name. + * + * @since 30.0 + */ + public static final String SEC_CH_UA = "Sec-CH-UA"; + /** + * The HTTP {@code + * Sec-CH-UA-Arch} header field name. + * + * @since 30.0 + */ + public static final String SEC_CH_UA_ARCH = "Sec-CH-UA-Arch"; + /** + * The HTTP {@code + * Sec-CH-UA-Model} header field name. + * + * @since 30.0 + */ + public static final String SEC_CH_UA_MODEL = "Sec-CH-UA-Model"; + /** + * The HTTP {@code + * Sec-CH-UA-Platform} header field name. + * + * @since 30.0 + */ + public static final String SEC_CH_UA_PLATFORM = "Sec-CH-UA-Platform"; + /** + * The HTTP {@code + * Sec-CH-UA-Platform-Version} header field name. + * + * @since 30.0 + */ + public static final String SEC_CH_UA_PLATFORM_VERSION = "Sec-CH-UA-Platform-Version"; + /** + * The HTTP {@code + * Sec-CH-UA-Full-Version} header field name. + * + * @since 30.0 + */ + @Deprecated + public static final String SEC_CH_UA_FULL_VERSION = "Sec-CH-UA-Full-Version"; + /** + * The HTTP {@code + * Sec-CH-UA-Full-Version} header field name. + * + * @since 31.1 + */ + public static final String SEC_CH_UA_FULL_VERSION_LIST = "Sec-CH-UA-Full-Version-List"; + /** + * The HTTP {@code + * Sec-CH-UA-Mobile} header field name. + * + * @since 30.0 + */ + public static final String SEC_CH_UA_MOBILE = "Sec-CH-UA-Mobile"; + /** + * The HTTP {@code + * Sec-CH-UA-WoW64} header field name. + * + * @since 32.0.0 + */ + public static final String SEC_CH_UA_WOW64 = "Sec-CH-UA-WoW64"; + /** + * The HTTP {@code + * Sec-CH-UA-Bitness} header field name. + * + * @since 31.0 + */ + public static final String SEC_CH_UA_BITNESS = "Sec-CH-UA-Bitness"; + /** + * The HTTP {@code + * Sec-CH-UA-Form-Factor} header field name. + * + * @since 32.0.0 + */ + public static final String SEC_CH_UA_FORM_FACTOR = "Sec-CH-UA-Form-Factor"; + /** + * The HTTP {@code + * Sec-CH-Viewport-Width} header field name. + * + * @since 32.0.0 + */ + public static final String SEC_CH_VIEWPORT_WIDTH = "Sec-CH-Viewport-Width"; + /** + * The HTTP {@code + * Sec-CH-Viewport-Height} header field name. + * + * @since 32.0.0 + */ + public static final String SEC_CH_VIEWPORT_HEIGHT = "Sec-CH-Viewport-Height"; + /** + * The HTTP {@code + * Sec-CH-DPR} header field name. + * + * @since 32.0.0 + */ + public static final String SEC_CH_DPR = "Sec-CH-DPR"; + /** + * The HTTP {@code Sec-Fetch-Dest} + * header field name. + * + * @since 27.1 + */ + public static final String SEC_FETCH_DEST = "Sec-Fetch-Dest"; + /** + * The HTTP {@code Sec-Fetch-Mode} + * header field name. + * + * @since 27.1 + */ + public static final String SEC_FETCH_MODE = "Sec-Fetch-Mode"; + /** + * The HTTP {@code Sec-Fetch-Site} + * header field name. + * + * @since 27.1 + */ + public static final String SEC_FETCH_SITE = "Sec-Fetch-Site"; + /** + * The HTTP {@code Sec-Fetch-User} + * header field name. + * + * @since 27.1 + */ + public static final String SEC_FETCH_USER = "Sec-Fetch-User"; + /** + * The HTTP {@code Sec-Metadata} + * header field name. + * + * @since 26.0 + */ + public static final String SEC_METADATA = "Sec-Metadata"; + /** + * The HTTP {@code + * Sec-Token-Binding} header field name. + * + * @since 25.1 + */ + public static final String SEC_TOKEN_BINDING = "Sec-Token-Binding"; + /** + * The HTTP {@code + * Sec-Provided-Token-Binding-ID} header field name. + * + * @since 25.1 + */ + public static final String SEC_PROVIDED_TOKEN_BINDING_ID = "Sec-Provided-Token-Binding-ID"; + /** + * The HTTP {@code + * Sec-Referred-Token-Binding-ID} header field name. + * + * @since 25.1 + */ + public static final String SEC_REFERRED_TOKEN_BINDING_ID = "Sec-Referred-Token-Binding-ID"; + /** + * The HTTP {@code Sec-WebSocket-Accept} header + * field name. + * + * @since 28.0 + */ + public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept"; + /** + * The HTTP {@code Sec-WebSocket-Extensions} + * header field name. + * + * @since 28.0 + */ + public static final String SEC_WEBSOCKET_EXTENSIONS = "Sec-WebSocket-Extensions"; + /** + * The HTTP {@code Sec-WebSocket-Key} header + * field name. + * + * @since 28.0 + */ + public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key"; + /** + * The HTTP {@code Sec-WebSocket-Protocol} + * header field name. + * + * @since 28.0 + */ + public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol"; + /** + * The HTTP {@code Sec-WebSocket-Version} header + * field name. + * + * @since 28.0 + */ + public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version"; + /** + * The HTTP {@code + * Sec-Browsing-Topics} header field name. + * + * @since 32.0.0 + */ + public static final String SEC_BROWSING_TOPICS = "Sec-Browsing-Topics"; + /** + * The HTTP {@code + * Observe-Browsing-Topics} header field name. + * + * @since 32.0.0 + */ + public static final String OBSERVE_BROWSING_TOPICS = "Observe-Browsing-Topics"; + + /** + * The HTTP {@code + * Sec-Ad-Auction-Fetch} header field name. + * + * @since 33.0.0 + */ + public static final String SEC_AD_AUCTION_FETCH = "Sec-Ad-Auction-Fetch"; + + /** + * The HTTP {@code + * Sec-GPC} header field name. + * + * @since 33.2.0 + */ + public static final String SEC_GPC = "Sec-GPC"; + + /** + * The HTTP {@code + * Ad-Auction-Signals} header field name. + * + * @since 33.0.0 + */ + public static final String AD_AUCTION_SIGNALS = "Ad-Auction-Signals"; + + /** + * The HTTP {@code + * Ad-Auction-Allowed} header field name. + * + * @since 33.2.0 + */ + public static final String AD_AUCTION_ALLOWED = "Ad-Auction-Allowed"; + + /** + * The HTTP {@code CDN-Loop} header field name. + * + * @since 28.0 + */ + public static final String CDN_LOOP = "CDN-Loop"; +} diff --git a/plugin/src/main/groovy/org/unify4j/model/enums/AuthType.java b/plugin/src/main/groovy/org/unify4j/model/enums/AuthType.java new file mode 100644 index 0000000..7790d9d --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/model/enums/AuthType.java @@ -0,0 +1,6 @@ +package org.unify4j.model.enums; + +public enum AuthType { + + BASIC, BEARER, API_KEY, OAUTH2, OAUTH2_CLIENT_CREDENTIALS, DIGEST +} diff --git a/plugin/src/main/groovy/org/unify4j/model/onlyrd/AbstractAuthClass.java b/plugin/src/main/groovy/org/unify4j/model/onlyrd/AbstractAuthClass.java new file mode 100644 index 0000000..8407a25 --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/model/onlyrd/AbstractAuthClass.java @@ -0,0 +1,119 @@ +package org.unify4j.model.onlyrd; + +import org.unify4j.model.enums.AuthType; +import org.unify4j.model.response.WrapResponse; +import org.unify4j.service.AuthFactory; + +import java.util.Map; + +public abstract class AbstractAuthClass { + + protected AuthType type; + protected AuthFactory factory; + protected String username; + protected String password; + protected String token; + protected String apiKey; + protected String headerNameApiKey; + protected String clientId; + protected String clientSecret; + protected String accessToken; + protected String refreshToken; + + public AuthType getType() { + return this.type; + } + + public abstract WrapResponse verify(); + + public abstract Map getHeaders(); + + public abstract String toString(); + + protected AbstractAuthClass(Builder builder) { + this.type = builder.type; + this.factory = builder.factory; + this.username = builder.username; + this.password = builder.password; + this.token = builder.token; + this.apiKey = builder.apiKey; + this.headerNameApiKey = builder.headerNameApiKey; + this.clientId = builder.clientId; + this.clientSecret = builder.clientSecret; + this.accessToken = builder.accessToken; + this.refreshToken = builder.refreshToken; + } + + public static abstract class Builder { + private AuthType type; + private AuthFactory factory; + private String username; + private String password; + private String token; + private String apiKey; + private String headerNameApiKey; + private String clientId; + private String clientSecret; + private String accessToken; + private String refreshToken; + + public abstract AbstractAuthClass build(); + + protected abstract T self(); + + public T type(AuthType type) { + this.type = type; + return this.self(); + } + + public T factory(AuthFactory factory) { + this.factory = factory; + return this.self(); + } + + public T username(String username) { + this.username = username; + return this.self(); + } + + public T password(String password) { + this.password = password; + return this.self(); + } + + public T token(String token) { + this.token = token; + return this.self(); + } + + public T apiKey(String apiKey) { + this.apiKey = apiKey; + return this.self(); + } + + public T headerNameApiKey(String value) { + this.headerNameApiKey = value; + return this.self(); + } + + public T clientId(String clientId) { + this.clientId = clientId; + return this.self(); + } + + public T clientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this.self(); + } + + public T accessToken(String accessToken) { + this.accessToken = accessToken; + return this.self(); + } + + public T refreshToken(String refreshToken) { + this.refreshToken = refreshToken; + return this.self(); + } + } +} diff --git a/plugin/src/main/groovy/org/unify4j/service/AuthFactory.java b/plugin/src/main/groovy/org/unify4j/service/AuthFactory.java new file mode 100644 index 0000000..82683fb --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/service/AuthFactory.java @@ -0,0 +1,6 @@ +package org.unify4j.service; + +public interface AuthFactory { + + String retrieveAccessToken(String clientId, String clientSecret); +} diff --git a/plugin/src/test/groovy/org/unify4j/Auth4jTest.java b/plugin/src/test/groovy/org/unify4j/Auth4jTest.java new file mode 100644 index 0000000..37800b5 --- /dev/null +++ b/plugin/src/test/groovy/org/unify4j/Auth4jTest.java @@ -0,0 +1,155 @@ +package org.unify4j; + +import org.junit.Before; +import org.junit.Test; +import org.unify4j.common.Auth4j; +import org.unify4j.model.enums.AuthType; +import org.unify4j.model.response.WrapResponse; +import org.unify4j.service.AuthFactory; + +import java.util.Map; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class Auth4jTest { + private Auth4j auth4j; + private AuthFactory mockFactory; + + @Before + public void setUp() { + mockFactory = new AuthFactory() { + @Override + public String retrieveAccessToken(String clientId, String clientSecret) { + return "validAccessToken"; + } + }; + } + + @Test + public void testBasicAuthWithValidCredentials() { + auth4j = new Auth4j.Builder().type(AuthType.BASIC).username("user").password("pass").build(); + + WrapResponse response = auth4j.verify(); + assertTrue(response.isSuccess()); + + Map headers = auth4j.getHeaders(); + assertTrue(headers.containsKey("Authorization")); + } + + @Test + public void testBasicAuthWithMissingUsername() { + auth4j = new Auth4j.Builder().type(AuthType.BASIC).password("pass").build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testBasicAuthWithMissingPassword() { + auth4j = new Auth4j.Builder().type(AuthType.BASIC).username("user").build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testBearerAuthWithValidToken() { + auth4j = new Auth4j.Builder().type(AuthType.BEARER).token("validToken").build(); + + WrapResponse response = auth4j.verify(); + assertTrue(response.isSuccess()); + + Map headers = auth4j.getHeaders(); + assertTrue(headers.containsKey("Authorization")); + } + + @Test + public void testBearerAuthWithMissingToken() { + auth4j = new Auth4j.Builder().type(AuthType.BEARER).build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testApiKeyAuthWithValidApiKey() { + auth4j = new Auth4j.Builder().type(AuthType.API_KEY).headerNameApiKey("X-API-KEY").apiKey("validApiKey").build(); + + WrapResponse response = auth4j.verify(); + assertTrue(response.isSuccess()); + + Map headers = auth4j.getHeaders(); + assertTrue(headers.containsKey("X-API-KEY")); + } + + @Test + public void testApiKeyAuthWithMissingHeaderName() { + auth4j = new Auth4j.Builder().type(AuthType.API_KEY).apiKey("validApiKey").build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testApiKeyAuthWithMissingApiKey() { + auth4j = new Auth4j.Builder().type(AuthType.API_KEY).headerNameApiKey("X-API-KEY").build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testOAuth2AuthWithValidAccessToken() { + auth4j = new Auth4j.Builder().type(AuthType.OAUTH2).accessToken("validAccessToken").build(); + + WrapResponse response = auth4j.verify(); + assertTrue(response.isSuccess()); + + Map headers = auth4j.getHeaders(); + assertTrue(headers.containsKey("Authorization")); + } + + @Test + public void testOAuth2AuthWithMissingAccessToken() { + auth4j = new Auth4j.Builder().type(AuthType.OAUTH2).build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testOAuth2ClientCredentialsAuthWithValidCredentials() { + auth4j = new Auth4j.Builder().type(AuthType.OAUTH2_CLIENT_CREDENTIALS).factory(mockFactory).clientId("clientId").clientSecret("clientSecret").build(); + + WrapResponse response = auth4j.verify(); + assertTrue(response.isSuccess()); + + Map headers = auth4j.getHeaders(); + assertTrue(headers.containsKey("Authorization")); + } + + @Test + public void testOAuth2ClientCredentialsAuthWithMissingFactory() { + auth4j = new Auth4j.Builder().type(AuthType.OAUTH2_CLIENT_CREDENTIALS).clientId("clientId").clientSecret("clientSecret").build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testOAuth2ClientCredentialsAuthWithMissingClientId() { + auth4j = new Auth4j.Builder().type(AuthType.OAUTH2_CLIENT_CREDENTIALS).factory(mockFactory).clientSecret("clientSecret").build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } + + @Test + public void testOAuth2ClientCredentialsAuthWithMissingClientSecret() { + auth4j = new Auth4j.Builder().type(AuthType.OAUTH2_CLIENT_CREDENTIALS).factory(mockFactory).clientId("clientId").build(); + + WrapResponse response = auth4j.verify(); + assertFalse(response.isSuccess()); + } +}