Skip to content

Commit bf178cc

Browse files
authored
RUST-1670: Add ALLOWED_HOSTS checking for human flow OIDC (#1042)
1 parent 6bc9c7c commit bf178cc

File tree

3 files changed

+62
-12
lines changed

3 files changed

+62
-12
lines changed

.evergreen/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ buildvariants:
295295

296296
- name: oidc
297297
display_name: OIDC
298-
patchable: false
298+
patchable: true
299299
run_on:
300300
- ubuntu2204-small
301301
expansions:

src/client/auth.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -210,16 +210,15 @@ impl AuthMechanism {
210210
"password must not be set for MONGODB-OIDC authentication",
211211
));
212212
}
213-
// TODO RUST-1670: handle ALLOWED_HOSTS
214-
// let default_allowed = vec![
215-
// "*.mongodb.net",
216-
// "*.mongodb-dev.net",
217-
// "*.mongodb-qa.net",
218-
// "*.mongodbgov.net",
219-
// "localhost",
220-
// "127.0.0.1",
221-
// "::1",
222-
// ]
213+
if let Some(allowed_hosts) = credential
214+
.mechanism_properties
215+
.as_ref()
216+
.and_then(|p| p.get("ALLOWED_HOSTS"))
217+
{
218+
allowed_hosts
219+
.as_array()
220+
.ok_or_else(|| Error::invalid_argument("ALLOWED_HOSTS must be an array"))?;
221+
}
223222
Ok(())
224223
}
225224
_ => Ok(()),

src/client/auth/oidc.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
sasl::{SaslResponse, SaslStart},
1212
AuthMechanism,
1313
},
14-
options::ServerApi,
14+
options::{ServerAddress, ServerApi},
1515
},
1616
cmap::{Command, Connection},
1717
error::{Error, Result},
@@ -25,6 +25,15 @@ const HUMAN_CALLBACK_TIMEOUT: Duration = Duration::from_secs(5 * 60);
2525
const MACHINE_CALLBACK_TIMEOUT: Duration = Duration::from_secs(60);
2626
const MACHINE_INVALIDATE_SLEEP_TIMEOUT: Duration = Duration::from_millis(100);
2727
const API_VERSION: u32 = 1;
28+
const DEFAULT_ALLOWED_HOSTS: &[&str] = &[
29+
"*.mongodb.net",
30+
"*.mongodb-qa.net",
31+
"*.mongodb-dev.net",
32+
"*.mongodbgov.net",
33+
"localhost",
34+
"127.0.0.1",
35+
"::1",
36+
];
2837

2938
/// The user-supplied callbacks for OIDC authentication.
3039
#[derive(Clone)]
@@ -351,12 +360,54 @@ async fn do_two_step_auth(
351360
Ok(())
352361
}
353362

363+
fn get_allowed_hosts(mechanism_properties: Option<&Document>) -> Result<Vec<&str>> {
364+
if mechanism_properties.is_none() {
365+
return Ok(Vec::from(DEFAULT_ALLOWED_HOSTS));
366+
}
367+
if let Some(allowed_hosts) =
368+
mechanism_properties.and_then(|p| p.get_array("ALLOWED_HOSTS").ok())
369+
{
370+
return allowed_hosts
371+
.iter()
372+
.map(|host| {
373+
host.as_str()
374+
.ok_or_else(|| auth_error("ALLOWED_HOSTS must contain only strings"))
375+
})
376+
.collect::<Result<Vec<_>>>();
377+
}
378+
Ok(Vec::from(DEFAULT_ALLOWED_HOSTS))
379+
}
380+
381+
fn validate_address_with_allowed_hosts(
382+
mechanism_properties: Option<&Document>,
383+
address: &ServerAddress,
384+
) -> Result<()> {
385+
let hostname = if let ServerAddress::Tcp { host, .. } = address {
386+
host.as_str()
387+
} else {
388+
return Err(auth_error("OIDC human flow only supports TCP addresses"));
389+
};
390+
for pattern in get_allowed_hosts(mechanism_properties)? {
391+
if pattern == hostname {
392+
return Ok(());
393+
}
394+
if pattern.starts_with("*.") && hostname.ends_with(&pattern[1..]) {
395+
return Ok(());
396+
}
397+
}
398+
Err(auth_error(
399+
"The Connection address is not in the allowed list of hosts",
400+
))
401+
}
402+
354403
async fn authenticate_human(
355404
conn: &mut Connection,
356405
credential: &Credential,
357406
server_api: Option<&ServerApi>,
358407
callback: Arc<CallbackInner>,
359408
) -> Result<()> {
409+
validate_address_with_allowed_hosts(credential.mechanism_properties.as_ref(), &conn.address)?;
410+
360411
let source = credential.source.as_deref().unwrap_or("$external");
361412

362413
// If the access token is in the cache, we can use it to send the sasl start command and avoid

0 commit comments

Comments
 (0)