Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/iceberg/catalog/rest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# specific language governing permissions and limitations
# under the License.

add_subdirectory(auth)

set(ICEBERG_REST_SOURCES
catalog_properties.cc
endpoint.cc
Expand All @@ -24,7 +26,10 @@ set(ICEBERG_REST_SOURCES
resource_paths.cc
rest_catalog.cc
rest_util.cc
types.cc)
types.cc
auth/auth_manager.cc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort them alphabetically

auth/auth_managers.cc
auth/auth_session.cc)

set(ICEBERG_REST_STATIC_BUILD_INTERFACE_LIBS)
set(ICEBERG_REST_SHARED_BUILD_INTERFACE_LIBS)
Expand Down
18 changes: 18 additions & 0 deletions src/iceberg/catalog/rest/auth/CMakeLists.txt
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)
41 changes: 41 additions & 0 deletions src/iceberg/catalog/rest/auth/auth_manager.cc
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
95 changes: 95 additions & 0 deletions src/iceberg/catalog/rest/auth/auth_manager.h
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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#include "iceberg/table_identifier.h"

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
///
/// 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.

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(
Copy link
Member

Choose a reason for hiding this comment

The 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.
Copy link
Member

Choose a reason for hiding this comment

The 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 std::unique_ptr<AuthSession>&& parent to make the ownership explicit: either directly return parent or the created session owns its parent. I didn't any case to share the session, am I missing something?

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
85 changes: 85 additions & 0 deletions src/iceberg/catalog/rest/auth/auth_managers.cc
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(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a enum class for the auth type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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));
Copy link
Member

Choose a reason for hiding this comment

The 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);
Copy link
Member

Choose a reason for hiding this comment

The 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);
Copy link
Member

Choose a reason for hiding this comment

The 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
70 changes: 70 additions & 0 deletions src/iceberg/catalog/rest/auth/auth_managers.h
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// \brief Function that builds an AuthManager for a given catalog.
/// \brief Function that creates an AuthManager from its name.

///
/// \param name Catalog name passed to the manager.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// \param name Catalog name passed to the manager.
/// \param name Name of the auth manager.

/// \param properties Consolidated catalog configuration.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// \param properties Consolidated catalog configuration.
/// \param properties Properties required by the auth manager.

/// \return Newly created manager instance.
using AuthManagerFactory = std::function<std::unique_ptr<AuthManager>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the factory return Result<std::unique_ptr<AuthManager>> just in case of any error or implementation is unavailable?

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 =
Copy link
Member

Choose a reason for hiding this comment

The 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.
Copy link
Member

Choose a reason for hiding this comment

The 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
Loading
Loading