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}