The two lookups every caller uses now honor Domain.directoryId, then the server default, then the internal directory, so sign-in, bearer routing, recipient lookup, discovery, the PACC record and the refusal of password changes on external accounts all follow the domain. A directoryId, or a server default, naming a directory that doesn't exist is unavailable, never the internal directory. A directory speaks only for the domains it serves: an account it returns on another directory's domain is refused, for sign-in and recipients alike, and aliases and group claims on such domains are dropped with a warning. A bearer token must belong to the user the client names, or the name must be one of its aliases with alias sign-in allowed. Accounts and groups that sync creates pass the tenant checks, limits included.
70 lines
2.6 KiB
Rust
70 lines
2.6 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use crate::{
|
|
Directories, Directory, UnavailableDirectory,
|
|
backend::{ldap::LdapDirectory, oidc::OpenIdDirectory, sql::SqlDirectory},
|
|
};
|
|
use registry::schema::{
|
|
prelude::ObjectType,
|
|
structs::{self, Authentication},
|
|
};
|
|
use std::{collections::HashMap, sync::Arc};
|
|
use store::registry::bootstrap::Bootstrap;
|
|
|
|
impl Directories {
|
|
pub async fn build(bp: &mut Bootstrap) -> Self {
|
|
let mut directories = HashMap::default();
|
|
|
|
for directory in bp.list_infallible::<structs::Directory>().await {
|
|
let id = directory.id;
|
|
let directory_type = directory.object.object_type();
|
|
let result = match directory.object {
|
|
structs::Directory::Ldap(directory) => LdapDirectory::open(directory).await,
|
|
structs::Directory::Sql(directory) => {
|
|
SqlDirectory::open(directory, &bp.data_store).await
|
|
}
|
|
structs::Directory::Oidc(directory) => OpenIdDirectory::open(directory).await,
|
|
};
|
|
|
|
let directory = match result {
|
|
Ok(directory) => directory,
|
|
Err(err) => {
|
|
bp.build_error(id, err.clone());
|
|
Directory::Unavailable(UnavailableDirectory::new(directory_type, err))
|
|
}
|
|
};
|
|
directories.insert(id.id().id() as u32, Arc::new(directory));
|
|
}
|
|
|
|
let auth = bp.setting_infallible::<Authentication>().await;
|
|
let default_directory = if let Some(directory_id) = auth.directory_id {
|
|
match directories.get(&(directory_id.id() as u32)) {
|
|
Some(default_directory) => default_directory.clone().into(),
|
|
None => {
|
|
bp.build_error(
|
|
ObjectType::Authentication.singleton(),
|
|
format!("Default directory with ID {} not found", directory_id),
|
|
);
|
|
// inbuxa: DIR-5: a missing default is unavailable, never the
|
|
// internal directory
|
|
Some(Arc::new(Directory::Unavailable(UnavailableDirectory::new(
|
|
registry::schema::enums::DirectoryType::Ldap,
|
|
format!("Default directory with ID {} not found", directory_id),
|
|
))))
|
|
}
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Directories {
|
|
default_directory,
|
|
directories,
|
|
}
|
|
}
|
|
}
|