From d97d27f827b394b50bc4e4b3ea67290da96f8e4b Mon Sep 17 00:00:00 2001 From: Martin Kylian Date: Mon, 28 Jul 2025 10:07:52 +0200 Subject: [PATCH] Kerberos Server fields now trims whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #41335 Signed-off-by: Martin Kylián Signed-off-by: Alexander Schwartz Co-authored-by: Martin Kylián Co-authored-by: Alexander Schwartz --- federation/kerberos/pom.xml | 10 ++ .../kerberos/CommonKerberosConfig.java | 2 - .../KerberosFederationProviderFactory.java | 20 ++++ ...KerberosFederationProviderFactoryTest.java | 101 ++++++++++++++++++ 4 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 federation/kerberos/src/test/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactoryTest.java diff --git a/federation/kerberos/pom.xml b/federation/kerberos/pom.xml index 95e483b06bf..cf21b968d88 100755 --- a/federation/kerberos/pom.xml +++ b/federation/kerberos/pom.xml @@ -55,6 +55,16 @@ jboss-logging provided + + junit + junit + test + + + org.hamcrest + hamcrest + test + diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java index d9c3d2074a6..b5e36f0806b 100644 --- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java +++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java @@ -22,8 +22,6 @@ import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.component.ComponentModel; import org.keycloak.representations.idm.ComponentRepresentation; -import java.util.Map; - /** * Common configuration useful for all providers * diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java index a197a5355fb..54bd05328b5 100755 --- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java +++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java @@ -38,6 +38,7 @@ import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProviderFactory; import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.utils.CredentialHelper; +import org.keycloak.component.ComponentValidationException; import java.util.List; @@ -168,4 +169,23 @@ public class KerberosFederationProviderFactory implements UserStorageProviderFac CredentialHelper.setOrReplaceAuthenticationRequirement(session, realm, CredentialRepresentation.KERBEROS, AuthenticationExecutionModel.Requirement.DISABLED, null); } + + @Override + public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException { + // Trim whitespace from string configuration values + trimConfigValue(config, KerberosConstants.SERVER_PRINCIPAL); + trimConfigValue(config, KerberosConstants.KERBEROS_REALM); + trimConfigValue(config, KerberosConstants.KEYTAB); + } + + private void trimConfigValue(ComponentModel config, String configKey) { + String value = config.getConfig().getFirst(configKey); + if (value != null) { + String trimmedValue = value.trim(); + if (!value.equals(trimmedValue)) { + // Update the config with trimmed value + config.getConfig().putSingle(configKey, trimmedValue); + } + } + } } diff --git a/federation/kerberos/src/test/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactoryTest.java b/federation/kerberos/src/test/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactoryTest.java new file mode 100644 index 00000000000..cfc28c6eab8 --- /dev/null +++ b/federation/kerberos/src/test/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactoryTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2024 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * 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. + */ + +package org.keycloak.federation.kerberos; + +import org.junit.Assert; +import org.junit.Test; +import org.keycloak.common.constants.KerberosConstants; +import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.component.ComponentModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; + +/** + * Tests for KerberosFederationProviderFactory validation functionality. + */ +public class KerberosFederationProviderFactoryTest { + + @Test + public void testValidateConfigurationTrimsValues() throws Exception { + KerberosFederationProviderFactory factory = new KerberosFederationProviderFactory(); + + ComponentModel config = new ComponentModel(); + MultivaluedHashMap configMap = new MultivaluedHashMap<>(); + configMap.add(KerberosConstants.SERVER_PRINCIPAL, " myPrincipal "); + configMap.add(KerberosConstants.KERBEROS_REALM, " MYREALM.COM "); + configMap.add(KerberosConstants.KEYTAB, " /path/to/keytab "); + config.setConfig(configMap); + + // Mock session and realm (not used in current implementation) + KeycloakSession session = null; + RealmModel realm = null; + + // Call validateConfiguration + factory.validateConfiguration(session, realm, config); + + // Verify values are trimmed + Assert.assertEquals("myPrincipal", config.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL)); + Assert.assertEquals("MYREALM.COM", config.getConfig().getFirst(KerberosConstants.KERBEROS_REALM)); + Assert.assertEquals("/path/to/keytab", config.getConfig().getFirst(KerberosConstants.KEYTAB)); + } + + @Test + public void testValidateConfigurationHandlesNullValues() throws Exception { + KerberosFederationProviderFactory factory = new KerberosFederationProviderFactory(); + + ComponentModel config = new ComponentModel(); + MultivaluedHashMap configMap = new MultivaluedHashMap<>(); + config.setConfig(configMap); + + // Mock session and realm (not used in current implementation) + KeycloakSession session = null; + RealmModel realm = null; + + // Call validateConfiguration - should not throw exception + factory.validateConfiguration(session, realm, config); + + // Verify null values remain null + Assert.assertNull(config.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL)); + Assert.assertNull(config.getConfig().getFirst(KerberosConstants.KERBEROS_REALM)); + Assert.assertNull(config.getConfig().getFirst(KerberosConstants.KEYTAB)); + } + + @Test + public void testValidateConfigurationHandlesAlreadyTrimmedValues() throws Exception { + KerberosFederationProviderFactory factory = new KerberosFederationProviderFactory(); + + ComponentModel config = new ComponentModel(); + MultivaluedHashMap configMap = new MultivaluedHashMap<>(); + configMap.add(KerberosConstants.SERVER_PRINCIPAL, "myPrincipal"); + configMap.add(KerberosConstants.KERBEROS_REALM, "MYREALM.COM"); + configMap.add(KerberosConstants.KEYTAB, "/path/to/keytab"); + config.setConfig(configMap); + + // Mock session and realm (not used in current implementation) + KeycloakSession session = null; + RealmModel realm = null; + + // Call validateConfiguration + factory.validateConfiguration(session, realm, config); + + // Verify values remain unchanged + Assert.assertEquals("myPrincipal", config.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL)); + Assert.assertEquals("MYREALM.COM", config.getConfig().getFirst(KerberosConstants.KERBEROS_REALM)); + Assert.assertEquals("/path/to/keytab", config.getConfig().getFirst(KerberosConstants.KEYTAB)); + } +} \ No newline at end of file