diff --git a/changelog.d/23165_custom_auth_path_access.feature.md b/changelog.d/23165_custom_auth_path_access.feature.md new file mode 100644 index 0000000000000..91cbd40e07779 --- /dev/null +++ b/changelog.d/23165_custom_auth_path_access.feature.md @@ -0,0 +1 @@ +Enabled URL path access in VRL scripts of custom auth strategy for server components. diff --git a/src/common/http/server_auth.rs b/src/common/http/server_auth.rs index fda8ccdbf82eb..b3155f5781206 100644 --- a/src/common/http/server_auth.rs +++ b/src/common/http/server_auth.rs @@ -198,6 +198,7 @@ impl HttpServerAuthMatcher { &self, address: Option<&SocketAddr>, headers: &HeaderMap, + path: &str, ) -> Result<(), ErrorMessage> { match self { HttpServerAuthMatcher::AuthHeader(expected, err_message) => { @@ -218,7 +219,7 @@ impl HttpServerAuthMatcher { } } HttpServerAuthMatcher::Vrl { program } => { - self.handle_vrl_auth(address, headers, program) + self.handle_vrl_auth(address, headers, path, program) } } } @@ -227,6 +228,7 @@ impl HttpServerAuthMatcher { &self, address: Option<&SocketAddr>, headers: &HeaderMap, + path: &str, program: &Program, ) -> Result<(), ErrorMessage> { let mut target = VrlTarget::new( @@ -250,6 +252,7 @@ impl HttpServerAuthMatcher { "address".into(), address.map_or(Value::Null, |a| Value::from(a.ip().to_string())), ), + ("path".into(), Value::from(path.to_owned())), ]), Default::default(), )), @@ -439,7 +442,7 @@ mod tests { let matcher = basic_auth.build(&Default::default()).unwrap(); - let result = matcher.handle_auth(Some(&next_addr()), &HeaderMap::new()); + let result = matcher.handle_auth(Some(&next_addr()), &HeaderMap::new(), "/"); assert!(result.is_err()); let error = result.unwrap_err(); @@ -458,7 +461,7 @@ mod tests { let mut headers = HeaderMap::new(); headers.insert(AUTHORIZATION, HeaderValue::from_static("Basic wrong")); - let result = matcher.handle_auth(Some(&next_addr()), &headers); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/"); assert!(result.is_err()); let error = result.unwrap_err(); @@ -482,7 +485,7 @@ mod tests { AUTHORIZATION, Authorization::basic(&username, &password).0.encode(), ); - let result = matcher.handle_auth(Some(&next_addr()), &headers); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/"); assert!(result.is_ok()); } @@ -497,7 +500,7 @@ mod tests { let mut headers = HeaderMap::new(); headers.insert(AUTHORIZATION, HeaderValue::from_static("test")); - let result = matcher.handle_auth(Some(&next_addr()), &headers); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/"); assert!(result.is_ok()); } @@ -513,7 +516,7 @@ mod tests { let matcher = custom_auth.build(&Default::default()).unwrap(); let headers = HeaderMap::new(); - let result = matcher.handle_auth(Some(&next_addr()), &headers); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/"); assert!(result.is_ok()); } @@ -529,7 +532,35 @@ mod tests { let matcher = custom_auth.build(&Default::default()).unwrap(); let headers = HeaderMap::new(); - let result = matcher.handle_auth(None, &headers); + let result = matcher.handle_auth(None, &headers, "/"); + + assert!(result.is_err()); + } + + #[test] + fn custom_auth_matcher_should_be_able_to_check_path() { + let custom_auth = HttpServerAuthConfig::Custom { + source: r#".path == "/ok""#.to_string(), + }; + + let matcher = custom_auth.build(&Default::default()).unwrap(); + + let headers = HeaderMap::new(); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/ok"); + + assert!(result.is_ok()); + } + + #[test] + fn custom_auth_matcher_should_return_401_with_wrong_path() { + let custom_auth = HttpServerAuthConfig::Custom { + source: r#".path == "/ok""#.to_string(), + }; + + let matcher = custom_auth.build(&Default::default()).unwrap(); + + let headers = HeaderMap::new(); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/bad"); assert!(result.is_err()); } @@ -544,7 +575,7 @@ mod tests { let mut headers = HeaderMap::new(); headers.insert(AUTHORIZATION, HeaderValue::from_static("wrong value")); - let result = matcher.handle_auth(Some(&next_addr()), &headers); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/"); assert!(result.is_err()); let error = result.unwrap_err(); @@ -562,7 +593,7 @@ mod tests { let mut headers = HeaderMap::new(); headers.insert(AUTHORIZATION, HeaderValue::from_static("test")); - let result = matcher.handle_auth(Some(&next_addr()), &headers); + let result = matcher.handle_auth(Some(&next_addr()), &headers, "/"); assert!(result.is_err()); let error = result.unwrap_err(); diff --git a/src/sinks/websocket_server/sink.rs b/src/sinks/websocket_server/sink.rs index 62da60bd1740a..f8ab7ebab45b9 100644 --- a/src/sinks/websocket_server/sink.rs +++ b/src/sinks/websocket_server/sink.rs @@ -214,7 +214,7 @@ impl WebSocketListenerSink { )); return Ok(response); }; - match auth.handle_auth(Some(&addr), req.headers()) { + match auth.handle_auth(Some(&addr), req.headers(), req.uri().path()) { Ok(_) => { extra_tags.append(&mut Self::extract_extra_tags( &extra_tags_config, diff --git a/src/sources/util/http/prelude.rs b/src/sources/util/http/prelude.rs index 15f7a23b1c0f5..b6310ec2c2c75 100644 --- a/src/sources/util/http/prelude.rs +++ b/src/sources/util/http/prelude.rs @@ -133,7 +133,11 @@ pub trait HttpSource: Clone + Send + Sync + 'static { let events = auth_matcher .as_ref() .map_or(Ok(()), |a| { - a.handle_auth(addr.as_ref().map(|a| a.0).as_ref(), &headers) + a.handle_auth( + addr.as_ref().map(|a| a.0).as_ref(), + &headers, + path.as_str(), + ) }) .and_then(|()| self.decode(encoding_header.as_deref(), body)) .and_then(|body| { diff --git a/website/cue/reference/components.cue b/website/cue/reference/components.cue index 11fbc0a3f34f9..46ac8ddc97bf9 100644 --- a/website/cue/reference/components.cue +++ b/website/cue/reference/components.cue @@ -1289,8 +1289,8 @@ components: { authorization code using VRL. Here is an example that looks up the token in an enrichment table backed by a CSV file. - Currently custom VRL auth has access to `headers` and `address` (IP address of the - client). + Currently custom VRL auth has access to `headers`, `path`, and `address` (IP + address of the client). ```yaml \(kind)s: