1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.persistence.jpa.dao;
20
21 import static org.assertj.core.api.Assertions.assertThat;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertFalse;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.Mockito.doAnswer;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.when;
30
31 import co.elastic.clients.elasticsearch._types.SearchType;
32 import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
33 import co.elastic.clients.elasticsearch._types.query_dsl.DisMaxQuery;
34 import co.elastic.clients.elasticsearch._types.query_dsl.Query;
35 import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
36 import co.elastic.clients.elasticsearch.core.SearchRequest;
37 import java.io.IOException;
38 import java.util.List;
39 import java.util.Optional;
40 import java.util.Set;
41 import org.apache.commons.lang3.tuple.Triple;
42 import org.apache.syncope.common.lib.SyncopeConstants;
43 import org.apache.syncope.common.lib.types.AnyTypeKind;
44 import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
45 import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
46 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
47 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
48 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
49 import org.apache.syncope.core.persistence.api.dao.search.AttrCond;
50 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
51 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
52 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
53 import org.apache.syncope.core.persistence.api.entity.DynRealm;
54 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
55 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
56 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
57 import org.apache.syncope.core.persistence.api.entity.Realm;
58 import org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema;
59 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue;
60 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
61 import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
62 import org.apache.syncope.core.spring.security.AuthContextUtils;
63 import org.apache.syncope.ext.elasticsearch.client.ElasticsearchUtils;
64 import org.junit.jupiter.api.BeforeEach;
65 import org.junit.jupiter.api.Test;
66 import org.junit.jupiter.api.extension.ExtendWith;
67 import org.mockito.Mock;
68 import org.mockito.MockedStatic;
69 import org.mockito.Mockito;
70 import org.mockito.junit.jupiter.MockitoExtension;
71 import org.springframework.util.ReflectionUtils;
72
73 @ExtendWith(MockitoExtension.class)
74 public class ElasticsearchAnySearchDAOTest {
75
76 @Mock
77 private RealmDAO realmDAO;
78
79 @Mock
80 private DynRealmDAO dynRealmDAO;
81
82 @Mock
83 private GroupDAO groupDAO;
84
85 @Mock
86 private EntityFactory entityFactory;
87
88 @Mock
89 private AnyUtilsFactory anyUtilsFactory;
90
91 @Mock
92 private PlainAttrValidationManager validator;
93
94 private ElasticsearchAnySearchDAO searchDAO;
95
96 @BeforeEach
97 protected void setupSearchDAO() {
98 searchDAO = new ElasticsearchAnySearchDAO(
99 realmDAO,
100 dynRealmDAO,
101 null,
102 groupDAO,
103 null,
104 null,
105 entityFactory,
106 anyUtilsFactory,
107 validator,
108 null,
109 10000);
110 }
111
112 @Test
113 public void getAdminRealmsFilter4realm() throws IOException {
114
115 Realm root = mock(Realm.class);
116 when(root.getFullPath()).thenReturn(SyncopeConstants.ROOT_REALM);
117
118 when(realmDAO.findByFullPath(SyncopeConstants.ROOT_REALM)).thenReturn(root);
119 when(realmDAO.findDescendants(eq(SyncopeConstants.ROOT_REALM), anyString())).thenReturn(List.of("rootKey"));
120
121
122 Set<String> adminRealms = Set.of(SyncopeConstants.ROOT_REALM);
123 Triple<Optional<Query>, Set<String>, Set<String>> filter =
124 searchDAO.getAdminRealmsFilter(root, true, adminRealms, AnyTypeKind.USER);
125
126 assertThat(new Query.Builder().disMax(QueryBuilders.disMax().queries(
127 new Query.Builder().term(QueryBuilders.term().field("realm").value("rootKey").build()).
128 build()).build()).build()).
129 usingRecursiveComparison().isEqualTo(filter.getLeft().get());
130 assertEquals(Set.of(), filter.getMiddle());
131 assertEquals(Set.of(), filter.getRight());
132 }
133
134 @Test
135 public void getAdminRealmsFilter4dynRealm() {
136
137 DynRealm dyn = mock(DynRealm.class);
138 when(dyn.getKey()).thenReturn("dyn");
139
140 when(dynRealmDAO.find("dyn")).thenReturn(dyn);
141
142
143 Set<String> adminRealms = Set.of("dyn");
144 Triple<Optional<Query>, Set<String>, Set<String>> filter =
145 searchDAO.getAdminRealmsFilter(realmDAO.getRoot(), true, adminRealms, AnyTypeKind.USER);
146 assertFalse(filter.getLeft().isPresent());
147 assertEquals(Set.of("dyn"), filter.getMiddle());
148 assertEquals(Set.of(), filter.getRight());
149 }
150
151 @Test
152 public void getAdminRealmsFilter4groupOwner() {
153 Set<String> adminRealms = Set.of(RealmUtils.getGroupOwnerRealm("/any", "groupKey"));
154 Triple<Optional<Query>, Set<String>, Set<String>> filter =
155 searchDAO.getAdminRealmsFilter(realmDAO.getRoot(), true, adminRealms, AnyTypeKind.USER);
156 assertFalse(filter.getLeft().isPresent());
157 assertEquals(Set.of(), filter.getMiddle());
158 assertEquals(Set.of("groupKey"), filter.getRight());
159 }
160
161 @Test
162 public void searchRequest4groupOwner() throws IOException {
163
164 AnyUtils anyUtils = mock(AnyUtils.class);
165 when(anyUtils.getField("key")).thenReturn(ReflectionUtils.findField(JPAUser.class, "id"));
166 when(anyUtils.newPlainAttrValue()).thenReturn(new JPAUPlainAttrValue());
167
168 when(anyUtilsFactory.getInstance(AnyTypeKind.USER)).thenReturn(anyUtils);
169
170 when(entityFactory.newEntity(PlainSchema.class)).thenReturn(new JPAPlainSchema());
171
172 when(groupDAO.findKey("groupKey")).thenReturn("groupKey");
173
174 try (MockedStatic<ElasticsearchUtils> utils = Mockito.mockStatic(ElasticsearchUtils.class)) {
175 utils.when(() -> ElasticsearchUtils.getAnyIndex(
176 SyncopeConstants.MASTER_DOMAIN, AnyTypeKind.USER)).thenReturn("master_user");
177
178
179 Set<String> adminRealms = Set.of(RealmUtils.getGroupOwnerRealm("/any", "groupKey"));
180
181 AnyCond anyCond = new AnyCond(AttrCond.Type.ISNOTNULL);
182 anyCond.setSchema("key");
183
184 SearchRequest request = new SearchRequest.Builder().
185 index(ElasticsearchUtils.getAnyIndex(AuthContextUtils.getDomain(), AnyTypeKind.USER)).
186 searchType(SearchType.QueryThenFetch).
187 query(searchDAO.getQuery(realmDAO.findByFullPath("/any"), true,
188 adminRealms, SearchCond.getLeaf(anyCond), AnyTypeKind.USER)).
189 from(1).
190 size(10).
191 build();
192
193 assertThat(
194 new Query.Builder().bool(QueryBuilders.bool().
195 must(new Query.Builder().exists(QueryBuilders.exists().field("id").build()).build()).
196 must(new Query.Builder().term(QueryBuilders.term().field("memberships").value("groupKey").
197 build()).build()).build()).build()).
198 usingRecursiveComparison().
199 isEqualTo(request.query());
200 }
201 }
202
203 @Test
204 public void issueSYNCOPE1725() throws IOException {
205
206 AnyUtils anyUtils = mock(AnyUtils.class);
207 when(anyUtils.getField("key")).thenReturn(ReflectionUtils.findField(JPAUser.class, "id"));
208 JPAUPlainAttrValue value = new JPAUPlainAttrValue();
209 when(anyUtils.newPlainAttrValue()).thenReturn(value);
210
211 when(anyUtilsFactory.getInstance(AnyTypeKind.USER)).thenReturn(anyUtils);
212
213 when(entityFactory.newEntity(PlainSchema.class)).thenReturn(new JPAPlainSchema());
214
215 doAnswer(ic -> {
216 value.setStringValue(ic.getArgument(1));
217 return null;
218 }).when(validator).validate(any(PlainSchema.class), anyString(), any(PlainAttrValue.class));
219
220 AnyCond cond1 = new AnyCond(AttrCond.Type.EQ);
221 cond1.setSchema("key");
222 cond1.setExpression("1");
223
224 AnyCond cond2 = new AnyCond(AttrCond.Type.EQ);
225 cond2.setSchema("key");
226 cond2.setExpression("2");
227
228 AnyCond cond3 = new AnyCond(AttrCond.Type.EQ);
229 cond3.setSchema("key");
230 cond3.setExpression("3");
231
232 AnyCond cond4 = new AnyCond(AttrCond.Type.EQ);
233 cond4.setSchema("key");
234 cond4.setExpression("4");
235
236 AnyCond cond5 = new AnyCond(AttrCond.Type.EQ);
237 cond5.setSchema("key");
238 cond5.setExpression("5");
239
240 AnyCond cond6 = new AnyCond(AttrCond.Type.EQ);
241 cond6.setSchema("key");
242 cond6.setExpression("6");
243
244 try (MockedStatic<ElasticsearchUtils> utils = Mockito.mockStatic(ElasticsearchUtils.class)) {
245 utils.when(() -> ElasticsearchUtils.getAnyIndex(
246 SyncopeConstants.MASTER_DOMAIN, AnyTypeKind.USER)).thenReturn("master_user");
247
248 Query query = searchDAO.getQuery(
249 SearchCond.getAnd(
250 List.of(SearchCond.getLeaf(cond1),
251 SearchCond.getLeaf(cond2),
252 SearchCond.getLeaf(cond3),
253 SearchCond.getLeaf(cond4),
254 SearchCond.getLeaf(cond5),
255 SearchCond.getLeaf(cond6))),
256 AnyTypeKind.USER);
257 assertEquals(Query.Kind.Bool, query._kind());
258 assertEquals(6, ((BoolQuery) query._get()).must().size());
259 assertThat(
260 new Query.Builder().bool(QueryBuilders.bool().
261 must(new Query.Builder().term(
262 QueryBuilders.term().field("id").value("1").build()).build()).
263 must(new Query.Builder().term(
264 QueryBuilders.term().field("id").value("2").build()).build()).
265 must(new Query.Builder().term(
266 QueryBuilders.term().field("id").value("3").build()).build()).
267 must(new Query.Builder().term(
268 QueryBuilders.term().field("id").value("4").build()).build()).
269 must(new Query.Builder().term(
270 QueryBuilders.term().field("id").value("5").build()).build()).
271 must(new Query.Builder().term(
272 QueryBuilders.term().field("id").value("6").build()).build()).
273 build()).build()).
274 usingRecursiveComparison().isEqualTo(query);
275
276 query = searchDAO.getQuery(
277 SearchCond.getOr(
278 List.of(SearchCond.getLeaf(cond1),
279 SearchCond.getLeaf(cond2),
280 SearchCond.getLeaf(cond3),
281 SearchCond.getLeaf(cond4),
282 SearchCond.getLeaf(cond5),
283 SearchCond.getLeaf(cond6))),
284 AnyTypeKind.USER);
285 assertEquals(Query.Kind.DisMax, query._kind());
286 assertEquals(6, ((DisMaxQuery) query._get()).queries().size());
287 assertThat(
288 new Query.Builder().disMax(QueryBuilders.disMax().
289 queries(new Query.Builder().term(
290 QueryBuilders.term().field("id").value("1").build()).build()).
291 queries(new Query.Builder().term(
292 QueryBuilders.term().field("id").value("2").build()).build()).
293 queries(new Query.Builder().term(
294 QueryBuilders.term().field("id").value("3").build()).build()).
295 queries(new Query.Builder().term(
296 QueryBuilders.term().field("id").value("4").build()).build()).
297 queries(new Query.Builder().term(
298 QueryBuilders.term().field("id").value("5").build()).build()).
299 queries(new Query.Builder().term(
300 QueryBuilders.term().field("id").value("6").build()).build()).
301 build()).build()).
302 usingRecursiveComparison().isEqualTo(query);
303
304 query = searchDAO.getQuery(
305 SearchCond.getAnd(List.of(
306 SearchCond.getOr(List.of(
307 SearchCond.getLeaf(cond1),
308 SearchCond.getLeaf(cond2),
309 SearchCond.getLeaf(cond3))),
310 SearchCond.getOr(List.of(
311 SearchCond.getLeaf(cond4),
312 SearchCond.getLeaf(cond5),
313 SearchCond.getLeaf(cond6))))),
314 AnyTypeKind.USER);
315 assertEquals(Query.Kind.Bool, query._kind());
316 assertEquals(2, ((BoolQuery) query._get()).must().size());
317 Query left = ((BoolQuery) query._get()).must().get(0);
318 assertEquals(Query.Kind.DisMax, left._kind());
319 assertEquals(3, ((DisMaxQuery) left._get()).queries().size());
320 Query right = ((BoolQuery) query._get()).must().get(1);
321 assertEquals(Query.Kind.DisMax, right._kind());
322 assertEquals(3, ((DisMaxQuery) right._get()).queries().size());
323 assertThat(
324 new Query.Builder().bool(QueryBuilders.bool().
325 must(new Query.Builder().disMax(QueryBuilders.disMax().
326 queries(new Query.Builder().term(
327 QueryBuilders.term().field("id").value("1").build()).build()).
328 queries(new Query.Builder().term(
329 QueryBuilders.term().field("id").value("2").build()).build()).
330 queries(new Query.Builder().term(
331 QueryBuilders.term().field("id").value("3").build()).build()).build()).
332 build()).
333 must(new Query.Builder().disMax(QueryBuilders.disMax().
334 queries(new Query.Builder().term(
335 QueryBuilders.term().field("id").value("4").build()).build()).
336 queries(new Query.Builder().term(
337 QueryBuilders.term().field("id").value("5").build()).build()).
338 queries(new Query.Builder().term(
339 QueryBuilders.term().field("id").value("6").build()).build()).build()).
340 build()).
341 build()).build()).
342 usingRecursiveComparison().isEqualTo(query);
343
344 query = searchDAO.getQuery(
345 SearchCond.getOr(List.of(
346 SearchCond.getAnd(List.of(
347 SearchCond.getLeaf(cond1),
348 SearchCond.getLeaf(cond2),
349 SearchCond.getLeaf(cond3))),
350 SearchCond.getAnd(List.of(
351 SearchCond.getLeaf(cond4),
352 SearchCond.getLeaf(cond5),
353 SearchCond.getLeaf(cond6))))),
354 AnyTypeKind.USER);
355 assertEquals(Query.Kind.DisMax, query._kind());
356 assertEquals(2, ((DisMaxQuery) query._get()).queries().size());
357 left = ((DisMaxQuery) query._get()).queries().get(0);
358 assertEquals(Query.Kind.Bool, left._kind());
359 assertEquals(3, ((BoolQuery) left._get()).must().size());
360 right = ((DisMaxQuery) query._get()).queries().get(1);
361 assertEquals(Query.Kind.Bool, right._kind());
362 assertEquals(3, ((BoolQuery) right._get()).must().size());
363 assertThat(
364 new Query.Builder().disMax(QueryBuilders.disMax().
365 queries(new Query.Builder().bool(QueryBuilders.bool().
366 must(new Query.Builder().term(
367 QueryBuilders.term().field("id").value("1").build()).build()).
368 must(new Query.Builder().term(
369 QueryBuilders.term().field("id").value("2").build()).build()).
370 must(new Query.Builder().term(
371 QueryBuilders.term().field("id").value("3").build()).build()).build()).
372 build()).
373 queries(new Query.Builder().bool(QueryBuilders.bool().
374 must(new Query.Builder().term(
375 QueryBuilders.term().field("id").value("4").build()).build()).
376 must(new Query.Builder().term(
377 QueryBuilders.term().field("id").value("5").build()).build()).
378 must(new Query.Builder().term(
379 QueryBuilders.term().field("id").value("6").build()).build()).build()).
380 build()).
381 build()).build()).
382 usingRecursiveComparison().isEqualTo(query);
383 }
384 }
385 }