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 #[serde(rename = "RoleArn")]
14 pub role_arn: String,
15
16 #[serde(rename = "RoleSessionName")]
18 pub role_session_name: String,
19
20 #[serde(rename = "Policy", skip_serializing_if = "Option::is_none")]
22 pub policy: Option<Policy>,
23
24 #[serde(rename = "DurationSeconds", skip_serializing_if = "Option::is_none")]
26 pub duration_seconds: Option<i64>,
27
28 #[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 #[serde(rename = "Credentials")]
143 pub credentials: Credentials,
144
145 #[serde(rename = "AssumedRoleUser")]
147 pub assumed_role_user: AssumedRoleUser,
148}
149
150#[derive(Debug, Serialize, Deserialize)]
151pub struct Credentials {
152 #[serde(rename = "AccessKeyId")]
154 pub access_key_id: String,
155
156 #[serde(rename = "AccessKeySecret")]
158 pub access_key_secret: String,
159
160 #[serde(rename = "SecurityToken")]
162 pub security_token: String,
163
164 #[serde(rename = "Expiration")]
166 pub expiration: DateTime<Utc>,
167}
168
169#[derive(Debug, Serialize, Deserialize)]
170pub struct AssumedRoleUser {
171 #[serde(rename = "Arn")]
173 pub arn: String,
174
175 #[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}