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.core;
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.assertNull;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  import static org.junit.jupiter.api.Assertions.fail;
26  
27  import java.security.AccessControlException;
28  import java.time.OffsetDateTime;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Set;
32  import javax.ws.rs.ForbiddenException;
33  import javax.ws.rs.core.Response;
34  import org.apache.commons.lang3.tuple.Triple;
35  import org.apache.syncope.client.lib.SyncopeClient;
36  import org.apache.syncope.common.lib.SyncopeClientException;
37  import org.apache.syncope.common.lib.SyncopeConstants;
38  import org.apache.syncope.common.lib.audit.AuditEntry;
39  import org.apache.syncope.common.lib.request.UserCR;
40  import org.apache.syncope.common.lib.to.AuditConfTO;
41  import org.apache.syncope.common.lib.to.DelegationTO;
42  import org.apache.syncope.common.lib.to.UserTO;
43  import org.apache.syncope.common.lib.types.AuditElements;
44  import org.apache.syncope.common.lib.types.AuditLoggerName;
45  import org.apache.syncope.common.lib.types.ClientExceptionType;
46  import org.apache.syncope.common.rest.api.beans.AnyQuery;
47  import org.apache.syncope.common.rest.api.beans.AuditQuery;
48  import org.apache.syncope.common.rest.api.service.DelegationService;
49  import org.apache.syncope.common.rest.api.service.UserService;
50  import org.apache.syncope.core.logic.UserLogic;
51  import org.apache.syncope.fit.AbstractITCase;
52  import org.junit.jupiter.api.Test;
53  
54  public class DelegationITCase extends AbstractITCase {
55  
56      private DelegationTO create(final DelegationService ds, final DelegationTO delegation) {
57          Response response = ds.create(delegation);
58          if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
59              Exception ex = CLIENT_FACTORY.getExceptionMapper().fromResponse(response);
60              if (ex != null) {
61                  throw (RuntimeException) ex;
62              }
63          }
64          return getObject(response.getLocation(), DelegationService.class, DelegationTO.class);
65      }
66  
67      @Test
68      public void crudAsAdmin() {
69          // 1. create users        
70          UserCR delegatingCR = UserITCase.getUniqueSample("delegating@syncope.apache.org");
71          delegatingCR.getRoles().add("User reviewer");
72          UserTO delegating = createUser(delegatingCR).getEntity();
73          assertNotNull(delegating.getKey());
74  
75          UserCR delegatedCR = UserITCase.getUniqueSample("delegated@syncope.apache.org");
76          UserTO delegated = createUser(delegatedCR).getEntity();
77          assertNotNull(delegated.getKey());
78  
79          DelegationTO delegation = new DelegationTO();
80          delegation.setDelegating(delegating.getKey());
81          delegation.setDelegated(delegated.getKey());
82  
83          // no dates set -> FAIL
84          try {
85              DELEGATION_SERVICE.create(delegation);
86              fail();
87          } catch (SyncopeClientException e) {
88              assertEquals(ClientExceptionType.InvalidEntity, e.getType());
89          }
90  
91          delegation.setStart(OffsetDateTime.now());
92          delegation.setEnd(OffsetDateTime.now().minusSeconds(1));
93  
94          // end before start -> FAIL
95          try {
96              DELEGATION_SERVICE.create(delegation);
97              fail();
98          } catch (SyncopeClientException e) {
99              assertEquals(ClientExceptionType.InvalidEntity, e.getType());
100         }
101 
102         delegation.setEnd(OffsetDateTime.now());
103 
104         // 2. create delegation
105         delegation = create(DELEGATION_SERVICE, delegation);
106         assertNotNull(delegation.getKey());
107         assertNotNull(delegation.getEnd());
108 
109         // 3. verify delegation is reported for users
110         delegating = USER_SERVICE.read(delegating.getKey());
111         assertEquals(List.of(delegation.getKey()), delegating.getDelegatingDelegations());
112         assertEquals(List.of(), delegating.getDelegatedDelegations());
113 
114         delegated = USER_SERVICE.read(delegated.getKey());
115         assertEquals(List.of(), delegated.getDelegatingDelegations());
116         assertEquals(List.of(delegation.getKey()), delegated.getDelegatedDelegations());
117 
118         // 4. update and read delegation
119         delegation.setEnd(null);
120         DELEGATION_SERVICE.update(delegation);
121 
122         delegation = DELEGATION_SERVICE.read(delegation.getKey());
123         assertNull(delegation.getEnd());
124 
125         // 5. delete delegation
126         DELEGATION_SERVICE.delete(delegation.getKey());
127 
128         try {
129             DELEGATION_SERVICE.read(delegation.getKey());
130             fail();
131         } catch (SyncopeClientException e) {
132             assertEquals(ClientExceptionType.NotFound, e.getType());
133         }
134 
135         // 6. verify delegation is not reported for users
136         delegating = USER_SERVICE.read(delegating.getKey());
137         assertEquals(List.of(), delegating.getDelegatingDelegations());
138         assertEquals(List.of(), delegating.getDelegatedDelegations());
139 
140         delegated = USER_SERVICE.read(delegated.getKey());
141         assertEquals(List.of(), delegated.getDelegatingDelegations());
142         assertEquals(List.of(), delegated.getDelegatedDelegations());
143     }
144 
145     @Test
146     public void crudAsUser() {
147         // 1. create users        
148         UserCR delegatingCR = UserITCase.getUniqueSample("delegating@syncope.apache.org");
149         delegatingCR.getRoles().add("User reviewer");
150         UserTO delegating = createUser(delegatingCR).getEntity();
151         assertNotNull(delegating.getKey());
152 
153         UserCR delegatedCR = UserITCase.getUniqueSample("delegated@syncope.apache.org");
154         UserTO delegated = createUser(delegatedCR).getEntity();
155         assertNotNull(delegated.getKey());
156 
157         DelegationTO delegation = new DelegationTO();
158         delegation.setDelegating("c9b2dec2-00a7-4855-97c0-d854842b4b24");
159         delegation.setDelegated(delegated.getKey());
160         delegation.setStart(OffsetDateTime.now());
161 
162         DelegationService uds = CLIENT_FACTORY.create(delegating.getUsername(), "password123").
163                 getService(DelegationService.class);
164 
165         // delegating user is not requesting user -> FAIL
166         try {
167             create(uds, delegation);
168             fail();
169         } catch (SyncopeClientException e) {
170             assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
171         }
172 
173         // 2. create delegation
174         delegation.setDelegating(delegating.getKey());
175 
176         delegation = create(uds, delegation);
177         assertNotNull(delegation.getKey());
178         assertNull(delegation.getEnd());
179 
180         // 3. update and read delegation
181         delegation.setEnd(OffsetDateTime.now());
182         uds.update(delegation);
183 
184         delegation = uds.read(delegation.getKey());
185         assertNotNull(delegation.getEnd());
186 
187         // 4. delete delegation
188         uds.delete(delegation.getKey());
189 
190         try {
191             uds.read(delegation.getKey());
192             fail();
193         } catch (SyncopeClientException e) {
194             assertEquals(ClientExceptionType.NotFound, e.getType());
195         }
196     }
197 
198     @Test
199     public void operations() {
200         // 0. enable audit
201         AuditLoggerName authLoginSuccess = new AuditLoggerName(
202                 AuditElements.EventCategoryType.LOGIC,
203                 UserLogic.class.getSimpleName(),
204                 null,
205                 "search",
206                 AuditElements.Result.SUCCESS);
207         AuditConfTO authLogin = new AuditConfTO();
208         authLogin.setKey(authLoginSuccess.toAuditKey());
209         authLogin.setActive(true);
210         AUDIT_SERVICE.set(authLogin);
211 
212         // 1. bellini delegates rossini
213         DelegationTO delegation = new DelegationTO();
214         delegation.setDelegating("bellini");
215         delegation.setDelegated("rossini");
216         delegation.setStart(OffsetDateTime.now());
217         delegation = create(DELEGATION_SERVICE, delegation);
218         assertNotNull(delegation.getKey());
219 
220         // 2. search users as bellini
221         SyncopeClient bellini = CLIENT_FACTORY.create("bellini", "password");
222         int forBellini = bellini.getService(UserService.class).search(
223                 new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).build()).getTotalCount();
224 
225         SyncopeClient rossini = CLIENT_FACTORY.create("rossini", "password");
226 
227         // 3. search users as rossini
228         Triple<Map<String, Set<String>>, List<String>, UserTO> self = rossini.self();
229         assertEquals(List.of("bellini"), self.getMiddle());
230 
231         // 3a. search users as rossini without delegation -> FAIL
232         try {
233             rossini.getService(UserService.class).search(
234                     new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).build());
235             fail();
236         } catch (ForbiddenException e) {
237             assertNotNull(e);
238         }
239 
240         // 3b. search users as rossini with delegation -> SUCCESS
241         int forRossini = rossini.delegatedBy("bellini").getService(UserService.class).search(
242                 new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).build()).getTotalCount();
243         if (!IS_EXT_SEARCH_ENABLED) {
244             assertEquals(forBellini, forRossini);
245         }
246 
247         // 4. delete delegation: searching users as rossini does not work, even with delegation
248         DELEGATION_SERVICE.delete(delegation.getKey());
249 
250         try {
251             rossini.getService(UserService.class).search(
252                     new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).build());
253             fail();
254         } catch (AccessControlException e) {
255             assertNotNull(e);
256         }
257 
258         // 5. query audit entries
259         AuditQuery query = new AuditQuery.Builder().
260                 type(authLoginSuccess.getType()).
261                 category(authLoginSuccess.getCategory()).
262                 event(authLoginSuccess.getEvent()).
263                 result(authLoginSuccess.getResult()).
264                 build();
265         List<AuditEntry> entries = query(query, MAX_WAIT_SECONDS);
266         assertTrue(entries.stream().anyMatch(entry -> "rossini [delegated by bellini]".equals(entry.getWho())));
267 
268         // 6. disable audit
269         authLogin.setActive(false);
270         AUDIT_SERVICE.set(authLogin);
271     }
272 }