1use models::{AuthResponse, Claims, ServiceAccountKey, ServiceCredentialsInput};
2use reqwest::blocking::Client;
3use std::{fs, time::{SystemTime, UNIX_EPOCH}};
4use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
5
6mod models;
7
8fn create_jwt(key: &ServiceAccountKey, scopes: Vec<String>) -> String {
9 let iat = SystemTime::now()
10 .duration_since(UNIX_EPOCH)
11 .expect("Time went backwards")
12 .as_secs() as usize;
13 let exp = iat + 3600;
14
15 let scopes = {
16 let count = scopes.iter().count();
17 if count > 1 {
18 let mut scopes_string = scopes.iter().take(count - 1).map(|x| x.to_string() + ",").collect::<String>();
19 scopes_string.push_str(&scopes[count - 1]);
20 scopes_string
21 }
22 else {
23 let scope = scopes[0].clone();
24 drop(scopes);
25 scope
26 }
27 };
28
29 let claims = Claims {
30 iss: key.client_email.clone(),
31 scope: scopes,
32 aud: key.token_uri.clone(),
33 exp,
34 iat,
35 };
36
37 let encoding_key = EncodingKey::from_rsa_pem(key.private_key.as_bytes()).expect("Invalid RSA Key");
38 encode(&Header::new(Algorithm::RS256), &claims, &encoding_key).expect("JWT Encoding failed")
39}
40
41fn get_access_token(key: &ServiceAccountKey, scopes: Vec<String>) -> AuthResponse {
42 let jwt = create_jwt(key, scopes);
43
44 let params = format!("grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={}",jwt);
45
46 let client = Client::new();
47
48 let res = client.post(format!("https://oauth2.googleapis.com/token"))
49 .header("content-type", "application/x-www-form-urlencoded")
50 .body(params)
51 .send()
52 .expect("Failed to get access token");
53
54 let content = res.text();
55
56 let token_response: AuthResponse = serde_json::from_str(
57 &content.expect("Failed to get text out of response.")
58 ).expect("Failed to parse token response");
59 token_response
60}
61
62pub struct AuthenticationHandler {
99 service_credentials: ServiceAccountKey
100}
101
102impl AuthenticationHandler {
103 pub fn new(creds: ServiceCredentialsInput) -> AuthenticationHandler {
105 match creds {
106 ServiceCredentialsInput::PathBuf(creds) => {
107 let key_data = fs::read_to_string(creds)
108 .expect("Failed to read service account key file");
109 let service_account_key: ServiceAccountKey = serde_json::from_str(&key_data)
110 .expect("Failed to parse service account key");
111 AuthenticationHandler {
112 service_credentials: service_account_key
113 }
114 },
115 ServiceCredentialsInput::String(creds) => {
116 let service_account_key: ServiceAccountKey = serde_json::from_str(&creds)
117 .expect("Failed to parse service account key");
118 AuthenticationHandler {
119 service_credentials: service_account_key
120 }
121 }
122 }
123 }
124
125 pub fn get_access_token_model(&self, scopes: Vec<String>) -> AuthResponse {
127 let token = get_access_token(&self.service_credentials, scopes);
128 token
129 }
130}