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.fit.enduser;
20  
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  
23  import com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;
24  import com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;
25  import com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;
26  import com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.general.GeneralSettingsProperties;
27  import com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.boot.actuator.WicketEndpointRepositoryDefault;
28  import java.io.InputStream;
29  import java.time.OffsetDateTime;
30  import java.time.format.DateTimeFormatter;
31  import java.util.List;
32  import java.util.Locale;
33  import java.util.Properties;
34  import org.apache.syncope.client.enduser.EnduserProperties;
35  import org.apache.syncope.client.enduser.FlowableEnduserContext;
36  import org.apache.syncope.client.enduser.IdRepoEnduserContext;
37  import org.apache.syncope.client.enduser.OIDCC4UIEnduserContext;
38  import org.apache.syncope.client.enduser.SAML2SP4UIEnduserContext;
39  import org.apache.syncope.client.enduser.SyncopeWebApplication;
40  import org.apache.syncope.client.enduser.init.ClassPathScanImplementationLookup;
41  import org.apache.syncope.client.enduser.pages.Login;
42  import org.apache.syncope.client.lib.SyncopeClient;
43  import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
44  import org.apache.syncope.common.keymaster.client.self.SelfKeymasterClientContext;
45  import org.apache.syncope.common.keymaster.client.zookeeper.ZookeeperKeymasterClientContext;
46  import org.apache.syncope.common.lib.Attr;
47  import org.apache.syncope.common.lib.SyncopeConstants;
48  import org.apache.syncope.common.lib.request.UserCR;
49  import org.apache.syncope.common.rest.api.beans.AnyQuery;
50  import org.apache.syncope.common.rest.api.service.SecurityQuestionService;
51  import org.apache.syncope.common.rest.api.service.SyncopeService;
52  import org.apache.syncope.common.rest.api.service.UserService;
53  import org.apache.syncope.fit.AbstractUIITCase;
54  import org.apache.wicket.util.tester.FormTester;
55  import org.apache.wicket.util.tester.WicketTester;
56  import org.junit.jupiter.api.AfterAll;
57  import org.junit.jupiter.api.BeforeAll;
58  import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
59  import org.springframework.context.annotation.AnnotationConfigApplicationContext;
60  import org.springframework.context.annotation.Bean;
61  import org.springframework.context.annotation.Configuration;
62  import org.springframework.test.context.support.TestPropertySourceUtils;
63  
64  public abstract class AbstractEnduserITCase extends AbstractUIITCase {
65  
66      @ImportAutoConfiguration(classes = {
67          SelfKeymasterClientContext.class,
68          ZookeeperKeymasterClientContext.class,
69          IdRepoEnduserContext.class,
70          FlowableEnduserContext.class,
71          SAML2SP4UIEnduserContext.class,
72          OIDCC4UIEnduserContext.class })
73      @Configuration(proxyBeanMethods = false)
74      public static class SyncopeEnduserWebApplicationTestConfig {
75  
76          @Bean
77          public EnduserProperties enduserProperties() {
78              EnduserProperties enduserProperties = new EnduserProperties();
79  
80              enduserProperties.setAdminUser(ADMIN_UNAME);
81  
82              enduserProperties.setAnonymousUser(ANONYMOUS_UNAME);
83              enduserProperties.setAnonymousKey(ANONYMOUS_KEY);
84  
85              enduserProperties.setCsrf(false);
86  
87              return enduserProperties;
88          }
89  
90          @Bean
91          public GeneralSettingsProperties generalSettingsProperties() {
92              return new GeneralSettingsProperties();
93          }
94  
95          @Bean
96          public List<WicketApplicationInitConfiguration> configurations() {
97              return List.of();
98          }
99  
100         @Bean
101         public WicketClassCandidatesHolder wicketClassCandidatesHolder() {
102             return new WicketClassCandidatesHolder();
103         }
104 
105         @Bean
106         public WicketEndpointRepository wicketEndpointRepository() {
107             return new WicketEndpointRepositoryDefault();
108         }
109 
110         @Bean
111         public ClassPathScanImplementationLookup classPathScanImplementationLookup() {
112             ClassPathScanImplementationLookup lookup = new ClassPathScanImplementationLookup();
113             lookup.load();
114             return lookup;
115         }
116     }
117 
118     protected static SyncopeClientFactoryBean CLIENT_FACTORY;
119 
120     protected static SyncopeClient ADMIN_CLIENT;
121 
122     protected static UserService USER_SERVICE;
123 
124     protected static SecurityQuestionService SECURITY_QUESTION_SERVICE;
125 
126     @BeforeAll
127     public static void setUp() {
128         Locale.setDefault(Locale.ENGLISH);
129 
130         AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
131 
132         ctx.register(SyncopeEnduserWebApplicationTestConfig.class);
133         ctx.register(SyncopeWebApplication.class);
134 
135         String springActiveProfiles = null;
136         try (InputStream propStream = AbstractEnduserITCase.class.getResourceAsStream("/test.properties")) {
137             Properties props = new Properties();
138             props.load(propStream);
139 
140             springActiveProfiles = props.getProperty("springActiveProfiles");
141         } catch (Exception e) {
142             LOG.error("Could not load /test.properties", e);
143         }
144         assertNotNull(springActiveProfiles);
145 
146         if (springActiveProfiles.contains("zookeeper")) {
147             TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
148                     ctx, "keymaster.address=127.0.0.1:2181");
149         } else {
150             TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
151                     ctx, "keymaster.address=http://localhost:9080/syncope/rest/keymaster");
152         }
153         TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
154                 ctx, "keymaster.username=" + ANONYMOUS_UNAME);
155         TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
156                 ctx, "keymaster.password=" + ANONYMOUS_KEY);
157 
158         ctx.refresh();
159 
160         TESTER = new WicketTester(ctx.getBean(SyncopeWebApplication.class));
161 
162         SYNCOPE_SERVICE = new SyncopeClientFactoryBean().
163                 setAddress(ADDRESS).create(ADMIN_UNAME, ADMIN_PWD).
164                 getService(SyncopeService.class);
165     }
166 
167     @BeforeAll
168     public static void restSetup() {
169         CLIENT_FACTORY = new SyncopeClientFactoryBean().setAddress(ADDRESS);
170         LOG.info("Performing IT with content type {}", CLIENT_FACTORY.getContentType().getMediaType());
171 
172         ADMIN_CLIENT = CLIENT_FACTORY.create(ADMIN_UNAME, ADMIN_PWD);
173 
174         USER_SERVICE = ADMIN_CLIENT.getService(UserService.class);
175 
176         // create test user for must change password
177         USER_SERVICE.create(new UserCR.Builder(SyncopeConstants.ROOT_REALM, "mustchangepassword").
178                 password("password123").
179                 mustChangePassword(true).
180                 plainAttr(attr("fullname", "mustchangepassword@apache.org")).
181                 plainAttr(attr("firstname", "mustchangepassword@apache.org")).
182                 plainAttr(attr("surname", "surname")).
183                 plainAttr(attr("ctype", "a type")).
184                 plainAttr(attr("userId", "mustchangepassword@apache.org")).
185                 plainAttr(attr("email", "mustchangepassword@apache.org")).
186                 plainAttr(attr("loginDate", DateTimeFormatter.ISO_LOCAL_DATE.format(OffsetDateTime.now()))).
187                 build());
188 
189         // create test user for self password reset
190         USER_SERVICE.create(new UserCR.Builder(SyncopeConstants.ROOT_REALM, "selfpwdreset").
191                 password("password123").
192                 plainAttr(attr("fullname", "selfpwdreset@apache.org")).
193                 plainAttr(attr("firstname", "selfpwdreset@apache.org")).
194                 plainAttr(attr("surname", "surname")).
195                 plainAttr(attr("ctype", "a type")).
196                 plainAttr(attr("userId", "selfpwdreset@apache.org")).
197                 plainAttr(attr("email", "selfpwdreset@apache.org")).
198                 plainAttr(attr("loginDate", DateTimeFormatter.ISO_LOCAL_DATE.format(OffsetDateTime.now()))).
199                 build());
200 
201         // create test user for self update
202         USER_SERVICE.create(new UserCR.Builder(SyncopeConstants.ROOT_REALM, "selfupdate").
203                 password("password123").
204                 plainAttr(attr("fullname", "selfupdate@apache.org")).
205                 plainAttr(attr("firstname", "selfupdate@apache.org")).
206                 plainAttr(attr("surname", "surname")).
207                 plainAttr(attr("ctype", "a type")).
208                 plainAttr(attr("userId", "selfupdate@apache.org")).
209                 build());
210 
211         SECURITY_QUESTION_SERVICE = ADMIN_CLIENT.getService(SecurityQuestionService.class);
212     }
213 
214     @AfterAll
215     public static void cleanUp() {
216         USER_SERVICE.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
217                 fiql(SyncopeClient.getUserSearchConditionBuilder().
218                         is("username").equalTo("selfupdate").
219                         or("username").equalTo("selfpwdreset").
220                         or("username").equalTo("mustchangepassword").query()).
221                 build()).getResult().forEach(user -> USER_SERVICE.delete(user.getKey()));
222     }
223 
224     protected static void doLogin(final String user, final String passwd) {
225         TESTER.startPage(Login.class);
226         TESTER.assertRenderedPage(Login.class);
227 
228         FormTester formTester = TESTER.newFormTester("login");
229         formTester.setValue("username", user);
230         formTester.setValue("password", passwd);
231         formTester.submit("submit");
232     }
233 
234     protected static Attr attr(final String schema, final String value) {
235         return new Attr.Builder(schema).value(value).build();
236     }
237 }