Skip to main content

u_sdk/sts/
mod.rs

1//! STS (Security Token Service) client for assuming roles and obtaining temporary security credentials.
2//!
3//! [官方文档](https://help.aliyun.com/zh/ram/developer-reference/api-sts-2015-04-01-assumerole)
4mod error;
5pub mod ram_policy;
6mod types;
7
8pub use error::Error;
9pub use types::*;
10
11use crate::credentials::CredentialsProvider;
12use bon::bon;
13use std::sync::Arc;
14use u_sdk_common::helper::into_header_map;
15use u_sdk_common::open_api_sign::{OpenApiStyle, SignParams, get_openapi_request_header};
16
17//region client
18pub struct Client {
19    credentials_provider: Arc<dyn CredentialsProvider>,
20    http_client: reqwest::Client,
21    host: String,
22    style: OpenApiStyle,
23}
24
25#[bon]
26impl Client {
27    #[builder(on(String, into))]
28    pub fn new(
29        credentials_provider: Arc<dyn CredentialsProvider>,
30        /// 参数host: [host地址](https://help.aliyun.com/zh/ram/developer-reference/api-sts-2015-04-01-endpoint)
31        host: String,
32    ) -> Self {
33        Self {
34            credentials_provider,
35            http_client: reqwest::Client::new(),
36            host,
37            style: OpenApiStyle::RPC,
38        }
39    }
40
41    pub fn assume_role(&self) -> AssumeRoleBuilder<'_> {
42        AssumeRole::builder(self)
43    }
44}
45//endregion
46
47async fn parse_json_response<T: serde::de::DeserializeOwned>(
48    resp: reqwest::Response,
49) -> Result<T, Error> {
50    let status = resp.status();
51    if !status.is_success() {
52        return Err(Error::RequestAPIFailed {
53            status: status.to_string(),
54            text: resp.text().await?,
55        });
56    }
57
58    let bytes = resp.bytes().await?;
59    let data: T = serde_json::from_slice(&bytes).map_err(|e| {
60        Error::Common(format!(
61            "parse response json error: {}, response text: {}",
62            e,
63            String::from_utf8_lossy(&bytes)
64        ))
65    })?;
66
67    Ok(data)
68}
69
70impl AssumeRole<'_> {
71    pub async fn send(&self) -> Result<AssumeRoleResponse, Error> {
72        let client = self.client;
73        let creds = client.credentials_provider.load().await?;
74
75        let sign_params = SignParams {
76            req_method: "GET",
77            host: &client.host,
78            query_map: self,
79            x_acs_action: "AssumeRole",
80            x_acs_version: "2015-04-01",
81            x_acs_security_token: creds.sts_security_token.as_deref(),
82            request_body: None,
83            style: &client.style,
84        };
85
86        let (common_headers, url_) =
87            get_openapi_request_header(&creds.access_key_secret, &creds.access_key_id, sign_params)
88                .map_err(|e| Error::Common(format!("get_openapi_request_header error: {}", e)))?;
89
90        let header_map = into_header_map(common_headers);
91        let resp = client
92            .http_client
93            .get(url_)
94            .headers(header_map)
95            .send()
96            .await?;
97
98        let res = parse_json_response(resp).await?;
99        Ok(res)
100    }
101}