Skip to content

Commit fb7c2f6

Browse files
committed
Extract CredentialsProvider instance creation logic to SDK
1 parent 1a66707 commit fb7c2f6

File tree

10 files changed

+338
-208
lines changed

10 files changed

+338
-208
lines changed

athena-datalakegen2/src/main/java/com/amazonaws/athena/connectors/datalakegen2/DataLakeGen2CredentialProviderUtils.java

Lines changed: 0 additions & 73 deletions
This file was deleted.

athena-datalakegen2/src/main/java/com/amazonaws/athena/connectors/datalakegen2/DataLakeGen2MetadataHandler.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package com.amazonaws.athena.connectors.datalakegen2;
2121

2222
import com.amazonaws.athena.connector.credentials.CredentialsProvider;
23+
import com.amazonaws.athena.connector.credentials.CredentialsProviderFactory;
2324
import com.amazonaws.athena.connector.lambda.QueryStatusChecker;
2425
import com.amazonaws.athena.connector.lambda.data.Block;
2526
import com.amazonaws.athena.connector.lambda.data.BlockAllocator;
@@ -289,9 +290,10 @@ protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schem
289290
@Override
290291
protected CredentialsProvider getCredentialProvider()
291292
{
292-
return DataLakeGen2CredentialProviderUtils.getCredentialProvider(
293+
return CredentialsProviderFactory.createCredentialProvider(
293294
getDatabaseConnectionConfig().getSecret(),
294-
getCachableSecretsManager()
295+
getCachableSecretsManager(),
296+
DataLakeGen2OAuthCredentialsProvider.class
295297
);
296298
}
297299
}

athena-datalakegen2/src/main/java/com/amazonaws/athena/connectors/datalakegen2/DataLakeGen2OAuthCredentialsProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public DataLakeGen2OAuthCredentialsProvider(String secretName, Map<String, Strin
4949
super(secretName, secretMap, secretsManager, httpClient);
5050
}
5151

52-
protected static boolean isOAuthConfigured(Map<String, String> secretMap)
52+
@Override
53+
protected boolean isOAuthConfigured(Map<String, String> secretMap)
5354
{
5455
return secretMap.containsKey(CredentialsConstants.CLIENT_ID) &&
5556
!secretMap.get(CredentialsConstants.CLIENT_ID).isEmpty() &&

athena-datalakegen2/src/main/java/com/amazonaws/athena/connectors/datalakegen2/DataLakeGen2RecordHandler.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package com.amazonaws.athena.connectors.datalakegen2;
2121
import com.amazonaws.athena.connector.credentials.CredentialsProvider;
22+
import com.amazonaws.athena.connector.credentials.CredentialsProviderFactory;
2223
import com.amazonaws.athena.connector.lambda.domain.Split;
2324
import com.amazonaws.athena.connector.lambda.domain.TableName;
2425
import com.amazonaws.athena.connector.lambda.domain.predicate.Constraints;
@@ -81,9 +82,10 @@ public PreparedStatement buildSplitSql(Connection jdbcConnection, String catalog
8182
@Override
8283
protected CredentialsProvider getCredentialProvider()
8384
{
84-
return DataLakeGen2CredentialProviderUtils.getCredentialProvider(
85+
return CredentialsProviderFactory.createCredentialProvider(
8586
getDatabaseConnectionConfig().getSecret(),
86-
getCachableSecretsManager()
87+
getCachableSecretsManager(),
88+
DataLakeGen2OAuthCredentialsProvider.class
8789
);
8890
}
8991
}

athena-datalakegen2/src/test/java/com/amazonaws/athena/connectors/datalakegen2/DataLakeGen2CredentialProviderUtilsTest.java

Lines changed: 0 additions & 128 deletions
This file was deleted.

athena-datalakegen2/src/test/java/com/amazonaws/athena/connectors/datalakegen2/DataLakeGen2OAuthCredentialsProviderTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public void testIsOAuthConfigured_WithValidConfig()
8282
secretMap.put(CLIENT_SECRET, TEST_CLIENT_SECRET);
8383
secretMap.put(TENANT_ID, TEST_TENANT_ID);
8484

85-
assertTrue(DataLakeGen2OAuthCredentialsProvider.isOAuthConfigured(secretMap));
85+
assertTrue(credentialsProvider.isOAuthConfigured(secretMap));
8686
}
8787

8888
@Test
@@ -92,7 +92,7 @@ public void testIsOAuthConfigured_WithMissingConfig()
9292
secretMap.put(CLIENT_ID, TEST_CLIENT_ID);
9393
// Missing client_secret and tenant_id
9494

95-
assertFalse(DataLakeGen2OAuthCredentialsProvider.isOAuthConfigured(secretMap));
95+
assertFalse(credentialsProvider.isOAuthConfigured(secretMap));
9696
}
9797

