|
|
|
|
@ -2,11 +2,13 @@ pub mod ext;
|
|
|
|
|
|
|
|
|
|
extern crate base64; |
|
|
|
|
extern crate openidconnect; |
|
|
|
|
extern crate time; |
|
|
|
|
extern crate url; |
|
|
|
|
|
|
|
|
|
use std::time::{SystemTime, UNIX_EPOCH, Duration}; |
|
|
|
|
use time::{OffsetDateTime, format_description}; |
|
|
|
|
use std::sync::{Arc, Mutex}; |
|
|
|
|
use std::thread::{sleep, spawn, JoinHandle}; |
|
|
|
|
use std::time::Duration; |
|
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
use openidconnect::core::{CoreClient, CoreProviderMetadata, CoreResponseType}; |
|
|
|
|
use openidconnect::reqwest::http_client; |
|
|
|
|
@ -50,6 +52,23 @@ pub struct AuthInfo {
|
|
|
|
|
pkce_verifier: Option<PkceCodeVerifier>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn systemtime_strftime<T>(dt: T, format: &str) -> String |
|
|
|
|
where T: Into<OffsetDateTime> |
|
|
|
|
{ |
|
|
|
|
let f = format_description::parse(format); |
|
|
|
|
match f { |
|
|
|
|
Ok(f) => { |
|
|
|
|
match dt.into().format(&f) { |
|
|
|
|
Ok(s) => s, |
|
|
|
|
Err(_e) => "".to_string(), |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
Err(_e) => { |
|
|
|
|
"".to_string() |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl ZeroIDC { |
|
|
|
|
fn new( |
|
|
|
|
network_id: &str, |
|
|
|
|
@ -124,10 +143,84 @@ impl ZeroIDC {
|
|
|
|
|
let inner_local = Arc::clone(&self.inner); |
|
|
|
|
(*local.lock().unwrap()).oidc_thread = Some(spawn(move || { |
|
|
|
|
(*inner_local.lock().unwrap()).running = true; |
|
|
|
|
let mut running = true; |
|
|
|
|
|
|
|
|
|
while running { |
|
|
|
|
let exp = UNIX_EPOCH + Duration::from_secs((*inner_local.lock().unwrap()).exp_time); |
|
|
|
|
let now = SystemTime::now(); |
|
|
|
|
|
|
|
|
|
println!("refresh token thread tick, now: {}, exp: {}", systemtime_strftime(now, "[year]-[month]-[day] [hour]:[minute]:[second]"), systemtime_strftime(exp, "[year]-[month]-[day] [hour]:[minute]:[second]")); |
|
|
|
|
let refresh_token = (*inner_local.lock().unwrap()).refresh_token.clone(); |
|
|
|
|
if let Some(refresh_token) = refresh_token { |
|
|
|
|
if now >= (exp - Duration::from_secs(15)) { |
|
|
|
|
let token_response = (*inner_local.lock().unwrap()).oidc_client.as_ref().map(|c| { |
|
|
|
|
let res = c.exchange_refresh_token(&refresh_token) |
|
|
|
|
.request(http_client); |
|
|
|
|
|
|
|
|
|
res |
|
|
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if let Some(res) = token_response { |
|
|
|
|
if let Ok(res) = res { |
|
|
|
|
let id_token = res.id_token(); |
|
|
|
|
|
|
|
|
|
if let Some(id_token) = id_token { |
|
|
|
|
let params = [("id_token", id_token.to_string()),("state", "refresh".to_string())]; |
|
|
|
|
let client = reqwest::blocking::Client::new(); |
|
|
|
|
let r = client.post((*inner_local.lock().unwrap()).auth_endpoint.clone()) |
|
|
|
|
.form(¶ms) |
|
|
|
|
.send(); |
|
|
|
|
|
|
|
|
|
match r { |
|
|
|
|
Ok(r) => { |
|
|
|
|
if r.status().is_success() { |
|
|
|
|
println!("hit url: {}", r.url().as_str()); |
|
|
|
|
println!("status: {}", r.status()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let access_token = res.access_token(); |
|
|
|
|
let at = access_token.secret(); |
|
|
|
|
let exp = dangerous_insecure_decode::<Exp>(&at); |
|
|
|
|
|
|
|
|
|
if let Ok(e) = exp { |
|
|
|
|
(*inner_local.lock().unwrap()).exp_time = e.claims.exp |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
(*inner_local.lock().unwrap()).access_token = Some(access_token.clone()); |
|
|
|
|
if let Some(t) = res.refresh_token() { |
|
|
|
|
println!("New Refresh Token: {}", t.secret()); |
|
|
|
|
(*inner_local.lock().unwrap()).refresh_token = Some(t.clone()); |
|
|
|
|
} |
|
|
|
|
println!("Central post succeeded"); |
|
|
|
|
} else { |
|
|
|
|
println!("Central post failed: {}", r.status().to_string()); |
|
|
|
|
println!("hit url: {}", r.url().as_str()); |
|
|
|
|
println!("Status: {}", r.status()); |
|
|
|
|
(*inner_local.lock().unwrap()).exp_time = 0; |
|
|
|
|
(*inner_local.lock().unwrap()).running = false; |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
Err(e) => { |
|
|
|
|
println!("Central post failed: {}", e.to_string()); |
|
|
|
|
println!("hit url: {}", e.url().unwrap().as_str()); |
|
|
|
|
println!("Status: {}", e.status().unwrap()); |
|
|
|
|
// (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
|
|
(*inner_local.lock().unwrap()).running = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
} else { |
|
|
|
|
println!("waiting to refresh"); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
println!("no refresh token?"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (*inner_local.lock().unwrap()).running { |
|
|
|
|
println!("tick"); |
|
|
|
|
sleep(Duration::from_secs(1)); |
|
|
|
|
running = (*inner_local.lock().unwrap()).running; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
println!("thread done!") |
|
|
|
|
@ -207,12 +300,14 @@ impl ZeroIDC {
|
|
|
|
|
(*self.inner.lock().unwrap()).access_token = Some(tok.access_token().clone()); |
|
|
|
|
if let Some(t) = tok.refresh_token() { |
|
|
|
|
(*self.inner.lock().unwrap()).refresh_token = Some(t.clone()); |
|
|
|
|
self.start(); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
Err(res) => { |
|
|
|
|
println!("hit url: {}", res.url().unwrap().as_str()); |
|
|
|
|
println!("Status: {}", res.status().unwrap()); |
|
|
|
|
println!("Post error: {}", res.to_string()); |
|
|
|
|
(*self.inner.lock().unwrap()).exp_time = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -246,7 +341,7 @@ impl ZeroIDC {
|
|
|
|
|
.add_extra_param("network_id", network_id) |
|
|
|
|
.url(); |
|
|
|
|
|
|
|
|
|
println!("URL: {}", auth_url); |
|
|
|
|
// println!("URL: {}", auth_url);
|
|
|
|
|
|
|
|
|
|
return AuthInfo { |
|
|
|
|
url: auth_url, |
|
|
|
|
|