You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2020/04/09 14:24:44 UTC
[syncope] 04/07: [SYNCOPE-1545] allow wa to lazy-load application
context by scheduling a quartz job to retry/refresh the context after
startup
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch SYNCOPE-160
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit f840d8c00d4e358efe9467cfa3f1473cebf1dfd7
Author: Misagh Moayyed <mm...@apache.org>
AuthorDate: Thu Apr 9 13:38:20 2020 +0200
[SYNCOPE-1545] allow wa to lazy-load application context by scheduling a quartz job to retry/refresh the context after startup
---
docker/wa/src/main/resources/wa.properties | 27 +++
fit/wa-reference/pom.xml | 24 +--
fit/wa-reference/src/main/resources/wa.properties | 27 +++
wa/bootstrap/pom.xml | 10 +-
.../java/org/apache/syncope/wa/WARestClient.java | 101 ++++++++++
.../bootstrap/SyncopeWABootstrapConfiguration.java | 52 ++++++
...on.java => SyncopeWAPropertySourceLocator.java} | 44 +++--
.../src/main/resources/META-INF/spring.factories | 2 +-
wa/starter/pom.xml | 49 ++++-
.../syncope/wa/mapper/RegisteredServiceMapper.java | 205 +++++++++++++++++++++
.../syncope/wa/starter/SyncopeWAApplication.java | 70 ++++++-
.../syncope/wa/starter/SyncopeWAConfiguration.java | 30 ++-
.../wa/starter/rest/SyncopeServiceRegistry.java | 148 +++++++++++++++
.../src/main/resources/application.properties | 6 +-
wa/starter/src/main/resources/wa.properties | 19 ++
15 files changed, 764 insertions(+), 50 deletions(-)
diff --git a/docker/wa/src/main/resources/wa.properties b/docker/wa/src/main/resources/wa.properties
index c44b04e..c98a6e7 100644
--- a/docker/wa/src/main/resources/wa.properties
+++ b/docker/wa/src/main/resources/wa.properties
@@ -23,3 +23,30 @@ useGZIPCompression=true
conf.directory=${conf.directory}
cas.standalone.configurationDirectory=${conf.directory}
cas.authn.oidc.jwks.jwksFile=file:${conf.directory}/oidc.keystore
+
+cas.server.name=http://localhost:8080
+cas.server.prefix=${cas.server.name}/syncope-wa
+cas.server.scope=syncope.org
+
+cas.authn.samlIdp.entityId=https://syncope.apache.org/saml
+cas.authn.samlIdp.metadata.location=file:${conf.directory}
+
+# Disable access to the login endpoint
+# if no target application is specified.
+cas.sso.allow-missing-service-parameter=true
+
+# Disable the acceptable usage policy
+# by default for now.
+cas.acceptableUsagePolicy.enabled=false
+
+management.endpoints.web.exposure.include=health,loggers,refresh
+management.endpoint.health.show-details=always
+
+management.endpoint.health.enabled=true
+management.endpoint.loggers.enabled=true
+management.endpoint.refresh.enabled=true
+
+cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
+
+spring.security.user.name=${anonymousUser}
+spring.security.user.password=${anonymousKey}
diff --git a/fit/wa-reference/pom.xml b/fit/wa-reference/pom.xml
index fa05bad..e3b4dcb 100644
--- a/fit/wa-reference/pom.xml
+++ b/fit/wa-reference/pom.xml
@@ -143,18 +143,18 @@ under the License.
<context>syncope</context>
</properties>
</deployable>
- <deployable>
- <location>${basedir}/../console-reference/target/syncope-fit-console-reference-${project.version}</location>
- <properties>
- <context>syncope-console</context>
- </properties>
- </deployable>
- <deployable>
- <location>${basedir}/../enduser-reference/target/syncope-fit-enduser-reference-${project.version}</location>
- <properties>
- <context>syncope-enduser</context>
- </properties>
- </deployable>
+<!-- <deployable>-->
+<!-- <location>${basedir}/../console-reference/target/syncope-fit-console-reference-${project.version}</location>-->
+<!-- <properties>-->
+<!-- <context>syncope-console</context>-->
+<!-- </properties>-->
+<!-- </deployable>-->
+<!-- <deployable>-->
+<!-- <location>${basedir}/../enduser-reference/target/syncope-fit-enduser-reference-${project.version}</location>-->
+<!-- <properties>-->
+<!-- <context>syncope-enduser</context>-->
+<!-- </properties>-->
+<!-- </deployable>-->
<deployable>
<location>${project.build.directory}/${project.build.finalName}</location>
<properties>
diff --git a/fit/wa-reference/src/main/resources/wa.properties b/fit/wa-reference/src/main/resources/wa.properties
index c44b04e..c98a6e7 100644
--- a/fit/wa-reference/src/main/resources/wa.properties
+++ b/fit/wa-reference/src/main/resources/wa.properties
@@ -23,3 +23,30 @@ useGZIPCompression=true
conf.directory=${conf.directory}
cas.standalone.configurationDirectory=${conf.directory}
cas.authn.oidc.jwks.jwksFile=file:${conf.directory}/oidc.keystore
+
+cas.server.name=http://localhost:8080
+cas.server.prefix=${cas.server.name}/syncope-wa
+cas.server.scope=syncope.org
+
+cas.authn.samlIdp.entityId=https://syncope.apache.org/saml
+cas.authn.samlIdp.metadata.location=file:${conf.directory}
+
+# Disable access to the login endpoint
+# if no target application is specified.
+cas.sso.allow-missing-service-parameter=true
+
+# Disable the acceptable usage policy
+# by default for now.
+cas.acceptableUsagePolicy.enabled=false
+
+management.endpoints.web.exposure.include=health,loggers,refresh
+management.endpoint.health.show-details=always
+
+management.endpoint.health.enabled=true
+management.endpoint.loggers.enabled=true
+management.endpoint.refresh.enabled=true
+
+cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
+
+spring.security.user.name=${anonymousUser}
+spring.security.user.password=${anonymousKey}
diff --git a/wa/bootstrap/pom.xml b/wa/bootstrap/pom.xml
index 72b7482..9ea1e97 100644
--- a/wa/bootstrap/pom.xml
+++ b/wa/bootstrap/pom.xml
@@ -43,11 +43,19 @@ under the License.
<artifactId>syncope-client-am-lib</artifactId>
<version>${project.version}</version>
</dependency>
-
+ <dependency>
+ <groupId>org.apache.syncope.common.keymaster</groupId>
+ <artifactId>syncope-common-keymaster-client-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-configuration-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-core-util-api</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/WARestClient.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/WARestClient.java
new file mode 100644
index 0000000..ca2d048
--- /dev/null
+++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/WARestClient.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.wa;
+
+import org.apereo.cas.util.spring.ApplicationContextProvider;
+
+import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.keymaster.client.api.KeymasterException;
+import org.apache.syncope.common.keymaster.client.api.ServiceOps;
+import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
+
+import java.util.Collection;
+
+public class WARestClient {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WARestClient.class);
+
+ private final String anonymousUser;
+
+ private final String anonymousKey;
+
+ private final boolean useGZIPCompression;
+
+ private SyncopeClient client;
+
+ public WARestClient(
+ final String anonymousUser,
+ final String anonymousKey,
+ final boolean useGZIPCompression) {
+
+ this.anonymousUser = anonymousUser;
+ this.anonymousKey = anonymousKey;
+ this.useGZIPCompression = useGZIPCompression;
+ }
+
+ public SyncopeClient getSyncopeClient() {
+ synchronized (this) {
+ if (client == null && isReady()) {
+ try {
+ client = new SyncopeClientFactoryBean().
+ setAddress(getCore().getAddress()).
+ setUseCompression(useGZIPCompression).
+ create(new AnonymousAuthenticationHandler(anonymousUser, anonymousKey));
+ } catch (Exception e) {
+ LOG.error("Could not init SyncopeClient", e);
+ }
+ }
+ }
+
+ return client;
+ }
+
+ private static NetworkService getCore() {
+ try {
+ final ApplicationContext context = ApplicationContextProvider.getApplicationContext();
+ if (context == null) {
+ return null;
+ }
+
+ Collection<ServiceOps> serviceOpsList = context.getBeansOfType(ServiceOps.class).values();
+ if (serviceOpsList.isEmpty()) {
+ return null;
+ }
+ ServiceOps serviceOps = serviceOpsList.iterator().next();
+ return serviceOps.get(NetworkService.Type.CORE);
+ } catch (KeymasterException e) {
+ LOG.trace(e.getMessage());
+ }
+ return null;
+ }
+
+ public static boolean isReady() {
+ try {
+ return getCore() != null;
+ } catch (Exception e) {
+ LOG.trace(e.getMessage());
+ }
+ return false;
+ }
+}
diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWABootstrapConfiguration.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWABootstrapConfiguration.java
new file mode 100644
index 0000000..2330c3f
--- /dev/null
+++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWABootstrapConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.wa.bootstrap;
+
+import org.apache.syncope.wa.WARestClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+@Configuration(proxyBeanMethods = false)
+@PropertySource("classpath:wa.properties")
+@PropertySource(value = "file:${conf.directory}/wa.properties", ignoreResourceNotFound = true)
+public class SyncopeWABootstrapConfiguration {
+ @Value("${anonymousUser}")
+ private String anonymousUser;
+
+ @Value("${anonymousKey}")
+ private String anonymousKey;
+
+ @Value("${useGZIPCompression}")
+ private boolean useGZIPCompression;
+
+ @Bean
+ public WARestClient waRestClient() {
+ return new WARestClient(anonymousUser, anonymousKey, useGZIPCompression);
+ }
+
+ @Autowired
+ @Bean
+ public PropertySourceLocator configPropertySourceLocator(final WARestClient waRestClient) {
+ return new SyncopeWAPropertySourceLocator(waRestClient);
+ }
+}
diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/RestfulCloudConfigBootstrapConfiguration.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
similarity index 55%
rename from wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/RestfulCloudConfigBootstrapConfiguration.java
rename to wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
index 262931f..22f3669 100644
--- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/RestfulCloudConfigBootstrapConfiguration.java
+++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
@@ -7,7 +7,7 @@
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
@@ -16,36 +16,42 @@
* specific language governing permissions and limitations
* under the License.
*/
+
package org.apache.syncope.wa.bootstrap;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import java.net.URI;
-import java.util.Map;
-import javax.ws.rs.core.MediaType;
-import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.wa.WARestClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
-@Configuration(value = "restfulCloudConfigBootstrapConfiguration", proxyBeanMethods = false)
-public class RestfulCloudConfigBootstrapConfiguration implements PropertySourceLocator {
+import java.util.HashMap;
+import java.util.Map;
+
+@Order
+public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
+ private static final Logger LOG = LoggerFactory.getLogger(SyncopeWABootstrapConfiguration.class);
- private static final ObjectMapper MAPPER = new ObjectMapper().findAndRegisterModules();
+ private final WARestClient waRestClient;
+
+ public SyncopeWAPropertySourceLocator(final WARestClient waRestClient) {
+ this.waRestClient = waRestClient;
+ }
@Override
public PropertySource<?> locate(final Environment environment) {
try {
- String content = WebClient.create(URI.create("https://demo5926981.mockable.io/casproperties")).
- accept(MediaType.APPLICATION_JSON_TYPE).
- get().
- readEntity(String.class);
-
- Map<String, Object> payload = MAPPER.readValue(content, new TypeReference<Map<String, Object>>() {
- });
- return new MapPropertySource(getClass().getName(), payload);
+ Map<String, Object> properties = new HashMap<>();
+ if (WARestClient.isReady()) {
+ LOG.info("Bootstrapping WA configuration");
+ return new MapPropertySource(getClass().getName(), properties);
+ }
+
+ LOG.warn("Application context is not ready to bootstrap WA configuration");
+ return null;
} catch (Exception e) {
throw new IllegalArgumentException("Unable to fetch settings", e);
}
diff --git a/wa/bootstrap/src/main/resources/META-INF/spring.factories b/wa/bootstrap/src/main/resources/META-INF/spring.factories
index 4cd20b8..0729129 100644
--- a/wa/bootstrap/src/main/resources/META-INF/spring.factories
+++ b/wa/bootstrap/src/main/resources/META-INF/spring.factories
@@ -16,4 +16,4 @@
# under the License.
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
- org.apache.syncope.wa.bootstrap.RestfulCloudConfigBootstrapConfiguration
+ org.apache.syncope.wa.bootstrap.SyncopeWABootstrapConfiguration
diff --git a/wa/starter/pom.xml b/wa/starter/pom.xml
index 3fa2b65..afd48ac 100644
--- a/wa/starter/pom.xml
+++ b/wa/starter/pom.xml
@@ -90,6 +90,14 @@ under the License.
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-core-services-registry</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-core-services-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-tickets</artifactId>
</dependency>
<dependency>
@@ -146,10 +154,30 @@ under the License.
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-support-radius</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-support-radius-mfa</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-support-saml-idp</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-support-saml-idp-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-oidc</artifactId>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-support-oauth-services</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-validation</artifactId>
</dependency>
<dependency>
@@ -176,6 +204,21 @@ under the License.
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-webapp-config</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-support-oidc-services</artifactId>
+ <version>6.2.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-core-authentication-attributes</artifactId>
+ <version>6.2.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-core-services-authentication</artifactId>
+ <version>6.2.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -197,6 +240,11 @@ under the License.
</dependency>
<dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.syncope.common.keymaster</groupId>
<artifactId>syncope-common-keymaster-client-zookeeper</artifactId>
<version>${project.version}</version>
@@ -273,7 +321,6 @@ under the License.
<groupId>org.apache.syncope.common.keymaster</groupId>
<artifactId>syncope-common-keymaster-client-zookeeper</artifactId>
<version>${project.version}</version>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/mapper/RegisteredServiceMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/mapper/RegisteredServiceMapper.java
new file mode 100644
index 0000000..c81d1a7
--- /dev/null
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/mapper/RegisteredServiceMapper.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.wa.mapper;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import org.apache.syncope.common.lib.policy.AllowedAttrReleasePolicyConf;
+import org.apache.syncope.common.lib.policy.DefaultAccessPolicyConf;
+import org.apache.syncope.common.lib.policy.DefaultAuthPolicyConf;
+import org.apache.syncope.common.lib.policy.DefaultAuthPolicyCriteriaConf;
+import org.apache.syncope.common.lib.to.RegisteredClientAppTO;
+import org.apache.syncope.common.lib.to.client.OIDCRPTO;
+import org.apache.syncope.common.lib.to.client.SAML2SPTO;
+import org.apache.syncope.common.lib.types.OIDCSubjectType;
+import org.apache.syncope.common.lib.types.SAML2SPNameId;
+import org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy;
+import org.apereo.cas.services.DefaultRegisteredServiceAuthenticationPolicy;
+import org.apereo.cas.services.DenyAllAttributeReleasePolicy;
+import org.apereo.cas.services.OidcRegisteredService;
+import org.apereo.cas.services.RegisteredService;
+import org.apereo.cas.services.RegisteredServiceAccessStrategy;
+import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
+import org.apereo.cas.services.AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria;
+import org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy;
+import org.apereo.cas.support.saml.services.SamlRegisteredService;
+
+public class RegisteredServiceMapper {
+
+ public RegisteredService toRegisteredService(final RegisteredClientAppTO clientApp) {
+
+ DefaultRegisteredServiceAuthenticationPolicy authenticationPolicy =
+ new DefaultRegisteredServiceAuthenticationPolicy();
+ AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria criteria =
+ new AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria();
+ criteria.setTryAll(((DefaultAuthPolicyCriteriaConf) clientApp.getAuthPolicyConf().getCriteria()).isAll());
+ authenticationPolicy.setCriteria(criteria);
+
+ RegisteredServiceAccessStrategy accessStrategy =
+ new DefaultRegisteredServiceAccessStrategy(
+ clientApp.getAccessPolicyConf().isEnabled(), clientApp.getAccessPolicyConf().isSsoEnabled());
+ accessStrategy.getRequiredAttributes().putAll(clientApp.getAccessPolicyConf().getRequiredAttributes());
+
+ RegisteredServiceAttributeReleasePolicy attributeReleasePolicy;
+ if (clientApp.getAttrReleasePolicyConf() != null
+ && clientApp.getAttrReleasePolicyConf() instanceof AllowedAttrReleasePolicyConf
+ && !((AllowedAttrReleasePolicyConf) clientApp.getAttrReleasePolicyConf()).
+ getAllowedAttributes().isEmpty()) {
+ attributeReleasePolicy = new ReturnAllowedAttributeReleasePolicy();
+ ((AllowedAttrReleasePolicyConf) clientApp.getAttrReleasePolicyConf()).getAllowedAttributes();
+ ((ReturnAllowedAttributeReleasePolicy) attributeReleasePolicy).getAllowedAttributes().addAll(
+ ((AllowedAttrReleasePolicyConf) clientApp.getAttrReleasePolicyConf()).getAllowedAttributes());
+ } else {
+ attributeReleasePolicy = new DenyAllAttributeReleasePolicy();
+ }
+
+ if (clientApp.getClientAppTO() instanceof OIDCRPTO) {
+ OIDCRPTO rp = OIDCRPTO.class.cast(clientApp.getClientAppTO());
+ OidcRegisteredService registeredService = new OidcRegisteredService();
+
+ String redirectURIs = String.join("|", rp.getRedirectUris());
+ registeredService.setServiceId(redirectURIs);
+ registeredService.setName(rp.getName());
+ registeredService.setDescription(rp.getDescription());
+ registeredService.setAccessStrategy(accessStrategy);
+ registeredService.setAuthenticationPolicy(authenticationPolicy);
+ registeredService.setAttributeReleasePolicy(attributeReleasePolicy);
+
+ registeredService.setClientId(rp.getClientId());
+ registeredService.setClientSecret(rp.getClientSecret());
+ registeredService.setSignIdToken(rp.isSignIdToken());
+ registeredService.setJwks(rp.getJwks());
+ registeredService.setSubjectType(rp.getSubjectType().name());
+ registeredService.setRedirectUrl(redirectURIs);
+ registeredService.setSupportedGrantTypes((HashSet<String>) rp.getSupportedGrantTypes());
+ registeredService.setSupportedResponseTypes((HashSet<String>) rp.getSupportedResponseTypes());
+
+ return registeredService;
+ } else if (clientApp.getClientAppTO() instanceof SAML2SPTO) {
+ SAML2SPTO sp = SAML2SPTO.class.cast(clientApp.getClientAppTO());
+ SamlRegisteredService registeredService = new SamlRegisteredService();
+
+ registeredService.setServiceId(sp.getEntityId());
+ registeredService.setName(sp.getName());
+ registeredService.setDescription(sp.getDescription());
+ registeredService.setAccessStrategy(accessStrategy);
+ registeredService.setAuthenticationPolicy(authenticationPolicy);
+ registeredService.setAttributeReleasePolicy(attributeReleasePolicy);
+
+ registeredService.setMetadataLocation(sp.getMetadataLocation());
+ registeredService.setMetadataSignatureLocation(sp.getMetadataSignatureLocation());
+ registeredService.setSignAssertions(sp.isSignAssertions());
+ registeredService.setSignResponses(sp.isSignResponses());
+ registeredService.setEncryptionOptional(sp.isEncryptionOptional());
+ registeredService.setEncryptAssertions(sp.isEncryptAssertions());
+ registeredService.setRequiredAuthenticationContextClass(sp.getRequiredAuthenticationContextClass());
+ registeredService.setRequiredNameIdFormat(sp.getRequiredNameIdFormat().getNameId());
+ registeredService.setSkewAllowance(sp.getSkewAllowance());
+ registeredService.setNameIdQualifier(sp.getNameIdQualifier());
+ registeredService.setAssertionAudiences(sp.getAssertionAudiences());
+ registeredService.setServiceProviderNameIdQualifier(sp.getServiceProviderNameIdQualifier());
+ return registeredService;
+ }
+ return null;
+ }
+
+ public RegisteredClientAppTO fromRegisteredService(final RegisteredService registeredService) {
+ RegisteredClientAppTO clientApp = new RegisteredClientAppTO();
+
+ if (registeredService.getAuthenticationPolicy() != null) {
+ DefaultAuthPolicyConf authPolicyConf = new DefaultAuthPolicyConf();
+ DefaultAuthPolicyCriteriaConf criteria = new DefaultAuthPolicyCriteriaConf();
+ criteria.setAll(((DefaultAuthPolicyCriteriaConf) registeredService.
+ getAuthenticationPolicy().getCriteria()).isAll());
+ authPolicyConf.setCriteria(criteria);
+
+ clientApp.setAuthPolicyConf(authPolicyConf);
+ }
+
+ if (registeredService.getAccessStrategy() != null) {
+ DefaultAccessPolicyConf accessPolicyConf = new DefaultAccessPolicyConf();
+ accessPolicyConf.setEnabled(
+ ((DefaultRegisteredServiceAccessStrategy) registeredService.getAccessStrategy()).
+ isEnabled());
+ accessPolicyConf.setSsoEnabled(((DefaultRegisteredServiceAccessStrategy) registeredService.
+ getAccessStrategy()).
+ isSsoEnabled());
+ accessPolicyConf.getRequiredAttributes().putAll(((DefaultRegisteredServiceAccessStrategy) registeredService.
+ getAccessStrategy()).getRejectedAttributes());
+
+ clientApp.setAccessPolicyConf(accessPolicyConf);
+ }
+
+ if (registeredService.getAttributeReleasePolicy() != null) {
+
+ if (registeredService.getAttributeReleasePolicy() instanceof ReturnAllowedAttributeReleasePolicy) {
+ ReturnAllowedAttributeReleasePolicy returnAllowedAttributeReleasePolicy =
+ ReturnAllowedAttributeReleasePolicy.class.cast(registeredService.getAttributeReleasePolicy());
+ AllowedAttrReleasePolicyConf allowedAttrReleasePolicyConf = new AllowedAttrReleasePolicyConf();
+ allowedAttrReleasePolicyConf.getAllowedAttributes().addAll(returnAllowedAttributeReleasePolicy.
+ getAllowedAttributes());
+
+ clientApp.setAttrReleasePolicyConf(allowedAttrReleasePolicyConf);
+ }
+ }
+
+ if (registeredService instanceof OidcRegisteredService) {
+ OidcRegisteredService oidcRegisteredService = OidcRegisteredService.class.cast(registeredService);
+ OIDCRPTO oidcrpto = new OIDCRPTO();
+
+ Arrays.asList(registeredService.getServiceId().split("|")).forEach(redirectURI
+ -> oidcrpto.getRedirectUris().add(redirectURI));
+ oidcrpto.setName(oidcRegisteredService.getName());
+ oidcrpto.setDescription(oidcRegisteredService.getDescription());
+ oidcrpto.setClientId(oidcRegisteredService.getClientId());
+ oidcrpto.setClientSecret(oidcRegisteredService.getClientSecret());
+ oidcrpto.setSignIdToken(oidcRegisteredService.isSignIdToken());
+ oidcrpto.setJwks(oidcRegisteredService.getJwks());
+ oidcrpto.setSubjectType(OIDCSubjectType.valueOf(oidcRegisteredService.getSubjectType()));
+ oidcrpto.getSupportedGrantTypes().addAll(oidcRegisteredService.getSupportedGrantTypes());
+ oidcrpto.getSupportedResponseTypes().addAll(oidcRegisteredService.getSupportedResponseTypes());
+
+ clientApp.setClientAppTO(oidcrpto);
+ } else if (registeredService instanceof SamlRegisteredService) {
+ SamlRegisteredService samlRegisteredService = SamlRegisteredService.class.cast(registeredService);
+ SAML2SPTO saml2spto = new SAML2SPTO();
+
+ saml2spto.setEntityId(samlRegisteredService.getServiceId());
+ saml2spto.setName(samlRegisteredService.getName());
+ saml2spto.setDescription(samlRegisteredService.getDescription());
+
+ saml2spto.setMetadataLocation(samlRegisteredService.getMetadataLocation());
+ saml2spto.setMetadataSignatureLocation(samlRegisteredService.getMetadataSignatureLocation());
+ saml2spto.setSignAssertions(samlRegisteredService.isSignAssertions());
+ saml2spto.setSignResponses(samlRegisteredService.isSignResponses());
+ saml2spto.setEncryptionOptional(samlRegisteredService.isEncryptionOptional());
+ saml2spto.setEncryptAssertions(samlRegisteredService.isEncryptAssertions());
+ saml2spto.setRequiredAuthenticationContextClass(samlRegisteredService.
+ getRequiredAuthenticationContextClass());
+ saml2spto.setRequiredNameIdFormat(SAML2SPNameId.valueOf(samlRegisteredService.getRequiredNameIdFormat()));
+ saml2spto.setSkewAllowance(samlRegisteredService.getSkewAllowance());
+ saml2spto.setNameIdQualifier(samlRegisteredService.getNameIdQualifier());
+ saml2spto.setAssertionAudiences(samlRegisteredService.getAssertionAudiences());
+ saml2spto.setServiceProviderNameIdQualifier(samlRegisteredService.getServiceProviderNameIdQualifier());
+
+ clientApp.setClientAppTO(saml2spto);
+ }
+ return clientApp;
+ }
+}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java
index 4d5d43a..887ad97 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java
@@ -24,8 +24,18 @@ import org.apereo.cas.util.AsciiArtUtils;
import org.apereo.cas.util.DateTimeUtils;
import org.apache.commons.lang.StringUtils;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDetail;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobKey;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
@@ -43,13 +53,19 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+
@PropertySource("classpath:wa.properties")
@PropertySource(value = "file:${conf.directory}/wa.properties", ignoreResourceNotFound = true)
@SpringBootApplication(exclude = {
@@ -75,10 +91,32 @@ public class SyncopeWAApplication extends SpringBootServletInitializer {
private static final Logger LOG = LoggerFactory.getLogger(SyncopeWAApplication.class);
+ @Autowired
+ private ContextRefresher contextRefresher;
+
+ @Autowired
+ private SchedulerFactoryBean scheduler;
+
+ @Value("${contextRefreshDelay:15}")
+ private long contextRefreshDelay;
+
public static void main(final String[] args) {
new SpringApplicationBuilder(SyncopeWAApplication.class).run(args);
}
+ private static void advertiseReady(final ApplicationReadyEvent event) {
+ AsciiArtUtils.printAsciiArtReady(LOG, StringUtils.EMPTY);
+ LOG.info("Ready to process requests @ [{}]", DateTimeUtils.zonedDateTimeOf(event.getTimestamp()));
+ }
+
+ private static void validateConfiguration(final ApplicationReadyEvent event) {
+ if (!Boolean.getBoolean("SKIP_CONFIG_VALIDATION")) {
+ CasConfigurationPropertiesValidator validator =
+ new CasConfigurationPropertiesValidator(event.getApplicationContext());
+ validator.validate();
+ }
+ }
+
/**
* Handle application ready event.
*
@@ -86,13 +124,33 @@ public class SyncopeWAApplication extends SpringBootServletInitializer {
*/
@EventListener
public void handleApplicationReadyEvent(final ApplicationReadyEvent event) {
- if (!Boolean.getBoolean("SKIP_CONFIG_VALIDATION")) {
- CasConfigurationPropertiesValidator validator =
- new CasConfigurationPropertiesValidator(event.getApplicationContext());
- validator.validate();
+ validateConfiguration(event);
+ scheduleJobToRefreshContext();
+ advertiseReady(event);
+ }
+
+ private void scheduleJobToRefreshContext() {
+ try {
+ Date date = Date.from(LocalDateTime.now().plusSeconds(this.contextRefreshDelay).
+ atZone(ZoneId.systemDefault()).toInstant());
+ Trigger trigger = TriggerBuilder.newTrigger().startAt(date).build();
+ JobKey jobKey = new JobKey(getClass().getSimpleName());
+
+ JobDetail job = JobBuilder.newJob(RefreshApplicationContextJob.class).withIdentity(jobKey).build();
+ scheduler.getScheduler().scheduleJob(job, trigger);
+ } catch (SchedulerException e) {
+ throw new RuntimeException("Could not schedule refresh job", e);
}
+ }
- AsciiArtUtils.printAsciiArtReady(LOG, StringUtils.EMPTY);
- LOG.info("Ready to process requests @ [{}]", DateTimeUtils.zonedDateTimeOf(event.getTimestamp()));
+ private class RefreshApplicationContextJob implements Job {
+ @Override
+ public void execute(final JobExecutionContext jobExecutionContext) {
+ try {
+ LOG.debug("Refreshed context: {}", contextRefresher.refresh());
+ } catch (final Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
}
}
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAConfiguration.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAConfiguration.java
index 16375c3..07661e0 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAConfiguration.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAConfiguration.java
@@ -18,24 +18,36 @@
*/
package org.apache.syncope.wa.starter;
-import java.io.Serializable;
-import org.apereo.cas.services.DefaultRegisteredServiceEntityMapper;
-import org.apereo.cas.services.RegisteredService;
-import org.apereo.cas.services.RegisteredServiceEntityMapper;
+import java.util.Collection;
import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.apache.syncope.wa.WARestClient;
+import org.apache.syncope.wa.starter.rest.SyncopeServiceRegistry;
+import org.apereo.cas.services.ServiceRegistryExecutionPlanConfigurer;
+import org.apereo.cas.services.ServiceRegistryListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-@Configuration(proxyBeanMethods = false)
+@Configuration
public class SyncopeWAConfiguration {
+ @Autowired
+ private ConfigurableApplicationContext applicationContext;
+
+ @Autowired
+ @Qualifier("serviceRegistryListeners")
+ private Collection<ServiceRegistryListener> serviceRegistryListeners;
+
+ @Autowired
@Bean
- @ConditionalOnProperty(name = "cas.serviceRegistry.rest.url")
- public RegisteredServiceEntityMapper<RegisteredService, Serializable> registeredServiceEntityMapper() {
- return new DefaultRegisteredServiceEntityMapper();
+ public ServiceRegistryExecutionPlanConfigurer syncopeServiceRegistryConfigurer(final WARestClient restClient) {
+ SyncopeServiceRegistry registry =
+ new SyncopeServiceRegistry(restClient, applicationContext, serviceRegistryListeners);
+ return plan -> plan.registerServiceRegistry(registry);
}
@Bean
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/rest/SyncopeServiceRegistry.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/rest/SyncopeServiceRegistry.java
new file mode 100644
index 0000000..b042262
--- /dev/null
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/rest/SyncopeServiceRegistry.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.wa.starter.rest;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.types.ClientAppType;
+import org.apache.syncope.common.rest.api.service.RegisteredClientAppService;
+import org.apache.syncope.wa.WARestClient;
+import org.apache.syncope.wa.mapper.RegisteredServiceMapper;
+import org.apereo.cas.services.AbstractServiceRegistry;
+import org.apereo.cas.services.OidcRegisteredService;
+import org.apereo.cas.services.RegisteredService;
+import org.apereo.cas.services.ServiceRegistryListener;
+import org.apereo.cas.support.saml.services.SamlRegisteredService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ConfigurableApplicationContext;
+
+public class SyncopeServiceRegistry extends AbstractServiceRegistry {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SyncopeServiceRegistry.class);
+
+ private final WARestClient restClient;
+
+ private final RegisteredServiceMapper mapper;
+
+ public SyncopeServiceRegistry(final WARestClient restClient,
+ final ConfigurableApplicationContext applicationContext,
+ final Collection<ServiceRegistryListener> serviceRegistryListeners) {
+
+ super(applicationContext, serviceRegistryListeners);
+ this.restClient = restClient;
+ this.mapper = new RegisteredServiceMapper();
+ }
+
+ @Override
+ public RegisteredService save(final RegisteredService registeredService) {
+ if (WARestClient.isReady()) {
+ LOG.info("Create application definitions");
+ Response response =
+ restClient.getSyncopeClient().getService(RegisteredClientAppService.class).create(mapper.
+ fromRegisteredService(registeredService));
+ if (response.getStatusInfo().getStatusCode() == Response.Status.CREATED.getStatusCode()) {
+ return registeredService;
+ }
+ }
+ LOG.debug("Syncope client is not yet ready to fetch application definitions");
+ return null;
+ }
+
+ @Override
+ public boolean delete(final RegisteredService registeredService) {
+ if (WARestClient.isReady()) {
+ LOG.info("Delete application definitions");
+ return restClient.getSyncopeClient().getService(RegisteredClientAppService.class).
+ delete(registeredService.getName());
+ }
+ LOG.debug("Syncope client is not yet ready to fetch application definitions");
+ return false;
+ }
+
+ @Override
+ public Collection<RegisteredService> load() {
+ if (WARestClient.isReady()) {
+ LOG.info("Loading application definitions");
+ return restClient.getSyncopeClient().getService(RegisteredClientAppService.class).list().stream().
+ map(clientApp -> mapper.toRegisteredService(clientApp)).collect(Collectors.toList());
+ }
+ LOG.debug("Syncope client is not yet ready to fetch application definitions");
+ return List.of();
+ }
+
+ @Override
+ public RegisteredService findServiceById(final long id) {
+ if (WARestClient.isReady()) {
+ LOG.info("Searching for application definition by id {}", id);
+ return mapper.toRegisteredService(restClient.getSyncopeClient().
+ getService(RegisteredClientAppService.class).read(id));
+ }
+ LOG.debug("Syncope client is not yet ready to fetch application definitions");
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends RegisteredService> T findServiceByExactServiceName(final String name, final Class<T> clazz) {
+ if (WARestClient.isReady()) {
+ LOG.info("Searching for application definition by name {} and type {}", name, clazz);
+ if (clazz.isInstance(OidcRegisteredService.class)) {
+ return (T) mapper.toRegisteredService(restClient.getSyncopeClient().
+ getService(RegisteredClientAppService.class).read(name, ClientAppType.OIDCRP));
+ } else if (clazz.isInstance(SamlRegisteredService.class)) {
+ return (T) mapper.toRegisteredService(restClient.getSyncopeClient().
+ getService(RegisteredClientAppService.class).read(name, ClientAppType.SAML2SP));
+ }
+ }
+ LOG.debug("Syncope client is not yet ready to fetch application definitions");
+ return null;
+ }
+
+ @Override
+ public RegisteredService findServiceByExactServiceName(final String name) {
+ if (WARestClient.isReady()) {
+ LOG.info("Searching for application definition by name {}", name);
+ return mapper.toRegisteredService(restClient.getSyncopeClient().
+ getService(RegisteredClientAppService.class).read(name));
+ }
+ LOG.debug("Syncope client is not yet ready to fetch application definitions");
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends RegisteredService> T findServiceById(final long id, final Class<T> clazz) {
+ if (WARestClient.isReady()) {
+ LOG.info("Searching for application definition by id {} and type {}", id, clazz);
+ if (clazz.isInstance(OidcRegisteredService.class)) {
+ return (T) mapper.toRegisteredService(restClient.getSyncopeClient().
+ getService(RegisteredClientAppService.class).read(id, ClientAppType.OIDCRP));
+ } else if (clazz.isInstance(SamlRegisteredService.class)) {
+ return (T) mapper.toRegisteredService(restClient.getSyncopeClient().
+ getService(RegisteredClientAppService.class).read(id, ClientAppType.SAML2SP));
+ }
+ }
+ LOG.debug("Syncope client is not yet ready to fetch application definitions");
+ return null;
+ }
+
+}
diff --git a/wa/starter/src/main/resources/application.properties b/wa/starter/src/main/resources/application.properties
index 5ad1d51..1104f29 100644
--- a/wa/starter/src/main/resources/application.properties
+++ b/wa/starter/src/main/resources/application.properties
@@ -28,9 +28,13 @@ server.servlet.contextPath=/syncope-wa
spring.resources.static-locations=classpath:/thymeleaf/static,classpath:/static
-management.endpoints.web.exposure.include=health,loggers
+management.endpoints.web.exposure.include=health,loggers,refresh
management.endpoint.health.show-details=always
+management.endpoint.health.enabled=true
+management.endpoint.loggers.enabled=true
+management.endpoint.refresh.enabled=true
+
##
# Allow configuration classes to override bean definitions from Spring Boot
#
diff --git a/wa/starter/src/main/resources/wa.properties b/wa/starter/src/main/resources/wa.properties
index 5d1ef1c..c98a6e7 100644
--- a/wa/starter/src/main/resources/wa.properties
+++ b/wa/starter/src/main/resources/wa.properties
@@ -24,6 +24,13 @@ conf.directory=${conf.directory}
cas.standalone.configurationDirectory=${conf.directory}
cas.authn.oidc.jwks.jwksFile=file:${conf.directory}/oidc.keystore
+cas.server.name=http://localhost:8080
+cas.server.prefix=${cas.server.name}/syncope-wa
+cas.server.scope=syncope.org
+
+cas.authn.samlIdp.entityId=https://syncope.apache.org/saml
+cas.authn.samlIdp.metadata.location=file:${conf.directory}
+
# Disable access to the login endpoint
# if no target application is specified.
cas.sso.allow-missing-service-parameter=true
@@ -31,3 +38,15 @@ cas.sso.allow-missing-service-parameter=true
# Disable the acceptable usage policy
# by default for now.
cas.acceptableUsagePolicy.enabled=false
+
+management.endpoints.web.exposure.include=health,loggers,refresh
+management.endpoint.health.show-details=always
+
+management.endpoint.health.enabled=true
+management.endpoint.loggers.enabled=true
+management.endpoint.refresh.enabled=true
+
+cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
+
+spring.security.user.name=${anonymousUser}
+spring.security.user.password=${anonymousKey}