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.starter;
20  
21  import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
22  import io.swagger.v3.oas.integration.api.OpenAPIConfiguration;
23  import io.swagger.v3.oas.models.security.SecurityScheme;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.regex.Pattern;
28  import org.apache.commons.lang3.StringUtils;
29  import org.apache.cxf.Bus;
30  import org.apache.cxf.endpoint.Server;
31  import org.apache.cxf.jaxrs.ext.MessageContext;
32  import org.apache.cxf.jaxrs.model.doc.JavaDocProvider;
33  import org.apache.cxf.jaxrs.openapi.OpenApiCustomizer;
34  import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
35  import org.apache.cxf.jaxrs.spring.JAXRSServerFactoryBeanDefinitionParser.SpringJAXRSServerFactoryBean;
36  import org.apache.cxf.jaxrs.utils.JAXRSUtils;
37  import org.apache.cxf.jaxrs.validation.JAXRSBeanValidationInInterceptor;
38  import org.apache.cxf.transport.common.gzip.GZIPInInterceptor;
39  import org.apache.cxf.transport.common.gzip.GZIPOutInterceptor;
40  import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
41  import org.apache.syncope.common.keymaster.client.api.DomainOps;
42  import org.apache.syncope.common.keymaster.client.api.DomainWatcher;
43  import org.apache.syncope.common.keymaster.client.api.KeymasterProperties;
44  import org.apache.syncope.common.keymaster.client.api.ServiceOps;
45  import org.apache.syncope.common.keymaster.rest.api.service.ConfParamService;
46  import org.apache.syncope.common.keymaster.rest.api.service.DomainService;
47  import org.apache.syncope.common.keymaster.rest.api.service.NetworkServiceService;
48  import org.apache.syncope.core.keymaster.internal.InternalConfParamHelper;
49  import org.apache.syncope.core.keymaster.internal.SelfKeymasterInternalConfParamOps;
50  import org.apache.syncope.core.keymaster.internal.SelfKeymasterInternalDomainOps;
51  import org.apache.syncope.core.keymaster.internal.SelfKeymasterInternalServiceOps;
52  import org.apache.syncope.core.keymaster.rest.cxf.service.ConfParamServiceImpl;
53  import org.apache.syncope.core.keymaster.rest.cxf.service.DomainServiceImpl;
54  import org.apache.syncope.core.keymaster.rest.cxf.service.NetworkServiceServiceImpl;
55  import org.apache.syncope.core.keymaster.rest.security.SelfKeymasterUsernamePasswordAuthenticationProvider;
56  import org.apache.syncope.core.logic.ConfParamLogic;
57  import org.apache.syncope.core.logic.DomainLogic;
58  import org.apache.syncope.core.logic.NetworkServiceLogic;
59  import org.apache.syncope.core.persistence.api.dao.ConfParamDAO;
60  import org.apache.syncope.core.persistence.api.dao.DomainDAO;
61  import org.apache.syncope.core.persistence.api.dao.NetworkServiceDAO;
62  import org.apache.syncope.core.persistence.api.entity.SelfKeymasterEntityFactory;
63  import org.apache.syncope.core.persistence.jpa.dao.JPAConfParamDAO;
64  import org.apache.syncope.core.persistence.jpa.dao.JPADomainDAO;
65  import org.apache.syncope.core.persistence.jpa.dao.JPANetworkServiceDAO;
66  import org.apache.syncope.core.persistence.jpa.entity.JPASelfKeymasterEntityFactory;
67  import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
68  import org.apache.syncope.core.rest.cxf.JavaDocUtils;
69  import org.apache.syncope.core.rest.cxf.RestServiceExceptionMapper;
70  import org.apache.syncope.core.spring.security.AuthDataAccessor;
71  import org.apache.syncope.core.spring.security.DefaultCredentialChecker;
72  import org.apache.syncope.core.spring.security.SecurityProperties;
73  import org.apache.syncope.core.spring.security.UsernamePasswordAuthenticationProvider;
74  import org.apache.syncope.core.spring.security.WebSecurityContext;
75  import org.apache.syncope.core.starter.SelfKeymasterContext.SelfKeymasterCondition;
76  import org.slf4j.Logger;
77  import org.slf4j.LoggerFactory;
78  import org.springframework.boot.autoconfigure.AutoConfigureBefore;
79  import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
80  import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
81  import org.springframework.boot.context.properties.EnableConfigurationProperties;
82  import org.springframework.context.annotation.Bean;
83  import org.springframework.context.annotation.ConditionContext;
84  import org.springframework.context.annotation.Conditional;
85  import org.springframework.context.annotation.Configuration;
86  import org.springframework.core.env.Environment;
87  import org.springframework.core.type.AnnotatedTypeMetadata;
88  
89  @EnableConfigurationProperties(KeymasterProperties.class)
90  @Configuration(proxyBeanMethods = false)
91  @AutoConfigureBefore(WebSecurityContext.class)
92  @Conditional(SelfKeymasterCondition.class)
93  public class SelfKeymasterContext {
94  
95      private static final Logger LOG = LoggerFactory.getLogger(SelfKeymasterContext.class);
96  
97      private static final Pattern HTTP = Pattern.compile("^http.+");
98  
99      static class SelfKeymasterCondition extends SpringBootCondition {
100 
101         @Override
102         public ConditionOutcome getMatchOutcome(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
103             String keymasterAddress = context.getEnvironment().getProperty("keymaster.address");
104             return new ConditionOutcome(
105                     keymasterAddress != null && HTTP.matcher(keymasterAddress).matches(),
106                     "Keymaster address not set for Self: " + keymasterAddress);
107         }
108     }
109 
110     @Bean
111     public Server selfKeymasterContainer(
112             final ConfParamService confParamService,
113             final NetworkServiceService networkServiceService,
114             final DomainService domainService,
115             final JacksonJsonProvider jsonProvider,
116             final GZIPInInterceptor gzipInInterceptor,
117             final GZIPOutInterceptor gzipOutInterceptor,
118             final JAXRSBeanValidationInInterceptor validationInInterceptor,
119             final RestServiceExceptionMapper restServiceExceptionMapper,
120             final Bus bus,
121             final Environment env) {
122 
123         SpringJAXRSServerFactoryBean selfKeymasterContainer = new SpringJAXRSServerFactoryBean();
124         selfKeymasterContainer.setBus(bus);
125         selfKeymasterContainer.setAddress("/keymaster");
126         selfKeymasterContainer.setStaticSubresourceResolution(true);
127 
128         selfKeymasterContainer.setProperties(Map.of("convert.wadl.resources.to.dom", "false"));
129 
130         selfKeymasterContainer.setServiceBeans(List.of(confParamService, networkServiceService, domainService));
131 
132         selfKeymasterContainer.setInInterceptors(List.of(gzipInInterceptor, validationInInterceptor));
133 
134         selfKeymasterContainer.setOutInterceptors(List.of(gzipOutInterceptor));
135 
136         selfKeymasterContainer.setProviders(List.of(restServiceExceptionMapper, jsonProvider));
137 
138         // OpenAPI
139         JavaDocProvider javaDocProvider = JavaDocUtils.getJavaDocURLs().
140                 map(JavaDocProvider::new).
141                 orElseGet(() -> JavaDocUtils.getJavaDocPaths(env).
142                 map(javaDocPaths -> {
143                     try {
144                         return new JavaDocProvider(javaDocPaths);
145                     } catch (Exception e) {
146                         LOG.error("Could not set javadoc paths from {}", List.of(javaDocPaths), e);
147                         return null;
148                     }
149                 }).
150                 orElse(null));
151         OpenApiCustomizer openApiCustomizer = new OpenApiCustomizer() {
152 
153             @Override
154             public OpenAPIConfiguration customize(final OpenAPIConfiguration configuration) {
155                 super.customize(configuration);
156 
157                 MessageContext ctx = JAXRSUtils.createContextValue(
158                         JAXRSUtils.getCurrentMessage(), null, MessageContext.class);
159 
160                 String url = StringUtils.substringBeforeLast(ctx.getUriInfo().getRequestUri().getRawPath(), "/");
161                 configuration.getOpenAPI().setServers(List.of(new io.swagger.v3.oas.models.servers.Server().url(url)));
162 
163                 return configuration;
164             }
165         };
166         openApiCustomizer.setDynamicBasePath(false);
167         openApiCustomizer.setReplaceTags(false);
168         openApiCustomizer.setJavadocProvider(javaDocProvider);
169 
170         String version = env.getProperty("version");
171         OpenApiFeature openapiFeature = new OpenApiFeature();
172         openapiFeature.setUseContextBasedConfig(true);
173         openapiFeature.setTitle("Apache Syncope Self Keymaster");
174         openapiFeature.setVersion(version);
175         openapiFeature.setDescription("Apache Syncope Self Keymaster" + version);
176         openapiFeature.setContactName("The Apache Syncope community");
177         openapiFeature.setContactEmail("dev@syncope.apache.org");
178         openapiFeature.setContactUrl("https://syncope.apache.org");
179         openapiFeature.setScan(false);
180         openapiFeature.setResourcePackages(Set.of("org.apache.syncope.common.keymaster.rest.api.service"));
181         openapiFeature.setSecurityDefinitions(
182                 Map.of("BasicAuthentication", new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")));
183         openapiFeature.setCustomizer(openApiCustomizer);
184         selfKeymasterContainer.setFeatures(List.of(openapiFeature));
185 
186         return selfKeymasterContainer.create();
187     }
188 
189     @Bean
190     public UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider(
191             final DomainOps domainOps,
192             final AuthDataAccessor dataAccessor,
193             final UserProvisioningManager provisioningManager,
194             final DefaultCredentialChecker credentialChecker,
195             final SecurityProperties securityProperties,
196             final KeymasterProperties keymasterProperties) {
197 
198         return new SelfKeymasterUsernamePasswordAuthenticationProvider(
199                 domainOps,
200                 dataAccessor,
201                 provisioningManager,
202                 credentialChecker,
203                 securityProperties,
204                 keymasterProperties);
205     }
206 
207     @Bean
208     public InternalConfParamHelper internalConfParamHelper(
209             final ConfParamDAO confParamDAO,
210             final SelfKeymasterEntityFactory entityFactory) {
211 
212         return new InternalConfParamHelper(confParamDAO, entityFactory);
213     }
214 
215     @Bean
216     public ConfParamOps internalConfParamOps(final InternalConfParamHelper helper) {
217         return new SelfKeymasterInternalConfParamOps(helper);
218     }
219 
220     @Bean
221     public ServiceOps internalServiceOps(
222             final NetworkServiceLogic networkServiceLogic,
223             final KeymasterProperties props) {
224 
225         return new SelfKeymasterInternalServiceOps(networkServiceLogic, props);
226     }
227 
228     @Bean
229     public DomainOps domainOps(final DomainLogic domainLogic, final KeymasterProperties props) {
230         return new SelfKeymasterInternalDomainOps(domainLogic, props);
231     }
232 
233     @Bean
234     public ConfParamLogic confParamLogic(final InternalConfParamHelper helper) {
235         return new ConfParamLogic(helper);
236     }
237 
238     @Bean
239     public DomainLogic domainLogic(
240             final DomainDAO domainDAO,
241             final SelfKeymasterEntityFactory selfKeymasterEntityFactory,
242             final DomainWatcher domainWatcher) {
243 
244         return new DomainLogic(domainDAO, selfKeymasterEntityFactory, domainWatcher);
245     }
246 
247     @Bean
248     public NetworkServiceLogic networkServiceLogic(
249             final NetworkServiceDAO serviceDAO,
250             final SelfKeymasterEntityFactory selfKeymasterEntityFactory) {
251 
252         return new NetworkServiceLogic(serviceDAO, selfKeymasterEntityFactory);
253     }
254 
255     @Bean
256     public SelfKeymasterEntityFactory selfKeymasterEntityFactory() {
257         return new JPASelfKeymasterEntityFactory();
258     }
259 
260     @Bean
261     public ConfParamDAO confParamDAO() {
262         return new JPAConfParamDAO();
263     }
264 
265     @Bean
266     public DomainDAO domainDAO() {
267         return new JPADomainDAO();
268     }
269 
270     @Bean
271     public NetworkServiceDAO networkServiceDAO() {
272         return new JPANetworkServiceDAO();
273     }
274 
275     @Bean
276     public ConfParamService confParamService(final ConfParamLogic confParamLogic) {
277         return new ConfParamServiceImpl(confParamLogic);
278     }
279 
280     @Bean
281     public DomainService domainService(final DomainLogic domainLogic) {
282         return new DomainServiceImpl(domainLogic);
283     }
284 
285     @Bean
286     public NetworkServiceService networkServiceService(final NetworkServiceLogic networkServiceLogic) {
287         return new NetworkServiceServiceImpl(networkServiceLogic);
288     }
289 }