mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-28 11:25:00 +00:00
fix(auth): close API token scope filter gap on /api/cli/ routes
ApiTokenAuthenticationFilter authenticates /api/cli/** Bearer tokens but ApiTokenScopeFilter.shouldNotFilter() previously skipped them. The result: API token requests on CLI routes were authenticated and authorization-policy-checked, but scope enforcement never ran. Tokens without skill:publish or skill:delete could call /publish, /publish/validate, and DELETE despite the policy table requiring those scopes. Add /api/cli/ to the scope filter's covered prefixes and a filter-level test that confirms a token missing skill:publish is rejected on the new validate endpoint. Update the existing CLI controller tests to grant the appropriate SCOPE_* authorities to their api_token principals so they continue to pass under enforced scopes.
This commit is contained in:
parent
943294b558
commit
d7d0790b28
4 changed files with 44 additions and 3 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue