1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.ext.scimv2.cxf.service;
20
21 import java.util.List;
22 import java.util.Optional;
23 import javax.ws.rs.core.Response;
24 import javax.ws.rs.core.Response.ResponseBuilder;
25 import org.apache.commons.lang3.ArrayUtils;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.commons.lang3.tuple.Pair;
28 import org.apache.syncope.common.lib.AnyOperations;
29 import org.apache.syncope.common.lib.request.StatusR;
30 import org.apache.syncope.common.lib.request.UserUR;
31 import org.apache.syncope.common.lib.to.ProvisioningResult;
32 import org.apache.syncope.common.lib.to.UserTO;
33 import org.apache.syncope.common.lib.types.StatusRType;
34 import org.apache.syncope.core.logic.GroupLogic;
35 import org.apache.syncope.core.logic.SCIMDataBinder;
36 import org.apache.syncope.core.logic.UserLogic;
37 import org.apache.syncope.core.logic.scim.SCIMConfManager;
38 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
39 import org.apache.syncope.core.persistence.api.dao.UserDAO;
40 import org.apache.syncope.ext.scimv2.api.BadRequestException;
41 import org.apache.syncope.ext.scimv2.api.data.ListResponse;
42 import org.apache.syncope.ext.scimv2.api.data.SCIMPatchOp;
43 import org.apache.syncope.ext.scimv2.api.data.SCIMSearchRequest;
44 import org.apache.syncope.ext.scimv2.api.data.SCIMUser;
45 import org.apache.syncope.ext.scimv2.api.service.SCIMUserService;
46 import org.apache.syncope.ext.scimv2.api.type.ErrorType;
47 import org.apache.syncope.ext.scimv2.api.type.Resource;
48 import org.apache.syncope.ext.scimv2.api.type.SortOrder;
49
50 public class SCIMUserServiceImpl extends AbstractSCIMService<SCIMUser> implements SCIMUserService {
51
52 public SCIMUserServiceImpl(
53 final UserDAO userDAO,
54 final GroupDAO groupDAO,
55 final UserLogic userLogic,
56 final GroupLogic groupLogic,
57 final SCIMDataBinder binder,
58 final SCIMConfManager confManager) {
59
60 super(userDAO, groupDAO, userLogic, groupLogic, binder, confManager);
61 }
62
63 @Override
64 public Response create(final SCIMUser user) {
65 ProvisioningResult<UserTO> result = userLogic.create(binder.toUserCR(user), false);
66 return createResponse(
67 result.getEntity().getKey(),
68 binder.toSCIMUser(
69 result.getEntity(),
70 uriInfo.getAbsolutePathBuilder().path(result.getEntity().getKey()).build().toASCIIString(),
71 List.of(),
72 List.of()));
73 }
74
75 @Override
76 public SCIMUser get(final String id,
77 final String attributes,
78 final String excludedAttributes) {
79
80 return binder.toSCIMUser(
81 userLogic.read(id),
82 uriInfo.getAbsolutePathBuilder().build().toASCIIString(),
83 List.of(ArrayUtils.nullToEmpty(StringUtils.split(attributes, ','))),
84 List.of(ArrayUtils.nullToEmpty(StringUtils.split(excludedAttributes, ','))));
85 }
86
87 @Override
88 public Response update(final String id, final SCIMPatchOp patch) {
89 ResponseBuilder builder = checkETag(Resource.User, id);
90 if (builder != null) {
91 return builder.build();
92 }
93
94 patch.getOperations().forEach(op -> {
95 Pair<UserUR, StatusR> update = binder.toUserUpdate(
96 userLogic.read(id),
97 userDAO.findAllResourceKeys(id),
98 op);
99 userLogic.update(update.getLeft(), false);
100 Optional.ofNullable(update.getRight()).ifPresent(statusR -> userLogic.status(statusR, false));
101 });
102
103 return updateResponse(
104 id,
105 binder.toSCIMUser(
106 userLogic.read(id),
107 uriInfo.getAbsolutePathBuilder().path(id).build().toASCIIString(),
108 List.of(),
109 List.of()));
110 }
111
112 @Override
113 public Response replace(final String id, final SCIMUser user) {
114 if (!id.equals(user.getId())) {
115 throw new BadRequestException(ErrorType.invalidPath, "Expected " + id + ", found " + user.getId());
116 }
117
118 ResponseBuilder builder = checkETag(Resource.User, id);
119 if (builder != null) {
120 return builder.build();
121 }
122
123 UserTO before = userLogic.read(id);
124
125 ProvisioningResult<UserTO> result = userLogic.update(
126 AnyOperations.diff(binder.toUserTO(user, true), before, false), false);
127
128 if (before.isSuspended() == user.isActive()) {
129 StatusR statusR = new StatusR.Builder(
130 before.getKey(),
131 user.isActive() ? StatusRType.REACTIVATE : StatusRType.SUSPEND).
132 build();
133 userLogic.status(statusR, false);
134 }
135
136 return updateResponse(
137 result.getEntity().getKey(),
138 binder.toSCIMUser(
139 result.getEntity(),
140 uriInfo.getAbsolutePathBuilder().path(result.getEntity().getKey()).build().toASCIIString(),
141 List.of(),
142 List.of()));
143 }
144
145 @Override
146 public Response delete(final String id) {
147 ResponseBuilder builder = checkETag(Resource.User, id);
148 if (builder != null) {
149 return builder.build();
150 }
151
152 anyLogic(Resource.User).delete(id, false);
153 return Response.noContent().build();
154 }
155
156 @Override
157 public ListResponse<SCIMUser> search(
158 final String attributes,
159 final String excludedAttributes,
160 final String filter,
161 final String sortBy,
162 final SortOrder sortOrder,
163 final Integer startIndex,
164 final Integer count) {
165
166 SCIMSearchRequest request = new SCIMSearchRequest(filter, sortBy, sortOrder, startIndex, count);
167 if (attributes != null) {
168 request.getAttributes().addAll(
169 List.of(ArrayUtils.nullToEmpty(StringUtils.split(attributes, ','))));
170 }
171 if (excludedAttributes != null) {
172 request.getExcludedAttributes().addAll(
173 List.of(ArrayUtils.nullToEmpty(StringUtils.split(excludedAttributes, ','))));
174 }
175
176 return doSearch(Resource.User, request);
177 }
178
179 @Override
180 public ListResponse<SCIMUser> search(final SCIMSearchRequest request) {
181 return doSearch(Resource.User, request);
182 }
183 }