001/*
002 * (C) Copyright 2015 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 */
018
019package org.nuxeo.scim.server.jaxrs.usermanager;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import javax.servlet.http.HttpServletResponse;
028import javax.ws.rs.Consumes;
029import javax.ws.rs.DELETE;
030import javax.ws.rs.GET;
031import javax.ws.rs.POST;
032import javax.ws.rs.PUT;
033import javax.ws.rs.Path;
034import javax.ws.rs.PathParam;
035import javax.ws.rs.Produces;
036import javax.ws.rs.core.Context;
037import javax.ws.rs.core.MediaType;
038import javax.ws.rs.core.Response;
039import javax.ws.rs.core.Response.Status;
040import javax.ws.rs.core.UriInfo;
041
042import org.nuxeo.ecm.core.api.ClientException;
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.WebException;
049import org.nuxeo.ecm.webengine.model.WebObject;
050import org.nuxeo.runtime.api.Framework;
051import org.nuxeo.scim.server.jaxrs.marshalling.GroupResponse;
052
053import com.unboundid.scim.data.GroupResource;
054import com.unboundid.scim.sdk.Resources;
055
056/**
057 * Simple Resource class used to expose the SCIM API on Users endpoint
058 *
059 * @author tiry
060 * @since 7.4
061 */
062
063@WebObject(type = "groups")
064@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
065public class SCIMGroupWebObject extends BaseUMObject {
066
067    @Override
068    protected String getPrefix() {
069        return "/Groups";
070    }
071
072    protected GroupResource resolveGroupRessource(String uid) {
073
074        try {
075            DocumentModel groupModel = um.getGroupModel(uid);
076            if (groupModel != null) {
077                return mapper.getGroupResourceFromNuxeoGroup(groupModel);
078            }
079        } catch (Exception e) {
080            log.error("Error while resolving User", e);
081        }
082        return null;
083    }
084
085    @GET
086    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + "; qs=0.9" })
087    public Resources<GroupResource> getGroups(@Context UriInfo uriInfo) {
088
089        Map<String, List<String>> params = uriInfo.getQueryParameters();
090
091        // filter
092        Map<String, Serializable> filter = new HashMap<>();
093        List<String> filters = params.get("filter");
094        if (filters != null && filters.size() > 0) {
095            String[] filterParts = filters.get(0).split(" ");
096            if (filterParts[1].equals("eq")) {
097                String key = filterParts[0];
098                if (key.equals("userName")) {
099                    key = "username";
100                }
101                String value = filterParts[2];
102                if (value.startsWith("\"")) {
103                    value = value.substring(1, value.length() - 2);
104                }
105                filter.put(key, value);
106            }
107        }
108
109        // sort
110        List<String> sortCol = params.get("sortBy");
111        List<String> sortType = params.get("sortOrder");
112        // XXX mapping
113        Map<String, String> orderBy = new HashMap<>();
114        if (sortCol != null && sortCol.size() > 0) {
115            String order = "asc";
116            if (sortType != null && sortType.size() > 0) {
117                if (sortType.get(0).equalsIgnoreCase("descending")) {
118                    order = "desc";
119                }
120                orderBy.put(sortCol.get(0), order);
121            }
122        }
123        int startIndex = 1;
124        if (params.get("startIndex") != null) {
125            startIndex = Integer.parseInt(params.get("startIndex").get(0));
126        }
127        int count = 10;
128        if (params.get("count") != null) {
129            count = Integer.parseInt(params.get("count").get(0));
130        }
131
132        try {
133            String directoryName = um.getGroupDirectoryName();
134
135            DirectoryService ds = Framework.getLocalService(DirectoryService.class);
136
137            Session dSession = null;
138            DocumentModelList groupModels = null;
139            try {
140                dSession = ds.open(directoryName);
141                groupModels = dSession.query(filter, null, orderBy, true, count, startIndex - 1);
142            } finally {
143                dSession.close();
144            }
145
146            List<GroupResource> groupResources = new ArrayList<>();
147            for (DocumentModel groupModel : groupModels) {
148                groupResources.add(mapper.getGroupResourceFromNuxeoGroup(groupModel));
149            }
150            return new Resources<>(groupResources, groupResources.size(), startIndex);
151        } catch (Exception e) {
152            log.error("Error while getting Groups", e);
153        }
154        return null;
155    }
156
157    @Path("{uid}")
158    @GET
159    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
160    public GroupResource getGroupResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
161        return resolveGroupRessource(uid);
162
163    }
164
165    @Path("{uid}.xml")
166    @GET
167    @Produces(MediaType.APPLICATION_XML)
168    public GroupResource getGroupResourceAsXml(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
169        return getGroupResource(uriInfo, uid);
170    }
171
172    @Path("{uid}.json")
173    @GET
174    @Produces(MediaType.APPLICATION_JSON)
175    public GroupResource getUserResourceAsJSON(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
176        return getGroupResource(uriInfo, uid);
177    }
178
179    @POST
180    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
181    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
182    public Response createGroup(@Context UriInfo uriInfo, GroupResource group,
183            @Context final HttpServletResponse response) {
184        try {
185            checkUpdateGuardPreconditions();
186            return doCreateGroup(group, fixeMediaType);
187        } catch (ClientException e) {
188            throw WebException.wrap(e);
189        }
190    }
191
192    @PUT
193    @Path("{uid}")
194    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
195    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
196    public Response updateGroup(@Context UriInfo uriInfo, @PathParam("uid") String uid, GroupResource user) {
197        try {
198            checkUpdateGuardPreconditions();
199            return doUpdateGroup(uid, user, fixeMediaType);
200        } catch (ClientException e) {
201            throw WebException.wrap(e);
202        }
203    }
204
205    protected Response doUpdateGroup(String uid, GroupResource group, MediaType mt) {
206
207        try {
208            DocumentModel groupModel = mapper.updateGroupModelFromGroupResource(uid, group);
209            if (groupModel != null) {
210                GroupResource groupResource = mapper.getGroupResourceFromNuxeoGroup(groupModel);
211                return GroupResponse.updated(groupResource, mt);
212            }
213        } catch (Exception e) {
214            log.error("Unable to update Group", e);
215        }
216        return null;
217    }
218
219    protected Response doCreateGroup(GroupResource group, MediaType mt) {
220
221        try {
222            DocumentModel newGroup = mapper.createGroupModelFromGroupResource(group);
223            GroupResource groupResource = mapper.getGroupResourceFromNuxeoGroup(newGroup);
224            return GroupResponse.created(groupResource, mt);
225        } catch (Exception e) {
226            log.error("Unable to create Group", e);
227        }
228        return null;
229    }
230
231    @Path("{uid}")
232    @DELETE
233    public Response deleteGroupResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
234        try {
235            um.deleteGroup(uid);
236            return Response.ok().build();
237        } catch (DirectoryException e) {
238            return Response.status(Status.NOT_FOUND).build();
239        }
240    }
241
242}