From f1f35b356a81bfaeacd8bc09d580bcf87c265061 Mon Sep 17 00:00:00 2001 From: Bhavik Shah <115029313+bhvkshah@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:57:09 -0500 Subject: [PATCH] Fixed a bug where the check for token/credentials expiration time was incorrect --- .../com/amazon/redshift/CredentialsHolder.java | 3 ++- .../com/amazon/redshift/NativeTokenHolder.java | 5 +++-- .../com/amazon/redshift/core/IamHelper.java | 6 +++--- .../redshift/core/NativeAuthPluginHelper.java | 8 ++------ .../redshift/core/ServerlessIamHelper.java | 3 ++- .../amazon/redshift/jdbc/RedshiftSQLXML.java | 18 +++++++++--------- .../redshift/plugin/utils/RequestUtils.java | 13 +++++++++++++ 7 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/amazon/redshift/CredentialsHolder.java b/src/main/java/com/amazon/redshift/CredentialsHolder.java index 32ebd34..65c8bb6 100755 --- a/src/main/java/com/amazon/redshift/CredentialsHolder.java +++ b/src/main/java/com/amazon/redshift/CredentialsHolder.java @@ -2,6 +2,7 @@ import java.util.Date; +import com.amazon.redshift.plugin.utils.RequestUtils; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSSessionCredentials; @@ -70,7 +71,7 @@ public String getAWSSecretKey() public boolean isExpired() { - return m_expiration != null && m_expiration.before(new Date(System.currentTimeMillis() - 60 * 1000 * 5)); + return RequestUtils.isCredentialExpired(m_expiration); } public Date getExpiration() diff --git a/src/main/java/com/amazon/redshift/NativeTokenHolder.java b/src/main/java/com/amazon/redshift/NativeTokenHolder.java index dd1bbf6..f4b7833 100644 --- a/src/main/java/com/amazon/redshift/NativeTokenHolder.java +++ b/src/main/java/com/amazon/redshift/NativeTokenHolder.java @@ -1,5 +1,7 @@ package com.amazon.redshift; +import com.amazon.redshift.plugin.utils.RequestUtils; + import java.util.Date; @@ -31,8 +33,7 @@ public static NativeTokenHolder newInstance(String accessToken, Date expiration) public boolean isExpired() { - return (m_expiration == null) - || (m_expiration != null && m_expiration.before(new Date(System.currentTimeMillis() - 60 * 1000 * 5))); + return RequestUtils.isCredentialExpired(m_expiration); } public String getAccessToken() diff --git a/src/main/java/com/amazon/redshift/core/IamHelper.java b/src/main/java/com/amazon/redshift/core/IamHelper.java index a178d92..fb57425 100755 --- a/src/main/java/com/amazon/redshift/core/IamHelper.java +++ b/src/main/java/com/amazon/redshift/core/IamHelper.java @@ -574,7 +574,7 @@ else if (RedshiftProperty.DB_GROUPS_FILTER.getName().equalsIgnoreCase(pluginArgK } if (credentials == null - || credentials.getExpiration().before(new Date(System.currentTimeMillis() - 60 * 1000 * 5))) { + || RequestUtils.isCredentialExpired(credentials.getExpiration())) { // If not found or expired // Get IDP token if (providerType == CredentialProviderType.PLUGIN) { @@ -806,7 +806,7 @@ private static synchronized GetClusterCredentialsResult getClusterCredentialsRes } if (credentials == null || (providerType == CredentialProviderType.PLUGIN && idpCredentialsRefresh) - || credentials.getExpiration().before(new Date(System.currentTimeMillis() - 60 * 1000 * 5))) { + || RequestUtils.isCredentialExpired(credentials.getExpiration())) { if (RedshiftLogger.isEnable()) log.logInfo("GetClusterCredentials NOT from cache"); @@ -940,7 +940,7 @@ private static synchronized GetClusterCredentialsWithIAMResult getClusterCredent } if (credentials == null || (providerType == CredentialProviderType.PLUGIN && settings.m_idpToken != null) - || credentials.getExpiration().before(new Date(System.currentTimeMillis() - 60 * 1000 * 5))) + || RequestUtils.isCredentialExpired(credentials.getExpiration())) { if (RedshiftLogger.isEnable()) log.logInfo("GetClusterCredentialsV2 NOT from cache"); diff --git a/src/main/java/com/amazon/redshift/core/NativeAuthPluginHelper.java b/src/main/java/com/amazon/redshift/core/NativeAuthPluginHelper.java index 50295fb..fb751f1 100755 --- a/src/main/java/com/amazon/redshift/core/NativeAuthPluginHelper.java +++ b/src/main/java/com/amazon/redshift/core/NativeAuthPluginHelper.java @@ -1,5 +1,6 @@ package com.amazon.redshift.core; +import com.amazon.redshift.plugin.utils.RequestUtils; import com.amazon.redshift.util.RedshiftProperties; import com.amazonaws.util.StringUtils; import com.amazon.redshift.INativePlugin; @@ -142,12 +143,7 @@ private static String getNativeAuthPluginCredentials(RedshiftJDBCSettings settin // here. NativeTokenHolder credentials = provider.getCredentials(); - if (credentials == null - || - (credentials.getExpiration() != null - && credentials.getExpiration().before(new Date(System.currentTimeMillis() - 60 * 1000 * 5)) - ) - ) { + if (credentials == null || RequestUtils.isCredentialExpired(credentials.getExpiration())) { // If not found or expired // Get IDP token IPlugin plugin = (IPlugin) provider; diff --git a/src/main/java/com/amazon/redshift/core/ServerlessIamHelper.java b/src/main/java/com/amazon/redshift/core/ServerlessIamHelper.java index e8b9600..5738f36 100644 --- a/src/main/java/com/amazon/redshift/core/ServerlessIamHelper.java +++ b/src/main/java/com/amazon/redshift/core/ServerlessIamHelper.java @@ -6,6 +6,7 @@ import com.amazon.redshift.core.IamHelper.CredentialProviderType; import com.amazon.redshift.logger.RedshiftLogger; +import com.amazon.redshift.plugin.utils.RequestUtils; import com.amazonaws.AmazonClientException; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.redshiftserverless.AWSRedshiftServerlessClient; @@ -78,7 +79,7 @@ synchronized void getCredentialsResult(RedshiftJDBCSettings settings, if (credentials == null || (providerType == CredentialProviderType.PLUGIN && idpCredentialsRefresh) - || credentials.getExpiration().before(new Date(System.currentTimeMillis() - 60 * 1000 * 5))) + || RequestUtils.isCredentialExpired(credentials.getExpiration())) { if (RedshiftLogger.isEnable()) log.logInfo("GetCredentials NOT from cache"); diff --git a/src/main/java/com/amazon/redshift/jdbc/RedshiftSQLXML.java b/src/main/java/com/amazon/redshift/jdbc/RedshiftSQLXML.java index 0d64c44..e903fff 100644 --- a/src/main/java/com/amazon/redshift/jdbc/RedshiftSQLXML.java +++ b/src/main/java/com/amazon/redshift/jdbc/RedshiftSQLXML.java @@ -26,6 +26,7 @@ import java.sql.SQLException; import java.sql.SQLXML; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLInputFactory; @@ -205,11 +206,10 @@ public synchronized T setResult(Class resultClass) throws (SAXTransformerFactory) SAXTransformerFactory.newInstance(); // https://www.aristotle.a2z.com/implementations/255 - transformerFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - transformerFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - transformerFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); - transformerFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false); - + + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + TransformerHandler transformerHandler = transformerFactory.newTransformerHandler(); stringWriter = new StringWriter(); transformerHandler.setResult(new StreamResult(stringWriter)); @@ -293,10 +293,10 @@ private void ensureInitialized() throws SQLException { // Disable External Entities (XXE) parsing for Java // https://www.aristotle.a2z.com/implementations/255 - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - + + factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + Transformer transformer = factory.newTransformer(); DOMSource domSource = new DOMSource(domResult.getNode()); StringWriter stringWriter = new StringWriter(); diff --git a/src/main/java/com/amazon/redshift/plugin/utils/RequestUtils.java b/src/main/java/com/amazon/redshift/plugin/utils/RequestUtils.java index a8301e9..b575cb9 100755 --- a/src/main/java/com/amazon/redshift/plugin/utils/RequestUtils.java +++ b/src/main/java/com/amazon/redshift/plugin/utils/RequestUtils.java @@ -8,6 +8,7 @@ import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; import java.net.URL; +import java.util.Date; /** * Http Request utils. @@ -112,4 +113,16 @@ private static boolean isCustomStsEndpointUrl(String stsEndpoint) throws Excepti return isCustomStsEndPoint; } + + /* + * Checks expiry for credential. + * Note that this method returns true (i.e. credential is "expired") 1 minute before actual expiry time - This + * arbitrary buffer has been added to accommodate corner cases and allow enough time for retries if implemented. + * + * Returns true (i.e. credential is "expired") if expiry time is null. + */ + public static boolean isCredentialExpired(Date expiryTime) { + // We preemptively conclude the credential as expired 1 minute before actual expiry. + return expiryTime==null || expiryTime.before(new Date(System.currentTimeMillis() + 1000 * 60)); + } }