Skip to content

Commit 572d02a

Browse files
author
shuxu.li
committed
feat: add restcatalog authentication api
1 parent 7e784dc commit 572d02a

File tree

10 files changed

+631
-0
lines changed

10 files changed

+631
-0
lines changed

src/iceberg/catalog/rest/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18+
# Include auth subdirectory
19+
add_subdirectory(auth)
20+
1821
set(ICEBERG_REST_SOURCES
1922
catalog_properties.cc
2023
endpoint.cc
@@ -26,6 +29,11 @@ set(ICEBERG_REST_SOURCES
2629
rest_util.cc
2730
types.cc)
2831

32+
# Add auth sources with proper path prefix
33+
foreach(AUTH_SOURCE ${ICEBERG_REST_AUTH_SOURCES})
34+
list(APPEND ICEBERG_REST_SOURCES "auth/${AUTH_SOURCE}")
35+
endforeach()
36+
2937
set(ICEBERG_REST_STATIC_BUILD_INTERFACE_LIBS)
3038
set(ICEBERG_REST_SHARED_BUILD_INTERFACE_LIBS)
3139
set(ICEBERG_REST_STATIC_INSTALL_INTERFACE_LIBS)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
set(ICEBERG_REST_AUTH_SOURCES auth_session.cc auth_manager.cc auth_managers.cc)
19+
20+
# Expose sources to parent scope for inclusion in iceberg_rest library
21+
set(ICEBERG_REST_AUTH_SOURCES
22+
${ICEBERG_REST_AUTH_SOURCES}
23+
PARENT_SCOPE)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/catalog/rest/auth/auth_manager.h"
21+
22+
namespace iceberg::rest::auth {
23+
24+
std::shared_ptr<AuthSession> AuthManager::InitSession(
25+
HttpClient* init_client,
26+
const std::unordered_map<std::string, std::string>& properties) {
27+
// By default, use the catalog session for initialization
28+
return CatalogSession(init_client, properties);
29+
}
30+
31+
std::shared_ptr<AuthSession> AuthManager::TableSession(
32+
[[maybe_unused]] const TableIdentifier& table,
33+
[[maybe_unused]] const std::unordered_map<std::string, std::string>& properties,
34+
std::shared_ptr<AuthSession> parent) {
35+
// By default, return the parent session
36+
return parent;
37+
}
38+
39+
} // namespace iceberg::rest::auth
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
#include <memory>
23+
#include <string>
24+
#include <unordered_map>
25+
26+
#include "iceberg/catalog/rest/auth/auth_session.h"
27+
#include "iceberg/catalog/rest/iceberg_rest_export.h"
28+
#include "iceberg/table_identifier.h"
29+
30+
/// \file iceberg/catalog/rest/auth/auth_manager.h
31+
/// \brief Authentication manager interface for REST catalog.
32+
33+
namespace iceberg::rest {
34+
class HttpClient;
35+
} // namespace iceberg::rest
36+
37+
namespace iceberg::rest::auth {
38+
39+
/// \brief Manager for authentication sessions.
40+
///
41+
/// This interface is used to create sessions for the catalog, tables/views,
42+
/// and any other context that requires authentication.
43+
///
44+
/// Managers are typically stateful and may require initialization and cleanup.
45+
/// The manager is created by the catalog and is closed when the catalog is closed.
46+
///
47+
/// This interface is modeled after Java Iceberg's AuthManager interface.
48+
class ICEBERG_REST_EXPORT AuthManager {
49+
public:
50+
virtual ~AuthManager() = default;
51+
52+
/// \brief Return a temporary session for contacting the configuration endpoint.
53+
///
54+
/// This session is used only during catalog initialization to fetch server
55+
/// configuration. The returned session will be closed after the configuration
56+
/// endpoint is contacted and should not be cached.
57+
///
58+
/// The provided HTTP client is a short-lived client; it should only be used
59+
/// to fetch initial credentials if required, and must be discarded after that.
60+
///
61+
/// This method cannot return null. By default, it returns the catalog session.
62+
///
63+
/// \param init_client A short-lived HTTP client for initialization.
64+
/// \param properties Configuration properties.
65+
/// \return A session for initialization, or the catalog session by default.
66+
virtual std::shared_ptr<AuthSession> InitSession(
67+
HttpClient* init_client,
68+
const std::unordered_map<std::string, std::string>& properties);
69+
70+
/// \brief Return a long-lived session for catalog operations.
71+
///
72+
/// This session's lifetime is tied to the owning catalog. It serves as the
73+
/// parent session for all other sessions (contextual and table-specific).
74+
/// It is closed when the owning catalog is closed.
75+
///
76+
/// The provided HTTP client is a long-lived, shared client. Implementors may
77+
/// store it and reuse it for subsequent requests to the authorization server
78+
/// (e.g., for renewing or refreshing credentials). It is not necessary to
79+
/// close it when Close() is called.
80+
///
81+
/// This method cannot return null.
82+
///
83+
/// It is not required to cache the returned session internally, as the catalog
84+
/// will keep it alive for the lifetime of the catalog.
85+
///
86+
/// \param shared_client A long-lived, shared HTTP client.
87+
/// \param properties Configuration properties (merged with server config).
88+
/// \return A session for catalog operations.
89+
virtual std::shared_ptr<AuthSession> CatalogSession(
90+
HttpClient* shared_client,
91+
const std::unordered_map<std::string, std::string>& properties) = 0;
92+
93+
/// \brief Return a session for a specific table or view.
94+
///
95+
/// If the table or view requires a specific AuthSession (e.g., vended credentials),
96+
/// this method should return a new AuthSession instance. Otherwise, it should
97+
/// return the parent session.
98+
///
99+
/// This method cannot return null. By default, it returns the parent session.
100+
///
101+
/// Implementors should cache table sessions internally, as the catalog will not
102+
/// cache them. Also, the owning catalog never closes table sessions; implementations
103+
/// should manage their lifecycle and close them when they are no longer needed.
104+
///
105+
/// \param table The table identifier.
106+
/// \param properties Properties returned by the table/view endpoint.
107+
/// \param parent The parent session (typically the catalog session).
108+
/// \return A session for the table, or the parent session by default.
109+
virtual std::shared_ptr<AuthSession> TableSession(
110+
const TableIdentifier& table,
111+
const std::unordered_map<std::string, std::string>& properties,
112+
std::shared_ptr<AuthSession> parent);
113+
114+
/// \brief Close the manager and release any resources.
115+
///
116+
/// This method is called when the owning catalog is closed. Implementations
117+
/// should release any resources held by the manager, such as cached sessions
118+
/// or background threads.
119+
virtual void Close() {}
120+
};
121+
122+
} // namespace iceberg::rest::auth
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/catalog/rest/auth/auth_managers.h"
21+
22+
#include <algorithm>
23+
24+
#include "iceberg/catalog/rest/auth/auth_properties.h"
25+
26+
namespace iceberg::rest::auth {
27+
28+
namespace {
29+
30+
/// \brief Convert a string to lowercase for case-insensitive comparison.
31+
std::string ToLower(std::string_view str) {
32+
std::string result(str);
33+
std::transform(result.begin(), result.end(), result.begin(),
34+
[](unsigned char c) { return std::tolower(c); });
35+
return result;
36+
}
37+
38+
/// \brief Infer the authentication type from properties.
39+
///
40+
/// If no explicit auth type is set, this function tries to infer it from
41+
/// other properties. For example, if "credential" or "token" is present,
42+
/// it implies OAuth2 authentication.
43+
std::string InferAuthType(
44+
const std::unordered_map<std::string, std::string>& properties) {
45+
// Check for explicit auth type
46+
auto it = properties.find(std::string(AuthProperties::kAuthType));
47+
if (it != properties.end() && !it->second.empty()) {
48+
return ToLower(it->second);
49+
}
50+
51+
// Infer from OAuth2 properties
52+
bool has_credential =
53+
properties.contains(std::string(AuthProperties::kOAuth2Credential));
54+
bool has_token = properties.contains(std::string(AuthProperties::kOAuth2Token));
55+
56+
if (has_credential || has_token) {
57+
return std::string(AuthProperties::kAuthTypeOAuth2);
58+
}
59+
60+
// Default to no authentication
61+
return std::string(AuthProperties::kAuthTypeNone);
62+
}
63+
64+
} // namespace
65+
66+
std::unordered_map<std::string, AuthManagerFactory>& AuthManagers::GetRegistry() {
67+
static std::unordered_map<std::string, AuthManagerFactory> registry;
68+
return registry;
69+
}
70+
71+
void AuthManagers::Register(const std::string& auth_type, AuthManagerFactory factory) {
72+
GetRegistry()[ToLower(auth_type)] = std::move(factory);
73+
}
74+
75+
Result<std::unique_ptr<AuthManager>> AuthManagers::Load(
76+
const std::string& name,
77+
const std::unordered_map<std::string, std::string>& properties) {
78+
std::string auth_type = InferAuthType(properties);
79+
80+
auto& registry = GetRegistry();
81+
auto it = registry.find(auth_type);
82+
if (it == registry.end()) {
83+
return NotImplemented("Authentication type '{}' is not supported", auth_type);
84+
}
85+
86+
return it->second(name, properties);
87+
}
88+
89+
} // namespace iceberg::rest::auth
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
#include <functional>
23+
#include <memory>
24+
#include <string>
25+
#include <unordered_map>
26+
27+
#include "iceberg/catalog/rest/auth/auth_manager.h"
28+
#include "iceberg/catalog/rest/iceberg_rest_export.h"
29+
#include "iceberg/result.h"
30+
31+
/// \file iceberg/catalog/rest/auth/auth_managers.h
32+
/// \brief Factory for creating authentication managers.
33+
34+
namespace iceberg::rest::auth {
35+
36+
/// \brief Factory function type for creating AuthManager instances.
37+
///
38+
/// \param name The name of the manager (used for logging).
39+
/// \param properties Configuration properties.
40+
/// \return A unique pointer to the created AuthManager.
41+
using AuthManagerFactory = std::function<std::unique_ptr<AuthManager>(
42+
const std::string& name,
43+
const std::unordered_map<std::string, std::string>& properties)>;
44+
45+
/// \brief Factory class for loading authentication managers.
46+
///
47+
/// This class provides a registry-based approach to create AuthManager instances
48+
/// based on the configured authentication type. It supports built-in types
49+
/// (none, basic, oauth2) and allows registration of custom types.
50+
///
51+
/// This class is modeled after Java Iceberg's AuthManagers class.
52+
class ICEBERG_REST_EXPORT AuthManagers {
53+
public:
54+
/// \brief Load an authentication manager based on configuration.
55+
///
56+
/// This method reads the "rest.auth.type" property to determine which
57+
/// AuthManager implementation to create. Supported types include:
58+
/// - "none": NoopAuthManager (no authentication)
59+
/// - "basic": BasicAuthManager (HTTP Basic authentication)
60+
/// - "oauth2": OAuth2AuthManager (OAuth2 authentication)
61+
/// - "sigv4": SigV4AuthManager (AWS Signature V4)
62+
///
63+
/// If no auth type is specified, the method will infer the type based on
64+
/// other properties (e.g., presence of "credential" or "token" implies oauth2).
65+
/// If no auth-related properties are found, it defaults to "none".
66+
///
67+
/// \param name A name for the manager (used for logging).
68+
/// \param properties Configuration properties.
69+
/// \return A unique pointer to the created AuthManager, or an error.
70+
static Result<std::unique_ptr<AuthManager>> Load(
71+
const std::string& name,
72+
const std::unordered_map<std::string, std::string>& properties);
73+
74+
/// \brief Register a custom authentication manager factory.
75+
///
76+
/// This allows users to extend the supported authentication types by
77+
/// registering their own AuthManager implementations.
78+
///
79+
/// \param auth_type The authentication type name (e.g., "custom").
80+
/// \param factory The factory function to create the AuthManager.
81+
static void Register(const std::string& auth_type, AuthManagerFactory factory);
82+
83+
private:
84+
/// \brief Get the global registry of auth manager factories.
85+
static std::unordered_map<std::string, AuthManagerFactory>& GetRegistry();
86+
};
87+
88+
} // namespace iceberg::rest::auth

0 commit comments

Comments
 (0)