Skip to content

Commit

Permalink
fix(citrusframework#1062): Enable SSL secure connection configuration
Browse files Browse the repository at this point in the history
- Add SSL connector configuration on Http server
- Add SSL connection manager configuration on Http client
- Simplify basic auth configuration on client and server
  • Loading branch information
christophd committed Nov 16, 2023
1 parent dc7cd92 commit d8f223e
Show file tree
Hide file tree
Showing 23 changed files with 1,142 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.citrusframework.TestActionRunner;
import org.citrusframework.TestCaseRunner;
import org.citrusframework.common.InitializingPhase;
import org.citrusframework.common.Named;
import org.citrusframework.context.TestContext;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.citrusframework.spi.BindToRegistry;
Expand Down Expand Up @@ -249,6 +250,11 @@ public static void parseConfiguration(Object configuration, CitrusContext citrus
try {
String name = ReferenceRegistry.getName(m.getAnnotation(BindToRegistry.class), m.getName());
Object component = m.invoke(configuration);

if (component instanceof Named named) {
named.setName(name);
}

citrusContext.getReferenceResolver().bind(name, component);

initializeComponent(name, component, citrusContext);
Expand All @@ -270,6 +276,11 @@ public static void parseConfiguration(Object configuration, CitrusContext citrus
try {
String name = ReferenceRegistry.getName(f.getAnnotation(BindToRegistry.class), f.getName());
Object component = f.get(configuration);

if (component instanceof Named named) {
named.setName(name);
}

citrusContext.getReferenceResolver().bind(name, component);

initializeComponent(name, component, citrusContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public MessageCorrelator getCorrelator() {

/**
* Gets the pollingInterval.
* @return the pollingInterval the pollingInterval to get.
* @return the pollingInterval to get.
*/
public long getPollingInterval() {
return pollingInterval;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
import org.apache.hc.client5.http.auth.AuthCache;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.auth.BasicScheme;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpHost;
Expand All @@ -45,7 +45,7 @@
public class BasicAuthClientHttpRequestFactory implements FactoryBean<HttpComponentsClientHttpRequestFactory>, InitializingPhase {

/** The target request factory */
private HttpClient httpClient;
private HttpClientBuilder httpClient;

/** User credentials for basic authentication */
private Credentials credentials;
Expand All @@ -59,7 +59,7 @@ public class BasicAuthClientHttpRequestFactory implements FactoryBean<HttpCompon
public HttpComponentsClientHttpRequestFactory getObject() throws Exception {
ObjectHelper.assertNotNull(credentials, "User credentials not set properly!");

return new HttpComponentsClientHttpRequestFactory(httpClient) {
return new HttpComponentsClientHttpRequestFactory(httpClient.build()) {
@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
// we have to use preemptive authentication
Expand Down Expand Up @@ -99,13 +99,14 @@ public boolean isSingleton() {

@Override
public void initialize() {
if (httpClient == null) {
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(authScope, credentials);
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(authScope, credentials);

if (httpClient == null) {
httpClient = HttpClients.custom()
.setDefaultCredentialsProvider(credentialsProvider)
.build();
.setDefaultCredentialsProvider(credentialsProvider);
} else {
httpClient.setDefaultCredentialsProvider(credentialsProvider);
}
}

Expand All @@ -129,7 +130,7 @@ public void setAuthScope(AuthScope authScope) {
* Sets the httpClient.
* @param httpClient the httpClient to set
*/
public void setHttpClient(HttpClient httpClient) {
public void setHttpClient(HttpClientBuilder httpClient) {
this.httpClient = httpClient;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.citrusframework.endpoint.AbstractEndpointBuilder;
import org.citrusframework.endpoint.resolver.EndpointUriResolver;
import org.citrusframework.http.message.HttpMessageConverter;
import org.citrusframework.http.security.HttpAuthentication;
import org.citrusframework.http.security.HttpSecureConnection;
import org.citrusframework.message.ErrorHandlingStrategy;
import org.citrusframework.message.MessageCorrelator;
import org.springframework.http.MediaType;
Expand All @@ -38,7 +40,7 @@
public class HttpClientBuilder extends AbstractEndpointBuilder<HttpClient> {

/** Endpoint target */
private HttpClient endpoint = new HttpClient();
private final HttpClient endpoint = new HttpClient();

@Override
protected HttpClient getEndpoint() {
Expand Down Expand Up @@ -234,4 +236,25 @@ public HttpClientBuilder timeout(long timeout) {
endpoint.getEndpointConfiguration().setTimeout(timeout);
return this;
}

/**
* Sets the user authentication.
* @param auth
* @return
*/
public HttpClientBuilder authentication(HttpAuthentication auth) {
endpoint.getEndpointConfiguration().setRequestFactory(
auth.getRequestFactory(endpoint.getEndpointConfiguration().getRequestUrl(), endpoint));
return this;
}

/**
* Enable secured connection on the client using provided SSL connection.
* @return
*/
public HttpClientBuilder secured(HttpSecureConnection conn) {
endpoint.getEndpointConfiguration().getHttpClient()
.setConnectionManager(conn.getClientConnectionManager());
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Arrays;
import java.util.List;

import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.citrusframework.endpoint.AbstractPollableEndpointConfiguration;
import org.citrusframework.endpoint.resolver.DynamicEndpointUriResolver;
import org.citrusframework.endpoint.resolver.EndpointUriResolver;
Expand Down Expand Up @@ -62,6 +63,9 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura
/** The rest template */
private RestTemplate restTemplate;

/** Http client builder */
private HttpClientBuilder httpClient;

/** Request factory */
private ClientHttpRequestFactory requestFactory;

Expand All @@ -75,7 +79,7 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura
private HttpMessageConverter messageConverter = new HttpMessageConverter();

/** Endpoint clientInterceptors */
private List<ClientHttpRequestInterceptor> clientInterceptors;
private List<ClientHttpRequestInterceptor> clientInterceptors = new ArrayList<>();

/** Should http errors be handled within endpoint consumer or simply throw exception */
private ErrorHandlingStrategy errorHandlingStrategy = ErrorHandlingStrategy.PROPAGATE;
Expand Down Expand Up @@ -110,9 +114,7 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura
* Default constructor initializes with default logging interceptor.
*/
public HttpEndpointConfiguration() {
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new LoggingClientInterceptor());
setClientInterceptors(interceptors);
clientInterceptors.add(new LoggingClientInterceptor());
}

/**
Expand Down Expand Up @@ -228,6 +230,7 @@ public String getContentType() {
public RestTemplate getRestTemplate() {
if (restTemplate == null) {
restTemplate = new RestTemplate();
restTemplate.setInterceptors(clientInterceptors);
}

restTemplate.setRequestFactory(getRequestFactory());
Expand Down Expand Up @@ -298,7 +301,7 @@ public MessageCorrelator getCorrelator() {
*/
public ClientHttpRequestFactory getRequestFactory() {
if (requestFactory == null) {
requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory = new HttpComponentsClientHttpRequestFactory(getHttpClient().build());
}

return requestFactory;
Expand All @@ -312,6 +315,18 @@ public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
this.requestFactory = requestFactory;
}

public HttpClientBuilder getHttpClient() {
if (httpClient == null) {
httpClient = HttpClientBuilder.create().useSystemProperties();
}

return httpClient;
}

public void setHttpClient(HttpClientBuilder httpClient) {
this.httpClient = httpClient;
}

/**
* Gets the message converter.
* @return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,16 @@
* @return
*/
String actor() default "";

/**
* User authentication.
* @return
*/
String authentication() default "";

/**
* Secured connection.
* @return
*/
String secured() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.citrusframework.http.client.HttpClient;
import org.citrusframework.http.client.HttpClientBuilder;
import org.citrusframework.http.message.HttpMessageConverter;
import org.citrusframework.http.security.HttpAuthentication;
import org.citrusframework.http.security.HttpSecureConnection;
import org.citrusframework.message.MessageCorrelator;
import org.citrusframework.spi.ReferenceResolver;
import org.citrusframework.util.StringUtils;
Expand Down Expand Up @@ -112,6 +114,14 @@ public HttpClient parse(HttpClientConfig annotation, ReferenceResolver reference
builder.actor(referenceResolver.resolve(annotation.actor(), TestActor.class));
}

if (StringUtils.hasText(annotation.authentication())) {
builder.authentication(referenceResolver.resolve(annotation.authentication(), HttpAuthentication.class));
}

if (StringUtils.hasText(annotation.secured())) {
builder.secured(referenceResolver.resolve(annotation.secured(), HttpSecureConnection.class));
}

return builder.initialize().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,28 @@
* @return
*/
String actor() default "";

/**
* User authentication.
* @return
*/
String authentication() default "";

/**
* Resource path that is secured with user authentication.
* @return
*/
String securedPath() default "/*";

/**
* Secured connection.
* @return
*/
String secured() default "";

/**
* Secured server port.
* @return
*/
int securePort() default 8443;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.citrusframework.endpoint.EndpointAdapter;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.citrusframework.http.message.HttpMessageConverter;
import org.citrusframework.http.security.HttpAuthentication;
import org.citrusframework.http.security.HttpSecureConnection;
import org.citrusframework.http.server.HttpServer;
import org.citrusframework.http.server.HttpServerBuilder;
import org.citrusframework.spi.ReferenceResolver;
Expand Down Expand Up @@ -138,6 +140,14 @@ public HttpServer parse(HttpServerConfig annotation, ReferenceResolver reference
builder.defaultStatus(annotation.defaultStatus());
builder.responseCacheSize(annotation.responseCacheSize());

if (StringUtils.hasText(annotation.authentication())) {
builder.authentication(annotation.securedPath(), referenceResolver.resolve(annotation.authentication(), HttpAuthentication.class));
}

if (StringUtils.hasText(annotation.secured())) {
builder.secured(annotation.securePort(), referenceResolver.resolve(annotation.secured(), HttpSecureConnection.class));
}

return builder.initialize().build();
}
}
Loading

0 comments on commit d8f223e

Please sign in to comment.