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(userLogic.read(id), op);
96 userLogic.update(update.getLeft(), false);
97 Optional.ofNullable(update.getRight()).ifPresent(statusR -> userLogic.status(statusR, false));
98 });
99
100 return updateResponse(
101 id,
102 binder.toSCIMUser(
103 userLogic.read(id),
104 uriInfo.getAbsolutePathBuilder().path(id).build().toASCIIString(),
105 List.of(),
106 List.of()));
107 }
108
109 @Override
110 public Response replace(final String id, final SCIMUser user) {
111 if (!id.equals(user.getId())) {
112 throw new BadRequestException(ErrorType.invalidPath, "Expected " + id + ", found " + user.getId());
113 }
114
115 ResponseBuilder builder = checkETag(Resource.User, id);
116 if (builder != null) {
117 return builder.build();
118 }
119
120 UserTO before = userLogic.read(id);
121
122 ProvisioningResult<UserTO> result = userLogic.update(
123 AnyOperations.diff(binder.toUserTO(user, true), before, false), false);
124
125 if (before.isSuspended() == user.isActive()) {
126 StatusR statusR = new StatusR.Builder(
127 before.getKey(),
128 user.isActive() ? StatusRType.REACTIVATE : StatusRType.SUSPEND).
129 build();
130 userLogic.status(statusR, false);
131 }
132
133 return updateResponse(
134 result.getEntity().getKey(),
135 binder.toSCIMUser(
136 result.getEntity(),
137 uriInfo.getAbsolutePathBuilder().path(result.getEntity().getKey()).build().toASCIIString(),
138 List.of(),
139 List.of()));
140 }
141
142 @Override
143 public Response delete(final String id) {
144 ResponseBuilder builder = checkETag(Resource.User, id);
145 if (builder != null) {
146 return builder.build();
147 }
148
149 anyLogic(Resource.User).delete(id, false);
150 return Response.noContent().build();
151 }
152
153 @Override
154 public ListResponse<SCIMUser> search(
155 final String attributes,
156 final String excludedAttributes,
157 final String filter,
158 final String sortBy,
159 final SortOrder sortOrder,
160 final Integer startIndex,
161 final Integer count) {
162
163 SCIMSearchRequest request = new SCIMSearchRequest(filter, sortBy, sortOrder, startIndex, count);
164 if (attributes != null) {
165 request.getAttributes().addAll(
166 List.of(ArrayUtils.nullToEmpty(StringUtils.split(attributes, ','))));
167 }
168 if (excludedAttributes != null) {
169 request.getExcludedAttributes().addAll(
170 List.of(ArrayUtils.nullToEmpty(StringUtils.split(excludedAttributes, ','))));
171 }
172
173 return doSearch(Resource.User, request);
174 }
175
176 @Override
177 public ListResponse<SCIMUser> search(final SCIMSearchRequest request) {
178 return doSearch(Resource.User, request);
179 }
180 }