From 3db6a326bff257ac7cec00a886c3bde7426b63fa Mon Sep 17 00:00:00 2001
From: Charley Wu <akunzai@gmail.com>
Date: Wed, 26 Aug 2026 11:32:29 +0000
Subject: [PATCH] Add unit tests for CAS RedirectUtils

---
 src/test/java/org/keycloak/protocol/cas/RedirectUtilsTest.java |  164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 164 insertions(+), 0 deletions(-)

diff --git a/src/test/java/org/keycloak/protocol/cas/RedirectUtilsTest.java b/src/test/java/org/keycloak/protocol/cas/RedirectUtilsTest.java
new file mode 100644
index 0000000..5ebb698
--- /dev/null
+++ b/src/test/java/org/keycloak/protocol/cas/RedirectUtilsTest.java
@@ -0,0 +1,164 @@
+package org.keycloak.protocol.cas;
+
+import org.junit.jupiter.api.Test;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakUriInfo;
+import org.keycloak.protocol.cas.utils.RedirectUtils;
+
+import java.net.URI;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RedirectUtilsTest {
+
+    private KeycloakSession createMockSession() {
+        KeycloakSession session = mock(KeycloakSession.class);
+        KeycloakContext context = mock(KeycloakContext.class);
+        KeycloakUriInfo uriInfo = mock(KeycloakUriInfo.class);
+        when(session.getContext()).thenReturn(context);
+        when(context.getUri()).thenReturn(uriInfo);
+        when(uriInfo.getBaseUri()).thenReturn(URI.create("http://localhost:8080/auth/"));
+        return session;
+    }
+
+    private ClientModel createMockClient(String... redirectUris) {
+        ClientModel client = mock(ClientModel.class);
+        when(client.getRedirectUris()).thenReturn(Set.of(redirectUris));
+        return client;
+    }
+
+    @Test
+    public void testVerifyRedirectUriNull() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = mock(ClientModel.class);
+        assertNull(RedirectUtils.verifyRedirectUri(session, null, client));
+        assertNull(RedirectUtils.verifyRedirectUri(session, "https://localhost:5003/signin-cas", null));
+        assertNull(RedirectUtils.verifyRedirectUri(session, null, null));
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithoutForbiddenParams() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String serviceUrl = "https://localhost:5003/signin-cas";
+        String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+
+        assertEquals(serviceUrl, verified);
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithState() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String serviceUrl = "https://localhost:5003/signin-cas?state=CfDJ81234567890";
+        String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+
+        assertEquals(serviceUrl, verified);
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithAllowedQueryParams() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String[] allowedParams = new String[]{"code", "id_token", "access_token", "session_state", "error", "custom_param"};
+        for (String param : allowedParams) {
+            String serviceUrl = "https://localhost:5003/signin-cas?" + param + "=testValue";
+            String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+            assertEquals(serviceUrl, verified, "Should be allowed for parameter: " + param);
+        }
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithEncodedChars() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String serviceUrl = "https://localhost:5003/signin-cas?state=CfDJ8%20123";
+        String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+
+        assertEquals(serviceUrl, verified);
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithForbiddenCasParams() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String[] forbiddenParams = new String[]{"ticket", "TICKET", "Ticket", "SAMLart", "samlart", "SAMLART"};
+        for (String param : forbiddenParams) {
+            String serviceUrl = "https://localhost:5003/signin-cas?" + param + "=ST-123456";
+            String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+            assertNull(verified, "Should be rejected for parameter: " + param);
+        }
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithStateAndForbiddenCasParam() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String serviceUrl = "https://localhost:5003/signin-cas?state=CfDJ8&ticket=ST-123456";
+        String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+
+        assertNull(verified);
+
+        String samlUrl = "https://localhost:5003/signin-cas?state=CfDJ8&SAMLart=ST-123456";
+        String samlVerified = RedirectUtils.verifyRedirectUri(session, samlUrl, client);
+
+        assertNull(samlVerified);
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithStateAndCustomParam() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String serviceUrl = "https://localhost:5003/signin-cas?state=CfDJ8&custom_param=value123";
+        String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+
+        assertEquals(serviceUrl, verified);
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithFragment() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String serviceUrl = "https://localhost:5003/signin-cas?state=CfDJ8#section1";
+        String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+
+        assertEquals(serviceUrl, verified);
+    }
+
+    @Test
+    public void testVerifyRedirectUriInvalidDomain() {
+        KeycloakSession session = createMockSession();
+        ClientModel client = createMockClient("https://localhost:5003/*");
+
+        String serviceUrl = "https://evil.com/signin-cas?state=CfDJ8";
+        String verified = RedirectUtils.verifyRedirectUri(session, serviceUrl, client);
+
+        assertNull(verified);
+    }
+
+    @Test
+    public void testVerifyRedirectUriWithoutRequireRedirectUri() {
+        KeycloakSession session = createMockSession();
+        ClientModel singleRedirectClient = createMockClient("https://localhost:5003/*");
+
+        String verified = RedirectUtils.verifyRedirectUri(session, null, singleRedirectClient, false);
+        assertEquals("https://localhost:5003", verified);
+
+        ClientModel multiRedirectClient = createMockClient("https://localhost:5003/*", "https://localhost:5004/*");
+        assertNull(RedirectUtils.verifyRedirectUri(session, null, multiRedirectClient, false));
+    }
+}

--
Gitblit v1.10.0