From 795c9fef4483a937a128faafc3205e02cbed69b3 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Fri, 28 Feb 2025 10:21:57 -0500 Subject: [PATCH 1/3] added header-based auth filter --- .../rs/HeaderAuthorizationFilter.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java diff --git a/src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java b/src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java new file mode 100644 index 0000000..8347950 --- /dev/null +++ b/src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java @@ -0,0 +1,58 @@ +/* + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package com.inteligr8.rs; + +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Map.Entry; + +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import jakarta.ws.rs.client.ClientRequestContext; + +/** + * This class implements a header-based authorization filter. + * + * @author brian@inteligr8.com + */ +public class HeaderAuthorizationFilter implements AuthorizationFilter { + + private final MultiValueMap headers = new LinkedMultiValueMap<>(); + + /** + * @param headers An array of header name/value pairs. + */ + public HeaderAuthorizationFilter(String headerName, String headerValue) { + this.headers.add(headerName, headerValue); + } + + public HeaderAuthorizationFilter add(String headerName, String headerValue) { + this.headers.add(headerName, headerValue); + return this; + } + + /** + * This method applies the 'Authorization' header to the {@link ClientRequestContext}. + * + * @param requestContext A request context. + */ + @Override + public void filter(ClientRequestContext requestContext) throws UnsupportedEncodingException { + for (Entry> header : this.headers.entrySet()) + requestContext.getHeaders().addAll(header.getKey(), header.getValue()); + } + +} From e9bc1919454f77fa9968fa7c41418e01aaaf0ce5 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Fri, 28 Feb 2025 11:07:55 -0500 Subject: [PATCH 2/3] updated javadocs --- .../rs/BasicAuthorizationFilter.java | 2 + .../rs/BearerTokenAuthorizationFilter.java | 2 + src/main/java/com/inteligr8/rs/Client.java | 43 ++++++--- .../com/inteligr8/rs/ClientConfiguration.java | 93 +++++++++++++++---- .../java/com/inteligr8/rs/ClientImpl.java | 23 +---- .../rs/ForwardingAuthorizationFilter.java | 2 + .../rs/HeaderAuthorizationFilter.java | 12 ++- 7 files changed, 128 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/inteligr8/rs/BasicAuthorizationFilter.java b/src/main/java/com/inteligr8/rs/BasicAuthorizationFilter.java index 0d11761..f676839 100755 --- a/src/main/java/com/inteligr8/rs/BasicAuthorizationFilter.java +++ b/src/main/java/com/inteligr8/rs/BasicAuthorizationFilter.java @@ -34,6 +34,8 @@ public class BasicAuthorizationFilter implements AuthorizationFilter { private final String password; /** + * This constructor instantiates the filter with required fields. + * * @param username A username or access key. * @param password A password or secret key. */ diff --git a/src/main/java/com/inteligr8/rs/BearerTokenAuthorizationFilter.java b/src/main/java/com/inteligr8/rs/BearerTokenAuthorizationFilter.java index 84fb6a5..716265c 100755 --- a/src/main/java/com/inteligr8/rs/BearerTokenAuthorizationFilter.java +++ b/src/main/java/com/inteligr8/rs/BearerTokenAuthorizationFilter.java @@ -32,6 +32,8 @@ public class BearerTokenAuthorizationFilter implements AuthorizationFilter { private final String token; /** + * This constructor instantiates the filter with required fields. + * * @param token A 'Bearer' token. */ public BearerTokenAuthorizationFilter(String token) { diff --git a/src/main/java/com/inteligr8/rs/Client.java b/src/main/java/com/inteligr8/rs/Client.java index 2af9cbf..2c1c84e 100644 --- a/src/main/java/com/inteligr8/rs/Client.java +++ b/src/main/java/com/inteligr8/rs/Client.java @@ -26,7 +26,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider; /** - * A class that provides pre-configured JAX-RS Client & WebTarget objects. + * A class that provides pre-configured Jakarta RS Client & WebTarget objects. * * @author brian@inteligr8.com */ @@ -36,12 +36,17 @@ public abstract class Client { private jakarta.ws.rs.client.Client client; /** + * This method retrieves the configuration for the client. + * * @return The client configuration. */ public abstract ClientConfiguration getConfig(); /** - * @return A pre-configured JAX-RS client (no URL) with configured authorization. + * This method retrieves an anonymous cached instance of the underlying + * Jakarta RS client. + * + * @return A pre-configured Jakarta RS client (no URL) with configured authorization. */ public final jakarta.ws.rs.client.Client getClient() { synchronized (this.sync) { @@ -53,8 +58,11 @@ public abstract class Client { } /** + * This method retrieves either an anonymous cached instance or builds an + * authorized instance of the underlying Jakarta RS client. + * * @param authFilter A dynamic authorization filter. - * @return A pre-configured JAX-RS client (no URL) with the specified authorization. + * @return A pre-configured Jakarta RS client (no URL) with the specified authorization. */ public jakarta.ws.rs.client.Client getClient(AuthorizationFilter authFilter) { if (authFilter == null) { @@ -65,8 +73,10 @@ public abstract class Client { } /** + * This method builds a new Jakarta RS client with optional authorization. + * * @param authFilter A dynamic authorization filter. - * @return A pre-configured JAX-RS client (no URL) with the specified authorization. + * @return A pre-configured Jakarta RS client (no URL) with the specified authorization. */ public final jakarta.ws.rs.client.Client buildClient(AuthorizationFilter authFilter) { ObjectMapper om = new ObjectMapper(); @@ -101,14 +111,19 @@ public abstract class Client { } /** - * @param clientBuilder A client builder + * This method allows sub-classes to extend the Jakarta RS client builder + * before the client is built. + * + * @param clientBuilder A Jakarta RS client builder. */ public void buildClient(ClientBuilder clientBuilder) { // for extension purposes } /** - * @return A pre-configured JAX-RS target (client w/ base URL) with configured authorization. + * This method builds an anonymous Jakarta RS target. + * + * @return A pre-configured Jakarta RS target (client w/ base URL) with configured authorization. */ public final WebTarget getTarget() { return this.getClient() @@ -116,8 +131,10 @@ public abstract class Client { } /** + * This method builds an authorized Jakarta RS target. + * * @param authFilter A dynamic authorization filter. - * @return A pre-configured JAX-RS target (client w/ base URL) with the specified authorization. + * @return A pre-configured Jakarta RS target (client w/ base URL) with the specified authorization. */ public WebTarget getTarget(AuthorizationFilter authFilter) { if (authFilter == null) { @@ -129,10 +146,10 @@ public abstract class Client { } /** - * This method retrieves a JAX-RS implementation of the specified API. + * This method retrieves a Jakarta RS implementation of the specified API. * - * @param A JAX-RS annotated API class. - * @param apiClass A JAX-RS annotated API class. + * @param A Jakarta RS annotated API class. + * @param apiClass A Jakarta RS annotated API class. * @return An instance of the API class. */ public final T getApi(Class apiClass) { @@ -140,12 +157,12 @@ public abstract class Client { } /** - * This method retrieves a JAX-RS implementation of the specified API with + * This method retrieves a Jakarta RS implementation of the specified API with * the specified authorization. * - * @param A JAX-RS annotated API class. + * @param A Jakarta RS annotated API class. * @param authFilter A dynamic authorization filter. - * @param apiClass A JAX-RS annotated API class. + * @param apiClass A Jakarta RS annotated API class. * @return An instance of the API class. */ public abstract T getApi(AuthorizationFilter authFilter, Class apiClass); diff --git a/src/main/java/com/inteligr8/rs/ClientConfiguration.java b/src/main/java/com/inteligr8/rs/ClientConfiguration.java index 9eda168..2db8a1f 100644 --- a/src/main/java/com/inteligr8/rs/ClientConfiguration.java +++ b/src/main/java/com/inteligr8/rs/ClientConfiguration.java @@ -30,89 +30,127 @@ import jakarta.ws.rs.client.ClientBuilder; public interface ClientConfiguration { /** - * @return The base or root URL of the service. + * This method retrieves the base/root URL of the client service. + * + * @return The URL. */ String getBaseUrl(); /** - * @return The username for BASIC authentication. + * This method retrieves the username to use in HTTP BASIC authentication/authorization. + * + * @return A username. */ default String getBasicAuthUsername() { return null; } /** - * @return The corresponding password for the username in BASIC authentication. + * This method retrieves the password to use in HTTP BASIC authentication/authorization. + * + * @return The corresponding password for the username. */ default String getBasicAuthPassword() { return null; } /** - * @return The client ID for Client Enforcement authentication. + * This method retrieves the client identifier to use in Client Enforcement authorization. + * + * @return A client identifier. */ default String getClientId() { return null; } /** - * @return The corresponding client secret for the client ID in Client Enforcement authentication. + * This method retrieves the client secret to use in Client Enforcement authorization. + * + * @return The corresponding client secret for the client identifier. */ default String getClientSecret() { return null; } /** - * @return The token for BEARER authorization. + * This method retrieves the token to use in HTTP BEARER authorization. + * This is provided in a response to the token URL. + * + * @return An access token. */ default String getBearerToken() { return null; } /** - * @return The token URL for OAuth authorization. + * This method retrieves the token URL to use for OAuth authorization. + * The value can be pulled from OAuth endpoint well-known meta-data. That + * endpoint or the token URL itself may also be provided OAuth IdP + * administrator. + * + * @return An OAuth token URL. */ default String getOAuthTokenUrl() { return null; } /** - * @return The client ID provided by the OAuth IdP administrator. + * This method retrieves the client identifier to use in OAuth + * authorization. This is provided by the OAuth IdP administrator or + * tooling. + * + * @return A client identifier. */ default String getOAuthClientId() { return this.getClientId(); } /** - * @return The corresponding client secret for the client ID provided by the OAuth IdP administrator. + * This method retrieves the client secret to use in OAuth authorization. + * This is provided by the OAuth IdP administrator or tooling. + * + * @return The corresponding client secret for the client identifier. */ default String getOAuthClientSecret() { return this.getClientSecret(); } /** - * @return The authorization code used in the OAuth Authorization Code flow. + * This method retrieves the authorization code to use in OAuth + * Authorization Code flow. This is provided by the OAuth IdP + * administrator or tooling. + * + * @return An authorization code. */ default String getOAuthAuthCode() { return null; } /** - * @return The redirect URL used in the OAuth Authorization Code flow. + * This method retrieves the redirect URL to use in OAuth Authorization + * Code flow. This has meaning to the client-side web application. + * + * @return A URL for the OAuth flow to redirect to when complete. */ default String getOAuthAuthRedirectUri() { return null; } /** - * @return The username used in the OAuth Password Grant flow. + * This method retrieves the username to use in OAuth Password Grant flow. + * This is provided by the OAuth IdP administrator or tooling. + * + * @return A username. */ default String getOAuthUsername() { return null; } /** - * @return The corresponding password for the username used in the OAuth Password Grant flow. + * This method retrieves the password to use in OAuth Password Grant flow. + * This is provided by the OAuth IdP administrator or tooling. + * + * @return The corresponding password for the username. */ default String getOAuthPassword() { return null; @@ -120,10 +158,22 @@ public interface ClientConfiguration { + /** + * This method retrieves the connection (before request sent) timeout for + * the client. + * + * @return A timeout in milliseconds. + */ default Integer getConnectTimeoutInMillis() { return null; } + /** + * This method retrieves the response (after request sent) timeout for the + * client. + * + * @return A timeout in milliseconds. + */ default Integer getResponseTimeoutInMillis() { return null; } @@ -131,27 +181,36 @@ public interface ClientConfiguration { /** - * @return true to enable Jackson UNWRAP_ROOT_VALUE feature; false otherwise. + * This method enables/disables the JackSON UNWRAP_ROOT_VALUE feature. + * + * @return `true` to enable; `false` otherwise. */ default boolean isUnwrapRootValueEnabled() { return false; } /** - * @return true to enable Jackson WRAP_ROOT_VALUE feature; false otherwise. + * This method enables/disables the JackSON WRAP_ROOT_VALUE feature. + * + * @return `true` to enable; `false` otherwise. */ default boolean isWrapRootValueEnabled() { return false; } /** - * @param mapper A Jackson object mapper to configure. + * This method allows sub-classes to extend the JackSON mapper + * configuration and behavior. + * + * @param mapper A JackSON object mapper. */ default void configureJacksonMapper(ObjectMapper mapper) { } /** - * @param provider A Jackson Jakarta RS provider to configure. + * This method allows sub-classes to extend the JackSON JSON provider. + * + * @param provider A JackSON Jakarta RS provider. */ default void configureJacksonProvider(JacksonJsonProvider provider) { } diff --git a/src/main/java/com/inteligr8/rs/ClientImpl.java b/src/main/java/com/inteligr8/rs/ClientImpl.java index 3606f3f..0bb5f29 100644 --- a/src/main/java/com/inteligr8/rs/ClientImpl.java +++ b/src/main/java/com/inteligr8/rs/ClientImpl.java @@ -21,8 +21,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * A class that provides pre-configured JAX-RS Client & WebTarget objects - * for Jersey. + * A class that provides pre-configured Jakarta RS Client & WebTarget + * objects. * * @author brian@inteligr8.com */ @@ -34,6 +34,7 @@ public class ClientImpl extends Client { /** * This constructor is for Spring or POJO use. + * * @param config The client configuration. */ public ClientImpl(ClientConfiguration config) { @@ -41,36 +42,22 @@ public class ClientImpl extends Client { } /** - * This method registers the Jersey library as the default provider for the - * JAX-RS specification. + * This method is a placeholder. */ @PostConstruct public void register() { this.logger.info("API Base URL: {}", this.getConfig().getBaseUrl()); } - /** - * @param clientBuilder A client builder. - */ @Override public void buildClient(ClientBuilder clientBuilder) { } - /** - * @return The client configuration. - */ + @Override public ClientConfiguration getConfig() { return this.config; } - /** - * This method retrieves a JAX-RS implementation of the specified API with - * the specified authorization. - * - * @param authFilter A dynamic authorization filter. - * @param apiClass A JAX-RS annotation API class. - * @return An instance of the API class. - */ @Override public T getApi(AuthorizationFilter authFilter, Class apiClass) { throw new UnsupportedOperationException(); diff --git a/src/main/java/com/inteligr8/rs/ForwardingAuthorizationFilter.java b/src/main/java/com/inteligr8/rs/ForwardingAuthorizationFilter.java index 94c5338..dc4750c 100755 --- a/src/main/java/com/inteligr8/rs/ForwardingAuthorizationFilter.java +++ b/src/main/java/com/inteligr8/rs/ForwardingAuthorizationFilter.java @@ -32,6 +32,8 @@ public class ForwardingAuthorizationFilter implements AuthorizationFilter { private final String authorizationHeaderValue; /** + * This constructor instantiates the filter with required fields. + * * @param authorizationHeaderValue A previously used or formulated 'Authorization' header. */ public ForwardingAuthorizationFilter(String authorizationHeaderValue) { diff --git a/src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java b/src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java index 8347950..dae994b 100644 --- a/src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java +++ b/src/main/java/com/inteligr8/rs/HeaderAuthorizationFilter.java @@ -33,12 +33,22 @@ public class HeaderAuthorizationFilter implements AuthorizationFilter { private final MultiValueMap headers = new LinkedMultiValueMap<>(); /** - * @param headers An array of header name/value pairs. + * This constructor instantiates the filter with required fields. + * + * @param headerName A header name. + * @param headerValue A header value. */ public HeaderAuthorizationFilter(String headerName, String headerValue) { this.headers.add(headerName, headerValue); } + /** + * This method adds another header name/value to outgoing requests. + * + * @param headerName A header name. + * @param headerValue A header value. + * @return This class for fluent chaining. + */ public HeaderAuthorizationFilter add(String headerName, String headerValue) { this.headers.add(headerName, headerValue); return this; From 52cffffa8e76a0d3a36cb15f7fdbe238f3b37653 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Fri, 28 Feb 2025 11:10:17 -0500 Subject: [PATCH 3/3] upgrade maven plugins --- pom.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index fe1897a..7221a72 100644 --- a/pom.xml +++ b/pom.xml @@ -43,9 +43,9 @@ 11 11 - 5.10.0 - 6.0.19 - 2.17.2 + 5.12.0 + 6.0.23 + 2.17.3 @@ -77,12 +77,12 @@ org.apache.commons commons-lang3 - 3.14.0 + 3.17.0 org.slf4j slf4j-api - 2.0.13 + 2.0.17 jakarta.ws.rs @@ -113,7 +113,7 @@ maven-surefire-plugin - 3.1.0 + 3.4.0 org.junit.jupiter @@ -124,7 +124,7 @@ maven-failsafe-plugin - 3.1.0 + 3.4.0 org.junit.jupiter @@ -180,7 +180,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.13 + 1.6.14 ossrh https://s01.oss.sonatype.org/