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.core.rest.cxf;
20  
21  import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
22  import com.fasterxml.jackson.jaxrs.xml.JacksonXMLProvider;
23  import com.fasterxml.jackson.jaxrs.yaml.JacksonYAMLProvider;
24  import io.swagger.v3.oas.models.security.SecurityScheme;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.concurrent.ThreadPoolExecutor;
30  import java.util.stream.Collectors;
31  import javax.validation.Validator;
32  import org.apache.cxf.Bus;
33  import org.apache.cxf.endpoint.Server;
34  import org.apache.cxf.jaxrs.ext.ContextProvider;
35  import org.apache.cxf.jaxrs.ext.search.SearchContext;
36  import org.apache.cxf.jaxrs.ext.search.SearchContextImpl;
37  import org.apache.cxf.jaxrs.ext.search.SearchContextProvider;
38  import org.apache.cxf.jaxrs.ext.search.SearchUtils;
39  import org.apache.cxf.jaxrs.model.doc.JavaDocProvider;
40  import org.apache.cxf.jaxrs.openapi.OpenApiCustomizer;
41  import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
42  import org.apache.cxf.jaxrs.spring.JAXRSServerFactoryBeanDefinitionParser.SpringJAXRSServerFactoryBean;
43  import org.apache.cxf.jaxrs.validation.JAXRSBeanValidationInInterceptor;
44  import org.apache.cxf.transport.common.gzip.GZIPInInterceptor;
45  import org.apache.cxf.transport.common.gzip.GZIPOutInterceptor;
46  import org.apache.cxf.validation.BeanValidationProvider;
47  import org.apache.syncope.common.lib.jackson.SyncopeJsonMapper;
48  import org.apache.syncope.common.lib.jackson.SyncopeXmlMapper;
49  import org.apache.syncope.common.lib.jackson.SyncopeYAMLMapper;
50  import org.apache.syncope.common.lib.search.SyncopeFiqlParser;
51  import org.apache.syncope.common.rest.api.DateParamConverterProvider;
52  import org.apache.syncope.common.rest.api.service.AccessTokenService;
53  import org.apache.syncope.common.rest.api.service.AnyObjectService;
54  import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
55  import org.apache.syncope.common.rest.api.service.AnyTypeService;
56  import org.apache.syncope.common.rest.api.service.ApplicationService;
57  import org.apache.syncope.common.rest.api.service.AuditService;
58  import org.apache.syncope.common.rest.api.service.CommandService;
59  import org.apache.syncope.common.rest.api.service.DelegationService;
60  import org.apache.syncope.common.rest.api.service.DynRealmService;
61  import org.apache.syncope.common.rest.api.service.FIQLQueryService;
62  import org.apache.syncope.common.rest.api.service.GroupService;
63  import org.apache.syncope.common.rest.api.service.ImplementationService;
64  import org.apache.syncope.common.rest.api.service.JAXRSService;
65  import org.apache.syncope.common.rest.api.service.MailTemplateService;
66  import org.apache.syncope.common.rest.api.service.NotificationService;
67  import org.apache.syncope.common.rest.api.service.PolicyService;
68  import org.apache.syncope.common.rest.api.service.RealmService;
69  import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
70  import org.apache.syncope.common.rest.api.service.ReportService;
71  import org.apache.syncope.common.rest.api.service.RoleService;
72  import org.apache.syncope.common.rest.api.service.SchemaService;
73  import org.apache.syncope.common.rest.api.service.SecurityQuestionService;
74  import org.apache.syncope.common.rest.api.service.SyncopeService;
75  import org.apache.syncope.common.rest.api.service.TaskService;
76  import org.apache.syncope.common.rest.api.service.UserSelfService;
77  import org.apache.syncope.common.rest.api.service.UserService;
78  import org.apache.syncope.core.logic.AccessTokenLogic;
79  import org.apache.syncope.core.logic.AnyObjectLogic;
80  import org.apache.syncope.core.logic.AnyTypeClassLogic;
81  import org.apache.syncope.core.logic.AnyTypeLogic;
82  import org.apache.syncope.core.logic.ApplicationLogic;
83  import org.apache.syncope.core.logic.AuditLogic;
84  import org.apache.syncope.core.logic.CommandLogic;
85  import org.apache.syncope.core.logic.DelegationLogic;
86  import org.apache.syncope.core.logic.DynRealmLogic;
87  import org.apache.syncope.core.logic.FIQLQueryLogic;
88  import org.apache.syncope.core.logic.GroupLogic;
89  import org.apache.syncope.core.logic.ImplementationLogic;
90  import org.apache.syncope.core.logic.MailTemplateLogic;
91  import org.apache.syncope.core.logic.NotificationLogic;
92  import org.apache.syncope.core.logic.PolicyLogic;
93  import org.apache.syncope.core.logic.RealmLogic;
94  import org.apache.syncope.core.logic.RelationshipTypeLogic;
95  import org.apache.syncope.core.logic.ReportLogic;
96  import org.apache.syncope.core.logic.RoleLogic;
97  import org.apache.syncope.core.logic.SchemaLogic;
98  import org.apache.syncope.core.logic.SecurityQuestionLogic;
99  import org.apache.syncope.core.logic.SyncopeLogic;
100 import org.apache.syncope.core.logic.TaskLogic;
101 import org.apache.syncope.core.logic.UserLogic;
102 import org.apache.syncope.core.persistence.api.DomainHolder;
103 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
104 import org.apache.syncope.core.persistence.api.dao.BatchDAO;
105 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
106 import org.apache.syncope.core.persistence.api.dao.UserDAO;
107 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
108 import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
109 import org.apache.syncope.core.rest.cxf.service.AccessTokenServiceImpl;
110 import org.apache.syncope.core.rest.cxf.service.AnyObjectServiceImpl;
111 import org.apache.syncope.core.rest.cxf.service.AnyTypeClassServiceImpl;
112 import org.apache.syncope.core.rest.cxf.service.AnyTypeServiceImpl;
113 import org.apache.syncope.core.rest.cxf.service.ApplicationServiceImpl;
114 import org.apache.syncope.core.rest.cxf.service.AuditServiceImpl;
115 import org.apache.syncope.core.rest.cxf.service.CommandServiceImpl;
116 import org.apache.syncope.core.rest.cxf.service.DelegationServiceImpl;
117 import org.apache.syncope.core.rest.cxf.service.DynRealmServiceImpl;
118 import org.apache.syncope.core.rest.cxf.service.FIQLQueryServiceImpl;
119 import org.apache.syncope.core.rest.cxf.service.GroupServiceImpl;
120 import org.apache.syncope.core.rest.cxf.service.ImplementationServiceImpl;
121 import org.apache.syncope.core.rest.cxf.service.MailTemplateServiceImpl;
122 import org.apache.syncope.core.rest.cxf.service.NotificationServiceImpl;
123 import org.apache.syncope.core.rest.cxf.service.PolicyServiceImpl;
124 import org.apache.syncope.core.rest.cxf.service.RealmServiceImpl;
125 import org.apache.syncope.core.rest.cxf.service.RelationshipTypeServiceImpl;
126 import org.apache.syncope.core.rest.cxf.service.ReportServiceImpl;
127 import org.apache.syncope.core.rest.cxf.service.RoleServiceImpl;
128 import org.apache.syncope.core.rest.cxf.service.SchemaServiceImpl;
129 import org.apache.syncope.core.rest.cxf.service.SecurityQuestionServiceImpl;
130 import org.apache.syncope.core.rest.cxf.service.SyncopeServiceImpl;
131 import org.apache.syncope.core.rest.cxf.service.TaskServiceImpl;
132 import org.apache.syncope.core.rest.cxf.service.UserSelfServiceImpl;
133 import org.apache.syncope.core.rest.cxf.service.UserServiceImpl;
134 import org.slf4j.Logger;
135 import org.slf4j.LoggerFactory;
136 import org.springframework.beans.factory.annotation.Qualifier;
137 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
138 import org.springframework.boot.context.properties.EnableConfigurationProperties;
139 import org.springframework.context.annotation.Bean;
140 import org.springframework.context.annotation.Configuration;
141 import org.springframework.context.annotation.PropertySource;
142 import org.springframework.core.env.Environment;
143 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
144 
145 @PropertySource("classpath:errorMessages.properties")
146 @EnableConfigurationProperties(RESTProperties.class)
147 @Configuration(proxyBeanMethods = false)
148 public class IdRepoRESTCXFContext {
149 
150     private static final Logger LOG = LoggerFactory.getLogger(IdRepoRESTCXFContext.class);
151 
152     @Bean
153     public ThreadPoolTaskExecutor batchExecutor(final RESTProperties props) {
154         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
155         executor.setCorePoolSize(props.getBatchExecutor().getCorePoolSize());
156         executor.setMaxPoolSize(props.getBatchExecutor().getMaxPoolSize());
157         executor.setQueueCapacity(props.getBatchExecutor().getQueueCapacity());
158         executor.setAwaitTerminationSeconds(props.getBatchExecutor().getAwaitTerminationSeconds());
159         executor.setWaitForTasksToCompleteOnShutdown(true);
160         executor.setThreadNamePrefix("Batch-");
161         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
162         executor.initialize();
163         return executor;
164     }
165 
166     @ConditionalOnMissingBean
167     @Bean
168     public DateParamConverterProvider dateParamConverterProvider() {
169         return new DateParamConverterProvider();
170     }
171 
172     @ConditionalOnMissingBean
173     @Bean
174     public JacksonJsonProvider jsonProvider() {
175         return new JacksonJsonProvider(new SyncopeJsonMapper());
176     }
177 
178     @ConditionalOnMissingBean
179     @Bean
180     public JacksonXMLProvider xmlProvider() {
181         return new JacksonXMLProvider(new SyncopeXmlMapper());
182     }
183 
184     @ConditionalOnMissingBean
185     @Bean
186     public JacksonYAMLProvider yamlProvider() {
187         return new JacksonYAMLProvider(new SyncopeYAMLMapper());
188     }
189 
190     @ConditionalOnMissingBean
191     @Bean
192     public MDCInInterceptor mdcInInterceptor() {
193         return new MDCInInterceptor();
194     }
195 
196     @ConditionalOnMissingBean
197     @Bean
198     public JAXRSBeanValidationInInterceptor validationInInterceptor(final Validator validator) {
199         JAXRSBeanValidationInInterceptor validationInInterceptor = new JAXRSBeanValidationInInterceptor();
200         validationInInterceptor.setProvider(new BeanValidationProvider(validator));
201         return validationInInterceptor;
202     }
203 
204     @ConditionalOnMissingBean
205     @Bean
206     public GZIPInInterceptor gzipInInterceptor() {
207         return new GZIPInInterceptor();
208     }
209 
210     @ConditionalOnMissingBean
211     @Bean
212     public GZIPOutInterceptor gzipOutInterceptor() {
213         GZIPOutInterceptor gzipOutInterceptor = new GZIPOutInterceptor();
214         gzipOutInterceptor.setThreshold(0);
215         gzipOutInterceptor.setForce(true);
216         return gzipOutInterceptor;
217     }
218 
219     @ConditionalOnMissingBean
220     @Bean
221     public ThreadLocalCleanupOutInterceptor threadLocalCleanupOutInterceptor() {
222         return new ThreadLocalCleanupOutInterceptor();
223     }
224 
225     @ConditionalOnMissingBean
226     @Bean
227     public RestServiceExceptionMapper restServiceExceptionMapper(final Environment env) {
228         return new RestServiceExceptionMapper(env);
229     }
230 
231     @ConditionalOnMissingBean
232     @Bean
233     public ContextProvider<SearchContext> searchContextProvider() {
234         return new SearchContextProvider();
235     }
236 
237     @ConditionalOnMissingBean
238     @Bean
239     public AddDomainFilter addDomainFilter() {
240         return new AddDomainFilter();
241     }
242 
243     @ConditionalOnMissingBean
244     @Bean
245     public AddETagFilter addETagFilter() {
246         return new AddETagFilter();
247     }
248 
249     @ConditionalOnMissingBean(name = { "openApiCustomizer", "syncopeOpenApiCustomizer" })
250     @Bean
251     public OpenApiCustomizer openApiCustomizer(final DomainHolder domainHolder, final Environment env) {
252         JavaDocProvider javaDocProvider = JavaDocUtils.getJavaDocURLs().
253                 map(JavaDocProvider::new).
254                 orElseGet(() -> JavaDocUtils.getJavaDocPaths(env).
255                 map(javaDocPaths -> {
256                     try {
257                         return new JavaDocProvider(javaDocPaths);
258                     } catch (Exception e) {
259                         LOG.error("Could not set javadoc paths from {}", List.of(javaDocPaths), e);
260                         return null;
261                     }
262                 }).
263                 orElse(null));
264 
265         SyncopeOpenApiCustomizer openApiCustomizer = new SyncopeOpenApiCustomizer(domainHolder);
266         openApiCustomizer.setDynamicBasePath(false);
267         openApiCustomizer.setReplaceTags(false);
268         openApiCustomizer.setJavadocProvider(javaDocProvider);
269         return openApiCustomizer;
270     }
271 
272     @ConditionalOnMissingBean
273     @Bean
274     public OpenApiFeature openapiFeature(final OpenApiCustomizer openApiCustomizer, final Environment env) {
275         String version = env.getProperty("version");
276         OpenApiFeature openapiFeature = new OpenApiFeature();
277         openapiFeature.setUseContextBasedConfig(true);
278         openapiFeature.setTitle("Apache Syncope");
279         openapiFeature.setVersion(version);
280         openapiFeature.setDescription("Apache Syncope " + version);
281         openapiFeature.setContactName("The Apache Syncope community");
282         openapiFeature.setContactEmail("dev@syncope.apache.org");
283         openapiFeature.setContactUrl("https://syncope.apache.org");
284         openapiFeature.setScan(false);
285         openapiFeature.setResourcePackages(Set.of("org.apache.syncope.common.rest.api.service"));
286         openapiFeature.setCustomizer(openApiCustomizer);
287         openapiFeature.setSecurityDefinitions(Map.of(
288                 "BasicAuthentication", new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic"),
289                 "Bearer", new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
290 
291         return openapiFeature;
292     }
293 
294     @ConditionalOnMissingBean
295     @Bean
296     public Server restContainer(
297             final List<JAXRSService> services,
298             final AddETagFilter addETagFilter,
299             final AddDomainFilter addDomainFilter,
300             final ContextProvider<SearchContext> searchContextProvider,
301             final JacksonYAMLProvider yamlProvider,
302             final JacksonXMLProvider xmlProvider,
303             final JacksonJsonProvider jsonProvider,
304             final DateParamConverterProvider dateParamConverterProvider,
305             final MDCInInterceptor mdcInInterceptor,
306             final JAXRSBeanValidationInInterceptor validationInInterceptor,
307             final GZIPInInterceptor gzipInInterceptor,
308             final GZIPOutInterceptor gzipOutInterceptor,
309             final ThreadLocalCleanupOutInterceptor threadLocalCleanupOutInterceptor,
310             final OpenApiFeature openapiFeature,
311             final RestServiceExceptionMapper restServiceExceptionMapper,
312             final Bus bus) {
313 
314         SpringJAXRSServerFactoryBean restContainer = new SpringJAXRSServerFactoryBean();
315         restContainer.setBus(bus);
316         restContainer.setAddress("/");
317         restContainer.setStaticSubresourceResolution(true);
318 
319         Map<String, Object> properties = new HashMap<>();
320         properties.put(SearchContextImpl.CUSTOM_SEARCH_PARSER_CLASS_PROPERTY, SyncopeFiqlParser.class.getName());
321         properties.put(SearchUtils.LAX_PROPERTY_MATCH, "true");
322         properties.put("convert.wadl.resources.to.dom", "false");
323         restContainer.setProperties(properties);
324 
325         restContainer.setServiceBeans(services.stream().map(Object.class::cast).collect(Collectors.toList()));
326 
327         restContainer.setProviders(List.of(
328                 dateParamConverterProvider,
329                 jsonProvider,
330                 xmlProvider,
331                 yamlProvider,
332                 restServiceExceptionMapper,
333                 searchContextProvider,
334                 addDomainFilter,
335                 addETagFilter));
336 
337         restContainer.setInInterceptors(List.of(mdcInInterceptor, validationInInterceptor, gzipInInterceptor));
338 
339         restContainer.setOutInterceptors(List.of(gzipOutInterceptor, threadLocalCleanupOutInterceptor));
340 
341         restContainer.setFeatures(List.of(openapiFeature));
342 
343         return restContainer.create();
344     }
345 
346     @ConditionalOnMissingBean
347     @Bean
348     public AccessTokenService accessTokenService(final AccessTokenLogic accessTokenLogic) {
349         return new AccessTokenServiceImpl(accessTokenLogic);
350     }
351 
352     @ConditionalOnMissingBean
353     @Bean
354     public AnyObjectService anyObjectService(final AnyObjectDAO anyObjectDAO, final AnyObjectLogic anyObjectLogic,
355             final SearchCondVisitor searchCondVisitor) {
356         return new AnyObjectServiceImpl(searchCondVisitor, anyObjectDAO, anyObjectLogic);
357     }
358 
359     @ConditionalOnMissingBean
360     @Bean
361     public AnyTypeClassService anyTypeClassService(final AnyTypeClassLogic anyTypeClassLogic) {
362         return new AnyTypeClassServiceImpl(anyTypeClassLogic);
363     }
364 
365     @ConditionalOnMissingBean
366     @Bean
367     public AnyTypeService anyTypeService(final AnyTypeLogic anyTypeLogic) {
368         return new AnyTypeServiceImpl(anyTypeLogic);
369     }
370 
371     @ConditionalOnMissingBean
372     @Bean
373     public ApplicationService applicationService(final ApplicationLogic applicationLogic) {
374         return new ApplicationServiceImpl(applicationLogic);
375     }
376 
377     @ConditionalOnMissingBean
378     @Bean
379     public AuditService auditService(final AuditLogic auditLogic) {
380         return new AuditServiceImpl(auditLogic);
381     }
382 
383     @ConditionalOnMissingBean
384     @Bean
385     public CommandService commandService(final CommandLogic commandLogic) {
386         return new CommandServiceImpl(commandLogic);
387     }
388 
389     @ConditionalOnMissingBean
390     @Bean
391     public FIQLQueryService fiqlQueryService(final FIQLQueryLogic fiqlQueryLogic) {
392         return new FIQLQueryServiceImpl(fiqlQueryLogic);
393     }
394 
395     @ConditionalOnMissingBean
396     @Bean
397     public DelegationService delegationService(final DelegationLogic delegationLogic) {
398         return new DelegationServiceImpl(delegationLogic);
399     }
400 
401     @ConditionalOnMissingBean
402     @Bean
403     public DynRealmService dynRealmService(final DynRealmLogic dynRealmLogic) {
404         return new DynRealmServiceImpl(dynRealmLogic);
405     }
406 
407     @ConditionalOnMissingBean
408     @Bean
409     public GroupService groupService(final GroupDAO groupDAO, final GroupLogic groupLogic,
410             final SearchCondVisitor searchCondVisitor) {
411         return new GroupServiceImpl(searchCondVisitor, groupDAO, groupLogic);
412     }
413 
414     @ConditionalOnMissingBean
415     @Bean
416     public ImplementationService implementationService(final ImplementationLogic implementationLogic) {
417         return new ImplementationServiceImpl(implementationLogic);
418     }
419 
420     @ConditionalOnMissingBean
421     @Bean
422     public MailTemplateService mailTemplateService(final MailTemplateLogic mailTemplateLogic) {
423         return new MailTemplateServiceImpl(mailTemplateLogic);
424     }
425 
426     @ConditionalOnMissingBean
427     @Bean
428     public NotificationService notificationService(final NotificationLogic notificationLogic) {
429         return new NotificationServiceImpl(notificationLogic);
430     }
431 
432     @ConditionalOnMissingBean
433     @Bean
434     public PolicyService policyService(final PolicyLogic policyLogic) {
435         return new PolicyServiceImpl(policyLogic);
436     }
437 
438     @ConditionalOnMissingBean
439     @Bean
440     public RealmService realmService(final RealmLogic realmLogic) {
441         return new RealmServiceImpl(realmLogic);
442     }
443 
444     @ConditionalOnMissingBean
445     @Bean
446     public RelationshipTypeService relationshipTypeService(final RelationshipTypeLogic relationshipTypeLogic) {
447         return new RelationshipTypeServiceImpl(relationshipTypeLogic);
448     }
449 
450     @ConditionalOnMissingBean
451     @Bean
452     public ReportService reportService(final ReportLogic reportLogic) {
453         return new ReportServiceImpl(reportLogic);
454     }
455 
456     @ConditionalOnMissingBean
457     @Bean
458     public RoleService roleService(final RoleLogic roleLogic) {
459         return new RoleServiceImpl(roleLogic);
460     }
461 
462     @ConditionalOnMissingBean
463     @Bean
464     public SchemaService schemaService(final SchemaLogic schemaLogic) {
465         return new SchemaServiceImpl(schemaLogic);
466     }
467 
468     @ConditionalOnMissingBean
469     @Bean
470     public SecurityQuestionService securityQuestionService(final SecurityQuestionLogic securityQuestionLogic) {
471         return new SecurityQuestionServiceImpl(securityQuestionLogic);
472     }
473 
474     @ConditionalOnMissingBean
475     @Bean
476     public SyncopeService syncopeService(
477             final Bus bus,
478             final SyncopeLogic syncopeLogic,
479             @Qualifier("batchExecutor")
480             final ThreadPoolTaskExecutor batchExecutor,
481             final BatchDAO batchDAO,
482             final EntityFactory entityFactory) {
483 
484         return new SyncopeServiceImpl(syncopeLogic, batchExecutor, bus, batchDAO, entityFactory);
485     }
486 
487     @ConditionalOnMissingBean
488     @Bean
489     public TaskService taskService(final TaskLogic taskLogic) {
490         return new TaskServiceImpl(taskLogic);
491     }
492 
493     @ConditionalOnMissingBean
494     @Bean
495     public UserSelfService userSelfService(final UserLogic userLogic, final SyncopeLogic syncopeLogic) {
496         return new UserSelfServiceImpl(userLogic, syncopeLogic);
497     }
498 
499     @ConditionalOnMissingBean
500     @Bean
501     public UserService userService(
502             final UserDAO userDAO,
503             final UserLogic userLogic,
504             final SearchCondVisitor searchCondVisitor) {
505 
506         return new UserServiceImpl(searchCondVisitor, userDAO, userLogic);
507     }
508 }