From 3f19e7d73c0664e8aa671ecd1271faf666d43bd4 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Thu, 10 Mar 2022 12:59:26 -0800 Subject: [PATCH 1/7] Show sso errors on the last step of the oidc process --- service/OneService.cpp | 94 +++++++++++++++++++++++++----------------- zeroidc/src/lib.rs | 7 ++++ 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index 2f9f9a0b7..8072a764b 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -147,8 +147,47 @@ size_t curlResponseWrite(void *ptr, size_t size, size_t nmemb, std::string *data } #endif + namespace ZeroTier { +const char *ssoResponseTemplate = "\ +\ +\ +\ +\ +





\ +
\ +
\ +
%s
\ +
\ +\ +"; + // Configured networks class NetworkState { @@ -1668,8 +1707,21 @@ public: } #if OIDC_SUPPORTED } else if (ps[0] == "sso") { + char resBuf[4096] = {0}; + const char *error = zeroidc::zeroidc_get_url_param_value("error", path.c_str()); + if (error != nullptr) { + const char *desc = zeroidc::zeroidc_get_url_param_value("error_description", path.c_str()); + scode = 500; + char errBuff[256] = {0}; + sprintf(errBuff, "ERROR %s: %s", error, desc); + sprintf(resBuf, ssoResponseTemplate, errBuff); + responseBody = std::string(resBuf); + responseContentType = "text/html"; + return scode; + } + // SSO redirect handling - const char* state = zeroidc::zeroidc_get_url_param_value("state", path.c_str()); + const char* state = zeroidc::zeroidc_get_url_param_value("state", path.c_str()); const char* nwid = zeroidc::zeroidc_network_id_from_state(state); const uint64_t id = Utils::hexStrToU64(nwid); @@ -1679,43 +1731,9 @@ public: const char* code = zeroidc::zeroidc_get_url_param_value("code", path.c_str()); ns.doTokenExchange(code); scode = 200; - responseBody = "\ -\ -\ -\ -\ -





