I'm playing around with building an app on Zendesk using Rust. Below is a server-side rust function that gets called in a route
pub fn oktaredirectprocessor(mut cookies: Cookies, code: String, state: String) -> bool {
let cookie_state_string = cookies.get_private("state").unwrap().value().to_string();
println!("cookie retrieved in oktaredirectprocessor is {}", cookie_state_string);
if state != cookie_state_string {
debug!("State did not match");
false
}else if code == ""{
debug!("Code is empty");
false
}else{
let oktarequest: Oktarequest = Oktarequest::new();
let http = reqwest::Client::new();
let config = oidc::discovery::discover(&http, oktarequest.issuer).expect("error in config-discovery-oidc");
let jwks = oidc::discovery::jwks(&http, config.jwks_uri.clone()).expect("error in jwks-discovery-oidc");
let provider = oidc::discovery::Discovered(config);
let client = oidc::Client::new(oktarequest.id, oktarequest.secret, oktarequest.redirect, provider, jwks);
let mut token = client.request_token(&http, code.as_str()).expect("error in request token-oidc");
client.decode_token(&mut token.id_token).expect("error in decode token oidc");
client.validate_token(&token.id_token, Some(cookies.get_private("nonce").unwrap().value()), None).expect("error in validate token oidc"); cookies.add_private(Cookie::new("access_token", token.access_token().to_string()));
true
}
}
It works when I run localhost directly from a browser tab. However, the thread panics if I run the app from inside Zendesk. Below is the backtrace. I'm a novice coder and don't understand it entirely.
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:214:60
stack backtrace:
0: rust_begin_unwind
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/std/src/panicking.rs:493:5
1: core::panicking::panic_fmt
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/panicking.rs:92:14
2: core::panicking::panic
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/panicking.rs:50:5
3: core::option::Option<T>::unwrap
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/option.rs:386:21
4: app_remote::oktaredirecthandler
at ./src/main.rs:214:28
5: app_remote::rocket_route_fn_oktaredirecthandler
at ./src/main.rs:213:4
6: core::ops::function::Fn::call
at /rustc/7efc097c4fe6e97f54a44cee91c56189e9ddb41c/library/core/src/ops/function.rs:70:5
7: <F as rocket::handler::Handler>::handle
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/handler.rs:177:9
8: rocket::rocket::Rocket::route
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:296:27
9: rocket::rocket::Rocket::route_and_process
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:242:34
10: rocket::rocket::Rocket::dispatch
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:217:28
11: <rocket::rocket::Rocket as hyper::server::Handler>::handle
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.5/src/rocket.rs:82:24
12: hyper::server::Worker<H>::keep_alive_loop
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:340:13
13: hyper::server::Worker<H>::handle_connection
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:282:15
14: hyper::server::handle::{{closure}}
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/mod.rs:242:34
15: hyper::server::listener::spawn_with::{{closure}}
at /Users/nalinnarayan/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-0.10.16/src/server/listener.rs:50:31
Weirdly, the problematic "cookies.get_private("state").unwrap()" works in another function even when run inside Zendesk. Below is the function where it works
fn oktalogin(mut cookies: Cookies) -> Redirect {
let oktarequest: Oktarequest = Oktarequest::new();
cookies.add_private(Cookie::new("state", oktarequest.state.clone()));
cookies.add_private(Cookie::new("nonce", oktarequest.nonce.clone()));
println!("stored state cookie from random gen is: {}", cookies.get_private("state").unwrap().value().to_string());
let http = reqwest::Client::new();
let config = oidc::discovery::discover(&http, oktarequest.issuer).expect("error in config-discovery-oidc");
let jwks = oidc::discovery::jwks(&http, config.jwks_uri.clone()).expect("error in jwks-discovery-oidc");
let provider = oidc::discovery::Discovered(config);
let client = oidc::Client::new(oktarequest.id, oktarequest.secret, oktarequest.redirect, provider, jwks);
let options = Options{
scope: Some("openid profile email".to_string()),
state: Some(oktarequest.state.clone()),
nonce: Some(oktarequest.nonce.clone()),
..Default::default()
};
let auth_url = client.auth_url(&options);
Redirect::to(auth_url.into_string())
}
My cargo.toml
[dependencies]
rocket = { version = "0.4.5", features = ["private-cookies"] }
rocket_codegen = "0.4.5"
serde = "1.0.116"
serde_derive = "1.0.116"
diesel = { version = "1.4.5", features = ["postgres"] }
dotenv = "0.15.0"
serde_urlencoded = "0.7.0"
oidc = "0.3.0"
ring = "=0.16.15"
log = "0.4.8"
rand = "0.7.3"
reqwest = "=0.9.24"
inth-oauth2 = "0.16.0"
url = "=1.7.2"
serde_json = "1.0"
console_log = { version = "0.2", features = ["color"] }
[dependencies.rocket_contrib]
version = "*"
default-features = false
features = ["tera_templates", "json"]
Why it worked in localhost was that cookie remained. To work correctly needs to add code when cookie doesn't exist, without
unwrap()
.