Skip to content

Commit

Permalink
Append key type to clientCertificateObject in TemplateBuilder and acc…
Browse files Browse the repository at this point in the history
…ess the keyType to set in authContext at MutualSSLAuthenticator
  • Loading branch information
RusJaI committed May 29, 2024
1 parent 4d1d00e commit e9605db
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,17 @@ public void setTierName(String tierName) {
}

/**
* To get the endpoint type of the certificate.
* @return endpoint type.
* To get the key type of the certificate.
* @return key type.
*/
public String getKeyType() {
return keyType;
}

/**
* To set the endpoint type for the current certificate.
* To set the key type for the current certificate.
*
* @param keyType endpoint type (whether PRODUCTION or SANDBOX).
* @param keyType key type (whether PRODUCTION or SANDBOX).
*/
public void setKeyType(String keyType) {
this.keyType = keyType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -151,6 +152,24 @@ public void setAPILevelPolicy(String apiLevelPolicy) {
this.apiLevelPolicy = apiLevelPolicy;
}

/**
* To get the environment type (whether production or sandbox).
*
* @return the environment type.
*/
public String getEnvironmentType() {
return environmentType;
}

/**
* To set the environment type (whether production or sandbox).
*
* @param environmentType the environment type.
*/
public void setEnvironmentType(String environmentType) {
this.environmentType = environmentType;
}

/**
* Get type of the API
* @return API Type
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class MutualSSLAuthenticator implements Authenticator {
private boolean isMandatory;

// <UniqueIdentifierName,Tier> -Format
private HashMap<String, String> certificates;
private HashMap<String, HashMap<String, String>> certificates;

/**
* Initialized the mutual SSL authenticator.
Expand All @@ -71,14 +71,18 @@ public class MutualSSLAuthenticator implements Authenticator {
public MutualSSLAuthenticator(String apiLevelPolicy, boolean isMandatory, String certificateDetails) {
this.apiLevelPolicy = apiLevelPolicy;
certificates = new HashMap<>();
HashMap<String, String> 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);
}
}
}
Expand Down Expand Up @@ -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);
}

/**
Expand All @@ -195,6 +200,7 @@ private void setAuthContext(MessageContext messageContext, Certificate[] certifi
throws APISecurityException, APIManagementException {

String tier = null;
String keyType = null;
List<X509Certificate> x509Certificates = Utils.convertCertificatesToX509Certificates(certificatesArray);
String subjectDN = x509Certificates.get(0).getSubjectDN().getName();
String issuerDNIdentifier = x509Certificates.get(x509Certificates.size() - 1).getIssuerDN().getName()
Expand All @@ -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<String, String> entry : certificates.entrySet()) {
for (Map.Entry<String, HashMap<String, String>> 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;
}
}
Expand All @@ -218,36 +225,41 @@ private void setAuthContext(MessageContext messageContext, Certificate[] certifi
}
}
if (StringUtils.isEmpty(tier)) {
for (Map.Entry<String, String> entry : certificates.entrySet()) {
for (Map.Entry<String, HashMap<String, String>> 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<X509Certificate> x509Certificates,
List<String> uniqueIdentifiers) throws APIManagementException {
private List<String> getUniqueIdentifierFromCompleteCertificateChain(List<X509Certificate> x509Certificates,
List<String> uniqueIdentifiers) throws APIManagementException {

String tier = null;
X509Certificate certificate = x509Certificates.get(x509Certificates.size() - 1);
String subjectDN = certificate.getSubjectDN().getName();
String issuerDN = certificate.getIssuerDN().getName();
Expand All @@ -266,16 +278,47 @@ private String getTierFromCompleteCertificateChain(List<X509Certificate> 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<String> 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;
}
}
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<String> 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
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4631,7 +4631,7 @@ paths:
description: API tier to which the certificate should be applied.
keyType:
type: string
description: Whether the endpoint is production or sandbox
description: Whether the key type is PRODUCTION or SANDBOX
default: PRODUCTION
required: true
responses:
Expand Down Expand Up @@ -4747,7 +4747,7 @@ paths:
description: The tier of the certificate
keyType:
type: string
description: Whether the endpoint is production or sandbox
description: Whether the key type is PRODUCTION or SANDBOX
default: PRODUCTION
responses:
200:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
}

Expand Down Expand Up @@ -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()));

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4631,7 +4631,7 @@ paths:
description: API tier to which the certificate should be applied.
keyType:
type: string
description: Whether the endpoint is production or sandbox
description: Whether the key type is PRODUCTION or SANDBOX
default: PRODUCTION
required: true
responses:
Expand Down Expand Up @@ -4747,7 +4747,7 @@ paths:
description: The tier of the certificate
keyType:
type: string
description: Whether the endpoint is production or sandbox
description: Whether the key type is PRODUCTION or SANDBOX
default: PRODUCTION
responses:
200:
Expand Down

0 comments on commit e9605db

Please sign in to comment.