\ -
\ -
\ -
Authentication Successful. You may now access the network.
\ -
\ -\ -"; + sprintf(resBuf, ssoResponseTemplate, "Authentication Successful. You may now access the network."); + responseBody = std::string(resBuf); + responseContentType = "text/html"; return scode; } else { diff --git a/zeroidc/src/lib.rs b/zeroidc/src/lib.rs index a5db2319f..80c13bb74 100644 --- a/zeroidc/src/lib.rs +++ b/zeroidc/src/lib.rs @@ -325,6 +325,13 @@ impl ZeroIDC { println!("Central post failed: {}", r.status().to_string()); println!("hit url: {}", r.url().as_str()); println!("Status: {}", r.status()); + if let Ok(body) = r.bytes() { + if let Ok(body) = std::str::from_utf8(&body) { + println!("Body: {}", body); + } + + } + (*inner_local.lock().unwrap()).exp_time = 0; (*inner_local.lock().unwrap()).running = false; } From 32f49b44b06315b146e599c3d3c31e8c9cfdd64e Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 15 Mar 2022 09:44:46 -0700 Subject: [PATCH 2/7] Modify snap to use pre-compiled static binaries --- snap/snapcraft.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 46fb373ff..91bd3da74 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -64,13 +64,12 @@ layout: parts: one: - plugin: make - source: . - build-packages: - - build-essential - - libc++-dev - make-parameters: - - CXX=g++ + source: ./ + plugin: dump + organize: + zerotier-one : usr/sbin/zerotier-one + zerotier-cli : usr/sbin/zerotier-cli + zerotier-idtool : usr/sbin/zerotier-idtool filesets: binaries: - usr/sbin/zerotier-one From 2d975f275c01e5df1e8f416a51d01dd75d83d8a2 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 29 Mar 2022 09:11:25 -0700 Subject: [PATCH 3/7] enable rfc3339 timestamps in oidc library for auth0 --- zeroidc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeroidc/Cargo.toml b/zeroidc/Cargo.toml index 9b4449dd2..68fa99488 100644 --- a/zeroidc/Cargo.toml +++ b/zeroidc/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["staticlib","rlib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -openidconnect = { version = "2.2", default-features = false, features = ["reqwest", "native-tls"] } +openidconnect = { version = "2.2", default-features = false, features = ["reqwest", "native-tls", "accept-rfc3339-timestamps"] } base64 = "0.13" url = "2.2" reqwest = "0.11" From 96a49bf47665648df4b987a837d4c37122ed5543 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 29 Mar 2022 09:11:55 -0700 Subject: [PATCH 4/7] auth0 compatibility --- zeroidc/src/lib.rs | 217 +++++++++++++++++---------------------------- 1 file changed, 81 insertions(+), 136 deletions(-) diff --git a/zeroidc/src/lib.rs b/zeroidc/src/lib.rs index 80c13bb74..0f05b86ca 100644 --- a/zeroidc/src/lib.rs +++ b/zeroidc/src/lib.rs @@ -26,6 +26,7 @@ use jwt::{Token}; use openidconnect::core::{CoreClient, CoreProviderMetadata, CoreResponseType}; use openidconnect::reqwest::http_client; use openidconnect::{AccessToken, AccessTokenHash, AuthorizationCode, AuthenticationFlow, ClientId, CsrfToken, IssuerUrl, Nonce, OAuth2TokenResponse, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope, TokenResponse}; +use std::error::Error; use std::str::from_utf8; use std::sync::{Arc, Mutex}; use std::thread::{sleep, spawn, JoinHandle}; @@ -140,6 +141,8 @@ impl ZeroIDC { })), }; + println!("issuer: {}, client_id: {}, auth_endopint: {}, local_web_port: {}", + issuer, client_id, auth_ep, local_web_port); let iss = IssuerUrl::new(issuer.to_string())?; let provider_meta = CoreProviderMetadata::discover(&iss, http_client)?; @@ -155,7 +158,8 @@ impl ZeroIDC { ClientId::new(client_id.to_string()), None, ) - .set_redirect_uri(redirect), + .set_redirect_uri(redirect) + .set_auth_type(openidconnect::AuthType::RequestBody), ); Ok(idc) @@ -187,6 +191,7 @@ impl ZeroIDC { 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 { let should_kick = (*inner_local.lock().unwrap()).kick; if now >= (exp - Duration::from_secs(30)) || should_kick { @@ -197,6 +202,10 @@ impl ZeroIDC { (*inner_local.lock().unwrap()).kick = false; } + #[cfg(debug_assertions)] { + println!("Refresh Token: {}", refresh_token.secret()); + } + let token_response = (*inner_local.lock().unwrap()).oidc_client.as_ref().map(|c| { let res = c.exchange_refresh_token(&refresh_token) .request(http_client); @@ -207,151 +216,82 @@ impl ZeroIDC { if let Some(res) = token_response { match res { Ok(res) => { - - let n = match nonce.clone() { - Some(n) => n, - None => { - println!("err: no nonce"); - continue; - } - }; - - let id = match res.id_token() { - Some(t) => t, - None => { - println!("err: no id_token"); - continue; - } - }; - - // verify & validate claims - let verified = (*inner_local.lock().unwrap()).oidc_client.as_ref().map(|c| { - let claims = match id.claims(&c.id_token_verifier(), &n) { - Ok(c) => c, - Err(e) => { - println!("claims err: {}", e); - return false; - } - }; - - let signing_algo = match id.signing_alg() { - Ok(s) => s, - Err(e) => { - println!("alg err: {}", e); - return false; - } - }; - - if let Some(expected_hash) = claims.access_token_hash() { - let actual_hash = match AccessTokenHash::from_token(res.access_token(), &signing_algo) { - Ok(h) => h, - Err(e) => { - println!("Error hashing access token: {}", e); - return false; - } + match res.id_token() { + Some(id_token) => { + let n = match nonce.clone() { + Some(n) => n.secret().to_string(), + None => "".to_string(), }; - - if actual_hash != *expected_hash { - println!("token hash error"); - return false; + + let params = [("id_token", id_token.to_string()),("state", "refresh".to_string()),("extra_nonce", n)]; + #[cfg(debug_assertions)] { + println!("New ID token: {}", id_token.to_string()); } - } - return true; - }); - - let v = match verified { - Some(verified) => { - if !verified { - println!("not verified."); - (*inner_local.lock().unwrap()).running = false; - false - } else { - true - } - }, - None => { - println!("no verification performed?"); - (*inner_local.lock().unwrap()).running = false; - false - } - }; - - if v { - match res.id_token() { - Some(id_token) => { - let params = [("id_token", id_token.to_string()),("state", "refresh".to_string())]; - #[cfg(debug_assertions)] { - println!("New ID token: {}", id_token.to_string()); - } - let client = reqwest::blocking::Client::new(); - let r = client.post((*inner_local.lock().unwrap()).auth_endpoint.clone()) - .form(¶ms) - .send(); + 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() { - #[cfg(debug_assertions)] { - println!("hit url: {}", r.url().as_str()); - println!("status: {}", r.status()); - } - - let access_token = res.access_token(); - let at = access_token.secret(); - - let t: Result>, jwt::Error>= Token::parse_unverified(at); - - if let Ok(t) = t { - let claims = t.claims().registered.clone(); - match claims.expiration { - Some(exp) => { - (*inner_local.lock().unwrap()).exp_time = exp; - }, - None => { - panic!("expiration is None. This shouldn't happen") - } - } - } - - (*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()); - } - #[cfg(debug_assertions)] { - println!("Central post succeeded"); - } - } else { - println!("Central post failed: {}", r.status().to_string()); + match r { + Ok(r) => { + if r.status().is_success() { + #[cfg(debug_assertions)] { println!("hit url: {}", r.url().as_str()); - println!("Status: {}", r.status()); - if let Ok(body) = r.bytes() { - if let Ok(body) = std::str::from_utf8(&body) { - println!("Body: {}", body); + println!("status: {}", r.status()); + } + + let access_token = res.access_token(); + let at = access_token.secret(); + + let t: Result>, jwt::Error>= Token::parse_unverified(at); + + if let Ok(t) = t { + let claims = t.claims().registered.clone(); + match claims.expiration { + Some(exp) => { + (*inner_local.lock().unwrap()).exp_time = exp; + }, + None => { + panic!("expiration is None. This shouldn't happen") } - + } + } + + (*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()); + } + #[cfg(debug_assertions)] { + println!("Central post succeeded"); + } + } else { + println!("Central post failed: {}", r.status().to_string()); + println!("hit url: {}", r.url().as_str()); + println!("Status: {}", r.status()); + if let Ok(body) = r.bytes() { + if let Ok(body) = std::str::from_utf8(&body) { + println!("Body: {}", body); } - (*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; } + }, + 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; } - }, - None => { - println!("no id token?!?"); } + }, + None => { + println!("no id token?!?"); } - } else { - println!("claims not verified"); } }, Err(e) => { @@ -483,6 +423,8 @@ impl ZeroIDC { let res = (*local.lock().unwrap()).as_opt().map(|i| { if let Some(verifier) = i.pkce_verifier.take() { let token_response = i.oidc_client.as_ref().map(|c| { + println!("auth code: {}", code); + let r = c.exchange_code(AuthorizationCode::new(code.to_string())) .set_pkce_verifier(verifier) .request(http_client); @@ -493,6 +435,7 @@ impl ZeroIDC { let n = match i.nonce.clone() { Some(n) => n, None => { + println!("no noce"); return None; } }; @@ -500,6 +443,7 @@ impl ZeroIDC { let id = match res.id_token() { Some(t) => t, None => { + println!("no id token"); return None; } }; @@ -507,6 +451,7 @@ impl ZeroIDC { let claims = match id.claims(&c.id_token_verifier(), &n) { Ok(c) => c, Err(_e) => { + println!("no claims"); return None; } }; @@ -514,6 +459,7 @@ impl ZeroIDC { let signing_algo = match id.signing_alg() { Ok(s) => s, Err(_) => { + println!("no signing algorithm"); return None; } }; @@ -534,11 +480,10 @@ impl ZeroIDC { } Some(res) }, - Err(_e) => { - #[cfg(debug_assertions)] { - println!("token response error: {}", _e.to_string()); - } - + Err(e) => { + println!("token response error: {:?}", e.to_string()); + println!("\t {:?}", e.source()); + return None; }, } From df3b29e6ff56c89b539f093ad750705904604ac8 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 29 Mar 2022 10:01:02 -0700 Subject: [PATCH 5/7] get exp time out of correct token --- zeroidc/src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/zeroidc/src/lib.rs b/zeroidc/src/lib.rs index 0f05b86ca..2efaef7fc 100644 --- a/zeroidc/src/lib.rs +++ b/zeroidc/src/lib.rs @@ -203,6 +203,7 @@ impl ZeroIDC { } #[cfg(debug_assertions)] { + println!("now: {:?}\nexp: {:?}", now, exp); println!("Refresh Token: {}", refresh_token.secret()); } @@ -519,15 +520,17 @@ impl ZeroIDC { println!("Status: {}", res.status()); } - let at = tok.access_token().secret(); + let idt = &id_token.to_string(); - let t: Result>, jwt::Error>= Token::parse_unverified(at); + let t: Result>, jwt::Error>= + Token::parse_unverified(idt); if let Ok(t) = t { let claims = t.claims().registered.clone(); match claims.expiration { Some(exp) => { i.exp_time = exp; + println!("Set exp time to: {:?}", i.exp_time); }, None => { panic!("expiration is None. This shouldn't happen") From 425f5201a234d2931a70b3a8a819095c9e141688 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 29 Mar 2022 10:03:34 -0700 Subject: [PATCH 6/7] remove extraneous debug log line --- zeroidc/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zeroidc/src/lib.rs b/zeroidc/src/lib.rs index 2efaef7fc..2a1e423d0 100644 --- a/zeroidc/src/lib.rs +++ b/zeroidc/src/lib.rs @@ -203,7 +203,6 @@ impl ZeroIDC { } #[cfg(debug_assertions)] { - println!("now: {:?}\nexp: {:?}", now, exp); println!("Refresh Token: {}", refresh_token.secret()); } From 3670b8cefd94342c228fee501b966e440fcca7f0 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 29 Mar 2022 10:33:27 -0700 Subject: [PATCH 7/7] another at->idt for exp --- zeroidc/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zeroidc/src/lib.rs b/zeroidc/src/lib.rs index 2a1e423d0..76bccc9e3 100644 --- a/zeroidc/src/lib.rs +++ b/zeroidc/src/lib.rs @@ -241,9 +241,10 @@ impl ZeroIDC { } let access_token = res.access_token(); - let at = access_token.secret(); + let idt = &id_token.to_string(); - let t: Result>, jwt::Error>= Token::parse_unverified(at); + let t: Result>, jwt::Error> = + Token::parse_unverified(idt); if let Ok(t) = t { let claims = t.claims().registered.clone();