OIDC example connects, now to fix my kanidm setup
This commit is contained in:
parent
ac4dfca0ac
commit
9d3c7efbba
77
Cargo.lock
generated
77
Cargo.lock
generated
|
@ -1127,20 +1127,6 @@ dependencies = [
|
||||||
"native-tls",
|
"native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hyper-rustls"
|
|
||||||
version = "0.24.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
|
|
||||||
dependencies = [
|
|
||||||
"futures-util",
|
|
||||||
"http 0.2.12",
|
|
||||||
"hyper 0.14.30",
|
|
||||||
"rustls 0.21.12",
|
|
||||||
"tokio",
|
|
||||||
"tokio-rustls 0.24.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.27.2"
|
version = "0.27.2"
|
||||||
|
@ -1151,10 +1137,10 @@ dependencies = [
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"hyper 1.4.1",
|
"hyper 1.4.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.23.12",
|
"rustls",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.26.0",
|
"tokio-rustls",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1634,7 +1620,6 @@ dependencies = [
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"reqwest 0.11.27",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_path_to_error",
|
"serde_path_to_error",
|
||||||
|
@ -2202,7 +2187,6 @@ dependencies = [
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"http-body 0.4.6",
|
"http-body 0.4.6",
|
||||||
"hyper 0.14.30",
|
"hyper 0.14.30",
|
||||||
"hyper-rustls 0.24.2",
|
|
||||||
"hyper-tls 0.5.0",
|
"hyper-tls 0.5.0",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
@ -2213,7 +2197,6 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding 2.3.1",
|
"percent-encoding 2.3.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustls 0.21.12",
|
|
||||||
"rustls-pemfile 1.0.4",
|
"rustls-pemfile 1.0.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -2222,14 +2205,12 @@ dependencies = [
|
||||||
"system-configuration",
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
"tokio-rustls 0.24.1",
|
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"url 2.5.2",
|
"url 2.5.2",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots",
|
|
||||||
"winreg 0.50.0",
|
"winreg 0.50.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2249,7 +2230,7 @@ dependencies = [
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.4.1",
|
"hyper 1.4.1",
|
||||||
"hyper-rustls 0.27.2",
|
"hyper-rustls",
|
||||||
"hyper-tls 0.6.0",
|
"hyper-tls 0.6.0",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
|
@ -2496,18 +2477,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls"
|
|
||||||
version = "0.21.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
|
|
||||||
dependencies = [
|
|
||||||
"log 0.4.22",
|
|
||||||
"ring",
|
|
||||||
"rustls-webpki 0.101.7",
|
|
||||||
"sct",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.12"
|
version = "0.23.12"
|
||||||
|
@ -2516,7 +2485,7 @@ checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"rustls-webpki 0.102.6",
|
"rustls-webpki",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
@ -2546,16 +2515,6 @@ version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
|
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls-webpki"
|
|
||||||
version = "0.101.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
|
|
||||||
dependencies = [
|
|
||||||
"ring",
|
|
||||||
"untrusted",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.102.6"
|
version = "0.102.6"
|
||||||
|
@ -2609,16 +2568,6 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sct"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
|
|
||||||
dependencies = [
|
|
||||||
"ring",
|
|
||||||
"untrusted",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sec1"
|
name = "sec1"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
@ -3073,23 +3022,13 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-rustls"
|
|
||||||
version = "0.24.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
|
||||||
dependencies = [
|
|
||||||
"rustls 0.21.12",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls 0.23.12",
|
"rustls",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
@ -3515,12 +3454,6 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "webpki-roots"
|
|
||||||
version = "0.25.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websocket"
|
name = "websocket"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
|
|
|
@ -15,11 +15,12 @@ reqwest-tracing = "0.5.0"
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
serde_json = "1.0.115"
|
serde_json = "1.0.115"
|
||||||
serde_with = "3.7.0"
|
serde_with = "3.7.0"
|
||||||
tokio = { workspace = true }
|
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
|
openidconnect = { version = "3.5.0", default_features = false }
|
||||||
|
|
||||||
http_client = { workspace = true }
|
http_client = { workspace = true }
|
||||||
discord_bot = { workspace = true }
|
discord_bot = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
openidconnect = "3.5.0"
|
tokio = { workspace = true }
|
||||||
|
|
|
@ -6,65 +6,58 @@ use color_eyre::{eyre::eyre, Result};
|
||||||
use openidconnect::core::{
|
use openidconnect::core::{
|
||||||
CoreAuthenticationFlow, CoreClient, CoreProviderMetadata, CoreUserInfoClaims,
|
CoreAuthenticationFlow, CoreClient, CoreProviderMetadata, CoreUserInfoClaims,
|
||||||
};
|
};
|
||||||
use openidconnect::AuthorizationCode;
|
|
||||||
use openidconnect::{
|
use openidconnect::{
|
||||||
AccessTokenHash, ClientId, CsrfToken, HttpResponse, IssuerUrl, Nonce, PkceCodeChallenge,
|
AccessTokenHash, ClientId, CsrfToken, HttpResponse, IssuerUrl, Nonce, PkceCodeChallenge,
|
||||||
RedirectUrl, Scope,
|
RedirectUrl, Scope,
|
||||||
};
|
};
|
||||||
|
use openidconnect::{AuthorizationCode, PolicyUrl};
|
||||||
|
|
||||||
const ISSUER_URL: &str = "https://localhost:8443/oauth2/openid/yourcloud";
|
const ISSUER_URL: &str = "https://localhost:8443/oauth2/openid/yourcloud";
|
||||||
const CLIENT_ID: &str = "yourcloud";
|
const CLIENT_ID: &str = "yourcloud";
|
||||||
const REDIRECT_URL: &str = "http://localhost:3000/oauth2/handler";
|
const REDIRECT_URL: &str = "http://localhost:3000/oauth2/handler";
|
||||||
const SCOPES: [&str; 3] = ["read", "write", "email"];
|
const SCOPES: [&str; 3] = ["read", "write", "email"];
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
use http_client::{Client, Error};
|
||||||
pub enum Error {
|
|
||||||
/// Error returned by reqwest crate.
|
|
||||||
#[error("request failed")]
|
|
||||||
Reqwest(#[source] reqwest::Error),
|
|
||||||
/// I/O error.
|
|
||||||
#[error("I/O error")]
|
|
||||||
Io(#[source] std::io::Error),
|
|
||||||
/// Other error.
|
|
||||||
#[error("Other error: {}", _0)]
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn http_client(request: openidconnect::HttpRequest) -> Result<HttpResponse, Error> {
|
pub async fn async_http_client(request: openidconnect::HttpRequest) -> Result<HttpResponse, Error> {
|
||||||
let client = reqwest::Client::builder()
|
let builder = {
|
||||||
// Following redirects opens the client up to SSRF vulnerabilities.
|
let mut builder = Client::builder();
|
||||||
.redirect(Policy::none())
|
builder.client_builder = builder
|
||||||
.build()
|
.client_builder
|
||||||
.map_err(Error::Reqwest)?;
|
.danger_accept_invalid_certs(true) // hitting localhost
|
||||||
|
.redirect(http_client::reqwest::redirect::Policy::none());
|
||||||
|
builder
|
||||||
|
};
|
||||||
|
|
||||||
let mut request_builder = client
|
let mut request_builder = builder
|
||||||
.request(request.method, request.url.as_str())
|
.build()?
|
||||||
|
.build_request(request.method, request.url.as_str())?
|
||||||
.body(request.body);
|
.body(request.body);
|
||||||
|
|
||||||
for (name, value) in &request.headers {
|
for (name, value) in &request.headers {
|
||||||
request_builder = request_builder.header(name.as_str(), value.as_bytes());
|
request_builder = request_builder.header(name.as_str(), value.as_bytes());
|
||||||
}
|
}
|
||||||
let mut response = client
|
let response = request_builder.send().await?;
|
||||||
.execute(request_builder.build().map_err(Error::Reqwest)?)
|
|
||||||
.map_err(Error::Reqwest)?;
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let status_code = response.status();
|
||||||
response.read_to_end(&mut body).map_err(Error::Io)?;
|
let headers = response.headers().to_owned();
|
||||||
|
let chunks = response.bytes().await.map_err(Error::Reqwest)?;
|
||||||
{
|
|
||||||
Ok(HttpResponse {
|
Ok(HttpResponse {
|
||||||
status_code: response.status(),
|
status_code,
|
||||||
headers: response.headers().to_owned(),
|
headers,
|
||||||
body,
|
body: chunks.to_vec(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
// Use OpenID Connect Discovery to fetch the provider metadata.
|
// Use OpenID Connect Discovery to fetch the provider metadata.
|
||||||
use openidconnect::{OAuth2TokenResponse, TokenResponse};
|
use openidconnect::{OAuth2TokenResponse, TokenResponse};
|
||||||
let provider_metadata =
|
let provider_metadata = CoreProviderMetadata::discover_async(
|
||||||
CoreProviderMetadata::discover(&IssuerUrl::new(ISSUER_URL.to_string())?, http_client)?;
|
IssuerUrl::new(ISSUER_URL.to_string())?,
|
||||||
|
async_http_client,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Create an OpenID Connect client by specifying the client ID, client secret, authorization URL
|
// Create an OpenID Connect client by specifying the client ID, client secret, authorization URL
|
||||||
// and token URL.
|
// and token URL.
|
||||||
|
@ -114,7 +107,8 @@ fn main() -> Result<()> {
|
||||||
.exchange_code(AuthorizationCode::new(authorization_code))
|
.exchange_code(AuthorizationCode::new(authorization_code))
|
||||||
// Set the PKCE code verifier.
|
// Set the PKCE code verifier.
|
||||||
.set_pkce_verifier(pkce_verifier)
|
.set_pkce_verifier(pkce_verifier)
|
||||||
.request(http_client)?;
|
.request_async(async_http_client)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Extract the ID token claims after verifying its authenticity and nonce.
|
// Extract the ID token claims after verifying its authenticity and nonce.
|
||||||
let id_token = token_response
|
let id_token = token_response
|
||||||
|
@ -151,7 +145,8 @@ fn main() -> Result<()> {
|
||||||
let userinfo: CoreUserInfoClaims = client
|
let userinfo: CoreUserInfoClaims = client
|
||||||
.user_info(token_response.access_token().to_owned(), None)
|
.user_info(token_response.access_token().to_owned(), None)
|
||||||
.map_err(|err| eyre!("No user info endpoint: {:?}", err))?
|
.map_err(|err| eyre!("No user info endpoint: {:?}", err))?
|
||||||
.request(http_client)
|
.request_async(async_http_client)
|
||||||
|
.await
|
||||||
.map_err(|err| eyre!("Failed requesting user info: {:?}", err))?;
|
.map_err(|err| eyre!("Failed requesting user info: {:?}", err))?;
|
||||||
|
|
||||||
println!("{:#?}", userinfo);
|
println!("{:#?}", userinfo);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i bash -p ripgrep oath-toolkit
|
#!nix-shell -i bash -p ripgrep oath-toolkit
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
FAKE_PASSWORD="f0rTkN0x1s_cool"
|
FAKE_PASSWORD="f0rTkN0x1s_cool"
|
||||||
function kdrun {
|
function kdrun {
|
||||||
podman exec -it kanidm "$@"
|
podman exec -it kanidm "$@"
|
||||||
|
@ -13,7 +15,7 @@ echo "admin password: $admin_password"
|
||||||
echo "idm_admin password: $idm_password"
|
echo "idm_admin password: $idm_password"
|
||||||
|
|
||||||
# start a kanidm client in the background for an hour
|
# start a kanidm client in the background for an hour
|
||||||
podman kill kanidm-client || true
|
podman kill kanidm-client &>/dev/null || true
|
||||||
sleep 0.2
|
sleep 0.2
|
||||||
|
|
||||||
podman run -itd --rm \
|
podman run -itd --rm \
|
||||||
|
|
|
@ -5,4 +5,4 @@ podman run -itd --rm \
|
||||||
-v "$PWD/chain.pem:/data/chain.pem:ro" \
|
-v "$PWD/chain.pem:/data/chain.pem:ro" \
|
||||||
-v "$PWD/key.pem:/data/key.pem:ro" \
|
-v "$PWD/key.pem:/data/key.pem:ro" \
|
||||||
--name kanidm \
|
--name kanidm \
|
||||||
docker.io/kanidm/server:latest
|
docker.io/kanidm/server:latest &>/dev/null || true
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub use reqwest;
|
||||||
pub use reqwest::header::{HeaderMap, HeaderValue};
|
pub use reqwest::header::{HeaderMap, HeaderValue};
|
||||||
pub use reqwest::{Body, ClientBuilder, Method, Response, Url};
|
pub use reqwest::{Body, ClientBuilder, Method, Response, Url};
|
||||||
pub use reqwest_middleware::ClientBuilder as MiddlewareClientBuilder;
|
pub use reqwest_middleware::ClientBuilder as MiddlewareClientBuilder;
|
||||||
|
@ -16,6 +17,8 @@ pub struct Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
|
pub client_builder: ClientBuilder,
|
||||||
|
// middleware_client_builder: MiddlewareClientBuilder,
|
||||||
middleware: Option<Box<Vec<Arc<dyn Middleware>>>>,
|
middleware: Option<Box<Vec<Arc<dyn Middleware>>>>,
|
||||||
default_headers: Option<HeaderMap>,
|
default_headers: Option<HeaderMap>,
|
||||||
base_url: Option<Url>,
|
base_url: Option<Url>,
|
||||||
|
@ -33,6 +36,7 @@ impl Default for Builder {
|
||||||
middleware.push(Arc::new(TracingMiddleware::default()));
|
middleware.push(Arc::new(TracingMiddleware::default()));
|
||||||
|
|
||||||
Builder {
|
Builder {
|
||||||
|
client_builder: ClientBuilder::new(),
|
||||||
name: None,
|
name: None,
|
||||||
base_url: None,
|
base_url: None,
|
||||||
default_headers: None,
|
default_headers: None,
|
||||||
|
@ -70,7 +74,7 @@ impl Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(mut self) -> Result<Client> {
|
pub fn build(mut self) -> Result<Client> {
|
||||||
let mut builder = reqwest::Client::builder();
|
let mut builder = self.client_builder;
|
||||||
|
|
||||||
if let Some(headers) = self.default_headers {
|
if let Some(headers) = self.default_headers {
|
||||||
builder = builder.default_headers(headers);
|
builder = builder.default_headers(headers);
|
||||||
|
|
Loading…
Reference in a new issue