Per-domain directories: each domain signs in against its own directory (DIR-1 to DIR-15)

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.
This commit is contained in:
2026-09-19 10:32:57 -07:00
parent b080fa0736
commit f72e3bb85c
4 changed files with 173 additions and 13 deletions
+6 -1
View File
@@ -49,7 +49,12 @@ impl Directories {
ObjectType::Authentication.singleton(),
format!("Default directory with ID {} not found", directory_id),
);
None
// 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 {