Skip to content

Commit

Permalink
Merge branch 'main' into fix-user-declarative-profile-import
Browse files Browse the repository at this point in the history
  • Loading branch information
st3v0rr authored Jul 13, 2023
2 parents 8b1c2f1 + 49ecfe7 commit a0283f1
Show file tree
Hide file tree
Showing 18 changed files with 459 additions and 31 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=21.0.1
KEYCLOAK_VERSION=21.1.1
12 changes: 6 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- KEYCLOAK_VERSION: 18.0.2
- KEYCLOAK_VERSION: 19.0.3
- KEYCLOAK_VERSION: 20.0.5
- KEYCLOAK_VERSION: 21.0.1
- KEYCLOAK_VERSION: 21.1.1
steps:
- uses: actions/checkout@v3
with:
Expand Down Expand Up @@ -62,14 +62,14 @@ jobs:
run: echo "::set-output name=VERSION::$(tail -n1 .env | cut -d= -f2)"

- name: Login to Docker Hub
uses: docker/login-action@v2.1.0
uses: docker/login-action@v2.2.0
if: startsWith(github.event.ref, 'refs/tags/v')
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: Login to Quay.io
uses: docker/login-action@v2.1.0
uses: docker/login-action@v2.2.0
if: startsWith(github.event.ref, 'refs/tags/v')
with:
registry: quay.io
Expand All @@ -81,7 +81,7 @@ jobs:

- name: Set up Docker Build Metadata
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v4.3.0
uses: crazy-max/ghaction-docker-meta@v4.6.0
with:
images: adorsys/keycloak-config-cli,quay.io/adorsys/keycloak-config-cli
flavor: |
Expand All @@ -102,7 +102,7 @@ jobs:
uses: docker/setup-buildx-action@v2

- name: Build and push
uses: docker/build-push-action@v4.0.0
uses: docker/build-push-action@v4.1.1
with:
build-args: |-
KEYCLOAK_VERSION=${{ matrix.env.KEYCLOAK_VERSION }}
Expand Down Expand Up @@ -161,7 +161,7 @@ jobs:
fail-fast: false
matrix:
env:
- KEYCLOAK_VERSION: 21.0.1
- KEYCLOAK_VERSION: 21.1.1
steps:
- uses: actions/checkout@v3

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- copy the JSON array of the old `userProfile` property to the new `userProfile.attributes` property
- create a new JSON array for the `userProfile.groups` property (containing the attribute groups definitions)
- in the end, the `userProfile` property should match the content of the "JSON editor" tab in the "Realm settings > User profile" page from the Keycloak admin console
- Add support for managing client-policies

## [5.6.1] - 2023-03-05

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=21.0.1
ARG KEYCLOAK_VERSION=21.1.1
ARG MAVEN_CLI_OPTS="-ntp -B"

COPY .mvn .mvn
Expand Down
1 change: 1 addition & 0 deletions docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
| Remove clientScopeMappings | 2.5.0 | Remove existing clientScopeMappings while creating or updating realms |
| Synchronize user federation | 3.5.0 | Synchronize the user federation defined on the realm configuration |
| Synchronize user profile | 5.4.0 | Synchronize the user profile configuration defined on the realm configuration |
| Synchronize client-policies | 5.6.0 | Synchronize the client-policies (clientProfiles and clientPolicies) while updating realms |

# Specificities

Expand Down
44 changes: 27 additions & 17 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.9</version>
<version>2.7.12</version>
<relativePath />
</parent>

Expand Down Expand Up @@ -59,7 +59,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<keycloak.version>21.0.1</keycloak.version>
<keycloak.version>21.1.1</keycloak.version>

