-
Notifications
You must be signed in to change notification settings - Fork 80
feat: add restcatalog authentication api #479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
572d02a
904fdf0
83084ad
72df76d
54b4868
28e195a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| iceberg_install_all_headers(iceberg/catalog/rest/auth) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| #include "iceberg/catalog/rest/auth/auth_manager.h" | ||
|
|
||
| #include "iceberg/catalog/rest/auth/auth_session.h" | ||
|
|
||
| namespace iceberg::rest::auth { | ||
|
|
||
| Result<std::unique_ptr<AuthSession>> AuthManager::InitSession( | ||
| HttpClient& init_client, | ||
| const std::unordered_map<std::string, std::string>& properties) { | ||
| // By default, use the catalog session for initialization | ||
| return CatalogSession(init_client, properties); | ||
| } | ||
|
|
||
| Result<std::unique_ptr<AuthSession>> AuthManager::TableSession( | ||
| [[maybe_unused]] const TableIdentifier& table, | ||
| [[maybe_unused]] const std::unordered_map<std::string, std::string>& properties, | ||
| [[maybe_unused]] const AuthSession& parent) { | ||
| // By default, return nullptr to indicate the parent session should be reused. | ||
| return nullptr; | ||
| } | ||
|
|
||
| } // namespace iceberg::rest::auth |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,95 @@ | ||||||||||||||||
| /* | ||||||||||||||||
| * Licensed to the Apache Software Foundation (ASF) under one | ||||||||||||||||
| * or more contributor license agreements. See the NOTICE file | ||||||||||||||||
| * distributed with this work for additional information | ||||||||||||||||
| * regarding copyright ownership. The ASF licenses this file | ||||||||||||||||
| * to you under the Apache License, Version 2.0 (the | ||||||||||||||||
| * "License"); you may not use this file except in compliance | ||||||||||||||||
| * with the License. You may obtain a copy of the License at | ||||||||||||||||
| * | ||||||||||||||||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||
| * | ||||||||||||||||
| * Unless required by applicable law or agreed to in writing, | ||||||||||||||||
| * software distributed under the License is distributed on an | ||||||||||||||||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||||||||||||
| * KIND, either express or implied. See the License for the | ||||||||||||||||
| * specific language governing permissions and limitations | ||||||||||||||||
| * under the License. | ||||||||||||||||
| */ | ||||||||||||||||
|
|
||||||||||||||||
| #pragma once | ||||||||||||||||
|
|
||||||||||||||||
| #include <memory> | ||||||||||||||||
| #include <string> | ||||||||||||||||
| #include <unordered_map> | ||||||||||||||||
|
|
||||||||||||||||
| #include "iceberg/catalog/rest/iceberg_rest_export.h" | ||||||||||||||||
| #include "iceberg/catalog/rest/type_fwd.h" | ||||||||||||||||
| #include "iceberg/result.h" | ||||||||||||||||
| #include "iceberg/table_identifier.h" | ||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
We can remove this |
||||||||||||||||
|
|
||||||||||||||||
| /// \file iceberg/catalog/rest/auth/auth_manager.h | ||||||||||||||||
| /// \brief Authentication manager interface for REST catalog. | ||||||||||||||||
|
|
||||||||||||||||
| namespace iceberg::rest::auth { | ||||||||||||||||
|
|
||||||||||||||||
| /// \brief Produces authentication sessions for catalog and table requests. | ||||||||||||||||
| /// | ||||||||||||||||
| /// AuthManager is responsible for creating authentication sessions at different scopes: | ||||||||||||||||
| /// - InitSession: Short-lived session for catalog initialization (optional) | ||||||||||||||||
| /// - CatalogSession: Long-lived session for catalog-level operations (required) | ||||||||||||||||
| /// - TableSession: Optional table-specific session or reuse of catalog session | ||||||||||||||||
| /// | ||||||||||||||||
| /// Implementations are registered via AuthManagers::Register() and loaded by auth type. | ||||||||||||||||
|
Comment on lines
+37
to
+43
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
We don't need such verbose comments. |
||||||||||||||||
| class ICEBERG_REST_EXPORT AuthManager { | ||||||||||||||||
| public: | ||||||||||||||||
| virtual ~AuthManager() = default; | ||||||||||||||||
|
|
||||||||||||||||
| /// \brief Create a short-lived session used to contact the configuration endpoint. | ||||||||||||||||
| /// | ||||||||||||||||
| /// This session is used only during catalog initialization to fetch server | ||||||||||||||||
| /// configuration and perform initial authentication. It is typically discarded after | ||||||||||||||||
| /// initialization. | ||||||||||||||||
| /// | ||||||||||||||||
| /// \param init_client HTTP client used for initialization requests. | ||||||||||||||||
| /// \param properties Client configuration supplied by the catalog. | ||||||||||||||||
| /// \return Session for initialization or an error if credentials cannot be acquired. | ||||||||||||||||
| virtual Result<std::unique_ptr<AuthSession>> InitSession( | ||||||||||||||||
| HttpClient& init_client, | ||||||||||||||||
| const std::unordered_map<std::string, std::string>& properties); | ||||||||||||||||
|
|
||||||||||||||||
| /// \brief Create the long-lived catalog session that acts as the parent session. | ||||||||||||||||
| /// | ||||||||||||||||
| /// This session is used for all catalog-level operations (list namespaces, list tables, | ||||||||||||||||
| /// etc.) and serves as the parent session for table-specific operations. It is owned | ||||||||||||||||
| /// by the catalog and reused throughout the catalog's lifetime. | ||||||||||||||||
| /// | ||||||||||||||||
| /// \param shared_client HTTP client owned by the catalog and reused for auth calls. | ||||||||||||||||
| /// \param properties Catalog properties (client config + server defaults). | ||||||||||||||||
| /// \return Session for catalog operations or an error if authentication cannot be set | ||||||||||||||||
| /// up. | ||||||||||||||||
| virtual Result<std::unique_ptr<AuthSession>> CatalogSession( | ||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we don't have contextual session as the Java impl? I think this is used by each rest endpoint before sending the http request. |
||||||||||||||||
| HttpClient& shared_client, | ||||||||||||||||
| const std::unordered_map<std::string, std::string>& properties) = 0; | ||||||||||||||||
|
|
||||||||||||||||
| /// \brief Create or reuse a session scoped to a single table/view. | ||||||||||||||||
| /// | ||||||||||||||||
| /// This method can return a new table-specific session or indicate that the parent | ||||||||||||||||
| /// catalog session should be reused by returning nullptr. | ||||||||||||||||
| /// | ||||||||||||||||
| /// \param table Target table identifier. | ||||||||||||||||
| /// \param properties Table-specific auth properties returned by the server. | ||||||||||||||||
| /// \param parent Catalog session to inherit from or extract information from. | ||||||||||||||||
| /// \return A new session for the table, nullptr to reuse parent session, or an error. | ||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks weird to return nullptr to reuse parent session. I'm not sure if it is a good idea to use |
||||||||||||||||
| virtual Result<std::unique_ptr<AuthSession>> TableSession( | ||||||||||||||||
| const TableIdentifier& table, | ||||||||||||||||
| const std::unordered_map<std::string, std::string>& properties, | ||||||||||||||||
| const AuthSession& parent); | ||||||||||||||||
|
|
||||||||||||||||
| /// \brief Release resources held by the manager. | ||||||||||||||||
| /// | ||||||||||||||||
| /// \return Status of the close operation. | ||||||||||||||||
| virtual Status Close() { return {}; } | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| } // namespace iceberg::rest::auth | ||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| #include "iceberg/catalog/rest/auth/auth_managers.h" | ||
|
|
||
| #include <algorithm> | ||
| #include <cctype> | ||
|
|
||
| #include "iceberg/catalog/rest/auth/auth_properties.h" | ||
| #include "iceberg/util/string_util.h" | ||
|
|
||
| namespace iceberg::rest::auth { | ||
|
|
||
| namespace { | ||
|
|
||
| /// \brief Infer the authentication type from properties. | ||
| /// | ||
| /// If no explicit auth type is set, this function tries to infer it from | ||
| /// other properties. If "credential" or "token" is present, it implies | ||
| /// OAuth2 authentication. Otherwise, defaults to no authentication. | ||
| /// | ||
| /// This behavior is consistent with Java Iceberg's AuthManagers. | ||
| std::string InferAuthType( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add a enum class for the auth type?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Auth types come from external config files/properties as strings, so the string-based approach allows users to register custom auth types without modifying core code. It also matches the Iceberg REST spec. |
||
| const std::unordered_map<std::string, std::string>& properties) { | ||
| // Check for explicit auth type first | ||
| auto it = properties.find(std::string(AuthProperties::kAuthType)); | ||
| if (it != properties.end() && !it->second.empty()) { | ||
| return StringUtils::ToLower(it->second); | ||
| } | ||
|
|
||
| // Infer from OAuth2 properties (credential or token) | ||
| bool has_credential = | ||
| properties.contains(std::string(AuthProperties::kOAuth2Credential)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to define them as const std::string? It creates a string every time it is used. |
||
| bool has_token = properties.contains(std::string(AuthProperties::kOAuth2Token)); | ||
| if (has_credential || has_token) { | ||
| return std::string(AuthProperties::kAuthTypeOAuth2); | ||
| } | ||
|
|
||
| // Default to no authentication | ||
| return std::string(AuthProperties::kAuthTypeNone); | ||
| } | ||
|
|
||
| /// \brief Get the global registry of auth manager factories. | ||
| AuthManagerRegistry& GetRegistry() { | ||
| static AuthManagerRegistry registry; | ||
| return registry; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| void AuthManagers::Register(std::string_view auth_type, AuthManagerFactory factory) { | ||
| GetRegistry()[StringUtils::ToLower(std::string(auth_type))] = std::move(factory); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that we have unnecessary string allocations here. |
||
| } | ||
|
|
||
| Result<std::unique_ptr<AuthManager>> AuthManagers::Load( | ||
| std::string_view name, | ||
| const std::unordered_map<std::string, std::string>& properties) { | ||
| std::string auth_type = InferAuthType(properties); | ||
|
|
||
| auto& registry = GetRegistry(); | ||
| auto it = registry.find(auth_type); | ||
| if (it == registry.end()) { | ||
| return NotImplemented("Authentication type '{}' is not supported", auth_type); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a TODO to say we need to fallback to our default auth manager implementations. |
||
| } | ||
|
|
||
| return it->second(name, properties); | ||
| } | ||
|
|
||
| } // namespace iceberg::rest::auth | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,70 @@ | ||||||
| /* | ||||||
| * Licensed to the Apache Software Foundation (ASF) under one | ||||||
| * or more contributor license agreements. See the NOTICE file | ||||||
| * distributed with this work for additional information | ||||||
| * regarding copyright ownership. The ASF licenses this file | ||||||
| * to you under the Apache License, Version 2.0 (the | ||||||
| * "License"); you may not use this file except in compliance | ||||||
| * with the License. You may obtain a copy of the License at | ||||||
| * | ||||||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||||||
| * | ||||||
| * Unless required by applicable law or agreed to in writing, | ||||||
| * software distributed under the License is distributed on an | ||||||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
| * KIND, either express or implied. See the License for the | ||||||
| * specific language governing permissions and limitations | ||||||
| * under the License. | ||||||
| */ | ||||||
|
|
||||||
| #pragma once | ||||||
|
|
||||||
| #include <functional> | ||||||
| #include <memory> | ||||||
| #include <string> | ||||||
| #include <string_view> | ||||||
| #include <unordered_map> | ||||||
|
|
||||||
| #include "iceberg/catalog/rest/auth/auth_manager.h" | ||||||
| #include "iceberg/catalog/rest/iceberg_rest_export.h" | ||||||
| #include "iceberg/result.h" | ||||||
| #include "iceberg/util/string_util.h" | ||||||
|
|
||||||
| /// \file iceberg/catalog/rest/auth/auth_managers.h | ||||||
| /// \brief Factory for creating authentication managers. | ||||||
|
|
||||||
| namespace iceberg::rest::auth { | ||||||
|
|
||||||
| /// \brief Function that builds an AuthManager for a given catalog. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| /// | ||||||
| /// \param name Catalog name passed to the manager. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| /// \param properties Consolidated catalog configuration. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| /// \return Newly created manager instance. | ||||||
| using AuthManagerFactory = std::function<std::unique_ptr<AuthManager>( | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the factory return |
||||||
| std::string_view name, | ||||||
| const std::unordered_map<std::string, std::string>& properties)>; | ||||||
|
|
||||||
| /// \brief Registry type for AuthManager factories with heterogeneous lookup support. | ||||||
| using AuthManagerRegistry = | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can move this line to the cc file because users do not need to know this. |
||||||
| std::unordered_map<std::string, AuthManagerFactory, StringHash, StringEqual>; | ||||||
|
|
||||||
| /// \brief Registry-backed factory for AuthManager implementations. | ||||||
| class ICEBERG_REST_EXPORT AuthManagers { | ||||||
| public: | ||||||
| /// \brief Load a manager by consulting the "rest.auth.type" configuration. | ||||||
| /// | ||||||
| /// \param name Catalog name passed to the manager. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this correct? Why it is catalog name? |
||||||
| /// \param properties Catalog properties used to determine auth type. | ||||||
| /// \return Manager instance or an error if no factory matches. | ||||||
| static Result<std::unique_ptr<AuthManager>> Load( | ||||||
| std::string_view name, | ||||||
| const std::unordered_map<std::string, std::string>& properties); | ||||||
|
|
||||||
| /// \brief Register or override the factory for a given auth type. | ||||||
| /// | ||||||
| /// \param auth_type Case-insensitive type identifier (e.g., "basic"). | ||||||
| /// \param factory Factory function that produces the manager. | ||||||
| static void Register(std::string_view auth_type, AuthManagerFactory factory); | ||||||
| }; | ||||||
|
|
||||||
| } // namespace iceberg::rest::auth | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort them alphabetically