rust_aliyun/
sts.rs

1use std::collections::HashMap;
2use std::str::FromStr;
3use chrono::{DateTime, Utc};
4use reqwest::Method;
5use serde::{Deserialize, Serialize};
6use crate::client::{ContentType, Request};
7use crate::error::Error;
8use crate::Result;
9
10#[derive(Debug, Serialize, Deserialize)]
11pub struct AssumeRoleRequest {
12    /// 角色ARN(必须)
13    #[serde(rename = "RoleArn")]
14    pub role_arn: String,
15
16    /// 角色会话名称(必须)
17    #[serde(rename = "RoleSessionName")]
18    pub role_session_name: String,
19
20    /// 自定义策略(可选)
21    #[serde(rename = "Policy", skip_serializing_if = "Option::is_none")]
22    pub policy: Option<Policy>,
23
24    /// 临时凭证有效期(单位:秒,可选,默认3600)
25    #[serde(rename = "DurationSeconds", skip_serializing_if = "Option::is_none")]
26    pub duration_seconds: Option<i64>,
27
28    /// 外部ID(用于跨账号授权,可选)
29    #[serde(rename = "ExternalId", skip_serializing_if = "Option::is_none")]
30    pub external_id: Option<String>,
31}
32
33
34#[derive(Debug, Serialize, Deserialize)]
35pub struct Policy {
36
37    #[serde(rename = "Statement")]
38    pub statements: Vec<Statement>,
39
40    #[serde(rename = "Version")]
41    pub version: Version
42}
43
44impl Policy {
45    pub fn allow(action: Value, resource: Value) -> Self {
46        Policy {
47            statements: vec![
48                Statement {
49                    action,
50                    effect: Effect::Allow,
51                    resource,
52                    condition: None,
53                    principal: None,
54                }
55            ],
56            version: Version::Version1
57        }
58    }
59
60    pub fn deny(action: Value, resource: Value) -> Self {
61        Policy {
62            statements: vec![
63                Statement {
64                    action,
65                    effect: Effect::Deny,
66                    resource,
67                    condition: None,
68                    principal: None,
69                }
70            ],
71            version: Version::Version1
72        }
73    }
74}
75
76#[derive(Debug, Serialize, Deserialize)]
77pub struct Statement {
78
79    #[serde(rename = "Action")]
80    pub action: Value,
81
82    #[serde(rename = "Effect")]
83    pub effect: Effect,
84
85    #[serde(rename = "Resource")]
86    pub resource: Value,
87
88    #[serde(rename = "Condition", skip_serializing_if = "Option::is_none")]
89    pub condition: Option<HashMap<String, Value>>,
90
91    #[serde(rename = "Principal", skip_serializing_if = "Option::is_none")]
92    pub principal: Option<Principal>,
93}
94
95#[derive(Debug, Serialize, Deserialize)]
96pub struct Principal {
97    #[serde(rename = "RAM", skip_serializing_if = "Option::is_none")]
98    pub ram: Option<Value>,
99    #[serde(rename = "Service", skip_serializing_if = "Option::is_none")]
100    pub service: Option<Value>,
101    #[serde(rename = "Federated", skip_serializing_if = "Option::is_none")]
102    pub federated: Option<Value>,
103}
104
105#[derive(Debug, Serialize, Deserialize)]
106#[serde(untagged)]
107pub enum Value {
108    String(String),
109    Array(Vec<String>),
110}
111
112impl FromStr for Value {
113    type Err = Error;
114
115    fn from_str(s: &str) -> Result<Self> {
116        Ok(Value::String(s.to_string()))
117    }
118}
119
120impl <'a> FromIterator<&'a str> for Value {
121    fn from_iter<I: IntoIterator<Item=&'a str>>(iter: I) -> Self {
122        Value::Array(iter.into_iter().map(|s| s.to_string()).collect())
123    }
124}
125
126#[derive(Debug, Serialize, Deserialize)]
127pub enum Effect {
128    #[serde(rename = "Allow")]
129    Allow,
130    #[serde(rename = "Deny")]
131    Deny,
132}
133#[derive(Debug, Serialize, Deserialize)]
134pub enum Version {
135    #[serde(rename = "1")]
136    Version1,
137}
138
139#[derive(Debug, Serialize, Deserialize)]
140pub struct AssumeRoleResponse {
141    /// 临时凭证信息
142    #[serde(rename = "Credentials")]
143    pub credentials: Credentials,
144
145    /// 角色所属账号的阿里云UID
146    #[serde(rename = "AssumedRoleUser")]
147    pub assumed_role_user: AssumedRoleUser,
148}
149
150#[derive(Debug, Serialize, Deserialize)]
151pub struct Credentials {
152    /// 临时AccessKey ID
153    #[serde(rename = "AccessKeyId")]
154    pub access_key_id: String,
155
156    /// 临时AccessKey Secret
157    #[serde(rename = "AccessKeySecret")]
158    pub access_key_secret: String,
159
160    /// 安全令牌(STS Token)
161    #[serde(rename = "SecurityToken")]
162    pub security_token: String,
163
164    /// 过期时间(ISO 8601格式)
165    #[serde(rename = "Expiration")]
166    pub expiration: DateTime<Utc>,
167}
168
169#[derive(Debug, Serialize, Deserialize)]
170pub struct AssumedRoleUser {
171    /// 角色ARN
172    #[serde(rename = "Arn")]
173    pub arn: String,
174
175    /// 角色会话ID
176    #[serde(rename = "AssumedRoleId")]
177    pub assumed_role_id: String,
178}
179
180impl From<AssumeRoleRequest> for Request<AssumeRoleRequest> {
181    fn from(value: AssumeRoleRequest) -> Self {
182        Request {
183            action: "AssumeRole".to_string(),
184            ssl: true,
185            uri: "/".to_string(),
186            headers: None,
187            queries: None,
188            data: Some(value),
189            content_type: ContentType::Json,
190            method: Method::POST,
191            version: "2015-04-01".to_string()
192        }
193    }
194}
195
196mod test {
197    use crate::sts::{AssumeRoleRequest, Policy, Value};
198
199    #[test]
200    fn test_request() {
201        let req = AssumeRoleRequest {
202            role_arn: "acs:ram::123456789012****:role/adminrole".to_string(),
203            role_session_name: "alice".to_string(),
204            policy: Some(Policy::allow(Value::String("*".to_string()), Value::String("*".to_string()))),
205            duration_seconds: None,
206            external_id: Some("abcd1234".to_string()),
207        };
208
209        let request: crate::client::Request<AssumeRoleRequest> = req.into();
210        println!("{:#?}", request);
211    }
212}