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.DocumentModel;
045import org.nuxeo.ecm.core.api.DocumentModelList;
046import org.nuxeo.ecm.directory.DirectoryException;
047import org.nuxeo.ecm.directory.Session;
048import org.nuxeo.ecm.directory.api.DirectoryService;
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.getService(DirectoryService.class);
136
137            DocumentModelList groupModels = null;
138            try (Session dSession = ds.open(directoryName)) {
139                groupModels = dSession.query(filter, null, orderBy, true, count, startIndex - 1);
140            }
141
142            List<GroupResource> groupResources = new ArrayList<>();
143            for (DocumentModel groupModel : groupModels) {
144                groupResources.add(mapper.getGroupResourceFromNuxeoGroup(groupModel));
145            }
146            return new Resources<>(groupResources, groupResources.size(), startIndex);
147        } catch (Exception e) {
148            log.error("Error while getting Groups", e);
149        }
150        return null;
151    }
152
153    @Path("{uid}")
154    @GET
155    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
156    public GroupResource getGroupResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
157        return resolveGroupRessource(uid);
158
159    }
160
161    @Path("{uid}.xml")
162    @GET
163    @Produces(MediaType.APPLICATION_XML)
164    public GroupResource getGroupResourceAsXml(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
165        return getGroupResource(uriInfo, uid);
166    }
167
168    @Path("{uid}.json")
169    @GET
170    @Produces(MediaType.APPLICATION_JSON)
171    public GroupResource getUserResourceAsJSON(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
172        return getGroupResource(uriInfo, uid);
173    }
174
175    @POST
176    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
177    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
178    public Response createGroup(@Context UriInfo uriInfo, GroupResource group,
179            @Context final HttpServletResponse response) {
180        checkUpdateGuardPreconditions();
181        return doCreateGroup(group, fixeMediaType);
182    }
183
184    @PUT
185    @Path("{uid}")
186    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
187    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
188    public Response updateGroup(@Context UriInfo uriInfo, @PathParam("uid") String uid, GroupResource user) {
189        checkUpdateGuardPreconditions();
190        return doUpdateGroup(uid, user, fixeMediaType);
191    }
192
193    protected Response doUpdateGroup(String uid, GroupResource group, MediaType mt) {
194
195        try {
196            DocumentModel groupModel = mapper.updateGroupModelFromGroupResource(uid, group);
197            if (groupModel != null) {
198                GroupResource groupResource = mapper.getGroupResourceFromNuxeoGroup(groupModel);
199                return GroupResponse.updated(groupResource, mt);
200            }
201        } catch (Exception e) {
202            log.error("Unable to update Group", e);
203        }
204        return null;
205    }
206
207    protected Response doCreateGroup(GroupResource group, MediaType mt) {
208
209        try {
210            DocumentModel newGroup = mapper.createGroupModelFromGroupResource(group);
211            GroupResource groupResource = mapper.getGroupResourceFromNuxeoGroup(newGroup);
212            return GroupResponse.created(groupResource, mt);
213        } catch (Exception e) {
214            log.error("Unable to create Group", e);
215        }
216        return null;
217    }
218
219    @Path("{uid}")
220    @DELETE
221    public Response deleteGroupResource(@Context UriInfo uriInfo, @PathParam("uid") String uid) {
222        try {
223            um.deleteGroup(uid);
224            return Response.ok().build();
225        } catch (DirectoryException e) {
226            return Response.status(Status.NOT_FOUND).build();
227        }
228    }
229
230}