Skip to content

Commit b3367bf

Browse files
committed
Issue #13 - add option to bypass SSL restrictions in scenarios like development where untrusted certs are the norm
1 parent 82513da commit b3367bf

File tree

8 files changed

+140
-16
lines changed

8 files changed

+140
-16
lines changed

src/main/java/org/openstack4j/api/EndpointTokenProvider.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,13 @@ public interface EndpointTokenProvider {
2323
* @return the auth token identifier
2424
*/
2525
String getTokenId();
26+
27+
/**
28+
* Determines if the client should ignore self-signed cerificates and hostnames typically found in private or
29+
* DEV based environments.
30+
*
31+
* @return true to use non strict SSL client
32+
*/
33+
boolean useNonStrictSSLClient();
2634

2735
}

src/main/java/org/openstack4j/core/transport/HttpExecutorService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,14 @@ public interface HttpExecutorService {
1616
*/
1717
<R> HttpResponse execute(HttpRequest<R> request);
1818

19+
/**
20+
* Executes the given request and returns the {@code HttpResponse} result from the server
21+
*
22+
* @param <R> the underlying return entity type
23+
* @param request the request to execute
24+
* @param useNonStrictSSL set this to true if the endpoint is using a self-signed certificate. False to use trusted only client
25+
* @return HttpResponse from the server
26+
*/
27+
<R> HttpResponse execute(HttpRequest<R> request, boolean useNonStrictSSL);
28+
1929
}

