Skip to content

Commit 08c4810

Browse files
dnschwarzercesmarvin
authored andcommitted
Merge branch 'release/v7.2.6-1'
2 parents 934b683 + 6df776d commit 08c4810

25 files changed

+492
-177
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [v7.2.6-1] - 2025-08-26
11+
### Changed
12+
- [#279] Changed Jenkins-Build to be able to start the integration tests more reliably
13+
- [#281] Upgraded CAS to 7.2.6
14+
- [#281] Upgraded Sprint Boot to 3.4.4
15+
1016
## [v7.1.6-6] - 2025-08-14
1117
### Fixed
1218
- [#276] Fix typo in cas configuration

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ RUN apk update && apk add wget && wget -O "apache-tomcat-${TOMCAT_VERSION}.tar.
3939

4040
# registry.cloudogu.com/official/cas
4141
FROM registry.cloudogu.com/official/java:21.0.5-1 AS cas
42-
4342
LABEL NAME="official/cas" \
44-
VERSION="7.1.6-6" \
43+
VERSION="7.2.6-1" \
4544
maintainer="[email protected]"
4645

4746
ARG TOMCAT_VERSION
@@ -56,7 +55,8 @@ RUN set -o errexit \
5655
&& apk upgrade \
5756
&& apk add --no-cache --update \
5857
wget \
59-
jq
58+
jq \
59+
curl
6060

6161
# configure environment
6262
ENV TOMCAT_VERSION=${TOMCAT_VERSION} \

Jenkinsfile

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,29 @@ parallel(
197197
timeout(15) {
198198
ecoSystem.waitForDogu("nginx")
199199
ecoSystem.waitForDogu("cas")
200+
201+
// The http health check is not yet implemented, so this is the manual workaround.
202+
waitForCondition(20, 10) {
203+
def status = sh(
204+
script: """
205+
wget --spider -S --tries=1 --timeout=10 --no-check-certificate http://${ecoSystem.externalIP}/cas/actuator/health 2>&1 \
206+
| awk '/^ HTTP/{print \$2}' | tail -1
207+
""",
208+
returnStdout: true
209+
).trim()
210+
211+
echo "HTTP status: ${status}"
212+
return status == "200"
213+
}
200214
}
201215
}
202216

203217
stage('Integration Tests') {
204218
echo "Create custom dogu to access OAuth endpoints for the integration tests"
205219
ecoSystem.vagrant.ssh "sudo docker cp /dogu/integrationTests/services/ cas:/etc/cas/services/production/"
206220
ecoSystem.vagrant.sshOut "sudo docker exec cas ls /etc/cas/services/production"
221+
// Wait for Service-Watch start delay (see: cas.service-registry.schedule.start-delay)
222+
sleep time: 30, unit: 'SECONDS'
207223

208224
ecoSystem.runCypressIntegrationTests([
209225
cypressImage : "cypress/included:13.13.2",
@@ -284,4 +300,18 @@ void gitWithCredentials(String command) {
284300
returnStdout: true
285301
)
286302
}
287-
}
303+
}
304+
305+
def waitForCondition(maxRetries = 10, sleepSeconds = 5, checkClosure) {
306+
def retries = 0
307+
while (retries < maxRetries) {
308+
if (checkClosure()) {
309+
echo "Condition met after ${retries} attempt(s)"
310+
return true
311+
}
312+
echo "Condition not met, retrying... (${retries + 1}/${maxRetries})"
313+
sleep time: sleepSeconds, unit: 'SECONDS'
314+
retries++
315+
}
316+
error "Condition not met after ${maxRetries} attempts"
317+
}

app/build.gradle

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ buildscript {
3232

3333
classpath "de.undercouch:gradle-download-task:${project.gradleDownloadTaskVersion}"
3434
classpath "org.apereo.cas:cas-server-core-api-configuration-model:${project.'cas.version'}"
35-
classpath "org.apereo.cas:cas-server-core-configuration-metadata-repository:${project.'cas.version'}"
35+
classpath "org.apereo.cas:cas-server-support-configuration-metadata-repository:${project.'cas.version'}"
3636
}
3737
}
3838

@@ -120,7 +120,6 @@ test {
120120

121121
dependencies {
122122
implementation enforcedPlatform("org.apereo.cas:cas-server-support-bom:${project.'cas.version'}")
123-
implementation platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
124123

125124
// Other CAS dependencies/modules may be listed here...
126125
implementation "org.apereo.cas:cas-server-core-api-protocol"
@@ -192,26 +191,15 @@ dependencies {
192191
developmentOnly "org.springframework.boot:spring-boot-devtools:${project.springBootVersion}"
193192
runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
194193

194+
implementation "org.apereo.cas:cas-server-core-scripting:${project.'cas.version'}"
195+
195196
implementation "org.pac4j:pac4j-cas"
196197
implementation "org.pac4j:pac4j-oidc"
197198
implementation "org.pac4j:pac4j-config"
198-
199-
implementation "org.apereo.cas:cas-server-core-scripting:${project.'cas.version'}"
199+
implementation "org.apereo.cas:cas-server-core-multitenancy"
200200
}
201201

202202
configurations.all {
203203
resolutionStrategy {
204-
force 'org.apache.logging.log4j:log4j-core:2.23.1'
205-
force 'org.apache.logging.log4j:log4j-api:2.23.1'
206-
207-
force 'org.springframework.security:spring-security-core:6.3.4'
208-
force 'org.springframework.security:spring-security-web:6.3.4'
209-
force 'org.springframework.security:spring-security-config:6.3.4'
210-
force 'org.springframework.security:spring-security-oauth2-core:6.3.4'
211-
force 'org.springframework.security:spring-security-oauth2-client:6.3.4'
212-
force 'org.springframework.security:spring-security-oauth2-jose:6.3.4'
213-
force 'org.springframework.security:spring-security-oauth2-resource-server:6.3.4'
214-
force 'org.springframework.security:spring-security-crypto:6.3.4'
215-
force 'org.springframework.security:spring-security-rsa:1.1.1'
216204
}
217205
}

app/gradle.properties

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# CAS server version
2-
cas.version=7.1.6
2+
cas.version=7.2.6
33

44
###############################
55
# Spring versions
66
###############################
7-
springBootVersion=3.3.9
7+
springBootVersion=3.4.4
88

99
###############################
1010
# Tomcat versions
@@ -21,7 +21,7 @@ gradleFreeFairPluginVersion=8.6
2121
gradleDependencyManagementPluginVersion=1.1.5
2222

2323
# The version of this overlay project
24-
version=7.1.6
24+
version=7.2.6
2525
group=org.apereo.cas
2626
artifactId=cas-overlay
2727
sourceCompatibility=21

app/gradle/springboot.gradle

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -114,31 +114,6 @@ bootWar {
114114
excludes = [
115115
"WEB-INF/lib/servlet-api-6*.jar",
116116
"WEB-INF/lib/tomcat-*-10.1.31.jar", // as we use an external tomcat server we can remove the embedded on
117-
118-
119-
// Exclude outdated security libs if they exist in overlay WAR
120-
"WEB-INF/lib/spring-security-web-6.2.4.jar",
121-
"WEB-INF/lib/spring-security-web-6.2.4.jar",
122-
"WEB-INF/lib/spring-security-core-6.2.4.jar",
123-
"WEB-INF/lib/spring-security-config-6.2.4.jar",
124-
"WEB-INF/lib/spring-security-crypto-6.2.4.jar",
125-
"WEB-INF/lib/spring-security-oauth2-core-6.2.4.jar",
126-
"WEB-INF/lib/spring-security-oauth2-client-6.2.4.jar",
127-
"WEB-INF/lib/spring-security-oauth2-jose-6.2.4.jar",
128-
"WEB-INF/lib/spring-security-oauth2-resource-server-6.2.4.jar",
129-
130-
"WEB-INF/lib/spring-security-web-6.3.3.jar",
131-
"WEB-INF/lib/spring-security-core-6.3.3.jar",
132-
"WEB-INF/lib/spring-security-config-6.3.3.jar",
133-
"WEB-INF/lib/spring-security-crypto-6.3.3.jar",
134-
"WEB-INF/lib/spring-security-oauth2-core-6.3.3.jar",
135-
"WEB-INF/lib/spring-security-oauth2-client-6.3.3.jar",
136-
"WEB-INF/lib/spring-security-oauth2-jose-6.3.3.jar",
137-
"WEB-INF/lib/spring-security-oauth2-resource-server-6.3.3.jar",
138-
139-
"WEB-INF/lib/spring-web-6.2.3.jar",
140-
"WEB-INF/lib/spring-web-6.2.5.jar",
141-
"WEB-INF/lib/spring-web-6.1.12.jar",
142117
]
143118
}
144119
}

app/gradle/tasks.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ buildscript {
3131
}
3232
dependencies {
3333
classpath "org.apache.ivy:ivy:${project.ivyVersion}"
34-
classpath "org.apereo.cas:cas-server-core-configuration-metadata-repository:${project.'cas.version'}"
34+
classpath "org.apereo.cas:cas-server-support-configuration-metadata-repository:${project.'cas.version'}"
3535
}
3636
}
3737
apply plugin: "de.undercouch.download"
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package de.triology.cas.authentication;
2+
3+
import org.apereo.cas.authentication.handler.ByCredentialSourceAuthenticationHandlerResolver;
4+
import org.apereo.cas.authentication.handler.DefaultAuthenticationHandlerResolver;
5+
import org.apereo.cas.authentication.principal.PrincipalResolver;
6+
import org.apereo.cas.util.CollectionUtils;
7+
import org.apereo.cas.util.spring.beans.BeanSupplier;
8+
import lombok.NonNull;
9+
import lombok.extern.slf4j.Slf4j;
10+
import lombok.val;
11+
import org.apache.commons.lang3.StringUtils;
12+
import org.jooq.lambda.Unchecked;
13+
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
14+
import java.util.LinkedHashMap;
15+
import java.util.LinkedHashSet;
16+
import java.util.Map;
17+
import java.util.Set;
18+
import java.util.stream.Collectors;
19+
import org.apereo.cas.authentication.AuthenticationHandlerResolver;
20+
import org.apereo.cas.authentication.DefaultAuthenticationEventExecutionPlan;
21+
import org.apereo.cas.authentication.AuthenticationHandler;
22+
import org.apereo.cas.authentication.AuthenticationTransaction;
23+
import org.apereo.cas.authentication.MultifactorAuthenticationHandler;
24+
import org.apereo.cas.authentication.AuthenticationException;
25+
26+
import org.apereo.cas.multitenancy.TenantExtractor;
27+
28+
@Slf4j
29+
public class LegacyDefaultAuthenticationEventExecutionPlan extends DefaultAuthenticationEventExecutionPlan {
30+
31+
private final Map<AuthenticationHandler, PrincipalResolver> authenticationHandlerPrincipalResolverMap = new LinkedHashMap<>(0);
32+
33+
public LegacyDefaultAuthenticationEventExecutionPlan(
34+
AuthenticationHandlerResolver defaultAuthenticationHandlerResolver, TenantExtractor tenantExtractor) {
35+
super(defaultAuthenticationHandlerResolver, tenantExtractor);
36+
}
37+
38+
/**
39+
* Only override the handler resolution. Everything else stays as-is.
40+
*/
41+
@Override
42+
public @NonNull Set<AuthenticationHandler> resolveAuthenticationHandlers(final AuthenticationTransaction transaction) throws Throwable {
43+
// Use the public API of the parent
44+
val handlers = super.getAuthenticationHandlers();
45+
LOGGER.debug("Candidate/Registered authentication handlers for this transaction [{}] are [{}]", transaction, handlers);
46+
47+
val handlerResolvers = super.getAuthenticationHandlerResolvers(transaction);
48+
LOGGER.debug("Authentication handler resolvers for this transaction are [{}]", handlerResolvers);
49+
50+
val resolvedHandlers = handlerResolvers.stream()
51+
.filter(BeanSupplier::isNotProxy)
52+
.filter(Unchecked.predicate(r -> r.supports(handlers, transaction)))
53+
.map(Unchecked.function(r -> r.resolve(handlers, transaction)))
54+
.flatMap(Set::stream)
55+
.collect(Collectors.toCollection(LinkedHashSet::new));
56+
57+
// Fallback to a fresh DefaultAuthenticationHandlerResolver instance
58+
if (resolvedHandlers.isEmpty()) {
59+
LOGGER.debug("Resolvers produced no candidates. Using the default resolver fallback...");
60+
var fallback = new DefaultAuthenticationHandlerResolver();
61+
if (fallback.supports(handlers, transaction)) {
62+
resolvedHandlers.addAll(fallback.resolve(handlers, transaction));
63+
}
64+
}
65+
66+
// Optional: filter by credential source, but *don’t* assume access to parent internals
67+
val byCredential = new ByCredentialSourceAuthenticationHandlerResolver();
68+
if (byCredential.supports(resolvedHandlers, transaction)) {
69+
val credentialHandlers = byCredential.resolve(resolvedHandlers, transaction);
70+
if (!credentialHandlers.isEmpty()) {
71+
LOGGER.debug("Handlers resolved by credential source are [{}]", credentialHandlers);
72+
resolvedHandlers.removeIf(handler ->
73+
!(handler instanceof MultifactorAuthenticationHandler)
74+
&& credentialHandlers.stream().noneMatch(credHandler ->
75+
StringUtils.equalsIgnoreCase(credHandler.getName(), handler.getName())));
76+
}
77+
}
78+
79+
if (resolvedHandlers.isEmpty()) {
80+
throw new AuthenticationException("No authentication handlers could be resolved to support the authentication transaction");
81+
}
82+
LOGGER.debug("Resolved and finalized authentication handlers for this transaction are [{}]", resolvedHandlers);
83+
return resolvedHandlers;
84+
}
85+
86+
@Override
87+
public Set<AuthenticationHandler> getAuthenticationHandlers() {
88+
val handlers = authenticationHandlerPrincipalResolverMap.keySet().toArray(AuthenticationHandler[]::new);
89+
AnnotationAwareOrderComparator.sortIfNecessary(handlers);
90+
return new LinkedHashSet<>(CollectionUtils.wrapList(handlers));
91+
}
92+
}

app/src/main/java/de/triology/cas/oidc/config/CesOidcConfiguration.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package de.triology.cas.oidc.config;
22

3+
import de.triology.cas.authentication.LegacyDefaultAuthenticationEventExecutionPlan;
4+
import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
35
import de.triology.cas.ldap.LdapOperationFactory;
46
import de.triology.cas.ldap.UserManager;
7+
import de.triology.cas.oidc.beans.CesOAuthProfileRenderer;
58
import de.triology.cas.oidc.beans.CesOidcClientRedirectActionBuilder;
69
import de.triology.cas.oidc.beans.delegation.AttributeMapping;
710
import de.triology.cas.oidc.beans.delegation.CesCustomDelegatedAuthenticationClientLogoutAction;
@@ -14,12 +17,14 @@
1417
import org.apereo.cas.configuration.CasConfigurationProperties;
1518
import org.apereo.cas.configuration.model.support.ldap.LdapAuthenticationProperties;
1619
import org.apereo.cas.support.oauth.web.response.OAuth20CasClientRedirectActionBuilder;
20+
import org.apereo.cas.support.oauth.web.views.OAuth20UserProfileViewRenderer;
1721
import org.apereo.cas.authentication.principal.provision.DelegatedClientUserProfileProvisioner;
1822
import org.apereo.cas.util.LdapUtils;
1923
import org.ldaptive.PooledConnectionFactory;
2024
import org.pac4j.core.client.BaseClient;
2125
import org.pac4j.core.client.Client;
2226
import org.pac4j.core.client.Clients;
27+
import org.pac4j.core.context.WebContext;
2328
import org.pac4j.core.context.session.SessionStore;
2429
import org.pac4j.oidc.client.OidcClient;
2530
import org.pac4j.oidc.config.OidcConfiguration;
@@ -34,6 +39,10 @@
3439
import org.springframework.context.annotation.Primary;
3540
import org.springframework.webflow.execution.Action;
3641
import org.apereo.cas.config.CasOidcAutoConfiguration;
42+
import org.apereo.cas.authentication.principal.Service;
43+
import org.apereo.cas.multitenancy.TenantExtractor;
44+
import org.apereo.cas.authentication.AuthenticationHandlerResolver;
45+
import org.springframework.beans.factory.annotation.Qualifier;
3746

3847
import java.util.ArrayList;
3948
import java.util.Arrays;
@@ -93,6 +102,23 @@ public CesDelegatedOidcClientsProperties cesDelegatedOidcClientsProperties() {
93102
return new CesDelegatedOidcClientsProperties();
94103
}
95104

105+
@Bean
106+
@RefreshScope
107+
public OAuth20UserProfileViewRenderer oauthUserProfileViewRenderer() {
108+
return new CesOAuthProfileRenderer();
109+
}
110+
111+
@Bean
112+
@Primary
113+
@RefreshScope
114+
public AuthenticationEventExecutionPlan authenticationEventExecutionPlan(
115+
@Qualifier("defaultAuthenticationHandlerResolver")
116+
AuthenticationHandlerResolver authenticationHandlerResolver,
117+
TenantExtractor tenantExtractor) {
118+
return new LegacyDefaultAuthenticationEventExecutionPlan(authenticationHandlerResolver, tenantExtractor);
119+
}
120+
121+
96122
/**
97123
* Creates OIDC client objects dynamically from the loaded properties.
98124
*
@@ -187,6 +213,11 @@ public List<Client> findAllClients() {
187213
}
188214
return new ArrayList<>(baseClients);
189215
}
216+
217+
@Override
218+
public List<Client> findAllClients(Service service, WebContext context) {
219+
return findAllClients();
220+
}
190221

191222
@Override
192223
public Optional<Client> findClient(String name) {

app/src/main/java/de/triology/cas/pm/CesLdapPasswordManagementService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ public CesLdapPasswordManagementService(
3939
final PasswordHistoryService passwordHistoryService,
4040
final Map<String, ConnectionFactory> connectionFactoryMap) {
4141
super(cipherExecutor,
42-
casProperties.getServer().getPrefix(),
43-
casProperties.getAuthn().getPm(),
42+
casProperties,
4443
passwordHistoryService,
4544
connectionFactoryMap);
4645

0 commit comments

Comments
 (0)