From d7147cde7c9de3e0dcfa1c52c885411247349364 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 25 Sep 2023 17:20:33 -0500 Subject: [PATCH] Use regex for bearer token validation --- Cargo.lock | 1 + core/Cargo.toml | 1 + core/src/auth_tokens.rs | 40 ++++++++++------------------------------ 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ae443adc..646fb412e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2044,6 +2044,7 @@ dependencies = [ "mockito", "prio 0.15.2", "rand", + "regex", "reqwest", "ring", "rstest", diff --git a/core/Cargo.toml b/core/Cargo.toml index c439f9c09..f36381b6a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -47,6 +47,7 @@ kube = { workspace = true, optional = true, features = ["rustls-tls"] } k8s-openapi = { workspace = true, optional = true } prio.workspace = true rand = "0.8" +regex = "1.9.5" reqwest = { version = "0.11.20", default-features = false, features = ["rustls-tls", "json"] } ring = "0.16.20" serde.workspace = true diff --git a/core/src/auth_tokens.rs b/core/src/auth_tokens.rs index 2c7c54043..5d8bb84f4 100644 --- a/core/src/auth_tokens.rs +++ b/core/src/auth_tokens.rs @@ -2,12 +2,13 @@ use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; use derivative::Derivative; use http::{header::AUTHORIZATION, HeaderValue}; use rand::{distributions::Standard, prelude::Distribution}; +use regex::Regex; use ring::{ constant_time, digest::{digest, SHA256, SHA256_OUTPUT_LEN}, }; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; -use std::str; +use std::{str, sync::OnceLock}; /// HTTP header where auth tokens are provided in messages between participants. pub const DAP_AUTH_HEADER: &str = "DAP-Auth-Token"; @@ -204,36 +205,15 @@ impl BearerToken { /// Validate that a bearer token value matches the format in /// https://datatracker.ietf.org/doc/html/rfc6750#section-2.1. fn validate(value: &str) -> Result<(), anyhow::Error> { - let mut iter = value.chars(); - let mut any_non_equals = false; - // First loop: consume "normal" characters, stop when we see an equals sign for padding or - // reach the end of the input. - for c in &mut iter { - match c { - 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '.' | '_' | '~' | '+' | '/' => { - any_non_equals = true; - } - '=' => { - if !any_non_equals { - return Err(anyhow::anyhow!("bearer token may not start with '='")); - } - break; - } - _ => return Err(anyhow::anyhow!("bearer token may not contain '{c}'")), - } - } - // Second loop: consume any further padding characters, if present. - for c in &mut iter { - match c { - '=' => {} - _ => { - return Err(anyhow::anyhow!( - "bearer token may only contain '=' at the end" - )) - } - } + static REGEX: OnceLock = OnceLock::new(); + + let regex = REGEX.get_or_init(|| Regex::new("^[-A-Za-z0-9._~+/]+=*$").unwrap()); + + if regex.is_match(value) { + Ok(()) + } else { + Err(anyhow::anyhow!("bearer token has invalid format")) } - Ok(()) } }