Implement method for Https ssl trustmanager and improve exception

apim420
Pasindu Rupasinghe 2 years ago
parent eb11036b6c
commit 455917f21e

@ -19,6 +19,7 @@
package io.entgra.device.mgt.core.apimgt.extension.rest.api; package io.entgra.device.mgt.core.apimgt.extension.rest.api;
import com.google.gson.Gson; import com.google.gson.Gson;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.util.HttpsTrustManagerUtils;
import org.json.JSONObject; import org.json.JSONObject;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.APIApplicationKey; import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.APIApplicationKey;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.constants.Constants; import io.entgra.device.mgt.core.apimgt.extension.rest.api.constants.Constants;
@ -48,7 +49,7 @@ import java.util.concurrent.TimeUnit;
public class APIApplicationServicesImpl implements APIApplicationServices { public class APIApplicationServicesImpl implements APIApplicationServices {
private static final Log log = LogFactory.getLog(APIApplicationServicesImpl.class); private static final Log log = LogFactory.getLog(APIApplicationServicesImpl.class);
private static final OkHttpClient client = getOkHttpClient(); private static final OkHttpClient client = new OkHttpClient(HttpsTrustManagerUtils.getSSLClient().newBuilder());
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
String msg = null; String msg = null;
@ -133,55 +134,4 @@ public class APIApplicationServicesImpl implements APIApplicationServices {
throw new APIServicesException(e); throw new APIServicesException(e);
} }
} }
protected static OkHttpClient getOkHttpClient() {
X509TrustManager trustAllCerts = new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
};
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(300, TimeUnit.SECONDS)
.writeTimeout(300, TimeUnit.SECONDS)
.readTimeout(300, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(500, 500, TimeUnit.SECONDS))
.sslSocketFactory(getSimpleTrustedSSLSocketFactory(), trustAllCerts)
.hostnameVerifier((hostname, sslSession) -> true).build();
return okHttpClient;
}
private static SSLSocketFactory getSimpleTrustedSSLSocketFactory() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
return sc.getSocketFactory();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
log.error("Error while creating the SSL socket factory due to " + e.getMessage(), e);
return null;
}
}
} }

