package com.mgm.mcrm; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.mgm.mcrm.appsetting.controllers.CfgSettingController; import com.mgm.mcrm.appsetting.dtos.CfgSettingQueryRequest; import com.mgm.mcrm.appsetting.models.CfgSettings; import com.mgm.mcrm.appsetting.models.SysSetting; import com.mgm.mcrm.appsetting.services.SettingService; import com.mgm.mcrm.appsetting.services.SysSettingService; import com.mgm.mcrm.authorization.services.UserTokenService; import com.mgm.mcrm.common.config.WebFilterConfig; import com.mgm.mcrm.logging.controllers.SysLogAppController; import com.mgm.mcrm.logging.dtos.AppLogDto; import com.mgm.mcrm.logging.models.SysLogApp; import com.mgm.mcrm.logging.services.SysLogAppService; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; class PublicEndpointsMigrationTest { @Test void publicConfigurationRejectsOtherKeysBeforeQuery() throws Exception { var service = mock(SettingService.class); var controller = new CfgSettingController(); ReflectionTestUtils.setField(controller, "settingService", service); for (String key : new String[]{null, "", "MACAU_IP", "macau_string", "MACAU_STRING "}) { var query = new CfgSettingQueryRequest(); query.setKeyName(key); var result = controller.getPublicSettingByKey(new MockHttpServletRequest(), query).getBody(); assertFalse(result.isSuccess()); assertEquals("SETTING_KEY_NOT_ALLOWED", result.getCode()); } assertFalse(controller.getPublicSettingByKey(new MockHttpServletRequest(), null).getBody().isSuccess()); verifyNoInteractions(service); var setting = new CfgSettings(); when(service.getSettingByKey("MACAU_STRING")).thenReturn(setting); var query = new CfgSettingQueryRequest(); query.setKeyName("MACAU_STRING"); assertSame(setting, controller.getPublicSettingByKey(new MockHttpServletRequest(), query).getBody().getData()); verify(service).getSettingByKey("MACAU_STRING"); } @Test void publicLoginSettingsOnlyFetchTwoAllowedKeysAndAllowMissingSettings() { var service = mock(SysSettingService.class); var controller = new CfgSettingController(); ReflectionTestUtils.setField(controller, "sysSettingService", service); var sso = new SysSetting(); var tpd = new SysSetting(); when(service.getSysSettingByKey("APP_MOCK_SSO")).thenReturn(sso); when(service.getSysSettingByKey("APP_MOCK_TPD")).thenReturn(tpd); assertEquals(java.util.List.of(sso, tpd), controller.getPublicLoginSettings(new MockHttpServletRequest()).getBody().getData()); verify(service).getSysSettingByKey("APP_MOCK_SSO"); verify(service).getSysSettingByKey("APP_MOCK_TPD"); verifyNoMoreInteractions(service); when(service.getSysSettingByKey("APP_MOCK_TPD")).thenReturn(null); assertEquals(1, controller.getPublicLoginSettings(new MockHttpServletRequest()).getBody().getData().size()); } @Test void filterAllowsOnlyNewPublicRoutesAndKeepsRefreshProtected() throws Exception { var config = new WebFilterConfig(); var tokens = mock(UserTokenService.class); ReflectionTestUtils.setField(config, "secretKey", "test-only-key"); ReflectionTestUtils.setField(config, "userTokenService", tokens); var filter = config.jwtAuthFilter().getFilter(); for (String route : new String[]{"/system/write_public_log", "/system/sys_setting/get_public_login_settings", "/web/setting/get_public_setting_by_key"}) { var reached = new AtomicBoolean(); filter.doFilter(new MockHttpServletRequest("POST", "/api" + route), new MockHttpServletResponse(), (req, res) -> reached.set(true)); assertTrue(reached.get(), route); } for (String route : new String[]{"/system/write_log", "/system/sys_setting/get_list", "/web/setting/get_setting_by_key", "/app/booking/mock_cancel", "/app/refresh_token"}) { var reached = new AtomicBoolean(); var response = new MockHttpServletResponse(); filter.doFilter(new MockHttpServletRequest("POST", "/api" + route), response, (req, res) -> reached.set(true)); assertFalse(reached.get(), route); assertEquals(401, response.getStatus(), route); } } private SysLogAppController logs(SysLogAppService service) { var controller = new SysLogAppController(); ReflectionTestUtils.setField(controller, "logService", service); when(service.save(any(SysLogApp.class))).thenAnswer(call -> call.getArgument(0)); return controller; } @Test void anonymousIdentityCannotBeSpoofedAndNullBodiesAreSafe() { var service = mock(SysLogAppService.class); var controller = logs(service); var dto = new AppLogDto(); dto.setLoginId("admin"); var result = controller.writePublicAppLog(new MockHttpServletRequest(), dto).getBody().getData(); assertEquals("ANONYMOUS", result.getLoginId()); assertNull(result.getLogDesc()); assertNull(result.getRequestBody()); assertNull(result.getResponseBody()); assertEquals(0, result.getTagSuccess()); assertEquals(400, controller.writePublicAppLog(new MockHttpServletRequest(), null).getStatusCode().value()); verify(service, times(1)).save(any(SysLogApp.class)); } @Test void authenticatedLogUsesTokenIdentityAndRequiresIdentity() { var service = mock(SysLogAppService.class); var controller = logs(service); var dto = new AppLogDto(); dto.setLoginId("forged-user"); var request = new MockHttpServletRequest(); assertEquals(401, controller.writeAppLog(request, dto).getStatusCode().value()); verify(service, never()).save(any()); // Controller identity test; JWT admission is covered separately by the filter test. request.addHeader("Authorization", "Bearer " + JWT.create().withSubject("80001") .withClaim("login_id", "actual-user").sign(Algorithm.HMAC256("test-only-key"))); assertEquals("actual-user", controller.writeAppLog(request, dto).getBody().getData().getLoginId()); } @Test void logsLimitInputAndEscapeText() { var controller = logs(mock(SysLogAppService.class)); var dto = new AppLogDto(); dto.setEventCode("e".repeat(101)); dto.setTransId("t".repeat(101)); dto.setLogDesc("x".repeat(999) + "&"); var log = controller.writePublicAppLog(new MockHttpServletRequest(), dto).getBody().getData(); assertEquals(100, log.getEventCode().length()); assertEquals(100, log.getTransId().length()); assertEquals("x".repeat(999) + "<", log.getLogDesc()); assertEquals(4000, log.getRequestBody().length()); assertEquals("<script>&", log.getResponseBody()); } @Test void httpRejectsMissingAndMalformedLogBodiesWithoutSaving() throws Exception { var service = mock(SysLogAppService.class); var mvc = MockMvcBuilders.standaloneSetup(logs(service)).build(); mvc.perform(post("/api/system/write_public_log")).andExpect(status().isBadRequest()); mvc.perform(post("/api/system/write_public_log").contentType("application/json") .content("{\"tagSuccess\":\"not-a-number\"}")).andExpect(status().isBadRequest()); verify(service, never()).save(any()); } }