Skip to content

Conversation

@lishuxu
Copy link
Contributor

@lishuxu lishuxu commented Jan 2, 2026

feat: add restcatalog authentication api

Comment on lines 31 to 37
/// \brief Convert a string to lowercase for case-insensitive comparison.
std::string ToLower(std::string_view str) {
std::string result(str);
std::ranges::transform(result, result.begin(),
[](unsigned char c) { return std::tolower(c); });
return result;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a StringUtils::ToLower func in util/string_util.h

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, fixed.

/// (i.e., request headers take precedence).
///
/// \param headers The headers map to add authentication information to.
void Authenticate(std::unordered_map<std::string, std::string>& headers) override;
Copy link
Member

Choose a reason for hiding this comment

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

Do you think it is worth adding a class HttpRequest? We don't have it yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think we need an HttpRequest class at this stage. The current design is sufficient for most auth schemes (Basic, Bearer, OAuth2, API keys), but we can add can add it later if needed.

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


private:
/// \brief Get the global registry of auth manager factories.
static std::unordered_map<std::string, AuthManagerFactory>& GetRegistry();
Copy link
Member

Choose a reason for hiding this comment

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

We don't need this function in the header file, right?

Comment on lines +55 to +57
for (const auto& [key, value] : headers_) {
headers.try_emplace(key, value);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
for (const auto& [key, value] : headers_) {
headers.try_emplace(key, value);
}
headers.merge(headers_);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

merge() is destructive - it moves nodes from headers_ to headers, leaving headers_ empty or partially empty.
so, I think the current implementation can be retained.

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

#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

Comment on lines +37 to +43
///
/// 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.
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 AuthManager;
class AuthSession;
class DefaultAuthSession;
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to forward declare DefaultAuthSession? Isn't it used only by the implementation?

Comment on lines +50 to +52
/// \return Status indicating success or failure of authentication.
/// - Success: Returns Status::OK
/// - Failure: Returns one of the following errors:
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
/// \return Status indicating success or failure of authentication.
/// - Success: Returns Status::OK
/// - Failure: Returns one of the following errors:
/// \return Status indicating success or one of the following errors:


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

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.

} // 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.

/// \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?

/// \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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants