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.wa.starter;
20  
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.util.Collection;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import org.apache.syncope.common.lib.auth.OIDCAuthModuleConf;
30  import org.apache.syncope.common.lib.policy.AccessPolicyTO;
31  import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO;
32  import org.apache.syncope.common.lib.policy.AuthPolicyTO;
33  import org.apache.syncope.common.lib.policy.DefaultAccessPolicyConf;
34  import org.apache.syncope.common.lib.policy.DefaultAttrReleasePolicyConf;
35  import org.apache.syncope.common.lib.policy.DefaultAuthPolicyConf;
36  import org.apache.syncope.common.lib.policy.DefaultTicketExpirationPolicyConf;
37  import org.apache.syncope.common.lib.policy.TicketExpirationPolicyTO;
38  import org.apache.syncope.common.lib.to.AuthModuleTO;
39  import org.apache.syncope.common.lib.to.OIDCRPClientAppTO;
40  import org.apache.syncope.common.lib.to.SAML2SPClientAppTO;
41  import org.apache.syncope.common.lib.types.LogoutType;
42  import org.apache.syncope.common.lib.types.OIDCGrantType;
43  import org.apache.syncope.common.lib.types.OIDCResponseType;
44  import org.apache.syncope.common.lib.types.OIDCSubjectType;
45  import org.apache.syncope.common.lib.types.SAML2SPNameId;
46  import org.apache.syncope.common.lib.wa.WAClientApp;
47  import org.apache.syncope.common.rest.api.service.AuthModuleService;
48  import org.apache.syncope.common.rest.api.service.wa.WAClientAppService;
49  import org.apache.syncope.wa.bootstrap.WARestClient;
50  import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
51  import org.apereo.cas.services.AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria;
52  import org.apereo.cas.services.ChainingAttributeReleasePolicy;
53  import org.apereo.cas.services.DenyAllAttributeReleasePolicy;
54  import org.apereo.cas.services.OidcRegisteredService;
55  import org.apereo.cas.services.RegisteredService;
56  import org.apereo.cas.services.RegisteredServiceAccessStrategy;
57  import org.apereo.cas.services.RegisteredServiceDelegatedAuthenticationPolicy;
58  import org.apereo.cas.services.RegisteredServiceLogoutType;
59  import org.apereo.cas.services.ServicesManager;
60  import org.apereo.cas.support.saml.services.SamlRegisteredService;
61  import org.apereo.cas.util.RandomUtils;
62  import org.junit.jupiter.api.Test;
63  import org.springframework.beans.factory.ObjectProvider;
64  import org.springframework.beans.factory.annotation.Autowired;
65  import org.springframework.cloud.context.refresh.ContextRefresher;
66  
67  public class WAServiceRegistryTest extends AbstractTest {
68  
69      private static OIDCRPClientAppTO buildOIDCRP() {
70          OIDCRPClientAppTO oidcrpTO = new OIDCRPClientAppTO();
71          oidcrpTO.setName("ExampleRP_" + getUUIDString());
72          oidcrpTO.setClientAppId(RandomUtils.nextLong());
73          oidcrpTO.setDescription("Example OIDC RP application");
74          oidcrpTO.setClientId("clientId_" + getUUIDString());
75          oidcrpTO.setClientSecret("secret");
76          oidcrpTO.getRedirectUris().addAll(List.of("uri1", "uri2"));
77          oidcrpTO.setSubjectType(OIDCSubjectType.PUBLIC);
78          oidcrpTO.getSupportedGrantTypes().add(OIDCGrantType.password);
79          oidcrpTO.getSupportedResponseTypes().add(OIDCResponseType.CODE);
80          oidcrpTO.setLogoutType(LogoutType.BACK_CHANNEL);
81  
82          return oidcrpTO;
83      }
84  
85      private static SAML2SPClientAppTO buildSAML2SP() {
86          SAML2SPClientAppTO saml2spto = new SAML2SPClientAppTO();
87          saml2spto.setName("ExampleSAML2SP_" + getUUIDString());
88          saml2spto.setClientAppId(RandomUtils.nextLong());
89          saml2spto.setDescription("Example SAML 2.0 service provider");
90          saml2spto.setEntityId("SAML2SPEntityId_" + getUUIDString());
91          saml2spto.setMetadataLocation("file:./test.xml");
92          saml2spto.setRequiredNameIdFormat(SAML2SPNameId.EMAIL_ADDRESS);
93          saml2spto.setEncryptionOptional(true);
94          saml2spto.setEncryptAssertions(true);
95          saml2spto.setLogoutType(LogoutType.BACK_CHANNEL);
96          return saml2spto;
97      }
98  
99      private static void addPolicies(
100             final WAClientApp waClientApp,
101             final boolean withAttrReleasePolicy) {
102 
103         DefaultAuthPolicyConf authPolicyConf = new DefaultAuthPolicyConf();
104         authPolicyConf.setTryAll(true);
105         authPolicyConf.getAuthModules().add("TestAuthModule");
106         AuthPolicyTO authPolicy = new AuthPolicyTO();
107         authPolicy.setConf(authPolicyConf);
108 
109         waClientApp.setAuthPolicy(authPolicy);
110 
111         AuthModuleTO authModule = new AuthModuleTO();
112         authModule.setKey("TestAuthModule");
113         waClientApp.getAuthModules().add(authModule);
114 
115         AccessPolicyTO accessPolicy = new AccessPolicyTO();
116         DefaultAccessPolicyConf accessPolicyConf = new DefaultAccessPolicyConf();
117         accessPolicyConf.setEnabled(true);
118         accessPolicyConf.getRequiredAttrs().put("cn", "admin,Admin,TheAdmin");
119         accessPolicy.setConf(accessPolicyConf);
120         waClientApp.setAccessPolicy(accessPolicy);
121 
122         if (withAttrReleasePolicy) {
123             DefaultAttrReleasePolicyConf attrReleasePolicyConf = new DefaultAttrReleasePolicyConf();
124             attrReleasePolicyConf.getAllowedAttrs().add("cn");
125             attrReleasePolicyConf.getPrincipalAttrRepoConf().getAttrRepos().add("TestAttrRepo");
126             attrReleasePolicyConf.getReleaseAttrs().putAll(Map.of("uid", "username", "cn", "fullname"));
127 
128             AttrReleasePolicyTO attrReleasePolicy = new AttrReleasePolicyTO();
129             attrReleasePolicy.setConf(attrReleasePolicyConf);
130             waClientApp.setAttrReleasePolicy(attrReleasePolicy);
131         }
132 
133         TicketExpirationPolicyTO ticketExpirationPolicy = new TicketExpirationPolicyTO();
134         DefaultTicketExpirationPolicyConf ticketExpirationPolicyConf = new DefaultTicketExpirationPolicyConf();
135         DefaultTicketExpirationPolicyConf.TGTConf tgtConf = new DefaultTicketExpirationPolicyConf.TGTConf();
136         tgtConf.setMaxTimeToLiveInSeconds(110);
137         ticketExpirationPolicyConf.setTgtConf(tgtConf);
138         ticketExpirationPolicy.setConf(ticketExpirationPolicyConf);
139         waClientApp.setTicketExpirationPolicy(ticketExpirationPolicy);
140     }
141 
142     @Autowired
143     private WARestClient waRestClient;
144 
145     @Autowired
146     private ServicesManager servicesManager;
147 
148     @Autowired
149     private ObjectProvider<AuthenticationEventExecutionPlan> authenticationEventExecutionPlan;
150 
151     @Autowired
152     private ContextRefresher contextRefresher;
153 
154     @Test
155     public void addClientApp() {
156         // 1. start with no client apps defined on mocked Core
157         SyncopeCoreTestingServer.CLIENT_APPS.clear();
158 
159         WAClientAppService service = waRestClient.getService(WAClientAppService.class);
160         assertTrue(service.list().isEmpty());
161 
162         // 2. add one client app on mocked Core, nothing on WA yet
163         WAClientApp waClientApp = new WAClientApp();
164         waClientApp.setClientAppTO(buildOIDCRP());
165         Long clientAppId = waClientApp.getClientAppTO().getClientAppId();
166         addPolicies(waClientApp, false);
167 
168         SyncopeCoreTestingServer.CLIENT_APPS.add(waClientApp);
169         List<WAClientApp> apps = service.list();
170         assertEquals(1, apps.size());
171 
172         assertNotNull(servicesManager.findServiceBy(clientAppId));
173 
174         // 3. trigger client app refresh
175         Collection<RegisteredService> load = servicesManager.load();
176         assertEquals(3, load.size());
177 
178         // 4. look for the service created above
179         RegisteredService found = servicesManager.findServiceBy(clientAppId);
180         assertNotNull(found);
181         assertTrue(found instanceof OidcRegisteredService);
182         OidcRegisteredService oidc = OidcRegisteredService.class.cast(found);
183         OIDCRPClientAppTO oidcrpto = OIDCRPClientAppTO.class.cast(waClientApp.getClientAppTO());
184         assertEquals("uri1|uri2", oidc.getServiceId());
185         assertEquals(oidcrpto.getClientId(), oidc.getClientId());
186         assertEquals(oidcrpto.getClientSecret(), oidc.getClientSecret());
187         assertTrue(oidc.getAuthenticationPolicy().getRequiredAuthenticationHandlers().contains("TestAuthModule"));
188         assertTrue(((AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria) oidc.
189                 getAuthenticationPolicy().getCriteria()).isTryAll());
190         assertTrue(oidc.getAttributeReleasePolicy() instanceof ChainingAttributeReleasePolicy);
191         assertEquals(RegisteredServiceLogoutType.valueOf(oidcrpto.getLogoutType().name()), oidc.getLogoutType());
192 
193         // 5. more client with different attributes 
194         waClientApp = new WAClientApp();
195         waClientApp.setClientAppTO(buildSAML2SP());
196         clientAppId = waClientApp.getClientAppTO().getClientAppId();
197         addPolicies(waClientApp, true);
198 
199         SyncopeCoreTestingServer.CLIENT_APPS.add(waClientApp);
200         apps = service.list();
201         assertEquals(2, apps.size());
202 
203         load = servicesManager.load();
204         assertEquals(4, load.size());
205 
206         found = servicesManager.findServiceBy(clientAppId);
207         assertTrue(found instanceof SamlRegisteredService);
208         SamlRegisteredService saml = SamlRegisteredService.class.cast(found);
209         SAML2SPClientAppTO samlspto = SAML2SPClientAppTO.class.cast(waClientApp.getClientAppTO());
210         assertEquals(samlspto.getMetadataLocation(), saml.getMetadataLocation());
211         assertEquals(samlspto.getEntityId(), saml.getServiceId());
212         assertTrue(saml.getAuthenticationPolicy().getRequiredAuthenticationHandlers().contains("TestAuthModule"));
213         assertNotNull(found.getAccessStrategy());
214         assertTrue(saml.getAttributeReleasePolicy() instanceof ChainingAttributeReleasePolicy);
215         assertEquals(RegisteredServiceLogoutType.valueOf(samlspto.getLogoutType().name()), saml.getLogoutType());
216 
217         waClientApp = new WAClientApp();
218         waClientApp.setClientAppTO(buildSAML2SP());
219         clientAppId = waClientApp.getClientAppTO().getClientAppId();
220         addPolicies(waClientApp, false);
221 
222         SyncopeCoreTestingServer.CLIENT_APPS.add(waClientApp);
223         apps = service.list();
224         assertEquals(3, apps.size());
225 
226         load = servicesManager.load();
227         assertEquals(5, load.size());
228 
229         found = servicesManager.findServiceBy(clientAppId);
230         assertTrue(found.getAttributeReleasePolicy() instanceof DenyAllAttributeReleasePolicy);
231     }
232 
233     @Test
234     public void delegatedAuthentication() {
235         // 1. start with 1 client app and 1 auth module defined on mocked Core
236         OIDCAuthModuleConf oidcAuthModuleConf = new OIDCAuthModuleConf();
237         oidcAuthModuleConf.setClientId("clientId");
238         oidcAuthModuleConf.setClientSecret("clientSecret");
239         AuthModuleTO authModuleTO = new AuthModuleTO();
240         authModuleTO.setKey("keycloack");
241         authModuleTO.setConf(oidcAuthModuleConf);
242 
243         SyncopeCoreTestingServer.AUTH_MODULES.clear();
244         SyncopeCoreTestingServer.AUTH_MODULES.add(authModuleTO);
245         AuthModuleService authModuleService = waRestClient.getService(AuthModuleService.class);
246         assertEquals(1, authModuleService.list().size());
247 
248         SyncopeCoreTestingServer.CLIENT_APPS.clear();
249         WAClientAppService waClientAppService = waRestClient.getService(WAClientAppService.class);
250         assertTrue(waClientAppService.list().isEmpty());
251 
252         WAClientApp waClientApp = new WAClientApp();
253         waClientApp.setClientAppTO(buildOIDCRP());
254         waClientApp.getAuthModules().add(0, authModuleTO);
255         Long clientAppId = waClientApp.getClientAppTO().getClientAppId();
256         addPolicies(waClientApp, false);
257         DefaultAuthPolicyConf authPolicyConf = (DefaultAuthPolicyConf) waClientApp.getAuthPolicy().getConf();
258         authPolicyConf.getAuthModules().clear();
259         authPolicyConf.getAuthModules().add(authModuleTO.getKey());
260         SyncopeCoreTestingServer.CLIENT_APPS.add(waClientApp);
261 
262         // 2. trigger refresh
263         int before = authenticationEventExecutionPlan.getObject().getAuthenticationHandlers().size();
264 
265         contextRefresher.refresh();
266 
267         int after = authenticationEventExecutionPlan.getObject().getAuthenticationHandlers().size();
268         assertEquals(before + 1, after);
269 
270         // 3. check service
271         RegisteredService service = servicesManager.findServiceBy(clientAppId);
272         assertNotNull(service);
273 
274         assertEquals(
275                 Set.of("TestAuthModule", "DelegatedClientAuthenticationHandler"),
276                 service.getAuthenticationPolicy().getRequiredAuthenticationHandlers());
277 
278         RegisteredServiceAccessStrategy accessStrategy = service.getAccessStrategy();
279         assertNotNull(accessStrategy);
280         RegisteredServiceDelegatedAuthenticationPolicy delegatedAuthPolicy =
281                 accessStrategy.getDelegatedAuthenticationPolicy();
282         assertNotNull(delegatedAuthPolicy);
283         assertEquals(1, delegatedAuthPolicy.getAllowedProviders().size());
284         assertTrue(delegatedAuthPolicy.getAllowedProviders().contains(authModuleTO.getKey()));
285 
286         assertNotNull(service.getTicketGrantingTicketExpirationPolicy());
287     }
288 }