|
@@ -59,7 +59,9 @@ pub struct ZeroIDC {
|
|
|
))]
|
|
|
struct Inner {
|
|
|
running: bool,
|
|
|
+ issuer: String,
|
|
|
auth_endpoint: String,
|
|
|
+ provider: String,
|
|
|
oidc_thread: Option<JoinHandle<()>>,
|
|
|
oidc_client: Option<openidconnect::core::CoreClient>,
|
|
|
access_token: Option<AccessToken>,
|
|
@@ -114,12 +116,15 @@ impl ZeroIDC {
|
|
|
pub fn new(
|
|
|
issuer: &str,
|
|
|
client_id: &str,
|
|
|
+ provider: &str,
|
|
|
auth_ep: &str,
|
|
|
local_web_port: u16,
|
|
|
) -> Result<ZeroIDC, ZeroIDCError> {
|
|
|
let idc = ZeroIDC {
|
|
|
inner: Arc::new(Mutex::new(Inner {
|
|
|
running: false,
|
|
|
+ issuer: issuer.to_string(),
|
|
|
+ provider: provider.to_string(),
|
|
|
auth_endpoint: auth_ep.to_string(),
|
|
|
oidc_thread: None,
|
|
|
oidc_client: None,
|
|
@@ -148,7 +153,7 @@ impl ZeroIDC {
|
|
|
|
|
|
let redirect = RedirectUrl::new(redir_url.to_string())?;
|
|
|
|
|
|
- (*idc.inner.lock().unwrap()).oidc_client = Some(
|
|
|
+ idc.inner.lock().unwrap().oidc_client = Some(
|
|
|
CoreClient::from_provider_metadata(
|
|
|
provider_meta,
|
|
|
ClientId::new(client_id.to_string()),
|
|
@@ -163,25 +168,25 @@ impl ZeroIDC {
|
|
|
|
|
|
fn kick_refresh_thread(&mut self) {
|
|
|
let local = Arc::clone(&self.inner);
|
|
|
- (*local.lock().unwrap()).kick = true;
|
|
|
+ local.lock().unwrap().kick = true;
|
|
|
}
|
|
|
|
|
|
fn start(&mut self) {
|
|
|
let local = Arc::clone(&self.inner);
|
|
|
|
|
|
- if !(*local.lock().unwrap()).running {
|
|
|
+ if !local.lock().unwrap().running {
|
|
|
let inner_local = Arc::clone(&self.inner);
|
|
|
- (*local.lock().unwrap()).oidc_thread = Some(spawn(move || {
|
|
|
- (*inner_local.lock().unwrap()).running = true;
|
|
|
+ local.lock().unwrap().oidc_thread = Some(spawn(move || {
|
|
|
+ inner_local.lock().unwrap().running = true;
|
|
|
let mut running = true;
|
|
|
|
|
|
// Keep a copy of the initial nonce used to get the tokens
|
|
|
// Will be needed later when verifying the responses from refresh tokens
|
|
|
- let nonce = (*inner_local.lock().unwrap()).nonce.clone();
|
|
|
+ let nonce = inner_local.lock().unwrap().nonce.clone();
|
|
|
|
|
|
while running {
|
|
|
let exp =
|
|
|
- UNIX_EPOCH + Duration::from_secs((*inner_local.lock().unwrap()).exp_time);
|
|
|
+ UNIX_EPOCH + Duration::from_secs(inner_local.lock().unwrap().exp_time);
|
|
|
let now = SystemTime::now();
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
@@ -198,17 +203,17 @@ impl ZeroIDC {
|
|
|
)
|
|
|
);
|
|
|
}
|
|
|
- let refresh_token = (*inner_local.lock().unwrap()).refresh_token.clone();
|
|
|
+ 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;
|
|
|
+ let should_kick = inner_local.lock().unwrap().kick;
|
|
|
if now >= (exp - Duration::from_secs(30)) || should_kick {
|
|
|
if should_kick {
|
|
|
#[cfg(debug_assertions)]
|
|
|
{
|
|
|
println!("refresh thread kicked");
|
|
|
}
|
|
|
- (*inner_local.lock().unwrap()).kick = false;
|
|
|
+ inner_local.lock().unwrap().kick = false;
|
|
|
}
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
@@ -216,10 +221,8 @@ impl ZeroIDC {
|
|
|
println!("Refresh Token: {}", refresh_token.secret());
|
|
|
}
|
|
|
|
|
|
- let token_response = (*inner_local.lock().unwrap())
|
|
|
- .oidc_client
|
|
|
- .as_ref()
|
|
|
- .map(|c| {
|
|
|
+ let token_response =
|
|
|
+ inner_local.lock().unwrap().oidc_client.as_ref().map(|c| {
|
|
|
let res = c
|
|
|
.exchange_refresh_token(&refresh_token)
|
|
|
.request(http_client);
|
|
@@ -252,7 +255,9 @@ impl ZeroIDC {
|
|
|
let client = reqwest::blocking::Client::new();
|
|
|
let r = client
|
|
|
.post(
|
|
|
- (*inner_local.lock().unwrap())
|
|
|
+ inner_local
|
|
|
+ .lock()
|
|
|
+ .unwrap()
|
|
|
.auth_endpoint
|
|
|
.clone(),
|
|
|
)
|
|
@@ -289,10 +294,10 @@ impl ZeroIDC {
|
|
|
match claims.expiration {
|
|
|
Some(exp) => {
|
|
|
println!("exp: {}", exp);
|
|
|
- (*inner_local
|
|
|
+ inner_local
|
|
|
.lock()
|
|
|
- .unwrap())
|
|
|
- .exp_time = exp;
|
|
|
+ .unwrap()
|
|
|
+ .exp_time = exp;
|
|
|
}
|
|
|
None => {
|
|
|
panic!("expiration is None. This shouldn't happen")
|
|
@@ -302,12 +307,16 @@ impl ZeroIDC {
|
|
|
panic!("error parsing claims");
|
|
|
}
|
|
|
|
|
|
- (*inner_local.lock().unwrap())
|
|
|
+ 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())
|
|
|
+ inner_local
|
|
|
+ .lock()
|
|
|
+ .unwrap()
|
|
|
.refresh_token =
|
|
|
Some(t.clone());
|
|
|
}
|
|
@@ -333,10 +342,10 @@ impl ZeroIDC {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- (*inner_local.lock().unwrap())
|
|
|
- .exp_time = 0;
|
|
|
- (*inner_local.lock().unwrap())
|
|
|
- .running = false;
|
|
|
+ inner_local.lock().unwrap().exp_time =
|
|
|
+ 0;
|
|
|
+ inner_local.lock().unwrap().running =
|
|
|
+ false;
|
|
|
}
|
|
|
}
|
|
|
Err(e) => {
|
|
@@ -346,29 +355,28 @@ impl ZeroIDC {
|
|
|
e.url().unwrap().as_str()
|
|
|
);
|
|
|
println!("Status: {}", e.status().unwrap());
|
|
|
- (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
- (*inner_local.lock().unwrap()).running =
|
|
|
- false;
|
|
|
+ inner_local.lock().unwrap().exp_time = 0;
|
|
|
+ inner_local.lock().unwrap().running = false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
None => {
|
|
|
println!("no id token?!?");
|
|
|
- (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
- (*inner_local.lock().unwrap()).running = false;
|
|
|
+ inner_local.lock().unwrap().exp_time = 0;
|
|
|
+ inner_local.lock().unwrap().running = false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
Err(e) => {
|
|
|
println!("token error: {}", e);
|
|
|
- (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
- (*inner_local.lock().unwrap()).running = false;
|
|
|
+ inner_local.lock().unwrap().exp_time = 0;
|
|
|
+ inner_local.lock().unwrap().running = false;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
println!("token response??");
|
|
|
- (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
- (*inner_local.lock().unwrap()).running = false;
|
|
|
+ inner_local.lock().unwrap().exp_time = 0;
|
|
|
+ inner_local.lock().unwrap().running = false;
|
|
|
}
|
|
|
} else {
|
|
|
#[cfg(debug_assertions)]
|
|
@@ -376,19 +384,19 @@ impl ZeroIDC {
|
|
|
}
|
|
|
} else {
|
|
|
println!("no refresh token?");
|
|
|
- (*inner_local.lock().unwrap()).exp_time = 0;
|
|
|
- (*inner_local.lock().unwrap()).running = false;
|
|
|
+ inner_local.lock().unwrap().exp_time = 0;
|
|
|
+ inner_local.lock().unwrap().running = false;
|
|
|
}
|
|
|
|
|
|
sleep(Duration::from_secs(1));
|
|
|
{
|
|
|
- running = (*inner_local.lock().unwrap()).running;
|
|
|
+ running = inner_local.lock().unwrap().running;
|
|
|
}
|
|
|
}
|
|
|
// end run loop
|
|
|
|
|
|
println!("thread done!");
|
|
|
- (*inner_local.lock().unwrap()).running = false;
|
|
|
+ inner_local.lock().unwrap().running = false;
|
|
|
println!("set idc thread running flag to false");
|
|
|
}));
|
|
|
}
|
|
@@ -397,19 +405,19 @@ impl ZeroIDC {
|
|
|
pub fn stop(&mut self) {
|
|
|
let local = self.inner.clone();
|
|
|
if self.is_running() {
|
|
|
- (*local.lock().unwrap()).running = false;
|
|
|
+ local.lock().unwrap().running = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pub fn is_running(&mut self) -> bool {
|
|
|
let local = Arc::clone(&self.inner);
|
|
|
- let running = (*local.lock().unwrap()).running;
|
|
|
+ let running = local.lock().unwrap().running;
|
|
|
|
|
|
running
|
|
|
}
|
|
|
|
|
|
pub fn get_exp_time(&mut self) -> u64 {
|
|
|
- return (*self.inner.lock().unwrap()).exp_time;
|
|
|
+ return self.inner.lock().unwrap().exp_time;
|
|
|
}
|
|
|
|
|
|
pub fn set_nonce_and_csrf(&mut self, csrf_token: String, nonce: String) {
|
|
@@ -439,20 +447,53 @@ impl ZeroIDC {
|
|
|
if need_verifier || csrf_diff || nonce_diff {
|
|
|
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
|
|
|
let r = i.oidc_client.as_ref().map(|c| {
|
|
|
- let (auth_url, csrf_token, nonce) = c
|
|
|
+ let mut auth_builder = c
|
|
|
.authorize_url(
|
|
|
AuthenticationFlow::<CoreResponseType>::AuthorizationCode,
|
|
|
csrf_func(csrf_token),
|
|
|
nonce_func(nonce),
|
|
|
)
|
|
|
- .add_scope(Scope::new("profile".to_string()))
|
|
|
- .add_scope(Scope::new("email".to_string()))
|
|
|
- .add_scope(Scope::new("offline_access".to_string()))
|
|
|
- .add_scope(Scope::new("openid".to_string()))
|
|
|
- .set_pkce_challenge(pkce_challenge)
|
|
|
- .url();
|
|
|
-
|
|
|
- (auth_url, csrf_token, nonce)
|
|
|
+ .set_pkce_challenge(pkce_challenge);
|
|
|
+ match i.provider.as_str() {
|
|
|
+ "auth0" => {
|
|
|
+ auth_builder = auth_builder
|
|
|
+ .add_scope(Scope::new("profile".to_string()))
|
|
|
+ .add_scope(Scope::new("email".to_string()))
|
|
|
+ .add_scope(Scope::new("offline_access".to_string()));
|
|
|
+ }
|
|
|
+ "okta" => {
|
|
|
+ auth_builder = auth_builder
|
|
|
+ .add_scope(Scope::new("profile".to_string()))
|
|
|
+ .add_scope(Scope::new("email".to_string()))
|
|
|
+ .add_scope(Scope::new("groups".to_string()))
|
|
|
+ .add_scope(Scope::new("offline_access".to_string()));
|
|
|
+ }
|
|
|
+ "keycloak" => {
|
|
|
+ auth_builder = auth_builder
|
|
|
+ .add_scope(Scope::new("profile".to_string()))
|
|
|
+ .add_scope(Scope::new("email".to_string()));
|
|
|
+ }
|
|
|
+ "onelogin" => {
|
|
|
+ auth_builder = auth_builder
|
|
|
+ .add_scope(Scope::new("profile".to_string()))
|
|
|
+ .add_scope(Scope::new("email".to_string()))
|
|
|
+ .add_scope(Scope::new("groups".to_string()))
|
|
|
+ }
|
|
|
+ "default" => {
|
|
|
+ auth_builder = auth_builder
|
|
|
+ .add_scope(Scope::new("profile".to_string()))
|
|
|
+ .add_scope(Scope::new("email".to_string()))
|
|
|
+ .add_scope(Scope::new("offline_access".to_string()));
|
|
|
+ }
|
|
|
+ _ => {
|
|
|
+ auth_builder = auth_builder
|
|
|
+ .add_scope(Scope::new("profile".to_string()))
|
|
|
+ .add_scope(Scope::new("email".to_string()))
|
|
|
+ .add_scope(Scope::new("offline_access".to_string()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ auth_builder.url()
|
|
|
});
|
|
|
|
|
|
if let Some(r) = r {
|
|
@@ -653,8 +694,7 @@ impl ZeroIDC {
|
|
|
}
|
|
|
Err(res) => {
|
|
|
println!("error result: {}", res);
|
|
|
- println!("hit url: {}", res.url().unwrap().as_str());
|
|
|
- println!("Status: {}", res.status().unwrap());
|
|
|
+ println!("hit url: {}", i.auth_endpoint.clone());
|
|
|
println!("Post error: {}", res);
|
|
|
i.exp_time = 0;
|
|
|
i.running = false;
|