@ -23,6 +23,8 @@ import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.APIApplicationKey
import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.AccessTokenInfo; import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.AccessTokenInfo;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.APIServicesException; import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.APIServicesException;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.BadRequestException; import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.BadRequestException;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.UnexpectedResponseException;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.util.HttpsTrustManagerUtils;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.util.ScopeUtils; import io.entgra.device.mgt.core.apimgt.extension.rest.api.util.ScopeUtils;
import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
@ -38,17 +40,15 @@ import org.wso2.carbon.apimgt.api.model.Scope;
import java.io.IOException; import java.io.IOException;
import static io.entgra.device.mgt.core.apimgt.extension.rest.api.APIApplicationServicesImpl.getOkHttpClient;
public class PublisherRESTAPIServices { public class PublisherRESTAPIServices {
private static final Log log = LogFactory.getLog(PublisherRESTAPIServices.class); private static final Log log = LogFactory.getLog(PublisherRESTAPIServices.class);
private static final OkHttpClient client = getOkHttpClient(); private static final OkHttpClient client = new OkHttpClient(HttpsTrustManagerUtils.getSSLClient().newBuilder());
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static final String host = System.getProperty(Constants.IOT_CORE_HOST); private static final String host = System.getProperty(Constants.IOT_CORE_HOST);
private static final String port = System.getProperty(Constants.IOT_CORE_HTTPS_PORT); private static final String port = System.getProperty(Constants.IOT_CORE_HTTPS_PORT);
public JSONObject getScopes(APIApplicationKey apiApplicationKey, AccessTokenInfo accessTokenInfo) public JSONObject getScopes(APIApplicationKey apiApplicationKey, AccessTokenInfo accessTokenInfo)
throws APIServicesException, BadRequestException { throws APIServicesException, BadRequestException, UnexpectedResponseException {
String getAllScopesUrl = Constants.HTTPS_PROTOCOL + Constants.SCHEME_SEPARATOR + host + Constants.COLON String getAllScopesUrl = Constants.HTTPS_PROTOCOL + Constants.SCHEME_SEPARATOR + host + Constants.COLON
+ port + Constants.GET_ALL_SCOPES; + port + Constants.GET_ALL_SCOPES;
@ -76,7 +76,8 @@ public class PublisherRESTAPIServices {
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} else { } else {
return null; String msg = "Response : " + response.code() + response.body();
throw new UnexpectedResponseException(msg);
} }
} catch (IOException e) { } catch (IOException e) {
String msg = "Error occurred while processing the response"; String msg = "Error occurred while processing the response";
@ -86,7 +87,7 @@ public class PublisherRESTAPIServices {
} }
public boolean isSharedScopeNameExists(APIApplicationKey apiApplicationKey, AccessTokenInfo accessTokenInfo, String key) public boolean isSharedScopeNameExists(APIApplicationKey apiApplicationKey, AccessTokenInfo accessTokenInfo, String key)
throws APIServicesException, BadRequestException { throws APIServicesException, BadRequestException, UnexpectedResponseException {
String keyValue = new String(Base64.encodeBase64((key).getBytes())).replace(Constants.QUERY_KEY_VALUE_SEPARATOR, String keyValue = new String(Base64.encodeBase64((key).getBytes())).replace(Constants.QUERY_KEY_VALUE_SEPARATOR,
Constants.EMPTY_STRING); Constants.EMPTY_STRING);
@ -115,7 +116,8 @@ public class PublisherRESTAPIServices {
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} else { } else {
return false; String msg = "Response : " + response.code() + response.body();
throw new UnexpectedResponseException(msg);
} }
} catch (IOException e) { } catch (IOException e) {
String msg = "Error occurred while processing the response"; String msg = "Error occurred while processing the response";
@ -125,7 +127,7 @@ public class PublisherRESTAPIServices {
} }
public boolean updateSharedScope(APIApplicationKey apiApplicationKey, AccessTokenInfo accessTokenInfo, Scope scope) public boolean updateSharedScope(APIApplicationKey apiApplicationKey, AccessTokenInfo accessTokenInfo, Scope scope)
throws APIServicesException, BadRequestException { throws APIServicesException, BadRequestException, UnexpectedResponseException {
String updateScopeUrl = Constants.HTTPS_PROTOCOL + Constants.SCHEME_SEPARATOR + host String updateScopeUrl = Constants.HTTPS_PROTOCOL + Constants.SCHEME_SEPARATOR + host
+ Constants.COLON + port + Constants.GET_SCOPE + scope.getId(); + Constants.COLON + port + Constants.GET_SCOPE + scope.getId();
@ -161,7 +163,8 @@ public class PublisherRESTAPIServices {
log.error(msg); log.error(msg);
throw new BadRequestException(msg); throw new BadRequestException(msg);
} else { } else {
return false; String msg = "Response : " + response.code() + response.body();
throw new UnexpectedResponseException(msg);
} }
} catch (IOException e) { } catch (IOException e) {
String msg = "Error occurred while processing the response"; String msg = "Error occurred while processing the response";

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Custom exception class for handling unexpected server response exceptions.
*/
package io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions;
public class UnexpectedResponseException extends Exception {
private static final long serialVersionUID = -2387103750774855056L;
public UnexpectedResponseException(String errorMessage) {
super(errorMessage);
}
}

@ -0,0 +1,229 @@
/*
* Copyright (c) 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.entgra.device.mgt.core.apimgt.extension.rest.api.util;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.base.ServerConfiguration;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.SSLSession;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.HostnameVerifier;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class HttpsTrustManagerUtils {
private static final Log log = LogFactory.getLog(HttpsTrustManagerUtils.class);
private static final String KEY_STORE_TYPE = "JKS";
/**
* Default truststore type of the client
*/
private static final String TRUST_STORE_TYPE = "JKS";
/**
* Default keymanager type of the client
*/
private static final String KEY_MANAGER_TYPE = "SunX509"; //Default Key Manager Type
/**
* Default trustmanager type of the client
*/
private static final String TRUST_MANAGER_TYPE = "SunX509"; //Default Trust Manager Type
private static final String SSLV3 = "SSLv3";
private static final String DEFAULT_HOST = "localhost";
private static final String DEFAULT_HOST_IP = "127.0.0.1";
private static final int TIMEOUT = 100;
public static OkHttpClient getSSLClient() {
boolean isIgnoreHostnameVerification = Boolean.parseBoolean(System.getProperty("org.wso2"
+ ".ignoreHostnameVerification"));
OkHttpClient okHttpClient;
final String proxyHost = System.getProperty("http.proxyHost");
final String proxyPort = System.getProperty("http.proxyPort");
final String nonProxyHostsValue = System.getProperty("http.nonProxyHosts");
final ProxySelector proxySelector = new ProxySelector() {
@Override
public List<Proxy> select(URI uri) {
List<Proxy> proxyList = new ArrayList<>();
String host = uri.getHost();
if (!StringUtils.isEmpty(host)) {
if (host.startsWith(DEFAULT_HOST_IP) || host.startsWith(DEFAULT_HOST) || StringUtils
.isEmpty(nonProxyHostsValue) || StringUtils.contains(nonProxyHostsValue, host) ||
StringUtils.isEmpty(proxyHost) || StringUtils.isEmpty(proxyPort)) {
proxyList.add(Proxy.NO_PROXY);
} else {
proxyList.add(new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort))));
}
} else {
log.error("Host is null. Host could not be empty or null");
}
return proxyList;
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
throw new UnsupportedOperationException("Not supported yet.");
}
};
X509TrustManager trustAllCerts = new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
};
if (isIgnoreHostnameVerification) {
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(TIMEOUT, TIMEOUT, TimeUnit.SECONDS))
.sslSocketFactory(getSimpleTrustedSSLSocketFactory(), trustAllCerts)
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
}).proxySelector(proxySelector).build();
return okHttpClient;
} else {
SSLSocketFactory trustedSSLSocketFactory = getTrustedSSLSocketFactory();
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(TIMEOUT, TIMEOUT, TimeUnit.SECONDS))
.sslSocketFactory(trustedSSLSocketFactory)
.proxySelector(proxySelector).build();
return okHttpClient;
}
}
private static SSLSocketFactory getSimpleTrustedSSLSocketFactory() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
return sc.getSocketFactory();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
log.error("Error while creating the SSL socket factory due to " + e.getMessage(), e);
return null;
}
}
private static SSLSocketFactory getTrustedSSLSocketFactory() {
try {
String keyStorePassword = ServerConfiguration.getInstance().getFirstProperty("Security.KeyStore.Password");
String keyStoreLocation = ServerConfiguration.getInstance().getFirstProperty("Security.KeyStore.Location");
String trustStorePassword = ServerConfiguration.getInstance().getFirstProperty(
"Security.TrustStore.Password");
String trustStoreLocation = ServerConfiguration.getInstance().getFirstProperty(
"Security.TrustStore.Location");
KeyStore keyStore = loadKeyStore(keyStoreLocation, keyStorePassword, KEY_STORE_TYPE);
KeyStore trustStore = loadTrustStore(trustStoreLocation, trustStorePassword);
return initSSLConnection(keyStore, keyStorePassword, trustStore);
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException
| CertificateException | IOException | UnrecoverableKeyException e) {
log.error("Error while creating the SSL socket factory due to " + e.getMessage(), e);
return null;
}
}
private static SSLSocketFactory initSSLConnection(KeyStore keyStore, String keyStorePassword, KeyStore trustStore)
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeyManagementException {
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KEY_MANAGER_TYPE);
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TRUST_MANAGER_TYPE);
trustManagerFactory.init(trustStore);
// Create and initialize SSLContext for HTTPS communication
SSLContext sslContext = SSLContext.getInstance(SSLV3);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
SSLContext.setDefault(sslContext);
return sslContext.getSocketFactory();
}
private static KeyStore loadKeyStore(String keyStorePath, String ksPassword, String type)
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
InputStream fileInputStream = null;
try {
char[] keypassChar = ksPassword.toCharArray();
KeyStore keyStore = KeyStore.getInstance(type);
fileInputStream = new FileInputStream(keyStorePath);
keyStore.load(fileInputStream, keypassChar);
return keyStore;
} finally {
if (fileInputStream != null) {
fileInputStream.close();
}
}
}
private static KeyStore loadTrustStore(String trustStorePath, String tsPassword)
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
return loadKeyStore(trustStorePath, tsPassword, TRUST_STORE_TYPE);
}
}

@ -25,6 +25,7 @@ import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.APIApplicationKey
import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.AccessTokenInfo; import io.entgra.device.mgt.core.apimgt.extension.rest.api.dto.AccessTokenInfo;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.APIServicesException; import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.APIServicesException;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.BadRequestException; import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.BadRequestException;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.UnexpectedResponseException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -468,6 +469,10 @@ public class APIPublisherServiceImpl implements APIPublisherService {
String errorMsg = "Error while calling Publisher REST APIs"; String errorMsg = "Error while calling Publisher REST APIs";
log.error(errorMsg, e); log.error(errorMsg, e);
throw new APIManagerPublisherException(e); throw new APIManagerPublisherException(e);
} catch (UnexpectedResponseException e) {
String errorMsg = "Unexpected response from the server";
log.error(errorMsg, e);
throw new APIManagerPublisherException(e);
}finally { }finally {
PrivilegedCarbonContext.endTenantFlow(); PrivilegedCarbonContext.endTenantFlow();
} }

Loading…
Cancel
Save