Skip to content

Commit

Permalink
Merge pull request #1052 from jonasvoelcker/keycloak-25
Browse files Browse the repository at this point in the history
Keycloak 25.0.1
  • Loading branch information
francis-pouatcha authored Jun 25, 2024
2 parents 7eb7675 + 03d901b commit af2f54a
Show file tree
Hide file tree
Showing 34 changed files with 2,140 additions and 165 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Used in docker-compose
# shellcheck disable=SC2034
KEYCLOAK_VERSION=24.0.5
KEYCLOAK_VERSION=25.0.1
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
- KEYCLOAK_VERSION: 22.0.4
- KEYCLOAK_VERSION: 23.0.7
- KEYCLOAK_VERSION: 24.0.5
- KEYCLOAK_VERSION: 25.0.1
steps:
- uses: actions/checkout@v4.1.7
with:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
- Updated CI to use Keycloak 25.0.1
- Identity Providers are now updated using the name of policies, scopes and resources

### Fixed
- Importing more than 10 subgroups into a realm
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ FROM ${BUILDER_IMAGE} AS BUILDER

WORKDIR /app/

ARG KEYCLOAK_VERSION=24.0.5
ARG KEYCLOAK_VERSION=25.0.1
ARG MAVEN_CLI_OPTS="-ntp -B"

