Skip to content

Commit 3e6bd2a

Browse files
add plugin for DSQL auth tokens
1 parent 3b32ac2 commit 3e6bd2a

14 files changed

+511
-10
lines changed

wrapper/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ dependencies {
3737
compileOnly("software.amazon.awssdk:rds:2.31.78")
3838
compileOnly("software.amazon.awssdk:auth:2.31.45") // Required for IAM (light implementation)
3939
compileOnly("software.amazon.awssdk:http-client-spi:2.31.60") // Required for IAM (light implementation)
40+
compileOnly("software.amazon.awssdk:dsql:2.31.78")
4041
compileOnly("software.amazon.awssdk:sts:2.31.78")
4142
compileOnly("com.zaxxer:HikariCP:4.0.3") // Version 4.+ is compatible with Java 8
4243
compileOnly("com.mchange:c3p0:0.11.0")
@@ -73,6 +74,7 @@ dependencies {
7374
testImplementation("software.amazon.awssdk:rds:2.31.78")
7475
testImplementation("software.amazon.awssdk:auth:2.31.45") // Required for IAM (light implementation)
7576
testImplementation("software.amazon.awssdk:http-client-spi:2.31.60") // Required for IAM (light implementation)
77+
testImplementation("software.amazon.awssdk:dsql:2.31.78")
7678
testImplementation("software.amazon.awssdk:ec2:2.31.78")
7779
testImplementation("software.amazon.awssdk:secretsmanager:2.31.12")
7880
testImplementation("software.amazon.awssdk:sts:2.31.78")

wrapper/src/main/java/software/amazon/jdbc/ConnectionPluginChainBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import software.amazon.jdbc.plugin.failover.FailoverConnectionPluginFactory;
4646
import software.amazon.jdbc.plugin.federatedauth.FederatedAuthPluginFactory;
4747
import software.amazon.jdbc.plugin.federatedauth.OktaAuthPluginFactory;
48+
import software.amazon.jdbc.plugin.iam.DsqlIamConnectionPluginFactory;
4849
import software.amazon.jdbc.plugin.iam.IamAuthConnectionPluginFactory;
4950
import software.amazon.jdbc.plugin.limitless.LimitlessConnectionPluginFactory;
5051
import software.amazon.jdbc.plugin.readwritesplitting.ReadWriteSplittingPluginFactory;
@@ -75,6 +76,7 @@ public class ConnectionPluginChainBuilder {
7576
put("failover", new FailoverConnectionPluginFactory());
7677
put("failover2", new software.amazon.jdbc.plugin.failover2.FailoverConnectionPluginFactory());
7778
put("iam", new IamAuthConnectionPluginFactory());
79+
put("iamDsql", new DsqlIamConnectionPluginFactory());
7880
put("awsSecretsManager", new AwsSecretsManagerConnectionPluginFactory());
7981
put("federatedAuth", new FederatedAuthPluginFactory());
8082
put("okta", new OktaAuthPluginFactory());
@@ -114,6 +116,7 @@ public class ConnectionPluginChainBuilder {
114116
put(FastestResponseStrategyPluginFactory.class, 900);
115117
put(LimitlessConnectionPluginFactory.class, 950);
116118
put(IamAuthConnectionPluginFactory.class, 1000);
119+
put(DsqlIamConnectionPluginFactory.class, 1001);
117120
put(AwsSecretsManagerConnectionPluginFactory.class, 1100);
118121
put(FederatedAuthPluginFactory.class, 1200);
119122
put(LogQueryConnectionPluginFactory.class, 1300);

wrapper/src/main/java/software/amazon/jdbc/plugin/federatedauth/FederatedAuthPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public Set<String> getSubscribedMethods() {
121121

122122
public FederatedAuthPlugin(final PluginService pluginService,
123123
final CredentialsProviderFactory credentialsProviderFactory) {
124-
this(pluginService, credentialsProviderFactory, new RdsUtils(), IamAuthUtils.getTokenUtility());
124+
this(pluginService, credentialsProviderFactory, new RdsUtils(), IamAuthUtils.getRdsTokenUtility());
125125
}
126126

127127
FederatedAuthPlugin(

wrapper/src/main/java/software/amazon/jdbc/plugin/federatedauth/OktaAuthPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public class OktaAuthPlugin extends AbstractConnectionPlugin {
9595
private final TelemetryCounter fetchTokenCounter;
9696

9797
public OktaAuthPlugin(PluginService pluginService, CredentialsProviderFactory credentialsProviderFactory) {
98-
this(pluginService, credentialsProviderFactory, new RdsUtils(), IamAuthUtils.getTokenUtility());
98+
this(pluginService, credentialsProviderFactory, new RdsUtils(), IamAuthUtils.getRdsTokenUtility());
9999
}
100100

101101
OktaAuthPlugin(
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package software.amazon.jdbc.plugin.iam;
18+
19+
import java.util.Properties;
20+
import org.checkerframework.checker.nullness.qual.NonNull;
21+
import software.amazon.jdbc.ConnectionPlugin;
22+
import software.amazon.jdbc.ConnectionPluginFactory;
23+
import software.amazon.jdbc.PluginService;
24+
import software.amazon.jdbc.util.IamAuthUtils;
25+
26+
/**
27+
* Provides {@link ConnectionPlugin} instances which can be used to connect to Amazon Aurora DSQL.
28+
*/
29+
public class DsqlIamConnectionPluginFactory implements ConnectionPluginFactory {
30+
@Override
31+
public ConnectionPlugin getInstance(@NonNull final PluginService pluginService, @NonNull final Properties props) {
32+
return new IamAuthConnectionPlugin(pluginService, IamAuthUtils.getDsqlTokenUtility());
33+
}
34+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package software.amazon.jdbc.plugin.iam;
18+
19+
import org.checkerframework.checker.nullness.qual.NonNull;
20+
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
21+
import software.amazon.awssdk.regions.Region;
22+
import software.amazon.awssdk.services.dsql.DsqlUtilities;
23+
24+
/**
25+
* Represents an {@link IamTokenUtility} which provides auth tokens for connecting to Amazon Aurora DSQL.
26+
*/
27+
public class DsqlTokenUtility implements IamTokenUtility {
28+
29+
private DsqlUtilities utilities = null;
30+
31+
public DsqlTokenUtility() { }
32+
33+
@Override
34+
public String generateAuthenticationToken(
35+
@NonNull final AwsCredentialsProvider credentialsProvider,
36+
@NonNull final Region region,
37+
@NonNull final String hostname,
38+
final int port,
39+
@NonNull final String username) {
40+
if (this.utilities == null) {
41+
this.utilities = DsqlUtilities.builder()
42+
.credentialsProvider(credentialsProvider)
43+
.region(region)
44+
.build();
45+
}
46+
if (username.equals("admin")) {
47+
return this.utilities.generateDbConnectAdminAuthToken((builder) ->
48+
builder.hostname(hostname).region(region)
49+
);
50+
} else {
51+
return this.utilities.generateDbConnectAuthToken((builder) ->
52+
builder.hostname(hostname).region(region)
53+
);
54+
}
55+
}
56+
}

wrapper/src/main/java/software/amazon/jdbc/plugin/iam/IamAuthConnectionPlugin.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,7 @@ public class IamAuthConnectionPlugin extends AbstractConnectionPlugin {
8686

8787
private final IamTokenUtility iamTokenUtility;
8888

89-
public IamAuthConnectionPlugin(final @NonNull PluginService pluginService) {
90-
this(pluginService, IamAuthUtils.getTokenUtility());
91-
}
92-
93-
IamAuthConnectionPlugin(final @NonNull PluginService pluginService, IamTokenUtility utility) {
89+
IamAuthConnectionPlugin(final @NonNull PluginService pluginService, final IamTokenUtility utility) {
9490
this.iamTokenUtility = utility;
9591
this.pluginService = pluginService;
9692
this.telemetryFactory = pluginService.getTelemetryFactory();

wrapper/src/main/java/software/amazon/jdbc/plugin/iam/IamAuthConnectionPluginFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
import software.amazon.jdbc.ConnectionPlugin;
2121
import software.amazon.jdbc.ConnectionPluginFactory;
2222
import software.amazon.jdbc.PluginService;
23+
import software.amazon.jdbc.util.IamAuthUtils;
2324

2425
public class IamAuthConnectionPluginFactory implements ConnectionPluginFactory {
2526
@Override
2627
public ConnectionPlugin getInstance(final PluginService pluginService, final Properties props) {
27-
return new IamAuthConnectionPlugin(pluginService);
28+
return new IamAuthConnectionPlugin(pluginService, IamAuthUtils.getRdsTokenUtility());
2829
}
2930
}

wrapper/src/main/java/software/amazon/jdbc/util/IamAuthUtils.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import software.amazon.awssdk.regions.Region;
2222
import software.amazon.jdbc.HostSpec;
2323
import software.amazon.jdbc.PluginService;
24+
import software.amazon.jdbc.plugin.iam.DsqlTokenUtility;
2425
import software.amazon.jdbc.plugin.iam.IamTokenUtility;
2526
import software.amazon.jdbc.plugin.iam.LightRdsUtility;
2627
import software.amazon.jdbc.plugin.iam.RegularRdsUtility;
@@ -59,7 +60,7 @@ public static String getCacheKey(
5960
return String.format("%s:%s:%d:%s", region, hostname, port, user);
6061
}
6162

62-
public static IamTokenUtility getTokenUtility() {
63+
public static IamTokenUtility getRdsTokenUtility() {
6364
try {
6465
// RegularRdsUtility requires AWS Java SDK RDS v2.x to be presented in classpath.
6566
Class.forName("software.amazon.awssdk.services.rds.RdsUtilities");
@@ -81,6 +82,15 @@ public static IamTokenUtility getTokenUtility() {
8182
}
8283
}
8384

85+
public static IamTokenUtility getDsqlTokenUtility() {
86+
try {
87+
Class.forName("software.amazon.awssdk.services.dsql.DsqlUtilities");
88+
return new DsqlTokenUtility();
89+
} catch (final ClassNotFoundException e) {
90+
throw new RuntimeException(Messages.get("AuthenticationToken.javaDsqlSdkNotInClasspath"), e);
91+
}
92+
}
93+
8494
public static String generateAuthenticationToken(
8595
final IamTokenUtility tokenUtils,
8696
final PluginService pluginService,

wrapper/src/main/java/software/amazon/jdbc/util/RdsUtils.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ public class RdsUtils {
144144
+ "\\.(amazonaws\\.com\\.?|c2s\\.ic\\.gov\\.?|sc2s\\.sgov\\.gov\\.?))$",
145145
Pattern.CASE_INSENSITIVE);
146146

147+
private static final Pattern AURORA_DSQL_CLUSTER_PATTERN =
148+
Pattern.compile(
149+
"^(?<instance>[^.]+)\\."
150+
+ "(?<dns>dsql(?:-[^.]+)?)\\."
151+
+ "(?<domain>(?<region>[a-zA-Z0-9\\-]+)"
152+
+ "\\.on\\.aws\\.?)$",
153+
Pattern.CASE_INSENSITIVE);
154+
147155
private static final Pattern ELB_PATTERN =
148156
Pattern.compile(
149157
"^(?<instance>.+)\\.elb\\."
@@ -259,14 +267,25 @@ public String getRdsInstanceHostPattern(final String host) {
259267
return group == null ? "?" : "?." + group;
260268
}
261269

270+
public String getDsqlInstanceId(final String host) {
271+
final String preparedHost = getPreparedHost(host);
272+
if (StringUtils.isNullOrEmpty(preparedHost)) {
273+
return null;
274+
}
275+
276+
final Matcher matcher = cacheMatcher(preparedHost, AURORA_DSQL_CLUSTER_PATTERN);
277+
return getRegexGroup(matcher, INSTANCE_GROUP);
278+
}
279+
262280
public String getRdsRegion(final String host) {
263281
final String preparedHost = getPreparedHost(host);
264282
if (StringUtils.isNullOrEmpty(preparedHost)) {
265283
return null;
266284
}
267285

268286
final Matcher matcher = cacheMatcher(preparedHost,
269-
AURORA_DNS_PATTERN, AURORA_CHINA_DNS_PATTERN, AURORA_OLD_CHINA_DNS_PATTERN, AURORA_GOV_DNS_PATTERN);
287+
AURORA_DNS_PATTERN, AURORA_CHINA_DNS_PATTERN, AURORA_OLD_CHINA_DNS_PATTERN, AURORA_GOV_DNS_PATTERN,
288+
AURORA_DSQL_CLUSTER_PATTERN);
270289
final String group = getRegexGroup(matcher, REGION_GROUP);
271290
if (group != null) {
272291
return group;
@@ -294,6 +313,11 @@ public boolean isLimitlessDbShardGroupDns(final String host) {
294313
return dnsGroup != null && dnsGroup.equalsIgnoreCase("shardgrp-");
295314
}
296315

316+
public boolean isDsqlCluster(final String host) {
317+
final String instanceId = getDsqlInstanceId(host);
318+
return instanceId != null;
319+
}
320+
297321
public String getRdsClusterHostUrl(final String host) {
298322
final String preparedHost = getPreparedHost(host);
299323
if (StringUtils.isNullOrEmpty(preparedHost)) {

0 commit comments

Comments
 (0)