2 * Copyright (c) 2014, 2015 Hewlett-Packard Development Company, L.P. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.aaa.idm.rest;
11 import java.util.ArrayList;
12 import java.util.List;
13 import javax.ws.rs.Consumes;
14 import javax.ws.rs.DELETE;
15 import javax.ws.rs.GET;
16 import javax.ws.rs.POST;
17 import javax.ws.rs.PUT;
18 import javax.ws.rs.Path;
19 import javax.ws.rs.PathParam;
20 import javax.ws.rs.Produces;
21 import javax.ws.rs.core.Context;
22 import javax.ws.rs.core.Response;
23 import javax.ws.rs.core.UriInfo;
24 import org.opendaylight.aaa.api.IDMStoreException;
25 import org.opendaylight.aaa.api.model.Claim;
26 import org.opendaylight.aaa.api.model.Domain;
27 import org.opendaylight.aaa.api.model.Domains;
28 import org.opendaylight.aaa.api.model.Grant;
29 import org.opendaylight.aaa.api.model.Grants;
30 import org.opendaylight.aaa.api.model.IDMError;
31 import org.opendaylight.aaa.api.model.Role;
32 import org.opendaylight.aaa.api.model.Roles;
33 import org.opendaylight.aaa.api.model.User;
34 import org.opendaylight.aaa.api.model.UserPwd;
35 import org.opendaylight.aaa.api.model.Users;
36 import org.opendaylight.aaa.idm.IdmLightProxy;
37 import org.opendaylight.yang.gen.v1.config.aaa.authn.idmlight.rev151204.AAAIDMLightModule;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * REST application used to manipulate the H2 database domains table. The REST
43 * endpoint is <code>/auth/v1/domains</code>.
45 * The following provides examples of curl commands and payloads to utilize the
46 * domains REST endpoint:
48 * <b>Get All Domains</b>
49 * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/domains</code>
51 * <b>Get A Specific Domain</b>
52 * <code>curl -u admin:admin http://{HOST}:{PORT}/auth/v1/domains/{id}</code>
54 * <b>Create A Domain</b>
55 * <code>curl -u admin:admin -X POST -H "Content-Type: application/json" --data-binary {@literal @}domain.json http://{HOST}:{PORT}/auth/v1/domains</code>
56 * Example domain.json <code>{
57 * "description": "new domain",
62 * <b>Update A Domain</b>
63 * <code>curl -u admin:admin -X PUT -H "Content-Type: application/json" --data-binary {@literal @}domain.json http://{HOST}:{PORT}/auth/v1/domains</code>
64 * Example domain.json <code>{
65 * "description": "new domain description",
70 * @author peter.mellquist@hp.com
71 * @author Ryan Goulding (ryandgoulding@gmail.com)
74 public class DomainHandler {
76 private static final Logger LOG = LoggerFactory.getLogger(DomainHandler.class);
79 * Extracts all domains.
81 * @return a response with all domains stored in the H2 database
84 @Produces("application/json")
85 public Response getDomains() {
86 LOG.info("Get /domains");
87 Domains domains = null;
89 domains = AAAIDMLightModule.getStore().getDomains();
90 } catch (IDMStoreException se) {
91 LOG.error("StoreException: ", se);
92 IDMError idmerror = new IDMError();
93 idmerror.setMessage("Internal error getting domains");
94 idmerror.setDetails(se.getMessage());
95 return Response.status(500).entity(idmerror).build();
97 return Response.ok(domains).build();
101 * Extracts the domain represented by <code>domainId</code>.
103 * @param domainId the string domain (i.e., "sdn")
104 * @return a response with the specified domain
108 @Produces("application/json")
109 public Response getDomain(@PathParam("id") String domainId) {
110 LOG.info("Get /domains/{}", domainId);
111 Domain domain = null;
113 domain = AAAIDMLightModule.getStore().readDomain(domainId);
114 } catch (IDMStoreException se) {
115 LOG.error("StoreException: ", se);
116 IDMError idmerror = new IDMError();
117 idmerror.setMessage("Internal error getting domain");
118 idmerror.setDetails(se.getMessage());
119 return Response.status(500).entity(idmerror).build();
122 if (domain == null) {
123 IDMError idmerror = new IDMError();
124 idmerror.setMessage("Not found! domain id :" + domainId);
125 return Response.status(404).entity(idmerror).build();
127 return Response.ok(domain).build();
131 * Creates a domain. The name attribute is required for domain creation.
132 * Enabled and description fields are optional. Optional fields default
133 * in the following manner:
134 * <code>enabled</code>: <code>false</code>
135 * <code>description</code>: An empty string (<code>""</code>).
137 * @param info passed from Jersey
138 * @param domain designated by the REST payload
139 * @return A response stating success or failure of domain creation.
142 @Consumes("application/json")
143 @Produces("application/json")
144 public Response createDomain(@Context UriInfo info, Domain domain) {
145 LOG.info("Post /domains");
147 if (domain.isEnabled() == null) {
148 domain.setEnabled(false);
150 if (domain.getName() == null) {
153 if (domain.getDescription() == null) {
154 domain.setDescription("");
156 domain = AAAIDMLightModule.getStore().writeDomain(domain);
157 } catch (IDMStoreException se) {
158 LOG.error("StoreException: ", se);
159 IDMError idmerror = new IDMError();
160 idmerror.setMessage("Internal error creating domain");
161 idmerror.setDetails(se.getMessage());
162 return Response.status(500).entity(idmerror).build();
164 return Response.status(201).entity(domain).build();
170 * @param info passed from Jersey
171 * @param domain the REST payload
172 * @param domainId the last part of the path, containing the specified domain id
173 * @return A response stating success or failure of domain update.
177 @Consumes("application/json")
178 @Produces("application/json")
179 public Response putDomain(@Context UriInfo info, Domain domain, @PathParam("id") String domainId) {
180 LOG.info("Put /domains/{}", domainId);
182 domain.setDomainid(domainId);
183 domain = AAAIDMLightModule.getStore().updateDomain(domain);
184 if (domain == null) {
185 IDMError idmerror = new IDMError();
186 idmerror.setMessage("Not found! Domain id :" + domainId);
187 return Response.status(404).entity(idmerror).build();
189 IdmLightProxy.clearClaimCache();
190 return Response.status(200).entity(domain).build();
191 } catch (IDMStoreException se) {
192 LOG.error("StoreException: ", se);
193 IDMError idmerror = new IDMError();
194 idmerror.setMessage("Internal error putting domain");
195 idmerror.setDetails(se.getMessage());
196 return Response.status(500).entity(idmerror).build();
203 * @param info passed from Jersey
204 * @param domainId the last part of the path, containing the specified domain id
205 * @return A response stating success or failure of domain deletion.
209 public Response deleteDomain(@Context UriInfo info, @PathParam("id") String domainId) {
210 LOG.info("Delete /domains/{}", domainId);
213 Domain domain = AAAIDMLightModule.getStore().deleteDomain(domainId);
214 if (domain == null) {
215 IDMError idmerror = new IDMError();
216 idmerror.setMessage("Not found! Domain id :" + domainId);
217 return Response.status(404).entity(idmerror).build();
219 } catch (IDMStoreException se) {
220 LOG.error("StoreException: ", se);
221 IDMError idmerror = new IDMError();
222 idmerror.setMessage("Internal error deleting Domain");
223 idmerror.setDetails(se.getMessage());
224 return Response.status(500).entity(idmerror).build();
226 IdmLightProxy.clearClaimCache();
227 return Response.status(204).build();
231 * Creates a grant. A grant defines the role a particular user is given on
232 * a particular domain. For example, by default, AAA installs a grant for
233 * the "admin" user, granting permission to act with "admin" role on the
236 * @param info passed from Jersey
237 * @param domainId the domain the user is allowed to access
238 * @param userId the user that is allowed to access the domain
239 * @param grant the payload containing role access controls
240 * @return A response stating success or failure of grant creation.
243 @Path("/{did}/users/{uid}/roles")
244 @Consumes("application/json")
245 @Produces("application/json")
246 public Response createGrant(@Context UriInfo info, @PathParam("did") String domainId,
247 @PathParam("uid") String userId, Grant grant) {
248 LOG.info("Post /domains/{}/users/{}/roles", domainId, userId);
249 Domain domain = null;
252 String roleId = null;
254 // validate domain id
256 domain = AAAIDMLightModule.getStore().readDomain(domainId);
257 } catch (IDMStoreException se) {
258 LOG.error("StoreException: ", se);
259 IDMError idmerror = new IDMError();
260 idmerror.setMessage("Internal error getting domain");
261 idmerror.setDetails(se.getMessage());
262 return Response.status(500).entity(idmerror).build();
264 if (domain == null) {
265 IDMError idmerror = new IDMError();
266 idmerror.setMessage("Not found! domain id :" + domainId);
267 return Response.status(404).entity(idmerror).build();
269 grant.setDomainid(domainId);
272 user = AAAIDMLightModule.getStore().readUser(userId);
273 } catch (IDMStoreException se) {
274 LOG.error("StoreException: ", se);
275 IDMError idmerror = new IDMError();
276 idmerror.setMessage("Internal error getting user");
277 idmerror.setDetails(se.getMessage());
278 return Response.status(500).entity(idmerror).build();
281 IDMError idmerror = new IDMError();
282 idmerror.setMessage("Not found! User id :" + userId);
283 return Response.status(404).entity(idmerror).build();
285 grant.setUserid(userId);
289 roleId = grant.getRoleid();
290 LOG.info("roleid = {}", roleId);
291 } catch (NumberFormatException nfe) {
292 IDMError idmerror = new IDMError();
293 idmerror.setMessage("Invalid Role id :" + grant.getRoleid());
294 return Response.status(404).entity(idmerror).build();
297 role = AAAIDMLightModule.getStore().readRole(roleId);
298 } catch (IDMStoreException se) {
299 LOG.error("StoreException: ", se);
300 IDMError idmerror = new IDMError();
301 idmerror.setMessage("Internal error getting role");
302 idmerror.setDetails(se.getMessage());
303 return Response.status(500).entity(idmerror).build();
306 IDMError idmerror = new IDMError();
307 idmerror.setMessage("Not found! role :" + grant.getRoleid());
308 return Response.status(404).entity(idmerror).build();
311 // see if grant already exists for this
313 Grant existingGrant = AAAIDMLightModule.getStore().readGrant(domainId, userId, roleId);
314 if (existingGrant != null) {
315 IDMError idmerror = new IDMError();
316 idmerror.setMessage("Grant already exists for did:" + domainId + " uid:" + userId
318 return Response.status(403).entity(idmerror).build();
320 } catch (IDMStoreException se) {
321 LOG.error("StoreException: ", se);
322 IDMError idmerror = new IDMError();
323 idmerror.setMessage("Internal error creating grant");
324 idmerror.setDetails(se.getMessage());
325 return Response.status(500).entity(idmerror).build();
330 grant = AAAIDMLightModule.getStore().writeGrant(grant);
331 } catch (IDMStoreException se) {
332 LOG.error("StoreException: ", se);
333 IDMError idmerror = new IDMError();
334 idmerror.setMessage("Internal error creating grant");
335 idmerror.setDetails(se.getMessage());
336 return Response.status(500).entity(idmerror).build();
339 IdmLightProxy.clearClaimCache();
340 return Response.status(201).entity(grant).build();
344 * Used to validate user access.
346 * @param info passed from Jersey
347 * @param domainId the domain in question
348 * @param userpwd the password attempt
349 * @return A response stating success or failure of user validation.
352 @Path("/{did}/users/roles")
353 @Consumes("application/json")
354 @Produces("application/json")
355 public Response validateUser(@Context UriInfo info, @PathParam("did") String domainId,
358 LOG.info("GET /domains/{}/users", domainId);
359 Domain domain = null;
360 Claim claim = new Claim();
361 List<Role> roleList = new ArrayList<Role>();
364 domain = AAAIDMLightModule.getStore().readDomain(domainId);
365 } catch (IDMStoreException se) {
366 LOG.error("StoreException: ", se);
367 IDMError idmerror = new IDMError();
368 idmerror.setMessage("Internal error getting domain");
369 idmerror.setDetails(se.getMessage());
370 return Response.status(500).entity(idmerror).build();
372 if (domain == null) {
373 IDMError idmerror = new IDMError();
374 idmerror.setMessage("Not found! Domain id :" + domainId);
375 return Response.status(404).entity(idmerror).build();
378 // check request body for username and pwd
379 String username = userpwd.getUsername();
380 if (username == null) {
381 IDMError idmerror = new IDMError();
382 idmerror.setMessage("username not specfied in request body");
383 return Response.status(400).entity(idmerror).build();
385 String pwd = userpwd.getUserpwd();
387 IDMError idmerror = new IDMError();
388 idmerror.setMessage("userpwd not specfied in request body");
389 return Response.status(400).entity(idmerror).build();
392 // find userid for user
394 Users users = AAAIDMLightModule.getStore().getUsers(username, domainId);
395 List<User> userList = users.getUsers();
396 if (userList.size() == 0) {
397 IDMError idmerror = new IDMError();
398 idmerror.setMessage("did not find username: " + username);
399 return Response.status(404).entity(idmerror).build();
401 User user = userList.get(0);
402 String userPwd = user.getPassword();
403 String reqPwd = userpwd.getUserpwd();
404 if (!userPwd.equals(reqPwd)) {
405 IDMError idmerror = new IDMError();
406 idmerror.setMessage("password does not match for username: " + username);
407 return Response.status(401).entity(idmerror).build();
409 claim.setDomainid(domainId);
410 claim.setUsername(username);
411 claim.setUserid(user.getUserid());
413 Grants grants = AAAIDMLightModule.getStore().getGrants(domainId, user.getUserid());
414 List<Grant> grantsList = grants.getGrants();
415 for (int i = 0; i < grantsList.size(); i++) {
416 Grant grant = grantsList.get(i);
417 Role role = AAAIDMLightModule.getStore().readRole(grant.getRoleid());
420 } catch (IDMStoreException se) {
421 LOG.error("StoreException: ", se);
422 IDMError idmerror = new IDMError();
423 idmerror.setMessage("Internal error getting Roles");
424 idmerror.setDetails(se.getMessage());
425 return Response.status(500).entity(idmerror).build();
427 claim.setRoles(roleList);
428 } catch (IDMStoreException se) {
429 LOG.error("StoreException: ", se);
430 IDMError idmerror = new IDMError();
431 idmerror.setMessage("Internal error getting user");
432 idmerror.setDetails(se.getMessage());
433 return Response.status(500).entity(idmerror).build();
436 return Response.ok(claim).build();
440 * Get the grants for a user on a domain.
442 * @param info passed from Jersey
443 * @param domainId the domain in question
444 * @param userId the user in question
445 * @return A response containing the grants for a user on a domain.
448 @Path("/{did}/users/{uid}/roles")
449 @Produces("application/json")
450 public Response getRoles(@Context UriInfo info, @PathParam("did") String domainId,
451 @PathParam("uid") String userId) {
452 LOG.info("GET /domains/{}/users/{}/roles", domainId, userId);
453 Domain domain = null;
455 Roles roles = new Roles();
456 List<Role> roleList = new ArrayList<Role>();
459 domain = AAAIDMLightModule.getStore().readDomain(domainId);
460 } catch (IDMStoreException se) {
461 LOG.error("StoreException: ", se);
462 IDMError idmerror = new IDMError();
463 idmerror.setMessage("Internal error getting domain");
464 idmerror.setDetails(se.getMessage());
465 return Response.status(500).entity(idmerror).build();
467 if (domain == null) {
468 IDMError idmerror = new IDMError();
469 idmerror.setMessage("Not found! Domain id :" + domainId);
470 return Response.status(404).entity(idmerror).build();
474 user = AAAIDMLightModule.getStore().readUser(userId);
475 } catch (IDMStoreException se) {
476 LOG.error("StoreException: ", se);
477 IDMError idmerror = new IDMError();
478 idmerror.setMessage("Internal error getting user");
479 idmerror.setDetails(se.getMessage());
480 return Response.status(500).entity(idmerror).build();
483 IDMError idmerror = new IDMError();
484 idmerror.setMessage("Not found! User id :" + userId);
485 return Response.status(404).entity(idmerror).build();
489 Grants grants = AAAIDMLightModule.getStore().getGrants(domainId, userId);
490 List<Grant> grantsList = grants.getGrants();
491 for (int i = 0; i < grantsList.size(); i++) {
492 Grant grant = grantsList.get(i);
493 Role role = AAAIDMLightModule.getStore().readRole(grant.getRoleid());
496 } catch (IDMStoreException se) {
497 LOG.error("StoreException: ", se);
498 IDMError idmerror = new IDMError();
499 idmerror.setMessage("Internal error getting Roles");
500 idmerror.setDetails(se.getMessage());
501 return Response.status(500).entity(idmerror).build();
504 roles.setRoles(roleList);
505 return Response.ok(roles).build();
511 * @param info passed from Jersey
512 * @param domainId the domain for the grant
513 * @param userId the user for the grant
514 * @param roleId the role for the grant
515 * @return A response stating success or failure of the grant deletion.
518 @Path("/{did}/users/{uid}/roles/{rid}")
519 public Response deleteGrant(@Context UriInfo info, @PathParam("did") String domainId,
520 @PathParam("uid") String userId, @PathParam("rid") String roleId) {
521 Domain domain = null;
526 domain = AAAIDMLightModule.getStore().readDomain(domainId);
527 } catch (IDMStoreException se) {
528 LOG.error("Error deleting Grant : ", se);
529 IDMError idmerror = new IDMError();
530 idmerror.setMessage("Internal error getting domain");
531 idmerror.setDetails(se.getMessage());
532 return Response.status(500).entity(idmerror).build();
534 if (domain == null) {
535 IDMError idmerror = new IDMError();
536 idmerror.setMessage("Not found! Domain id :" + domainId);
537 return Response.status(404).entity(idmerror).build();
541 user = AAAIDMLightModule.getStore().readUser(userId);
542 } catch (IDMStoreException se) {
543 LOG.error("StoreException : ", se);
544 IDMError idmerror = new IDMError();
545 idmerror.setMessage("Internal error getting user");
546 idmerror.setDetails(se.getMessage());
547 return Response.status(500).entity(idmerror).build();
550 IDMError idmerror = new IDMError();
551 idmerror.setMessage("Not found! User id :" + userId);
552 return Response.status(404).entity(idmerror).build();
556 role = AAAIDMLightModule.getStore().readRole(roleId);
557 } catch (IDMStoreException se) {
558 LOG.error("StoreException: ", se);
559 IDMError idmerror = new IDMError();
560 idmerror.setMessage("Internal error getting Role");
561 idmerror.setDetails(se.getMessage());
562 return Response.status(500).entity(idmerror).build();
565 IDMError idmerror = new IDMError();
566 idmerror.setMessage("Not found! Role id :" + roleId);
567 return Response.status(404).entity(idmerror).build();
570 // see if grant already exists
572 Grant existingGrant = AAAIDMLightModule.getStore().readGrant(domainId, userId, roleId);
573 if (existingGrant == null) {
574 IDMError idmerror = new IDMError();
575 idmerror.setMessage("Grant does not exist for did:" + domainId + " uid:" + userId
577 return Response.status(404).entity(idmerror).build();
579 existingGrant = AAAIDMLightModule.getStore().deleteGrant(existingGrant.getGrantid());
580 } catch (IDMStoreException se) {
581 LOG.error("StoreException: ", se);
582 IDMError idmerror = new IDMError();
583 idmerror.setMessage("Internal error creating grant");
584 idmerror.setDetails(se.getMessage());
585 return Response.status(500).entity(idmerror).build();
587 IdmLightProxy.clearClaimCache();
588 return Response.status(204).build();