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)); } }