diff --git a/ozgcloud-keycloak-operator/src/main/java/de/ozgcloud/operator/keycloak/realm/KeycloakRealmService.java b/ozgcloud-keycloak-operator/src/main/java/de/ozgcloud/operator/keycloak/realm/KeycloakRealmService.java index 6eb9892724db1493d2b88b222e673647bbbd83e9..43cff3483a19f89dfa29d55916a155e5fdbfd411 100644 --- a/ozgcloud-keycloak-operator/src/main/java/de/ozgcloud/operator/keycloak/realm/KeycloakRealmService.java +++ b/ozgcloud-keycloak-operator/src/main/java/de/ozgcloud/operator/keycloak/realm/KeycloakRealmService.java @@ -25,7 +25,10 @@ package de.ozgcloud.operator.keycloak.realm; import java.util.Optional; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.userprofile.config.UPAttribute; import org.keycloak.representations.userprofile.config.UPAttributePermissions; @@ -42,6 +45,8 @@ import lombok.extern.log4j.Log4j2; class KeycloakRealmService { public static final String USER_PROFILE_CONFIG_OZGCLOUD_ATTRIBUTE_NAME = "ozgCloudUserId"; + public static final String LOGIN_THEME_PREFIX = "ozg-"; + public static final Pattern STANDARD_OZGCLOUD_NAMESPACE_PATTERN = Pattern.compile("^([a-zA-Z]{2})-.*$"); private final KeycloakRealmRemoteService remoteService; @@ -60,6 +65,7 @@ class KeycloakRealmService { try { LOG.debug("{}: Updating existing realm...", existingRealm); var realmRepresentation = mapper.update(existingRealm, spec); + addRealmTheme(realmRepresentation); remoteService.updateRealm(realmRepresentation); addUserProfileAttributes(realmRepresentation); } catch (Exception e) { @@ -73,6 +79,7 @@ class KeycloakRealmService { Optional.of(realm) .map(mapper::map) .map(realmRepresentation -> addRealmName(realmRepresentation, realmName)) + .map(realmRepresentation -> addRealmTheme(realmRepresentation)) .ifPresent(realmRepresentation -> { remoteService.createRealm(realmRepresentation); addUserProfileAttributes(realmRepresentation); @@ -92,6 +99,33 @@ class KeycloakRealmService { return realm; } + RealmRepresentation addRealmTheme(RealmRepresentation realm) { + if (realm == null || StringUtils.isEmpty(realm.getRealm())) { + LOG.warn("Realm has no valid value to resolve theme"); + } else { + String realmName = realm.getRealm(); + realm.setLoginTheme(createRealmLoginThemeName(getBundesland(realmName))); + } + return realm; + } + + String getBundesland(String realmName) { + if (realmName != null) { + Matcher matcher = STANDARD_OZGCLOUD_NAMESPACE_PATTERN.matcher(realmName); + if (matcher.matches()) { + return matcher.group(1); + } + } + return ""; + } + + String createRealmLoginThemeName(String bundesland) { + if (!StringUtils.isEmpty(bundesland)) { + return LOGIN_THEME_PREFIX + bundesland; + } + return ""; + } + public void deleteRealm(String realmName) { remoteService.deleteRealm(realmName); } diff --git a/ozgcloud-keycloak-operator/src/test/java/de/ozgcloud/operator/keycloak/realm/KeycloakRealmServiceThemeTest.java b/ozgcloud-keycloak-operator/src/test/java/de/ozgcloud/operator/keycloak/realm/KeycloakRealmServiceThemeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ee49812e321ec42c107249d900147b9636709e64 --- /dev/null +++ b/ozgcloud-keycloak-operator/src/test/java/de/ozgcloud/operator/keycloak/realm/KeycloakRealmServiceThemeTest.java @@ -0,0 +1,205 @@ +package de.ozgcloud.operator.keycloak.realm; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import com.thedeanda.lorem.LoremIpsum; + +public class KeycloakRealmServiceThemeTest { + + public static final LoremIpsum LOREM_IPSUM = LoremIpsum.getInstance(); + private static final String TARGET_BUNDESLAND = "by"; + private static final String BUNDESLAND_NAMESPACE_NAME = TARGET_BUNDESLAND + "-" + LOREM_IPSUM.getWords(1); + private static final String RESOLVED_THEME_NAME = "ozg-" + TARGET_BUNDESLAND; + + @Spy + @InjectMocks + private KeycloakRealmService service; + + @Mock + private KeycloakRealmRemoteService remoteService; + + @Mock + private KeycloakRealmMapper mapper; + + private RealmRepresentation realm; + + private final OzgCloudKeycloakRealmSpec spec = OzgCloudKeycloakRealmSpecTestFactory.create(); + + public static final String REALM_FIELD_LOGIN_THEME = "loginTheme"; + + @Nested + class CreateRealmWithThemeTest { + + @Test + void shouldCreateRealmUseAddTheme() { + prepareMocksWithRealm(BUNDESLAND_NAMESPACE_NAME); + + callCreateRealm(BUNDESLAND_NAMESPACE_NAME); + + verify(service).addRealmTheme(realm); + } + + @Test + void shouldRealmHaveTheme() { + prepareMocksWithRealm(BUNDESLAND_NAMESPACE_NAME); + + callCreateRealm(BUNDESLAND_NAMESPACE_NAME); + + assertThat(realm).extracting(REALM_FIELD_LOGIN_THEME).isEqualTo(RESOLVED_THEME_NAME); + } + + @Test + void shouldHaveNoThemeForAnyName(){ + String nonBundeslandNamespaceName = LOREM_IPSUM.getWords(1); + prepareMocksWithRealm(nonBundeslandNamespaceName); + + callCreateRealm(nonBundeslandNamespaceName); + + assertThat(realm).extracting(REALM_FIELD_LOGIN_THEME).isEqualTo(""); + } + + void prepareMocksWithRealm(String namespaceName) { + realm = RealmRepresentationTestFactory.create(namespaceName); + when(mapper.map(spec)).thenReturn(realm); + doNothing().when(remoteService).createRealm(realm); + doNothing().when(service).addUserProfileAttributes(realm); + } + + void callCreateRealm(String namespaceName) { + service.createRealm(spec, namespaceName); + } + } + + @Nested + class UpdateRealmWithThemeTest { + @Test + void shouldCallAddRealmTheme() { + prepareMocksWithRealm(); + + callService(); + + verify(service).addRealmTheme(realm); + } + + @Test + void shouldRealmHaveTheme() { + prepareMocksWithRealm(); + + callService(); + + assertThat(realm).extracting(REALM_FIELD_LOGIN_THEME).isEqualTo(RESOLVED_THEME_NAME); + } + + void prepareMocksWithRealm() { + realm = RealmRepresentationTestFactory.create(BUNDESLAND_NAMESPACE_NAME); + when(mapper.update(realm, spec)).thenReturn(realm); + doNothing().when(remoteService).updateRealm(realm); + doNothing().when(service).addUserProfileAttributes(realm); + } + + void callService() { + service.updateRealm(realm, spec); + } + + } + + @Nested + class CreateThemeTest { + @Test + void shouldReturnSameObject() { + RealmRepresentation mock = mock(RealmRepresentation.class); + + var result = callService(mock); + + assertThat(result).isSameAs(mock); + } + + @Test + void shouldCallGetBundesland() { + realm = RealmRepresentationTestFactory.create(BUNDESLAND_NAMESPACE_NAME); + + callService(realm); + + verify(service).getBundesland(BUNDESLAND_NAMESPACE_NAME); + } + + @Test + void shouldCallCreateRealmLoginTheme() { + realm = RealmRepresentationTestFactory.create(BUNDESLAND_NAMESPACE_NAME); + + callService(realm); + + verify(service).createRealmLoginThemeName(TARGET_BUNDESLAND); + } + + RealmRepresentation callService(RealmRepresentation realm) { + return service.addRealmTheme(realm); + } + } + + @Nested + class GetBundeslandThemeTest { + @Test + void shouldReturnTheme() { + var result = service.getBundesland(BUNDESLAND_NAMESPACE_NAME); + + assertThat(result).isEqualTo(TARGET_BUNDESLAND); + } + + @Test + void shouldReturnEmptyThemeIfNull() { + var result = service.getBundesland(null); + + assertThat(result).isEqualTo(""); + } + + @Test + void shouldReturnEmptyThemeIfEmpty() { + var result = service.getBundesland(""); + + assertThat(result).isEqualTo(""); + } + + @Test + void shouldReturnEmptyThemeIfGarbage() { + var result = service.getBundesland(LOREM_IPSUM.getWords(20)); + + assertThat(result).isEqualTo(""); + } + + } + + @Nested + class CreateRealmLoginThemeNameTest { + + @Test + void shouldCreateRealmLoginTheme() { + var realmLoginThemeName = service.createRealmLoginThemeName(TARGET_BUNDESLAND); + + assertThat(realmLoginThemeName).isEqualTo(RESOLVED_THEME_NAME); + } + + @Test + void shouldReturnEmptyThemeIfEmpty() { + var realmLoginThemeName = service.createRealmLoginThemeName(""); + + assertThat(realmLoginThemeName).isEqualTo(""); + } + + @Test + void shouldReturnEmptyThemeIfNull() { + var realmLoginThemeName = service.createRealmLoginThemeName(null); + + assertThat(realmLoginThemeName).isEqualTo(""); + } + } + +} diff --git a/ozgcloud-keycloak-operator/src/test/java/de/ozgcloud/operator/keycloak/realm/RealmRepresentationTestFactory.java b/ozgcloud-keycloak-operator/src/test/java/de/ozgcloud/operator/keycloak/realm/RealmRepresentationTestFactory.java index 72a8830e8b4ffaee3a3d673945ca9508cc313f1a..ac43ec3ca65dee9c03a9c0ac8f6fab3b5322ae41 100644 --- a/ozgcloud-keycloak-operator/src/test/java/de/ozgcloud/operator/keycloak/realm/RealmRepresentationTestFactory.java +++ b/ozgcloud-keycloak-operator/src/test/java/de/ozgcloud/operator/keycloak/realm/RealmRepresentationTestFactory.java @@ -30,8 +30,11 @@ public class RealmRepresentationTestFactory { public static final String NAME = "TestRealm"; public static RealmRepresentation create() { + return create(NAME); + } + public static RealmRepresentation create(String name) { var realm = new RealmRepresentation(); - realm.setRealm(NAME); + realm.setRealm(name); return realm; }