This is an automated email from the ASF dual-hosted git repository.
mmoayyed 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 2fa7e28 Switch CAS to use 6.5.x / Spring Boot 2.6.x (#296)
2fa7e28 is described below
commit 2fa7e28874acfeca8b6124ffec94d7f0a2d0d9ba
Author: Misagh Moayyed <[email protected]>
AuthorDate: Fri Dec 10 09:18:45 2021 +0400
Switch CAS to use 6.5.x / Spring Boot 2.6.x (#296)
* switch cas to use 6.5 rc2
* resume with boot 2.6 upgrade
* update spring cloud gateway
* upgrade to boot 2.6
* Upgrading Groovy
* Fix test cases; make sure exceptions are caught in SAML2 metadata
generation process
* assign a name to the syncope authn handler matching master-content and
auth-module
* Upgrading Tomcat
* Upgrading Spring Boot
* Upgrading Payara
* Upgrading Wildfly
* Getting Started Guide: reviewed for 3.0
* [SYNCOPE-1651] Reviewing delegation validation logic
* Upgrading gmavenplus-plugin
* Reference Guide reviewed and compelted for 3.0 up to Customization
* Typos in Reference Guide 3.0
* [SYNCOPE-1654] Allowing to search realm by key or full path
* Upgrading Swagger UI and Checkstyle
* Upgrading Bouncycastle
* Upgrading Wicket
* upgrade to spring boot 2.6; fixes build issues
* fix checkstyle
* restore spring cloud contract wiremock version
* update pac4j to match latest CAS 6.5 SNAPSHOT
Co-authored-by: Francesco Chicchiriccò <[email protected]>
---
client/idrepo/console/pom.xml | 2 +-
.../console/src/main/resources/console.properties | 1 +
client/idrepo/enduser/pom.xml | 2 +-
.../enduser/src/main/resources/enduser.properties | 1 +
.../enduser/SyncopeEnduserApplicationTest.java | 2 -
.../syncope/common/lib/types/AMEntitlement.java | 2 +
.../common/rest/api/service/OIDCJWKSService.java | 8 +++
.../apache/syncope/core/logic/OIDCJWKSLogic.java | 8 +++
.../core/rest/cxf/service/OIDCJWKSServiceImpl.java | 5 ++
core/starter/pom.xml | 2 +-
fit/build-tools/pom.xml | 2 +-
.../src/main/resources/application.properties | 1 +
.../org/apache/syncope/fit/AbstractITCase.java | 2 -
.../src/main/resources/wa-embedded.properties | 7 +++
pom.xml | 30 +++++++---
sra/pom.xml | 2 +-
.../org/apache/syncope/sra/SecurityConfig.java | 8 ++-
.../bootstrap/SyncopeWABootstrapConfiguration.java | 32 ++++++-----
.../syncope/wa/starter/SyncopeWAApplication.java | 7 ++-
.../wa/starter/config/SyncopeWAConfiguration.java | 64 +++++++++++++---------
.../starter/events/SyncopeWAEventRepository.java | 5 +-
.../oidc/SyncopeWAOIDCJWKSGeneratorService.java | 24 +++++++-
.../metadata/RestfulSamlIdPMetadataLocator.java | 11 +++-
wa/starter/src/main/resources/wa.properties | 11 +++-
.../audit/SyncopeWAAuditTrailManagerTest.java | 2 +-
.../src/test/resources/debug/wa-debug.properties | 11 +++-
26 files changed, 180 insertions(+), 72 deletions(-)
diff --git a/client/idrepo/console/pom.xml b/client/idrepo/console/pom.xml
index 31ca830..c0ba1d6 100644
--- a/client/idrepo/console/pom.xml
+++ b/client/idrepo/console/pom.xml
@@ -124,7 +124,7 @@ under the License.
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j18-impl</artifactId>
+ <artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
diff --git a/client/idrepo/console/src/main/resources/console.properties
b/client/idrepo/console/src/main/resources/console.properties
index bf17a78..723e8e3 100644
--- a/client/idrepo/console/src/main/resources/console.properties
+++ b/client/idrepo/console/src/main/resources/console.properties
@@ -17,6 +17,7 @@
spring.application.name=Apache Syncope ${syncope.version} Console
spring.groovy.template.check-template-location=false
spring.main.banner-mode=log
+spring.main.allow-circular-references=true
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
diff --git a/client/idrepo/enduser/pom.xml b/client/idrepo/enduser/pom.xml
index 6c127c7..f6b10eb 100644
--- a/client/idrepo/enduser/pom.xml
+++ b/client/idrepo/enduser/pom.xml
@@ -112,7 +112,7 @@ under the License.
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j18-impl</artifactId>
+ <artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
diff --git a/client/idrepo/enduser/src/main/resources/enduser.properties
b/client/idrepo/enduser/src/main/resources/enduser.properties
index a10cbce..a9f6930 100644
--- a/client/idrepo/enduser/src/main/resources/enduser.properties
+++ b/client/idrepo/enduser/src/main/resources/enduser.properties
@@ -17,6 +17,7 @@
spring.application.name=Apache Syncope ${syncope.version} Enduser
spring.groovy.template.check-template-location=false
spring.main.banner-mode=log
+spring.main.allow-circular-references=true
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
diff --git
a/client/idrepo/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java
b/client/idrepo/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java
index fa678ca..b9227a7 100644
---
a/client/idrepo/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java
+++
b/client/idrepo/enduser/src/test/java/org/apache/syncope/client/enduser/SyncopeEnduserApplicationTest.java
@@ -25,8 +25,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.security.AccessControlException;
-import java.util.Enumeration;
-import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.ws.rs.BadRequestException;
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
index 1935279..305deca 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
@@ -88,6 +88,8 @@ public final class AMEntitlement {
public static final String OIDC_JWKS_READ = "OIDC_JWKS_READ";
+ public static final String OIDC_JWKS_SET = "OIDC_JWKS_SET";
+
public static final String OIDC_JWKS_DELETE = "OIDC_JWKS_DELETE";
public static final String WA_CONFIG_LIST = "WA_CONFIG_LIST";
diff --git
a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
index e108097..53eb241 100644
---
a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
+++
b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
@@ -52,6 +52,13 @@ public interface OIDCJWKSService extends JAXRSService {
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML,
MediaType.APPLICATION_XML })
OIDCJWKSTO get();
+ @ApiResponses(
+ @ApiResponse(responseCode = "204", description = "Operation was
successful"))
+ @POST
+ @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML,
MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML,
MediaType.APPLICATION_XML })
+ void set(@NotNull OIDCJWKSTO entityTO);
+
@ApiResponses({
@ApiResponse(responseCode = "201",
description = "JWKS successfully created", headers = {
@@ -63,6 +70,7 @@ public interface OIDCJWKSService extends JAXRSService {
@POST
@Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML,
MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML,
MediaType.APPLICATION_XML })
+ @Path("new")
Response generate(
@NotNull @QueryParam("size") @DefaultValue("2048") int size,
@NotNull @QueryParam("algorithm") @DefaultValue("RS256")
JWSAlgorithm algorithm);
diff --git
a/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
b/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
index 0e03700..e105e82 100644
---
a/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
+++
b/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
@@ -76,4 +76,12 @@ public class OIDCJWKSLogic extends
AbstractTransactionalLogic<OIDCJWKSTO> {
}
return binder.getOIDCJWKSTO(jwks);
}
+
+ @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_SET + "') "
+ + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+ public OIDCJWKSTO set(final OIDCJWKSTO entityTO) {
+ OIDCJWKS jwks = dao.get();
+ jwks.setJson(entityTO.getJson());
+ return binder.getOIDCJWKSTO(dao.save(jwks));
+ }
}
diff --git
a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
index a4fcb71..ded23ea 100644
---
a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
+++
b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
@@ -41,6 +41,11 @@ public class OIDCJWKSServiceImpl extends AbstractService
implements OIDCJWKSServ
}
@Override
+ public void set(final OIDCJWKSTO entityTO) {
+ logic.set(entityTO);
+ }
+
+ @Override
public Response generate(final int size, final JWSAlgorithm algorithm) {
OIDCJWKSTO jwks = logic.generate(size, algorithm);
URI location = uriInfo.getAbsolutePathBuilder().build();
diff --git a/core/starter/pom.xml b/core/starter/pom.xml
index 0cee5ae..3bf08a6 100644
--- a/core/starter/pom.xml
+++ b/core/starter/pom.xml
@@ -83,7 +83,7 @@ under the License.
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j18-impl</artifactId>
+ <artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
diff --git a/fit/build-tools/pom.xml b/fit/build-tools/pom.xml
index 2b5808c..a3319d9 100644
--- a/fit/build-tools/pom.xml
+++ b/fit/build-tools/pom.xml
@@ -203,7 +203,7 @@ under the License.
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j18-impl</artifactId>
+ <artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
diff --git a/fit/build-tools/src/main/resources/application.properties
b/fit/build-tools/src/main/resources/application.properties
index 9e8bdb3..6ee9cb4 100644
--- a/fit/build-tools/src/main/resources/application.properties
+++ b/fit/build-tools/src/main/resources/application.properties
@@ -17,6 +17,7 @@
spring.application.name=Apache Syncope ${syncope.version} Build Tools
spring.groovy.template.check-template-location=false
#spring.main.banner-mode=log
+spring.main.allow-circular-references=true
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
diff --git
a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index c52de8a..933e1d2 100644
---
a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++
b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -18,8 +18,6 @@
*/
package org.apache.syncope.fit;
-import static org.apache.syncope.fit.AbstractUIITCase.ANONYMOUS_KEY;
-import static org.apache.syncope.fit.AbstractUIITCase.ANONYMOUS_UNAME;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
diff --git a/fit/wa-reference/src/main/resources/wa-embedded.properties
b/fit/wa-reference/src/main/resources/wa-embedded.properties
index 87fae00..6eb99fd 100644
--- a/fit/wa-reference/src/main/resources/wa-embedded.properties
+++ b/fit/wa-reference/src/main/resources/wa-embedded.properties
@@ -14,6 +14,8 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+spring.main.allow-circular-references=true
+
keymaster.address=http://localhost:9080/syncope/rest/keymaster
keymaster.username=${anonymousUser}
keymaster.password=${anonymousKey}
@@ -30,3 +32,8 @@
cas.authn.saml-idp.metadata.http.metadata-backup-location=file:${conf.directory}
cas.authn.oidc.core.issuer=${cas.server.prefix}/oidc
service.discovery.address=http://localhost:9080/syncope-wa/
+
+##
+# Default strategy for matching request paths against
+# registered Spring MVC handler mappings
+spring.mvc.pathmatch.matching-strategy=ant-path-matcher
diff --git a/pom.xml b/pom.xml
index 2a756cc..6f4a6e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -409,8 +409,8 @@ under the License.
<jackson.version>2.13.0</jackson.version>
- <spring-boot.version>2.5.7</spring-boot.version>
- <spring-cloud-gateway.version>3.0.5</spring-cloud-gateway.version>
+ <spring-boot.version>2.6.1</spring-boot.version>
+ <spring-cloud-gateway.version>3.1.0</spring-cloud-gateway.version>
<openjpa.version>3.2.0</openjpa.version>
<hikaricp.version>5.0.0</hikaricp.version>
@@ -428,7 +428,7 @@ under the License.
<camel.version>3.13.0</camel.version>
- <slf4j.version>2.0.0-alpha5</slf4j.version>
+ <slf4j.version>1.7.32</slf4j.version>
<elasticsearch.version>7.15.2</elasticsearch.version>
@@ -446,9 +446,9 @@ under the License.
<modernizer-maven.version>2.3.0</modernizer-maven.version>
- <pac4j.version>5.1.4</pac4j.version>
+ <pac4j.version>5.2.0</pac4j.version>
- <cas.version>6.4.2</cas.version>
+ <cas.version>6.5.0-SNAPSHOT</cas.version>
<cas-client.version>3.6.2</cas-client.version>
<h2.version>1.4.200</h2.version>
@@ -1740,7 +1740,7 @@ under the License.
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j18-impl</artifactId>
+ <artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
@@ -1888,9 +1888,7 @@ under the License.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-wiremock</artifactId>
- <version>3.0.4</version>
- <!-- unfortunately, not always aligned with spring-cloud-gateway -->
- <!--<version>${spring-cloud-gateway.version}</version>-->
+ <version>${spring-cloud-gateway.version}</version>
<scope>test</scope>
</dependency>
@@ -1922,6 +1920,13 @@ under the License.
<enabled>true</enabled>
</releases>
</repository>
+ <repository>
+ <id>spring</id>
+ <url>https://repo.spring.io/milestone</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ </repository>
</repositories>
<pluginRepositories>
@@ -1955,6 +1960,13 @@ under the License.
<enabled>true</enabled>
</snapshots>
</pluginRepository>
+ <pluginRepository>
+ <id>spring</id>
+ <url>https://repo.spring.io/milestone</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ </pluginRepository>
</pluginRepositories>
<build>
diff --git a/sra/pom.xml b/sra/pom.xml
index cfa3a79..8a575db 100644
--- a/sra/pom.xml
+++ b/sra/pom.xml
@@ -130,7 +130,7 @@ under the License.
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j18-impl</artifactId>
+ <artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
diff --git a/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
b/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
index 139780d..e3e75b6 100644
--- a/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
+++ b/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
@@ -63,6 +63,7 @@ import
org.springframework.security.oauth2.client.registration.ClientRegistratio
import
org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
+import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.MappedJwtClaimSetConverter;
@@ -146,8 +147,11 @@ public class SecurityConfig {
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = SRAProperties.PREFIX, name =
SRAProperties.AM_TYPE, havingValue = "OIDC")
public ReactiveJwtDecoder oidcJWTDecoder() {
- NimbusReactiveJwtDecoder jwtDecoder =
NimbusReactiveJwtDecoder.withJwkSetUri(
-
oidcClientRegistrationRepository().iterator().next().getProviderDetails().getJwkSetUri()).build();
+ String jwkSetUri =
oidcClientRegistrationRepository().iterator().next().getProviderDetails().getJwkSetUri();
+ NimbusReactiveJwtDecoder jwtDecoder =
NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri)
+ .jwsAlgorithm(SignatureAlgorithm.RS256)
+ .jwsAlgorithm(SignatureAlgorithm.RS512)
+ .build();
jwtDecoder.setJwtValidator(oidcJWTValidator());
jwtDecoder.setClaimSetConverter(jwtClaimSetConverter());
return jwtDecoder;
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
index 1d1dc2dd..d167e80 100644
---
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
@@ -30,23 +30,29 @@ import
org.springframework.context.annotation.PropertySource;
@PropertySource(value = "file:${conf.directory}/wa.properties",
ignoreResourceNotFound = true)
public class SyncopeWABootstrapConfiguration {
- @Value("${wa.anonymousUser}")
- private String anonymousUser;
+ @Configuration(proxyBeanMethods = false)
+ public static class WAClientConfiguration {
+ @Value("${wa.anonymousUser}")
+ private String anonymousUser;
- @Value("${wa.anonymousKey}")
- private String anonymousKey;
+ @Value("${wa.anonymousKey}")
+ private String anonymousKey;
- @Value("${wa.useGZIPCompression:true}")
- private boolean useGZIPCompression;
+ @Value("${wa.useGZIPCompression:true}")
+ private boolean useGZIPCompression;
- @Bean
- public WARestClient waRestClient() {
- return new WARestClient(anonymousUser, anonymousKey,
useGZIPCompression);
+ @Bean
+ public WARestClient waRestClient() {
+ return new WARestClient(anonymousUser, anonymousKey,
useGZIPCompression);
+ }
}
- @Autowired
- @Bean
- public PropertySourceLocator configPropertySourceLocator(final
WARestClient waRestClient) {
- return new SyncopeWAPropertySourceLocator(waRestClient);
+ @Configuration(proxyBeanMethods = false)
+ public static class PropertySourceConfiguration {
+ @Autowired
+ @Bean
+ public PropertySourceLocator configPropertySourceLocator(final
WARestClient waRestClient) {
+ return new SyncopeWAPropertySourceLocator(waRestClient);
+ }
}
}
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 7c4b0fd..6e83d8f 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
@@ -84,8 +84,8 @@ public class SyncopeWAApplication extends
SpringBootServletInitializer {
public static void main(final String[] args) {
new SpringApplicationBuilder(SyncopeWAApplication.class).
- properties("spring.config.name:wa").
- build().run(args);
+ properties(Map.of("spring.config.name", "wa",
"spring.cloud.bootstrap.name", "wa")).
+ build().run(args);
}
@Autowired
@@ -96,7 +96,8 @@ public class SyncopeWAApplication extends
SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(final
SpringApplicationBuilder builder) {
- return builder.properties(Map.of("spring.config.name",
"wa")).sources(SyncopeWAApplication.class);
+ return builder.properties(Map.of("spring.config.name", "wa",
+ "spring.cloud.bootstrap.name",
"wa")).sources(SyncopeWAApplication.class);
}
/**
diff --git
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
index b8bd1ed..ccb9625 100644
---
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
+++
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
@@ -27,9 +27,12 @@ import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityScheme;
import java.time.LocalDate;
import java.time.ZoneId;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart;
@@ -70,11 +73,12 @@ import
org.apereo.cas.audit.AuditTrailExecutionPlanConfigurer;
import org.apereo.cas.authentication.surrogate.SurrogateAuthenticationService;
import org.apereo.cas.configuration.CasConfigurationProperties;
import
org.apereo.cas.configuration.model.support.mfa.u2f.U2FCoreMultifactorAuthenticationProperties;
-import org.apereo.cas.oidc.jwks.OidcJsonWebKeystoreGeneratorService;
+import org.apereo.cas.oidc.jwks.generator.OidcJsonWebKeystoreGeneratorService;
import
org.apereo.cas.otp.repository.credentials.OneTimeTokenCredentialRepository;
import org.apereo.cas.otp.repository.token.OneTimeTokenRepository;
import org.apereo.cas.services.ServiceRegistryExecutionPlanConfigurer;
import org.apereo.cas.services.ServiceRegistryListener;
+import org.apereo.cas.services.web.CasThymeleafLoginFormDirector;
import org.apereo.cas.support.events.CasEventRepository;
import org.apereo.cas.support.events.CasEventRepositoryFilter;
import
org.apereo.cas.support.pac4j.authentication.DelegatedClientFactoryCustomizer;
@@ -83,8 +87,10 @@ import
org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGenerat
import org.apereo.cas.support.saml.idp.metadata.locator.SamlIdPMetadataLocator;
import org.apereo.cas.util.DateTimeUtils;
import org.apereo.cas.util.crypto.CipherExecutor;
+import org.apereo.cas.web.flow.CasWebflowExecutionPlan;
import org.apereo.cas.webauthn.storage.WebAuthnCredentialRepository;
import org.pac4j.core.client.Client;
+import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -96,31 +102,21 @@ import
org.springframework.context.annotation.Configuration;
@Configuration(value = "SyncopeWAConfiguration", proxyBeanMethods = false)
public class SyncopeWAConfiguration {
- @Autowired
- private CasConfigurationProperties casProperties;
-
- @Autowired
- private ConfigurableApplicationContext ctx;
-
- @Autowired
- @Qualifier("serviceRegistryListeners")
- private Collection<ServiceRegistryListener> serviceRegistryListeners;
-
- private String version() {
+ private static String version(final ConfigurableApplicationContext ctx) {
return ctx.getEnvironment().getProperty("version");
}
@Bean
- public OpenAPI casSwaggerOpenApi() {
+ public OpenAPI casSwaggerOpenApi(final ConfigurableApplicationContext ctx)
{
return new OpenAPI().
info(new Info().
title("Apache Syncope").
- description("Apache Syncope " + version()).
+ description("Apache Syncope " + version(ctx)).
contact(new Contact().
name("The Apache Syncope community").
email("[email protected]").
url("https://syncope.apache.org")).
- version(version())).
+ version(version(ctx))).
schemaRequirement("BasicAuthentication",
new
SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")).
schemaRequirement("Bearer",
@@ -165,7 +161,7 @@ public class SyncopeWAConfiguration {
@ConditionalOnMissingBean
@Bean
- public RegisteredServiceMapper registeredServiceMapper() {
+ public RegisteredServiceMapper registeredServiceMapper(final
ConfigurableApplicationContext ctx) {
Map<String, AuthMapper> authPolicyConfMappers = new HashMap<>();
ctx.getBeansOfType(AuthMapper.class).forEach((name, bean) -> {
AuthMapFor authMapFor = ctx.findAnnotationOnBean(name,
AuthMapFor.class);
@@ -209,10 +205,15 @@ public class SyncopeWAConfiguration {
@Autowired
@Bean
public ServiceRegistryExecutionPlanConfigurer
syncopeServiceRegistryConfigurer(
- final WARestClient restClient, final RegisteredServiceMapper
registeredServiceMapper) {
+ final ConfigurableApplicationContext ctx,
+ final WARestClient restClient,
+ final RegisteredServiceMapper registeredServiceMapper,
+ @Qualifier("serviceRegistryListeners")
+ final ObjectProvider<List<ServiceRegistryListener>>
serviceRegistryListeners) {
SyncopeWAServiceRegistry registry = new SyncopeWAServiceRegistry(
- restClient, registeredServiceMapper, ctx,
serviceRegistryListeners);
+ restClient, registeredServiceMapper, ctx,
+
Optional.ofNullable(serviceRegistryListeners.getIfAvailable()).orElseGet(ArrayList::new));
return plan -> plan.registerServiceRegistry(registry);
}
@@ -260,9 +261,10 @@ public class SyncopeWAConfiguration {
return new SyncopeWASAML2ClientCustomizer(restClient);
}
- @Autowired
@Bean
- public OneTimeTokenRepository
oneTimeTokenAuthenticatorTokenRepository(final WARestClient restClient) {
+ public OneTimeTokenRepository oneTimeTokenAuthenticatorTokenRepository(
+ final CasConfigurationProperties casProperties,
+ final WARestClient restClient) {
return new SyncopeWAGoogleMfaAuthTokenRepository(
restClient,
casProperties.getAuthn().getMfa().getGauth().getCore().getTimeStepSize());
}
@@ -277,7 +279,9 @@ public class SyncopeWAConfiguration {
@Autowired
@Bean
- public OidcJsonWebKeystoreGeneratorService
oidcJsonWebKeystoreGeneratorService(final WARestClient restClient) {
+ public OidcJsonWebKeystoreGeneratorService
oidcJsonWebKeystoreGeneratorService(
+ final ConfigurableApplicationContext ctx,
+ final WARestClient restClient) {
int size = ctx.getEnvironment().
getProperty("cas.authn.oidc.jwks.size", int.class, 2048);
JWSAlgorithm algorithm = ctx.getEnvironment().
@@ -287,15 +291,17 @@ public class SyncopeWAConfiguration {
@RefreshScope
@Bean
- @Autowired
- public WebAuthnCredentialRepository webAuthnCredentialRepository(final
WARestClient restClient) {
+ public WebAuthnCredentialRepository webAuthnCredentialRepository(
+ final CasConfigurationProperties casProperties,
+ final WARestClient restClient) {
return new SyncopeWAWebAuthnCredentialRepository(casProperties,
restClient);
}
@Bean
- @Autowired
@RefreshScope
- public U2FDeviceRepository u2fDeviceRepository(final WARestClient
restClient) {
+ public U2FDeviceRepository u2fDeviceRepository(
+ final CasConfigurationProperties casProperties,
+ final WARestClient restClient) {
U2FCoreMultifactorAuthenticationProperties u2f =
casProperties.getAuthn().getMfa().getU2f().getCore();
LocalDate expirationDate = LocalDate.now(ZoneId.systemDefault()).
minus(u2f.getExpireDevices(),
DateTimeUtils.toChronoUnit(u2f.getExpireDevicesTimeUnit()));
@@ -333,4 +339,10 @@ public class SyncopeWAConfiguration {
public KeymasterStop keymasterStop() {
return new KeymasterStop(NetworkService.Type.WA);
}
+
+ @Bean
+ public CasThymeleafLoginFormDirector casThymeleafLoginFormDirector(
+ @Qualifier("casWebflowExecutionPlan") final CasWebflowExecutionPlan
webflowExecutionPlan) {
+ return new CasThymeleafLoginFormDirector(webflowExecutionPlan);
+ }
}
diff --git
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepository.java
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepository.java
index c89eea0..69fd679 100644
---
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepository.java
+++
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/events/SyncopeWAEventRepository.java
@@ -20,10 +20,11 @@ package org.apache.syncope.wa.starter.events;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
-import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.stream.Stream;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.common.lib.audit.AuditEntry;
@@ -100,7 +101,7 @@ public class SyncopeWAEventRepository extends
AbstractCasEventRepository {
}
@Override
- public Collection<? extends CasEvent> load() {
+ public Stream<? extends CasEvent> load() {
throw new UnsupportedOperationException("Fetching authentication
events from WA is not supported");
}
}
diff --git
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
index 23f254d..830733a 100644
---
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
+++
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
@@ -18,7 +18,11 @@
*/
package org.apache.syncope.wa.starter.oidc;
+import org.apereo.cas.oidc.jwks.generator.OidcJsonWebKeystoreGeneratorService;
+
import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+
import javax.ws.rs.core.Response;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.to.OIDCJWKSTO;
@@ -26,7 +30,8 @@ import
org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.JWSAlgorithm;
import org.apache.syncope.common.rest.api.service.OIDCJWKSService;
import org.apache.syncope.wa.bootstrap.WARestClient;
-import org.apereo.cas.oidc.jwks.OidcJsonWebKeystoreGeneratorService;
+import org.jose4j.jwk.JsonWebKey;
+import org.jose4j.jwk.JsonWebKeySet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
@@ -51,6 +56,23 @@ public class SyncopeWAOIDCJWKSGeneratorService implements
OidcJsonWebKeystoreGen
}
@Override
+ public JsonWebKeySet store(final JsonWebKeySet jsonWebKeySet) throws
Exception {
+ if (!WARestClient.isReady()) {
+ throw new RuntimeException("Syncope core is not yet ready");
+ }
+ OIDCJWKSService service =
waRestClient.getSyncopeClient().getService(OIDCJWKSService.class);
+ OIDCJWKSTO to = new OIDCJWKSTO();
+
to.setJson(jsonWebKeySet.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE));
+ service.set(to);
+ return jsonWebKeySet;
+ }
+
+ @Override
+ public Optional<Resource> find() {
+ return Optional.of(generate());
+ }
+
+ @Override
public Resource generate() {
if (!WARestClient.isReady()) {
throw new RuntimeException("Syncope core is not yet ready");
diff --git
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java
index 88568e8..25352ce 100644
---
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java
+++
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java
@@ -87,11 +87,16 @@ public class RestfulSamlIdPMetadataLocator extends
AbstractSamlIdPMetadataLocato
LOG.warn("Not a valid SAML2 IdP metadata document");
return null;
- } catch (SyncopeClientException e) {
- if (e.getType() == ClientExceptionType.NotFound) {
+ } catch (Exception e) {
+ if (e instanceof SyncopeClientException
+ && ((SyncopeClientException) e).getType() ==
ClientExceptionType.NotFound) {
LOG.info(e.getMessage());
} else {
- LOG.error("While fetching SAML2 IdP metadata", e);
+ if (LOG.isDebugEnabled()) {
+ LOG.error("While fetching SAML2 IdP metadata", e);
+ } else {
+ LOG.error("While fetching SAML2 IdP metadata: " +
e.getMessage());
+ }
}
}
diff --git a/wa/starter/src/main/resources/wa.properties
b/wa/starter/src/main/resources/wa.properties
index 51840bd..281f148 100644
--- a/wa/starter/src/main/resources/wa.properties
+++ b/wa/starter/src/main/resources/wa.properties
@@ -17,6 +17,7 @@
spring.application.name=Apache Syncope ${syncope.version} WA
spring.groovy.template.check-template-location=false
spring.main.banner-mode=log
+spring.main.allow-circular-references=true
version=${syncope.version}
@@ -79,7 +80,7 @@
cas.authn.saml-idp.metadata.http.metadata-backup-location=file:${conf.directory}
cas.authn.oidc.core.issuer=${cas.server.prefix}/oidc
cas.authn.oidc.discovery.id-token-signing-alg-values-supported=RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512,HS256,HS384,HS512
cas.authn.oidc.discovery.user-info-signing-alg-values-supported=RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512,HS256,HS384,HS512
-cas.authn.oauth.user-profile-view-type=FLAT
+cas.authn.oauth.core.user-profile-view-type=FLAT
# Disable access to the login endpoint
# if no target application is specified.
@@ -102,4 +103,10 @@
cas.authn.mfa.web-authn.core.application-id=https://localhost:8443
cas.authn.mfa.web-authn.core.relying-party-name=Syncope
cas.authn.mfa.web-authn.core.relying-party-id=syncope.apache.org
-cas.authn.syncope.url=${cas.server.name}/syncope/rest/
+cas.authn.syncope.url=${cas.server.name}/syncope
+cas.authn.syncope.name=DefaultSyncopeAuthModule
+
+##
+# Default strategy for matching request paths against
+# registered Spring MVC handler mappings
+spring.mvc.pathmatch.matching-strategy=ant-path-matcher
diff --git
a/wa/starter/src/test/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManagerTest.java
b/wa/starter/src/test/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManagerTest.java
index 7c2a352..9d2f878 100644
---
a/wa/starter/src/test/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManagerTest.java
+++
b/wa/starter/src/test/java/org/apache/syncope/wa/starter/audit/SyncopeWAAuditTrailManagerTest.java
@@ -50,7 +50,7 @@ public class SyncopeWAAuditTrailManagerTest extends
AbstractTest {
@Test
public void saveAuditRecord() {
AuditActionContext audit = new AuditActionContext("principal",
"resourceOperatedUpon", "actionPerformed",
- "applicationCode", new Date(), "clientIpAddress",
"serverIpAddress");
+ "applicationCode", new Date(), "clientIpAddress",
"serverIpAddress", "userAgent");
SyncopeWAAuditTrailManager auditTrailManager = new
SyncopeWAAuditTrailManager(getWaRestClient());
auditTrailManager.saveAuditRecord(audit);
verify(loggerService).create(any(AuditEntry.class));
diff --git a/wa/starter/src/test/resources/debug/wa-debug.properties
b/wa/starter/src/test/resources/debug/wa-debug.properties
index fdcb208..243d97d 100644
--- a/wa/starter/src/test/resources/debug/wa-debug.properties
+++ b/wa/starter/src/test/resources/debug/wa-debug.properties
@@ -14,6 +14,8 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+spring.main.allow-circular-references=true
+
keymaster.address=http://localhost:9080/syncope/rest/keymaster
keymaster.username=${anonymousUser}
keymaster.password=${anonymousKey}
@@ -21,4 +23,11 @@ keymaster.password=${anonymousKey}
cas.server.name=http://localhost:8080
cas.server.prefix=${cas.server.name}/syncope-wa
cas.authn.accept.users=admin::password
-cas.authn.syncope.url=http://localhost:9080/syncope/rest/
+
+cas.authn.syncope.url=http://localhost:9080/syncope
+cas.authn.syncope.name=DefaultSyncopeAuthModule
+
+##
+# Default strategy for matching request paths against
+# registered Spring MVC handler mappings
+spring.mvc.pathmatch.matching-strategy=ant-path-matcher