This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 45da018d58 [SYNCOPE-1786] Allowing domain selection for Keymaster API
via Swagger UI + fixing KeymasterConfParamLoader for additional domains
45da018d58 is described below
commit 45da018d58f2672e15c7f508df91488b2f431434
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Wed Mar 13 10:49:50 2024 +0100
[SYNCOPE-1786] Allowing domain selection for Keymaster API via Swagger UI +
fixing KeymasterConfParamLoader for additional domains
---
.../common/keymaster/client/api/DomainOps.java | 2 +
.../common/keymaster/client/api/model/Domain.java | 10 +++
.../client/zookeeper/ZookeeperDomainOps.java | 82 +++++++++++++---------
.../client/self/SelfKeymasterDomainOps.java | 11 +++
.../keymaster/rest/api/service/DomainService.java | 12 ++++
.../apache/syncope/core/logic/DummyDomainOps.java | 5 ++
.../apache/syncope/core/logic/DummyDomainOps.java | 5 ++
.../persistence/common/RuntimeDomainLoader.java | 16 +++--
.../common/content/KeymasterConfParamLoader.java | 61 ++++++++--------
.../persistence/jpa/JPARuntimeDomainLoader.java | 4 +-
.../core/persistence/jpa/PersistenceContext.java | 3 +-
.../core/persistence/jpa/DummyDomainOps.java | 5 ++
.../core/persistence/neo4j/PersistenceContext.java | 3 +-
.../core/persistence/neo4j/DummyDomainOps.java | 5 ++
.../core/provisioning/java/DummyDomainOps.java | 5 ++
.../internal/SelfKeymasterInternalDomainOps.java | 8 +++
.../rest/cxf/service/DomainServiceImpl.java | 5 ++
.../org/apache/syncope/core/logic/DomainLogic.java | 11 +++
.../syncope/core/starter/SelfKeymasterContext.java | 33 +++++++++
.../syncope/core/starter/SyncopeCoreStart.java | 3 +-
.../syncope/core/workflow/java/DummyDomainOps.java | 5 ++
.../apache/syncope/fit/core/KeymasterITCase.java | 36 ++++------
22 files changed, 233 insertions(+), 97 deletions(-)
diff --git
a/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/DomainOps.java
b/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/DomainOps.java
index b7ec18a9b5..78139f6cd6 100644
---
a/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/DomainOps.java
+++
b/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/DomainOps.java
@@ -33,6 +33,8 @@ public interface DomainOps {
void create(Domain domain);
+ void deployed(String key);
+
void changeAdminPassword(String key, String password, CipherAlgorithm
cipherAlgorithm);
void adjustPoolSize(String key, int poolMaxActive, int poolMinIdle);
diff --git
a/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/model/Domain.java
b/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/model/Domain.java
index eec05b4b6f..6edb517586 100644
---
a/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/model/Domain.java
+++
b/common/keymaster/client-api/src/main/java/org/apache/syncope/common/keymaster/client/api/model/Domain.java
@@ -98,6 +98,8 @@ public abstract class Domain implements Serializable {
protected String keymasterConfParams;
+ protected boolean deployed = false;
+
@JsonProperty("_class")
public String getDiscriminator() {
return getClass().getName();
@@ -145,6 +147,14 @@ public abstract class Domain implements Serializable {
return keymasterConfParams;
}
+ public boolean isDeployed() {
+ return deployed;
+ }
+
+ public void setDeployed(final boolean deployed) {
+ this.deployed = deployed;
+ }
+
@Override
public int hashCode() {
return new HashCodeBuilder().
diff --git
a/common/keymaster/client-zookeeper/src/main/java/org/apache/syncope/common/keymaster/client/zookeeper/ZookeeperDomainOps.java
b/common/keymaster/client-zookeeper/src/main/java/org/apache/syncope/common/keymaster/client/zookeeper/ZookeeperDomainOps.java
index bc15acba26..f6d212d81c 100644
---
a/common/keymaster/client-zookeeper/src/main/java/org/apache/syncope/common/keymaster/client/zookeeper/ZookeeperDomainOps.java
+++
b/common/keymaster/client-zookeeper/src/main/java/org/apache/syncope/common/keymaster/client/zookeeper/ZookeeperDomainOps.java
@@ -67,41 +67,43 @@ public class ZookeeperDomainOps implements DomainOps,
InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
- if (watcher != null) {
- if (client.checkExists().forPath(buildDomainPath()) == null) {
-
client.create().creatingParentContainersIfNeeded().forPath(buildDomainPath());
- }
+ if (watcher == null) {
+ LOG.warn("No watcher found, aborting");
+ return;
+ }
- CuratorCache cache = CuratorCache.build(client, buildDomainPath());
- cache.listenable().addListener((type, oldData, newData) -> {
- switch (type) {
- case NODE_CREATED:
- LOG.debug("Domain {} added", newData.getPath());
- try {
- Domain domain =
MAPPER.readValue(newData.getData(), Domain.class);
-
- LOG.info("Domain {} created", domain.getKey());
- watcher.added(domain);
- } catch (IOException e) {
- LOG.debug("Could not parse {}", new
String(newData.getData()), e);
- }
- break;
-
- case NODE_CHANGED:
- LOG.debug("Domain {} updated", newData.getPath());
- break;
-
- case NODE_DELETED:
- LOG.debug("Domain {} removed", newData.getPath());
-
watcher.removed(StringUtils.substringAfter(newData.getPath(), DOMAIN_PATH +
'/'));
- break;
-
- default:
- LOG.debug("Event {} received with data {}", type,
newData);
- }
- });
- cache.start();
+ if (client.checkExists().forPath(buildDomainPath()) == null) {
+
client.create().creatingParentContainersIfNeeded().forPath(buildDomainPath());
}
+
+ CuratorCache cache = CuratorCache.build(client, buildDomainPath());
+ cache.listenable().addListener((type, oldData, newData) -> {
+ switch (type) {
+ case NODE_CREATED -> {
+ LOG.debug("Domain {} added", newData.getPath());
+ try {
+ Domain domain = MAPPER.readValue(newData.getData(),
Domain.class);
+
+ LOG.info("Domain {} created", domain.getKey());
+ watcher.added(domain);
+ } catch (IOException e) {
+ LOG.debug("Could not parse {}", new
String(newData.getData()), e);
+ }
+ }
+
+ case NODE_CHANGED ->
+ LOG.debug("Domain {} updated", newData.getPath());
+
+ case NODE_DELETED -> {
+ LOG.debug("Domain {} removed", newData.getPath());
+
watcher.removed(StringUtils.substringAfter(newData.getPath(), DOMAIN_PATH +
'/'));
+ }
+
+ default ->
+ LOG.debug("Event {} received with data {}", type, newData);
+ }
+ });
+ cache.start();
}
@Override
@@ -151,6 +153,20 @@ public class ZookeeperDomainOps implements DomainOps,
InitializingBean {
}
}
+ @Override
+ public void deployed(final String key) {
+ try {
+ Domain domain = read(key);
+
+ domain.setDeployed(true);
+ client.setData().forPath(buildDomainPath(key),
MAPPER.writeValueAsBytes(domain));
+ } catch (KeymasterException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new KeymasterException(e);
+ }
+ }
+
@Override
public void changeAdminPassword(
final String key, final String password, final CipherAlgorithm
cipherAlgorithm) {
diff --git
a/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterDomainOps.java
b/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterDomainOps.java
index 92a2dd4793..06a7c160a5 100644
---
a/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterDomainOps.java
+++
b/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterDomainOps.java
@@ -60,6 +60,17 @@ public class SelfKeymasterDomainOps extends SelfKeymasterOps
implements DomainOp
}
}
+ @Override
+ public void deployed(final String key) {
+ try {
+ client(DomainService.class, Map.of()).deployed(key);
+ } catch (KeymasterException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new KeymasterException(e);
+ }
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
try {
diff --git
a/common/keymaster/self/rest-api/src/main/java/org/apache/syncope/common/keymaster/rest/api/service/DomainService.java
b/common/keymaster/self/rest-api/src/main/java/org/apache/syncope/common/keymaster/rest/api/service/DomainService.java
index 489158e124..99a60102c3 100644
---
a/common/keymaster/self/rest-api/src/main/java/org/apache/syncope/common/keymaster/rest/api/service/DomainService.java
+++
b/common/keymaster/self/rest-api/src/main/java/org/apache/syncope/common/keymaster/rest/api/service/DomainService.java
@@ -92,6 +92,18 @@ public interface DomainService extends Serializable {
@Produces({ MediaType.APPLICATION_JSON })
Response create(Domain domain);
+ /**
+ * Notify that the given domain is deployed.
+ *
+ * @param key key of domain to be updated
+ */
+ @ApiResponses(
+ @ApiResponse(responseCode = "204", description = "Operation was
successful"))
+ @POST
+ @Path("{key}/deployed")
+ @Produces({ MediaType.APPLICATION_JSON })
+ void deployed(@NotNull @PathParam("key") String key);
+
/**
* Change admin's password for the given domain.
*
diff --git
a/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
b/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
index f899baea17..2af29d9bfb 100644
---
a/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
+++
b/core/idm/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
@@ -48,6 +48,11 @@ public class DummyDomainOps implements DomainOps {
domainRegistry.register((JPADomain) domain);
}
+ @Override
+ public void deployed(final String key) {
+ // nothing to do
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
// nothing to do
diff --git
a/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
b/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
index f899baea17..2af29d9bfb 100644
---
a/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
+++
b/core/idrepo/logic/src/test/java/org/apache/syncope/core/logic/DummyDomainOps.java
@@ -48,6 +48,11 @@ public class DummyDomainOps implements DomainOps {
domainRegistry.register((JPADomain) domain);
}
+ @Override
+ public void deployed(final String key) {
+ // nothing to do
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
// nothing to do
diff --git
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/RuntimeDomainLoader.java
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/RuntimeDomainLoader.java
index 1d725f2938..278602178f 100644
---
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/RuntimeDomainLoader.java
+++
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/RuntimeDomainLoader.java
@@ -19,17 +19,18 @@
package org.apache.syncope.core.persistence.common;
import java.util.Comparator;
+import org.apache.syncope.common.keymaster.client.api.DomainOps;
import org.apache.syncope.common.keymaster.client.api.DomainWatcher;
import org.apache.syncope.common.keymaster.client.api.model.Domain;
import org.apache.syncope.core.persistence.api.DomainHolder;
import org.apache.syncope.core.persistence.api.DomainRegistry;
import org.apache.syncope.core.persistence.api.SyncopeCoreLoader;
import org.apache.syncope.core.spring.ApplicationContextProvider;
-import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.scheduling.annotation.Async;
public class RuntimeDomainLoader<D extends Domain> implements DomainWatcher {
@@ -39,13 +40,17 @@ public class RuntimeDomainLoader<D extends Domain>
implements DomainWatcher {
protected final DomainRegistry<D> domainRegistry;
+ protected final DomainOps domainOps;
+
public RuntimeDomainLoader(
final DomainHolder<?> domainHolder,
final DomainRegistry<D> domainRegistry,
+ final DomainOps domainOps,
final ConfigurableApplicationContext ctx) {
this.domainHolder = domainHolder;
this.domainRegistry = domainRegistry;
+ this.domainOps = domainOps;
// only needed by ZookeeperDomainOps' early init on afterPropertiesSet
if (ApplicationContextProvider.getApplicationContext() == null) {
@@ -57,6 +62,7 @@ public class RuntimeDomainLoader<D extends Domain> implements
DomainWatcher {
// nothing to do
}
+ @Async
@SuppressWarnings("unchecked")
@Override
public void added(final Domain domain) {
@@ -76,17 +82,17 @@ public class RuntimeDomainLoader<D extends Domain>
implements DomainWatcher {
LOG.debug("[{}] Starting on domain '{}'", loaderName,
domain);
- AuthContextUtils.runAsAdmin(
- domain.getKey(),
- () -> loader.load(domain.getKey()));
+ loader.load(domain.getKey());
LOG.debug("[{}] Completed on domain '{}'", loaderName,
domain);
});
+ domainOps.deployed(domain.getKey());
LOG.info("Domain {} successfully deployed", domain.getKey());
}
}
+ @Async
@Override
public void removed(final String domain) {
if (domainHolder.getDomains().containsKey(domain)) {
@@ -98,7 +104,9 @@ public class RuntimeDomainLoader<D extends Domain>
implements DomainWatcher {
String loaderName =
AopUtils.getTargetClass(loader).getName();
LOG.debug("[{}] Starting dispose on domain '{}'",
loaderName, domain);
+
loader.unload(domain);
+
LOG.debug("[{}] Dispose completed on domain '{}'",
loaderName, domain);
});
diff --git
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/content/KeymasterConfParamLoader.java
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/content/KeymasterConfParamLoader.java
index 6cd7754d48..13a96801ea 100644
---
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/content/KeymasterConfParamLoader.java
+++
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/content/KeymasterConfParamLoader.java
@@ -20,15 +20,17 @@ package org.apache.syncope.core.persistence.common.content;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.json.JsonMapper;
-import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
+import java.util.Optional;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
import org.apache.syncope.core.persistence.api.content.ConfParamLoader;
import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.transaction.annotation.Transactional;
/**
* Initialize Keymaster with default content if no data is present already.
@@ -52,41 +54,38 @@ public class KeymasterConfParamLoader implements
ConfParamLoader {
@Override
public void load(final String domain) {
- boolean existingData;
- try {
- existingData = !confParamOps.list(domain).isEmpty();
- } catch (Exception e) {
- LOG.error("[{}] Could not access Keymaster", domain, e);
- existingData = true;
- }
+ AuthContextUtils.runAsAdmin(domain, new Runnable() {
- if (existingData) {
- LOG.info("[{}] Data found in Keymaster, leaving untouched",
domain);
- } else {
- LOG.info("[{}] Empty Keymaster found, loading default content",
domain);
+ @Transactional
+ @Override
+ public void run() {
+ boolean existingData;
+ try {
+ existingData = !confParamOps.list(domain).isEmpty();
+ } catch (Exception e) {
+ LOG.error("[{}] Could not access Keymaster", domain, e);
+ existingData = true;
+ }
- try {
- InputStream contentJSON =
ApplicationContextProvider.getBeanFactory().
- getBean(domain + "KeymasterConfParamsJSON",
InputStream.class);
- loadDefaultContent(domain, contentJSON);
- } catch (Exception e) {
- LOG.error("[{}] While loading default Keymaster content",
domain, e);
- }
- }
- }
+ if (existingData) {
+ LOG.info("[{}] Data found in Keymaster, leaving
untouched", domain);
+ } else {
+ LOG.info("[{}] Empty Keymaster found, loading default
content", domain);
- protected void loadDefaultContent(final String domain, final InputStream
contentJSON)
- throws IOException {
+ try (InputStream contentJSON =
ApplicationContextProvider.getBeanFactory().
+ getBean(domain + "KeymasterConfParamsJSON",
InputStream.class)) {
- try (contentJSON) {
- JsonNode content = MAPPER.readTree(contentJSON);
- for (Iterator<Map.Entry<String, JsonNode>> itor =
content.fields(); itor.hasNext();) {
- Map.Entry<String, JsonNode> param = itor.next();
- Object value = MAPPER.treeToValue(param.getValue(),
Object.class);
- if (value != null) {
- confParamOps.set(domain, param.getKey(), value);
+ JsonNode content = MAPPER.readTree(contentJSON);
+ for (Iterator<Map.Entry<String, JsonNode>> itor =
content.fields(); itor.hasNext();) {
+ Map.Entry<String, JsonNode> param = itor.next();
+
Optional.ofNullable(MAPPER.treeToValue(param.getValue(), Object.class)).
+ ifPresent(value ->
confParamOps.set(domain, param.getKey(), value));
+ }
+ } catch (Exception e) {
+ LOG.error("[{}] While loading default Keymaster
content", domain, e);
+ }
}
}
- }
+ });
}
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/JPARuntimeDomainLoader.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/JPARuntimeDomainLoader.java
index 5ad94dc8c5..54cd86b90d 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/JPARuntimeDomainLoader.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/JPARuntimeDomainLoader.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.persistence.jpa;
+import org.apache.syncope.common.keymaster.client.api.DomainOps;
import org.apache.syncope.common.keymaster.client.api.model.Domain;
import org.apache.syncope.common.keymaster.client.api.model.JPADomain;
import org.apache.syncope.core.persistence.api.DomainHolder;
@@ -35,9 +36,10 @@ public class JPARuntimeDomainLoader extends
RuntimeDomainLoader<JPADomain> {
final DomainHolder<?> domainHolder,
final DomainRegistry<JPADomain> domainRegistry,
final DomainRoutingEntityManagerFactory entityManagerFactory,
+ final DomainOps domainOps,
final ConfigurableApplicationContext ctx) {
- super(domainHolder, domainRegistry, ctx);
+ super(domainHolder, domainRegistry, domainOps, ctx);
this.entityManagerFactory = entityManagerFactory;
}
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
index 619b10f8aa..4b088db279 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
@@ -331,9 +331,10 @@ public class PersistenceContext {
final DomainHolder<?> domainHolder,
final DomainRegistry<JPADomain> domainRegistry,
final DomainRoutingEntityManagerFactory entityManagerFactory,
+ final @Lazy DomainOps domainOps,
final ConfigurableApplicationContext ctx) {
- return new JPARuntimeDomainLoader(domainHolder, domainRegistry,
entityManagerFactory, ctx);
+ return new JPARuntimeDomainLoader(domainHolder, domainRegistry,
entityManagerFactory, domainOps, ctx);
}
@ConditionalOnMissingBean
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyDomainOps.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyDomainOps.java
index 8491534651..8cae9f1ee9 100644
---
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyDomainOps.java
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyDomainOps.java
@@ -48,6 +48,11 @@ public class DummyDomainOps implements DomainOps {
domainRegistry.register((JPADomain) domain);
}
+ @Override
+ public void deployed(final String key) {
+ // nothing to do
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
// nothing to do
diff --git
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java
index 3d06e5efb1..ed1854cfcd 100644
---
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java
+++
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java
@@ -372,9 +372,10 @@ public class PersistenceContext {
public RuntimeDomainLoader<Neo4jDomain> runtimeDomainLoader(
final DomainHolder<?> domainHolder,
final DomainRegistry<Neo4jDomain> domainRegistry,
+ final @Lazy DomainOps domainOps,
final ConfigurableApplicationContext ctx) {
- return new RuntimeDomainLoader<>(domainHolder, domainRegistry, ctx);
+ return new RuntimeDomainLoader<>(domainHolder, domainRegistry,
domainOps, ctx);
}
@ConditionalOnMissingBean
diff --git
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/DummyDomainOps.java
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/DummyDomainOps.java
index 2a0c39d4c6..f80bff7b36 100644
---
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/DummyDomainOps.java
+++
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/DummyDomainOps.java
@@ -48,6 +48,11 @@ public class DummyDomainOps implements DomainOps {
domainRegistry.register((Neo4jDomain) domain);
}
+ @Override
+ public void deployed(final String key) {
+ // nothing to do
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
// nothing to do
diff --git
a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyDomainOps.java
b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyDomainOps.java
index bd29f19659..bd5fb03bad 100644
---
a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyDomainOps.java
+++
b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyDomainOps.java
@@ -48,6 +48,11 @@ public class DummyDomainOps implements DomainOps {
domainRegistry.register((JPADomain) domain);
}
+ @Override
+ public void deployed(final String key) {
+ // nothing to do
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
// nothing to do
diff --git
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/internal/SelfKeymasterInternalDomainOps.java
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/internal/SelfKeymasterInternalDomainOps.java
index ca74494bd7..27882487df 100644
---
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/internal/SelfKeymasterInternalDomainOps.java
+++
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/internal/SelfKeymasterInternalDomainOps.java
@@ -64,6 +64,14 @@ public class SelfKeymasterInternalDomainOps implements
DomainOps {
});
}
+ @Override
+ public void deployed(final String key) {
+ AuthContextUtils.callAs(SyncopeConstants.MASTER_DOMAIN,
props.getUsername(), List.of(), () -> {
+ logic.deployed(key);
+ return null;
+ });
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
AuthContextUtils.callAs(SyncopeConstants.MASTER_DOMAIN,
props.getUsername(), List.of(), () -> {
diff --git
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/rest/cxf/service/DomainServiceImpl.java
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/rest/cxf/service/DomainServiceImpl.java
index ec94bca8d3..f5c81cdb8b 100644
---
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/rest/cxf/service/DomainServiceImpl.java
+++
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/keymaster/rest/cxf/service/DomainServiceImpl.java
@@ -63,6 +63,11 @@ public class DomainServiceImpl implements DomainService {
build();
}
+ @Override
+ public void deployed(final String key) {
+ logic.deployed(key);
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
logic.changeAdminPassword(key, password, cipherAlgorithm);
diff --git
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
index 832cee9dd7..f5c6a54717 100644
---
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
+++
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
@@ -87,6 +87,17 @@ public class DomainLogic extends
AbstractTransactionalLogic<EntityTO> {
return domainEntity.get();
}
+ @PreAuthorize("@environment.getProperty('keymaster.username') ==
authentication.name")
+ public void deployed(final String key) {
+ DomainEntity domain = domainDAO.findById(key).
+ orElseThrow(() -> new NotFoundException("Domain " + key));
+
+ Domain domainObj = domain.get();
+ domainObj.setDeployed(true);
+ domain.set(domainObj);
+ domainDAO.save(domain);
+ }
+
@PreAuthorize("@environment.getProperty('keymaster.username') ==
authentication.name")
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
DomainEntity domain = domainDAO.findById(key).
diff --git
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
index 9f23bb4d12..29353ff024 100644
---
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
+++
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
@@ -20,9 +20,14 @@ package org.apache.syncope.core.starter;
import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
import io.swagger.v3.oas.integration.api.OpenAPIConfiguration;
+import io.swagger.v3.oas.models.ExternalDocumentation;
+import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.parameters.HeaderParameter;
+import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.security.SecurityScheme;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
@@ -45,6 +50,8 @@ import
org.apache.syncope.common.keymaster.client.api.ServiceOps;
import org.apache.syncope.common.keymaster.rest.api.service.ConfParamService;
import org.apache.syncope.common.keymaster.rest.api.service.DomainService;
import
org.apache.syncope.common.keymaster.rest.api.service.NetworkServiceService;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.core.keymaster.internal.InternalConfParamHelper;
import
org.apache.syncope.core.keymaster.internal.SelfKeymasterInternalConfParamOps;
import
org.apache.syncope.core.keymaster.internal.SelfKeymasterInternalDomainOps;
@@ -56,6 +63,7 @@ import
org.apache.syncope.core.keymaster.rest.security.SelfKeymasterUsernamePass
import org.apache.syncope.core.logic.ConfParamLogic;
import org.apache.syncope.core.logic.DomainLogic;
import org.apache.syncope.core.logic.NetworkServiceLogic;
+import org.apache.syncope.core.persistence.api.DomainHolder;
import org.apache.syncope.core.persistence.api.dao.keymaster.ConfParamDAO;
import org.apache.syncope.core.persistence.api.dao.keymaster.DomainDAO;
import org.apache.syncope.core.persistence.api.dao.keymaster.NetworkServiceDAO;
@@ -105,6 +113,7 @@ public class SelfKeymasterContext {
@Bean
public Server selfKeymasterContainer(
+ final DomainHolder<?> domainHolder,
final ConfParamService confParamService,
final NetworkServiceService networkServiceService,
final DomainService domainService,
@@ -158,6 +167,30 @@ public class SelfKeymasterContext {
return configuration;
}
+
+ @Override
+ protected void addParameters(final List<Parameter> parameters) {
+ Optional<Parameter> domainHeaderParameter =
parameters.stream().
+ filter(p -> p instanceof HeaderParameter &&
RESTHeaders.DOMAIN.equals(p.getName())).findFirst();
+ if (domainHeaderParameter.isEmpty()) {
+ HeaderParameter parameter = new HeaderParameter();
+ parameter.setName(RESTHeaders.DOMAIN);
+ parameter.setRequired(true);
+
+ ExternalDocumentation extDoc = new ExternalDocumentation();
+ extDoc.setDescription("Apache Syncope Reference Guide");
+
extDoc.setUrl("https://syncope.apache.org/docs/3.0/reference-guide.html#domains");
+
+ Schema<String> schema = new Schema<>();
+ schema.setDescription("Domains are built to facilitate
multitenancy.");
+ schema.setExternalDocs(extDoc);
+
schema.setEnum(domainHolder.getDomains().keySet().stream().sorted().toList());
+ schema.setDefault(SyncopeConstants.MASTER_DOMAIN);
+ parameter.setSchema(schema);
+
+ parameters.add(parameter);
+ }
+ }
};
openApiCustomizer.setDynamicBasePath(false);
openApiCustomizer.setReplaceTags(false);
diff --git
a/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreStart.java
b/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreStart.java
index d9d48e7d78..b3e6e440e1 100644
---
a/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreStart.java
+++
b/core/starter/src/main/java/org/apache/syncope/core/starter/SyncopeCoreStart.java
@@ -24,7 +24,6 @@ import
org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart;
import org.apache.syncope.core.persistence.api.DomainHolder;
import org.apache.syncope.core.persistence.api.SyncopeCoreLoader;
import org.apache.syncope.core.provisioning.java.job.JobStatusUpdater;
-import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
@@ -64,7 +63,7 @@ public class SyncopeCoreStart extends KeymasterStart
implements Ordered {
domainHolder.getDomains().keySet().forEach(domain -> {
LOG.debug("[{}] Starting init on domain '{}'",
loaderName, domain);
- AuthContextUtils.runAsAdmin(domain, () ->
loader.load(domain));
+ loader.load(domain);
LOG.debug("[{}] Init completed on domain '{}'",
loaderName, domain);
});
diff --git
a/core/workflow-java/src/test/java/org/apache/syncope/core/workflow/java/DummyDomainOps.java
b/core/workflow-java/src/test/java/org/apache/syncope/core/workflow/java/DummyDomainOps.java
index 54f4f1338e..b5edf5ec50 100644
---
a/core/workflow-java/src/test/java/org/apache/syncope/core/workflow/java/DummyDomainOps.java
+++
b/core/workflow-java/src/test/java/org/apache/syncope/core/workflow/java/DummyDomainOps.java
@@ -48,6 +48,11 @@ public class DummyDomainOps implements DomainOps {
domainRegistry.register((JPADomain) domain);
}
+ @Override
+ public void deployed(final String key) {
+ // nothing to do
+ }
+
@Override
public void changeAdminPassword(final String key, final String password,
final CipherAlgorithm cipherAlgorithm) {
// nothing to do
diff --git
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java
index 3df305e6ca..3f7e2cb593 100644
---
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java
+++
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/KeymasterITCase.java
@@ -44,7 +44,6 @@ import
org.apache.syncope.common.keymaster.client.api.KeymasterException;
import org.apache.syncope.common.keymaster.client.api.model.Domain;
import org.apache.syncope.common.keymaster.client.api.model.JPADomain;
import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
-import org.apache.syncope.common.keymaster.client.self.SelfKeymasterDomainOps;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.request.UserCR;
import org.apache.syncope.common.lib.to.PagedResult;
@@ -216,11 +215,11 @@ public class KeymasterITCase extends AbstractITCase {
assumeTrue(initial.stream().anyMatch(domain ->
"Two".equals(domain.getKey())));
// 1. create new domain
- String key = UUID.randomUUID().toString();
+ String newDomain = UUID.randomUUID().toString();
- domainOps.create(new JPADomain.Builder(key).
+ domainOps.create(new JPADomain.Builder(newDomain).
jdbcDriver("org.h2.Driver").
- jdbcURL("jdbc:h2:mem:syncopetest" + key +
";DB_CLOSE_DELAY=-1").
+ jdbcURL("jdbc:h2:mem:syncopetest" + newDomain +
";DB_CLOSE_DELAY=-1").
dbUsername("sa").
dbPassword("").
databasePlatform("org.apache.openjpa.jdbc.sql.H2Dictionary").
@@ -229,37 +228,26 @@ public class KeymasterITCase extends AbstractITCase {
adminCipherAlgorithm(CipherAlgorithm.BCRYPT).
build());
- JPADomain domain = (JPADomain) domainOps.read(key);
+ JPADomain domain = (JPADomain) domainOps.read(newDomain);
assertEquals(JPADomain.TransactionIsolation.TRANSACTION_READ_UNCOMMITTED,
domain.getTransactionIsolation());
assertEquals(CipherAlgorithm.BCRYPT, domain.getAdminCipherAlgorithm());
assertEquals(10, domain.getPoolMaxActive());
assertEquals(2, domain.getPoolMinIdle());
- assertEquals(domain, domainOps.read(key));
+ assertEquals(domain, domainOps.read(newDomain));
// 2. update domain
- domainOps.adjustPoolSize(key, 100, 23);
+ domainOps.adjustPoolSize(newDomain, 100, 23);
- domain = (JPADomain) domainOps.read(key);
+ domain = (JPADomain) domainOps.read(newDomain);
assertEquals(100, domain.getPoolMaxActive());
assertEquals(23, domain.getPoolMinIdle());
- // temporarily finish test case at this point in case Zookeeper
- // is used: in such a case, in fact, errors are found in the logs
- // at this point as follows:
- // org.springframework.beans.factory.BeanCreationException: Error
creating bean
- // with name
- //
'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration':
- // Initialization of bean failed; nested exception is
- // org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named
- //
'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry'
- // available
- // the same test, execute alone, works fine with Zookeeper, so it musy
be something
- // set or left unclean from previous tests
- assumeTrue(domainOps instanceof SelfKeymasterDomainOps);
-
// 3. work with new domain - create user
- CLIENT_FACTORY = new
SyncopeClientFactoryBean().setAddress(ADDRESS).setDomain(key);
+ await().atMost(MAX_WAIT_SECONDS, TimeUnit.SECONDS).pollInterval(1,
TimeUnit.SECONDS).
+ until(() -> domainOps.read(newDomain).isDeployed());
+
+ CLIENT_FACTORY = new
SyncopeClientFactoryBean().setAddress(ADDRESS).setDomain(newDomain);
ADMIN_CLIENT = CLIENT_FACTORY.create(ADMIN_UNAME, "password");
USER_SERVICE = ADMIN_CLIENT.getService(UserService.class);
@@ -297,7 +285,7 @@ public class KeymasterITCase extends AbstractITCase {
assertEquals(1, users.getTotalCount());
// 4. delete domain
- domainOps.delete(key);
+ domainOps.delete(newDomain);
List<Domain> list = domainOps.list();
assertEquals(initial, list);