COPY .mvn .mvn
Expand Down
4 changes: 2 additions & 2 deletions contrib/example-config/benchmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9466,9 +9466,9 @@ requiredActions:
defaultAction: false
priority: 10
config: {}
- alias: terms_and_conditions
- alias: TERMS_AND_CONDITIONS
name: "Terms and Conditions"
providerId: terms_and_conditions
providerId: TERMS_AND_CONDITIONS
enabled: false
defaultAction: false
priority: 20
Expand Down
4 changes: 2 additions & 2 deletions contrib/example-config/moped.json
Original file line number Diff line number Diff line change
Expand Up @@ -940,9 +940,9 @@
"config": {}
},
{
"alias": "terms_and_conditions",
"alias": "TERMS_AND_CONDITIONS",
"name": "Terms and Conditions",
"providerId": "terms_and_conditions",
"providerId": "TERMS_AND_CONDITIONS",
"enabled": false,
"defaultAction": false,
"priority": 20,
Expand Down
2 changes: 1 addition & 1 deletion contrib/scripts/generate-export-realm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ docker run -d --rm \
"quay.io/keycloak/keycloak:${KEYCLOAK_VERSION}" \
start-dev

while ! docker exec keycloak-export bash -c '/opt/keycloak/bin/kcadm.sh config credentials --server http://$HOSTNAME:8080/auth --realm master --user $KEYCLOAK_USER --password $KEYCLOAK_PASSWORD'; do
while ! docker exec keycloak-export bash -c '/opt/keycloak/bin/kcadm.sh config credentials --server http://$HOSTNAME:8080/auth --realm master'; do
sleep 2
done

Expand Down
57 changes: 55 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<keycloak.version>24.0.5</keycloak.version>
<keycloak.version>25.0.1</keycloak.version>

<checkstyle-plugin.version>3.3.1</checkstyle-plugin.version>
<checkstyle.version>10.17.0</checkstyle.version>
Expand Down Expand Up @@ -163,6 +163,11 @@
<artifactId>spring-boot-loader</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
Expand Down Expand Up @@ -627,7 +632,7 @@
<version>${maven-replacer.version}</version>
<executions>
<execution>
<id>replace-pre-keycloak22</id>
<id>replace-pre-keycloak19</id>
<phase>generate-sources</phase>
<goals>
<goal>replace</goal>
Expand Down Expand Up @@ -659,6 +664,22 @@ import org.keycloak.representations.userprofile.config.UPConfig;</token>
<token>return groupResource.getSubGroups\(0, Integer.MAX_VALUE, false\);</token>
<value>return groupResource.toRepresentation().getSubGroups();</value>
</replacement>
<replacement>
<token>if \(userProfile == null\)</token>
<value>if (userProfile == null || userProfile.isEmpty())</value>
</replacement>
<replacement>
<token>private UPConfig userProfile;</token>
<value>private Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; userProfile;</value>
</replacement>
<replacement>
<token>public void setUserProfile\(UPConfig userProfile\)</token>
<value>public void setUserProfile(Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; userProfile)</value>
</replacement>
<replacement>
<token>public UPConfig getUserProfile\(\)</token>
<value>public Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; getUserProfile()</value>
</replacement>
</replacements>
</configuration>
</plugin>
Expand Down Expand Up @@ -736,6 +757,22 @@ import org.keycloak.representations.userprofile.config.UPConfig;</token>
<token>return groupResource.getSubGroups\(0, Integer.MAX_VALUE, false\);</token>
<value>return groupResource.toRepresentation().getSubGroups();</value>
</replacement>
<replacement>
<token>if \(userProfile == null\)</token>
<value>if (userProfile == null || userProfile.isEmpty())</value>
</replacement>
<replacement>
<token>private UPConfig userProfile;</token>
<value>private Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; userProfile;</value>
</replacement>
<replacement>
<token>public void setUserProfile\(UPConfig userProfile\)</token>
<value>public void setUserProfile(Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; userProfile)</value>
</replacement>
<replacement>
<token>public UPConfig getUserProfile\(\)</token>
<value>public Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; getUserProfile()</value>
</replacement>
</replacements>
</configuration>
</plugin>
Expand Down Expand Up @@ -798,6 +835,22 @@ import org.keycloak.representations.userprofile.config.UPConfig;</token>
<token>return groupResource.getSubGroups\(0, Integer.MAX_VALUE, false\);</token>
<value>return groupResource.toRepresentation().getSubGroups();</value>
</replacement>
<replacement>
<token>if \(userProfile == null\)</token>
<value>if (userProfile == null || userProfile.isEmpty())</value>
</replacement>
<replacement>
<token>private UPConfig userProfile;</token>
<value>private Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; userProfile;</value>
</replacement>
<replacement>
<token>public void setUserProfile\(UPConfig userProfile\)</token>
<value>public void setUserProfile(Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; userProfile)</value>
</replacement>
<replacement>
<token>public UPConfig getUserProfile\(\)</token>
<value>public Map&lt;String, List&lt;Map&lt;String, Object&gt;&gt;&gt; getUserProfile()</value>
</replacement>
</replacements>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.fasterxml.jackson.annotation.JsonSetter;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
Expand All @@ -34,7 +35,7 @@
public class RealmImport extends RealmRepresentation {
private List<AuthenticationFlowImport> authenticationFlowImports;

private Map<String, List<Map<String, Object>>> userProfile;
private UPConfig userProfile;

private Map<String, Map<String, String>> messageBundles;

Expand All @@ -56,7 +57,7 @@ public void setAuthenticationFlowImports(List<AuthenticationFlowImport> authenti

@SuppressWarnings("unused")
@JsonSetter("userProfile")
public void setUserProfile(Map<String, List<Map<String, Object>>> userProfile) {
public void setUserProfile(UPConfig userProfile) {
this.userProfile = userProfile;
}

Expand All @@ -70,7 +71,7 @@ public void setMessageBundles(Map<String, Map<String, String>> messageBundles) {
this.messageBundles = messageBundles;
}

public Map<String, List<Map<String, Object>>> getUserProfile() {
public UPConfig getUserProfile() {
return userProfile;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.time.Duration;
import java.util.function.Supplier;

import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.client.Entity;
Expand All @@ -54,16 +55,17 @@ public class KeycloakProvider implements AutoCloseable {
private static final Logger logger = LoggerFactory.getLogger(KeycloakProvider.class);

private final KeycloakConfigProperties properties;
private final ResteasyClient resteasyClient;
private final Supplier<ResteasyClient> resteasyClientSupplier;

private Keycloak keycloak;
private ResteasyClient resteasyClient;

private String version;

@Autowired
private KeycloakProvider(KeycloakConfigProperties properties) {
this.properties = properties;
this.resteasyClient = ResteasyUtil.getClient(
this.resteasyClientSupplier = () -> ResteasyUtil.getClient(
!this.properties.isSslVerify(),
this.properties.getHttpProxy(),
this.properties.getConnectTimeout(),
Expand All @@ -72,7 +74,8 @@ private KeycloakProvider(KeycloakConfigProperties properties) {
}

public Keycloak getInstance() {
if (keycloak == null || keycloak.isClosed()) {
if (keycloak == null || resteasyClient == null || keycloak.isClosed() || resteasyClient.isClosed()) {
resteasyClient = resteasyClientSupplier.get();
keycloak = createKeycloak();

checkServerVersion();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,24 @@ public void createAuthorizationResource(String realmName, String id, ResourceRep

public void updateAuthorizationResource(String realmName, String id, ResourceRepresentation resource) {
ClientResource clientResource = getResourceById(realmName, id);
clientResource.authorization().resources().resource(resource.getId()).update(resource);
String resourceId = getResourceId(clientResource, resource.getName());
clientResource.authorization().resources().resource(resourceId).update(resource);
}

public void removeAuthorizationResource(String realmName, String id, String resourceId) {
public void removeAuthorizationResource(String realmName, String id, String resourceName) {
ClientResource clientResource = getResourceById(realmName, id);
clientResource.authorization().resources().resource(resourceId).remove();
String resourceId = getResourceId(clientResource, resourceName);
if (resourceId != null) {
clientResource.authorization().resources().resource(resourceId).remove();
}
}

private String getResourceId(ClientResource clientResource, String resourceName) {
return clientResource.authorization().resources().resources().stream()
.filter(resource -> resourceName.equals(resource.getName()))
.findFirst()
.map(ResourceRepresentation::getId)
.orElse(null);
}

public void addAuthorizationScope(String realmName, String id, String name) {
Expand All @@ -200,12 +212,24 @@ public void addAuthorizationScope(String realmName, String id, String name) {

public void updateAuthorizationScope(String realmName, String id, ScopeRepresentation scope) {
ClientResource clientResource = getResourceById(realmName, id);
clientResource.authorization().scopes().scope(scope.getId()).update(scope);
String scopeId = getScopeId(clientResource, scope.getName());
clientResource.authorization().scopes().scope(scopeId).update(scope);
}

public void removeAuthorizationScope(String realmName, String id, String scopeId) {
public void removeAuthorizationScope(String realmName, String id, String scopeName) {
ClientResource clientResource = getResourceById(realmName, id);
clientResource.authorization().scopes().scope(scopeId).remove();
String scopeId = getScopeId(clientResource, scopeName);
if (scopeId != null) {
clientResource.authorization().scopes().scope(scopeId).remove();
}
}

private String getScopeId(ClientResource clientResource, String scopeName) {
return clientResource.authorization().scopes().scopes().stream()
.filter(scope -> scopeName.equals(scope.getName()))
.findFirst()
.map(ScopeRepresentation::getId)
.orElse(null);
}

public void createAuthorizationPolicy(String realmName, String id, PolicyRepresentation policy) {
Expand All @@ -218,12 +242,24 @@ public void createAuthorizationPolicy(String realmName, String id, PolicyReprese

public void updateAuthorizationPolicy(String realmName, String id, PolicyRepresentation policy) {
ClientResource clientResource = getResourceById(realmName, id);
clientResource.authorization().policies().policy(policy.getId()).update(policy);
String policyId = getPolicyId(clientResource, policy.getName());
clientResource.authorization().policies().policy(policyId).update(policy);
}

public void removeAuthorizationPolicy(String realmName, String id, String policyId) {
public void removeAuthorizationPolicy(String realmName, String id, String policyName) {
ClientResource clientResource = getResourceById(realmName, id);
clientResource.authorization().policies().policy(policyId).remove();
String policyId = getPolicyId(clientResource, policyName);
if (policyId != null) {
clientResource.authorization().policies().policy(policyId).remove();
}
}

private String getPolicyId(ClientResource clientResource, String policyName) {
return clientResource.authorization().policies().policies().stream()
.filter(policy -> policyName.equals(policy.getName()))
.findFirst()
.map(PolicyRepresentation::getId)
.orElse(null);
}

public void addScopeMapping(String realmName, String clientId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -86,7 +87,7 @@ public void createExecutionFlow(
logger.trace("Create non-top-level-flow in realm '{}' and top-level-flow '{}'", realmName, topLevelFlowAlias);

AuthenticationManagementResource flowsResource = authenticationFlowRepository.getFlowResources(realmName);
flowsResource.addExecutionFlow(topLevelFlowAlias, executionFlowData);
flowsResource.addExecutionFlow(topLevelFlowAlias, new HashMap<>(executionFlowData));
}

public void updateExecutionFlow(
Expand Down Expand Up @@ -136,7 +137,7 @@ public void createSubFlowExecution(
realmName, subFlowAlias);

AuthenticationManagementResource flowsResource = authenticationFlowRepository.getFlowResources(realmName);
flowsResource.addExecution(subFlowAlias, executionData);
flowsResource.addExecution(subFlowAlias, new HashMap<>(executionData));

logger.trace("Created flow-execution in realm '{}' and non-top-level-flow '{}'",
realmName, subFlowAlias);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ private void removeAuthorizationResource(
existingClientAuthorizationResource.getName(), getClientIdentifier(client), realmName
);
clientRepository.removeAuthorizationResource(
realmName, client.getId(), existingClientAuthorizationResource.getId()
realmName, client.getId(), existingClientAuthorizationResource.getName()
);
}

Expand Down Expand Up @@ -430,7 +430,7 @@ private void removeAuthorizationScope(
logger.debug("Remove authorization scope '{}' for client '{}' in realm '{}'",
existingClientAuthorizationScope.getName(), getClientIdentifier(client), realmName);

clientRepository.removeAuthorizationScope(realmName, client.getId(), existingClientAuthorizationScope.getId());
clientRepository.removeAuthorizationScope(realmName, client.getId(), existingClientAuthorizationScope.getName());
}

private void createOrUpdateAuthorizationPolicies(
Expand Down Expand Up @@ -519,7 +519,7 @@ private void removeAuthorizationPolicy(

try {
clientRepository.removeAuthorizationPolicy(
realmName, client.getId(), existingClientAuthorizationPolicy.getId()
realmName, client.getId(), existingClientAuthorizationPolicy.getName()
);
} catch (NotFoundException ignored) {
// policies got deleted if linked resources are deleted, too.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void doImport(RealmImport realmImport) {

private String buildUserProfileConfigurationString(RealmImport realmImport) {
var userProfile = realmImport.getUserProfile();
if (userProfile == null || userProfile.isEmpty()) {
if (userProfile == null) {
return null;
}
return JsonUtil.toJson(userProfile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import de.adorsys.keycloak.config.extensions.GithubActionsExtension;
import de.adorsys.keycloak.config.model.RealmImport;
import de.adorsys.keycloak.config.provider.KeycloakImportProvider;
import de.adorsys.keycloak.config.provider.KeycloakProvider;
import de.adorsys.keycloak.config.service.RealmImportService;
import de.adorsys.keycloak.config.test.util.KeycloakAuthentication;
import de.adorsys.keycloak.config.test.util.KeycloakRepository;
Expand Down
Loading

0 comments on commit af2f54a

Please sign in to comment.