1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.userdirectory.endpoint;
23
24 import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
25 import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
26 import static javax.servlet.http.HttpServletResponse.SC_CREATED;
27 import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
28 import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
29 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
30 import static javax.servlet.http.HttpServletResponse.SC_OK;
31
32 import org.opencastproject.security.api.JaxbGroupList;
33 import org.opencastproject.security.api.UnauthorizedException;
34 import org.opencastproject.userdirectory.ConflictException;
35 import org.opencastproject.userdirectory.JpaGroupRoleProvider;
36 import org.opencastproject.util.NotFoundException;
37 import org.opencastproject.util.doc.rest.RestParameter;
38 import org.opencastproject.util.doc.rest.RestParameter.Type;
39 import org.opencastproject.util.doc.rest.RestQuery;
40 import org.opencastproject.util.doc.rest.RestResponse;
41 import org.opencastproject.util.doc.rest.RestService;
42
43 import org.apache.commons.lang3.StringUtils;
44 import org.osgi.service.component.annotations.Activate;
45 import org.osgi.service.component.annotations.Component;
46 import org.osgi.service.component.annotations.Reference;
47 import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 import javax.ws.rs.DELETE;
52 import javax.ws.rs.FormParam;
53 import javax.ws.rs.GET;
54 import javax.ws.rs.POST;
55 import javax.ws.rs.PUT;
56 import javax.ws.rs.Path;
57 import javax.ws.rs.PathParam;
58 import javax.ws.rs.Produces;
59 import javax.ws.rs.QueryParam;
60 import javax.ws.rs.WebApplicationException;
61 import javax.ws.rs.core.MediaType;
62 import javax.ws.rs.core.Response;
63
64
65
66
67 @Path("/groups")
68 @RestService(
69 name = "groups",
70 title = "Internal group manager",
71 abstractText = "This service offers the ability to manage the groups for internal accounts.",
72 notes = {
73 "All paths above are relative to the REST endpoint base (something like http://your.server/files)",
74 "If the service is down or not working it will return a status 503, this means the the "
75 + "underlying service is not working and is either restarting or has failed",
76 "A status code 500 means a general failure has occurred which is not recoverable and was "
77 + "not anticipated. In other words, there is a bug! You should file an error report "
78 + "with your server logs from the time when the error occurred: "
79 + "<a href=\"https://github.com/opencast/opencast/issues\">Opencast Issue Tracker</a>"
80 }
81 )
82 @Component(
83 property = {
84 "service.description=Group Role REST EndPoint",
85 "opencast.service.type=org.opencastproject.userdirectory.endpoint.GroupRoleEndpoint",
86 "opencast.service.jobproducer=false",
87 "opencast.service.path=/groups"
88 },
89 immediate = false,
90 service = { GroupRoleEndpoint.class }
91 )
92 @JaxrsResource
93 public class GroupRoleEndpoint {
94
95
96 private static final Logger logger = LoggerFactory.getLogger(GroupRoleEndpoint.class);
97
98
99 private JpaGroupRoleProvider jpaGroupRoleProvider;
100
101
102
103
104
105 @Reference
106 public void setJpaGroupRoleProvider(JpaGroupRoleProvider jpaGroupRoleProvider) {
107 this.jpaGroupRoleProvider = jpaGroupRoleProvider;
108 }
109
110
111
112
113 @Activate
114 public void activate() {
115 logger.info("Activating {}", getClass().getName());
116 }
117
118 @GET
119 @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_JSON })
120 @Path("groups.{format:xml|json}")
121 @RestQuery(
122 name = "allgroup",
123 description = "Returns a list of groups",
124 returnDescription = "Returns a JSON or XML representation of the list of groups available "
125 + "the current user's organization",
126 pathParameters = {
127 @RestParameter(
128 name = "format",
129 description = "The output format (json or xml) of the response body.",
130 isRequired = true,
131 type = RestParameter.Type.STRING
132 )
133 },
134 restParameters = {
135 @RestParameter(
136 name = "limit",
137 defaultValue = "100",
138 description = "The maximum number of items to return per page.",
139 isRequired = false,
140 type = RestParameter.Type.STRING
141 ),
142 @RestParameter(
143 name = "offset",
144 defaultValue = "0",
145 description = "The page number.",
146 isRequired = false,
147 type = RestParameter.Type.STRING
148 )
149 },
150 responses = { @RestResponse(responseCode = SC_OK, description = "The groups.") }
151 )
152 public Response getGroupsAsJsonOrXml(
153 @PathParam("format") String format,
154 @QueryParam("limit") int limit,
155 @QueryParam("offset") int offset
156 ) {
157 try {
158 final String type = "json".equals(format) ? MediaType.APPLICATION_JSON : MediaType.APPLICATION_XML;
159 JaxbGroupList list = jpaGroupRoleProvider.getGroups(limit, offset);
160 return Response.ok().entity(list).type(type).build();
161 } catch (Exception e) {
162 logger.info("Unable to get groups", e);
163 return Response.serverError().entity(buildUnexpectedErrorMessage(e)).build();
164 }
165 }
166
167 @DELETE
168 @Path("{id}")
169 @RestQuery(
170 name = "removegroup",
171 description = "Remove a group",
172 returnDescription = "Return no content",
173 pathParameters = {
174 @RestParameter(
175 name = "id",
176 description = "The group identifier",
177 isRequired = true,
178 type = Type.STRING
179 ),
180 },
181 responses = {
182 @RestResponse(
183 responseCode = SC_OK,
184 description = "Group deleted"
185 ),
186 @RestResponse(
187 responseCode = SC_FORBIDDEN,
188 description = "Not enough permissions to remove a group with the admin role."
189 ),
190 @RestResponse(
191 responseCode = SC_NOT_FOUND,
192 description = "Group not found."
193 ),
194 @RestResponse(
195 responseCode = SC_INTERNAL_SERVER_ERROR,
196 description = "An internal server error occured."
197 ),
198 }
199 )
200 public Response removeGroup(@PathParam("id") String groupId) {
201 try {
202 jpaGroupRoleProvider.removeGroup(groupId);
203 return Response.noContent().build();
204 } catch (NotFoundException e) {
205 return Response.status(SC_NOT_FOUND).build();
206 } catch (UnauthorizedException e) {
207 return Response.status(SC_FORBIDDEN).build();
208 } catch (Exception e) {
209 throw new WebApplicationException(e);
210 }
211 }
212
213 @POST
214 @Path("")
215 @RestQuery(
216 name = "createGroup",
217 description = "Add a group",
218 returnDescription = "Return the status codes",
219 restParameters = {
220 @RestParameter(
221 name = "name",
222 description = "The group name",
223 isRequired = true,
224 type = Type.STRING
225 ),
226 @RestParameter(
227 name = "description",
228 description = "The group description",
229 isRequired = false,
230 type = Type.STRING
231 ),
232 @RestParameter(
233 name = "roles",
234 description = "A comma seperated string of additional group roles",
235 isRequired = false,
236 type = Type.TEXT
237 ),
238 @RestParameter(
239 name = "users",
240 description = "A comma seperated string of group members",
241 isRequired = false,
242 type = Type.TEXT
243 ),
244 },
245 responses = {
246 @RestResponse(
247 responseCode = SC_CREATED,
248 description = "Group created"
249 ),
250 @RestResponse(
251 responseCode = SC_BAD_REQUEST,
252 description = "Name too long"
253 ),
254 @RestResponse(
255 responseCode = SC_FORBIDDEN,
256 description = "Not enough permissions to create a group with the admin role."
257 ),
258 @RestResponse(
259 responseCode = SC_CONFLICT,
260 description = "An group with this name already exists."
261 ),
262 }
263 )
264 public Response createGroup(
265 @FormParam("name") String name,
266 @FormParam("description") String description,
267 @FormParam("roles") String roles,
268 @FormParam("users") String users
269 ) {
270 try {
271 jpaGroupRoleProvider.createGroup(name, description, roles, users);
272 } catch (IllegalArgumentException e) {
273 logger.warn("Unable to create group {}: {}", name, e.getMessage());
274 return Response.status(SC_BAD_REQUEST).build();
275 } catch (UnauthorizedException e) {
276 return Response.status(SC_FORBIDDEN).build();
277 } catch (ConflictException e) {
278 return Response.status(SC_CONFLICT).build();
279 }
280 return Response.status(SC_CREATED).build();
281 }
282
283 @PUT
284 @Path("{id}")
285 @RestQuery(
286 name = "updateGroup",
287 description = "Update a group",
288 returnDescription = "Return the status codes",
289 pathParameters = {
290 @RestParameter(name = "id", description = "The group identifier", isRequired = true, type = Type.STRING),
291 },
292 restParameters = {
293 @RestParameter(
294 name = "name",
295 description = "The group name",
296 isRequired = true,
297 type = Type.STRING
298 ),
299 @RestParameter(
300 name = "description",
301 description = "The group description",
302 isRequired = false,
303 type = Type.STRING
304 ),
305 @RestParameter(
306 name = "roles",
307 description = "A comma seperated string of additional group roles",
308 isRequired = false,
309 type = Type.TEXT
310 ),
311 @RestParameter(
312 name = "users",
313 description = "A comma seperated string of group members",
314 isRequired = true,
315 type = Type.TEXT
316 ),
317 },
318 responses = {
319 @RestResponse(
320 responseCode = SC_OK,
321 description = "Group updated"
322 ),
323 @RestResponse(
324 responseCode = SC_FORBIDDEN,
325 description = "Not enough permissions to update a group with the admin role."
326 ),
327 @RestResponse(
328 responseCode = SC_NOT_FOUND,
329 description = "Group not found"
330 ),
331 @RestResponse(
332 responseCode = SC_BAD_REQUEST,
333 description = "Name too long"
334 ),
335 }
336 )
337 public Response updateGroup(
338 @PathParam("id") String groupId,
339 @FormParam("name") String name,
340 @FormParam("description") String description,
341 @FormParam("roles") String roles,
342 @FormParam("users") String users
343 ) throws NotFoundException {
344 try {
345 jpaGroupRoleProvider.updateGroup(groupId, name, description, roles, users);
346 } catch (IllegalArgumentException e) {
347 logger.warn("Unable to update group id {}: {}", groupId, e.getMessage());
348 return Response.status(SC_BAD_REQUEST).build();
349 } catch (UnauthorizedException ex) {
350 return Response.status(SC_FORBIDDEN).build();
351 }
352 return Response.ok().build();
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367 private String buildUnexpectedErrorMessage(Exception e) {
368 StringBuilder sb = new StringBuilder();
369 sb.append("Unexpected error (").append(e.getClass().getName()).append(")");
370 String message = e.getMessage();
371 if (StringUtils.isNotBlank(message)) {
372 sb.append(": ").append(message);
373 }
374 return sb.toString();
375 }
376 }