View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.client.enduser;
20  
21  import static org.mockito.ArgumentMatchers.any;
22  import static org.mockito.ArgumentMatchers.anyBoolean;
23  import static org.mockito.ArgumentMatchers.anyString;
24  import static org.mockito.ArgumentMatchers.eq;
25  import static org.mockito.ArgumentMatchers.isNull;
26  import static org.mockito.Mockito.mock;
27  import static org.mockito.Mockito.when;
28  
29  import com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;
30  import com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;
31  import com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;
32  import com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.general.GeneralSettingsProperties;
33  import com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.boot.actuator.WicketEndpointRepositoryDefault;
34  import java.io.IOException;
35  import java.time.OffsetDateTime;
36  import java.util.ArrayList;
37  import java.util.HashMap;
38  import java.util.HashSet;
39  import java.util.List;
40  import java.util.Map;
41  import java.util.Optional;
42  import org.apache.cxf.jaxrs.client.Client;
43  import org.apache.syncope.client.enduser.init.ClassPathScanImplementationLookup;
44  import org.apache.syncope.client.lib.AuthenticationHandler;
45  import org.apache.syncope.client.lib.SyncopeAnonymousClient;
46  import org.apache.syncope.client.lib.SyncopeClient;
47  import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
48  import org.apache.syncope.client.ui.commons.DynamicMenuStringResourceLoader;
49  import org.apache.syncope.client.ui.commons.rest.AnonymousRestClient;
50  import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
51  import org.apache.syncope.common.keymaster.client.api.DomainOps;
52  import org.apache.syncope.common.keymaster.client.api.ServiceOps;
53  import org.apache.syncope.common.keymaster.client.api.model.JPADomain;
54  import org.apache.syncope.common.lib.SyncopeConstants;
55  import org.apache.syncope.common.lib.collections.CircularFifoQueue;
56  import org.apache.syncope.common.lib.info.NumbersInfo;
57  import org.apache.syncope.common.lib.info.PlatformInfo;
58  import org.apache.syncope.common.lib.info.SystemInfo;
59  import org.apache.syncope.common.lib.to.AnyTypeTO;
60  import org.apache.syncope.common.lib.to.PlainSchemaTO;
61  import org.apache.syncope.common.lib.to.UserTO;
62  import org.apache.syncope.common.lib.types.AnyTypeKind;
63  import org.apache.syncope.common.lib.types.AttrSchemaType;
64  import org.apache.syncope.common.rest.api.beans.SchemaQuery;
65  import org.apache.syncope.common.rest.api.service.AnyTypeService;
66  import org.apache.syncope.common.rest.api.service.SchemaService;
67  import org.apache.syncope.common.rest.api.service.SyncopeService;
68  import org.apache.wicket.request.resource.IResource;
69  import org.apache.wicket.util.tester.WicketTester;
70  import org.junit.jupiter.api.BeforeAll;
71  import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
72  import org.springframework.context.annotation.AnnotationConfigApplicationContext;
73  import org.springframework.context.annotation.Bean;
74  import org.springframework.context.annotation.Configuration;
75  import org.springframework.core.io.ResourceLoader;
76  
77  public abstract class AbstractTest {
78  
79      @ImportAutoConfiguration
80      @Configuration(proxyBeanMethods = false)
81      public static class SyncopeEnduserWebApplicationTestConfig {
82  
83          @Bean
84          public EnduserProperties enduserProperties() {
85              EnduserProperties enduserProperties = new EnduserProperties();
86  
87              enduserProperties.getSecurityHeaders().put("X-XSS-Protection", "1; mode=block");
88              enduserProperties.getSecurityHeaders().
89                      put("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
90              enduserProperties.getSecurityHeaders().put("X-Content-Type-Options", "nosniff");
91              enduserProperties.getSecurityHeaders().put("X-Frame-Options", "sameorigin");
92  
93              enduserProperties.setAdminUser("admin");
94  
95              enduserProperties.setAnonymousUser("anonymousUser");
96  
97              return enduserProperties;
98          }
99  
100         @Bean
101         public ServiceOps selfServiceOps() {
102             return mock(ServiceOps.class);
103         }
104 
105         @Bean
106         public DomainOps domainOps() {
107             DomainOps domainOps = mock(DomainOps.class);
108             when(domainOps.list()).thenReturn(List.of(new JPADomain.Builder(SyncopeConstants.MASTER_DOMAIN).build()));
109             return domainOps;
110         }
111 
112         @Bean
113         public ConfParamOps confParamOps() {
114             ConfParamOps confParamOps = mock(ConfParamOps.class);
115             when(confParamOps.get(anyString(), anyString(), anyBoolean(), eq(boolean.class))).thenReturn(false);
116             return confParamOps;
117         }
118 
119         @Bean
120         public AnonymousRestClient anonymousRestClient() {
121             return mock(AnonymousRestClient.class);
122         }
123 
124         @Bean
125         public GeneralSettingsProperties generalSettingsProperties() {
126             return new GeneralSettingsProperties();
127         }
128 
129         @Bean
130         public List<WicketApplicationInitConfiguration> configurations() {
131             return List.of();
132         }
133 
134         @Bean
135         public WicketClassCandidatesHolder wicketClassCandidatesHolder() {
136             return new WicketClassCandidatesHolder();
137         }
138 
139         @Bean
140         public WicketEndpointRepository wicketEndpointRepository() {
141             return new WicketEndpointRepositoryDefault();
142         }
143 
144         @Bean
145         public ClassPathScanImplementationLookup classPathScanImplementationLookup() {
146             ClassPathScanImplementationLookup lookup = new ClassPathScanImplementationLookup();
147             lookup.load();
148             return lookup;
149         }
150 
151         @Bean
152         public DynamicMenuStringResourceLoader dynamicMenuStringResourceLoader() {
153             return new DynamicMenuStringResourceLoader();
154         }
155     }
156 
157     public static class TestSyncopeWebApplication extends SyncopeWebApplication {
158 
159         public TestSyncopeWebApplication(
160                 final ResourceLoader resourceLoader,
161                 final EnduserProperties props,
162                 final ClassPathScanImplementationLookup lookup,
163                 final ServiceOps serviceOps,
164                 final List<IResource> resources,
165                 final DynamicMenuStringResourceLoader dynamicMenuStringResourceLoader) {
166 
167             super(resourceLoader, props, lookup, serviceOps, resources, dynamicMenuStringResourceLoader);
168         }
169 
170         public interface SyncopeServiceClient extends SyncopeService, Client {
171         }
172 
173         public interface AnyTypeServiceClient extends AnyTypeService, Client {
174         }
175 
176         public interface SchemaServiceClient extends SchemaService, Client {
177         }
178 
179         private SyncopeService getSyncopeService() {
180             SyncopeServiceClient service = mock(SyncopeServiceClient.class);
181             when(service.type(anyString())).thenReturn(service);
182             when(service.accept(anyString())).thenReturn(service);
183 
184             return service;
185         }
186 
187         private SchemaService getSchemaService() {
188             SchemaServiceClient service = mock(SchemaServiceClient.class);
189 
190             when(service.type(anyString())).thenReturn(service);
191             when(service.accept(anyString())).thenReturn(service);
192 
193             PlainSchemaTO firstname = new PlainSchemaTO();
194             firstname.setKey("firstname");
195             firstname.setType(AttrSchemaType.String);
196             firstname.setAnyTypeClass("minimal user");
197             firstname.setMandatoryCondition("false");
198             when(service.search(any(SchemaQuery.class))).thenReturn(List.of(firstname));
199             return service;
200         }
201 
202         private AnyTypeService getAnyTypeService() {
203             AnyTypeServiceClient service = mock(AnyTypeServiceClient.class);
204 
205             when(service.type(anyString())).thenReturn(service);
206             when(service.accept(anyString())).thenReturn(service);
207 
208             AnyTypeTO anyTypeTO = new AnyTypeTO();
209             anyTypeTO.setKey("123456");
210             anyTypeTO.setKind(AnyTypeKind.USER);
211 
212             when(service.read(anyString())).thenReturn(anyTypeTO);
213             return service;
214         }
215 
216         private UserTO getUserTO() {
217             UserTO userTO = new UserTO();
218             userTO.setUsername("username");
219             return userTO;
220         }
221 
222         @Override
223         public SyncopeClientFactoryBean newClientFactory() {
224             SyncopeClient client = mock(SyncopeClient.class);
225             SyncopeAnonymousClient anonymousClient = mock(SyncopeAnonymousClient.class);
226 
227             when(client.jwtInfo()).thenReturn(Optional.of(new SyncopeClient.JwtInfo("<anyJWT>", OffsetDateTime.now())));
228 
229             when(client.self()).thenReturn(new SyncopeClient.Self(getUserTO(), Map.of(), List.of()));
230 
231             when(anonymousClient.platform()).thenReturn(new PlatformInfo(
232                     new HashSet<>(),
233                     new ArrayList<>(),
234                     new ArrayList<>(),
235                     new ArrayList<>(),
236                     new ArrayList<>(),
237                     new HashSet<>(),
238                     new HashSet<>(),
239                     new HashSet<>()));
240             when(anonymousClient.numbers()).thenAnswer(ic -> {
241                 NumbersInfo numbersInfo = new NumbersInfo(
242                         0,
243                         Map.of(),
244                         Map.of(),
245                         0,
246                         Map.of(),
247                         null,
248                         0,
249                         Map.of(),
250                         null,
251                         0,
252                         Map.of(),
253                         0,
254                         0,
255                         new HashMap<>());
256 
257                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.RESOURCE.name(), false);
258                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.ACCOUNT_POLICY.name(), false);
259                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.PASSWORD_POLICY.name(), false);
260                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.NOTIFICATION.name(), false);
261                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.PULL_TASK.name(), false);
262                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.ANY_TYPE.name(), false);
263                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.SECURITY_QUESTION.name(), false);
264                 numbersInfo.confCompleteness().put(NumbersInfo.ConfItem.ROLE.name(), false);
265 
266                 return numbersInfo;
267             });
268             when(anonymousClient.system()).thenReturn(new SystemInfo(
269                     null,
270                     null,
271                     null,
272                     0,
273                     0,
274                     new CircularFifoQueue<>()));
275 
276             SyncopeService syncopeService = getSyncopeService();
277             when(client.getService(SyncopeService.class)).thenReturn(syncopeService);
278 
279             SchemaService schemaService = getSchemaService();
280             when(client.getService(SchemaService.class)).thenReturn(schemaService);
281 
282             AnyTypeService anyTypeService = getAnyTypeService();
283             when(client.getService(AnyTypeService.class)).thenReturn(anyTypeService);
284 
285             SyncopeClientFactoryBean clientFactory = mock(SyncopeClientFactoryBean.class);
286             when(clientFactory.setDomain(any())).thenReturn(clientFactory);
287             when(clientFactory.create(any(AuthenticationHandler.class))).thenReturn(client);
288             when(clientFactory.create(anyString(), anyString())).thenReturn(client);
289             when(clientFactory.createAnonymous(anyString(), isNull())).thenReturn(anonymousClient);
290 
291             return clientFactory;
292         }
293     }
294 
295     protected static EnduserProperties PROPS;
296 
297     protected static WicketTester TESTER;
298 
299     @BeforeAll
300     public static void setupTester() throws IOException {
301         AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
302         ctx.register(SyncopeEnduserWebApplicationTestConfig.class);
303         ctx.register(TestSyncopeWebApplication.class);
304         ctx.refresh();
305 
306         PROPS = ctx.getBean(EnduserProperties.class);
307         TESTER = new WicketTester(ctx.getBean(SyncopeWebApplication.class));
308     }
309 }