|
30 | 30 | import jakarta.inject.Inject; |
31 | 31 | import jakarta.ws.rs.client.Client; |
32 | 32 | import jakarta.ws.rs.client.ClientBuilder; |
| 33 | +import jakarta.ws.rs.client.Entity; |
33 | 34 | import jakarta.ws.rs.core.MediaType; |
| 35 | +import jakarta.ws.rs.core.MultivaluedHashMap; |
34 | 36 | import jakarta.ws.rs.core.Response; |
35 | 37 | import jakarta.ws.rs.core.Response.Status; |
36 | 38 | import java.util.Map; |
37 | 39 | import java.util.Set; |
38 | 40 | import java.util.function.Consumer; |
39 | 41 | import org.apache.iceberg.rest.responses.ErrorResponse; |
40 | 42 | import org.apache.iceberg.rest.responses.ErrorResponseParser; |
| 43 | +import org.apache.iceberg.rest.responses.OAuthTokenResponse; |
41 | 44 | import org.apache.polaris.service.events.EventAttributes; |
42 | 45 | import org.apache.polaris.service.events.PolarisEvent; |
43 | 46 | import org.apache.polaris.service.events.PolarisEventType; |
@@ -80,6 +83,11 @@ public Map<String, String> getConfigOverrides() { |
80 | 83 | .put("polaris.rate-limiter.token-bucket.type", "default") |
81 | 84 | .put("polaris.metrics.tags.environment", "prod") |
82 | 85 | .put("polaris.realm-context.realms", "POLARIS,POLARIS2") |
| 86 | + // Bootstrapping both realms with known credentials so each realm can mint its own |
| 87 | + // access token. Tokens are bound to per-realm secret hashes and cannot be shared. |
| 88 | + .put( |
| 89 | + "polaris.bootstrap.credentials", |
| 90 | + "POLARIS,test-admin,test-secret;POLARIS2,test-admin2,test-secret2") |
83 | 91 | .put("polaris.metrics.realm-id-tag.enable-in-api-metrics", "true") |
84 | 92 | .put("polaris.metrics.realm-id-tag.enable-in-http-metrics", "true") |
85 | 93 | .put("polaris.authentication.token-broker.type", "symmetric-key") |
@@ -138,10 +146,14 @@ public void testRateLimiter() { |
138 | 146 | requestAsserter.accept(Status.TOO_MANY_REQUESTS); |
139 | 147 | } |
140 | 148 |
|
141 | | - // Ensure that a different realm identifier gets a separate limit |
| 149 | + // Ensure that a different realm identifier gets a separate limit. Access tokens are |
| 150 | + // bound to per-realm principal secrets, so mint a token for POLARIS2 rather than reusing |
| 151 | + // the POLARIS admin token (which would correctly return 401 after credentials binding). |
142 | 152 | MockRateLimiter.allowProceed = true; |
| 153 | + String polaris2Token = |
| 154 | + obtainAccessTokenForRealm(polarisEndpoints, "POLARIS2", "test-admin2", "test-secret2"); |
143 | 155 | Consumer<Status> requestAsserter2 = |
144 | | - constructRequestAsserter(polarisEndpoints, adminToken, "POLARIS2"); |
| 156 | + constructRequestAsserter(polarisEndpoints, polaris2Token, "POLARIS2"); |
145 | 157 | requestAsserter2.accept(Status.OK); |
146 | 158 | } |
147 | 159 |
|
@@ -243,4 +255,27 @@ private static Consumer<Status> constructRequestAsserter( |
243 | 255 | } |
244 | 256 | }; |
245 | 257 | } |
| 258 | + |
| 259 | + /** |
| 260 | + * Mints an access token in the given realm using client credentials. Realm must be bootstrapped |
| 261 | + * with those credentials (see {@link Profile}). |
| 262 | + */ |
| 263 | + private static String obtainAccessTokenForRealm( |
| 264 | + PolarisApiEndpoints endpoints, String realm, String clientId, String clientSecret) { |
| 265 | + MultivaluedHashMap<String, String> form = new MultivaluedHashMap<>(); |
| 266 | + form.add("grant_type", "client_credentials"); |
| 267 | + form.add("client_id", clientId); |
| 268 | + form.add("client_secret", clientSecret); |
| 269 | + form.add("scope", "PRINCIPAL_ROLE:ALL"); |
| 270 | + try (Client httpClient = ClientBuilder.newBuilder().build(); |
| 271 | + Response response = |
| 272 | + httpClient |
| 273 | + .target(String.format("%s/v1/oauth/tokens", endpoints.catalogApiEndpoint())) |
| 274 | + .request(MediaType.APPLICATION_JSON_TYPE) |
| 275 | + .header("Polaris-Realm", realm) |
| 276 | + .post(Entity.form(form))) { |
| 277 | + assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode()); |
| 278 | + return response.readEntity(OAuthTokenResponse.class).token(); |
| 279 | + } |
| 280 | + } |
246 | 281 | } |
0 commit comments