mirror of https://github.com/halo-dev/halo
Fix the incorrect list options builder while listing aggregated roles (#6530)
#### What type of PR is this? /kind bug /area core /milestone 2.19.0 #### What this PR does / why we need it: This PR corrects list options builder for listing aggregated roles, because I wrongly used the label selector in <https://github.com/halo-dev/halo/pull/6471>. #### Special notes for your reviewer: 1. Try to install the plugin <https://www.halo.run/store/apps/app-YXyaD> 2. Enable the plugin and enable setting `匿名评论需要验证码` 3. **Anonymous** request any of posts with comment enabled 4. Check the captcha in comment area #### Does this PR introduce a user-facing change? ```release-note 修复可能无法正常访问插件提供的接口的问题 ```pull/6533/head
parent
ab6c20a204
commit
b6222f48a4
|
@ -190,15 +190,12 @@ public class DefaultRoleService implements RoleService {
|
|||
if (CollectionUtils.isEmpty(roleNames)) {
|
||||
return Flux.empty();
|
||||
}
|
||||
var listOptionsBuilder = Optional.ofNullable(additionalListOptions)
|
||||
var listOptions = Optional.ofNullable(additionalListOptions)
|
||||
.map(ListOptions::builder)
|
||||
.orElseGet(ListOptions::builder);
|
||||
roleNames.stream()
|
||||
.map(roleName -> Role.ROLE_AGGREGATE_LABEL_PREFIX + roleName)
|
||||
.forEach(
|
||||
label -> listOptionsBuilder.labelSelector().eq(label, Boolean.TRUE.toString())
|
||||
);
|
||||
return client.listAll(Role.class, listOptionsBuilder.build(), ExtensionUtil.defaultSort());
|
||||
.orElseGet(ListOptions::builder)
|
||||
.andQuery(QueryFactory.in("labels.aggregateToRoles", roleNames))
|
||||
.build();
|
||||
return client.listAll(Role.class, listOptions, ExtensionUtil.defaultSort());
|
||||
}
|
||||
|
||||
Predicate<RoleBinding> getRoleBindingPredicate(Subject targetSubject) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package run.halo.app.infra;
|
|||
import static org.apache.commons.lang3.BooleanUtils.isTrue;
|
||||
import static org.apache.commons.lang3.BooleanUtils.toStringTrueFalse;
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static run.halo.app.core.extension.Role.ROLE_AGGREGATE_LABEL_PREFIX;
|
||||
import static run.halo.app.extension.index.IndexAttributeFactory.multiValueAttribute;
|
||||
import static run.halo.app.extension.index.IndexAttributeFactory.simpleAttribute;
|
||||
|
||||
|
@ -75,7 +76,23 @@ public class SchemeInitializer implements ApplicationListener<ApplicationContext
|
|||
public void onApplicationEvent(@NonNull ApplicationContextInitializedEvent event) {
|
||||
var schemeManager = createSchemeManager(event);
|
||||
|
||||
schemeManager.register(Role.class);
|
||||
schemeManager.register(Role.class, is -> {
|
||||
is.add(new IndexSpec()
|
||||
.setName("labels.aggregateToRoles")
|
||||
.setIndexFunc(multiValueAttribute(Role.class,
|
||||
role -> Optional.ofNullable(role.getMetadata().getLabels())
|
||||
.map(labels -> labels.keySet()
|
||||
.stream()
|
||||
.filter(key -> key.startsWith(ROLE_AGGREGATE_LABEL_PREFIX))
|
||||
.filter(key -> Boolean.parseBoolean(labels.get(key)))
|
||||
.map(
|
||||
key -> StringUtils.removeStart(key, ROLE_AGGREGATE_LABEL_PREFIX)
|
||||
)
|
||||
.collect(Collectors.toSet())
|
||||
)
|
||||
.orElseGet(Set::of)))
|
||||
);
|
||||
});
|
||||
|
||||
// plugin.halo.run
|
||||
schemeManager.register(Plugin.class);
|
||||
|
|
|
@ -6,19 +6,18 @@ import static org.mockito.Mockito.times;
|
|||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.PUT;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
import static run.halo.app.core.extension.Role.ROLE_AGGREGATE_LABEL_PREFIX;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -26,8 +25,10 @@ import org.springframework.lang.NonNull;
|
|||
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
@ -35,26 +36,31 @@ import reactor.core.publisher.Mono;
|
|||
import run.halo.app.core.extension.Role;
|
||||
import run.halo.app.core.extension.Role.PolicyRule;
|
||||
import run.halo.app.core.extension.service.RoleService;
|
||||
import run.halo.app.extension.ExtensionClient;
|
||||
import run.halo.app.extension.Metadata;
|
||||
import run.halo.app.infra.AnonymousUserConst;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureWebTestClient
|
||||
@DirtiesContext
|
||||
@Import(AuthorizationTest.TestConfig.class)
|
||||
class AuthorizationTest {
|
||||
|
||||
@Autowired
|
||||
WebTestClient webClient;
|
||||
|
||||
@MockBean
|
||||
@SpyBean
|
||||
ReactiveUserDetailsService userDetailsService;
|
||||
|
||||
@MockBean
|
||||
@SpyBean
|
||||
ReactiveUserDetailsPasswordService userDetailsPasswordService;
|
||||
|
||||
@MockBean
|
||||
@SpyBean
|
||||
RoleService roleService;
|
||||
|
||||
@Autowired
|
||||
ExtensionClient client;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
webClient = webClient.mutateWith(csrf());
|
||||
|
@ -122,16 +128,45 @@ class AuthorizationTest {
|
|||
verify(roleService).listDependenciesFlux(anySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
void anonymousUserShouldAccessResourcesByAggregatedRoles() {
|
||||
// create a role
|
||||
var role = new Role();
|
||||
role.setMetadata(new Metadata());
|
||||
role.getMetadata().setName("fake-role-with-aggregate-to-anonymous");
|
||||
role.getMetadata().setLabels(new HashMap<>(Map.of(
|
||||
ROLE_AGGREGATE_LABEL_PREFIX + AnonymousUserConst.Role, "true"
|
||||
)));
|
||||
role.setRules(new ArrayList<>());
|
||||
var policyRule = new PolicyRule.Builder()
|
||||
.apiGroups("fake.halo.run")
|
||||
.verbs("list")
|
||||
.resources("fakes")
|
||||
.build();
|
||||
role.getRules().add(policyRule);
|
||||
client.create(role);
|
||||
|
||||
webClient.get().uri("/apis/fake.halo.run/v1/fakes").exchange()
|
||||
.expectStatus()
|
||||
.isOk();
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
static class TestConfig {
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> postRoute() {
|
||||
return route(
|
||||
GET("/apis/fake.halo.run/v1/posts").and(accept(MediaType.APPLICATION_JSON)),
|
||||
this::queryPosts).andRoute(
|
||||
PUT("/apis/fake.halo.run/v1/posts/{name}").and(accept(MediaType.APPLICATION_JSON)),
|
||||
this::updatePost);
|
||||
return RouterFunctions.route()
|
||||
.GET("/apis/fake.halo.run/v1/posts", request -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue("returned posts")
|
||||
)
|
||||
.PUT("/apis/fake.halo.run/v1/posts/{name}", request -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue("updated post " + request.pathVariable("name"))
|
||||
)
|
||||
.GET("/apis/fake.halo.run/v1/fakes", request -> ServerResponse.ok().build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
Loading…
Reference in New Issue