1use std::error::Error;
14use std::fmt;
15
16use async_trait::async_trait;
17use rusoto_core::credential::ProvideAwsCredentials;
18use rusoto_core::region;
19use rusoto_core::request::{BufferedHttpResponse, DispatchSignedRequest};
20use rusoto_core::{Client, RusotoError};
21
22use rusoto_core::param::{Params, ServiceParams};
23use rusoto_core::proto;
24use rusoto_core::signature::SignedRequest;
25#[allow(unused_imports)]
26use serde::{Deserialize, Serialize};
27#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
29#[cfg_attr(any(test, feature = "serialize_structs"), derive(Serialize))]
30pub struct AccountInfo {
31 #[serde(rename = "accountId")]
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub account_id: Option<String>,
35 #[serde(rename = "accountName")]
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub account_name: Option<String>,
39 #[serde(rename = "emailAddress")]
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub email_address: Option<String>,
43}
44
45#[derive(Clone, Debug, Default, PartialEq, Serialize)]
46#[cfg_attr(feature = "deserialize_structs", derive(Deserialize))]
47pub struct GetRoleCredentialsRequest {
48 #[serde(rename = "accessToken")]
50 pub access_token: String,
51 #[serde(rename = "accountId")]
53 pub account_id: String,
54 #[serde(rename = "roleName")]
56 pub role_name: String,
57}
58
59#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
60#[cfg_attr(any(test, feature = "serialize_structs"), derive(Serialize))]
61pub struct GetRoleCredentialsResponse {
62 #[serde(rename = "roleCredentials")]
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub role_credentials: Option<RoleCredentials>,
66}
67
68#[derive(Clone, Debug, Default, PartialEq, Serialize)]
69#[cfg_attr(feature = "deserialize_structs", derive(Deserialize))]
70pub struct ListAccountRolesRequest {
71 #[serde(rename = "accessToken")]
73 pub access_token: String,
74 #[serde(rename = "accountId")]
76 pub account_id: String,
77 #[serde(rename = "maxResults")]
79 #[serde(skip_serializing_if = "Option::is_none")]
80 pub max_results: Option<i64>,
81 #[serde(rename = "nextToken")]
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub next_token: Option<String>,
85}
86
87#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
88#[cfg_attr(any(test, feature = "serialize_structs"), derive(Serialize))]
89pub struct ListAccountRolesResponse {
90 #[serde(rename = "nextToken")]
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub next_token: Option<String>,
94 #[serde(rename = "roleList")]
96 #[serde(skip_serializing_if = "Option::is_none")]
97 pub role_list: Option<Vec<RoleInfo>>,
98}
99
100#[derive(Clone, Debug, Default, PartialEq, Serialize)]
101#[cfg_attr(feature = "deserialize_structs", derive(Deserialize))]
102pub struct ListAccountsRequest {
103 #[serde(rename = "accessToken")]
105 pub access_token: String,
106 #[serde(rename = "maxResults")]
108 #[serde(skip_serializing_if = "Option::is_none")]
109 pub max_results: Option<i64>,
110 #[serde(rename = "nextToken")]
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub next_token: Option<String>,
114}
115
116#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
117#[cfg_attr(any(test, feature = "serialize_structs"), derive(Serialize))]
118pub struct ListAccountsResponse {
119 #[serde(rename = "accountList")]
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub account_list: Option<Vec<AccountInfo>>,
123 #[serde(rename = "nextToken")]
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub next_token: Option<String>,
127}
128
129#[derive(Clone, Debug, Default, PartialEq, Serialize)]
130#[cfg_attr(feature = "deserialize_structs", derive(Deserialize))]
131pub struct LogoutRequest {
132 #[serde(rename = "accessToken")]
134 pub access_token: String,
135}
136
137#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
139#[cfg_attr(any(test, feature = "serialize_structs"), derive(Serialize))]
140pub struct RoleCredentials {
141 #[serde(rename = "accessKeyId")]
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub access_key_id: Option<String>,
145 #[serde(rename = "expiration")]
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub expiration: Option<i64>,
149 #[serde(rename = "secretAccessKey")]
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub secret_access_key: Option<String>,
153 #[serde(rename = "sessionToken")]
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub session_token: Option<String>,
157}
158
159#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
161#[cfg_attr(any(test, feature = "serialize_structs"), derive(Serialize))]
162pub struct RoleInfo {
163 #[serde(rename = "accountId")]
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub account_id: Option<String>,
167 #[serde(rename = "roleName")]
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub role_name: Option<String>,
171}
172
173#[derive(Debug, PartialEq)]
175pub enum GetRoleCredentialsError {
176 InvalidRequest(String),
178 ResourceNotFound(String),
180 TooManyRequests(String),
182 Unauthorized(String),
184}
185
186impl GetRoleCredentialsError {
187 pub fn from_response(res: BufferedHttpResponse) -> RusotoError<GetRoleCredentialsError> {
188 if let Some(err) = proto::json::Error::parse_rest(&res) {
189 match err.typ.as_str() {
190 "InvalidRequestException" => {
191 return RusotoError::Service(GetRoleCredentialsError::InvalidRequest(err.msg))
192 }
193 "ResourceNotFoundException" => {
194 return RusotoError::Service(GetRoleCredentialsError::ResourceNotFound(err.msg))
195 }
196 "TooManyRequestsException" => {
197 return RusotoError::Service(GetRoleCredentialsError::TooManyRequests(err.msg))
198 }
199 "UnauthorizedException" => {
200 return RusotoError::Service(GetRoleCredentialsError::Unauthorized(err.msg))
201 }
202 "ValidationException" => return RusotoError::Validation(err.msg),
203 _ => {}
204 }
205 }
206 RusotoError::Unknown(res)
207 }
208}
209impl fmt::Display for GetRoleCredentialsError {
210 #[allow(unused_variables)]
211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212 match *self {
213 GetRoleCredentialsError::InvalidRequest(ref cause) => write!(f, "{}", cause),
214 GetRoleCredentialsError::ResourceNotFound(ref cause) => write!(f, "{}", cause),
215 GetRoleCredentialsError::TooManyRequests(ref cause) => write!(f, "{}", cause),
216 GetRoleCredentialsError::Unauthorized(ref cause) => write!(f, "{}", cause),
217 }
218 }
219}
220impl Error for GetRoleCredentialsError {}
221#[derive(Debug, PartialEq)]
223pub enum ListAccountRolesError {
224 InvalidRequest(String),
226 ResourceNotFound(String),
228 TooManyRequests(String),
230 Unauthorized(String),
232}
233
234impl ListAccountRolesError {
235 pub fn from_response(res: BufferedHttpResponse) -> RusotoError<ListAccountRolesError> {
236 if let Some(err) = proto::json::Error::parse_rest(&res) {
237 match err.typ.as_str() {
238 "InvalidRequestException" => {
239 return RusotoError::Service(ListAccountRolesError::InvalidRequest(err.msg))
240 }
241 "ResourceNotFoundException" => {
242 return RusotoError::Service(ListAccountRolesError::ResourceNotFound(err.msg))
243 }
244 "TooManyRequestsException" => {
245 return RusotoError::Service(ListAccountRolesError::TooManyRequests(err.msg))
246 }
247 "UnauthorizedException" => {
248 return RusotoError::Service(ListAccountRolesError::Unauthorized(err.msg))
249 }
250 "ValidationException" => return RusotoError::Validation(err.msg),
251 _ => {}
252 }
253 }
254 RusotoError::Unknown(res)
255 }
256}
257impl fmt::Display for ListAccountRolesError {
258 #[allow(unused_variables)]
259 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260 match *self {
261 ListAccountRolesError::InvalidRequest(ref cause) => write!(f, "{}", cause),
262 ListAccountRolesError::ResourceNotFound(ref cause) => write!(f, "{}", cause),
263 ListAccountRolesError::TooManyRequests(ref cause) => write!(f, "{}", cause),
264 ListAccountRolesError::Unauthorized(ref cause) => write!(f, "{}", cause),
265 }
266 }
267}
268impl Error for ListAccountRolesError {}
269#[derive(Debug, PartialEq)]
271pub enum ListAccountsError {
272 InvalidRequest(String),
274 ResourceNotFound(String),
276 TooManyRequests(String),
278 Unauthorized(String),
280}
281
282impl ListAccountsError {
283 pub fn from_response(res: BufferedHttpResponse) -> RusotoError<ListAccountsError> {
284 if let Some(err) = proto::json::Error::parse_rest(&res) {
285 match err.typ.as_str() {
286 "InvalidRequestException" => {
287 return RusotoError::Service(ListAccountsError::InvalidRequest(err.msg))
288 }
289 "ResourceNotFoundException" => {
290 return RusotoError::Service(ListAccountsError::ResourceNotFound(err.msg))
291 }
292 "TooManyRequestsException" => {
293 return RusotoError::Service(ListAccountsError::TooManyRequests(err.msg))
294 }
295 "UnauthorizedException" => {
296 return RusotoError::Service(ListAccountsError::Unauthorized(err.msg))
297 }
298 "ValidationException" => return RusotoError::Validation(err.msg),
299 _ => {}
300 }
301 }
302 RusotoError::Unknown(res)
303 }
304}
305impl fmt::Display for ListAccountsError {
306 #[allow(unused_variables)]
307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308 match *self {
309 ListAccountsError::InvalidRequest(ref cause) => write!(f, "{}", cause),
310 ListAccountsError::ResourceNotFound(ref cause) => write!(f, "{}", cause),
311 ListAccountsError::TooManyRequests(ref cause) => write!(f, "{}", cause),
312 ListAccountsError::Unauthorized(ref cause) => write!(f, "{}", cause),
313 }
314 }
315}
316impl Error for ListAccountsError {}
317#[derive(Debug, PartialEq)]
319pub enum LogoutError {
320 InvalidRequest(String),
322 TooManyRequests(String),
324 Unauthorized(String),
326}
327
328impl LogoutError {
329 pub fn from_response(res: BufferedHttpResponse) -> RusotoError<LogoutError> {
330 if let Some(err) = proto::json::Error::parse_rest(&res) {
331 match err.typ.as_str() {
332 "InvalidRequestException" => {
333 return RusotoError::Service(LogoutError::InvalidRequest(err.msg))
334 }
335 "TooManyRequestsException" => {
336 return RusotoError::Service(LogoutError::TooManyRequests(err.msg))
337 }
338 "UnauthorizedException" => {
339 return RusotoError::Service(LogoutError::Unauthorized(err.msg))
340 }
341 "ValidationException" => return RusotoError::Validation(err.msg),
342 _ => {}
343 }
344 }
345 RusotoError::Unknown(res)
346 }
347}
348impl fmt::Display for LogoutError {
349 #[allow(unused_variables)]
350 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351 match *self {
352 LogoutError::InvalidRequest(ref cause) => write!(f, "{}", cause),
353 LogoutError::TooManyRequests(ref cause) => write!(f, "{}", cause),
354 LogoutError::Unauthorized(ref cause) => write!(f, "{}", cause),
355 }
356 }
357}
358impl Error for LogoutError {}
359#[async_trait]
361pub trait Sso {
362 async fn get_role_credentials(
364 &self,
365 input: GetRoleCredentialsRequest,
366 ) -> Result<GetRoleCredentialsResponse, RusotoError<GetRoleCredentialsError>>;
367
368 async fn list_account_roles(
370 &self,
371 input: ListAccountRolesRequest,
372 ) -> Result<ListAccountRolesResponse, RusotoError<ListAccountRolesError>>;
373
374 async fn list_accounts(
376 &self,
377 input: ListAccountsRequest,
378 ) -> Result<ListAccountsResponse, RusotoError<ListAccountsError>>;
379
380 async fn logout(&self, input: LogoutRequest) -> Result<(), RusotoError<LogoutError>>;
382}
383#[derive(Clone)]
385pub struct SsoClient {
386 client: Client,
387 region: region::Region,
388}
389
390impl SsoClient {
391 pub fn new(region: region::Region) -> SsoClient {
395 SsoClient {
396 client: Client::shared(),
397 region,
398 }
399 }
400
401 pub fn new_with<P, D>(
402 request_dispatcher: D,
403 credentials_provider: P,
404 region: region::Region,
405 ) -> SsoClient
406 where
407 P: ProvideAwsCredentials + Send + Sync + 'static,
408 D: DispatchSignedRequest + Send + Sync + 'static,
409 {
410 SsoClient {
411 client: Client::new_with(credentials_provider, request_dispatcher),
412 region,
413 }
414 }
415
416 pub fn new_with_client(client: Client, region: region::Region) -> SsoClient {
417 SsoClient { client, region }
418 }
419}
420
421#[async_trait]
422impl Sso for SsoClient {
423 #[allow(unused_mut)]
425 async fn get_role_credentials(
426 &self,
427 input: GetRoleCredentialsRequest,
428 ) -> Result<GetRoleCredentialsResponse, RusotoError<GetRoleCredentialsError>> {
429 let request_uri = "/federation/credentials";
430
431 let mut request = SignedRequest::new("GET", "awsssoportal", &self.region, &request_uri);
432 request.set_content_type("application/x-amz-json-1.1".to_owned());
433
434 request.set_endpoint_prefix("portal.sso".to_string());
435
436 request.add_header("x-amz-sso_bearer_token", &input.access_token.to_string());
437 let mut params = Params::new();
438 params.put("account_id", &input.account_id);
439 params.put("role_name", &input.role_name);
440 request.set_params(params);
441
442 let mut response = self
443 .client
444 .sign_and_dispatch(request)
445 .await
446 .map_err(RusotoError::from)?;
447 if response.status.is_success() {
448 let mut response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
449 let result = proto::json::ResponsePayload::new(&response)
450 .deserialize::<GetRoleCredentialsResponse, _>()?;
451
452 Ok(result)
453 } else {
454 let response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
455 Err(GetRoleCredentialsError::from_response(response))
456 }
457 }
458
459 #[allow(unused_mut)]
461 async fn list_account_roles(
462 &self,
463 input: ListAccountRolesRequest,
464 ) -> Result<ListAccountRolesResponse, RusotoError<ListAccountRolesError>> {
465 let request_uri = "/assignment/roles";
466
467 let mut request = SignedRequest::new("GET", "awsssoportal", &self.region, &request_uri);
468 request.set_content_type("application/x-amz-json-1.1".to_owned());
469
470 request.set_endpoint_prefix("portal.sso".to_string());
471
472 request.add_header("x-amz-sso_bearer_token", &input.access_token.to_string());
473 let mut params = Params::new();
474 params.put("account_id", &input.account_id);
475 if let Some(ref x) = input.max_results {
476 params.put("max_result", x);
477 }
478 if let Some(ref x) = input.next_token {
479 params.put("next_token", x);
480 }
481 request.set_params(params);
482
483 let mut response = self
484 .client
485 .sign_and_dispatch(request)
486 .await
487 .map_err(RusotoError::from)?;
488 if response.status.is_success() {
489 let mut response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
490 let result = proto::json::ResponsePayload::new(&response)
491 .deserialize::<ListAccountRolesResponse, _>()?;
492
493 Ok(result)
494 } else {
495 let response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
496 Err(ListAccountRolesError::from_response(response))
497 }
498 }
499
500 #[allow(unused_mut)]
502 async fn list_accounts(
503 &self,
504 input: ListAccountsRequest,
505 ) -> Result<ListAccountsResponse, RusotoError<ListAccountsError>> {
506 let request_uri = "/assignment/accounts";
507
508 let mut request = SignedRequest::new("GET", "awsssoportal", &self.region, &request_uri);
509 request.set_content_type("application/x-amz-json-1.1".to_owned());
510
511 request.set_endpoint_prefix("portal.sso".to_string());
512
513 request.add_header("x-amz-sso_bearer_token", &input.access_token.to_string());
514 let mut params = Params::new();
515 if let Some(ref x) = input.max_results {
516 params.put("max_result", x);
517 }
518 if let Some(ref x) = input.next_token {
519 params.put("next_token", x);
520 }
521 request.set_params(params);
522
523 let mut response = self
524 .client
525 .sign_and_dispatch(request)
526 .await
527 .map_err(RusotoError::from)?;
528 if response.status.is_success() {
529 let mut response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
530 let result = proto::json::ResponsePayload::new(&response)
531 .deserialize::<ListAccountsResponse, _>()?;
532
533 Ok(result)
534 } else {
535 let response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
536 Err(ListAccountsError::from_response(response))
537 }
538 }
539
540 #[allow(unused_mut)]
542 async fn logout(&self, input: LogoutRequest) -> Result<(), RusotoError<LogoutError>> {
543 let request_uri = "/logout";
544
545 let mut request = SignedRequest::new("POST", "awsssoportal", &self.region, &request_uri);
546 request.set_content_type("application/x-amz-json-1.1".to_owned());
547
548 request.set_endpoint_prefix("portal.sso".to_string());
549
550 request.add_header("x-amz-sso_bearer_token", &input.access_token.to_string());
551
552 let mut response = self
553 .client
554 .sign_and_dispatch(request)
555 .await
556 .map_err(RusotoError::from)?;
557 if response.status.is_success() {
558 let mut response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
559 let result = ::std::mem::drop(response);
560
561 Ok(result)
562 } else {
563 let response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
564 Err(LogoutError::from_response(response))
565 }
566 }
567}