<checkstyle-plugin.version>3.2.0</checkstyle-plugin.version>
<checkstyle.version>10.0</checkstyle.version>
Expand All @@ -68,28 +68,29 @@
<commons-text.version>1.10.0</commons-text.version>
<failsafe.version>2.4.4</failsafe.version>
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
<jackson.version>2.13.4</jackson.version>
<jacoco.version>0.8.9</jacoco.version>
<junit-pioneer.version>2.0.0</junit-pioneer.version>
<jackson.version>2.13.5</jackson.version>
<jacoco.version>0.8.10</jacoco.version>
<junit-pioneer.version>2.0.1</junit-pioneer.version>
<junit5-system-exit.version>1.1.2</junit5-system-exit.version>
<keepachangelog.version>2.1.1</keepachangelog.version>
<license-plugin.version>2.0.0</license-plugin.version>
<logstash-logback-encoder.version>7.3</logstash-logback-encoder.version>
<logstash-logback-encoder.version>7.4</logstash-logback-encoder.version>
<maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version>
<maven-release-plugin.version>3.0.0</maven-release-plugin.version>
<maven-release-plugin.version>3.0.1</maven-release-plugin.version>
<maven-replacer.version>1.5.3</maven-replacer.version>
<maven-scm-plugin.version>2.0.0</maven-scm-plugin.version>
<maven-scm-plugin.version>2.0.1</maven-scm-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<mockserver.version>5.15.0</mockserver.version>
<pmd-plugin.version>3.20.0</pmd-plugin.version>
<pmd-plugin.version>3.21.0</pmd-plugin.version>
<pmd.version>6.55.0</pmd.version>
<reproducible-build-maven-plugin.version>0.15</reproducible-build-maven-plugin.version>
<resteasy.version>5.0.4.Final</resteasy.version>
<spotbugs-plugin.version>4.7.3.3</spotbugs-plugin.version>
<spotbugs-plugin.version>4.7.3.5</spotbugs-plugin.version>
<spotbugs.version>4.7.3</spotbugs.version>
<testcontainers.version>1.17.6</testcontainers.version>
<unboundid-ldapsdk.version>6.0.8</unboundid-ldapsdk.version>
<testcontainers.version>1.18.3</testcontainers.version>
<unboundid-ldapsdk.version>6.0.9</unboundid-ldapsdk.version>
<wiremock-jre8.version>2.27.2</wiremock-jre8.version>
<assertj.version>3.24.2</assertj.version>

<sonar.projectKey>keycloak-config-cli</sonar.projectKey>
<sonar.organization>adorsys</sonar.organization>
Expand Down Expand Up @@ -176,6 +177,7 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>5.8.3</version>
</dependency>

<dependency>
Expand All @@ -189,6 +191,12 @@
<artifactId>spring-boot-loader</artifactId>
</dependency>

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
</dependency>

<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
Expand Down Expand Up @@ -230,11 +238,6 @@
<artifactId>jackson-databind</artifactId>
</dependency>

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>

<!-- JSON logging -->
<dependency>
<groupId>net.logstash.logback</groupId>
Expand Down Expand Up @@ -287,6 +290,13 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-spring-test-listener</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*-
* ---license-start
* keycloak-config-cli
* ---
* Copyright (C) 2017 - 2021 adorsys GmbH & Co. KG @ https://adorsys.com
* ---
* Licensed 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.
* ---license-end
*/

package de.adorsys.keycloak.config.repository;

