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}