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.servlet.http.HttpServletResponse;
030import javax.ws.rs.Consumes;
031import javax.ws.rs.DELETE;
032import javax.ws.rs.GET;
033import javax.ws.rs.POST;
034import javax.ws.rs.PUT;
035import javax.ws.rs.Path;
036import javax.ws.rs.PathParam;
037import javax.ws.rs.Produces;
038import javax.ws.rs.core.Context;
039import javax.ws.rs.core.MediaType;
040import javax.ws.rs.core.Response;
041import javax.ws.rs.core.Response.Status;
042import javax.ws.rs.core.UriInfo;
043
044import org.nuxeo.ecm.core.api.ClientException;
045import org.nuxeo.ecm.core.api.DocumentModel;
046import org.nuxeo.ecm.core.api.DocumentModelList;
047import org.nuxeo.ecm.directory.DirectoryException;
048import org.nuxeo.ecm.directory.Session;
049import org.nuxeo.ecm.directory.api.DirectoryService;
050import org.nuxeo.ecm.webengine.WebException;
051import org.nuxeo.ecm.webengine.model.WebObject;
052import org.nuxeo.runtime.api.Framework;
053import org.nuxeo.scim.server.jaxrs.marshalling.GroupResponse;
054
055import com.unboundid.scim.data.GroupResource;
056import com.unboundid.scim.sdk.Resources;
057
058/**
059 * Simple Resource class used to expose the SCIM API on Users endpoint
060 *
061 * @author tiry
062 * @since 7.4
063 */
064
065@WebObject(type = "groups")
066@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
067public class SCIMGroupWebObject extends BaseUMObject {
068
069    @Override
070    protected String getPrefix() {
071        return "/Groups";
072    }
073
074    protected GroupResource resolveGroupRessource(String uid) {
075
076        try {
077            DocumentModel groupModel = um.getGroupModel(uid);
078            if (groupModel != null) {
079                return mapper.getGroupResourceFromNuxeoGroup(groupModel);
080            }
081        } catch (Exception e) {
082            log.error("Error while resolving User", e);
083        }
084        return null;
085    }
086
087    @GET
088    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + "; qs=0.9" })
089    public Resources<GroupResource> getGroups(@Context UriInfo uriInfo) {
090
091        Map<String, List<String>> params = uriInfo.getQueryParameters();
092
093        // filter
094        Map<String, Serializable> filter = new HashMap<>();
095        List<String> filters = params.get("filter");
096        if (filters != null && filters.size() > 0) {
097            String[] filterParts = filters.get(0).split(" ");
098            if (filterParts[1].equals("eq")) {
099                String key = filterParts[0];
100                if (key.equals("userName")) {
101                    key = "username";
102                }
103                String value = filterParts[2];
104                if (value.startsWith("\"")) {
105                    value = value.substring(1, value.length() - 2);
106                }
107                filter.put(key, value);
108            }
109        }
110
111        // sort
112        List<String> sortCol = params.get("sortBy");
113        List<String> sortType = params.get("sortOrder");
114        // XXX mapping
115        Map<String, String> orderBy = new HashMap<>();
116        if (sortCol != null && sortCol.size() > 0) {
117            String order = "asc";
118            if (sortType != null && sortType.size() > 0) {
119                if (sortType.get(0).equalsIgnoreCase("descending")) {
120                    order = "desc";
121                }
122                orderBy.put(sortCol.get(0), order);
123            }
124        }
125        int startIndex = 1;
126        if (params.get("startIndex") != null) {
127            startIndex = Integer.parseInt(params.get("startIndex").get(0));
128        }
129        int count = 10;
130        if (params.get("count") != null) {
131            count = Integer.parseInt(params.get("count").get(0));
132        }
133
134        try {
135            String directoryName = um.getGroupDirectoryName();
136
137            DirectoryService ds = Framework.getLocalService(DirectoryService.class);
138
139            Session dSession = null;
140            DocumentModelList groupModels = null;
141            try {
142                dSession = ds.open(directoryName);
143                groupModels = dSession.query(filter, null, orderBy, true, count, startIndex - 1);
144            } finally {
145                dSession.close();
146            }
147
148            List<GroupResource> groupResources = new ArrayList<>();
149            for (DocumentModel groupModel : groupModels) {
150                groupResources.add(mapper.getGroupResourceFromNuxeoGroup(groupModel));
151            }
152            return new Resources<>(groupResources, groupResources.size(), startIndex);
153        } catch (Exception e) {
154            log.error("Error while getting Groups", e);
155        }
156        return null;
157    }
158
159    @Path("{uid}")
160    @GET
161    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
162    public GroupResource getGroupResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
163        return resolveGroupRessource(uid);
164
165    }
166
167    @Path("{uid}.xml")
168    @GET
169    @Produces(MediaType.APPLICATION_XML)
170    public GroupResource getGroupResourceAsXml(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
171        return getGroupResource(uriInfo, uid);
172    }
173
174    @Path("{uid}.json")
175    @GET
176    @Produces(MediaType.APPLICATION_JSON)
177    public GroupResource getUserResourceAsJSON(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
178        return getGroupResource(uriInfo, uid);
179    }
180
181    @POST
182    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
183    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
184    public Response createGroup(@Context UriInfo uriInfo, GroupResource group,
185            @Context final HttpServletResponse response) {
186        try {
187            checkUpdateGuardPreconditions();
188            return doCreateGroup(group, fixeMediaType);
189        } catch (ClientException e) {
190            throw WebException.wrap(e);
191        }
192    }
193
194    @PUT
195    @Path("{uid}")
196    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
197    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
198    public Response updateGroup(@Context UriInfo uriInfo, @PathParam("uid") String uid, GroupResource user) {
199        try {
200            checkUpdateGuardPreconditions();
201            return doUpdateGroup(uid, user, fixeMediaType);
202        } catch (ClientException e) {
203            throw WebException.wrap(e);
204        }
205    }
206
207    protected Response doUpdateGroup(String uid, GroupResource group, MediaType mt) {
208
209        try {
210            DocumentModel groupModel = mapper.updateGroupModelFromGroupResource(uid, group);
211            if (groupModel != null) {
212                GroupResource groupResource = mapper.getGroupResourceFromNuxeoGroup(groupModel);
213                return GroupResponse.updated(groupResource, mt);
214            }
215        } catch (Exception e) {
216            log.error("Unable to update Group", e);
217        }
218        return null;
219    }
220
221    protected Response doCreateGroup(GroupResource group, MediaType mt) {
222
223        try {
224            DocumentModel newGroup = mapper.createGroupModelFromGroupResource(group);
225            GroupResource groupResource = mapper.getGroupResourceFromNuxeoGroup(newGroup);
226            return GroupResponse.created(groupResource, mt);
227        } catch (Exception e) {
228            log.error("Unable to create Group", e);
229        }
230        return null;
231    }
232
233    @Path("{uid}")
234    @DELETE
235    public Response deleteGroupResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
236        try {
237            um.deleteGroup(uid);
238            return Response.ok().build();
239        } catch (DirectoryException e) {
240            return Response.status(Status.NOT_FOUND).build();
241        }
242    }
243
244}