Skip to content
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

Upgrade apis to v2 & allow to select apis via feature flag for optimized compile times #565

Merged
merged 4 commits into from
Aug 26, 2024
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
Cargo.lock
temp*
src/api/generated
.idea
102 changes: 92 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,38 @@ default = []
## Feature that enables support for the [actix framework](https://actix.rs/).
actix = ["credentials", "oidc", "dep:actix-web"]

## The API feature enables the gRPC service clients to access the ZITADEL API.
api = ["dep:prost", "dep:prost-types", "dep:tonic", "dep:tonic-types", "dep:pbjson-types"]
## The API feature enables all gRPC service clients to access the ZITADEL API.
api = [
"api-admin-v1",
"api-auth-v1",
"api-management-v1",
"api-system-v1",
"api-oidc-v2",
"api-org-v2",
"api-session-v2",
"api-settings-v2",
"api-user-v2"
]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-admin-v1 = ["api-common", "zitadel-admin-v1" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-auth-v1 = ["api-common", "zitadel-auth-v1" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-management-v1 = ["api-common", "zitadel-v1-v1" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-system-v1 = ["api-common", "zitadel-system-v1", "zitadel-authn-v1" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-oidc-v2 = ["api-common", "zitadel-oidc-v2" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-org-v2 = ["api-common", "zitadel-org-v2", "zitadel-user-v2" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-session-v2 = ["api-common", "zitadel-session-v2" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-settings-v2 = ["api-common", "zitadel-settings-v2" ]
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
api-user-v2 = ["api-common", "zitadel-user-v2" ]
api-common = ["dep:prost", "dep:prost-types", "dep:tonic", "dep:tonic-types", "dep:pbjson-types" ]


## Feature that enables support for the [axum framework](https://docs.rs/axum/latest/axum/).
axum = ["credentials", "oidc", "dep:axum", "dep:axum-extra"]
Expand All @@ -36,7 +66,7 @@ credentials = ["dep:jsonwebtoken", "dep:openidconnect", "dep:reqwest", "dep:serd
## new convenience functions to create a gRPC client with interceptors.
## The interceptors provide easy access to an authenticated ZITADEL API client.
## The interceptors work with the credentials from this crate.
interceptors = ["api", "credentials", "dep:time", "dep:tokio"]
interceptors = ["credentials", "dep:time", "dep:tokio"]

## This feature enables caching of the OIDC discovery and introspection results.
## By default, only the in-memory cache is available. To use a different cache,
Expand All @@ -54,6 +84,59 @@ oidc = ["credentials", "dep:base64-compat"]
## Refer to the rocket module for more information.
rocket = ["credentials", "oidc", "dep:rocket"]

# @@protoc_deletion_point(features)
# This section is automatically generated by protoc-gen-prost-crate.
# Changes in this area may be lost on regeneration.
proto_full = ["zitadel-action-v1","zitadel-admin-v1","zitadel-app-v1","zitadel-auth-v1","zitadel-authn-v1","zitadel-change-v1","zitadel-event-v1","zitadel-feature-v1","zitadel-feature-v2","zitadel-feature-v2beta","zitadel-idp-v1","zitadel-idp-v2","zitadel-instance-v1","zitadel-management-v1","zitadel-member-v1","zitadel-metadata-v1","zitadel-milestone-v1","zitadel-object-v2","zitadel-object-v2beta","zitadel-object-v3alpha","zitadel-oidc-v2","zitadel-oidc-v2beta","zitadel-org-v1","zitadel-org-v2","zitadel-org-v2beta","zitadel-policy-v1","zitadel-project-v1","zitadel-protoc_gen_zitadel-v2","zitadel-quota-v1","zitadel-resources-action-v3alpha","zitadel-resources-object-v3alpha","zitadel-resources-webkey-v3alpha","zitadel-session-v2","zitadel-session-v2beta","zitadel-settings-object-v3alpha","zitadel-settings-v1","zitadel-settings-v2","zitadel-settings-v2beta","zitadel-system-v1","zitadel-text-v1","zitadel-user-schema-v3alpha","zitadel-user-v1","zitadel-user-v2","zitadel-user-v2beta","zitadel-user-v3alpha","zitadel-v1","zitadel-v1-v1"]
"zitadel-action-v1" = ["zitadel-v1"]
"zitadel-admin-v1" = ["zitadel-event-v1","zitadel-idp-v1","zitadel-instance-v1","zitadel-management-v1","zitadel-member-v1","zitadel-milestone-v1","zitadel-org-v1","zitadel-policy-v1","zitadel-settings-v1","zitadel-text-v1","zitadel-v1","zitadel-v1-v1"]
"zitadel-app-v1" = ["zitadel-v1"]
"zitadel-auth-v1" = ["zitadel-change-v1","zitadel-idp-v1","zitadel-metadata-v1","zitadel-org-v1","zitadel-policy-v1","zitadel-user-v1","zitadel-v1"]
"zitadel-authn-v1" = ["zitadel-v1"]
"zitadel-change-v1" = ["zitadel-v1"]
"zitadel-event-v1" = ["zitadel-v1"]
"zitadel-feature-v1" = []
"zitadel-feature-v2" = ["zitadel-object-v2"]
"zitadel-feature-v2beta" = ["zitadel-object-v2beta"]
"zitadel-idp-v1" = ["zitadel-v1"]
"zitadel-idp-v2" = ["zitadel-object-v2"]
"zitadel-instance-v1" = ["zitadel-v1"]
"zitadel-management-v1" = ["zitadel-action-v1","zitadel-app-v1","zitadel-authn-v1","zitadel-change-v1","zitadel-idp-v1","zitadel-member-v1","zitadel-metadata-v1","zitadel-org-v1","zitadel-policy-v1","zitadel-project-v1","zitadel-text-v1","zitadel-user-v1","zitadel-v1"]
"zitadel-member-v1" = ["zitadel-user-v1","zitadel-v1"]
"zitadel-metadata-v1" = ["zitadel-v1"]
"zitadel-milestone-v1" = []
"zitadel-object-v2" = []
"zitadel-object-v2beta" = []
"zitadel-object-v3alpha" = []
"zitadel-oidc-v2" = ["zitadel-object-v2"]
"zitadel-oidc-v2beta" = ["zitadel-object-v2beta"]
"zitadel-org-v1" = ["zitadel-v1"]
"zitadel-org-v2" = ["zitadel-object-v2"]
"zitadel-org-v2beta" = ["zitadel-object-v2beta"]
"zitadel-policy-v1" = ["zitadel-idp-v1","zitadel-v1"]
"zitadel-project-v1" = ["zitadel-v1"]
"zitadel-protoc_gen_zitadel-v2" = []
"zitadel-quota-v1" = []
"zitadel-resources-action-v3alpha" = ["zitadel-object-v3alpha","zitadel-resources-object-v3alpha"]
"zitadel-resources-object-v3alpha" = ["zitadel-object-v3alpha"]
"zitadel-resources-webkey-v3alpha" = ["zitadel-object-v3alpha","zitadel-resources-object-v3alpha"]
"zitadel-session-v2" = ["zitadel-object-v2","zitadel-v1"]
"zitadel-session-v2beta" = ["zitadel-object-v2beta","zitadel-v1"]
"zitadel-settings-object-v3alpha" = ["zitadel-object-v3alpha"]
"zitadel-settings-v1" = ["zitadel-v1"]
"zitadel-settings-v2" = ["zitadel-object-v2"]
"zitadel-settings-v2beta" = ["zitadel-object-v2beta"]
"zitadel-system-v1" = ["zitadel-feature-v1","zitadel-instance-v1","zitadel-member-v1","zitadel-quota-v1","zitadel-v1"]
"zitadel-text-v1" = ["zitadel-v1"]
"zitadel-user-schema-v3alpha" = ["zitadel-object-v2"]
"zitadel-user-v1" = ["zitadel-v1"]
"zitadel-user-v2" = ["zitadel-object-v2"]
"zitadel-user-v2beta" = ["zitadel-object-v2beta"]
"zitadel-user-v3alpha" = ["zitadel-object-v2"]
"zitadel-v1" = []
"zitadel-v1-v1" = ["zitadel-authn-v1","zitadel-idp-v1","zitadel-management-v1","zitadel-org-v1","zitadel-v1"]
# @@protoc_insertion_point(features)

[dependencies]
actix-web = { version = "4.5.1", optional = true }
async-trait = { version = "0.1.80", optional = true }
Expand All @@ -64,9 +147,9 @@ custom_error = "1.9.2"
document-features = { version = "0.2.8", optional = true }
jsonwebtoken = { version = "9.3.0", optional = true }
openidconnect = { version = "3.5.0", optional = true }
pbjson-types = { version = "0.6", optional = true }
prost = { version = "0.12.4", optional = true }
prost-types = { version = "0.12.4", optional = true }
pbjson-types = { version = "0.7.0", optional = true }
prost = { version = "0.13.1", optional = true }
prost-types = { version = "0.13.1", optional = true }
reqwest = { version = "0.11.27", features = ["json", "rustls-tls"], default-features = false, optional = true }
rocket = { version = "0.5.0", optional = true }
serde = { version = "1.0.200", features = ["derive"], optional = true }
Expand All @@ -77,17 +160,16 @@ tokio = { version = "1.37.0", optional = true, features = [
"macros",
"rt-multi-thread",
] }
tonic = { version = "0.11", features = [
tonic = { version = "0.12.1", features = [
"tls",
"tls-roots",
"tls-roots-common",
], optional = true }
tonic-types = { version = "0.11", optional = true }
tonic-types = { version = "0.12.1", optional = true }

[dev-dependencies]
chrono = "0.4.38"
tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread"] }
tower = { version = "0.4.13" }

[package.metadata.docs.rs]
all-features = true
all-features = true
6 changes: 3 additions & 3 deletions buf.gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ plugins:
- extern_path=.google.protobuf=::pbjson_types
- no_server
- name: prost-crate
out: src/api/generated
out: .
strategy: all
opt:
- no_features
- include_file=mod.rs
- gen_crate
- include_file=src/api/generated/mod.rs
57 changes: 45 additions & 12 deletions src/api/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,44 @@ use std::error::Error;
use custom_error::custom_error;
use tonic::codegen::InterceptedService;
use tonic::service::Interceptor;
use tonic::transport::{Channel, Endpoint};
use tonic::transport::{Channel, ClientTlsConfig, Endpoint};
use tonic::{Request, Status};

#[cfg(feature = "interceptors")]
use crate::api::interceptors::{AccessTokenInterceptor, ServiceAccountInterceptor};
use crate::api::zitadel::oidc::v2beta::oidc_service_client::OidcServiceClient;
use crate::api::zitadel::org::v2beta::organization_service_client::OrganizationServiceClient;
use crate::api::zitadel::session::v2beta::session_service_client::SessionServiceClient;
use crate::api::zitadel::settings::v2beta::settings_service_client::SettingsServiceClient;

#[cfg(feature = "api-oidc-v2")]
use crate::api::zitadel::oidc::v2::oidc_service_client::OidcServiceClient;
#[cfg(feature = "api-org-v2")]
use crate::api::zitadel::org::v2::organization_service_client::OrganizationServiceClient;
#[cfg(feature = "api-session-v2")]
use crate::api::zitadel::session::v2::session_service_client::SessionServiceClient;
#[cfg(feature = "api-settings-v2")]
use crate::api::zitadel::settings::v2::settings_service_client::SettingsServiceClient;
#[cfg(feature = "api-user-v2")]
use crate::api::zitadel::user::v2::user_service_client::UserServiceClient;

#[cfg(feature = "api-admin-v1")]
use crate::api::zitadel::admin::v1::admin_service_client::AdminServiceClient;
#[cfg(feature = "api-auth-v1")]
use crate::api::zitadel::auth::v1::auth_service_client::AuthServiceClient;
#[cfg(feature = "api-management-v1")]
use crate::api::zitadel::management::v1::management_service_client::ManagementServiceClient;
#[cfg(feature = "api-system-v1")]
use crate::api::zitadel::system::v1::system_service_client::SystemServiceClient;
use crate::api::zitadel::user::v2beta::user_service_client::UserServiceClient;
use crate::credentials::{AuthenticationOptions, ServiceAccount};

use super::zitadel::{
admin::v1::admin_service_client::AdminServiceClient,
auth::v1::auth_service_client::AuthServiceClient,
management::v1::management_service_client::ManagementServiceClient,
};
#[cfg(feature = "interceptors")]
use crate::credentials::{AuthenticationOptions, ServiceAccount};

custom_error! {
/// Errors that may occur when creating a client.
pub ClientError
InvalidUrl = "the provided url is invalid",
ConnectionError = "could not connect to provided endpoint",
TlsInitializationError = "could not setup tls connection",
}

#[cfg(feature = "interceptors")]
enum AuthType {
None,
AccessToken(String),
Expand All @@ -56,6 +69,7 @@ impl ChainedInterceptor {
}
}

#[cfg(feature = "interceptors")]
pub(crate) fn add_interceptor(mut self, interceptor: Box<dyn Interceptor + Send>) -> Self {
self.interceptors.push(interceptor);
self
Expand All @@ -77,6 +91,7 @@ impl Interceptor for ChainedInterceptor {
/// an authentication method.
pub struct ClientBuilder {
api_endpoint: String,
#[cfg(feature = "interceptors")]
auth_type: AuthType,
}

Expand All @@ -85,6 +100,7 @@ impl ClientBuilder {
pub fn new(api_endpoint: &str) -> Self {
Self {
api_endpoint: api_endpoint.to_string(),
#[cfg(feature = "interceptors")]
auth_type: AuthType::None,
}
}
Expand Down Expand Up @@ -127,6 +143,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-admin-v1")]
pub async fn build_admin_client(
&self,
) -> Result<AdminServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
Expand All @@ -148,6 +165,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-auth-v1")]
pub async fn build_auth_client(
&self,
) -> Result<AuthServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
Expand All @@ -169,6 +187,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-management-v1")]
pub async fn build_management_client(
&self,
) -> Result<
Expand All @@ -192,6 +211,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-oidc-v2")]
pub async fn build_oidc_client(
&self,
) -> Result<OidcServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
Expand All @@ -213,6 +233,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-org-v2")]
pub async fn build_organization_client(
&self,
) -> Result<
Expand All @@ -236,6 +257,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-session-v2")]
pub async fn build_session_client(
&self,
) -> Result<SessionServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
Expand All @@ -257,6 +279,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-settings-v2")]
pub async fn build_settings_client(
&self,
) -> Result<
Expand All @@ -280,6 +303,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-system-v1")]
pub async fn build_system_client(
&self,
) -> Result<SystemServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
Expand All @@ -301,6 +325,7 @@ impl ClientBuilder {
/// This function returns a [`ClientError`] if the provided API endpoint
/// cannot be parsed into a valid URL or if the connection to the endpoint
/// is not possible.
#[cfg(feature = "api-user-v2")]
pub async fn build_user_client(
&self,
) -> Result<UserServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
Expand All @@ -313,7 +338,9 @@ impl ClientBuilder {
}

fn get_chained_interceptor(&self) -> ChainedInterceptor {
#[allow(unused_mut)]
let mut interceptor = ChainedInterceptor::new();
#[cfg(feature = "interceptors")]
match &self.auth_type {
AuthType::AccessToken(token) => {
interceptor =
Expand All @@ -337,6 +364,12 @@ impl ClientBuilder {
async fn get_channel(api_endpoint: &str) -> Result<Channel, ClientError> {
Endpoint::from_shared(api_endpoint.to_string())
.map_err(|_| ClientError::InvalidUrl)?
.tls_config(
ClientTlsConfig::default()
.assume_http2(true)
.with_native_roots(),
)
.map_err(|_| ClientError::TlsInitializationError)?
.connect()
.await
.map_err(|_| ClientError::ConnectionError)
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

#[cfg(feature = "actix")]
pub mod actix;
#[cfg(feature = "api")]
#[cfg(feature = "api-common")]
pub mod api;
#[cfg(feature = "axum")]
pub mod axum;
Expand Down
2 changes: 1 addition & 1 deletion src/oidc/introspection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ custom_error! {
/// by default and [additional claims](https://zitadel.com/docs/apis/openidoauth/claims)
/// if requested by scope:
/// - When scope contains `urn:zitadel:iam:user:resourceowner`, the fields prefixed with
/// `resource_owner_` are set.
/// `resource_owner_` are set.
/// - When scope contains `urn:zitadel:iam:user:metadata`, the metadata hashmap will be
/// filled with the user metadata.
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
Expand Down
Loading