feat: Change Bearer Auth Token to use random bits (#24733)

This changes the 'influxdb3 create token' command so that it will just
automatically generate a completely random base64 encoded token prepended with
'apiv3_' that is then fed into a Sha512 algorithm instead of Sha256. The
user can no longer pass in a token to be turned into the proper output.

This also changes the server code to handle the change to Sha512 as well.

Closes #24704
pull/24737/head
Michael Gattozzi 2024-03-06 12:43:00 -05:00 committed by GitHub
parent 971676b498
commit ce8c158956
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 69 additions and 45 deletions

59
Cargo.lock generated
View File

@ -223,7 +223,7 @@ dependencies = [
"arrow-data",
"arrow-schema",
"arrow-select",
"base64",
"base64 0.21.7",
"chrono",
"comfy-table",
"half",
@ -279,7 +279,7 @@ dependencies = [
"arrow-schema",
"arrow-select",
"arrow-string",
"base64",
"base64 0.21.7",
"bytes",
"futures",
"once_cell",
@ -538,7 +538,7 @@ source = "git+https://github.com/influxdata/influxdb3_core?rev=86d72868fd39f7865
dependencies = [
"async-trait",
"backoff 0.1.0",
"base64",
"base64 0.21.7",
"generated_types",
"http",
"iox_time",
@ -644,6 +644,12 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
[[package]]
name = "base64ct"
version = "1.6.0"
@ -882,9 +888,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chrono"
version = "0.4.34"
version = "0.4.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
dependencies = [
"android-tzdata",
"iana-time-zone",
@ -1475,7 +1481,7 @@ version = "36.0.0"
source = "git+https://github.com/apache/arrow-datafusion.git?rev=91f3eb2e5430d23e2b551e66732bec1a3a575971#91f3eb2e5430d23e2b551e66732bec1a3a575971"
dependencies = [
"arrow",
"base64",
"base64 0.21.7",
"datafusion-common",
"datafusion-execution",
"datafusion-expr",
@ -1525,7 +1531,7 @@ dependencies = [
"arrow-ord",
"arrow-schema",
"arrow-string",
"base64",
"base64 0.21.7",
"blake2",
"blake3",
"chrono",
@ -2197,7 +2203,7 @@ version = "7.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d"
dependencies = [
"base64",
"base64 0.21.7",
"byteorder",
"flate2",
"nom",
@ -2464,6 +2470,7 @@ dependencies = [
"arrow_util",
"assert_cmd",
"backtrace",
"base64 0.22.0",
"clap",
"clap_blocks",
"console-subscriber",
@ -2488,6 +2495,7 @@ dependencies = [
"parking_lot",
"parquet_file",
"pretty_assertions",
"rand",
"reqwest",
"secrecy",
"sha2",
@ -2532,6 +2540,7 @@ dependencies = [
"arrow-schema",
"async-trait",
"authz",
"base64 0.22.0",
"bytes",
"chrono",
"data_types",
@ -2663,7 +2672,7 @@ version = "0.1.0"
source = "git+https://github.com/influxdata/influxdb3_core?rev=86d72868fd39f7865e97d0b3a66bac29a5f662b2#86d72868fd39f7865e97d0b3a66bac29a5f662b2"
dependencies = [
"arrow",
"base64",
"base64 0.21.7",
"bytes",
"data_types",
"datafusion",
@ -3003,7 +3012,7 @@ version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "550f99d93aa4c2b25de527bce492d772caf5e21d7ac9bd4b508ba781c8d91e30"
dependencies = [
"base64",
"base64 0.21.7",
"chrono",
"schemars",
"serde",
@ -3050,7 +3059,7 @@ version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe0d65dd6f3adba29cfb84f19dfe55449c7f6c35425f9d8294bec40313e0b64"
dependencies = [
"base64",
"base64 0.21.7",
"bytes",
"chrono",
"either",
@ -3731,7 +3740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8718f8b65fdf67a45108d1548347d4af7d71fb81ce727bbf9e3b2535e079db3"
dependencies = [
"async-trait",
"base64",
"base64 0.21.7",
"bytes",
"chrono",
"futures",
@ -3856,7 +3865,7 @@ dependencies = [
"arrow-ipc",
"arrow-schema",
"arrow-select",
"base64",
"base64 0.21.7",
"brotli",
"bytes",
"chrono",
@ -3924,7 +3933,7 @@ version = "0.1.0"
source = "git+https://github.com/influxdata/influxdb3_core?rev=86d72868fd39f7865e97d0b3a66bac29a5f662b2#86d72868fd39f7865e97d0b3a66bac29a5f662b2"
dependencies = [
"arrow",
"base64",
"base64 0.21.7",
"bytes",
"data_types",
"datafusion",
@ -3968,7 +3977,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1030c719b0ec2a2d25a5df729d6cff1acf3cc230bf766f4f97833591f7577b90"
dependencies = [
"base64",
"base64 0.21.7",
"serde",
]
@ -4005,7 +4014,7 @@ version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310"
dependencies = [
"base64",
"base64 0.21.7",
"serde",
]
@ -4621,7 +4630,7 @@ version = "0.11.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
dependencies = [
"base64",
"base64 0.21.7",
"bytes",
"encoding_rs",
"futures-core",
@ -4761,7 +4770,7 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [
"base64",
"base64 0.21.7",
]
[[package]]
@ -4770,7 +4779,7 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab"
dependencies = [
"base64",
"base64 0.21.7",
"rustls-pki-types",
]
@ -5411,7 +5420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
dependencies = [
"atoi",
"base64",
"base64 0.21.7",
"bitflags 2.4.2",
"byteorder",
"bytes",
@ -5454,7 +5463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
dependencies = [
"atoi",
"base64",
"base64 0.21.7",
"bitflags 2.4.2",
"byteorder",
"crc",
@ -5974,7 +5983,7 @@ checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
dependencies = [
"async-trait",
"axum",
"base64",
"base64 0.21.7",
"bytes",
"futures-core",
"futures-util",
@ -6003,7 +6012,7 @@ dependencies = [
"async-stream",
"async-trait",
"axum",
"base64",
"base64 0.21.7",
"bytes",
"h2",
"http",
@ -6090,7 +6099,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
dependencies = [
"base64",
"base64 0.21.7",
"bitflags 2.4.2",
"bytes",
"futures-core",
@ -6818,7 +6827,7 @@ dependencies = [
"ahash",
"arrow",
"arrow-ipc",
"base64",
"base64 0.21.7",
"bit-set",
"bit-vec",
"bitflags 2.4.2",

View File

@ -39,6 +39,7 @@ arrow-schema = "50.0.0"
assert_cmd = "2.0.14"
async-trait = "0.1"
backtrace = "0.3"
base64 = "0.22.0"
byteorder = "1.3.4"
bytes = "1.5"
chrono = "0.4"
@ -70,6 +71,7 @@ pretty_assertions = "1.4.0"
prost = "0.12.3"
prost-build = "0.12.2"
prost-types = "0.12.3"
rand = "0.8.5"
reqwest = { version = "0.11.24", default-features = false, features = ["rustls-tls"] }
secrecy = "0.8.0"
serde = { version = "1.0", features = ["derive"] }

View File

@ -28,6 +28,7 @@ influxdb3_write = { path = "../influxdb3_write" }
# Crates.io dependencies
backtrace.workspace = true
base64.workspace = true
clap.workspace = true
dotenvy.workspace = true
hex.workspace = true
@ -35,6 +36,7 @@ libc.workspace = true
num_cpus.workspace = true
once_cell.workspace = true
parking_lot.workspace = true
rand.workspace = true
secrecy.workspace = true
sha2.workspace = true
thiserror.workspace = true

View File

@ -1,6 +1,11 @@
use base64::engine::general_purpose::URL_SAFE_NO_PAD as B64;
use base64::Engine as _;
use rand::rngs::OsRng;
use rand::RngCore;
use sha2::Digest;
use sha2::Sha256;
use sha2::Sha512;
use std::error::Error;
use std::str;
#[derive(Debug, clap::Parser)]
pub struct Config {
@ -10,25 +15,28 @@ pub struct Config {
#[derive(Debug, clap::Parser)]
pub enum SubCommand {
Token { token: String },
Token,
}
pub fn command(config: Config) -> Result<(), Box<dyn Error>> {
match config.cmd {
SubCommand::Token { token } => {
if token.is_empty() {
return Err("Token argument must not be empty".into());
}
SubCommand::Token => {
let token = {
let mut token = String::from("apiv3_");
let mut key = [0u8; 64];
OsRng.fill_bytes(&mut key);
token.push_str(&B64.encode(key));
token
};
println!(
"\
Token Input: {token}\n\
Hashed Output: {hashed}\n\n\
Token: {token}\n\
Hashed Token: {hashed}\n\n\
Start the server with `influxdb3 serve --bearer-token {hashed}`\n\n\
HTTP requests require the following header: \"Authorization: Bearer {token}\"\n\
This will grant you access to every HTTP endpoint or deny it otherwise
",
hashed = hex::encode(&Sha256::digest(&token)[..])
hashed = hex::encode(&Sha512::digest(&token)[..])
);
}
}

View File

@ -27,6 +27,8 @@ static COMMAND: Mutex<Option<DropCommand>> = parking_lot::const_mutex(None);
#[tokio::test]
async fn auth() {
const HASHED_TOKEN: &str = "5315f0c4714537843face80cca8c18e27ce88e31e9be7a5232dc4dc8444f27c0227a9bd64831d3ab58f652bd0262dd8558dd08870ac9e5c650972ce9e4259439";
const TOKEN: &str = "apiv3_mp75KQAhbqv0GeQXk8MPuZ3ztaLEaR5JzS8iifk1FwuroSVyXXyrJK1c4gEr1kHkmbgzDV-j3MvQpaIMVJBAiA";
// The binary is made before testing so we have access to it
let bin_path = {
let mut bin_path = env::current_exe().unwrap();
@ -41,10 +43,10 @@ async fn auth() {
"--object-store",
"memory",
"--bearer-token",
"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", // foo as a sha256
HASHED_TOKEN,
])
.stderr(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.expect("Was able to spawn a server"),
);
@ -62,7 +64,7 @@ async fn auth() {
// Wait for the server to come up
while client
.get("http://127.0.0.1:8181/health")
.bearer_auth("foo")
.bearer_auth(TOKEN)
.send()
.await
.is_err()
@ -91,7 +93,7 @@ async fn auth() {
client
.post("http://127.0.0.1:8181/api/v3/write_lp?db=foo")
.body("cpu,host=a val=1i 123")
.bearer_auth("foo")
.bearer_auth(TOKEN)
.send()
.await
.unwrap()
@ -101,7 +103,7 @@ async fn auth() {
assert_eq!(
client
.get("http://127.0.0.1:8181/api/v3/query_sql?db=foo&q=select+*+from+cpu")
.bearer_auth("foo")
.bearer_auth(TOKEN)
.send()
.await
.unwrap()
@ -113,7 +115,7 @@ async fn auth() {
assert_eq!(
client
.get("http://127.0.0.1:8181/api/v3/query_sql?db=foo&q=select+*+from+cpu")
.header("Authorization", "Bearer foo whee")
.header("Authorization", format!("Bearer {TOKEN} whee"))
.send()
.await
.unwrap()
@ -123,7 +125,7 @@ async fn auth() {
assert_eq!(
client
.get("http://127.0.0.1:8181/api/v3/query_sql?db=foo&q=select+*+from+cpu")
.header("Authorization", "bearer foo")
.header("Authorization", format!("bearer {TOKEN}"))
.send()
.await
.unwrap()
@ -143,7 +145,7 @@ async fn auth() {
assert_eq!(
client
.get("http://127.0.0.1:8181/api/v3/query_sql?db=foo&q=select+*+from+cpu")
.header("Authorizon", "Bearer foo")
.header("auth", format!("Bearer {TOKEN}"))
.send()
.await
.unwrap()

View File

@ -38,6 +38,7 @@ arrow-flight.workspace = true
arrow-json.workspace = true
arrow-schema.workspace = true
async-trait.workspace = true
base64.workspace = true
bytes.workspace = true
chrono.workspace = true
datafusion.workspace = true

View File

@ -30,7 +30,7 @@ use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
use sha2::Sha512;
use std::convert::Infallible;
use std::fmt::Debug;
use std::num::NonZeroI32;
@ -516,7 +516,7 @@ where
}
// Check that the hashed token is acceptable
let authorized = &Sha256::digest(token)[..] == bearer_token;
let authorized = &Sha512::digest(token)[..] == bearer_token;
if !authorized {
return Err(AuthorizationError::Unauthorized);
}