1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.logic;
20
21 import java.lang.reflect.Method;
22 import java.util.List;
23 import org.apache.commons.io.output.NullOutputStream;
24 import org.apache.commons.lang3.tuple.Pair;
25 import org.apache.syncope.common.lib.SyncopeClientException;
26 import org.apache.syncope.common.lib.request.UserUR;
27 import org.apache.syncope.common.lib.to.EntityTO;
28 import org.apache.syncope.common.lib.to.ProvisioningResult;
29 import org.apache.syncope.common.lib.to.UserRequest;
30 import org.apache.syncope.common.lib.to.UserRequestForm;
31 import org.apache.syncope.common.lib.to.UserTO;
32 import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
33 import org.apache.syncope.common.lib.types.BpmnProcessFormat;
34 import org.apache.syncope.common.lib.types.ClientExceptionType;
35 import org.apache.syncope.common.lib.types.FlowableEntitlement;
36 import org.apache.syncope.core.flowable.api.BpmnProcessManager;
37 import org.apache.syncope.core.flowable.api.UserRequestHandler;
38 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
39 import org.apache.syncope.core.persistence.api.dao.UserDAO;
40 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
41 import org.apache.syncope.core.persistence.api.entity.user.User;
42 import org.apache.syncope.core.provisioning.api.UserWorkflowResult;
43 import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
44 import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
45 import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
46 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
47 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
48 import org.apache.syncope.core.spring.security.AuthContextUtils;
49 import org.flowable.engine.runtime.ProcessInstance;
50 import org.springframework.security.access.prepost.PreAuthorize;
51 import org.springframework.transaction.annotation.Transactional;
52
53 public class UserRequestLogic extends AbstractTransactionalLogic<EntityTO> {
54
55 protected final BpmnProcessManager bpmnProcessManager;
56
57 protected final UserRequestHandler userRequestHandler;
58
59 protected final PropagationManager propagationManager;
60
61 protected final PropagationTaskExecutor taskExecutor;
62
63 protected final UserDataBinder binder;
64
65 protected final UserDAO userDAO;
66
67 public UserRequestLogic(
68 final BpmnProcessManager bpmnProcessManager,
69 final UserRequestHandler userRequestHandler,
70 final PropagationManager propagationManager,
71 final PropagationTaskExecutor taskExecutor,
72 final UserDataBinder binder,
73 final UserDAO userDAO) {
74
75 this.bpmnProcessManager = bpmnProcessManager;
76 this.userRequestHandler = userRequestHandler;
77 this.propagationManager = propagationManager;
78 this.taskExecutor = taskExecutor;
79 this.binder = binder;
80 this.userDAO = userDAO;
81 }
82
83 @PreAuthorize("isAuthenticated()")
84 @Transactional(readOnly = true)
85 public Pair<Integer, List<UserRequest>> listRequests(
86 final String userKey,
87 final int page,
88 final int size,
89 final List<OrderByClause> orderByClauses) {
90
91 if (userKey == null) {
92 securityChecks(null,
93 FlowableEntitlement.USER_REQUEST_LIST,
94 "Listing user requests not allowed");
95 } else {
96 User user = userDAO.find(userKey);
97 if (user == null) {
98 throw new NotFoundException("User " + userKey);
99 }
100
101 securityChecks(user.getUsername(),
102 FlowableEntitlement.USER_REQUEST_LIST,
103 "Listing requests for user" + user.getUsername() + " not allowed");
104 }
105
106 return userRequestHandler.getUserRequests(userKey, page, size, orderByClauses);
107 }
108
109 protected UserRequest doStart(
110 final String bpmnProcess,
111 final User user,
112 final WorkflowTaskExecInput inputVariables) {
113
114
115 bpmnProcessManager.exportProcess(bpmnProcess, BpmnProcessFormat.XML, NullOutputStream.INSTANCE);
116
117 return userRequestHandler.start(bpmnProcess, user, inputVariables);
118 }
119
120 @PreAuthorize("isAuthenticated()")
121 public UserRequest startRequest(final String bpmnProcess, final WorkflowTaskExecInput inputVariables) {
122 return doStart(bpmnProcess, userDAO.findByUsername(AuthContextUtils.getUsername()), inputVariables);
123 }
124
125 @PreAuthorize("hasRole('" + FlowableEntitlement.USER_REQUEST_START + "')")
126 public UserRequest startRequest(
127 final String bpmnProcess,
128 final String userKey,
129 final WorkflowTaskExecInput inputVariables) {
130 return doStart(bpmnProcess, userDAO.authFind(userKey), inputVariables);
131 }
132
133 protected static void securityChecks(final String username, final String entitlement, final String errorMessage) {
134 if (!AuthContextUtils.getUsername().equals(username)
135 && !AuthContextUtils.getAuthorities().stream().
136 anyMatch(auth -> entitlement.equals(auth.getAuthority()))) {
137
138 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.DelegatedAdministration);
139 sce.getElements().add(errorMessage);
140 throw sce;
141 }
142 }
143
144 @PreAuthorize("isAuthenticated()")
145 public void cancelRequest(final String executionId, final String reason) {
146 Pair<ProcessInstance, String> parsed = userRequestHandler.parse(executionId);
147
148 securityChecks(userDAO.find(parsed.getRight()).getUsername(),
149 FlowableEntitlement.USER_REQUEST_CANCEL,
150 "Canceling " + executionId + " not allowed");
151
152 userRequestHandler.cancel(parsed.getLeft(), reason);
153 }
154
155 @PreAuthorize("isAuthenticated()")
156 public UserRequestForm claimForm(final String taskId) {
157 UserRequestForm form = userRequestHandler.claimForm(taskId);
158 securityChecks(form.getUsername(),
159 FlowableEntitlement.USER_REQUEST_FORM_CLAIM,
160 "Claiming form " + taskId + " not allowed");
161 return form;
162 }
163
164 @PreAuthorize("isAuthenticated()")
165 public UserRequestForm unclaimForm(final String taskId) {
166 UserRequestForm form = userRequestHandler.unclaimForm(taskId);
167 securityChecks(form.getUsername(),
168 FlowableEntitlement.USER_REQUEST_FORM_UNCLAIM,
169 "Unclaiming form " + taskId + " not allowed");
170 return form;
171 }
172
173 protected void evaluateKey(final String userKey) {
174 if (userKey == null) {
175 securityChecks(null,
176 FlowableEntitlement.USER_REQUEST_FORM_LIST,
177 "Listing forms not allowed");
178 } else {
179 User user = userDAO.find(userKey);
180 if (user == null) {
181 throw new NotFoundException("User " + userKey);
182 }
183
184 securityChecks(user.getUsername(),
185 FlowableEntitlement.USER_REQUEST_FORM_LIST,
186 "Listing forms for user" + user.getUsername() + " not allowed");
187 }
188 }
189
190 @PreAuthorize("isAuthenticated()")
191 public UserRequestForm getForm(final String userKey, final String taskId) {
192 evaluateKey(userKey);
193
194 return userRequestHandler.getForm(userKey, taskId);
195 }
196
197 @PreAuthorize("isAuthenticated()")
198 @Transactional(readOnly = true)
199 public Pair<Integer, List<UserRequestForm>> listForms(
200 final String userKey,
201 final int page,
202 final int size,
203 final List<OrderByClause> orderByClauses) {
204
205 evaluateKey(userKey);
206
207 return userRequestHandler.getForms(userKey, page, size, orderByClauses);
208 }
209
210 @PreAuthorize("isAuthenticated()")
211 public ProvisioningResult<UserTO> submitForm(final UserRequestForm form, final boolean nullPriorityAsync) {
212 if (form.getUsername() == null) {
213 securityChecks(null,
214 FlowableEntitlement.USER_REQUEST_FORM_SUBMIT,
215 "Submitting forms not allowed");
216 } else {
217 securityChecks(form.getUsername(),
218 FlowableEntitlement.USER_REQUEST_FORM_SUBMIT,
219 "Submitting forms for user" + form.getUsername() + " not allowed");
220 }
221
222 ProvisioningResult<UserTO> result = new ProvisioningResult<>();
223
224 UserWorkflowResult<UserUR> wfResult = userRequestHandler.submitForm(form);
225
226
227
228 if (wfResult.getPropByRes() != null && !wfResult.getPropByRes().isEmpty()) {
229 List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(
230 new UserWorkflowResult<>(
231 Pair.of(wfResult.getResult(), Boolean.TRUE),
232 wfResult.getPropByRes(),
233 wfResult.getPropByLinkedAccount(),
234 wfResult.getPerformedTasks()));
235
236 PropagationReporter propagationReporter = taskExecutor.execute(
237 taskInfos, nullPriorityAsync, AuthContextUtils.getUsername());
238 result.getPropagationStatuses().addAll(propagationReporter.getStatuses());
239 }
240
241 UserTO userTO;
242 if (userDAO.find(wfResult.getResult().getKey()) == null) {
243 userTO = new UserTO();
244 userTO.setKey(wfResult.getResult().getKey());
245 } else {
246 userTO = binder.getUserTO(wfResult.getResult().getKey());
247 }
248 result.setEntity(userTO);
249
250 return result;
251 }
252
253 @Override
254 protected EntityTO resolveReference(final Method method, final Object... args)
255 throws UnresolvedReferenceException {
256
257 throw new UnresolvedReferenceException();
258 }
259 }