diff --git a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakIngressDependentResource.java b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakIngressDependentResource.java index 4dd52f68dd..5d97c2c8c0 100644 --- a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakIngressDependentResource.java +++ b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakIngressDependentResource.java @@ -24,11 +24,14 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernete import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; +import io.quarkus.logging.Log; import org.keycloak.operator.Constants; import org.keycloak.operator.Utils; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.Optional; @@ -107,7 +110,17 @@ public class KeycloakIngressDependentResource extends CRUDKubernetesDependentRes final var hostnameSpec = keycloak.getSpec().getHostnameSpec(); if (hostnameSpec != null && hostnameSpec.getHostname() != null) { - ingress.getSpec().getRules().get(0).setHost(hostnameSpec.getHostname()); + String hostname = hostnameSpec.getHostname(); + + try { + hostname = new URL(hostname).getHost(); + Log.debug("Hostname is a URL, extracting host: " + hostname); + } + catch (MalformedURLException e) { + Log.debug("Hostname is not a URL, using as is: " + hostname); + } + + ingress.getSpec().getRules().get(0).setHost(hostname); } return ingress; diff --git a/operator/src/test/java/org/keycloak/operator/testsuite/unit/IngressLogicTest.java b/operator/src/test/java/org/keycloak/operator/testsuite/unit/IngressLogicTest.java index 87798bddf0..ce3176c2ac 100644 --- a/operator/src/test/java/org/keycloak/operator/testsuite/unit/IngressLogicTest.java +++ b/operator/src/test/java/org/keycloak/operator/testsuite/unit/IngressLogicTest.java @@ -41,7 +41,7 @@ public class IngressLogicTest { static class MockKeycloakIngress { - private static Keycloak getKeycloak(boolean tlsConfigured, IngressSpec ingressSpec) { + private static Keycloak getKeycloak(boolean tlsConfigured, IngressSpec ingressSpec, String hostname) { var kc = K8sUtils.getDefaultKeycloakDeployment(); kc.getMetadata().setUid("this-is-a-fake-uid"); if (ingressSpec != null) { @@ -50,6 +50,9 @@ public class IngressLogicTest { if (!tlsConfigured) { kc.getSpec().getHttpSpec().setTlsSecret(null); } + if (hostname != null) { + kc.getSpec().getHostnameSpec().setHostname(hostname); + } return kc; } @@ -58,10 +61,18 @@ public class IngressLogicTest { } public static MockKeycloakIngress build(Boolean defaultIngressEnabled, boolean ingressExists, boolean ingressSpecDefined, boolean tlsConfigured) { - return build(defaultIngressEnabled, ingressExists, ingressSpecDefined, tlsConfigured, null); + return build(defaultIngressEnabled, ingressExists, ingressSpecDefined, tlsConfigured, null, null); + } + + public static MockKeycloakIngress build(String hostname) { + return build(true, false, true, true, null, hostname); } public static MockKeycloakIngress build(Boolean defaultIngressEnabled, boolean ingressExists, boolean ingressSpecDefined, boolean tlsConfigured, Map annotations) { + return build(defaultIngressEnabled, ingressExists, ingressSpecDefined, tlsConfigured, annotations, null); + } + + public static MockKeycloakIngress build(Boolean defaultIngressEnabled, boolean ingressExists, boolean ingressSpecDefined, boolean tlsConfigured, Map annotations, String hostname) { IngressSpec ingressSpec = null; if (ingressSpecDefined) { ingressSpec = new IngressSpec(); @@ -72,7 +83,7 @@ public class IngressLogicTest { ingressSpec.setAnnotations(annotations); } } - MockKeycloakIngress mock = new MockKeycloakIngress(tlsConfigured, ingressSpec); + MockKeycloakIngress mock = new MockKeycloakIngress(tlsConfigured, ingressSpec, hostname); mock.ingressExists = ingressExists; return mock; } @@ -82,8 +93,12 @@ public class IngressLogicTest { private boolean deleted = false; private Keycloak keycloak; + public MockKeycloakIngress(boolean tlsConfigured, IngressSpec ingressSpec, String hostname) { + this.keycloak = getKeycloak(tlsConfigured, ingressSpec, hostname); + } + public MockKeycloakIngress(boolean tlsConfigured, IngressSpec ingressSpec) { - this.keycloak = getKeycloak(tlsConfigured, ingressSpec); + this(tlsConfigured, ingressSpec, null); } public boolean reconciled() { @@ -101,7 +116,7 @@ public class IngressLogicTest { } return Optional.empty(); } - + return Optional.of(keycloakIngressDependentResource.desired(keycloak, null)); } } @@ -217,4 +232,12 @@ public class IngressLogicTest { Ingress ingress = reconciled.map(Ingress.class::cast).orElseThrow(); assertEquals("my-class", ingress.getSpec().getIngressClassName()); } + + @Test + public void testHostnameSanitizing() { + var kc = MockKeycloakIngress.build("https://my-other.example.com:443/my-path"); + Optional reconciled = kc.getReconciledResource(); + Ingress ingress = reconciled.map(Ingress.class::cast).orElseThrow(); + assertEquals("my-other.example.com", ingress.getSpec().getRules().get(0).getHost()); + } }