import de.adorsys.keycloak.config.model.RealmImport;
import org.keycloak.admin.client.resource.ClientPoliciesPoliciesResource;
import org.keycloak.admin.client.resource.ClientPoliciesProfilesResource;
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
import org.keycloak.representations.idm.ClientProfilesRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ClientPoliciesRepository {

private static final Logger logger = LoggerFactory.getLogger(AuthenticationFlowRepository.class);

private final RealmRepository realmRepository;

@Autowired
public ClientPoliciesRepository(RealmRepository realmRepository) {
this.realmRepository = realmRepository;
}

private ClientPoliciesPoliciesResource getPoliciesResource(String realmName) {
return this.realmRepository.getResource(realmName).clientPoliciesPoliciesResource();
}

private ClientPoliciesProfilesResource getProfilesResource(String realmName) {
return this.realmRepository.getResource(realmName).clientPoliciesProfilesResource();
}

public void updateClientPoliciesPolicies(RealmImport realmImport, ClientPoliciesRepresentation newClientPolicies) {

ClientPoliciesPoliciesResource policiesResource = getPoliciesResource(realmImport.getRealm());

ClientPoliciesRepresentation existingClientPolicies;
try {
existingClientPolicies = policiesResource.getPolicies();
} catch (Exception ex) {
existingClientPolicies = null;
}

if (existingClientPolicies == null && newClientPolicies == null) {
logger.trace("No client-policy policies configured, skipping update.");
return;
}

if (existingClientPolicies != null && existingClientPolicies.equals(newClientPolicies)) {
logger.trace("Current client-policy policies match existing policies, skipping update.");
return;
}

if (newClientPolicies == null) {
logger.trace("New client-policy policies resets existing policies.");
newClientPolicies = new ClientPoliciesRepresentation();
}

policiesResource.updatePolicies(newClientPolicies);
}

public void updateClientPoliciesProfiles(RealmImport realmImport, ClientProfilesRepresentation newClientProfiles) {

ClientPoliciesProfilesResource profilesResource = getProfilesResource(realmImport.getRealm());

// Note that we deliberately ignore global profiles, to avoid inconsistencies.
ClientProfilesRepresentation existingClientProfiles;
try {
existingClientProfiles = profilesResource.getProfiles(false);
} catch (Exception ex) {
existingClientProfiles = null;
}

if (existingClientProfiles == null && newClientProfiles == null) {
logger.trace("No client-policy profiles configured, skipping update.");
return;
}

if (existingClientProfiles != null && existingClientProfiles.equals(newClientProfiles)) {
logger.trace("Current client-policy profiles match existing profiles, skipping update.");
return;
}

if (newClientProfiles == null) {
logger.trace("New client-policy profiles resets existing profiles.");
newClientProfiles = new ClientProfilesRepresentation();
}

profilesResource.updateProfiles(newClientProfiles);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*-
* ---license-start
* keycloak-config-cli
* ---
* Copyright (C) 2017 - 2021 adorsys GmbH & Co. KG @ https://adorsys.com
* ---
* Licensed 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.
* ---license-end
*/

package de.adorsys.keycloak.config.service;

import de.adorsys.keycloak.config.model.RealmImport;
import de.adorsys.keycloak.config.repository.ClientPoliciesRepository;
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
import org.keycloak.representations.idm.ClientProfilesRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ClientPoliciesImportService {

private static final Logger logger = LoggerFactory.getLogger(ClientPoliciesImportService.class);

private final ClientPoliciesRepository clientPoliciesRepository;

@Autowired
public ClientPoliciesImportService(ClientPoliciesRepository clientPoliciesRepository) {
this.clientPoliciesRepository = clientPoliciesRepository;
}

public void doImport(RealmImport realmImport) {

// client-profile profiles must be imported before client-profile policies
ClientProfilesRepresentation parsedClientProfiles = realmImport.getParsedClientProfiles();
clientPoliciesRepository.updateClientPoliciesProfiles(realmImport, parsedClientProfiles);
logger.trace("Updated client-policy profiles.");

ClientPoliciesRepresentation parsedClientPolicies = realmImport.getParsedClientPolicies();
clientPoliciesRepository.updateClientPoliciesPolicies(realmImport, parsedClientPolicies);
logger.trace("Updated client-policy policies.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public class RealmImportService {
"requiredActions",
"defaultDefaultClientScopes",
"defaultOptionalClientScopes",
"clientProfiles",
"clientPolicies",
};

private static final Logger logger = LoggerFactory.getLogger(RealmImportService.class);
Expand All @@ -64,6 +66,9 @@ public class RealmImportService {

private final UserImportService userImportService;
private final UserProfileImportService userProfileImportService;

private final ClientPoliciesImportService clientPoliciesImportService;

private final RoleImportService roleImportService;
private final ClientImportService clientImportService;
private final ClientScopeImportService clientScopeImportService;
Expand All @@ -90,6 +95,7 @@ public RealmImportService(
RealmRepository realmRepository,
UserImportService userImportService,
UserProfileImportService userProfileImportService,
ClientPoliciesImportService clientPoliciesImportService,
RoleImportService roleImportService,
ClientImportService clientImportService,
GroupImportService groupImportService,
Expand All @@ -110,6 +116,7 @@ public RealmImportService(
this.realmRepository = realmRepository;
this.userImportService = userImportService;
this.userProfileImportService = userProfileImportService;
this.clientPoliciesImportService = clientPoliciesImportService;
this.roleImportService = roleImportService;
this.clientImportService = clientImportService;
this.groupImportService = groupImportService;
Expand Down Expand Up @@ -194,6 +201,7 @@ private void configureRealm(RealmImport realmImport, RealmRepresentation existin
defaultGroupsImportService.doImport(realmImport);
componentImportService.doImport(realmImport);
userProfileImportService.doImport(realmImport);
clientPoliciesImportService.doImport(realmImport);
userImportService.doImport(realmImport);
requiredActionsImportService.doImport(realmImport);
authenticationFlowsImportService.doImport(realmImport);
Expand Down
Loading

0 comments on commit a0283f1

Please sign in to comment.