src/main/java/org/openstack4j/core/transport/HttpRequest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ public class HttpRequest<R> {
3333
private Map<String, List<Object>> queryParams;
3434
private Map<String, Object> headers = new HashMap<String, Object>();
3535
private Function<String, String> endpointFunc;
36-
37-
36+
private boolean useNonStrictSSLClient;
3837
public HttpRequest() { }
3938

4039
/**
@@ -96,6 +95,10 @@ public String getEndpoint() {
9695
return endpoint;
9796
}
9897

98+
public boolean useNonStrictSSLClient() {
99+
return useNonStrictSSLClient;
100+
}
101+
99102
/**
100103
* @return the http path
101104
*/
@@ -358,6 +361,7 @@ public HttpRequest<R> build() {
358361
if (provider != null)
359362
{
360363
request.endpoint = provider.getEndpoint(service);
364+
request.useNonStrictSSLClient = provider.useNonStrictSSLClient();
361365
request.getHeaders().put(ClientConstants.HEADER_X_AUTH_TOKEN, provider.getTokenId());
362366
}
363367
return request;

src/main/java/org/openstack4j/core/transport/internal/ClientFactory.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
package org.openstack4j.core.transport.internal;
22

33
import java.io.IOException;
4+
import java.security.SecureRandom;
5+
import java.security.cert.X509Certificate;
46

7+
import javax.net.ssl.HostnameVerifier;
8+
import javax.net.ssl.HttpsURLConnection;
9+
import javax.net.ssl.SSLContext;
10+
import javax.net.ssl.SSLSession;
11+
import javax.net.ssl.TrustManager;
12+
import javax.net.ssl.X509TrustManager;
513
import javax.ws.rs.client.Client;
614
import javax.ws.rs.client.ClientBuilder;
715
import javax.ws.rs.client.ClientRequestContext;
@@ -24,24 +32,29 @@
2432
class ClientFactory {
2533

2634
private static final CustomContextResolver RESOLVER = new CustomContextResolver();
35+
private static Client clientStrict;
2736
private static Client client;
37+
2838

2939
/**
3040
* Creates or Returns a Client
3141
*
3242
* @return the client
3343
*/
34-
static Client create() {
44+
static Client create(boolean useNonStrictSSL) {
45+
46+
if (useNonStrictSSL)
47+
return getNonStrictSSLClient();
3548

36-
if (client == null) {
37-
client = ClientBuilder.newBuilder()
49+
if (clientStrict == null) {
50+
clientStrict = ClientBuilder.newBuilder()
3851
.register(JacksonFeature.class)
3952
.register(RESOLVER)
4053
.register(new RequestFilter())
4154
.build();
4255
}
4356

44-
return client;
57+
return clientStrict;
4558
}
4659

4760
private static final class RequestFilter implements ClientRequestFilter {
@@ -54,7 +67,44 @@ public void filter(ClientRequestContext requestContext) throws IOException {
5467
requestContext.getHeaders().remove(ClientConstants.HEADER_CONTENT_LANGUAGE);
5568
requestContext.getHeaders().remove(ClientConstants.HEADER_CONTENT_ENCODING);
5669
}
70+
}
71+
72+
private static Client getNonStrictSSLClient() {
73+
if (client == null)
74+
{
75+
ClientBuilder cb = ClientBuilder.newBuilder()
76+
.register(JacksonFeature.class)
77+
.register(RESOLVER)
78+
.register(new RequestFilter());
79+
80+
try
81+
{
82+
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
83+
public X509Certificate[] getAcceptedIssuers() {
84+
return null;
85+
}
86+
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
87+
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
88+
} };
89+
SSLContext context = SSLContext.getInstance("TLS");
90+
context.init(null, trustAllCerts, new SecureRandom());
91+
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
92+
93+
cb.sslContext(context);
94+
cb.hostnameVerifier(new HostnameVerifier() {
95+
@Override
96+
public boolean verify(String s, SSLSession session) {
97+
return true;
98+
} });
99+
}
100+
catch (Throwable t) {
101+
t.printStackTrace();
102+
}
103+
104+
client = cb.build();
105+
}
57106

107+
return client;
58108
}
59109

60110
private static final class CustomContextResolver implements ContextResolver<ObjectMapper> {

src/main/java/org/openstack4j/core/transport/internal/HttpExecutor.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,16 @@ public static HttpExecutor create() {
4040
*/
4141
@Override
4242
public <R> HttpResponse execute(HttpRequest<R> request) {
43+
return execute(request, request.useNonStrictSSLClient());
44+
}
45+
46+
/**
47+
* {@inheritDoc}
48+
*/
49+
@Override
50+
public <R> HttpResponse execute(HttpRequest<R> request, boolean useNonStrictSSL) {
4351
try {
44-
return invoke(request);
52+
return invoke(request, useNonStrictSSL);
4553
}
4654
catch (ResponseException re) {
4755
throw re;
@@ -51,7 +59,7 @@ public <R> HttpResponse execute(HttpRequest<R> request) {
5159
return null;
5260
}
5361
}
54-
62+
5563
/**
5664
* Invokes the given request
5765
*
@@ -60,8 +68,8 @@ public <R> HttpResponse execute(HttpRequest<R> request) {
6068
* @return the response
6169
* @throws Exception the exception
6270
*/
63-
private <R> HttpResponse invoke(HttpRequest<R> request) throws Exception {
64-
Client client = ClientFactory.create();
71+
private <R> HttpResponse invoke(HttpRequest<R> request, boolean useNonStrictSSL) throws Exception {
72+
Client client = ClientFactory.create(useNonStrictSSL);
6573
WebTarget target = client.target(request.getEndpoint()).path(request.getPath());
6674

6775
if (Boolean.getBoolean(HttpLoggingFilter.class.getName()))

src/main/java/org/openstack4j/openstack/OSFactory.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ public class OSFactory {
2222
String user;
2323
String tenantName;
2424
String password;
25-
25+
boolean useNonStrictSSL;
26+
2627
private OSFactory() { }
2728

2829
/**
@@ -40,22 +41,51 @@ public static OSFactory builder() {
4041
return new OSFactory();
4142
}
4243

44+
/**
45+
* The identity endpoint to connect to
46+
* @param endpoint the endpoint URL of the identity service
47+
* @return self for method chaining
48+
*/
4349
public OSFactory endpoint(String endpoint) {
4450
this.endpoint = endpoint;
4551
return this;
4652
}
4753

54+
/**
55+
* The authentication credentials
56+
*
57+
* @param user the user to authenticate with
58+
* @param password the password to authenticate with
59+
* @return self for method chaining
60+
*/
4861
public OSFactory credentials(String user, String password) {
4962
this.user = user;
5063
this.password = password;
5164
return this;
5265
}
5366

67+
/**
68+
* The tenant/project to authenticate as
69+
* @param tenantName the tenant/project name
70+
* @return self for method chaining
71+
*/
5472
public OSFactory tenantName(String tenantName) {
5573
this.tenantName = tenantName;
5674
return this;
5775
}
5876

77+
/**
78+
* In some private environments self signed certificates are used. If you are using HTTPS and using
79+
* self-signed cerificates then set this to true. Otherwise the default strict hostname and properly
80+
* signed validation based client will be used.
81+
*
82+
* @param useNonStrictSSL true if an HTTPS self-signed environment
83+
* @return self for method chaining
84+
*/
85+
public OSFactory useNonStrictSSLClient(boolean useNonStrictSSL) {
86+
this.useNonStrictSSL = useNonStrictSSL;
87+
return this;
88+
}
5989
/**
6090
* Attempts to connect, authenticated and obtain an authorization access entity which contains a token, service catalog and endpoints
6191
* from the controller. As a result a client will be returned encapsulating the authorized access and corresponding API access
@@ -66,8 +96,8 @@ public OSFactory tenantName(String tenantName) {
6696
public OSClient authenticate() throws AuthenticationException {
6797
Credentials credentials = new Credentials(user, password, tenantName);
6898
HttpRequest<KeystoneAccess> request = HttpRequest.builder(KeystoneAccess.class).endpoint(endpoint).method(HttpMethod.POST).path("/tokens").entity(credentials).build();
69-
KeystoneAccess access = HttpExecutor.create().execute(request).getEntity(KeystoneAccess.class);
70-
return OSClientSession.createSession(access.applyContext(endpoint, credentials));
99+
KeystoneAccess access = HttpExecutor.create().execute(request, useNonStrictSSL).getEntity(KeystoneAccess.class);
100+
return OSClientSession.createSession(access.applyContext(endpoint, credentials), useNonStrictSSL);
71101
}
72102

73103
}

src/main/java/org/openstack4j/openstack/identity/domain/KeystoneAccess.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class KeystoneAccess implements Access {
2727
private AccessUser user;
2828
private String endpoint;
2929
private Credentials credentials;
30-
30+
3131
/**
3232
* @return the token
3333
*/

src/main/java/org/openstack4j/openstack/internal/OSClientSession.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,21 @@ public class OSClientSession implements OSClient, EndpointTokenProvider {
4040
KeystoneAccess access;
4141
Set<ServiceType> supports;
4242
String publicHostIP;
43+
boolean useNonStrictSSL;
4344

44-
private OSClientSession(KeystoneAccess access, String endpoint)
45+
private OSClientSession(KeystoneAccess access, String endpoint, boolean useNonStrictSSL)
4546
{
4647
this.access = access;
48+
this.useNonStrictSSL = useNonStrictSSL;
4749
sessions.set(this);
4850
}
4951

5052
public static OSClientSession createSession(KeystoneAccess access) {
51-
return new OSClientSession(access, access.getEndpoint());
53+
return new OSClientSession(access, access.getEndpoint(), Boolean.FALSE);
54+
}
55+
56+
public static OSClientSession createSession(KeystoneAccess access, boolean useNonStrictSSL) {
57+
return new OSClientSession(access, access.getEndpoint(), useNonStrictSSL);
5258
}
5359

5460
public static OSClientSession getCurrent() {
@@ -65,6 +71,14 @@ public Set<ServiceType> getSupportedServices() {
6571
return supports;
6672
}
6773

74+
/**
75+
* @return true if we should ignore self-signed cerificates
76+
*/
77+
@Override
78+
public boolean useNonStrictSSLClient() {
79+
return this.useNonStrictSSL;
80+
}
81+
6882
/**
6983
* {@inheritDoc}
7084
*/

0 commit comments

Comments
 (0)