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.awaitility.Awaitility.await;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertNotNull;
25  import static org.junit.jupiter.api.Assertions.fail;
26  
27  import java.nio.charset.StandardCharsets;
28  import java.util.concurrent.TimeUnit;
29  import javax.ws.rs.core.Response;
30  import org.apache.commons.io.IOUtils;
31  import org.apache.syncope.common.lib.SyncopeClientException;
32  import org.apache.syncope.common.lib.command.CommandTO;
33  import org.apache.syncope.common.lib.request.UserCR;
34  import org.apache.syncope.common.lib.to.AnyObjectTO;
35  import org.apache.syncope.common.lib.to.ExecTO;
36  import org.apache.syncope.common.lib.to.ImplementationTO;
37  import org.apache.syncope.common.lib.to.MacroTaskTO;
38  import org.apache.syncope.common.lib.to.RoleTO;
39  import org.apache.syncope.common.lib.to.UserTO;
40  import org.apache.syncope.common.lib.types.ClientExceptionType;
41  import org.apache.syncope.common.lib.types.ExecStatus;
42  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
43  import org.apache.syncope.common.lib.types.IdRepoImplementationType;
44  import org.apache.syncope.common.lib.types.ImplementationEngine;
45  import org.apache.syncope.common.lib.types.TaskType;
46  import org.apache.syncope.common.rest.api.RESTHeaders;
47  import org.apache.syncope.common.rest.api.beans.ExecSpecs;
48  import org.apache.syncope.common.rest.api.beans.RealmQuery;
49  import org.apache.syncope.common.rest.api.service.TaskService;
50  import org.apache.syncope.fit.AbstractITCase;
51  import org.apache.syncope.fit.core.reference.TestCommand;
52  import org.apache.syncope.fit.core.reference.TestCommandArgs;
53  import org.junit.jupiter.api.AfterAll;
54  import org.junit.jupiter.api.BeforeAll;
55  import org.junit.jupiter.api.Test;
56  
57  public class MacroITCase extends AbstractITCase {
58  
59      private static String MACRO_TASK_KEY;
60  
61      private static final TestCommandArgs TCA = new TestCommandArgs();
62  
63      static {
64          TCA.setParentRealm("/odd");
65          TCA.setRealmName("macro");
66          TCA.setPrinterName("aprinter112");
67      }
68  
69      @BeforeAll
70      public static void testCommandsSetup() throws Exception {
71          CommandITCase.testCommandSetup();
72  
73          ImplementationTO transformer = null;
74          try {
75              transformer = IMPLEMENTATION_SERVICE.read(
76                      IdRepoImplementationType.COMMAND, "GroovyCommand");
77          } catch (SyncopeClientException e) {
78              if (e.getType().getResponseStatus() == Response.Status.NOT_FOUND) {
79                  transformer = new ImplementationTO();
80                  transformer.setKey("GroovyCommand");
81                  transformer.setEngine(ImplementationEngine.GROOVY);
82                  transformer.setType(IdRepoImplementationType.COMMAND);
83                  transformer.setBody(IOUtils.toString(
84                          MacroITCase.class.getResourceAsStream("/GroovyCommand.groovy"), StandardCharsets.UTF_8));
85                  Response response = IMPLEMENTATION_SERVICE.create(transformer);
86                  transformer = IMPLEMENTATION_SERVICE.read(
87                          transformer.getType(), response.getHeaderString(RESTHeaders.RESOURCE_KEY));
88                  assertNotNull(transformer.getKey());
89              }
90          }
91          assertNotNull(transformer);
92  
93          if (MACRO_TASK_KEY == null) {
94              MacroTaskTO task = new MacroTaskTO();
95              task.setName("Test Macro");
96              task.setActive(true);
97              task.setRealm("/odd");
98              task.getCommands().add(new CommandTO.Builder("GroovyCommand").build());
99              task.getCommands().add(new CommandTO.Builder(TestCommand.class.getSimpleName()).args(TCA).build());
100 
101             Response response = TASK_SERVICE.create(TaskType.MACRO, task);
102             task = getObject(response.getLocation(), TaskService.class, MacroTaskTO.class);
103             MACRO_TASK_KEY = task.getKey();
104         }
105     }
106 
107     @AfterAll
108     public static void cleanup() {
109         TestCommandArgs args = new TestCommandArgs();
110         try {
111             ANY_OBJECT_SERVICE.delete(args.getPrinterName());
112             REALM_SERVICE.delete(args.getParentRealm() + "/" + args.getRealmName());
113         } catch (Exception e) {
114             // ignore
115         }
116     }
117 
118     @Test
119     public void execute() {
120         int preExecs = TASK_SERVICE.read(TaskType.MACRO, MACRO_TASK_KEY, true).getExecutions().size();
121         ExecTO execution = TASK_SERVICE.execute(new ExecSpecs.Builder().key(MACRO_TASK_KEY).build());
122         assertNotNull(execution.getExecutor());
123 
124         await().atMost(MAX_WAIT_SECONDS, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> {
125             try {
126                 return preExecs < TASK_SERVICE.read(TaskType.MACRO, MACRO_TASK_KEY, true).getExecutions().size();
127             } catch (Exception e) {
128                 return false;
129             }
130         });
131 
132         ExecTO exec = TASK_SERVICE.read(TaskType.MACRO, MACRO_TASK_KEY, true).getExecutions().get(preExecs);
133         assertEquals(ExecStatus.SUCCESS.name(), exec.getStatus());
134 
135         AnyObjectTO printer = ANY_OBJECT_SERVICE.read(PRINTER, TCA.getPrinterName());
136         assertNotNull(printer);
137         assertEquals(TCA.getParentRealm() + "/" + TCA.getRealmName(), printer.getRealm());
138         assertFalse(REALM_SERVICE.search(
139                 new RealmQuery.Builder().base(printer.getRealm()).build()).getResult().isEmpty());
140     }
141 
142     @Test
143     public void cantExecute() {
144         // 1. create Role for task execution
145         RoleTO role = new RoleTO();
146         role.setKey("new" + getUUIDString());
147         role.getRealms().add("/even");
148         role.getEntitlements().add(IdRepoEntitlement.TASK_EXECUTE);
149         role = createRole(role);
150         assertNotNull(role);
151 
152         // 2. create User with such a Role granted
153         UserCR userCR = UserITCase.getUniqueSample("cantrunncommand@test.org");
154         userCR.getRoles().add(role.getKey());
155         UserTO userTO = createUser(userCR).getEntity();
156         assertNotNull(userTO);
157 
158         // 3. attempt to run the macro task -> fail
159         TaskService taskService = CLIENT_FACTORY.create(
160                 userTO.getUsername(), "password123").getService(TaskService.class);
161         try {
162             taskService.execute(new ExecSpecs.Builder().key(MACRO_TASK_KEY).build());
163             fail();
164         } catch (SyncopeClientException e) {
165             assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
166         }
167     }
168 }