Skip to content

Commit 331196c

Browse files
committed
Call truststore.store() only once per tenant
1 parent 02c677c commit 331196c

File tree

6 files changed

+148
-3
lines changed

6 files changed

+148
-3
lines changed

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/EndpointCertificateDeployer.java

+34
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ private CloseableHttpResponse invokeService(String endpoint, String tenantDomain
141141
}
142142
}
143143

144+
public void deployAllTenantCertificatesAtStartup() throws APIManagementException {
145+
146+
String endpoint = baseURL + APIConstants.CERTIFICATE_RETRIEVAL_ENDPOINT;
147+
148+
try (CloseableHttpResponse closeableHttpResponse = invokeService(endpoint, tenantDomain)) {
149+
retrieveAllTenantCertificatesAndDeploy(closeableHttpResponse);
150+
} catch (IOException | ArtifactSynchronizerException e) {
151+
throw new APIManagementException("Error while inserting certificates into truststore", e);
152+
}
153+
}
154+
144155
public void deployAllCertificatesAtStartup() throws APIManagementException {
145156

146157
String endpoint = baseURL + APIConstants.CERTIFICATE_RETRIEVAL_ENDPOINT;
@@ -157,6 +168,29 @@ public void deployAllCertificatesAtStartup() throws APIManagementException {
157168
}
158169
}
159170

