diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliDryRunValidateTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliDryRunValidateTest.java index 0e10d343..f2224de0 100644 --- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliDryRunValidateTest.java +++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliDryRunValidateTest.java @@ -37,7 +37,9 @@ class CliDryRunValidateTest { PlatformPrincipal principal = new PlatformPrincipal( "user-1", "tester", "t@example.com", "", "api_token", Set.of("USER")); return new UsernamePasswordAuthenticationToken( - principal, null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); + principal, null, List.of( + new SimpleGrantedAuthority("ROLE_USER"), + new SimpleGrantedAuthority("SCOPE_skill:publish"))); } @Test diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliSkillControllerTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliSkillControllerTest.java index 16a76839..d7edf81d 100644 --- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliSkillControllerTest.java +++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/controller/cli/CliSkillControllerTest.java @@ -103,7 +103,9 @@ class CliSkillControllerTest { PlatformPrincipal principal = new PlatformPrincipal( "user-1", "tester", "t@example.com", "", "api_token", Set.of("USER")); var auth = new UsernamePasswordAuthenticationToken( - principal, null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); + principal, null, List.of( + new SimpleGrantedAuthority("ROLE_USER"), + new SimpleGrantedAuthority("SCOPE_skill:delete"))); given(cliSkillAppService.deleteRemote( org.mockito.ArgumentMatchers.eq("global"), diff --git a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilter.java b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilter.java index 8f69d5aa..97145f5d 100644 --- a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilter.java +++ b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilter.java @@ -70,7 +70,8 @@ public class ApiTokenScopeFilter extends OncePerRequestFilter { protected boolean shouldNotFilter(HttpServletRequest request) { String path = request.getRequestURI(); return path == null || (!path.startsWith("/api/v1/") - && !path.startsWith("/api/web/")); + && !path.startsWith("/api/web/") + && !path.startsWith("/api/cli/")); } private boolean isApiTokenAuthentication(Authentication authentication) { diff --git a/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilterTest.java b/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilterTest.java index 9156eba8..788e0291 100644 --- a/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilterTest.java +++ b/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/token/ApiTokenScopeFilterTest.java @@ -134,4 +134,40 @@ class ApiTokenScopeFilterTest { assertTrue(response.getErrorMessage().contains("Missing API token scope: skill:publish")); verify(chain, never()).doFilter(request, response); } + + @Test + void shouldDenyApiCliRequestsWithoutRequiredScope() throws Exception { + AccessDeniedHandler handler = (request, response, accessDeniedException) -> { + response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage()); + }; + ApiTokenScopeFilter filter = new ApiTokenScopeFilter(scopeService, handler); + + PlatformPrincipal principal = new PlatformPrincipal( + "user-4", + "Dave", + "dave@example.com", + "", + "api_token", + Set.of("USER") + ); + var authentication = new UsernamePasswordAuthenticationToken( + principal, + null, + List.of( + new SimpleGrantedAuthority("ROLE_USER"), + new SimpleGrantedAuthority("SCOPE_skill:read") + ) + ); + SecurityContextHolder.getContext().setAuthentication(authentication); + + MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/cli/v1/skills/global/publish/validate"); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = mock(FilterChain.class); + + filter.doFilter(request, response, chain); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); + assertTrue(response.getErrorMessage().contains("Missing API token scope: skill:publish")); + verify(chain, never()).doFilter(request, response); + } }