SCIM: publish meta in /Schemas, and run the conformance container on the host network (SCIM-6, SCIM-30)

scim2-client builds its models from /Schemas, so meta is described there
as the mapping tables give it, without lastModified. The tester container
now shares the host's network, so a host firewall that drops the Docker
bridge doesn't block the test server. With SCIM_CONFORMANCE=1, the
scim2-client lifecycle (12 steps), the eight replayed Okta, Keycloak and
Entra payloads, and scim2-tester (errors only for its generated
non-address userName) all pass.
This commit is contained in:
2026-09-19 09:52:11 -07:00
parent 3ffaee0695
commit a18e209015
2 changed files with 17 additions and 0 deletions
+14
View File
@@ -239,6 +239,18 @@ fn schema(base: &str, id: &str, name: &str, description: &str, attributes: Vec<A
}) })
} }
/// `meta` as the mapping tables give it: no `lastModified` (SCIM-30).
fn meta() -> Attr {
Attr::new("meta", "complex").read_only().with(vec![
Attr::new("resourceType", "string").read_only().case_exact(),
Attr::new("created", "dateTime").read_only(),
Attr::new("location", "reference")
.read_only()
.refs(&["uri"]),
Attr::new("version", "string").read_only().case_exact(),
])
}
/// The User attributes of the mapping table (SCIM-6); `password` isn't /// The User attributes of the mapping table (SCIM-6); `password` isn't
/// published. /// published.
pub fn user_schema(base: &str) -> Value { pub fn user_schema(base: &str) -> Value {
@@ -269,6 +281,7 @@ pub fn user_schema(base: &str) -> Value {
Attr::new("display", "string").read_only(), Attr::new("display", "string").read_only(),
Attr::new("$ref", "reference").read_only().refs(&["Group"]), Attr::new("$ref", "reference").read_only().refs(&["Group"]),
]), ]),
meta(),
], ],
) )
} }
@@ -289,6 +302,7 @@ pub fn group_schema(base: &str) -> Value {
Attr::new("type", "string").immutable().canonical(&["User"]), Attr::new("type", "string").immutable().canonical(&["User"]),
Attr::new("$ref", "reference").immutable().refs(&["User"]), Attr::new("$ref", "reference").immutable().refs(&["User"]),
]), ]),
meta(),
], ],
) )
} }
+3
View File
@@ -312,6 +312,9 @@ pub async fn ensure_scim_tester() -> &'static ContainerAsync<GenericImage> {
.expect("Failed to build the SCIM tester image"); .expect("Failed to build the SCIM tester image");
image image
.with_host("host.docker.internal", Host::HostGateway) .with_host("host.docker.internal", Host::HostGateway)
// inbuxa: on the host's network, so a host firewall that
// drops the Docker bridge doesn't block the test server
.with_network("host")
.with_startup_timeout(READY_TIMEOUT) .with_startup_timeout(READY_TIMEOUT)
.with_container_name("stalwart-test-scim-tester") .with_container_name("stalwart-test-scim-tester")
.with_reuse(ReuseDirective::Always) .with_reuse(ReuseDirective::Always)