171+
private void retrieveAllTenantCertificatesAndDeploy(CloseableHttpResponse closeableHttpResponse) throws IOException {
172+
173+
boolean tenantFlowStarted = false;
174+
if (closeableHttpResponse.getStatusLine().getStatusCode() == 200) {
175+
String content = EntityUtils.toString(closeableHttpResponse.getEntity());
176+
List<CertificateMetadataDTO> certificateMetadataDTOList;
177+
Type listType = new TypeToken<List<CertificateMetadataDTO>>() {
178+
}.getType();
179+
certificateMetadataDTOList = new Gson().fromJson(content, listType);
180+
181+
try {
182+
PrivilegedCarbonContext.startTenantFlow();
183+
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
184+
tenantFlowStarted = true;
185+
CertificateManagerImpl.getInstance().addAllTenantCertificatesToGateway(certificateMetadataDTOList);
186+
} finally {
187+
if (tenantFlowStarted) {
188+
PrivilegedCarbonContext.endTenantFlow();
189+
}
190+
}
191+
}
192+
}
193+
160194
private void retrieveAllCertificatesAndDeploy(HttpEntity certContent) throws IOException {
161195
CertificateManager certificateManager = CertificateManagerImpl.getInstance();
162196
String content = EntityUtils.toString(certContent);

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/listeners/GatewayStartupListener.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ public void createdConfigurationContext(ConfigurationContext configContext) {
480480
cleanDeployment(configContext.getAxisConfiguration().getRepository().getPath());
481481
new Thread(() -> {
482482
try {
483-
new EndpointCertificateDeployer(tenantDomain).deployCertificatesAtStartup();
483+
new EndpointCertificateDeployer(tenantDomain).deployAllTenantCertificatesAtStartup();
484484
new GoogleAnalyticsConfigDeployer(tenantDomain).deploy();
485485
} catch (APIManagementException e) {
486486
log.error(e);

components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/certificatemgt/CertificateManager.java

+8
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,14 @@ ResponseCode updateClientCertificate(String certificate, String alias, String ti
258258
*/
259259
boolean addAllCertificateToGateway(String certificate, String alias, int tenantId);
260260

261+
/**
262+
* Method to add the all tenant's certificate to gateway nodes.
263+
*
264+
* @param certificateMetadataDTOList : The list of all certificates of a tenant
265+
*/
266+
void addAllTenantCertificatesToGateway(List<CertificateMetadataDTO> certificateMetadataDTOList);
267+
268+
261269
/**
262270
* This method is used to retrieve all the certificates.
263271
*

components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/certificatemgt/CertificateManagerImpl.java

+6
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,12 @@ private boolean touchSSLListenerConfigFile() {
575575
return success;
576576
}
577577

578+
@Override
579+
public void addAllTenantCertificatesToGateway(List<CertificateMetadataDTO> certificateMetadataDTOList) {
580+
certificateMgtUtils.deployTenantCertsToGatewaySenderInABatch(certificateMetadataDTOList);
581+
touchSSLSenderConfigFile();
582+
}
583+
578584
@Override
579585
public boolean addAllCertificateToGateway(String certificate, String alias, int tenantId) {
580586
// Check whether the api is invoked via the APIGatewayAdmin service.

components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtils.java

+97
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.jetbrains.annotations.NotNull;
3131
import org.w3c.dom.Document;
3232
import org.wso2.carbon.apimgt.api.dto.CertificateInformationDTO;
33+
import org.wso2.carbon.apimgt.api.dto.CertificateMetadataDTO;
3334
import org.wso2.carbon.apimgt.impl.APIConstants;
3435
import org.wso2.carbon.apimgt.impl.certificatemgt.ResponseCode;
3536
import org.wso2.carbon.apimgt.impl.certificatemgt.TrustStoreUtils;
@@ -38,6 +39,8 @@
3839
import org.wso2.carbon.apimgt.impl.dto.TrustStoreDTO;
3940
import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder;
4041
import org.wso2.carbon.apimgt.impl.wsdl.util.SOAPToRESTConstants;
42+
import org.wso2.carbon.base.MultitenantConstants;
43+
import org.wso2.carbon.context.CarbonContext;
4144
import org.wso2.securevault.SecretResolver;
4245
import org.wso2.securevault.SecretResolverFactory;
4346
import org.wso2.securevault.commons.MiscellaneousUtil;
@@ -68,6 +71,7 @@
6871
import java.security.cert.CertificateFactory;
6972
import java.security.cert.X509Certificate;
7073
import java.util.Iterator;
74+
import java.util.List;
7175
import java.util.Optional;
7276
import javax.xml.namespace.QName;
7377
import javax.xml.parsers.DocumentBuilder;
@@ -954,4 +958,97 @@ public static Optional<X509Certificate> convert(Certificate cert) {
954958
}
955959
return Optional.ofNullable(null);
956960
}
961+
962+
public void deployTenantCertsToGatewaySenderInABatch(List<CertificateMetadataDTO> certificateMetadataDTOList) {
963+
//add cert to sender profile truststore
964+
try {
965+
TrustStoreDTO trustStoreDTO = getSenderProfileTrustStore();
966+
addCertificatesToTrustStore(trustStoreDTO, certificateMetadataDTOList);
967+
} catch (FileNotFoundException | XMLStreamException e) {
968+
log.error("Error reading/writing to the truststore file.", e);
969+
} catch (CertificateManagementException e) {
970+
log.error("Error while storing certificates to the truststore file.", e);
971+
}
972+
}
973+
974+
private void addCertificatesToTrustStore(TrustStoreDTO trustStoreDTO,
975+
List<CertificateMetadataDTO> certificateMetadataDTOList) throws CertificateManagementException {
976+
//Read the client-truststore.jks into a KeyStore.
977+
File trustStoreFile = new File(trustStoreDTO.getLocation());
978+
int loggedInTenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
979+
try (InputStream localTrustStoreStream = new FileInputStream(trustStoreFile)) {
980+
KeyStore trustStore = KeyStore.getInstance(trustStoreDTO.getType());
981+
trustStore.load(localTrustStoreStream, trustStoreDTO.getPassword());
982+
983+
String base64Cert, alias;
984+
for (CertificateMetadataDTO dto : certificateMetadataDTOList) {
985+
base64Cert = dto.getCertificate();
986+
alias = dto.getAlias();
987+
if (loggedInTenantId != MultitenantConstants.SUPER_TENANT_ID) {
988+
alias = alias + "_" + loggedInTenantId;
989+
}
990+
991+
byte[] cert = (Base64.decodeBase64(base64Cert.getBytes(StandardCharsets.UTF_8)));
992+
try (InputStream serverCert = new ByteArrayInputStream(cert)) {
993+
if (serverCert.available() == 0) {
994+
log.error("Certificate is empty for the provided alias " + alias + ". Hence skipping it. ");
995+
}
996+
997+
CertificateFactory cf = CertificateFactory.getInstance(certificateType);
998+
while (serverCert.available() > 0) {
999+
Certificate certificate = cf.generateCertificate(serverCert);
1000+
//Check whether the Alias exists in the trust store.
1001+
if (trustStore.containsAlias(alias)) {
1002+
log.info("Provided certificate alias: " + alias + " already exists in the " +
1003+
"truststore.");
1004+
} else {
1005+
/*
1006+
* If alias is not exists, check whether the certificate is expired or not. If expired
1007+
* set the
1008+
* expired flag.
1009+
* */
1010+
X509Certificate x509Certificate = (X509Certificate) certificate;
1011+
if (x509Certificate.getNotAfter().getTime() <= System.currentTimeMillis()) {
1012+
log.info("Provided certificate " + alias + " is expired.");
1013+
} else {
1014+
//If not expired add the certificate to trust store.
1015+
trustStore.setCertificateEntry(alias, certificate);
1016+
}
1017+
}
1018+
}
1019+
} catch (CertificateException | KeyStoreException e) {
1020+
String msg = "Error loading certificate.";
1021+
log.error(msg, e);
1022+
}
1023+
}
1024+
1025+
try (OutputStream fileOutputStream = new FileOutputStream(trustStoreFile)) {
1026+
trustStore.store(fileOutputStream, trustStoreDTO.getPassword());
1027+
}
1028+
} catch (CertificateException e) {
1029+
String msg = "Error storing certificate.";
1030+
log.error(msg, e);
1031+
throw new CertificateManagementException(msg);
1032+
} catch (FileNotFoundException e) {
1033+
String msg = "Error reading/ writing to the certificate file.";
1034+
log.error(msg, e);
1035+
throw new CertificateManagementException(msg);
1036+
} catch (NoSuchAlgorithmException e) {
1037+
String msg = "Could not find the algorithm to load the certificate.";
1038+
log.error(msg, e);
1039+
throw new CertificateManagementException(msg);
1040+
} catch (UnsupportedEncodingException e) {
1041+
String msg = "Error retrieving certificate from String.";
1042+
log.error(msg, e);
1043+
throw new CertificateManagementException(msg);
1044+
} catch (KeyStoreException e) {
1045+
String msg = "Error loading certificate.";
1046+
log.error(msg, e);
1047+
throw new CertificateManagementException(msg);
1048+
} catch (IOException e) {
1049+
String msg = "Error in loading the certificate.";
1050+
log.error(msg, e);
1051+
throw new CertificateManagementException(msg);
1052+
}
1053+
}
9571054
}

components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1354,8 +1354,8 @@
13541354
"type" : "string",
13551355
"example" : "EXCHANGED",
13561356
"description" : "The type of the tokens to be used (exchanged or without exchanged). Accepted values are EXCHANGED, DIRECT or BOTH.",
1357-
"default" : "DIRECT",
1358-
"enum" : [ "EXCHANGED", "DIRECT", "BOTH" ]
1357+
"enum" : [ "EXCHANGED", "DIRECT", "BOTH" ],
1358+
"default" : "DIRECT"
13591359
}
13601360
}
13611361
},

0 commit comments

Comments
 (0)