package com.example.keycloakpattern; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.servlet.MockMvc; @SpringBootTest @AutoConfigureMockMvc class ApiSecurityTest { @Autowired private MockMvc mockMvc; @Test void publicEndpointDoesNotRequireAuthentication() throws Exception { mockMvc.perform(get("/api/public")) .andExpect(status().isOk()) .andExpect(jsonPath("$.status").value("ok")); } @Test void echoEndpointReflectsForwardedHeadersWithoutAuthentication() throws Exception { mockMvc.perform(get("/api/echo") .header("X-Forwarded-Proto", "https") .header("X-Forwarded-Host", "app1.example.test")) .andExpect(status().isOk()) .andExpect(jsonPath("$.headers['x-forwarded-proto'][0]").value("https")) .andExpect(jsonPath("$.headers['x-forwarded-host'][0]").value("app1.example.test")) .andExpect(jsonPath("$.requestUrl").exists()) .andExpect(jsonPath("$.remoteAddr").exists()); } @Test void protectedEndpointRejectsAnonymousRequests() throws Exception { mockMvc.perform(get("/api/me")) .andExpect(status().isUnauthorized()); } @Test void protectedEndpointAcceptsJwtAuthentication() throws Exception { mockMvc.perform(get("/api/me").with(jwt().jwt(token -> token .subject("test-subject") .claim("preferred_username", "regular-user")))) .andExpect(status().isOk()) .andExpect(jsonPath("$.subject").value("test-subject")) .andExpect(jsonPath("$.username").value("regular-user")); } }