From 6559547a9baf8a5344373d7d1175bbe6c4578b17 Mon Sep 17 00:00:00 2001 From: rusirijayodaillesinghe Date: Wed, 29 May 2024 20:57:00 +0530 Subject: [PATCH] Append key type to clientCertificateObject in TemplateBuilder and access the keyType to set in authContext at MutualSSLAuthenticator --- .../security/APIAuthenticationHandler.java | 20 +++++ .../authenticator/MutualSSLAuthenticator.java | 87 ++++++++++++++----- .../wso2/carbon/apimgt/impl/APIConstants.java | 3 + .../apimgt/impl/dao/CertificateMgtDAO.java | 2 +- .../importexport/ImportExportConstants.java | 1 + .../v1/common/TemplateBuilderUtil.java | 15 +++- .../v1/common/mappings/APIControllerUtil.java | 1 + 7 files changed, 102 insertions(+), 27 deletions(-) diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandler.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandler.java index e68aca00112d..3542640264e4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandler.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/APIAuthenticationHandler.java @@ -97,6 +97,7 @@ public class APIAuthenticationHandler extends AbstractHandler implements Managed private String apiKeyHeader; private String apiSecurity; private String apiLevelPolicy; + private String environmentType; private String certificateInformation; private String apiUUID; private String apiType = String.valueOf(APIConstants.ApiTypes.API); // Default API Type @@ -151,6 +152,24 @@ public void setAPILevelPolicy(String apiLevelPolicy) { this.apiLevelPolicy = apiLevelPolicy; } + /** + * To get the environment type (whether production or sandbox). + * + * @return Relevant environment type related to the endpoint. + */ + public String getEnvironmentType() { + return environmentType; + } + + /** + * To set the API level tier policy. + * + * @param environmentType Relevant environment type related to the endpoint. + */ + public void setEnvironmentType(String environmentType) { + this.environmentType = environmentType; + } + /** * Get type of the API * @return API Type @@ -525,6 +544,7 @@ private void handleNoAuthentication(MessageContext messageContext){ authContext.setStopOnQuotaReach(true); //Requests are throttled by the ApiKey that is set here. In an unauthenticated scenario, we will use the client's IP address for throttling. authContext.setApiKey(clientIP); + //TODO: verify the key type authContext.setKeyType(APIConstants.API_KEY_TYPE_PRODUCTION); //This name is hardcoded as anonymous because there is no associated user token authContext.setUsername(APIConstants.END_USER_ANONYMOUS); diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/authenticator/MutualSSLAuthenticator.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/authenticator/MutualSSLAuthenticator.java index 6199f5ac9d0f..f4a0fcd9e6c3 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/authenticator/MutualSSLAuthenticator.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/authenticator/MutualSSLAuthenticator.java @@ -60,7 +60,7 @@ public class MutualSSLAuthenticator implements Authenticator { private boolean isMandatory; // -Format - private HashMap certificates; + private HashMap> certificates; /** * Initialized the mutual SSL authenticator. @@ -71,14 +71,18 @@ public class MutualSSLAuthenticator implements Authenticator { public MutualSSLAuthenticator(String apiLevelPolicy, boolean isMandatory, String certificateDetails) { this.apiLevelPolicy = apiLevelPolicy; certificates = new HashMap<>(); + HashMap certificateData = new HashMap<>(); if (StringUtils.isNotEmpty(certificateDetails)) { String[] certificateParts = certificateDetails.substring(1, certificateDetails.length() - 1).split(","); for (String certificatePart : certificateParts) { int tierDivisionIndex = certificatePart.lastIndexOf("="); if (tierDivisionIndex > 0) { String uniqueIdentifier = certificatePart.substring(0, tierDivisionIndex).trim(); - String tier = certificatePart.substring(tierDivisionIndex + 1); - certificates.put(uniqueIdentifier, tier); + String tierAndKeyTypeString = certificatePart.substring(tierDivisionIndex + 1); + String[] tierAndKeyType = tierAndKeyTypeString.split(APIConstants.DELEM_COLON); + certificateData.put(APIConstants.CLIENT_CERTIFICATE_TIER, tierAndKeyType[0]); + certificateData.put(APIConstants.CLIENT_CERTIFICATE_KEY_TYPE, tierAndKeyType[1]); + certificates.put(uniqueIdentifier, certificateData); } } } @@ -177,11 +181,12 @@ private void setAuthContext(MessageContext messageContext, Certificate certifica String subjectDN = x509Certificate.getSubjectDN().getName(); String uniqueIdentifier = (x509Certificate.getSerialNumber() + "_" + x509Certificate.getSubjectDN()).replaceAll(",", "#").replaceAll("\"", "'").trim(); - String tier = certificates.get(uniqueIdentifier); + String tier = certificates.get(uniqueIdentifier).get(APIConstants.CLIENT_CERTIFICATE_TIER); + String keyType = certificates.get(uniqueIdentifier).get(APIConstants.CLIENT_CERTIFICATE_KEY_TYPE); if (StringUtils.isEmpty(tier)) { handleCertificateNotAssociatedToAPIFailure(messageContext); } - setAuthenticationContext(messageContext, subjectDN, uniqueIdentifier, tier); + setAuthenticationContext(messageContext, subjectDN, uniqueIdentifier, tier, keyType); } /** @@ -195,6 +200,7 @@ private void setAuthContext(MessageContext messageContext, Certificate[] certifi throws APISecurityException, APIManagementException { String tier = null; + String keyType = null; List x509Certificates = Utils.convertCertificatesToX509Certificates(certificatesArray); String subjectDN = x509Certificates.get(0).getSubjectDN().getName(); String issuerDNIdentifier = x509Certificates.get(x509Certificates.size() - 1).getIssuerDN().getName() @@ -205,11 +211,12 @@ private void setAuthContext(MessageContext messageContext, Certificate[] certifi String subjectDNIdentifier = (x509Certificate.getSerialNumber() + "_" + x509Certificate.getSubjectDN()).replaceAll(",", "#").replaceAll("\"", "'").trim(); subjectDNIdentifiers.add(subjectDNIdentifier); - for (Map.Entry entry : certificates.entrySet()) { + for (Map.Entry> entry : certificates.entrySet()) { String key = entry.getKey(); if (StringUtils.equals(subjectDNIdentifier, key)) { uniqueIdentifier = key; - tier = entry.getValue(); + tier = entry.getValue().get(APIConstants.CLIENT_CERTIFICATE_TIER); + keyType = entry.getValue().get(APIConstants.CLIENT_CERTIFICATE_KEY_TYPE); break; } } @@ -218,36 +225,41 @@ private void setAuthContext(MessageContext messageContext, Certificate[] certifi } } if (StringUtils.isEmpty(tier)) { - for (Map.Entry entry : certificates.entrySet()) { + for (Map.Entry> entry : certificates.entrySet()) { String key = entry.getKey(); if (key.contains(issuerDNIdentifier)) { uniqueIdentifier = key; - tier = entry.getValue(); + tier = entry.getValue().get(APIConstants.CLIENT_CERTIFICATE_TIER); + keyType = entry.getValue().get(APIConstants.CLIENT_CERTIFICATE_KEY_TYPE); } } } - if (StringUtils.isEmpty(tier)) { - tier = getTierFromCompleteCertificateChain(x509Certificates, subjectDNIdentifiers); + if (StringUtils.isEmpty(tier) || StringUtils.isEmpty(keyType)) { + subjectDNIdentifiers = getUniqueIdentifierFromCompleteCertificateChain(x509Certificates, subjectDNIdentifiers); } if (StringUtils.isEmpty(tier)) { + tier = getTierFromCompleteCertificateChain(subjectDNIdentifiers); + } + if (StringUtils.isEmpty(keyType)) { + keyType = getKeyTypeFromCompleteCertificateChain(subjectDNIdentifiers); + } + if (StringUtils.isEmpty(tier) || StringUtils.isEmpty(keyType)) { handleCertificateNotAssociatedToAPIFailure(messageContext); } - setAuthenticationContext(messageContext, subjectDN, uniqueIdentifier, tier); + setAuthenticationContext(messageContext, subjectDN, uniqueIdentifier, tier, keyType); } /** - * Fetches tier assigned to the client certificate after making the complete certificate chain using certificates - * in truststore. + * Fetches the list of uniqueIdentifiers for complete certificate chain using certificates in truststore. * - * @param x509Certificates Client certificate chain + * @param x509Certificates client certificates chain * @param uniqueIdentifiers Unique identifiers list for client certificate chain - * @return Tier + * @return uniqueIdentifiers * @throws APIManagementException */ - private String getTierFromCompleteCertificateChain(List x509Certificates, - List uniqueIdentifiers) throws APIManagementException { + private List getUniqueIdentifierFromCompleteCertificateChain(List x509Certificates, + List uniqueIdentifiers) throws APIManagementException { - String tier = null; X509Certificate certificate = x509Certificates.get(x509Certificates.size() - 1); String subjectDN = certificate.getSubjectDN().getName(); String issuerDN = certificate.getIssuerDN().getName(); @@ -266,9 +278,21 @@ private String getTierFromCompleteCertificateChain(List x509Cer isIssuerCertificateUpdated = !StringUtils.equals(subjectDN, issuerDN); } } + return uniqueIdentifiers; + } + /** + * Fetches tier assigned to the client certificate after making the complete certificate chain using certificates + * in truststore. + * + * @param uniqueIdentifiers Unique identifiers list for client certificate chain + * @return Tier + */ + private String getTierFromCompleteCertificateChain(List uniqueIdentifiers) { + + String tier = null; for (String uniqueIdentifier : uniqueIdentifiers) { - tier = certificates.get(uniqueIdentifier); + tier = certificates.get(uniqueIdentifier).get(APIConstants.CLIENT_CERTIFICATE_TIER); if (StringUtils.isNotEmpty(tier)) { break; } @@ -276,6 +300,25 @@ private String getTierFromCompleteCertificateChain(List x509Cer return tier; } + /** + * Fetches keyType assigned to the client certificate after making the complete certificate chain using certificates + * in truststore. + * + * @param uniqueIdentifiers Unique identifiers list for client certificate chain + * @return keyType + */ + private String getKeyTypeFromCompleteCertificateChain(List uniqueIdentifiers) { + + String keyType = null; + for (String uniqueIdentifier : uniqueIdentifiers) { + keyType = certificates.get(uniqueIdentifier).get(APIConstants.CLIENT_CERTIFICATE_KEY_TYPE); + if (StringUtils.isNotEmpty(keyType)) { + break; + } + } + return keyType; + } + /** * Handles failures where message context does not contain client certificates. * @param messageContext Relevant message context @@ -321,7 +364,7 @@ private void handleCertificateNotAssociatedToAPIFailure(MessageContext messageCo * @param tier Throttling policy tier */ private void setAuthenticationContext(MessageContext messageContext, String subjectDN, String uniqueIdentifier, - String tier) { + String tier, String keyType) { AuthenticationContext authContext = new AuthenticationContext(); authContext.setAuthenticated(true); @@ -340,7 +383,7 @@ private void setAuthenticationContext(MessageContext messageContext, String subj } authContext.setApiTier(apiLevelPolicy); APIIdentifier apiIdentifier = getAPIIdentifier(messageContext); - authContext.setKeyType(APIConstants.API_KEY_TYPE_PRODUCTION); + authContext.setKeyType(keyType); authContext.setStopOnQuotaReach(true); authContext.setApiKey(uniqueIdentifier + "_" + apiIdentifier.toString()); authContext.setTier(tier); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java index 394c44553927..e09b8be19a12 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java @@ -790,6 +790,9 @@ private Permissions() { public static final String API_KEY_VALIDATOR_URL = API_KEY_VALIDATOR + "ServerURL"; public static final String API_KEY_VALIDATOR_USERNAME = API_KEY_VALIDATOR + "Username"; public static final String API_KEY_VALIDATOR_PASSWORD = API_KEY_VALIDATOR + "Password"; + public static final String CLIENT_CERTIFICATE_TIER = "TIER"; + public static final String CLIENT_CERTIFICATE_KEY_TYPE = "KEY_TYPE"; + public static final String ENABLE_DEFAULT_KEY_MANAGER_REGISTRATION = API_KEY_VALIDATOR + "EnableDefaultKeyManagerRegistration"; public static final String ENABLE_KEY_MANAGER_RETRIVAL = API_KEY_VALIDATOR + diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/CertificateMgtDAO.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/CertificateMgtDAO.java index 6a96343e6897..0b60c8c05891 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/CertificateMgtDAO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/CertificateMgtDAO.java @@ -126,7 +126,7 @@ public boolean updateClientCertificate(String certificate, String alias, String if (StringUtils.isNotEmpty(tier)) { clientCertificateDTO.setTierName(tier); } - if (StringUtils.isNotEmpty(tier)) { + if (StringUtils.isNotEmpty(keyType)) { clientCertificateDTO.setKeyType(keyType); } try (Connection connection = APIMgtDBUtil.getConnection()) { diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/importexport/ImportExportConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/importexport/ImportExportConstants.java index 213266db14a7..778b058c2424 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/importexport/ImportExportConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/importexport/ImportExportConstants.java @@ -166,6 +166,7 @@ public final class ImportExportConstants { public static final String ALIAS_JSON_KEY = "alias"; public static final String ENDPOINT_JSON_KEY = "endpoint"; + public static final String KEY_TYPE_JSON_KEY = "keyType"; public static final int REFER_REQUIRE_RE_SUBSCRIPTION_CHECK_ITEM = 1; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/TemplateBuilderUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/TemplateBuilderUtil.java index a89467883bb1..ca7e89fe370f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/TemplateBuilderUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/TemplateBuilderUtil.java @@ -184,9 +184,12 @@ public static APITemplateBuilderImpl getAPITemplateBuilder(API api, String tenan if (clientCertificateDTOS != null) { clientCertificateObject = new HashMap<>(); for (ClientCertificateDTO clientCertificateDTO : clientCertificateDTOS) { + /* appending the values without using a data structure to store them separately to avoid conflicts + when reading from certificatesDetails string at MutualSSLAuthenticator */ clientCertificateObject.put(certificateMgtUtils .getUniqueIdentifierOfCertificate(clientCertificateDTO.getCertificate()), - clientCertificateDTO.getTierName()); + clientCertificateDTO.getTierName().concat(APIConstants.DELEM_COLON) + .concat(clientCertificateDTO.getKeyType())); } } @@ -369,9 +372,13 @@ public static APITemplateBuilderImpl getAPITemplateBuilder(APIProduct apiProduct if (clientCertificateDTOS != null) { clientCertificateObject = new HashMap<>(); for (ClientCertificateDTO clientCertificateDTO : clientCertificateDTOS) { - clientCertificateObject.put(certificateMgtUtils - .getUniqueIdentifierOfCertificate(clientCertificateDTO.getCertificate()), - clientCertificateDTO.getTierName()); + /* appending the values without using a data structure to store them separately to avoid conflicts + when reading from certificatesDetails string at MutualSSLAuthenticator */ + clientCertificateObject.put(certificateMgtUtils. + getUniqueIdentifierOfCertificate(clientCertificateDTO.getCertificate()), + clientCertificateDTO.getTierName().concat(APIConstants.DELEM_COLON) + .concat(clientCertificateDTO.getKeyType())); + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIControllerUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIControllerUtil.java index 5fe30674411f..0b20f1bd49dc 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIControllerUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/APIControllerUtil.java @@ -991,6 +991,7 @@ private static void handleClientCertificates(JsonArray certificates, Identifier ClientCertificateDTO cert = new ClientCertificateDTO(); cert.setApiIdentifier(apiIdentifier); cert.setAlias(alias); + cert.setKeyType(certObject.get(ImportExportConstants.KEY_TYPE_JSON_KEY).getAsString()); cert.setTierName(certObject.get(ImportExportConstants.CERTIFICATE_TIER_NAME_PROPERTY).getAsString()); String certName = certObject.get(ImportExportConstants.CERTIFICATE_PATH_PROPERTY).getAsString(); cert.setCertificate(certName);