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_delete_external_credential_request, to_wire_exchange_external_credential_request,
9 to_wire_get_external_credential_request, to_wire_list_external_credentials_request,
10 to_wire_resolve_external_credential_request, to_wire_upsert_external_credential_request,
11 to_wire_validate_external_credential_config_request,
12};
13use crate::codec::host_service::{HostServiceChannel, connect_host_service, plain_channel};
14use crate::generated::v1;
15use crate::rpc_support::GestaltError;
16
17#[derive(Clone, Debug, Default, PartialEq)]
19pub struct DeleteExternalCredentialRequest {
20 pub id: String,
22}
23
24#[derive(Clone, Debug, Default, PartialEq)]
26pub struct ExchangeExternalCredentialRequest {
27 pub provider: String,
29 pub connection: String,
31 pub connection_id: String,
33 pub credential_subject_id: String,
35 pub actor_subject_id: String,
37 pub instance: String,
39 pub auth: Option<ExternalCredentialAuthConfig>,
41 pub credential_json: String,
43 pub connection_params: std::collections::BTreeMap<String, String>,
45}
46
47#[derive(Clone, Debug, Default, PartialEq)]
49pub struct ExchangeExternalCredentialResponse {
50 pub token_response: Option<ExternalCredentialTokenResponse>,
52}
53
54#[derive(Clone, Debug, Default, PartialEq)]
56pub struct ExternalCredential {
57 pub id: String,
59 pub subject_id: String,
61 pub instance: String,
63 pub access_token: String,
65 pub refresh_token: String,
67 pub scopes: String,
69 pub expires_at: Option<std::time::SystemTime>,
71 pub last_refreshed_at: Option<std::time::SystemTime>,
73 pub refresh_error_count: i32,
75 pub metadata_json: String,
77 pub created_at: Option<std::time::SystemTime>,
79 pub updated_at: Option<std::time::SystemTime>,
81 pub connection_id: String,
83}
84
85#[derive(Clone, Debug, Default, PartialEq)]
87pub struct ExternalCredentialAuthConfig {
88 pub r#type: String,
90 pub token: String,
92 pub token_prefix: String,
94 pub grant_type: String,
96 pub token_url: String,
98 pub client_id: String,
100 pub client_secret: String,
102 pub client_auth: String,
104 pub token_exchange: String,
106 pub scopes: Vec<String>,
108 pub scope_param: String,
110 pub scope_separator: String,
112 pub token_params: std::collections::BTreeMap<String, String>,
114 pub refresh_params: std::collections::BTreeMap<String, String>,
116 pub accept_header: String,
118 pub access_token_path: String,
120 pub token_exchange_drivers: Vec<ExternalCredentialTokenExchangeDriver>,
122 pub refresh_token: String,
124}
125
126#[derive(Clone, Debug, Default, PartialEq)]
128pub struct ExternalCredentialLookup {
129 pub subject_id: String,
131 pub instance: String,
133 pub connection_id: String,
135}
136
137#[derive(Clone, Debug, Default, PartialEq)]
139pub struct ExternalCredentialTokenExchangeDriver {
140 pub r#type: String,
142 pub target_principal: String,
144 pub scopes: Vec<String>,
146 pub lifetime_seconds: i32,
148 pub endpoint: String,
150 pub params: std::collections::BTreeMap<String, String>,
152}
153
154#[derive(Clone, Debug, Default, PartialEq)]
156pub struct ExternalCredentialTokenResponse {
157 pub access_token: String,
159 pub refresh_token: String,
161 pub expires_in: i32,
163 pub token_type: String,
165 pub extra_json: String,
167 pub refresh_source: String,
169}
170
171#[derive(Clone, Debug, Default, PartialEq)]
173pub struct GetExternalCredentialRequest {
174 pub lookup: Option<ExternalCredentialLookup>,
176}
177
178#[derive(Clone, Debug, Default, PartialEq)]
180pub struct ListExternalCredentialsRequest {
181 pub subject_id: String,
183 pub instance: String,
185 pub connection_id: String,
187}
188
189#[derive(Clone, Debug, Default, PartialEq)]
191pub struct ListExternalCredentialsResponse {
192 pub credentials: Vec<ExternalCredential>,
194}
195
196#[derive(Clone, Debug, Default, PartialEq)]
198pub struct ResolveExternalCredentialRequest {
199 pub provider: String,
201 pub connection: String,
203 pub connection_id: String,
205 pub mode: String,
207 pub credential_subject_id: String,
209 pub actor_subject_id: String,
211 pub instance: String,
213 pub auth: Option<ExternalCredentialAuthConfig>,
215 pub connection_params: std::collections::BTreeMap<String, String>,
217}
218
219#[derive(Clone, Debug, Default, PartialEq)]
221pub struct ResolveExternalCredentialResponse {
222 pub token: String,
224 pub expires_at: Option<std::time::SystemTime>,
226 pub metadata_json: String,
228 pub params: std::collections::BTreeMap<String, String>,
230 pub credential: Option<ExternalCredential>,
232}
233
234#[derive(Clone, Debug, Default, PartialEq)]
236pub struct UpsertExternalCredentialRequest {
237 pub credential: Option<ExternalCredential>,
239 pub preserve_timestamps: bool,
241}
242
243#[derive(Clone, Debug, Default, PartialEq)]
245pub struct ValidateExternalCredentialConfigRequest {
246 pub provider: String,
248 pub connection: String,
250 pub connection_id: String,
252 pub mode: String,
254 pub auth: Option<ExternalCredentialAuthConfig>,
256 pub connection_params: std::collections::BTreeMap<String, String>,
258}
259
260pub struct ExternalCredentials {
262 inner: v1::external_credentials_client::ExternalCredentialsClient<HostServiceChannel>,
263 timeout: Option<std::time::Duration>,
264}
265
266impl ExternalCredentials {
267 pub fn new(channel: tonic::transport::Channel) -> Self {
269 Self {
270 inner: v1::external_credentials_client::ExternalCredentialsClient::new(plain_channel(
271 channel,
272 )),
273 timeout: None,
274 }
275 }
276
277 pub fn with_timeout(mut self, timeout: std::time::Duration) -> Self {
280 self.timeout = Some(timeout);
281 self
282 }
283
284 pub async fn connect() -> Result<Self, GestaltError> {
286 Self::connect_named("").await
287 }
288
289 pub async fn connect_named(name: &str) -> Result<Self, GestaltError> {
291 Ok(Self {
292 inner: v1::external_credentials_client::ExternalCredentialsClient::new(
293 connect_host_service("external_credentials", name).await?,
294 ),
295 timeout: None,
296 })
297 }
298
299 pub async fn upsert_credential(
301 &mut self,
302 preserve_timestamps: bool,
303 credential: Option<ExternalCredential>,
304 ) -> Result<ExternalCredential, GestaltError> {
305 let request = UpsertExternalCredentialRequest {
306 preserve_timestamps,
307 credential,
308 };
309 let mut tonic_request =
310 tonic::Request::new(to_wire_upsert_external_credential_request(request));
311 if let Some(timeout) = self.timeout {
312 tonic_request.set_timeout(timeout);
313 }
314 let response = self.inner.upsert_credential(tonic_request).await?;
315 Ok(from_wire_external_credential(response.into_inner()))
316 }
317
318 pub async fn upsert_credential_raw(
320 &mut self,
321 request: UpsertExternalCredentialRequest,
322 ) -> Result<ExternalCredential, GestaltError> {
323 let mut tonic_request =
324 tonic::Request::new(to_wire_upsert_external_credential_request(request));
325 if let Some(timeout) = self.timeout {
326 tonic_request.set_timeout(timeout);
327 }
328 let response = self.inner.upsert_credential(tonic_request).await?;
329 Ok(from_wire_external_credential(response.into_inner()))
330 }
331
332 pub async fn get_credential(
334 &mut self,
335 lookup: Option<ExternalCredentialLookup>,
336 ) -> Result<ExternalCredential, GestaltError> {
337 let request = GetExternalCredentialRequest { lookup };
338 let mut tonic_request =
339 tonic::Request::new(to_wire_get_external_credential_request(request));
340 if let Some(timeout) = self.timeout {
341 tonic_request.set_timeout(timeout);
342 }
343 let response = self.inner.get_credential(tonic_request).await?;
344 Ok(from_wire_external_credential(response.into_inner()))
345 }
346
347 pub async fn get_credential_raw(
349 &mut self,
350 request: GetExternalCredentialRequest,
351 ) -> Result<ExternalCredential, GestaltError> {
352 let mut tonic_request =
353 tonic::Request::new(to_wire_get_external_credential_request(request));
354 if let Some(timeout) = self.timeout {
355 tonic_request.set_timeout(timeout);
356 }
357 let response = self.inner.get_credential(tonic_request).await?;
358 Ok(from_wire_external_credential(response.into_inner()))
359 }
360
361 pub async fn list_credentials(
363 &mut self,
364 subject_id: String,
365 instance: String,
366 connection_id: String,
367 ) -> Result<Vec<ExternalCredential>, GestaltError> {
368 let request = ListExternalCredentialsRequest {
369 subject_id,
370 instance,
371 connection_id,
372 };
373 let mut tonic_request =
374 tonic::Request::new(to_wire_list_external_credentials_request(request));
375 if let Some(timeout) = self.timeout {
376 tonic_request.set_timeout(timeout);
377 }
378 let response = from_wire_list_external_credentials_response(
379 self.inner
380 .list_credentials(tonic_request)
381 .await?
382 .into_inner(),
383 );
384 Ok(response.credentials)
385 }
386
387 pub async fn list_credentials_raw(
389 &mut self,
390 request: ListExternalCredentialsRequest,
391 ) -> Result<ListExternalCredentialsResponse, GestaltError> {
392 let mut tonic_request =
393 tonic::Request::new(to_wire_list_external_credentials_request(request));
394 if let Some(timeout) = self.timeout {
395 tonic_request.set_timeout(timeout);
396 }
397 let response = self.inner.list_credentials(tonic_request).await?;
398 Ok(from_wire_list_external_credentials_response(
399 response.into_inner(),
400 ))
401 }
402
403 pub async fn delete_credential(&mut self, id: String) -> Result<(), GestaltError> {
405 let request = DeleteExternalCredentialRequest { id };
406 let mut tonic_request =
407 tonic::Request::new(to_wire_delete_external_credential_request(request));
408 if let Some(timeout) = self.timeout {
409 tonic_request.set_timeout(timeout);
410 }
411 self.inner.delete_credential(tonic_request).await?;
412 Ok(())
413 }
414
415 pub async fn delete_credential_raw(
417 &mut self,
418 request: DeleteExternalCredentialRequest,
419 ) -> Result<(), GestaltError> {
420 let mut tonic_request =
421 tonic::Request::new(to_wire_delete_external_credential_request(request));
422 if let Some(timeout) = self.timeout {
423 tonic_request.set_timeout(timeout);
424 }
425 self.inner.delete_credential(tonic_request).await?;
426 Ok(())
427 }
428
429 pub async fn validate_credential_config(
431 &mut self,
432 provider: String,
433 connection: String,
434 connection_id: String,
435 mode: String,
436 auth: Option<ExternalCredentialAuthConfig>,
437 ) -> Result<(), GestaltError> {
438 let request = ValidateExternalCredentialConfigRequest {
439 provider,
440 connection,
441 connection_id,
442 mode,
443 auth,
444 ..Default::default()
445 };
446 let mut tonic_request =
447 tonic::Request::new(to_wire_validate_external_credential_config_request(request));
448 if let Some(timeout) = self.timeout {
449 tonic_request.set_timeout(timeout);
450 }
451 self.inner.validate_credential_config(tonic_request).await?;
452 Ok(())
453 }
454
455 pub async fn validate_credential_config_raw(
457 &mut self,
458 request: ValidateExternalCredentialConfigRequest,
459 ) -> Result<(), GestaltError> {
460 let mut tonic_request =
461 tonic::Request::new(to_wire_validate_external_credential_config_request(request));
462 if let Some(timeout) = self.timeout {
463 tonic_request.set_timeout(timeout);
464 }
465 self.inner.validate_credential_config(tonic_request).await?;
466 Ok(())
467 }
468
469 #[allow(clippy::too_many_arguments)]
471 pub async fn resolve_credential(
472 &mut self,
473 provider: String,
474 connection: String,
475 connection_id: String,
476 mode: String,
477 credential_subject_id: String,
478 actor_subject_id: String,
479 instance: String,
480 auth: Option<ExternalCredentialAuthConfig>,
481 ) -> Result<ResolveExternalCredentialResponse, GestaltError> {
482 let request = ResolveExternalCredentialRequest {
483 provider,
484 connection,
485 connection_id,
486 mode,
487 credential_subject_id,
488 actor_subject_id,
489 instance,
490 auth,
491 ..Default::default()
492 };
493 let mut tonic_request =
494 tonic::Request::new(to_wire_resolve_external_credential_request(request));
495 if let Some(timeout) = self.timeout {
496 tonic_request.set_timeout(timeout);
497 }
498 let response = self.inner.resolve_credential(tonic_request).await?;
499 Ok(from_wire_resolve_external_credential_response(
500 response.into_inner(),
501 ))
502 }
503
504 pub async fn resolve_credential_raw(
506 &mut self,
507 request: ResolveExternalCredentialRequest,
508 ) -> Result<ResolveExternalCredentialResponse, GestaltError> {
509 let mut tonic_request =
510 tonic::Request::new(to_wire_resolve_external_credential_request(request));
511 if let Some(timeout) = self.timeout {
512 tonic_request.set_timeout(timeout);
513 }
514 let response = self.inner.resolve_credential(tonic_request).await?;
515 Ok(from_wire_resolve_external_credential_response(
516 response.into_inner(),
517 ))
518 }
519
520 #[allow(clippy::too_many_arguments)]
522 pub async fn exchange_credential(
523 &mut self,
524 provider: String,
525 connection: String,
526 connection_id: String,
527 credential_subject_id: String,
528 actor_subject_id: String,
529 instance: String,
530 credential_json: String,
531 auth: Option<ExternalCredentialAuthConfig>,
532 ) -> Result<Option<ExternalCredentialTokenResponse>, GestaltError> {
533 let request = ExchangeExternalCredentialRequest {
534 provider,
535 connection,
536 connection_id,
537 credential_subject_id,
538 actor_subject_id,
539 instance,
540 credential_json,
541 auth,
542 ..Default::default()
543 };
544 let mut tonic_request =
545 tonic::Request::new(to_wire_exchange_external_credential_request(request));
546 if let Some(timeout) = self.timeout {
547 tonic_request.set_timeout(timeout);
548 }
549 let response = from_wire_exchange_external_credential_response(
550 self.inner
551 .exchange_credential(tonic_request)
552 .await?
553 .into_inner(),
554 );
555 Ok(response.token_response)
556 }
557
558 pub async fn exchange_credential_raw(
560 &mut self,
561 request: ExchangeExternalCredentialRequest,
562 ) -> Result<ExchangeExternalCredentialResponse, GestaltError> {
563 let mut tonic_request =
564 tonic::Request::new(to_wire_exchange_external_credential_request(request));
565 if let Some(timeout) = self.timeout {
566 tonic_request.set_timeout(timeout);
567 }
568 let response = self.inner.exchange_credential(tonic_request).await?;
569 Ok(from_wire_exchange_external_credential_response(
570 response.into_inner(),
571 ))
572 }
573}