ソースを参照

refresh token run loop

Need central-side work to complete
Grant Limberg 3 年 前
コミット
1192b1b422
6 ファイル変更135 行追加29 行削除
  1. 0 1
      node/NetworkConfig.cpp
  2. 8 8
      service/OneService.cpp
  3. 12 1
      zeroidc/Cargo.lock
  4. 1 0
      zeroidc/Cargo.toml
  5. 15 15
      zeroidc/src/ext.rs
  6. 99 4
      zeroidc/src/lib.rs

+ 0 - 1
node/NetworkConfig.cpp

@@ -411,7 +411,6 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
 					}
 					if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL, (unsigned int)sizeof(this->issuerURL)) > 0) {
 						this->issuerURL[sizeof(this->issuerURL) - 1] = 0;
-						fprintf(stderr, "Loaded issuer url: %s\n", this->issuerURL);
 					}
 					if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL, (unsigned int)sizeof(this->centralAuthURL)) > 0) {
 						this->centralAuthURL[sizeof(this->centralAuthURL) - 1] = 0;

+ 8 - 8
service/OneService.cpp

@@ -249,23 +249,23 @@ public:
 	void setConfig(const ZT_VirtualNetworkConfig *nwc) {
 		char nwbuf[17] = {};
 		const char* nwid = Utils::hex(nwc->nwid, nwbuf);
-		fprintf(stderr, "NetworkState::setConfig(%s)\n", nwid);
+		// fprintf(stderr, "NetworkState::setConfig(%s)\n", nwid);
 
 		memcpy(&_config, nwc, sizeof(ZT_VirtualNetworkConfig));
-		fprintf(stderr, "ssoEnabled: %s, ssoVersion: %d\n", 
-			_config.ssoEnabled ? "true" : "false", _config.ssoVersion);
+		// fprintf(stderr, "ssoEnabled: %s, ssoVersion: %d\n", 
+		// 	_config.ssoEnabled ? "true" : "false", _config.ssoVersion);
 
 		if (_config.ssoEnabled && _config.ssoVersion == 1) {
-			fprintf(stderr, "ssoEnabled for %s\n", nwid);
+			//  fprintf(stderr, "ssoEnabled for %s\n", nwid);
 			if (_idc == nullptr)
 			{
 				assert(_config.issuerURL != nullptr);
 				assert(_config.ssoClientID != nullptr);
 				assert(_config.centralAuthURL != nullptr);
 
-				fprintf(stderr, "Issuer URL: %s\n", _config.issuerURL);
-				fprintf(stderr, "Client ID: %s\n", _config.ssoClientID);
-				fprintf(stderr, "Central Auth URL: %s\n", _config.centralAuthURL);
+				// fprintf(stderr, "Issuer URL: %s\n", _config.issuerURL);
+				// fprintf(stderr, "Client ID: %s\n", _config.ssoClientID);
+				// fprintf(stderr, "Central Auth URL: %s\n", _config.centralAuthURL);
 				
 				char buf[17] = {};
 				_idc = zeroidc::zeroidc_new(
@@ -281,7 +281,7 @@ public:
 					return;
 				}
 
-				fprintf(stderr, "idc created (%s, %s, %s)\n", _config.issuerURL, _config.ssoClientID, _config.centralAuthURL);
+				// fprintf(stderr, "idc created (%s, %s, %s)\n", _config.issuerURL, _config.ssoClientID, _config.centralAuthURL);
 			}
 
 			if (_ainfo != nullptr) {

+ 12 - 1
zeroidc/Cargo.lock

@@ -108,7 +108,7 @@ dependencies = [
  "num-integer",
  "num-traits",
  "serde",
- "time",
+ "time 0.1.43",
  "winapi",
 ]
 
@@ -1144,6 +1144,16 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "time"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad"
+dependencies = [
+ "itoa",
+ "libc",
+]
+
 [[package]]
 name = "tinyvec"
 version = "1.5.0"
@@ -1489,5 +1499,6 @@ dependencies = [
  "openidconnect",
  "reqwest",
  "serde",
+ "time 0.3.5",
  "url",
 ]

+ 1 - 0
zeroidc/Cargo.toml

@@ -18,6 +18,7 @@ url = "2.2.2"
 reqwest = "0.11.7"
 jsonwebtoken = "7.2.0"
 serde = "1.0.130"
+time = { version = "0.3.5", features = ["formatting"] }
 
 [build-dependencies]
 cbindgen = "0.20.0"

+ 15 - 15
zeroidc/src/ext.rs

@@ -1,6 +1,6 @@
 use std::ffi::{CStr, CString};
 use std::os::raw::c_char;
-use url::{Url, ParseError};
+use url::{Url};
 
 use crate::{AuthInfo, ZeroIDC};
 
@@ -101,23 +101,23 @@ pub extern "C" fn zeroidc_get_exp_time(ptr: *mut ZeroIDC) -> u64 {
     id.get_exp_time()
 }
 
-#[no_mangle]
-pub extern "C" fn zeroidc_process_form_post(ptr: *mut ZeroIDC, body: *const c_char) -> bool {
-    let idc = unsafe {
-        assert!(!ptr.is_null());
-        &mut *ptr
-    };
+// #[no_mangle]
+// pub extern "C" fn zeroidc_process_form_post(ptr: *mut ZeroIDC, body: *const c_char) -> bool {
+//     let idc = unsafe {
+//         assert!(!ptr.is_null());
+//         &mut *ptr
+//     };
 
-    if body.is_null() {
-        println!("body is null");
-        return false
-    }
+//     if body.is_null() {
+//         println!("body is null");
+//         return false
+//     }
 
-    let body = unsafe { CStr::from_ptr(body) }
-        .to_str().unwrap().to_string();
+//     let body = unsafe { CStr::from_ptr(body) }
+//         .to_str().unwrap().to_string();
 
-    false
-}
+//     false
+// }
 
 #[no_mangle]
 pub extern "C" fn zeroidc_get_auth_info(

+ 99 - 4
zeroidc/src/lib.rs

@@ -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(&params)
+                                            .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,