Compare commits
	
		
			44 Commits
		
	
	
		
			v2.0.1-cxf
			...
			v2.0.10-cx
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5e3e9080a9 | |||
| dfb039dc17 | |||
| bedc424ab5 | |||
| b4d6c1c72c | |||
| 2cd9cc9484 | |||
| 618d008a37 | |||
| 303af956cb | |||
| ec4ffbee43 | |||
| eb654c5488 | |||
| 8c9cbecd53 | |||
| 81198de0fb | |||
| 803d49e53e | |||
| adad70d884 | |||
| d29ccbef79 | |||
| 26c37ab737 | |||
| 4de7968e11 | |||
| 378563560b | |||
| f84279a148 | |||
| d23a4249f7 | |||
| 8628d2dce8 | |||
| e4e393a855 | |||
| c7ce4e7c57 | |||
| 44e82b3a6b | |||
| ab920aedd7 | |||
| ab6b0d8da7 | |||
| 458cdad213 | |||
| 8b03d251e8 | |||
| a1acb3f9d9 | |||
| c25988fc8f | |||
| 00f25ff054 | |||
| 003afc208e | |||
| 85df5d3ea4 | |||
| 9a9a958913 | |||
| 37e8b63179 | |||
| 255a9c8e85 | |||
| c9833bb4b1 | |||
| bcb7d4a7ed | |||
| 23b9c4ccb2 | |||
| 6bb1561825 | |||
| 0ce2369452 | |||
| ae82bc4ec7 | |||
| 8b13f06667 | |||
| 964cec0fb5 | |||
| fe2e04f3af | 
							
								
								
									
										50
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -6,7 +6,7 @@ | ||||
| 	 | ||||
| 	<groupId>com.inteligr8</groupId> | ||||
| 	<artifactId>common-rest-client</artifactId> | ||||
| 	<version>2.0.1-cxf</version> | ||||
| 	<version>2.0.10-cxf</version> | ||||
| 	<packaging>jar</packaging> | ||||
|  | ||||
| 	<name>ReST API Client for Java</name> | ||||
| @@ -44,8 +44,9 @@ | ||||
| 		<maven.compiler.target>8</maven.compiler.target> | ||||
|  | ||||
| 		<junit.version>5.7.2</junit.version> | ||||
| 		<spring.version>5.2.14.RELEASE</spring.version> | ||||
| 		<cxf.version>3.3.2</cxf.version> | ||||
| 		<spring.version>5.3.27</spring.version> | ||||
| 		<jackson.version>2.15.1</jackson.version> | ||||
| 		<cxf.version>3.5.6</cxf.version> | ||||
| 	</properties> | ||||
|  | ||||
| 	<dependencies> | ||||
| @@ -57,22 +58,27 @@ | ||||
| 		<dependency> | ||||
| 			<groupId>com.fasterxml.jackson.core</groupId> | ||||
| 			<artifactId>jackson-databind</artifactId> | ||||
| 			<version>2.12.2</version> | ||||
| 			<version>${jackson.version}</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>com.fasterxml.jackson.jaxrs</groupId> | ||||
| 			<artifactId>jackson-jaxrs-json-provider</artifactId> | ||||
| 			<version>2.12.2</version> | ||||
| 			<version>${jackson.version}</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>com.fasterxml.jackson.datatype</groupId> | ||||
| 			<artifactId>jackson-datatype-jsr310</artifactId> | ||||
| 			<version>2.12.2</version> | ||||
| 			<version>${jackson.version}</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.apache.commons</groupId> | ||||
| 			<artifactId>commons-lang3</artifactId> | ||||
| 			<version>3.14.0</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.slf4j</groupId> | ||||
| 			<artifactId>slf4j-api</artifactId> | ||||
| 			<version>1.7.29</version> | ||||
| 			<version>1.7.36</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>jakarta.ws.rs</groupId> | ||||
| @@ -94,7 +100,7 @@ | ||||
| 		<dependency> | ||||
| 			<groupId>org.apache.httpcomponents</groupId> | ||||
| 			<artifactId>httpclient</artifactId> | ||||
| 			<version>4.5.9</version> | ||||
| 			<version>4.5.14</version> | ||||
| 			<scope>test</scope> | ||||
| 		</dependency> | ||||
| 		 | ||||
| @@ -111,7 +117,7 @@ | ||||
| 			<plugin> | ||||
| 				<groupId>org.codehaus.mojo</groupId> | ||||
| 				<artifactId>build-helper-maven-plugin</artifactId> | ||||
| 				<version>3.2.0</version> | ||||
| 				<version>3.4.0</version> | ||||
| 				<executions> | ||||
| 					<execution> | ||||
| 						<id>add-jaxrs-src</id> | ||||
| @@ -135,7 +141,7 @@ | ||||
| 			</plugin> | ||||
| 			<plugin> | ||||
| 				<artifactId>maven-surefire-plugin</artifactId> | ||||
| 				<version>3.0.0-M5</version> | ||||
| 				<version>3.1.0</version> | ||||
| 				<dependencies> | ||||
| 					<dependency> | ||||
| 						<groupId>org.junit.jupiter</groupId> | ||||
| @@ -146,7 +152,7 @@ | ||||
| 			</plugin> | ||||
| 			<plugin> | ||||
| 				<artifactId>maven-failsafe-plugin</artifactId> | ||||
| 				<version>3.0.0-M5</version> | ||||
| 				<version>3.1.0</version> | ||||
| 				<dependencies> | ||||
| 					<dependency> | ||||
| 						<groupId>org.junit.jupiter</groupId> | ||||
| @@ -155,6 +161,17 @@ | ||||
| 					</dependency> | ||||
| 				</dependencies> | ||||
| 			</plugin> | ||||
| 		</plugins> | ||||
| 	</build> | ||||
|  | ||||
| 	<profiles> | ||||
| 		<profile> | ||||
| 			<id>ossrh-release</id> | ||||
| 			<properties> | ||||
| 				<maven.deploy.skip>true</maven.deploy.skip> | ||||
| 			</properties> | ||||
| 			<build> | ||||
| 				<plugins> | ||||
| 					<plugin> | ||||
| 						<artifactId>maven-source-plugin</artifactId> | ||||
| 						<executions> | ||||
| @@ -178,17 +195,6 @@ | ||||
| 							</execution> | ||||
| 						</executions> | ||||
| 					</plugin> | ||||
| 		</plugins> | ||||
| 	</build> | ||||
|  | ||||
| 	<profiles> | ||||
| 		<profile> | ||||
| 			<id>ossrh-release</id> | ||||
| 			<properties> | ||||
| 				<maven.deploy.skip>true</maven.deploy.skip> | ||||
| 			</properties> | ||||
| 			<build> | ||||
| 				<plugins> | ||||
| 					<plugin> | ||||
| 						<artifactId>maven-gpg-plugin</artifactId> | ||||
| 						<executions> | ||||
|   | ||||
| @@ -14,6 +14,8 @@ | ||||
|  */ | ||||
| package com.inteligr8.rs; | ||||
|  | ||||
| import org.apache.cxf.jaxrs.client.WebClient; | ||||
|  | ||||
| /** | ||||
|  * This interface defines additional configurations specific to the Apache CXF | ||||
|  * JAX-RS library and its nuances. | ||||
| @@ -35,4 +37,12 @@ public interface ClientCxfConfiguration extends ClientConfiguration { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
|     /** | ||||
|      * A Jackson provider, logging filter, and authentication filter are already registered. | ||||
|      *  | ||||
|      * @param client A CXF client to configure. | ||||
|      */ | ||||
| 	default void configureClient(WebClient client) { | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -24,11 +24,13 @@ import org.apache.cxf.BusFactory; | ||||
| import org.apache.cxf.jaxrs.client.JAXRSClientFactory; | ||||
| import org.apache.cxf.jaxrs.client.WebClient; | ||||
| import org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl; | ||||
| import org.apache.cxf.transport.http.HTTPConduit; | ||||
| import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; | ||||
| import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; | ||||
|  | ||||
| /** | ||||
| @@ -37,18 +39,18 @@ import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; | ||||
|  *  | ||||
|  * @author brian@inteligr8.com | ||||
|  */ | ||||
| @Component("client.cxf") | ||||
| public class ClientCxfImpl extends Client { | ||||
| 	 | ||||
| 	private final Logger logger = LoggerFactory.getLogger(ClientCxfImpl.class); | ||||
|  | ||||
|     private final Object sync = new Object(); | ||||
| 	private ClientCxfConfiguration config; | ||||
|     private WebClient client; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * This constructor is for Spring or POJO use. | ||||
| 	 * @param config The client configuration. | ||||
| 	 */ | ||||
| 	@Autowired | ||||
| 	public ClientCxfImpl(ClientCxfConfiguration config) { | ||||
| 		this.config = config; | ||||
| 	} | ||||
| @@ -77,16 +79,40 @@ public class ClientCxfImpl extends Client { | ||||
| 	 * @return A CXF client (not JAX-RS). | ||||
| 	 */ | ||||
| 	public WebClient getCxfClient() { | ||||
| 		return this.getCxfClient(null); | ||||
|         synchronized (this.sync) { | ||||
|             if (this.client == null) | ||||
|                 this.client = this.buildCxfClient(null); | ||||
|         } | ||||
|  | ||||
|         return this.client; | ||||
| 	} | ||||
|      | ||||
|     /** | ||||
|      * @param authFilter A dynamic authorization filter. | ||||
|      * @return A pre-configured CXF client (no URL) with the specified authorization. | ||||
|      */ | ||||
|     public WebClient getCxfClient(AuthorizationFilter authFilter) { | ||||
|         if (authFilter == null) { | ||||
|             return this.getCxfClient(); | ||||
|         } else { | ||||
|             return this.buildCxfClient(authFilter); | ||||
|         } | ||||
|     } | ||||
| 	 | ||||
| 	/** | ||||
| 	 * @param authFilter A post-configuration authorization filter. | ||||
| 	 * @return A CXF client (not JAX-RS). | ||||
| 	 */ | ||||
| 	public WebClient getCxfClient(AuthorizationFilter authFilter) { | ||||
| 	public WebClient buildCxfClient(AuthorizationFilter authFilter) { | ||||
|         ObjectMapper om = new ObjectMapper(); | ||||
|         om.registerModules(new JavaTimeModule()); | ||||
|         this.getConfig().configureJacksonMapper(om); | ||||
|  | ||||
|         JacksonJaxbJsonProvider jacksonProvider = new JacksonJaxbJsonProvider(om, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS); | ||||
|         this.getConfig().configureJacksonProvider(jacksonProvider); | ||||
|          | ||||
| 		List<Object> providersAndFilters = new LinkedList<Object>(); | ||||
| 		providersAndFilters.add(new JacksonJaxbJsonProvider()); | ||||
| 		providersAndFilters.add(jacksonProvider); | ||||
| 		providersAndFilters.add(new CxfLoggingFilter()); | ||||
| 		providersAndFilters.add(new CxfMultipartProvider()); | ||||
| 		 | ||||
| @@ -101,6 +127,17 @@ public class ClientCxfImpl extends Client { | ||||
| 		// so we need to create a CXF client | ||||
| 		WebClient client = WebClient.create(this.getConfig().getBaseUrl(), providersAndFilters); | ||||
|  | ||||
|         if (this.getConfig().getConnectTimeoutInMillis() != null || this.getConfig().getResponseTimeoutInMillis() != null) { | ||||
|             HTTPConduit conduit = client.getConfiguration().getHttpConduit(); | ||||
|     		HTTPClientPolicy policy = conduit.getClient(); | ||||
|     		if (policy == null) | ||||
|     		    conduit.setClient(policy = new HTTPClientPolicy()); | ||||
|     		if (this.getConfig().getConnectTimeoutInMillis() != null) | ||||
|     		    policy.setConnectionTimeout(this.getConfig().getConnectTimeoutInMillis()); | ||||
|             if (this.getConfig().getResponseTimeoutInMillis() != null) | ||||
|                 policy.setReceiveTimeout(this.getConfig().getResponseTimeoutInMillis()); | ||||
|         } | ||||
|  | ||||
| 		if (!this.getConfig().isDefaultBusEnabled()) { | ||||
| 			// Some applications (like ACS) add interceptors to the default bus | ||||
| 			// those interceptors may treat all messages as SOAP messages (like ACS), resulting in ClassCastExceptions | ||||
| @@ -109,6 +146,8 @@ public class ClientCxfImpl extends Client { | ||||
| 			config.setBus(BusFactory.newInstance().createBus()); | ||||
| 		} | ||||
| 		 | ||||
| 		this.config.configureClient(client); | ||||
| 		 | ||||
| 		return client; | ||||
| 	} | ||||
| 	 | ||||
|   | ||||
| @@ -20,6 +20,8 @@ import java.util.Base64; | ||||
| import javax.ws.rs.client.ClientRequestContext; | ||||
| import javax.ws.rs.core.HttpHeaders; | ||||
|  | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
|  | ||||
| /** | ||||
|  * This class implements a simple 2-credential (username & password) based | ||||
|  * authorization filter. | ||||
| @@ -36,8 +38,8 @@ public class BasicAuthorizationFilter implements AuthorizationFilter { | ||||
| 	 * @param password A password or secret key. | ||||
| 	 */ | ||||
| 	public BasicAuthorizationFilter(String username, String password) { | ||||
| 		this.username = username; | ||||
| 		this.password = password; | ||||
| 		this.username = StringUtils.trimToNull(username); | ||||
| 		this.password = StringUtils.trimToNull(password); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
|   | ||||
| @@ -14,13 +14,16 @@ | ||||
|  */ | ||||
| package com.inteligr8.rs; | ||||
|  | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| import javax.ws.rs.client.ClientBuilder; | ||||
| import javax.ws.rs.client.WebTarget; | ||||
|  | ||||
| import com.fasterxml.jackson.databind.DeserializationFeature; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.fasterxml.jackson.databind.SerializationFeature; | ||||
| import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; | ||||
| import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; | ||||
| import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; | ||||
|  | ||||
| /** | ||||
|  * A class that provides pre-configured JAX-RS Client & WebTarget objects. | ||||
| @@ -66,7 +69,12 @@ public abstract class Client { | ||||
| 	 * @return A pre-configured JAX-RS client (no URL) with the specified authorization. | ||||
| 	 */ | ||||
| 	public final javax.ws.rs.client.Client buildClient(AuthorizationFilter authFilter) { | ||||
| 		JacksonJsonProvider provider = new JacksonJaxbJsonProvider(); | ||||
| 	    ObjectMapper om = new ObjectMapper(); | ||||
| 	    om.registerModules(new JavaTimeModule()); | ||||
| 	    this.getConfig().configureJacksonMapper(om); | ||||
| 	     | ||||
| 	    JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider(om, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS); | ||||
| 		this.getConfig().configureJacksonProvider(provider); | ||||
|          | ||||
| 		if (this.getConfig().isWrapRootValueEnabled()) | ||||
| 			provider.enable(SerializationFeature.WRAP_ROOT_VALUE); | ||||
| @@ -77,11 +85,17 @@ public abstract class Client { | ||||
| 				.register(provider) | ||||
| 				.register(new LoggingFilter()); | ||||
| 		 | ||||
| 		if (this.getConfig().getConnectTimeoutInMillis() != null) | ||||
| 		    clientBuilder.connectTimeout(this.getConfig().getConnectTimeoutInMillis(), TimeUnit.MILLISECONDS); | ||||
|         if (this.getConfig().getResponseTimeoutInMillis() != null) | ||||
|             clientBuilder.readTimeout(this.getConfig().getResponseTimeoutInMillis(), TimeUnit.MILLISECONDS); | ||||
|  | ||||
| 		if (authFilter == null) | ||||
| 			authFilter = this.getConfig().createAuthorizationFilter(); | ||||
| 		if (authFilter != null) | ||||
| 			clientBuilder.register(authFilter); | ||||
| 		this.buildClient(clientBuilder); | ||||
| 		this.getConfig().configureClient(clientBuilder); | ||||
| 		 | ||||
| 		return clientBuilder.build(); | ||||
| 	} | ||||
|   | ||||
| @@ -16,6 +16,11 @@ package com.inteligr8.rs; | ||||
|  | ||||
| import java.net.URI; | ||||
|  | ||||
| import javax.ws.rs.client.ClientBuilder; | ||||
|  | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; | ||||
|  | ||||
| /** | ||||
|  * This interface defines the configurable parameters of the clients; primarily | ||||
|  * their default authentication and authorization. | ||||
| @@ -115,6 +120,16 @@ public interface ClientConfiguration { | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	default Integer getConnectTimeoutInMillis() { | ||||
| 	    return null; | ||||
| 	} | ||||
| 	 | ||||
| 	default Integer getResponseTimeoutInMillis() { | ||||
| 	    return null; | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	/** | ||||
| 	 * @return true to enable Jackson UNWRAP_ROOT_VALUE feature; false otherwise. | ||||
| 	 */ | ||||
| @@ -129,6 +144,18 @@ public interface ClientConfiguration { | ||||
| 		return false; | ||||
| 	} | ||||
|      | ||||
|     /** | ||||
|      * @param mapper A Jackson object mapper to configure. | ||||
|      */ | ||||
|     default void configureJacksonMapper(ObjectMapper mapper) { | ||||
|     } | ||||
| 	 | ||||
| 	/** | ||||
| 	 * @param provider A Jackson JAX-RS provider to configure. | ||||
| 	 */ | ||||
| 	default void configureJacksonProvider(JacksonJaxbJsonProvider provider) { | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	/** | ||||
| @@ -170,4 +197,12 @@ public interface ClientConfiguration { | ||||
| 		} | ||||
| 	} | ||||
|      | ||||
|     /** | ||||
|      * A Jackson provider, logging filter, and authentication filter are already registered. | ||||
|      *  | ||||
|      * @param clientBuilder A JAX-RS client builder to configure. | ||||
|      */ | ||||
|     default void configureClient(ClientBuilder clientBuilder) { | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,8 @@ package com.inteligr8.rs; | ||||
|  | ||||
| import javax.ws.rs.client.ClientRequestContext; | ||||
|  | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
|  | ||||
| /** | ||||
|  * This class is the base for implementations of client authorization similar | ||||
|  * to OAuth-based flows. | ||||
| @@ -45,8 +47,8 @@ public class ClientEnforcementAuthorizationFilter implements AuthorizationFilter | ||||
| 	 * @param clientSecret A secret corresponding to the client ID. | ||||
| 	 */ | ||||
| 	public ClientEnforcementAuthorizationFilter(String clientId, String clientSecret) { | ||||
| 		this.clientId = clientId; | ||||
| 		this.clientSecret = clientSecret; | ||||
| 		this.clientId = StringUtils.trimToNull(clientId); | ||||
| 		this.clientSecret = StringUtils.trimToNull(clientSecret); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
							
								
								
									
										79
									
								
								src/main/java/com/inteligr8/rs/ClientImpl.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/main/java/com/inteligr8/rs/ClientImpl.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| /* | ||||
|  * 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 <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| package com.inteligr8.rs; | ||||
|  | ||||
| import javax.annotation.PostConstruct; | ||||
| import javax.ws.rs.client.ClientBuilder; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * A class that provides pre-configured JAX-RS Client & WebTarget objects | ||||
|  * for Jersey. | ||||
|  *  | ||||
|  * @author brian@inteligr8.com | ||||
|  */ | ||||
| public class ClientImpl extends Client { | ||||
| 	 | ||||
| 	private final Logger logger = LoggerFactory.getLogger(ClientImpl.class); | ||||
| 	 | ||||
| 	private ClientConfiguration config; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * This constructor is for Spring or POJO use. | ||||
| 	 * @param config The client configuration. | ||||
| 	 */ | ||||
| 	public ClientImpl(ClientConfiguration config) { | ||||
| 		this.config = config; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * This method registers the Jersey library as the default provider for the | ||||
| 	 * JAX-RS specification. | ||||
| 	 */ | ||||
| 	@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. | ||||
| 	 */ | ||||
| 	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> T getApi(AuthorizationFilter authFilter, Class<T> apiClass) { | ||||
| 		throw new UnsupportedOperationException(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -58,7 +58,7 @@ public class LoggingFilter implements ClientRequestFilter, ClientResponseFilter | ||||
| 				logger.trace("request: {} {}: {}", requestContext.getMethod(), requestContext.getUri(), | ||||
| 						((Form)requestContext.getEntity()).asMap()); | ||||
| 			} else { | ||||
| 				this.loggerRequest.trace("request: {} {}: failed to output form", requestContext.getMethod(), requestContext.getUri()); | ||||
| 				logger.trace("request: {} {}: failed to output form", requestContext.getMethod(), requestContext.getUri()); | ||||
| 			} | ||||
| 		} else { | ||||
| 			this.logUnhandledRequest(requestContext, logger); | ||||
|   | ||||
| @@ -18,6 +18,10 @@ import java.net.URI; | ||||
|  | ||||
| import javax.ws.rs.core.Form; | ||||
|  | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * This class implements the OAuth Authorization Code flow as an authorization | ||||
|  * filter. | ||||
| @@ -26,6 +30,8 @@ import javax.ws.rs.core.Form; | ||||
|  */ | ||||
| public class OAuthAuthorizationCodeAuthorizationFilter extends OAuthAuthorizationFilter { | ||||
|      | ||||
|     private final Logger logger = LoggerFactory.getLogger(this.getClass()); | ||||
| 	 | ||||
| 	private final String code; | ||||
| 	private final URI redirectUri; | ||||
| 	 | ||||
| @@ -68,17 +74,22 @@ public class OAuthAuthorizationCodeAuthorizationFilter extends OAuthAuthorizatio | ||||
| 	public OAuthAuthorizationCodeAuthorizationFilter(String tokenUrl, String clientId, String clientSecret, String code, URI redirectUri) { | ||||
| 		super(tokenUrl, clientId, clientSecret); | ||||
| 		 | ||||
| 		this.code = code; | ||||
| 		this.code = StringUtils.trimToNull(code); | ||||
| 		this.redirectUri = redirectUri; | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	protected Form createForm() { | ||||
| 		Form form = new Form().param("grant_type", "authorization_code") | ||||
| 				.param("code", this.code); | ||||
|         this.logger.debug("Using OAuth grant_type 'authorization_code'"); | ||||
| 		Form form = new Form().param("grant_type", "authorization_code"); | ||||
| 		if (this.redirectUri != null) | ||||
| 			form.param("redirect_uri", this.redirectUri.toString()); | ||||
| 		return form; | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	protected void extendFormSensitive(Form form) { | ||||
| 	    form.param("code", this.code); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -17,12 +17,19 @@ package com.inteligr8.rs; | ||||
| import java.util.Map; | ||||
|  | ||||
| import javax.ws.rs.WebApplicationException; | ||||
| import javax.ws.rs.client.Client; | ||||
| import javax.ws.rs.client.ClientBuilder; | ||||
| import javax.ws.rs.client.ClientRequestContext; | ||||
| import javax.ws.rs.client.Entity; | ||||
| import javax.ws.rs.client.WebTarget; | ||||
| import javax.ws.rs.core.Form; | ||||
| import javax.ws.rs.core.HttpHeaders; | ||||
| import javax.ws.rs.core.Response; | ||||
| import javax.ws.rs.core.Response.Status.Family; | ||||
|  | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; | ||||
|  | ||||
| @@ -33,6 +40,8 @@ import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; | ||||
|  */ | ||||
| public abstract class OAuthAuthorizationFilter implements AuthorizationFilter { | ||||
| 	 | ||||
|     private final Logger logger = LoggerFactory.getLogger(this.getClass()); | ||||
|      | ||||
| 	private final String tokenUrl; | ||||
| 	private final String clientId; | ||||
| 	private final String clientSecret; | ||||
| @@ -40,6 +49,7 @@ public abstract class OAuthAuthorizationFilter implements AuthorizationFilter { | ||||
| 	private String accessToken; | ||||
| 	private long expiration; | ||||
| 	private String refreshToken; | ||||
| 	private Long refreshTokenExpiration; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * This constructor creates an OAuth-based authorization filter using the | ||||
| @@ -79,9 +89,9 @@ public abstract class OAuthAuthorizationFilter implements AuthorizationFilter { | ||||
| 	 */ | ||||
| 	public OAuthAuthorizationFilter(String tokenUrl, String clientId, String clientSecret, String scope) { | ||||
| 		this.tokenUrl = tokenUrl; | ||||
| 		this.clientId = clientId; | ||||
| 		this.clientSecret = clientSecret; | ||||
| 		this.scope = scope; | ||||
| 		this.clientId = StringUtils.trimToNull(clientId); | ||||
| 		this.clientSecret = StringUtils.trimToNull(clientSecret); | ||||
| 		this.scope = StringUtils.trimToNull(scope); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -91,8 +101,29 @@ public abstract class OAuthAuthorizationFilter implements AuthorizationFilter { | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public void filter(ClientRequestContext requestContext) { | ||||
| 		if (this.accessToken == null || System.currentTimeMillis() > this.expiration) | ||||
| 		if (this.accessToken == null) { | ||||
| 		    this.requestToken(); | ||||
| 		} else if (System.currentTimeMillis() >= this.expiration) { | ||||
|             this.logger.trace("Access token expired; retrieving new one with refresh token"); | ||||
|              | ||||
| 		    if (this.refreshTokenExpiration != null && System.currentTimeMillis() >= this.refreshTokenExpiration.longValue()) { | ||||
|                 this.logger.debug("Refresh token expired; performing full authentication"); | ||||
|                 this.refreshToken = null; | ||||
|                 this.requestToken(); | ||||
| 		    } else { | ||||
|     		    try { | ||||
|     		        this.requestToken(); | ||||
|                 } catch (WebApplicationException wae) { | ||||
|                     if (wae.getResponse().getStatusInfo().getFamily() == Family.CLIENT_ERROR) { | ||||
|                         this.logger.debug("Received OAuth response {} using refresh token; performing full authentication", wae.getResponse().getStatus()); | ||||
|                         this.refreshToken = null; | ||||
|                         this.requestToken(); | ||||
|                     } else { | ||||
|                         throw wae; | ||||
|                     } | ||||
|                 } | ||||
| 		    } | ||||
| 		} | ||||
| 		 | ||||
| 		requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer " + this.accessToken); | ||||
| 	} | ||||
| @@ -111,29 +142,53 @@ public abstract class OAuthAuthorizationFilter implements AuthorizationFilter { | ||||
| 		} | ||||
|  | ||||
| 		form.param("client_id", this.clientId); | ||||
| 		if (this.clientSecret != null) | ||||
| 			form.param("client_secret", this.clientSecret); | ||||
| 		if (this.scope != null) | ||||
| 			form.param("scope", this.scope); | ||||
| 		this.extendRefreshTokenForm(form); | ||||
| 		 | ||||
| 		this.logger.trace("Sending OAuth request: {}", form); | ||||
| 		 | ||||
| 		if (this.refreshToken != null) { | ||||
| 		    this.extendRefreshFormSensitive(form); | ||||
| 		} else { | ||||
|             this.extendFormSensitive(form); | ||||
| 		} | ||||
|  | ||||
|         if (this.clientSecret != null) | ||||
|             form.param("client_secret", this.clientSecret); | ||||
| 		 | ||||
| 		Entity<Form> entity = Entity.form(form); | ||||
| 		 | ||||
| 		WebTarget target = ClientBuilder.newBuilder() | ||||
| 		Client client = ClientBuilder.newBuilder() | ||||
|                 .register(new JacksonJaxbJsonProvider()) | ||||
| 				.build() | ||||
| 				.target(this.tokenUrl); | ||||
|                 .build(); | ||||
| 		WebTarget target = client.target(this.tokenUrl); | ||||
| 		 | ||||
| 		long requestSendTime = System.currentTimeMillis(); | ||||
|  | ||||
| 		Response response = target.request().post(entity); | ||||
| 		 | ||||
|         this.logger.debug("Received OAuth response: {}", response.getStatus()); | ||||
|  | ||||
|         @SuppressWarnings("unchecked") | ||||
| 		Map<String, Object> response = target.request().post(entity, Map.class); | ||||
|         Map<String, Object> responseMap = response.readEntity(Map.class); | ||||
|  | ||||
| 		if (response.containsKey("error")) | ||||
| 			throw new WebApplicationException((String)response.get("error"), 400); | ||||
|         this.logger.trace("Received OAuth response: {}", responseMap); | ||||
| 		 | ||||
| 		this.accessToken = (String)response.get("access_token"); | ||||
| 		this.expiration = System.currentTimeMillis() + ((Number)response.get("expires_in")).longValue() * 1000L; | ||||
| 		this.refreshToken = (String)response.get("refresh_token"); | ||||
| 		this.extendRefreshTokenResponse(response); | ||||
| 		if (response.getStatusInfo().getFamily() != Family.SUCCESSFUL) { | ||||
|             String code = (String) responseMap.get("error"); | ||||
|             if (code != null) { | ||||
|                 String description = (String) responseMap.get("error_description"); | ||||
|     			throw new WebApplicationException(code + ": " + description, response.getStatus()); | ||||
|             } else { | ||||
|                 throw new WebApplicationException(response); | ||||
|             } | ||||
| 		} | ||||
| 		 | ||||
| 		this.accessToken = (String)responseMap.get("access_token"); | ||||
| 		this.expiration = requestSendTime + ((Number)responseMap.get("expires_in")).longValue() * 1000L; | ||||
| 		this.refreshToken = (String)responseMap.get("refresh_token"); | ||||
| 		if (responseMap.containsKey("refresh_token_expires_in")) | ||||
| 		    this.refreshTokenExpiration = requestSendTime + ((Number)responseMap.get("refresh_token_expires_in")).longValue() * 1000L; | ||||
| 	} | ||||
| 	 | ||||
| 	protected Form createRefreshForm() { | ||||
| @@ -143,10 +198,9 @@ public abstract class OAuthAuthorizationFilter implements AuthorizationFilter { | ||||
| 	 | ||||
| 	protected abstract Form createForm(); | ||||
| 	 | ||||
| 	protected void extendRefreshTokenForm(Form form) { | ||||
| 	protected void extendRefreshFormSensitive(Form form) { | ||||
| 	} | ||||
|  | ||||
| 	protected void extendRefreshTokenResponse(Map<String, Object> response) { | ||||
| 	} | ||||
|     protected abstract void extendFormSensitive(Form form); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,9 @@ package com.inteligr8.rs; | ||||
|  | ||||
| import javax.ws.rs.core.Form; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * This class implements the OAuth Client Credential flow as an authorization | ||||
|  * filter. | ||||
| @@ -24,6 +27,8 @@ import javax.ws.rs.core.Form; | ||||
|  */ | ||||
| public class OAuthClientCredentialAuthorizationFilter extends OAuthAuthorizationFilter { | ||||
|      | ||||
|     private final Logger logger = LoggerFactory.getLogger(this.getClass()); | ||||
|  | ||||
| 	/** | ||||
| 	 * @param tokenUrl The URL to the OAuth IdP token service. | ||||
| 	 * @param clientId The ID provided by the OAuth IdP administrator. | ||||
| @@ -35,7 +40,12 @@ public class OAuthClientCredentialAuthorizationFilter extends OAuthAuthorization | ||||
| 	 | ||||
| 	@Override | ||||
| 	protected Form createForm() { | ||||
|         this.logger.debug("Using OAuth grant_type 'client_credentials'"); | ||||
| 		return new Form().param("grant_type", "client_credentials"); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	protected void extendFormSensitive(Form form) { | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,10 @@ package com.inteligr8.rs; | ||||
|  | ||||
| import javax.ws.rs.core.Form; | ||||
|  | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * This class implements the OAuth Password Grant flow as an authorization | ||||
|  * filter. | ||||
| @@ -24,6 +28,8 @@ import javax.ws.rs.core.Form; | ||||
|  */ | ||||
| public class OAuthPasswordGrantAuthorizationFilter extends OAuthAuthorizationFilter { | ||||
|      | ||||
|     private final Logger logger = LoggerFactory.getLogger(this.getClass()); | ||||
| 	 | ||||
| 	private final String username; | ||||
| 	private final String password; | ||||
|  | ||||
| @@ -46,15 +52,20 @@ public class OAuthPasswordGrantAuthorizationFilter extends OAuthAuthorizationFil | ||||
| 	 */ | ||||
| 	public OAuthPasswordGrantAuthorizationFilter(String tokenUrl, String clientId, String clientSecret, String username, String password) { | ||||
| 		super(tokenUrl, clientId, clientSecret); | ||||
| 		this.username = username; | ||||
| 		this.password = password; | ||||
| 		this.username = StringUtils.trimToNull(username); | ||||
| 		this.password = StringUtils.trimToNull(password); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	protected Form createForm() { | ||||
|         this.logger.debug("Using OAuth grant_type 'password': {}", this.username); | ||||
| 		return new Form().param("grant_type", "password") | ||||
| 				.param("username", this.username) | ||||
| 				.param("password", this.password); | ||||
| 				.param("username", this.username); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	protected void extendFormSensitive(Form form) { | ||||
| 	    form.param("password", this.password); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user