Skip to content

Commit 4498206

Browse files
authored
feat(config): validate subject token is set (#217)
Add a cross-config validation in `OAuth2Config` that requires at least one subject token source (inline token, token file, or dynamic config) when the grant type is `TOKEN_EXCHANGE`. This catches misconfiguration early with a clear error message.
1 parent 8e580ab commit 4498206

2 files changed

Lines changed: 35 additions & 2 deletions

File tree

oauth2/core/src/main/java/com/dremio/iceberg/authmgr/oauth2/OAuth2Config.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ default void validate() {
157157
"either issuer URL or device authorization endpoint must be set if grant type is '%s'",
158158
GrantType.DEVICE_CODE.getValue());
159159
}
160+
if (grantType.equals(GrantType.TOKEN_EXCHANGE)) {
161+
validator.check(
162+
getTokenExchangeConfig().getSubjectToken().isPresent()
163+
|| getTokenExchangeConfig().getSubjectTokenFile().isPresent()
164+
|| !getTokenExchangeConfig().getSubjectTokenConfig().isEmpty(),
165+
TokenExchangeConfig.PREFIX + '.' + TokenExchangeConfig.SUBJECT_TOKEN,
166+
"subject token must be set if grant type is '%s'",
167+
GrantType.TOKEN_EXCHANGE.getValue());
168+
}
160169
ClientAuthenticationMethod method = getBasicConfig().getClientAuthenticationMethod();
161170
if (ConfigUtils.requiresJwsAlgorithm(method)) {
162171
if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) {

oauth2/core/src/test/java/com/dremio/iceberg/authmgr/oauth2/tokenexchange/SubjectTokenSupplierTest.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
import com.nimbusds.oauth2.sdk.token.AccessToken;
3030
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
3131
import com.nimbusds.oauth2.sdk.token.TokenTypeURI;
32+
import io.smallrye.config.SmallRyeConfig;
33+
import io.smallrye.config.SmallRyeConfigBuilder;
34+
import io.smallrye.config.common.MapBackedConfigSource;
3235
import java.nio.file.Files;
3336
import java.nio.file.Path;
3437
import java.util.Map;
@@ -78,7 +81,7 @@ void testSupplyTokenAsyncDynamic() {
7881
@Test
7982
@SuppressWarnings("resource")
8083
void testValidate() {
81-
OAuth2Config config = createMainConfig(null, null, TokenTypeURI.ACCESS_TOKEN, Map.of());
84+
OAuth2Config config = createInvalidMainConfig();
8285
assertThatIllegalArgumentException()
8386
.isThrownBy(() -> createSupplier(config))
8487
.withMessage("Subject token is dynamic but no configuration is provided");
@@ -102,7 +105,28 @@ private static OAuth2Config createMainConfig(
102105
Path subjectTokenFile,
103106
TokenTypeURI subjectTokenType,
104107
Map<String, String> subjectTokenConfig) {
108+
return OAuth2Config.from(
109+
createProperties(subjectToken, subjectTokenFile, subjectTokenType, subjectTokenConfig));
110+
}
111+
112+
private static OAuth2Config createInvalidMainConfig() {
113+
SmallRyeConfig smallRyeConfig =
114+
new SmallRyeConfigBuilder()
115+
.withSources(
116+
new MapBackedConfigSource(
117+
"catalog properties",
118+
createProperties(null, null, TokenTypeURI.ACCESS_TOKEN, Map.of()),
119+
200) {})
120+
.withMapping(OAuth2Config.class)
121+
.build();
122+
return smallRyeConfig.getConfigMapping(OAuth2Config.class);
123+
}
105124

125+
private static Map<String, String> createProperties(
126+
String subjectToken,
127+
Path subjectTokenFile,
128+
TokenTypeURI subjectTokenType,
129+
Map<String, String> subjectTokenConfig) {
106130
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
107131

108132
builder.put(PREFIX + '.' + BasicConfig.GRANT_TYPE, GrantType.TOKEN_EXCHANGE.getValue());
@@ -129,7 +153,7 @@ private static OAuth2Config createMainConfig(
129153
subjectTokenFile.toString());
130154
}
131155

132-
return OAuth2Config.from(builder.build());
156+
return builder.build();
133157
}
134158

135159
private static SubjectTokenSupplier createSupplier(OAuth2Config config) {

0 commit comments

Comments
 (0)