diff --git a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java index 56e07202f873..a72d3958c140 100644 --- a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java +++ b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java @@ -184,19 +184,34 @@ public void initialize(String name, Map unresolved) { long startTimeMillis = System.currentTimeMillis(); // keep track of the init start time for token refresh String initToken = props.get(OAuth2Properties.TOKEN); + boolean hasInitToken = initToken != null; // fetch auth and config to complete initialization ConfigResponse config; OAuthTokenResponse authResponse; String credential = props.get(OAuth2Properties.CREDENTIAL); + boolean hasCredential = credential != null && !credential.isEmpty(); String scope = props.getOrDefault(OAuth2Properties.SCOPE, OAuth2Properties.CATALOG_SCOPE); Map optionalOAuthParams = OAuth2Util.buildOptionalParam(props); + if (!props.containsKey(OAuth2Properties.OAUTH2_SERVER_URI) + && (hasInitToken || hasCredential) + && !PropertyUtil.propertyAsBoolean(props, "rest.sigv4-enabled", false)) { + LOG.warn( + "Iceberg REST client is missing the OAuth2 server URI configuration and defaults to {}{}. " + + "This automatic fallback will be removed in a future Iceberg release." + + "It is recommended to configure the OAuth2 endpoint using the '{}' property to be prepared. " + + "This warning will disappear if the OAuth2 endpoint is explicitly configured. " + + "See https://github.com/apache/iceberg/issues/10537", + props.get(CatalogProperties.URI), + ResourcePaths.tokens(), + OAuth2Properties.OAUTH2_SERVER_URI); + } String oauth2ServerUri = props.getOrDefault(OAuth2Properties.OAUTH2_SERVER_URI, ResourcePaths.tokens()); try (RESTClient initClient = clientBuilder.apply(props)) { Map initHeaders = RESTUtil.merge(configHeaders(props), OAuth2Util.authHeaders(initToken)); - if (credential != null && !credential.isEmpty()) { + if (hasCredential) { authResponse = OAuth2Util.fetchToken( initClient, initHeaders, credential, scope, oauth2ServerUri, optionalOAuthParams); diff --git a/open-api/rest-catalog-open-api.py b/open-api/rest-catalog-open-api.py index c5af1940c324..67498055502d 100644 --- a/open-api/rest-catalog-open-api.py +++ b/open-api/rest-catalog-open-api.py @@ -462,6 +462,8 @@ class TokenType(BaseModel): class OAuthClientCredentialsRequest(BaseModel): """ + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this spec, see description of the endpoint. + OAuth2 client credentials request See https://datatracker.ietf.org/doc/html/rfc6749#section-4.4 @@ -481,6 +483,8 @@ class OAuthClientCredentialsRequest(BaseModel): class OAuthTokenExchangeRequest(BaseModel): """ + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this spec, see description of the endpoint. + OAuth2 token exchange request See https://datatracker.ietf.org/doc/html/rfc8693 @@ -500,7 +504,10 @@ class OAuthTokenExchangeRequest(BaseModel): class OAuthTokenRequest(BaseModel): - __root__: Union[OAuthClientCredentialsRequest, OAuthTokenExchangeRequest] + __root__: Union[OAuthClientCredentialsRequest, OAuthTokenExchangeRequest] = Field( + ..., + description='The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this spec, see description of the endpoint.', + ) class CounterResult(BaseModel): @@ -532,6 +539,10 @@ class CommitReport(BaseModel): class OAuthError(BaseModel): + """ + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this spec, see description of the endpoint. + """ + error: Literal[ 'invalid_request', 'invalid_client', @@ -545,6 +556,10 @@ class OAuthError(BaseModel): class OAuthTokenResponse(BaseModel): + """ + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this spec, see description of the endpoint. + """ + access_token: str = Field( ..., description='The access token, for client credentials or token exchange' ) diff --git a/open-api/rest-catalog-open-api.yaml b/open-api/rest-catalog-open-api.yaml index 4bb73cd44120..feb2fdbc63cd 100644 --- a/open-api/rest-catalog-open-api.yaml +++ b/open-api/rest-catalog-open-api.yaml @@ -134,9 +134,22 @@ paths: post: tags: - OAuth2 API - summary: Get a token using an OAuth2 flow + summary: Get a token using an OAuth2 flow (DEPRECATED for REMOVAL) + deprecated: true operationId: getToken description: + The `oauth/tokens` endpoint is **DEPRECATED for REMOVAL**. It is _not_ recommended to + implement this endpoint, unless you are fully aware of the potential security implications. + + All clients are encouraged to explicitly set the configuration property `oauth2-server-uri` + to the correct OAuth endpoint. + + Deprecated since Iceberg (Java) 1.6.0. The endpoint and related types will be removed from + this spec in Iceberg (Java) 2.0. + + See [Security improvements in the Iceberg REST specification](https://github.com/apache/iceberg/issues/10537) + + Exchange credentials for a token using the OAuth2 client credentials flow or token exchange. @@ -2922,7 +2935,12 @@ components: See https://datatracker.ietf.org/doc/html/rfc8693#section-3 OAuthClientCredentialsRequest: - description: + deprecated: true + description: + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this + spec, see description of the endpoint. + + OAuth2 client credentials request @@ -2957,7 +2975,12 @@ components: a Basic Authorization header. OAuthTokenExchangeRequest: + deprecated: true description: + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this + spec, see description of the endpoint. + + OAuth2 token exchange request @@ -2988,6 +3011,10 @@ components: $ref: '#/components/schemas/TokenType' OAuthTokenRequest: + deprecated: true + description: + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this + spec, see description of the endpoint. anyOf: - $ref: '#/components/schemas/OAuthClientCredentialsRequest' - $ref: '#/components/schemas/OAuthTokenExchangeRequest' @@ -3142,6 +3169,10 @@ components: type: string OAuthError: + deprecated: true + description: + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this + spec, see description of the endpoint. type: object required: - error @@ -3161,6 +3192,10 @@ components: type: string OAuthTokenResponse: + deprecated: true + description: + The `oauth/tokens` endpoint and related schemas are **DEPRECATED for REMOVAL** from this + spec, see description of the endpoint. type: object required: - access_token