multistore_sts/
request.rs1use multistore::error::ProxyError;
9
10#[derive(Debug, Clone)]
12pub struct StsRequest {
13 pub role_arn: String,
15 pub web_identity_token: String,
17 pub duration_seconds: Option<u64>,
19}
20
21pub fn try_parse_sts_request(query: Option<&str>) -> Option<Result<StsRequest, ProxyError>> {
29 let q = query?;
30 let params: Vec<(String, String)> = url::form_urlencoded::parse(q.as_bytes())
31 .map(|(k, v)| (k.to_string(), v.to_string()))
32 .collect();
33
34 let action = params.iter().find(|(k, _)| k == "Action");
35 match action {
36 Some((_, value)) if value == "AssumeRoleWithWebIdentity" => {}
37 _ => return None,
38 }
39
40 Some(parse_sts_params(¶ms))
41}
42
43pub fn is_get_caller_identity(params: Option<&str>) -> bool {
50 let Some(q) = params else { return false };
51 url::form_urlencoded::parse(q.as_bytes())
52 .any(|(k, v)| k == "Action" && v == "GetCallerIdentity")
53}
54
55fn parse_sts_params(params: &[(String, String)]) -> Result<StsRequest, ProxyError> {
56 let role_arn = params
57 .iter()
58 .find(|(k, _)| k == "RoleArn")
59 .map(|(_, v)| v.clone())
60 .ok_or_else(|| ProxyError::InvalidRequest("missing RoleArn".into()))?;
61
62 let web_identity_token = params
63 .iter()
64 .find(|(k, _)| k == "WebIdentityToken")
65 .map(|(_, v)| v.clone())
66 .ok_or_else(|| ProxyError::InvalidRequest("missing WebIdentityToken".into()))?;
67
68 let duration_seconds = params
69 .iter()
70 .find(|(k, _)| k == "DurationSeconds")
71 .and_then(|(_, v)| v.parse().ok());
72
73 Ok(StsRequest {
74 role_arn,
75 web_identity_token,
76 duration_seconds,
77 })
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_not_sts_request() {
86 assert!(try_parse_sts_request(None).is_none());
87 assert!(try_parse_sts_request(Some("prefix=foo/")).is_none());
88 assert!(try_parse_sts_request(Some("Action=ListBuckets")).is_none());
89 }
90
91 #[test]
92 fn test_valid_sts_request() {
93 let query = "Action=AssumeRoleWithWebIdentity&RoleArn=my-role&WebIdentityToken=tok123";
94 let result = try_parse_sts_request(Some(query)).unwrap().unwrap();
95 assert_eq!(result.role_arn, "my-role");
96 assert_eq!(result.web_identity_token, "tok123");
97 assert_eq!(result.duration_seconds, None);
98 }
99
100 #[test]
101 fn test_sts_request_with_duration() {
102 let query =
103 "Action=AssumeRoleWithWebIdentity&RoleArn=r&WebIdentityToken=t&DurationSeconds=7200";
104 let result = try_parse_sts_request(Some(query)).unwrap().unwrap();
105 assert_eq!(result.duration_seconds, Some(7200));
106 }
107
108 #[test]
109 fn test_missing_role_arn() {
110 let query = "Action=AssumeRoleWithWebIdentity&WebIdentityToken=tok";
111 let result = try_parse_sts_request(Some(query)).unwrap();
112 assert!(result.is_err());
113 }
114
115 #[test]
116 fn test_missing_web_identity_token() {
117 let query = "Action=AssumeRoleWithWebIdentity&RoleArn=role";
118 let result = try_parse_sts_request(Some(query)).unwrap();
119 assert!(result.is_err());
120 }
121
122 #[test]
123 fn test_is_get_caller_identity() {
124 assert!(is_get_caller_identity(Some(
125 "Action=GetCallerIdentity&Version=2011-06-15"
126 )));
127 assert!(is_get_caller_identity(Some(
129 "Version=2011-06-15&Action=GetCallerIdentity"
130 )));
131 assert!(!is_get_caller_identity(Some(
132 "Action=AssumeRoleWithWebIdentity&RoleArn=r&WebIdentityToken=t"
133 )));
134 assert!(!is_get_caller_identity(Some("prefix=foo/")));
135 assert!(!is_get_caller_identity(None));
136 }
137}