1use serde::{Deserialize, Serialize};
2use std::time::SystemTime;
3use url::Url;
4
5use crate::internals;
6use crate::Auth as AuthTrait;
7use crate::Error;
8
9#[derive(Clone, Serialize)]
11pub struct ApproleLogin {
12 pub role_id: String,
14 pub secret_id: String,
16}
17
18#[allow(dead_code)]
19#[derive(Deserialize)]
20struct Auth {
21 pub renewable: bool,
23 pub lease_duration: u64,
25 pub token_policies: Vec<String>,
27 pub accessor: String,
29 pub client_token: String,
32}
33
34#[allow(dead_code)]
35#[derive(Deserialize)]
36struct ApproleResponse {
37 pub auth: Auth,
39 pub lease_duration: i64,
41 pub renewable: bool,
43 pub lease_id: String,
45}
46
47#[derive(Deserialize)]
48struct RenewAuth {
49 pub renewable: bool,
51 pub lease_duration: u64,
53 pub policies: Vec<String>,
55 pub client_token: String,
58}
59
60#[derive(Deserialize)]
61struct RenewResponse {
62 pub auth: RenewAuth,
64}
65
66pub struct Session {
69 approle: ApproleLogin,
70
71 token: internals::TokenContainer,
72}
73
74impl AuthTrait for Session {
75 fn is_expired(&self) -> bool {
76 let start_time = self.token.get_start();
77 let current_time = SystemTime::now()
78 .duration_since(SystemTime::UNIX_EPOCH)
79 .unwrap()
80 .as_secs();
81
82 let elapsed = current_time - start_time;
83 let duration = self.token.get_duration();
84
85 elapsed >= duration
86 }
87 fn get_token(&self) -> String {
88 match self.token.get_token() {
95 None => String::from(""),
96 Some(s) => s,
97 }
98 }
99 fn auth(&self, vault_url: &str) -> Result<(), Error> {
100 let mut login_url = match Url::parse(vault_url) {
101 Err(e) => {
102 return Err(Error::from(e));
103 }
104 Ok(url) => url,
105 };
106 login_url = match login_url.join("v1/auth/approle/login") {
107 Err(e) => {
108 return Err(Error::from(e));
109 }
110 Ok(u) => u,
111 };
112
113 let http_client = reqwest::blocking::Client::new();
114 let res = http_client.post(login_url).json(&self.approle).send();
115
116 let response = match res {
117 Err(e) => {
118 return Err(Error::from(e));
119 }
120 Ok(resp) => resp,
121 };
122
123 let status_code = response.status().as_u16();
124 if status_code != 200 && status_code != 204 {
125 return Err(Error::from(status_code));
126 }
127
128 let data = match response.json::<ApproleResponse>() {
129 Err(e) => Err(Error::from(e)),
130 Ok(json) => Ok(json),
131 };
132
133 let data = data.unwrap();
134
135 let token = data.auth.client_token;
136 let current_time = SystemTime::now()
137 .duration_since(SystemTime::UNIX_EPOCH)
138 .unwrap()
139 .as_secs();
140 let duration = data.auth.lease_duration;
141
142 self.token.set_token(token);
146
147 self.token.set_renewable(data.auth.renewable);
148
149 self.token.set_start(current_time);
154 self.token.set_duration(duration);
155
156 Ok(())
157 }
158
159 fn is_renewable(&self) -> bool {
160 self.token.get_renewable()
161 }
162
163 fn get_total_duration(&self) -> u64 {
164 self.token.get_duration()
165 }
166
167 fn renew(&self, vault_url: &str) -> Result<(), Error> {
168 let mut renew_url = match Url::parse(vault_url) {
169 Err(e) => {
170 return Err(Error::from(e));
171 }
172 Ok(url) => url,
173 };
174 renew_url = match renew_url.join("v1/auth/token/renew-self") {
175 Err(e) => {
176 return Err(Error::from(e));
177 }
178 Ok(u) => u,
179 };
180
181 let http_client = reqwest::blocking::Client::new();
182 let res = http_client
183 .post(renew_url)
184 .header("X-Vault-Token", self.token.get_token().unwrap())
185 .send();
186
187 let response = match res {
188 Err(e) => {
189 return Err(Error::from(e));
190 }
191 Ok(resp) => resp,
192 };
193
194 let status_code = response.status().as_u16();
195 if status_code != 200 && status_code != 204 {
196 return Err(Error::from(status_code));
197 }
198
199 let data = match response.json::<RenewResponse>() {
200 Err(e) => Err(Error::from(e)),
201 Ok(json) => Ok(json),
202 };
203
204 let data = data.unwrap();
205
206 let current_time = SystemTime::now()
207 .duration_since(SystemTime::UNIX_EPOCH)
208 .unwrap()
209 .as_secs();
210 let duration = data.auth.lease_duration;
211 let renewable = data.auth.renewable;
212
213 self.token.set_renewable(renewable);
214
215 self.token.set_start(current_time);
217 self.token.set_duration(duration);
218
219 Ok(())
220 }
221}
222
223impl Session {
224 pub fn new(role_id: String, secret_id: String) -> Result<Session, Error> {
227 let approle = ApproleLogin { role_id, secret_id };
228
229 Ok(Session {
230 approle,
231 token: internals::TokenContainer::new(),
232 })
233 }
234}