001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 */
020
021package org.nuxeo.scim.server.jaxrs.usermanager;
022
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Map;
028
029import javax.ws.rs.Consumes;
030import javax.ws.rs.DELETE;
031import javax.ws.rs.GET;
032import javax.ws.rs.POST;
033import javax.ws.rs.PUT;
034import javax.ws.rs.Path;
035import javax.ws.rs.PathParam;
036import javax.ws.rs.Produces;
037import javax.ws.rs.core.Context;
038import javax.ws.rs.core.MediaType;
039import javax.ws.rs.core.Response;
040import javax.ws.rs.core.Response.Status;
041import javax.ws.rs.core.UriInfo;
042
043import org.nuxeo.ecm.core.api.DocumentModel;
044import org.nuxeo.ecm.core.api.DocumentModelList;
045import org.nuxeo.ecm.directory.DirectoryException;
046import org.nuxeo.ecm.directory.Session;
047import org.nuxeo.ecm.directory.api.DirectoryService;
048import org.nuxeo.ecm.webengine.model.WebObject;
049import org.nuxeo.runtime.api.Framework;
050import org.nuxeo.scim.server.jaxrs.marshalling.UserResponse;
051
052import com.unboundid.scim.data.UserResource;
053import com.unboundid.scim.sdk.Resources;
054
055/**
056 * Simple Resource class used to expose the SCIM API on Users endpoint
057 *
058 * @author tiry
059 * @since 7.4
060 */
061@WebObject(type = "users")
062@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
063public class SCIMUserWebObject extends BaseUMObject {
064
065    @Override
066    protected String getPrefix() {
067        return "/Users";
068    }
069
070    protected UserResource resolveUserRessource(String uid) {
071
072        try {
073            DocumentModel userModel = um.getUserModel(uid);
074            if (userModel != null) {
075                return mapper.getUserResourceFromNuxeoUser(userModel);
076            }
077        } catch (Exception e) {
078            log.error("Error while resolving User", e);
079        }
080
081        return null;
082    }
083
084    @GET
085    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + "; qs=0.9" })
086    public Resources<UserResource> getUsers(@Context UriInfo uriInfo) {
087
088        Map<String, List<String>> params = uriInfo.getQueryParameters();
089
090        // filter
091        Map<String, Serializable> filter = new HashMap<>();
092        List<String> filters = params.get("filter");
093        if (filters != null && filters.size() > 0) {
094            String[] filterParts = filters.get(0).split(" ");
095            if (filterParts[1].equals("eq")) {
096                String key = filterParts[0];
097                if (key.equals("userName")) {
098                    key = "username";
099                }
100                String value = filterParts[2];
101                if (value.startsWith("\"")) {
102                    value = value.substring(1, value.length() - 2);
103                }
104                filter.put(key, value);
105            }
106        }
107
108        // sort
109        List<String> sortCol = params.get("sortBy");
110        List<String> sortType = params.get("sortOrder");
111        // XXX mapping
112        Map<String, String> orderBy = new HashMap<>();
113        if (sortCol != null && sortCol.size() > 0) {
114            String order = "asc";
115            if (sortType != null && sortType.size() > 0) {
116                if (sortType.get(0).equalsIgnoreCase("descending")) {
117                    order = "desc";
118                }
119                orderBy.put(sortCol.get(0), order);
120            }
121        }
122        int startIndex = 1;
123        if (params.get("startIndex") != null) {
124            startIndex = Integer.parseInt(params.get("startIndex").get(0));
125        }
126        int count = 10;
127        if (params.get("count") != null) {
128            count = Integer.parseInt(params.get("count").get(0));
129        }
130
131        try {
132            String directoryName = um.getUserDirectoryName();
133
134            DirectoryService ds = Framework.getService(DirectoryService.class);
135
136            Session dSession = null;
137            DocumentModelList userModels = null;
138            try {
139                dSession = ds.open(directoryName);
140                userModels = dSession.query(filter, null, orderBy, true, count, startIndex - 1);
141            } finally {
142                dSession.close();
143            }
144
145            List<UserResource> userResources = new ArrayList<>();
146            for (DocumentModel userModel : userModels) {
147                userResources.add(mapper.getUserResourceFromNuxeoUser(userModel));
148            }
149            return new Resources<>(userResources, userResources.size(), startIndex);
150        } catch (Exception e) {
151            log.error("Error while getting Users", e);
152        }
153        return null;
154    }
155
156    @Path("{uid}")
157    @GET
158    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
159    public UserResource getUserResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
160        return resolveUserRessource(uid);
161
162    }
163
164    @Path("{uid}.xml")
165    @GET
166    @Produces(MediaType.APPLICATION_XML)
167    public UserResource getUserResourceAsXml(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
168        return getUserResource(uriInfo, uid);
169    }
170
171    @Path("{uid}.json")
172    @GET
173    @Produces(MediaType.APPLICATION_JSON)
174    public UserResource getUserResourceAsJSON(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
175        return getUserResource(uriInfo, uid);
176    }
177
178    @POST
179    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
180    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
181    public Response createUser(UserResource user) {
182        return doCreateUserResponse(user, fixeMediaType);
183    }
184
185    protected Response doCreateUserResponse(UserResource user, MediaType mt) {
186        checkUpdateGuardPreconditions();
187        return UserResponse.created(doCreateUser(user), mt);
188
189    }
190
191    protected UserResource doCreateUser(UserResource user) {
192
193        try {
194            DocumentModel newUser = mapper.createNuxeoUserFromUserResource(user);
195            UserResource resource = mapper.getUserResourceFromNuxeoUser(newUser);
196            return resource;
197        } catch (Exception e) {
198            log.error("Unable to create User", e);
199        }
200        return null;
201    }
202
203    @PUT
204    @Path("{uid}")
205    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
206    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
207    public Response updateUser(@Context UriInfo uriInfo, @PathParam("uid") String uid, UserResource user) {
208        checkUpdateGuardPreconditions();
209        return doUpdateUser(uid, user, fixeMediaType);
210    }
211
212    protected Response doUpdateUser(String uid, UserResource user, MediaType mt) {
213
214        try {
215            DocumentModel userModel = mapper.updateNuxeoUserFromUserResource(uid, user);
216            if (userModel != null) {
217                UserResource userResource = mapper.getUserResourceFromNuxeoUser(userModel);
218                return UserResponse.updated(userResource, mt);
219            }
220        } catch (Exception e) {
221            log.error("Unable to create User", e);
222        }
223        return null;
224    }
225
226    @Path("{uid}")
227    @DELETE
228    public Response deleteUserResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
229        try {
230            um.deleteUser(uid);
231            return Response.ok().build();
232        } catch (DirectoryException e) {
233            return Response.status(Status.NOT_FOUND).build();
234        }
235    }
236
237}