9898
@Test
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*-
2+
* #%L
3+
* athena-federation-sdk
4+
* %%
5+
* Copyright (C) 2019 - 2025 Amazon Web Services
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.amazonaws.athena.connector.credentials;
21+
22+
import com.amazonaws.athena.connector.lambda.exceptions.AthenaConnectorException;
23+
import com.amazonaws.athena.connector.lambda.security.CachableSecretsManager;
24+
import com.fasterxml.jackson.databind.ObjectMapper;
25+
import org.apache.commons.lang3.StringUtils;
26+
import software.amazon.awssdk.services.glue.model.ErrorDetails;
27+
import software.amazon.awssdk.services.glue.model.FederationSourceErrorCode;
28+
29+
import java.io.IOException;
30+
import java.lang.reflect.Constructor;
31+
import java.util.Map;
32+
33+
/**
34+
* Factory class for handling credentials provider creation.
35+
* This class can be used by any connector that needs to support both
36+
* OAuth and username/password authentication.
37+
*/
38+
public final class CredentialsProviderFactory
39+
{
40+
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
41+
42+
private CredentialsProviderFactory()
43+
{
44+
}
45+
46+
/**
47+
* Creates a credentials provider based on the secret configuration.
48+
* If OAuth is configured (determined by the provider's isOAuthConfigured method), creates an instance
49+
* of the specified OAuth provider. Otherwise, creates a default username/password credentials provider.
50+
*
51+
* @param secretName The name of the secret in AWS Secrets Manager
52+
* @param secretsManager The secrets manager instance
53+
* @param oAuthProviderClass The class of the OAuth provider to instantiate (must extend OAuthCredentialsProvider)
54+
* @return A new CredentialsProvider instance based on the secret configuration
55+
* @throws AthenaConnectorException if there are errors deserializing the secret or creating the provider
56+
*/
57+
public static <T extends OAuthCredentialsProvider> CredentialsProvider createCredentialProvider(
58+
String secretName,
59+
CachableSecretsManager secretsManager,
60+
Class<T> oAuthProviderClass)
61+
{
62+
if (StringUtils.isNotBlank(secretName)) {
63+
try {
64+
String secretString = secretsManager.getSecret(secretName);
65+
Map<String, String> secretMap = OBJECT_MAPPER.readValue(secretString, Map.class);
66+
67+
// Create an instance of the OAuth provider
68+
T provider;
69+
try {
70+
Constructor<T> constructor = oAuthProviderClass.getConstructor(
71+
String.class, Map.class, CachableSecretsManager.class);
72+
provider = constructor.newInstance(secretName, secretMap, secretsManager);
73+
}
74+
catch (ReflectiveOperationException e) {
75+
throw new AthenaConnectorException("Failed to create OAuth provider: " + e.getMessage(),
76+
ErrorDetails.builder()
77+
.errorCode(FederationSourceErrorCode.INTERNAL_SERVICE_EXCEPTION.toString())
78+
.errorMessage(e.getMessage())
79+
.build());
80+
}
81+
82+
// Check if OAuth is configured
83+
if (provider.isOAuthConfigured(secretMap)) {
84+
return provider;
85+
}
86+
87+
// Fall back to default credentials if OAuth is not configured
88+
return new DefaultCredentialsProvider(secretString);
89+
}
90+
catch (IOException ioException) {
91+
throw new AthenaConnectorException("Could not deserialize credentials into HashMap: ",
92+
ErrorDetails.builder()
93+
.errorCode(FederationSourceErrorCode.INTERNAL_SERVICE_EXCEPTION.toString())
94+
.errorMessage(ioException.getMessage())
95+
.build());
96+
}
97+
}
98+
99+
return null;
100+
}
101+
}

athena-federation-sdk/src/main/java/com/amazonaws/athena/connector/credentials/OAuthCredentialsProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ public Credentials getCredential()
106106
}
107107
}
108108

109+
/**
110+
* Checks if OAuth is configured by verifying required fields exist.
111+
*/
112+
protected abstract boolean isOAuthConfigured(Map<String, String> secretMap);
113+
109114
/**
110115
* Builds the token request for the specific OAuth provider.
111116
*/

0 commit comments

Comments
 (0)