1use crate::codec::external_credential::{
6 from_wire_exchange_external_credential_response, from_wire_external_credential,
7 from_wire_list_external_credentials_response, from_wire_resolve_external_credential_response,
8 to_wire_create_external_credential_request, to_wire_delete_external_credential_request,
9 to_wire_exchange_external_credential_request, to_wire_get_external_credential_request,
10 to_wire_list_external_credentials_request, to_wire_resolve_external_credential_request,
11 to_wire_upsert_external_credential_request,
12 to_wire_validate_external_credential_config_request,
13};
14use crate::codec::host_service::{HostServiceChannel, connect_host_service, plain_channel};
15use crate::generated::v1;
16use crate::rpc_support::GestaltError;
17
18#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
20#[serde(rename_all = "camelCase")]
21pub struct CreateExternalCredentialRequest {
22 pub credential: Option<ExternalCredential>,
24}
25
26#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
28#[serde(rename_all = "camelCase")]
29pub struct DeleteExternalCredentialRequest {
30 pub id: String,
32}
33
34#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct ExchangeExternalCredentialRequest {
38 pub provider: String,
40 pub connection: String,
42 pub connection_id: String,
44 pub credential_subject_id: String,
46 pub actor_subject_id: String,
48 pub instance: String,
50 pub auth: Option<ExternalCredentialAuthConfig>,
52 pub credential_json: String,
54 pub connection_params: std::collections::BTreeMap<String, String>,
56}
57
58#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct ExchangeExternalCredentialResponse {
62 pub token_response: Option<ExternalCredentialTokenResponse>,
64}
65
66#[allow(clippy::enum_variant_names, clippy::large_enum_variant)]
68#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
69pub enum ExternalCredentialCredential {
70 Grant(ExternalCredentialGrant),
72 Client(ExternalCredentialClientInfo),
74 Opaque(ExternalCredentialOpaque),
76}
77
78#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
80#[serde(rename_all = "camelCase")]
81pub struct ExternalCredential {
82 pub id: String,
84 pub subject: String,
86 pub audience: String,
88 pub qualifier: String,
90 pub metadata_json: String,
92 #[serde(with = "crate::serde_time")]
93 pub created_at: Option<std::time::SystemTime>,
95 #[serde(with = "crate::serde_time")]
96 pub updated_at: Option<std::time::SystemTime>,
98 pub credential: Option<ExternalCredentialCredential>,
100}
101
102#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
104#[serde(rename_all = "camelCase")]
105pub struct ExternalCredentialAuthConfig {
106 pub r#type: String,
108 pub token: String,
110 pub token_prefix: String,
112 pub grant_type: String,
114 pub token_url: String,
116 pub client_id: String,
118 pub client_secret: String,
120 pub client_auth: String,
122 pub token_exchange: String,
124 pub scopes: Vec<String>,
126 pub scope_param: String,
128 pub scope_separator: String,
130 pub token_params: std::collections::BTreeMap<String, String>,
132 pub refresh_params: std::collections::BTreeMap<String, String>,
134 pub accept_header: String,
136 pub access_token_path: String,
138 pub token_exchange_drivers: Vec<ExternalCredentialTokenExchangeDriver>,
140 pub refresh_token: String,
142}
143
144#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
146#[serde(rename_all = "camelCase")]
147pub struct ExternalCredentialClientInfo {
148 pub client_id: String,
150 pub client_secret: String,
152 #[serde(with = "crate::serde_time")]
153 pub client_secret_expires_at: Option<std::time::SystemTime>,
155}
156
157#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
159#[serde(rename_all = "camelCase")]
160pub struct ExternalCredentialGrant {
161 pub access_token: String,
163 pub refresh_token: String,
165 pub scope: String,
167 #[serde(with = "crate::serde_time")]
168 pub expires_at: Option<std::time::SystemTime>,
170 #[serde(with = "crate::serde_time")]
171 pub last_refreshed_at: Option<std::time::SystemTime>,
173 pub refresh_error_count: i32,
175}
176
177#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
179#[serde(rename_all = "camelCase")]
180pub struct ExternalCredentialOpaque {
181 pub fields: std::collections::BTreeMap<String, String>,
183}
184
185#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
187#[serde(rename_all = "camelCase")]
188pub struct ExternalCredentialTokenExchangeDriver {
189 pub r#type: String,
191 pub target_principal: String,
193 pub scopes: Vec<String>,
195 pub lifetime_seconds: i32,
197 pub endpoint: String,
199 pub params: std::collections::BTreeMap<String, String>,
201}
202
203#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
205#[serde(rename_all = "camelCase")]
206pub struct ExternalCredentialTokenResponse {
207 pub access_token: String,
209 pub refresh_token: String,
211 pub expires_in: i32,
213 pub token_type: String,
215 pub extra_json: String,
217 pub refresh_source: String,
219}
220
221#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
223#[serde(rename_all = "camelCase")]
224pub struct GetExternalCredentialRequest {
225 pub subject: String,
227 pub audience: String,
229 pub qualifier: String,
231}
232
233#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
235#[serde(rename_all = "camelCase")]
236pub struct ListExternalCredentialsRequest {
237 pub subject: String,
239 pub audience: String,
241}
242
243#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
245#[serde(rename_all = "camelCase")]
246pub struct ListExternalCredentialsResponse {
247 pub credentials: Vec<ExternalCredential>,
249}
250
251#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
253#[serde(rename_all = "camelCase")]
254pub struct ResolveExternalCredentialRequest {
255 pub provider: String,
257 pub connection: String,
259 pub connection_id: String,
261 pub mode: String,
263 pub credential_subject_id: String,
265 pub actor_subject_id: String,
267 pub instance: String,
269 pub auth: Option<ExternalCredentialAuthConfig>,
271 pub connection_params: std::collections::BTreeMap<String, String>,
273}
274
275#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
277#[serde(rename_all = "camelCase")]
278pub struct ResolveExternalCredentialResponse {
279 pub token: String,
281 #[serde(with = "crate::serde_time")]
282 pub expires_at: Option<std::time::SystemTime>,
284 pub metadata_json: String,
286 pub params: std::collections::BTreeMap<String, String>,
288 pub credential: Option<ExternalCredential>,
290}
291
292#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
294#[serde(rename_all = "camelCase")]
295pub struct UpsertExternalCredentialRequest {
296 pub credential: Option<ExternalCredential>,
298}
299
300#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
302#[serde(rename_all = "camelCase")]
303pub struct ValidateExternalCredentialConfigRequest {
304 pub provider: String,
306 pub connection: String,
308 pub connection_id: String,
310 pub mode: String,
312 pub auth: Option<ExternalCredentialAuthConfig>,
314 pub connection_params: std::collections::BTreeMap<String, String>,
316}
317
318pub struct ExternalCredentials {
320 inner: v1::external_credentials_client::ExternalCredentialsClient<HostServiceChannel>,
321 timeout: Option<std::time::Duration>,
322}
323
324impl ExternalCredentials {
325 pub fn new(channel: tonic::transport::Channel) -> Self {
327 Self {
328 inner: v1::external_credentials_client::ExternalCredentialsClient::new(plain_channel(
329 channel,
330 )),
331 timeout: None,
332 }
333 }
334
335 pub fn with_timeout(mut self, timeout: std::time::Duration) -> Self {
338 self.timeout = Some(timeout);
339 self
340 }
341
342 pub async fn connect() -> Result<Self, GestaltError> {
344 Self::connect_named("").await
345 }
346
347 pub async fn connect_named(name: &str) -> Result<Self, GestaltError> {
349 Ok(Self {
350 inner: v1::external_credentials_client::ExternalCredentialsClient::new(
351 connect_host_service("external_credentials", name).await?,
352 ),
353 timeout: None,
354 })
355 }
356
357 pub async fn create_credential(
359 &mut self,
360 credential: Option<ExternalCredential>,
361 ) -> Result<ExternalCredential, GestaltError> {
362 let request = CreateExternalCredentialRequest { credential };
363 let mut tonic_request =
364 tonic::Request::new(to_wire_create_external_credential_request(request));
365 if let Some(timeout) = self.timeout {
366 tonic_request.set_timeout(timeout);
367 }
368 let response = self.inner.create_credential(tonic_request).await?;
369 Ok(from_wire_external_credential(response.into_inner()))
370 }
371
372 pub async fn create_credential_raw(
374 &mut self,
375 request: CreateExternalCredentialRequest,
376 ) -> Result<ExternalCredential, GestaltError> {
377 let mut tonic_request =
378 tonic::Request::new(to_wire_create_external_credential_request(request));
379 if let Some(timeout) = self.timeout {
380 tonic_request.set_timeout(timeout);
381 }
382 let response = self.inner.create_credential(tonic_request).await?;
383 Ok(from_wire_external_credential(response.into_inner()))
384 }
385
386 pub async fn upsert_credential(
388 &mut self,
389 credential: Option<ExternalCredential>,
390 ) -> Result<ExternalCredential, GestaltError> {
391 let request = UpsertExternalCredentialRequest { credential };
392 let mut tonic_request =
393 tonic::Request::new(to_wire_upsert_external_credential_request(request));
394 if let Some(timeout) = self.timeout {
395 tonic_request.set_timeout(timeout);
396 }
397 let response = self.inner.upsert_credential(tonic_request).await?;
398 Ok(from_wire_external_credential(response.into_inner()))
399 }
400
401 pub async fn upsert_credential_raw(
403 &mut self,
404 request: UpsertExternalCredentialRequest,
405 ) -> Result<ExternalCredential, GestaltError> {
406 let mut tonic_request =
407 tonic::Request::new(to_wire_upsert_external_credential_request(request));
408 if let Some(timeout) = self.timeout {
409 tonic_request.set_timeout(timeout);
410 }
411 let response = self.inner.upsert_credential(tonic_request).await?;
412 Ok(from_wire_external_credential(response.into_inner()))
413 }
414
415 pub async fn get_credential(
417 &mut self,
418 subject: String,
419 audience: String,
420 qualifier: String,
421 ) -> Result<ExternalCredential, GestaltError> {
422 let request = GetExternalCredentialRequest {
423 subject,
424 audience,
425 qualifier,
426 };
427 let mut tonic_request =
428 tonic::Request::new(to_wire_get_external_credential_request(request));
429 if let Some(timeout) = self.timeout {
430 tonic_request.set_timeout(timeout);
431 }
432 let response = self.inner.get_credential(tonic_request).await?;
433 Ok(from_wire_external_credential(response.into_inner()))
434 }
435
436 pub async fn get_credential_raw(
438 &mut self,
439 request: GetExternalCredentialRequest,
440 ) -> Result<ExternalCredential, GestaltError> {
441 let mut tonic_request =
442 tonic::Request::new(to_wire_get_external_credential_request(request));
443 if let Some(timeout) = self.timeout {
444 tonic_request.set_timeout(timeout);
445 }
446 let response = self.inner.get_credential(tonic_request).await?;
447 Ok(from_wire_external_credential(response.into_inner()))
448 }
449
450 pub async fn list_credentials(
452 &mut self,
453 subject: String,
454 options: ExternalCredentialsListCredentialsOptions,
455 ) -> Result<Vec<ExternalCredential>, GestaltError> {
456 let request = ListExternalCredentialsRequest {
457 subject,
458 audience: options.audience,
459 };
460 let mut tonic_request =
461 tonic::Request::new(to_wire_list_external_credentials_request(request));
462 if let Some(timeout) = self.timeout {
463 tonic_request.set_timeout(timeout);
464 }
465 let response = from_wire_list_external_credentials_response(
466 self.inner
467 .list_credentials(tonic_request)
468 .await?
469 .into_inner(),
470 );
471 Ok(response.credentials)
472 }
473
474 pub async fn list_credentials_raw(
476 &mut self,
477 request: ListExternalCredentialsRequest,
478 ) -> Result<ListExternalCredentialsResponse, GestaltError> {
479 let mut tonic_request =
480 tonic::Request::new(to_wire_list_external_credentials_request(request));
481 if let Some(timeout) = self.timeout {
482 tonic_request.set_timeout(timeout);
483 }
484 let response = self.inner.list_credentials(tonic_request).await?;
485 Ok(from_wire_list_external_credentials_response(
486 response.into_inner(),
487 ))
488 }
489
490 pub async fn delete_credential(&mut self, id: String) -> Result<(), GestaltError> {
492 let request = DeleteExternalCredentialRequest { id };
493 let mut tonic_request =
494 tonic::Request::new(to_wire_delete_external_credential_request(request));
495 if let Some(timeout) = self.timeout {
496 tonic_request.set_timeout(timeout);
497 }
498 self.inner.delete_credential(tonic_request).await?;
499 Ok(())
500 }
501
502 pub async fn delete_credential_raw(
504 &mut self,
505 request: DeleteExternalCredentialRequest,
506 ) -> Result<(), GestaltError> {
507 let mut tonic_request =
508 tonic::Request::new(to_wire_delete_external_credential_request(request));
509 if let Some(timeout) = self.timeout {
510 tonic_request.set_timeout(timeout);
511 }
512 self.inner.delete_credential(tonic_request).await?;
513 Ok(())
514 }
515
516 pub async fn validate_credential_config(
518 &mut self,
519 provider: String,
520 connection: String,
521 connection_id: String,
522 mode: String,
523 auth: Option<ExternalCredentialAuthConfig>,
524 ) -> Result<(), GestaltError> {
525 let request = ValidateExternalCredentialConfigRequest {
526 provider,
527 connection,
528 connection_id,
529 mode,
530 auth,
531 ..Default::default()
532 };
533 let mut tonic_request =
534 tonic::Request::new(to_wire_validate_external_credential_config_request(request));
535 if let Some(timeout) = self.timeout {
536 tonic_request.set_timeout(timeout);
537 }
538 self.inner.validate_credential_config(tonic_request).await?;
539 Ok(())
540 }
541
542 pub async fn validate_credential_config_raw(
544 &mut self,
545 request: ValidateExternalCredentialConfigRequest,
546 ) -> Result<(), GestaltError> {
547 let mut tonic_request =
548 tonic::Request::new(to_wire_validate_external_credential_config_request(request));
549 if let Some(timeout) = self.timeout {
550 tonic_request.set_timeout(timeout);
551 }
552 self.inner.validate_credential_config(tonic_request).await?;
553 Ok(())
554 }
555
556 #[allow(clippy::too_many_arguments)]
558 pub async fn resolve_credential(
559 &mut self,
560 provider: String,
561 connection: String,
562 connection_id: String,
563 mode: String,
564 credential_subject_id: String,
565 actor_subject_id: String,
566 instance: String,
567 auth: Option<ExternalCredentialAuthConfig>,
568 ) -> Result<ResolveExternalCredentialResponse, GestaltError> {
569 let request = ResolveExternalCredentialRequest {
570 provider,
571 connection,
572 connection_id,
573 mode,
574 credential_subject_id,
575 actor_subject_id,
576 instance,
577 auth,
578 ..Default::default()
579 };
580 let mut tonic_request =
581 tonic::Request::new(to_wire_resolve_external_credential_request(request));
582 if let Some(timeout) = self.timeout {
583 tonic_request.set_timeout(timeout);
584 }
585 let response = self.inner.resolve_credential(tonic_request).await?;
586 Ok(from_wire_resolve_external_credential_response(
587 response.into_inner(),
588 ))
589 }
590
591 pub async fn resolve_credential_raw(
593 &mut self,
594 request: ResolveExternalCredentialRequest,
595 ) -> Result<ResolveExternalCredentialResponse, GestaltError> {
596 let mut tonic_request =
597 tonic::Request::new(to_wire_resolve_external_credential_request(request));
598 if let Some(timeout) = self.timeout {
599 tonic_request.set_timeout(timeout);
600 }
601 let response = self.inner.resolve_credential(tonic_request).await?;
602 Ok(from_wire_resolve_external_credential_response(
603 response.into_inner(),
604 ))
605 }
606
607 #[allow(clippy::too_many_arguments)]
609 pub async fn exchange_credential(
610 &mut self,
611 provider: String,
612 connection: String,
613 connection_id: String,
614 credential_subject_id: String,
615 actor_subject_id: String,
616 instance: String,
617 credential_json: String,
618 auth: Option<ExternalCredentialAuthConfig>,
619 ) -> Result<Option<ExternalCredentialTokenResponse>, GestaltError> {
620 let request = ExchangeExternalCredentialRequest {
621 provider,
622 connection,
623 connection_id,
624 credential_subject_id,
625 actor_subject_id,
626 instance,
627 credential_json,
628 auth,
629 ..Default::default()
630 };
631 let mut tonic_request =
632 tonic::Request::new(to_wire_exchange_external_credential_request(request));
633 if let Some(timeout) = self.timeout {
634 tonic_request.set_timeout(timeout);
635 }
636 let response = from_wire_exchange_external_credential_response(
637 self.inner
638 .exchange_credential(tonic_request)
639 .await?
640 .into_inner(),
641 );
642 Ok(response.token_response)
643 }
644
645 pub async fn exchange_credential_raw(
647 &mut self,
648 request: ExchangeExternalCredentialRequest,
649 ) -> Result<ExchangeExternalCredentialResponse, GestaltError> {
650 let mut tonic_request =
651 tonic::Request::new(to_wire_exchange_external_credential_request(request));
652 if let Some(timeout) = self.timeout {
653 tonic_request.set_timeout(timeout);
654 }
655 let response = self.inner.exchange_credential(tonic_request).await?;
656 Ok(from_wire_exchange_external_credential_response(
657 response.into_inner(),
658 ))
659 }
660}
661
662#[derive(Clone, Debug, Default)]
665pub struct ExternalCredentialsListCredentialsOptions {
666 pub audience: String,
668}