2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.auth.service;
24 import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.force;
25 import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.future;
26 import static org.onap.aaf.auth.layer.Result.OK;
27 import static org.onap.aaf.auth.rserv.HttpMethods.DELETE;
28 import static org.onap.aaf.auth.rserv.HttpMethods.GET;
29 import static org.onap.aaf.auth.rserv.HttpMethods.POST;
30 import static org.onap.aaf.auth.rserv.HttpMethods.PUT;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.Date;
37 import java.util.GregorianCalendar;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
43 import java.util.TreeMap;
44 import java.util.UUID;
46 import javax.servlet.http.HttpServletRequest;
48 import org.onap.aaf.auth.common.Define;
49 import org.onap.aaf.auth.dao.DAOException;
50 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
51 import org.onap.aaf.auth.dao.cass.CertDAO;
52 import org.onap.aaf.auth.dao.cass.CredDAO;
53 import org.onap.aaf.auth.dao.cass.DelegateDAO;
54 import org.onap.aaf.auth.dao.cass.FutureDAO;
55 import org.onap.aaf.auth.dao.cass.HistoryDAO;
56 import org.onap.aaf.auth.dao.cass.Namespace;
57 import org.onap.aaf.auth.dao.cass.NsDAO;
58 import org.onap.aaf.auth.dao.cass.NsDAO.Data;
59 import org.onap.aaf.auth.dao.cass.NsSplit;
60 import org.onap.aaf.auth.dao.cass.NsType;
61 import org.onap.aaf.auth.dao.cass.PermDAO;
62 import org.onap.aaf.auth.dao.cass.RoleDAO;
63 import org.onap.aaf.auth.dao.cass.Status;
64 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
65 import org.onap.aaf.auth.dao.hl.CassExecutor;
66 import org.onap.aaf.auth.dao.hl.Function;
67 import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP;
68 import org.onap.aaf.auth.dao.hl.Function.Lookup;
69 import org.onap.aaf.auth.dao.hl.Function.OP_STATUS;
70 import org.onap.aaf.auth.dao.hl.Question;
71 import org.onap.aaf.auth.dao.hl.Question.Access;
72 import org.onap.aaf.auth.env.AuthzTrans;
73 import org.onap.aaf.auth.layer.Result;
74 import org.onap.aaf.auth.org.Executor;
75 import org.onap.aaf.auth.org.Organization;
76 import org.onap.aaf.auth.org.Organization.Expiration;
77 import org.onap.aaf.auth.org.Organization.Identity;
78 import org.onap.aaf.auth.org.Organization.Policy;
79 import org.onap.aaf.auth.org.OrganizationException;
80 import org.onap.aaf.auth.rserv.doc.ApiDoc;
81 import org.onap.aaf.auth.service.mapper.Mapper;
82 import org.onap.aaf.auth.service.mapper.Mapper.API;
83 import org.onap.aaf.auth.service.validation.ServiceValidator;
84 import org.onap.aaf.auth.validation.Validator;
85 import org.onap.aaf.cadi.principal.BasicPrincipal;
86 import org.onap.aaf.misc.env.Env;
87 import org.onap.aaf.misc.env.TimeTaken;
88 import org.onap.aaf.misc.env.util.Chrono;
89 import org.onap.aaf.misc.env.util.Split;
91 import aaf.v2_0.CredRequest;
94 * AuthzCassServiceImpl implements AuthzCassService for
109 public class AuthzCassServiceImpl <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS>
110 implements AuthzService <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> {
112 private Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper;
114 public Mapper <NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper() {return mapper;}
116 private static final String ASTERIX = "*";
117 private static final String CACHE = "cache";
118 private static final String ROOT_NS = Define.ROOT_NS();
119 private static final String ROOT_COMPANY = Define.ROOT_COMPANY();
121 private final Question ques;
122 private final Function func;
124 public AuthzCassServiceImpl(AuthzTrans trans, Mapper<NSS,PERMS,PERMKEY,ROLES,USERS,USERROLES,DELGS,CERTS,KEYS,REQUEST,HISTORY,ERR,APPROVALS> mapper,Question question) {
125 this.ques = question;
126 func = new Function(trans, question);
127 this.mapper = mapper;
131 /***********************************
133 ***********************************/
136 * @throws DAOException
137 * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
144 errorCodes = { 403,404,406,409 },
145 text = { "Namespace consists of: ",
146 "<ul><li>name - What you want to call this Namespace</li>",
147 "<li>responsible(s) - Person(s) who receive Notifications and approves Requests ",
148 "regarding this Namespace. Companies have Policies as to who may take on ",
149 "this Responsibility. Separate multiple identities with commas</li>",
150 "<li>admin(s) - Person(s) who are allowed to make changes on the namespace, ",
151 "including creating Roles, Permissions and Credentials. Separate multiple ",
152 "identities with commas</li></ul>",
153 "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ",
154 "created with parent credentials (i.e. To create com.myCompany.myApp, you must ",
155 "be an admin of com.myCompany or com"
159 public Result<Void> createNS(final AuthzTrans trans, REQUEST from, NsType type) {
160 final Result<Namespace> rnamespace = mapper.ns(trans, from);
161 final ServiceValidator v = new ServiceValidator();
162 if (v.ns(rnamespace).err()) {
163 return Result.err(Status.ERR_BadData,v.errs());
165 final Namespace namespace = rnamespace.value;
166 final Result<NsDAO.Data> parentNs = ques.deriveNs(trans,namespace.name);
167 if (parentNs.notOK()) {
168 return Result.err(parentNs);
171 if (namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed
172 return func.createNS(trans, namespace, false);
175 Result<FutureDAO.Data> fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true,
178 public String get() {
179 return "Create Namespace [" + namespace.name + ']';
183 private Result<NsDAO.Data> rnd;
185 public Result<?> mayChange() {
187 rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write);
194 Result<String> rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C);
196 return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name);
198 return Result.err(rfc);
201 return func.createNS(trans, namespace, false);
203 return Result.err(fd);
209 path = "/authz/ns/:ns/admin/:id",
210 params = { "ns|string|true",
214 errorCodes = { 403,404,406,409 },
215 text = { "Add an Identity :id to the list of Admins for the Namespace :ns",
216 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
219 public Result<Void> addAdminNS(AuthzTrans trans, String ns, String id) {
220 return func.addUserRole(trans, id, ns,Question.ADMIN);
225 path = "/authz/ns/:ns/admin/:id",
226 params = { "ns|string|true",
230 errorCodes = { 403,404 },
231 text = { "Remove an Identity :id from the list of Admins for the Namespace :ns",
232 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
235 public Result<Void> delAdminNS(AuthzTrans trans, String ns, String id) {
236 return func.delAdmin(trans,ns,id);
241 path = "/authz/ns/:ns/responsible/:id",
242 params = { "ns|string|true",
246 errorCodes = { 403,404,406,409 },
247 text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns",
248 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)" }
251 public Result<Void> addResponsibleNS(AuthzTrans trans, String ns, String id) {
252 return func.addUserRole(trans,id,ns,Question.OWNER);
257 path = "/authz/ns/:ns/responsible/:id",
258 params = { "ns|string|true",
262 errorCodes = { 403,404 },
263 text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns",
264 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)",
265 "Note: A namespace must have at least 1 responsible party"
269 public Result<Void> delResponsibleNS(AuthzTrans trans, String ns, String id) {
270 return func.delOwner(trans,ns,id);
274 * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
278 path = "/authz/ns/:ns/attrib/:key/:value",
279 params = { "ns|string|true",
281 "value|string|true"},
283 errorCodes = { 403,404,406,409 },
285 "Create an attribute in the Namespace",
286 "You must be given direct permission for key by AAF"
290 public Result<Void> createNsAttrib(AuthzTrans trans, String ns, String key, String value) {
291 TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
294 final Validator v = new ServiceValidator();
295 if (v.ns(ns).err() ||
297 v.value(value).err()) {
298 return Result.err(Status.ERR_BadData,v.errs());
301 // Check if exists already
302 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
303 if (rlnsd.notOKorIsEmpty()) {
304 return Result.err(rlnsd);
306 NsDAO.Data nsd = rlnsd.value.get(0);
308 // Check for Existence
309 if (nsd.attrib.get(key)!=null) {
310 return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key);
313 // Check if User may put
314 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
315 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
316 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
320 nsd.attrib.put(key, value);
321 ques.nsDAO.dao().attribAdd(trans,ns,key,value);
330 path = "/authz/ns/attrib/:key",
331 params = { "key|string|true" },
333 errorCodes = { 403,404 },
335 "Read Attributes for Namespace"
339 public Result<KEYS> readNsByAttrib(AuthzTrans trans, String key) {
341 final Validator v = new ServiceValidator();
342 if (v.nullOrBlank("Key",key).err()) {
343 return Result.err(Status.ERR_BadData,v.errs());
347 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
348 ":"+trans.org().getDomain()+".*:"+key, Question.READ)) {
349 return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key);
352 Result<Set<String>> rsd = ques.nsDAO.dao().readNsByAttrib(trans, key);
354 return Result.err(rsd);
356 return mapper().keys(rsd.value);
362 path = "/authz/ns/:ns/attrib/:key/:value",
363 params = { "ns|string|true",
366 errorCodes = { 403,404 },
368 "Update Value on an existing attribute in the Namespace",
369 "You must be given direct permission for key by AAF"
373 public Result<?> updateNsAttrib(AuthzTrans trans, String ns, String key, String value) {
374 TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB);
377 final Validator v = new ServiceValidator();
378 if (v.ns(ns).err() ||
380 v.value(value).err()) {
381 return Result.err(Status.ERR_BadData,v.errs());
384 // Check if exists already (NS must exist)
385 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
386 if (rlnsd.notOKorIsEmpty()) {
387 return Result.err(rlnsd);
389 NsDAO.Data nsd = rlnsd.value.get(0);
391 // Check for Existence
392 if (nsd.attrib.get(key)==null) {
393 return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key);
396 // Check if User may put
397 if (!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB,
398 ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) {
399 return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key);
403 nsd.attrib.put(key, value);
405 return ques.nsDAO.update(trans,nsd);
414 path = "/authz/ns/:ns/attrib/:key",
415 params = { "ns|string|true",
418 errorCodes = { 403,404 },
420 "Delete an attribute in the Namespace",
421 "You must be given direct permission for key by AAF"
425 public Result<Void> deleteNsAttrib(AuthzTrans trans, String ns, String key) {
426 TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB);
429 final Validator v = new ServiceValidator();
430 if (v.nullOrBlank("NS",ns).err() ||
431 v.nullOrBlank("Key",key).err()) {
432 return Result.err(Status.ERR_BadData,v.errs());
435 // Check if exists already
436 Result<List<Data>> rlnsd = ques.nsDAO.read(trans, ns);
437 if (rlnsd.notOKorIsEmpty()) {
438 return Result.err(rlnsd);
440 NsDAO.Data nsd = rlnsd.value.get(0);
442 // Check for Existence
443 if (nsd.attrib.get(key)==null) {
444 return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key);
447 // Check if User may del
448 if (!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) {
449 return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key);
453 nsd.attrib.remove(key);
454 ques.nsDAO.dao().attribRemove(trans,ns,key);
463 path = "/authz/nss/:id",
464 params = { "id|string|true" },
466 errorCodes = { 404,406 },
468 "Lists the Admin(s), Responsible Party(s), Role(s), Permission(s)",
469 "Credential(s) and Expiration of Credential(s) in Namespace :id",
473 public Result<NSS> getNSbyName(AuthzTrans trans, String ns) {
474 final Validator v = new ServiceValidator();
475 if (v.nullOrBlank("NS", ns).err()) {
476 return Result.err(Status.ERR_BadData,v.errs());
479 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, ns);
481 if (rlnd.isEmpty()) {
482 return Result.err(Status.ERR_NotFound, "No data found for %s",ns);
484 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read);
486 return Result.err(rnd);
490 Namespace namespace = new Namespace(rnd.value);
491 Result<List<String>> rd = func.getOwners(trans, namespace.name, false);
493 namespace.owner = rd.value;
495 rd = func.getAdmins(trans, namespace.name, false);
497 namespace.admin = rd.value;
500 NSS nss = mapper.newInstance(API.NSS);
501 return mapper.nss(trans, namespace, nss);
503 return Result.err(rlnd);
509 path = "/authz/nss/admin/:id",
510 params = { "id|string|true" },
512 errorCodes = { 403,404 },
513 text = { "Lists all Namespaces where Identity :id is an Admin",
514 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
518 public Result<NSS> getNSbyAdmin(AuthzTrans trans, String user, boolean full) {
519 final Validator v = new ServiceValidator();
520 if (v.nullOrBlank("User", user).err()) {
521 return Result.err(Status.ERR_BadData, v.errs());
524 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".admin", full);
526 return Result.err(rn);
529 return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user);
531 NSS nss = mapper.newInstance(API.NSS);
532 // Note: "loadNamespace" already validates view of Namespace
533 return mapper.nss(trans, rn.value, nss);
538 path = "/authz/nss/either/:id",
539 params = { "id|string|true" },
541 errorCodes = { 403,404 },
542 text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner",
543 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
547 public Result<NSS> getNSbyEither(AuthzTrans trans, String user, boolean full) {
548 final Validator v = new ServiceValidator();
549 if (v.nullOrBlank("User", user).err()) {
550 return Result.err(Status.ERR_BadData, v.errs());
553 Result<Collection<Namespace>> rn = loadNamepace(trans, user, null, full);
555 return Result.err(rn);
558 return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user);
560 NSS nss = mapper.newInstance(API.NSS);
561 // Note: "loadNamespace" already validates view of Namespace
562 return mapper.nss(trans, rn.value, nss);
565 private Result<Collection<Namespace>> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) {
566 Result<List<UserRoleDAO.Data>> urd = ques.userRoleDAO.readByUser(trans, user);
567 if (urd.notOKorIsEmpty()) {
568 return Result.err(urd);
570 Map<String, Namespace> lm = new HashMap<>();
571 Map<String, Namespace> other = full || endsWith==null?null:new TreeMap<>();
572 for (UserRoleDAO.Data urdd : urd.value) {
574 if (endsWith==null || urdd.role.endsWith(endsWith)) {
575 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
576 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
578 Namespace namespace = lm.get(nsd.value.name);
579 if (namespace==null) {
580 namespace = new Namespace(nsd.value);
581 lm.put(namespace.name,namespace);
583 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
585 namespace.admin=rls.value;
588 rls = func.getOwners(trans, namespace.name, false);
590 namespace.owner=rls.value;
594 } else { // Shortened version. Only Namespace Info available from Role.
595 if (Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) {
596 RoleDAO.Data rd = RoleDAO.Data.decode(urdd);
597 Result<NsDAO.Data> nsd = ques.mayUser(trans, user, rd, Access.read);
599 Namespace namespace = lm.get(nsd.value.name);
600 if (namespace==null) {
602 namespace = other.remove(nsd.value.name);
604 if (namespace==null) {
605 namespace = new Namespace(nsd.value);
606 namespace.admin=new ArrayList<>();
607 namespace.owner=new ArrayList<>();
609 if (endsWith==null || urdd.role.endsWith(endsWith)) {
610 lm.put(namespace.name,namespace);
612 other.put(namespace.name,namespace);
615 if (Question.OWNER.equals(urdd.rname)) {
616 namespace.owner.add(urdd.user);
618 namespace.admin.add(urdd.user);
624 return Result.ok(lm.values());
629 path = "/authz/nss/responsible/:id",
630 params = { "id|string|true" },
632 errorCodes = { 403,404 },
633 text = { "Lists all Namespaces where Identity :id is a Responsible Party",
634 "Note: :id must be fully qualified (i.e. ab1234@people.osaaf.org)"
638 public Result<NSS> getNSbyResponsible(AuthzTrans trans, String user, boolean full) {
639 final Validator v = new ServiceValidator();
640 if (v.nullOrBlank("User", user).err()) {
641 return Result.err(Status.ERR_BadData, v.errs());
643 Result<Collection<Namespace>> rn = loadNamepace(trans, user, ".owner",full);
645 return Result.err(rn);
648 return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user);
650 NSS nss = mapper.newInstance(API.NSS);
651 // Note: "loadNamespace" prevalidates
652 return mapper.nss(trans, rn.value, nss);
657 path = "/authz/nss/children/:id",
658 params = { "id|string|true" },
660 errorCodes = { 403,404 },
661 text = { "Lists all Child Namespaces of Namespace :id",
662 "Note: This is not a cached read"
666 public Result<NSS> getNSsChildren(AuthzTrans trans, String parent) {
667 final Validator v = new ServiceValidator();
668 if (v.nullOrBlank("NS", parent).err()) {
669 return Result.err(Status.ERR_BadData,v.errs());
672 Result<NsDAO.Data> rnd = ques.deriveNs(trans, parent);
674 return Result.err(rnd);
676 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
678 return Result.err(rnd);
681 Set<Namespace> lm = new HashSet<>();
682 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.dao().getChildren(trans, parent);
684 if (rlnd.isEmpty()) {
685 return Result.err(Status.ERR_NotFound, "No data found for %s",parent);
687 for (NsDAO.Data ndd : rlnd.value) {
688 Namespace namespace = new Namespace(ndd);
689 Result<List<String>> rls = func.getAdmins(trans, namespace.name, false);
691 namespace.admin=rls.value;
694 rls = func.getOwners(trans, namespace.name, false);
696 namespace.owner=rls.value;
701 NSS nss = mapper.newInstance(API.NSS);
702 return mapper.nss(trans,lm, nss);
704 return Result.err(rlnd);
714 errorCodes = { 403,404,406 },
715 text = { "Replace the Current Description of a Namespace with a new one"
719 public Result<Void> updateNsDescription(AuthzTrans trans, REQUEST from) {
720 final Result<Namespace> nsd = mapper.ns(trans, from);
721 final ServiceValidator v = new ServiceValidator();
722 if (v.ns(nsd).err()) {
723 return Result.err(Status.ERR_BadData,v.errs());
725 if (v.nullOrBlank("description", nsd.value.description).err()) {
726 return Result.err(Status.ERR_BadData,v.errs());
729 Namespace namespace = nsd.value;
730 Result<List<NsDAO.Data>> rlnd = ques.nsDAO.read(trans, namespace.name);
732 if (rlnd.notOKorIsEmpty()) {
733 return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name);
736 if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) {
737 return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name);
740 Result<Void> rdr = ques.nsDAO.dao().addDescription(trans, namespace.name, namespace.description);
744 return Result.err(rdr);
750 * @throws DAOException
751 * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String)
755 path = "/authz/ns/:ns",
756 params = { "ns|string|true" },
758 errorCodes = { 403,404,424 },
759 text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ",
760 "are still credentials associated with them, but they can be deleted by setting ",
761 "the \"force\" property. To do this: Add 'force=true' as a query parameter",
762 "<p>WARNING: Using force will delete all credentials attached to this namespace. Use with care.</p>"
763 + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted,"
764 + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted "
765 + "at or below Application Scope"
769 public Result<Void> deleteNS(AuthzTrans trans, String ns) {
770 return func.deleteNS(trans, ns);
774 /***********************************
776 ***********************************/
780 * @see org.onap.aaf.auth.service.AuthzService#createOrUpdatePerm(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object, boolean, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List)
784 path = "/authz/perm",
787 errorCodes = {403,404,406,409},
788 text = { "Permission consists of:",
789 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
790 + "is being protected</li>",
791 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
792 + " instance of the type</li>",
793 "<li>action - what kind of action is allowed</li></ul>",
794 "Note: instance and action can be an *"
798 public Result<Void> createPerm(final AuthzTrans trans,REQUEST rreq) {
799 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
800 final ServiceValidator v = new ServiceValidator();
801 if (v.perm(newPd).err()) {
802 return Result.err(Status.ERR_BadData,v.errs());
805 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false,
808 public String get() {
809 return "Create Permission [" +
810 newPd.value.fullType() + '|' +
811 newPd.value.instance + '|' +
812 newPd.value.action + ']';
816 private Result<NsDAO.Data> nsd;
818 public Result<?> mayChange() {
820 nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write);
825 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, newPd.value.ns);
826 if (nsr.notOKorIsEmpty()) {
827 return Result.err(nsr);
831 Result<String> rfc = func.createFuture(trans,fd.value,
832 newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action,
837 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
840 newPd.value.instance,
843 return Result.err(rfc);
846 return func.createPerm(trans, newPd.value, true);
848 return Result.err(fd);
854 path = "/authz/perms/:type",
855 params = {"type|string|true"},
857 errorCodes = { 404,406 },
858 text = { "List All Permissions that match the :type element of the key" }
861 public Result<PERMS> getPermsByType(AuthzTrans trans, final String permType) {
862 final Validator v = new ServiceValidator();
863 if (v.nullOrBlank("PermType", permType).err()) {
864 return Result.err(Status.ERR_BadData,v.errs());
867 Result<List<PermDAO.Data>> rlpd = ques.getPermsByType(trans, permType);
869 return Result.err(rlpd);
872 // We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper?
873 // Result<NsDAO.Data> r;
874 // if ((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r);
876 PERMS perms = mapper.newInstance(API.PERMS);
877 if (!rlpd.isEmpty()) {
878 // Note: Mapper will restrict what can be viewed
879 return mapper.perms(trans, rlpd.value, perms, true);
881 return Result.ok(perms);
886 path = "/authz/perms/:type/:instance/:action",
887 params = {"type|string|true",
888 "instance|string|true",
889 "action|string|true"},
891 errorCodes = { 404,406 },
892 text = { "List Permissions that match key; :type, :instance and :action" }
895 public Result<PERMS> getPermsByName(AuthzTrans trans, String type, String instance, String action) {
896 final Validator v = new ServiceValidator();
897 if (v.nullOrBlank("PermType", type).err()
898 || v.nullOrBlank("PermInstance", instance).err()
899 || v.nullOrBlank("PermAction", action).err()) {
900 return Result.err(Status.ERR_BadData,v.errs());
903 Result<List<PermDAO.Data>> rlpd = ques.getPermsByName(trans, type, instance, action);
905 return Result.err(rlpd);
908 PERMS perms = mapper.newInstance(API.PERMS);
909 if (!rlpd.isEmpty()) {
910 // Note: Mapper will restrict what can be viewed
911 return mapper.perms(trans, rlpd.value, perms, true);
913 return Result.ok(perms);
918 path = "/authz/perms/user/:user",
919 params = {"user|string|true"},
921 errorCodes = { 404,406 },
922 text = { "List All Permissions that match user :user",
923 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>"}
926 public Result<PERMS> getPermsByUser(AuthzTrans trans, String user) {
927 final Validator v = new ServiceValidator();
928 if (v.nullOrBlank("User", user).err()) {
929 return Result.err(Status.ERR_BadData,v.errs());
932 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,
933 trans.requested(force));
935 return Result.err(rlpd);
938 PERMS perms = mapper.newInstance(API.PERMS);
940 if (rlpd.isEmpty()) {
941 return Result.ok(perms);
943 // Note: Mapper will restrict what can be viewed
944 // if user is the same as that which is looked up, no filtering is required
945 return mapper.perms(trans, rlpd.value,
947 !user.equals(trans.user()));
952 path = "/authz/perms/user/:user/scope/:scope",
953 params = {"user|string|true","scope|string|true"},
955 errorCodes = { 404,406 },
956 text = { "List All Permissions that match user :user, filtered by NS (Scope)",
957 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
958 "<p>'scope' must be expressed as NSs separated by ':'</p>"
962 public Result<PERMS> getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) {
963 final Validator v = new ServiceValidator();
964 if (v.nullOrBlank("User", user).err()) {
965 return Result.err(Status.ERR_BadData,v.errs());
968 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user, trans.requested(force));
970 return Result.err(rlpd);
973 PERMS perms = mapper.newInstance(API.PERMS);
975 if (rlpd.isEmpty()) {
976 return Result.ok(perms);
978 // Note: Mapper will restrict what can be viewed
979 // if user is the same as that which is looked up, no filtering is required
980 return mapper.perms(trans, rlpd.value,
983 !user.equals(trans.user()));
988 path = "/authz/perms/user/:user",
989 params = {"user|string|true"},
991 errorCodes = { 404,406 },
992 text = { "List All Permissions that match user :user",
993 "<p>'user' must be expressed as full identity (ex: id@full.domain.com)</p>",
995 "Present Queries as one or more Permissions (see ContentType Links below for format).",
997 "If the Caller is Granted this specific Permission, and the Permission is valid",
998 " for the User, it will be included in response Permissions, along with",
999 " all the normal permissions on the 'GET' version of this call. If it is not",
1000 " valid, or Caller does not have permission to see, it will be removed from the list",
1002 " *Note: This design allows you to make one call for all expected permissions",
1003 " The permission to be included MUST be:",
1004 " <user namespace>.access|:<ns|role|perm>[:key]|<create|read|write>",
1006 " com.att.myns.access|:ns|write",
1007 " com.att.myns.access|:role:myrole|create",
1008 " com.att.myns.access|:perm:mytype:myinstance:myaction|read",
1013 public Result<PERMS> getPermsByUser(AuthzTrans trans, PERMS _perms, String user) {
1014 PERMS perms = _perms;
1015 final Validator v = new ServiceValidator();
1016 if (v.nullOrBlank("User", user).err()) {
1017 return Result.err(Status.ERR_BadData,v.errs());
1021 Result<List<PermDAO.Data>> rlpd = ques.getPermsByUser(trans, user,trans.requested(force));
1023 return Result.err(rlpd);
1027 1) See if allowed to query
1028 2) See if User is allowed
1030 Result<List<PermDAO.Data>> in = mapper.perms(trans, perms);
1031 if (in.isOKhasData()) {
1032 List<PermDAO.Data> out = rlpd.value;
1034 for (PermDAO.Data pdd : in.value) {
1036 if ("access".equals(pdd.type)) {
1037 Access access = Access.valueOf(pdd.action);
1038 String[] mdkey = Split.splitTrim(':',pdd.instance);
1039 if (mdkey.length>1) {
1040 String type = mdkey[1];
1041 if ("role".equals(type)) {
1042 if (mdkey.length>2) {
1043 RoleDAO.Data rdd = new RoleDAO.Data();
1046 ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK();
1048 } else if ("perm".equals(type)) {
1049 if (mdkey.length>4) { // also need instance/action
1050 PermDAO.Data p = new PermDAO.Data();
1053 p.instance=mdkey[3];
1055 ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK();
1057 } else if ("ns".equals(type)) {
1058 NsDAO.Data ndd = new NsDAO.Data();
1060 ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK();
1070 perms = mapper.newInstance(API.PERMS);
1071 if (rlpd.isEmpty()) {
1072 return Result.ok(perms);
1074 // Note: Mapper will restrict what can be viewed
1075 // if user is the same as that which is looked up, no filtering is required
1076 return mapper.perms(trans, rlpd.value,
1078 !user.equals(trans.user()));
1083 path = "/authz/perms/role/:role",
1084 params = {"role|string|true"},
1086 errorCodes = { 404,406 },
1087 text = { "List All Permissions that are granted to :role" }
1090 public Result<PERMS> getPermsByRole(AuthzTrans trans,String role) {
1091 final Validator v = new ServiceValidator();
1092 if (v.nullOrBlank("Role", role).err()) {
1093 return Result.err(Status.ERR_BadData,v.errs());
1096 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques,role);
1098 return Result.err(rrdd);
1101 Result<NsDAO.Data> r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
1103 return Result.err(r);
1106 PERMS perms = mapper.newInstance(API.PERMS);
1108 Result<List<PermDAO.Data>> rlpd = ques.getPermsByRole(trans, role, trans.requested(force));
1109 if (rlpd.isOKhasData()) {
1110 // Note: Mapper will restrict what can be viewed
1111 return mapper.perms(trans, rlpd.value, perms, true);
1113 return Result.ok(perms);
1118 path = "/authz/perms/ns/:ns",
1119 params = {"ns|string|true"},
1121 errorCodes = { 404,406 },
1122 text = { "List All Permissions that are in Namespace :ns" }
1125 public Result<PERMS> getPermsByNS(AuthzTrans trans,String ns) {
1126 final Validator v = new ServiceValidator();
1127 if (v.nullOrBlank("NS", ns).err()) {
1128 return Result.err(Status.ERR_BadData,v.errs());
1131 Result<NsDAO.Data> rnd = ques.deriveNs(trans, ns);
1133 return Result.err(rnd);
1136 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
1138 return Result.err(rnd);
1141 Result<List<PermDAO.Data>> rlpd = ques.permDAO.readNS(trans, ns);
1143 return Result.err(rlpd);
1146 PERMS perms = mapper.newInstance(API.PERMS);
1147 if (!rlpd.isEmpty()) {
1148 // Note: Mapper will restrict what can be viewed
1149 return mapper.perms(trans, rlpd.value,perms, true);
1151 return Result.ok(perms);
1156 path = "/authz/perm/:type/:instance/:action",
1157 params = {"type|string|true",
1158 "instance|string|true",
1159 "action|string|true"},
1161 errorCodes = { 404,406, 409 },
1162 text = { "Rename the Permission referenced by :type :instance :action, and "
1163 + "rename (copy/delete) to the Permission described in PermRequest" }
1166 public Result<Void> renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) {
1167 final Result<PermDAO.Data> newPd = mapper.perm(trans, rreq);
1168 final ServiceValidator v = new ServiceValidator();
1169 if (v.perm(newPd).err()) {
1170 return Result.err(Status.ERR_BadData,v.errs());
1173 if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) {
1174 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1175 newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action);
1178 Result<NsSplit> nss = ques.deriveNsSplit(trans, origType);
1179 Result<List<PermDAO.Data>> origRlpd = ques.permDAO.read(trans, nss.value.ns, nss.value.name, origInstance, origAction);
1181 if (origRlpd.notOKorIsEmpty()) {
1182 return Result.err(Status.ERR_PermissionNotFound,
1183 "Permission [%s|%s|%s] does not exist",
1184 origType,origInstance,origAction);
1187 PermDAO.Data origPd = origRlpd.value.get(0);
1189 if (!origPd.ns.equals(newPd.value.ns)) {
1190 return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " +
1191 "<new type> must start with [" + origPd.ns + "]");
1194 if ( origPd.type.equals(newPd.value.type) &&
1195 origPd.action.equals(newPd.value.action) &&
1196 origPd.instance.equals(newPd.value.instance) ) {
1197 return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission");
1200 Set<String> origRoles = origPd.roles(false);
1201 if (!origRoles.isEmpty()) {
1202 Set<String> roles = newPd.value.roles(true);
1203 for (String role : origPd.roles) {
1208 newPd.value.description = origPd.description;
1210 Result<Void> rv = null;
1212 rv = func.createPerm(trans, newPd.value, false);
1214 rv = func.deletePerm(trans, origPd, true, false);
1221 path = "/authz/perm",
1224 errorCodes = { 404,406 },
1225 text = { "Add Description Data to Perm" }
1228 public Result<Void> updatePermDescription(AuthzTrans trans, REQUEST from) {
1229 final Result<PermDAO.Data> pd = mapper.perm(trans, from);
1230 final ServiceValidator v = new ServiceValidator();
1231 if (v.perm(pd).err()) {
1232 return Result.err(Status.ERR_BadData,v.errs());
1234 if (v.nullOrBlank("description", pd.value.description).err()) {
1235 return Result.err(Status.ERR_BadData,v.errs());
1237 final PermDAO.Data perm = pd.value;
1238 if (ques.permDAO.read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) {
1239 return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist",
1240 perm.ns,perm.type,perm.instance,perm.action);
1243 if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) {
1244 return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]",
1245 perm.ns,perm.type,perm.instance,perm.action);
1248 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, pd.value.ns);
1249 if (nsr.notOKorIsEmpty()) {
1250 return Result.err(nsr);
1253 Result<Void> rdr = ques.permDAO.addDescription(trans, perm.ns, perm.type, perm.instance,
1254 perm.action, perm.description);
1258 return Result.err(rdr);
1265 path = "/authz/role/perm",
1268 errorCodes = {403,404,406,409},
1269 text = { "Set a permission's roles to roles given" }
1273 public Result<Void> resetPermRoles(final AuthzTrans trans, REQUEST rreq) {
1274 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1275 if (updt.notOKorIsEmpty()) {
1276 return Result.err(updt);
1279 final ServiceValidator v = new ServiceValidator();
1280 if (v.perm(updt).err()) {
1281 return Result.err(Status.ERR_BadData,v.errs());
1284 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write);
1286 return Result.err(nsd);
1289 // Read full set to get CURRENT values
1290 Result<List<PermDAO.Data>> rcurr = ques.permDAO.read(trans,
1293 updt.value.instance,
1296 if (rcurr.notOKorIsEmpty()) {
1297 return Result.err(Status.ERR_PermissionNotFound,
1298 "Permission [%s.%s|%s|%s] does not exist",
1299 updt.value.ns,updt.value.type,updt.value.instance,updt.value.action);
1302 // Create a set of Update Roles, which are in Internal Format
1303 Set<String> updtRoles = new HashSet<>();
1304 Result<NsSplit> nss;
1305 for (String role : updt.value.roles(false)) {
1306 nss = ques.deriveNsSplit(trans, role);
1308 updtRoles.add(nss.value.ns + '|' + nss.value.name);
1310 trans.error().log(nss.errorString());
1314 Result<Void> rv = null;
1316 for (PermDAO.Data curr : rcurr.value) {
1317 Set<String> currRoles = curr.roles(false);
1318 // must add roles to this perm, and add this perm to each role
1319 // in the update, but not in the current
1320 for (String role : updtRoles) {
1321 if (!currRoles.contains(role)) {
1322 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1323 if (key.isOKhasData()) {
1324 Result<List<RoleDAO.Data>> rrd = ques.roleDAO.read(trans, key.value);
1325 if (rrd.isOKhasData()) {
1326 for (RoleDAO.Data r : rrd.value) {
1327 rv = func.addPermToRole(trans, r, curr, false);
1328 if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) {
1329 return Result.err(rv);
1333 return Result.err(rrd);
1338 // similarly, must delete roles from this perm, and delete this perm from each role
1339 // in the update, but not in the current
1340 for (String role : currRoles) {
1341 if (!updtRoles.contains(role)) {
1342 Result<RoleDAO.Data> key = RoleDAO.Data.decode(trans, ques, role);
1343 if (key.isOKhasData()) {
1344 Result<List<RoleDAO.Data>> rdd = ques.roleDAO.read(trans, key.value);
1345 if (rdd.isOKhasData()) {
1346 for (RoleDAO.Data r : rdd.value) {
1347 rv = func.delPermFromRole(trans, r, curr, true);
1348 if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) {
1349 return Result.err(rv);
1357 return rv==null?Result.ok():rv;
1362 path = "/authz/perm",
1365 errorCodes = { 404,406 },
1366 text = { "Delete the Permission referenced by PermKey.",
1367 "You cannot normally delete a permission which is still granted to roles,",
1368 "however the \"force\" property allows you to do just that. To do this: Add",
1369 "'force=true' as a query parameter.",
1370 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>" }
1373 public Result<Void> deletePerm(final AuthzTrans trans, REQUEST from) {
1374 Result<PermDAO.Data> pd = mapper.perm(trans, from);
1376 return Result.err(pd);
1378 final ServiceValidator v = new ServiceValidator();
1379 if (v.nullOrBlank(pd.value).err()) {
1380 return Result.err(Status.ERR_BadData,v.errs());
1382 final PermDAO.Data perm = pd.value;
1383 if (ques.permDAO.read(trans, perm).notOKorIsEmpty()) {
1384 return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist",
1385 perm.ns,perm.type,perm.instance,perm.action );
1388 Result<FutureDAO.Data> fd = mapper.future(trans,PermDAO.TABLE,from,perm,false,
1391 public String get() {
1392 return "Delete Permission [" + perm.fullPerm() + ']';
1396 private Result<NsDAO.Data> nsd;
1398 public Result<?> mayChange() {
1400 nsd = ques.mayUser(trans, trans.user(), perm, Access.write);
1408 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, perm.ns);
1409 if (nsr.notOKorIsEmpty()) {
1410 return Result.err(nsr);
1413 Result<String> rfc = func.createFuture(trans, fd.value,
1414 perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
1416 return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode());
1418 return Result.err(rfc);
1420 case Status.ACC_Now:
1421 return func.deletePerm(trans,perm,trans.requested(force), false);
1423 return Result.err(fd);
1429 path = "/authz/perm/:name/:type/:action",
1430 params = {"type|string|true",
1431 "instance|string|true",
1432 "action|string|true"},
1434 errorCodes = { 404,406 },
1435 text = { "Delete the Permission referenced by :type :instance :action",
1436 "You cannot normally delete a permission which is still granted to roles,",
1437 "however the \"force\" property allows you to do just that. To do this: Add",
1438 "'force=true' as a query parameter",
1439 "<p>WARNING: Using force will ungrant this permission from all roles. Use with care.</p>"}
1442 public Result<Void> deletePerm(AuthzTrans trans, String type, String instance, String action) {
1443 final Validator v = new ServiceValidator();
1444 if (v.nullOrBlank("Type",type)
1445 .nullOrBlank("Instance",instance)
1446 .nullOrBlank("Action",action)
1448 return Result.err(Status.ERR_BadData,v.errs());
1451 Result<PermDAO.Data> pd = ques.permFrom(trans, type, instance, action);
1453 return func.deletePerm(trans, pd.value, trans.requested(force), false);
1455 return Result.err(pd);
1459 /***********************************
1461 ***********************************/
1464 path = "/authz/role",
1467 errorCodes = {403,404,406,409},
1470 "Roles are part of Namespaces",
1472 "<ul><li>org.onap.aaf - The team that created and maintains AAF</li>",
1473 "Roles do not include implied permissions for an App. Instead, they contain explicit Granted Permissions by any Namespace in AAF (See Permissions)",
1474 "Restrictions on Role Names:",
1475 "<ul><li>Must start with valid Namespace name, terminated by . (dot/period)</li>",
1476 "<li>Allowed Characters are a-zA-Z0-9._-</li>",
1477 "<li>role names are Case Sensitive</li></ul>",
1478 "The right questions to ask for defining and populating a Role in AAF, therefore, are:",
1479 "<ul><li>'What Job Function does this represent?'</li>",
1480 "<li>'Does this person perform this Job Function?'</li></ul>" }
1484 public Result<Void> createRole(final AuthzTrans trans, REQUEST from) {
1485 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1486 final ServiceValidator v = new ServiceValidator();
1487 if (v.role(rd).err()) {
1488 return Result.err(Status.ERR_BadData,v.errs());
1490 final RoleDAO.Data role = rd.value;
1491 if (ques.roleDAO.read(trans, role.ns, role.name).isOKhasData()) {
1492 return Result.err(Status.ERR_ConflictAlreadyExists, "Role [" + role.fullName() + "] already exists");
1495 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
1498 public String get() {
1499 return "Create Role [" +
1500 rd.value.fullName() +
1505 private Result<NsDAO.Data> nsd;
1507 public Result<?> mayChange() {
1509 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
1515 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
1516 if (nsr.notOKorIsEmpty()) {
1517 return Result.err(nsr);
1522 Result<String> rfc = func.createFuture(trans, fd.value,
1523 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.C);
1525 return Result.err(Status.ACC_Future, "Role [%s.%s] is saved for future processing",
1529 return Result.err(rfc);
1531 case Status.ACC_Now:
1532 Result<RoleDAO.Data> rdr = ques.roleDAO.create(trans, role);
1536 return Result.err(rdr);
1539 return Result.err(fd);
1544 * @see org.onap.aaf.auth.service.AuthzService#getRolesByName(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1548 path = "/authz/roles/:role",
1549 params = {"role|string|true"},
1551 errorCodes = {404,406},
1552 text = { "List Roles that match :role",
1553 "Note: You must have permission to see any given role"
1557 public Result<ROLES> getRolesByName(AuthzTrans trans, String role) {
1558 final Validator v = new ServiceValidator();
1559 if (v.nullOrBlank("Role", role).err()) {
1560 return Result.err(Status.ERR_BadData,v.errs());
1563 // Determine if User can ask this question
1564 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
1565 if (rrdd.isOKhasData()) {
1566 Result<NsDAO.Data> r;
1567 if ((r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read)).notOK()) {
1568 return Result.err(r);
1571 return Result.err(rrdd);
1575 int query = role.indexOf('?');
1576 Result<List<RoleDAO.Data>> rlrd = ques.getRolesByName(trans, query<0?role:role.substring(0, query));
1578 // Note: Mapper will restrict what can be viewed
1579 ROLES roles = mapper.newInstance(API.ROLES);
1580 return mapper.roles(trans, rlrd.value, roles, true);
1582 return Result.err(rlrd);
1587 * @see org.onap.aaf.auth.service.AuthzService#getRolesByUser(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1591 path = "/authz/roles/user/:name",
1592 params = {"name|string|true"},
1594 errorCodes = {404,406},
1595 text = { "List all Roles that match user :name",
1596 "'user' must be expressed as full identity (ex: id@full.domain.com)",
1597 "Note: You must have permission to see any given role"
1602 public Result<ROLES> getRolesByUser(AuthzTrans trans, String user) {
1603 final Validator v = new ServiceValidator();
1604 if (v.nullOrBlank("User", user).err()) {
1605 return Result.err(Status.ERR_BadData,v.errs());
1608 ROLES roles = mapper.newInstance(API.ROLES);
1609 // Get list of roles per user, then add to Roles as we go
1610 Result<List<RoleDAO.Data>> rlrd;
1611 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
1612 if (rlurd.isOKhasData()) {
1613 for (UserRoleDAO.Data urd : rlurd.value ) {
1614 rlrd = ques.roleDAO.read(trans, urd.ns,urd.rname);
1615 // Note: Mapper will restrict what can be viewed
1616 // if user is the same as that which is looked up, no filtering is required
1617 if (rlrd.isOKhasData()) {
1618 mapper.roles(trans, rlrd.value,roles, !user.equals(trans.user()));
1622 return Result.ok(roles);
1627 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1631 path = "/authz/roles/ns/:ns",
1632 params = {"ns|string|true"},
1634 errorCodes = {404,406},
1635 text = { "List all Roles for the Namespace :ns",
1636 "Note: You must have permission to see any given role"
1641 public Result<ROLES> getRolesByNS(AuthzTrans trans, String ns) {
1642 final Validator v = new ServiceValidator();
1643 if (v.nullOrBlank("NS", ns).err()) {
1644 return Result.err(Status.ERR_BadData,v.errs());
1647 // check if user is allowed to view NS
1648 Result<NsDAO.Data> rnsd = ques.deriveNs(trans, ns);
1650 return Result.err(rnsd);
1652 rnsd = ques.mayUser(trans, trans.user(), rnsd.value, Access.read);
1654 return Result.err(rnsd);
1657 TimeTaken tt = trans.start("MAP Roles by NS to Roles", Env.SUB);
1659 ROLES roles = mapper.newInstance(API.ROLES);
1660 // Get list of roles per user, then add to Roles as we go
1661 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readNS(trans, ns);
1663 if (!rlrd.isEmpty()) {
1664 // Note: Mapper doesn't need to restrict what can be viewed, because we did it already.
1665 mapper.roles(trans,rlrd.value,roles,false);
1667 return Result.ok(roles);
1669 return Result.err(rlrd);
1678 * @see org.onap.aaf.auth.service.AuthzService#getRolesByNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
1682 path = "/authz/roles/name/:name",
1683 params = {"name|string|true"},
1685 errorCodes = {404,406},
1686 text = { "List all Roles for only the Name of Role (without Namespace)",
1687 "Note: You must have permission to see any given role"
1691 public Result<ROLES> getRolesByNameOnly(AuthzTrans trans, String name) {
1692 final Validator v = new ServiceValidator();
1693 if (v.nullOrBlank("Name", name).err()) {
1694 return Result.err(Status.ERR_BadData,v.errs());
1697 // User Mapper to make sure user is allowed to view NS
1699 TimeTaken tt = trans.start("MAP Roles by Name to Roles", Env.SUB);
1701 ROLES roles = mapper.newInstance(API.ROLES);
1702 // Get list of roles per user, then add to Roles as we go
1703 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.readName(trans, name);
1705 if (!rlrd.isEmpty()) {
1706 // Note: Mapper will restrict what can be viewed
1707 mapper.roles(trans,rlrd.value,roles,true);
1709 return Result.ok(roles);
1711 return Result.err(rlrd);
1720 path = "/authz/roles/perm/:type/:instance/:action",
1721 params = {"type|string|true",
1722 "instance|string|true",
1723 "action|string|true"},
1725 errorCodes = {404,406},
1726 text = { "Find all Roles containing the given Permission." +
1727 "Permission consists of:",
1728 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1729 + "is being protected</li>",
1730 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1731 + " instance of the type</li>",
1732 "<li>action - what kind of action is allowed</li></ul>",
1733 "Notes: instance and action can be an *",
1734 " You must have permission to see any given role"
1739 public Result<ROLES> getRolesByPerm(AuthzTrans trans, String type, String instance, String action) {
1740 final Validator v = new ServiceValidator();
1741 if (v.permType(type)
1742 .permInstance(instance)
1745 return Result.err(Status.ERR_BadData,v.errs());
1748 TimeTaken tt = trans.start("Map Perm Roles Roles", Env.SUB);
1750 ROLES roles = mapper.newInstance(API.ROLES);
1751 // Get list of roles per user, then add to Roles as we go
1752 Result<NsSplit> nsSplit = ques.deriveNsSplit(trans, type);
1753 if (nsSplit.isOK()) {
1754 PermDAO.Data pdd = new PermDAO.Data(nsSplit.value, instance, action);
1756 if ((res=ques.mayUser(trans, trans.user(), pdd, Question.Access.read)).notOK()) {
1757 return Result.err(res);
1760 Result<List<PermDAO.Data>> pdlr = ques.permDAO.read(trans, pdd);
1761 if (pdlr.isOK())for (PermDAO.Data pd : pdlr.value) {
1762 Result<List<RoleDAO.Data>> rlrd;
1763 for (String r : pd.roles) {
1764 Result<String[]> rs = RoleDAO.Data.decodeToArray(trans, ques, r);
1766 rlrd = ques.roleDAO.read(trans, rs.value[0],rs.value[1]);
1767 // Note: Mapper will restrict what can be viewed
1768 if (rlrd.isOKhasData()) {
1769 mapper.roles(trans,rlrd.value,roles,true);
1775 return Result.ok(roles);
1783 path = "/authz/role",
1786 errorCodes = {404,406},
1787 text = { "Add Description Data to a Role" }
1791 public Result<Void> updateRoleDescription(AuthzTrans trans, REQUEST from) {
1792 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
1793 final ServiceValidator v = new ServiceValidator();
1794 if (v.role(rd).err()) {
1795 return Result.err(Status.ERR_BadData,v.errs());
1797 if (v.nullOrBlank("description", rd.value.description).err()) {
1798 return Result.err(Status.ERR_BadData,v.errs());
1801 final RoleDAO.Data role = rd.value;
1802 if (ques.roleDAO.read(trans, role.ns, role.name).notOKorIsEmpty()) {
1803 return Result.err(Status.ERR_NotFound, "Role [" + role.fullName() + "] does not exist");
1806 if (ques.mayUser(trans, trans.user(), role, Access.write).notOK()) {
1807 return Result.err(Status.ERR_Denied, "You do not have approval to change " + role.fullName());
1810 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
1811 if (nsr.notOKorIsEmpty()) {
1812 return Result.err(nsr);
1815 Result<Void> rdr = ques.roleDAO.addDescription(trans, role.ns, role.name, role.description);
1819 return Result.err(rdr);
1826 path = "/authz/role/perm",
1829 errorCodes = {403,404,406,409},
1830 text = { "Grant a Permission to a Role",
1831 "Permission consists of:",
1832 "<ul><li>type - a Namespace qualified identifier specifying what kind of resource "
1833 + "is being protected</li>",
1834 "<li>instance - a key, possibly multi-dimensional, that identifies a specific "
1835 + " instance of the type</li>",
1836 "<li>action - what kind of action is allowed</li></ul>",
1837 "Note: instance and action can be an *",
1838 "Note: Using the \"force\" property will create the Permission, if it doesn't exist AND the requesting " +
1839 " ID is allowed to create. It will then grant",
1840 " the permission to the role in one step. To do this: add 'force=true' as a query parameter."
1845 public Result<Void> addPermToRole(final AuthzTrans trans, REQUEST rreq) {
1846 // Translate Request into Perm and Role Objects
1847 final Result<PermDAO.Data> rpd = mapper.permFromRPRequest(trans, rreq);
1848 if (rpd.notOKorIsEmpty()) {
1849 return Result.err(rpd);
1851 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1852 if (rrd.notOKorIsEmpty()) {
1853 return Result.err(rrd);
1856 // Validate Role and Perm values
1857 final ServiceValidator v = new ServiceValidator();
1858 if (v.perm(rpd.value)
1861 return Result.err(Status.ERR_BadData,v.errs());
1864 Result<List<RoleDAO.Data>> rlrd = ques.roleDAO.read(trans, rrd.value.ns, rrd.value.name);
1865 if (rlrd.notOKorIsEmpty()) {
1866 return Result.err(Status.ERR_RoleNotFound, "Role [%s] does not exist", rrd.value.fullName());
1869 // Check Status of Data in DB (does it exist)
1870 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, rpd.value.ns,
1871 rpd.value.type, rpd.value.instance, rpd.value.action);
1872 PermDAO.Data createPerm = null; // if not null, create first
1873 if (rlpd.notOKorIsEmpty()) { // Permission doesn't exist
1874 if (trans.requested(force)) {
1875 // Remove roles from perm data object so we just create the perm here
1876 createPerm = rpd.value;
1877 createPerm.roles.clear();
1879 return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist",
1880 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action);
1883 if (rlpd.value.get(0).roles(false).contains(rrd.value.encode())) {
1884 return Result.err(Status.ERR_ConflictAlreadyExists,
1885 "Permission [%s.%s|%s|%s] already granted to Role [%s.%s]",
1886 rpd.value.ns,rpd.value.type,rpd.value.instance,rpd.value.action,
1887 rrd.value.ns,rrd.value.name
1893 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, rpd.value,true, // Allow grants to create Approvals
1896 public String get() {
1897 return "Grant Permission [" + rpd.value.fullPerm() + ']' +
1898 " to Role [" + rrd.value.fullName() + "]";
1902 private Result<NsDAO.Data> nsd;
1904 public Result<?> mayChange() {
1906 nsd = ques.mayUser(trans, trans.user(), rpd.value, Access.write);
1911 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rpd.value.ns);
1912 if (nsr.notOKorIsEmpty()) {
1913 return Result.err(nsr);
1917 Result<String> rfc = func.createFuture(trans,fd.value,
1918 rpd.value.fullPerm(),
1923 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
1929 return Result.err(rfc);
1931 case Status.ACC_Now:
1932 Result<Void> rv = null;
1933 if (createPerm!=null) {// has been validated for creating
1934 rv = func.createPerm(trans, createPerm, false);
1936 if (rv==null || rv.isOK()) {
1937 rv = func.addPermToRole(trans, rrd.value, rpd.value, false);
1941 return Result.err(fd);
1947 * Delete Perms from Roles (UnGrant)
1949 * @param roleFullName
1954 path = "/authz/role/:role/perm",
1955 params = {"role|string|true"},
1957 errorCodes = {404,406},
1958 text = { "Ungrant a permission from Role :role" }
1962 public Result<Void> delPermFromRole(final AuthzTrans trans, REQUEST rreq) {
1963 final Result<PermDAO.Data> updt = mapper.permFromRPRequest(trans, rreq);
1964 if (updt.notOKorIsEmpty()) {
1965 return Result.err(updt);
1967 final Result<RoleDAO.Data> rrd = mapper.roleFromRPRequest(trans, rreq);
1968 if (rrd.notOKorIsEmpty()) {
1969 return Result.err(rrd);
1972 final ServiceValidator v = new ServiceValidator();
1973 if (v.nullOrBlank(updt.value)
1974 .nullOrBlank(rrd.value)
1976 return Result.err(Status.ERR_BadData,v.errs());
1979 return delPermFromRole(trans, updt.value,rrd.value, rreq);
1982 private Result<Void> delPermFromRole(final AuthzTrans trans, PermDAO.Data pdd, RoleDAO.Data rdd, REQUEST rreq) {
1983 Result<List<PermDAO.Data>> rlpd = ques.permDAO.read(trans, pdd.ns, pdd.type,
1984 pdd.instance, pdd.action);
1986 if (rlpd.notOKorIsEmpty()) {
1987 return Result.err(Status.ERR_PermissionNotFound,
1988 "Permission [%s.%s|%s|%s] does not exist",
1989 pdd.ns,pdd.type,pdd.instance,pdd.action);
1992 Result<FutureDAO.Data> fd = mapper.future(trans, PermDAO.TABLE, rreq, pdd,true, // allow ungrants requests
1995 public String get() {
1996 return "Ungrant Permission [" + pdd.fullPerm() + ']' +
1997 " from Role [" + rdd.fullName() + "]";
2001 private Result<NsDAO.Data> nsd;
2003 public Result<?> mayChange() {
2005 nsd = ques.mayUser(trans, trans.user(), pdd, Access.write);
2010 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, pdd.ns);
2011 if (nsr.notOKorIsEmpty()) {
2012 return Result.err(nsr);
2016 Result<String> rfc = func.createFuture(trans,fd.value,
2023 return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing",
2029 return Result.err(rfc);
2031 case Status.ACC_Now:
2032 return func.delPermFromRole(trans, rdd, pdd, false);
2034 return Result.err(fd);
2041 path = "/authz/role/:role/perm/:type/:instance/:action",
2042 params = {"role|string|true",
2043 "perm type|string|true",
2044 "perm instance|string|true",
2045 "perm action|string|true"
2048 errorCodes = {404,406},
2049 text = { "Ungrant a single permission from Role :role with direct key" }
2053 public Result<Void> delPermFromRole(AuthzTrans trans, String role, String type, String instance, String action) {
2054 Result<Data> rpns = ques.deriveNs(trans, type);
2055 if (rpns.notOKorIsEmpty()) {
2056 return Result.err(rpns);
2059 final Validator v = new ServiceValidator();
2061 .permType(rpns.value.name,rpns.value.parent)
2062 .permInstance(instance)
2065 return Result.err(Status.ERR_BadData,v.errs());
2068 Result<Data> rrns = ques.deriveNs(trans, role);
2069 if (rrns.notOKorIsEmpty()) {
2070 return Result.err(rrns);
2073 final Result<List<RoleDAO.Data>> rrd = ques.roleDAO.read(trans, rrns.value.parent, rrns.value.name);
2074 if (rrd.notOKorIsEmpty()) {
2075 return Result.err(rrd);
2078 final Result<List<PermDAO.Data>> rpd = ques.permDAO.read(trans, rpns.value.parent, rpns.value.name, instance, action);
2079 if (rpd.notOKorIsEmpty()) {
2080 return Result.err(rpd);
2084 return delPermFromRole(trans,rpd.value.get(0), rrd.value.get(0), mapper.ungrantRequest(trans, role, type, instance, action));
2089 path = "/authz/role/:role",
2090 params = {"role|string|true"},
2092 errorCodes = {404,406},
2093 text = { "Delete the Role named :role"}
2097 public Result<Void> deleteRole(AuthzTrans trans, String role) {
2098 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
2099 if (rrdd.isOKhasData()) {
2100 final ServiceValidator v = new ServiceValidator();
2101 if (v.nullOrBlank(rrdd.value).err()) {
2102 return Result.err(Status.ERR_BadData,v.errs());
2104 return func.deleteRole(trans, rrdd.value, false, false);
2106 return Result.err(rrdd);
2112 path = "/authz/role",
2115 errorCodes = { 404,406 },
2116 text = { "Delete the Role referenced by RoleKey",
2117 "You cannot normally delete a role which still has permissions granted or users assigned to it,",
2118 "however the \"force\" property allows you to do just that. To do this: Add 'force=true'",
2119 "as a query parameter.",
2120 "<p>WARNING: Using force will remove all users and permission from this role. Use with care.</p>"}
2124 public Result<Void> deleteRole(final AuthzTrans trans, REQUEST from) {
2125 final Result<RoleDAO.Data> rd = mapper.role(trans, from);
2126 final ServiceValidator v = new ServiceValidator();
2128 return Result.err(Status.ERR_BadData,"Request does not contain Role");
2130 if (v.nullOrBlank(rd.value).err()) {
2131 return Result.err(Status.ERR_BadData,v.errs());
2133 final RoleDAO.Data role = rd.value;
2134 if (ques.roleDAO.read(trans, role).notOKorIsEmpty() && !trans.requested(force)) {
2135 return Result.err(Status.ERR_RoleNotFound, "Role [" + role.fullName() + "] does not exist");
2138 Result<FutureDAO.Data> fd = mapper.future(trans,RoleDAO.TABLE,from,role,false,
2139 () -> "Delete Role [" + role.fullName() + ']'
2140 + " and all attached user roles",
2142 private Result<NsDAO.Data> nsd;
2144 public Result<?> mayChange() {
2146 nsd = ques.mayUser(trans, trans.user(), role, Access.write);
2154 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rd.value.ns);
2155 if (nsr.notOKorIsEmpty()) {
2156 return Result.err(nsr);
2159 Result<String> rfc = func.createFuture(trans, fd.value,
2160 role.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D);
2162 return Result.err(Status.ACC_Future, "Role Deletion [%s.%s] is saved for future processing",
2166 return Result.err(rfc);
2168 case Status.ACC_Now:
2169 return func.deleteRole(trans,role,trans.requested(force), true /*preapproved*/);
2171 return Result.err(fd);
2176 /***********************************
2178 ***********************************/
2179 private class MayCreateCred implements MayChange {
2180 private Result<NsDAO.Data> nsd;
2181 private AuthzTrans trans;
2182 private CredDAO.Data cred;
2183 private Executor exec;
2185 public MayCreateCred(AuthzTrans trans, CredDAO.Data cred, Executor exec) {
2192 public Result<?> mayChange() {
2194 nsd = ques.validNSOfDomain(trans, cred.id);
2196 // is Ns of CredID valid?
2200 if (trans.org().validate(trans,Policy.CREATE_MECHID, exec, cred.id)==null) {
2203 Result<?> rmc = ques.mayUser(trans, trans.user(), nsd.value, Access.write);
2204 if (rmc.isOKhasData()) {
2208 } catch (Exception e) {
2209 trans.warn().log(e);
2212 trans.warn().log(nsd.errorString());
2214 return Result.err(Status.ERR_Denied,"%s is not allowed to create %s in %s",trans.user(),cred.id,cred.ns);
2218 private class MayChangeCred implements MayChange {
2220 private Result<NsDAO.Data> nsd;
2221 private AuthzTrans trans;
2222 private CredDAO.Data cred;
2223 public MayChangeCred(AuthzTrans trans, CredDAO.Data cred) {
2229 public Result<?> mayChange() {
2230 // User can change himself (but not create)
2231 if (trans.user().equals(cred.id)) {
2235 nsd = ques.validNSOfDomain(trans, cred.id);
2237 // Get the Namespace
2239 if (ques.mayUser(trans, trans.user(), nsd.value,Access.write).isOK()) {
2242 String user[] = Split.split('.',trans.user());
2243 if (user.length>2) {
2244 String company = user[user.length-1] + '.' + user[user.length-2];
2245 if (ques.isGranted(trans, trans.user(), ROOT_NS,"password",company,"reset")) {
2250 return Result.err(Status.ERR_Denied,"%s is not allowed to change %s in %s",trans.user(),cred.id,cred.ns);
2255 private final long DAY_IN_MILLIS = 24*3600*1000L;
2259 path = "/authn/cred",
2262 errorCodes = {403,404,406,409},
2263 text = { "A credential consists of:",
2264 "<ul><li>id - the ID to create within AAF. The domain is in reverse",
2265 "order of Namespace (i.e. Users of Namespace com.att.myapp would be",
2266 "AB1234@myapp.att.com</li>",
2267 "<li>password - Company Policy Compliant Password</li></ul>",
2268 "Note: AAF does support multiple credentials with the same ID.",
2269 "Check with your organization if you have this implemented."
2273 public Result<Void> createUserCred(final AuthzTrans trans, REQUEST from) {
2274 final String cmdDescription = ("Create User Credential");
2275 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2278 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2279 if (rcred.isOKhasData()) {
2280 byte[] rawCred = rcred.value.cred.array();
2281 rcred = ques.userCredSetup(trans, rcred.value);
2283 final ServiceValidator v = new ServiceValidator();
2285 if (v.cred(trans, trans.org(),rcred,true).err()) { // Note: Creates have stricter Validations
2286 return Result.err(Status.ERR_BadData,v.errs());
2290 // 2016-4 Jonathan, New Behavior - If MechID is not registered with Org, deny creation
2291 Identity mechID = null;
2292 Organization org = trans.org();
2294 mechID = org.getIdentity(trans, rcred.value.id);
2295 } catch (Exception e1) {
2296 trans.error().log(e1,rcred.value.id,"cannot be validated at this time");
2298 if (mechID==null || !mechID.isFound()) {
2299 return Result.err(Status.ERR_Policy,"MechIDs must be registered with %s before provisioning in AAF",org.getName());
2302 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
2303 if (nsr.notOKorIsEmpty()) {
2304 return Result.err(Status.ERR_NsNotFound,"Cannot provision %s on non-existent Namespace %s",mechID.id(),rcred.value.ns);
2308 boolean firstID = false;
2311 CassExecutor exec = new CassExecutor(trans, func);
2312 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
2313 if (rlcd.isOKhasData()) {
2314 if (!org.canHaveMultipleCreds(rcred.value.id)) {
2315 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential exists");
2318 for (CredDAO.Data curr : rlcd.value) {
2319 // May not use the same password in the list
2320 // Note: ASPR specifies character differences, but we don't actually store the
2321 // password to validate char differences.
2323 rb = ques.userCredCheck(trans, curr, rawCred);
2325 return Result.err(rb);
2326 } else if (rb.value){
2327 return Result.err(Status.ERR_Policy, "Credential content cannot be reused.");
2328 } else if (Chrono.dateOnlyStamp(curr.expires).equals(Chrono.dateOnlyStamp(rcred.value.expires)) && curr.type==rcred.value.type) {
2329 return Result.err(Status.ERR_ConflictAlreadyExists, "Credential with same Expiration Date exists, use 'reset'");
2334 // 2016-04-12 Jonathan If Caller is the Sponsor and is also an Owner of NS, allow without special Perm
2335 String theMechID = rcred.value.id;
2336 Boolean otherMechIDs = false;
2337 // find out if this is the only mechID. other MechIDs mean special handling (not automated)
2338 for (CredDAO.Data cd : ques.credDAO.readNS(trans,nsr.value.get(0).name).value) {
2339 if (!cd.id.equals(theMechID)) {
2340 otherMechIDs = true;
2345 // We can say "ID does not exist" here
2346 if ((reason=org.validate(trans, Policy.CREATE_MECHID, exec, theMechID,trans.user(),otherMechIDs.toString()))!=null) {
2347 return Result.err(Status.ERR_Denied, reason);
2350 } catch (Exception e) {
2351 return Result.err(e);
2355 mc = new MayCreateCred(trans, rcred.value, exec);
2357 final CredDAO.Data cdd = rcred.value;
2358 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false, // may want to enable in future.
2361 public String get() {
2362 return cmdDescription + " [" +
2365 + cdd.expires + ']';
2372 Result<String> rfc = func.createFuture(trans, fd.value,
2373 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2374 trans.user(), nsr.value.get(0), FUTURE_OP.C);
2376 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s] is saved for future processing",
2378 Integer.toString(rcred.value.type),
2379 rcred.value.expires.toString());
2381 return Result.err(rfc);
2383 case Status.ACC_Now:
2386 // && !nsr.value.get(0).isAdmin(trans.getUserPrincipal().getName())) {
2387 Result<List<String>> admins = func.getAdmins(trans, nsr.value.get(0).name, false);
2388 // OK, it's a first ID, and not by NS Admin, so let's set TempPassword length
2389 // Note, we only do this on First time, because of possibility of
2390 // prematurely expiring a production id
2391 if (admins.isOKhasData() && !admins.value.contains(trans.user())) {
2392 rcred.value.expires = org.expiration(null, Expiration.TempPassword).getTime();
2395 } catch (Exception e) {
2396 trans.error().log(e, "While setting expiration to TempPassword");
2398 Result<?>udr = ques.credDAO.create(trans, rcred.value);
2402 return Result.err(udr);
2404 return Result.err(fd);
2408 return Result.err(rcred);
2417 path = "/authn/creds/ns/:ns",
2418 params = {"ns|string|true"},
2420 errorCodes = {403,404,406},
2421 text = { "Return all IDs in Namespace :ns"
2425 public Result<USERS> getCredsByNS(AuthzTrans trans, String ns) {
2426 final Validator v = new ServiceValidator();
2427 if (v.ns(ns).err()) {
2428 return Result.err(Status.ERR_BadData,v.errs());
2431 // check if user is allowed to view NS
2432 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2434 return Result.err(rnd);
2436 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2438 return Result.err(rnd);
2441 TimeTaken tt = trans.start("MAP Creds by NS to Creds", Env.SUB);
2443 USERS users = mapper.newInstance(API.USERS);
2444 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readNS(trans, ns);
2447 if (!rlcd.isEmpty()) {
2448 return mapper.cred(rlcd.value, users);
2450 return Result.ok(users);
2452 return Result.err(rlcd);
2462 path = "/authn/creds/id/:ns",
2463 params = {"id|string|true"},
2465 errorCodes = {403,404,406},
2466 text = { "Return all IDs in for ID"
2467 ,"(because IDs are multiple, due to multiple Expiration Dates)"
2471 public Result<USERS> getCredsByID(AuthzTrans trans, String id) {
2472 final Validator v = new ServiceValidator();
2473 if (v.nullOrBlank("ID",id).err()) {
2474 return Result.err(Status.ERR_BadData,v.errs());
2477 String ns = Question.domain2ns(id);
2478 // check if user is allowed to view NS
2479 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
2481 return Result.err(rnd);
2483 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
2485 return Result.err(rnd);
2488 TimeTaken tt = trans.start("MAP Creds by ID to Creds", Env.SUB);
2490 USERS users = mapper.newInstance(API.USERS);
2491 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, id);
2494 if (!rlcd.isEmpty()) {
2495 return mapper.cred(rlcd.value, users);
2497 return Result.ok(users);
2499 return Result.err(rlcd);
2509 path = "/authn/certs/id/:id",
2510 params = {"id|string|true"},
2512 errorCodes = {403,404,406},
2513 text = { "Return Cert Info for ID"
2517 public Result<CERTS> getCertInfoByID(AuthzTrans trans, HttpServletRequest req, String id) {
2518 TimeTaken tt = trans.start("Get Cert Info by ID", Env.SUB);
2520 CERTS certs = mapper.newInstance(API.CERTS);
2521 Result<List<CertDAO.Data>> rlcd = ques.certDAO.readID(trans, id);
2524 if (!rlcd.isEmpty()) {
2525 return mapper.cert(rlcd.value, certs);
2527 return Result.ok(certs);
2529 return Result.err(rlcd);
2539 path = "/authn/cred",
2542 errorCodes = {300,403,404,406},
2543 text = { "Reset a Credential Password. If multiple credentials exist for this",
2544 "ID, you will need to specify which entry you are resetting in the",
2545 "CredRequest object"
2549 public Result<Void> changeUserCred(final AuthzTrans trans, REQUEST from) {
2550 final String cmdDescription = "Update User Credential";
2551 TimeTaken tt = trans.start(cmdDescription, Env.SUB);
2553 Result<CredDAO.Data> rcred = mapper.cred(trans, from, true);
2554 if (rcred.isOKhasData()) {
2555 rcred = ques.userCredSetup(trans, rcred.value);
2557 final ServiceValidator v = new ServiceValidator();
2559 if (v.cred(trans, trans.org(),rcred,false).err()) {// Note: Creates have stricter Validations
2560 return Result.err(Status.ERR_BadData,v.errs());
2562 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, rcred.value.id);
2563 if (rlcd.notOKorIsEmpty()) {
2564 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2567 MayChange mc = new MayChangeCred(trans, rcred.value);
2568 Result<?> rmc = mc.mayChange();
2570 return Result.err(rmc);
2573 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2575 return Result.err(ri);
2577 int entry = ri.value;
2580 final CredDAO.Data cred = rcred.value;
2582 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from, rcred.value,false,
2585 public String get() {
2586 return cmdDescription + " [" +
2589 + cred.expires + ']';
2594 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, rcred.value.ns);
2595 if (nsr.notOKorIsEmpty()) {
2596 return Result.err(nsr);
2601 Result<String> rfc = func.createFuture(trans, fd.value,
2602 rcred.value.id + '|' + rcred.value.type.toString() + '|' + rcred.value.expires,
2603 trans.user(), nsr.value.get(0), FUTURE_OP.U);
2605 return Result.err(Status.ACC_Future, "Credential Request [%s|%s|%s]",
2607 Integer.toString(rcred.value.type),
2608 rcred.value.expires.toString());
2610 return Result.err(rfc);
2612 case Status.ACC_Now:
2613 Result<?>udr = null;
2614 // If we are Resetting Password on behalf of someone else (am not the Admin)
2615 // use TempPassword Expiration time.
2617 if (ques.isAdmin(trans, trans.user(), nsr.value.get(0).name)) {
2618 exp = Expiration.Password;
2620 exp = Expiration.TempPassword;
2623 Organization org = trans.org();
2624 CredDAO.Data current = rlcd.value.get(entry);
2625 // If user resets password in same day, we will have a primary key conflict, so subtract 1 day
2626 if (current.expires.equals(rcred.value.expires)
2627 && rlcd.value.get(entry).type==rcred.value.type) {
2628 GregorianCalendar gc = org.expiration(null, exp,rcred.value.id);
2629 gc = Chrono.firstMomentOfDay(gc);
2630 gc.set(GregorianCalendar.HOUR_OF_DAY, org.startOfDay());
2631 rcred.value.expires = new Date(gc.getTimeInMillis() - DAY_IN_MILLIS);
2633 rcred.value.expires = org.expiration(null,exp).getTime();
2635 // Copy in other fields 10/21/2016
2636 rcred.value.notes=current.notes;
2638 udr = ques.credDAO.create(trans, rcred.value);
2640 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
2646 return Result.err(udr);
2648 return Result.err(fd);
2651 return Result.err(rcred);
2659 * Codify the way to get Either Choice Needed or actual Integer from Credit Request
2661 private Result<Integer> selectEntryIfMultiple(final CredRequest cr, List<CredDAO.Data> lcd) {
2663 if (lcd.size() > 1) {
2664 String inputOption = cr.getEntry();
2665 if (inputOption == null) {
2666 String message = selectCredFromList(lcd, false);
2667 Object[] variables = buildVariables(lcd);
2668 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2670 entry = Integer.parseInt(inputOption) - 1;
2672 if (entry < 0 || entry >= lcd.size()) {
2673 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2676 return Result.ok(entry);
2681 path = "/authn/cred/:days",
2682 params = {"days|string|true"},
2684 errorCodes = {300,403,404,406},
2685 text = { "Extend a Credential Expiration Date. The intention of this API is",
2686 "to avoid an outage in PROD due to a Credential expiring before it",
2687 "can be configured correctly. Measures are being put in place ",
2688 "so that this is not abused."
2692 public Result<Void> extendUserCred(final AuthzTrans trans, REQUEST from, String days) {
2693 TimeTaken tt = trans.start("Extend User Credential", Env.SUB);
2695 Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2696 Organization org = trans.org();
2697 final ServiceValidator v = new ServiceValidator();
2698 if (v.notOK(cred).err() ||
2699 v.nullOrBlank(cred.value.id, "Invalid ID").err() ||
2700 v.user(org,cred.value.id).err()) {
2701 return Result.err(Status.ERR_BadData,v.errs());
2706 if ((reason=org.validate(trans, Policy.MAY_EXTEND_CRED_EXPIRES, new CassExecutor(trans,func)))!=null) {
2707 return Result.err(Status.ERR_Policy,reason);
2709 } catch (Exception e) {
2711 trans.error().log(e, msg="Could not contact Organization for User Validation");
2712 return Result.err(Status.ERR_Denied, msg);
2715 // Get the list of Cred Entries
2716 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
2717 if (rlcd.notOKorIsEmpty()) {
2718 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2721 //Need to do the "Pick Entry" mechanism
2722 Result<Integer> ri = selectEntryIfMultiple((CredRequest)from, rlcd.value);
2724 return Result.err(ri);
2727 CredDAO.Data found = rlcd.value.get(ri.value);
2728 CredDAO.Data cd = cred.value;
2729 // Copy over the cred
2731 cd.cred = found.cred;
2732 cd.other = found.other;
2733 cd.type = found.type;
2734 cd.notes = found.notes;
2736 cd.expires = org.expiration(null, Expiration.ExtendPassword,days).getTime();
2738 cred = ques.credDAO.create(trans, cd);
2742 return Result.err(cred);
2748 private String[] buildVariables(List<CredDAO.Data> value) {
2749 // ensure credentials are sorted so we can fully automate Cred regression test
2750 Collections.sort(value, (cred1, cred2) -> cred1.expires.compareTo(cred2.expires));
2751 String [] vars = new String[value.size()+1];
2753 for (int i = 0; i < value.size(); i++) {
2754 vars[i+1] = value.get(i).id + " " + value.get(i).type
2755 + " |" + value.get(i).expires;
2760 private String selectCredFromList(List<CredDAO.Data> value, boolean isDelete) {
2761 StringBuilder errMessage = new StringBuilder();
2762 String userPrompt = isDelete?"Select which cred to delete (set force=true to delete all):":"Select which cred to update:";
2763 int numSpaces = value.get(0).id.length() - "Id".length();
2765 errMessage.append(userPrompt + '\n');
2766 errMessage.append(" Id");
2767 for (int i = 0; i < numSpaces; i++) {
2768 errMessage.append(' ');
2770 errMessage.append(" Type Expires" + '\n');
2771 for (int i=0;i<value.size();++i) {
2772 errMessage.append(" %s\n");
2774 errMessage.append("Run same command again with chosen entry as last parameter");
2776 return errMessage.toString();
2782 path = "/authn/cred",
2785 errorCodes = {300,403,404,406},
2786 text = { "Delete a Credential. If multiple credentials exist for this",
2787 "ID, you will need to specify which entry you are deleting in the",
2788 "CredRequest object."
2792 public Result<Void> deleteUserCred(AuthzTrans trans, REQUEST from) {
2793 final Result<CredDAO.Data> cred = mapper.cred(trans, from, false);
2794 final Validator v = new ServiceValidator();
2795 if (v.nullOrBlank("cred", cred.value.id).err()) {
2796 return Result.err(Status.ERR_BadData,v.errs());
2799 Result<List<CredDAO.Data>> rlcd = ques.credDAO.readID(trans, cred.value.id);
2800 if (rlcd.notOKorIsEmpty()) {
2801 // Empty Creds should have no user_roles.
2802 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
2804 for (UserRoleDAO.Data data : rlurd.value) {
2805 ques.userRoleDAO.delete(trans, data, false);
2808 return Result.err(Status.ERR_UserNotFound, "Credential does not exist");
2810 boolean isLastCred = rlcd.value.size()==1;
2812 MayChange mc = new MayChangeCred(trans,cred.value);
2813 Result<?> rmc = mc.mayChange();
2815 return Result.err(rmc);
2819 if (!trans.requested(force)) {
2820 if (rlcd.value.size() > 1) {
2821 CredRequest cr = (CredRequest)from;
2822 String inputOption = cr.getEntry();
2823 if (inputOption == null) {
2824 String message = selectCredFromList(rlcd.value, true);
2825 Object[] variables = buildVariables(rlcd.value);
2826 return Result.err(Status.ERR_ChoiceNeeded, message, variables);
2829 if (inputOption.length()>5) { // should be a date
2830 Date d = Chrono.xmlDatatypeFactory.newXMLGregorianCalendar(inputOption).toGregorianCalendar().getTime();
2832 for (CredDAO.Data cd : rlcd.value) {
2833 if (cd.type.equals(cr.getType()) && cd.expires.equals(d)) {
2839 entry = Integer.parseInt(inputOption) - 1;
2841 } catch (NullPointerException e) {
2842 return Result.err(Status.ERR_BadData, "Invalid Date Format for Entry");
2843 } catch (NumberFormatException e) {
2844 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2847 isLastCred = (entry==-1)?true:false;
2851 if (entry < -1 || entry >= rlcd.value.size()) {
2852 return Result.err(Status.ERR_BadData, "User chose invalid credential selection");
2856 Result<FutureDAO.Data> fd = mapper.future(trans,CredDAO.TABLE,from,cred.value,false,
2857 () -> "Delete Credential [" +
2862 Result<List<NsDAO.Data>> nsr = ques.nsDAO.read(trans, cred.value.ns);
2863 if (nsr.notOKorIsEmpty()) {
2864 return Result.err(nsr);
2869 Result<String> rfc = func.createFuture(trans, fd.value, cred.value.id,
2870 trans.user(), nsr.value.get(0), FUTURE_OP.D);
2873 return Result.err(Status.ACC_Future, "Credential Delete [%s] is saved for future processing",cred.value.id);
2875 return Result.err(rfc);
2877 case Status.ACC_Now:
2878 Result<?>udr = null;
2879 if (!trans.requested(force)) {
2880 if (entry<0 || entry >= rlcd.value.size()) {
2881 return Result.err(Status.ERR_BadData,"Invalid Choice [" + entry + "] chosen for Delete [%s] is saved for future processing",cred.value.id);
2883 udr = ques.credDAO.delete(trans, rlcd.value.get(entry),false);
2885 for (CredDAO.Data curr : rlcd.value) {
2886 udr = ques.credDAO.delete(trans, curr, false);
2888 return Result.err(udr);
2893 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, cred.value.id);
2895 for (UserRoleDAO.Data data : rlurd.value) {
2896 ques.userRoleDAO.delete(trans, data, false);
2901 return Result.err(Result.ERR_NotFound,"No User Data found");
2906 return Result.err(udr);
2908 return Result.err(fd);
2915 public Result<Date> doesCredentialMatch(AuthzTrans trans, REQUEST credReq) {
2916 TimeTaken tt = trans.start("Does Credential Match", Env.SUB);
2918 // Note: Mapper assigns RAW type
2919 Result<CredDAO.Data> data = mapper.cred(trans, credReq,false);
2920 if (data.notOKorIsEmpty()) {
2921 return Result.err(data);
2923 CredDAO.Data cred = data.value; // of the Mapped Cred
2924 if (cred.cred==null) {
2925 return Result.err(Result.ERR_BadData,"No Password");
2927 return ques.doesUserCredMatch(trans, cred.id, cred.cred.array());
2930 } catch (DAOException e) {
2931 trans.error().log(e,"Error looking up cred");
2932 return Result.err(Status.ERR_Denied,"Credential does not match");
2940 path = "/authn/basicAuth",
2943 errorCodes = { 403 },
2944 text = { "!!!! DEPRECATED without X509 Authentication STOP USING THIS API BY DECEMBER 2017, or use Certificates !!!!\n"
2945 + "Use /authn/validate instead\n"
2946 + "Note: Validate a Password using BasicAuth Base64 encoded Header. This HTTP/S call is intended as a fast"
2947 + " User/Password lookup for Security Frameworks, and responds 200 if it passes BasicAuth "
2948 + "security, and 403 if it does not." }
2950 private void basicAuth() {
2951 // This is a place holder for Documentation. The real BasicAuth API does not call Service.
2956 path = "/authn/validate",
2959 errorCodes = { 403 },
2960 text = { "Validate a Credential given a Credential Structure. This is a more comprehensive validation, can "
2961 + "do more than BasicAuth as Credential types exp" }
2964 public Result<Date> validateBasicAuth(AuthzTrans trans, String basicAuth) {
2965 //TODO how to make sure people don't use this in browsers? Do we care?
2966 TimeTaken tt = trans.start("Validate Basic Auth", Env.SUB);
2968 BasicPrincipal bp = new BasicPrincipal(basicAuth,trans.org().getRealm());
2969 Result<Date> rq = ques.doesUserCredMatch(trans, bp.getName(), bp.getCred());
2970 // Note: Only want to log problem, don't want to send back to end user
2974 trans.audit().log(rq.errorString());
2976 } catch (Exception e) {
2977 trans.warn().log(e);
2981 return Result.err(Status.ERR_Denied,"Bad Basic Auth");
2984 /***********************************
2986 ***********************************/
2989 path = "/authz/userRole",
2992 errorCodes = {403,404,406,409},
2993 text = { "Create a UserRole relationship (add User to Role)",
2994 "A UserRole is an object Representation of membership of a Role for limited time.",
2995 "If a shorter amount of time for Role ownership is required, use the 'End' field.",
2996 "** Note: Owners of Namespaces will be required to revalidate users in these roles ",
2997 "before Expirations expire. Namespace owners will be notified by email."
3001 public Result<Void> createUserRole(final AuthzTrans trans, REQUEST from) {
3002 TimeTaken tt = trans.start("Create UserRole", Env.SUB);
3004 Result<UserRoleDAO.Data> urr = mapper.userRole(trans, from);
3005 if (urr.notOKorIsEmpty()) {
3006 return Result.err(urr);
3008 final UserRoleDAO.Data userRole = urr.value;
3010 final ServiceValidator v = new ServiceValidator();
3011 if (v.user_role(userRole).err() ||
3012 v.user(trans.org(), userRole.user).err()) {
3013 return Result.err(Status.ERR_BadData,v.errs());
3018 // Check if user can change first
3019 Result<FutureDAO.Data> fd = mapper.future(trans,UserRoleDAO.TABLE,from,urr.value,true, // may request Approvals
3020 () -> "Add User [" + userRole.user + "] to Role [" +
3024 private Result<NsDAO.Data> nsd;
3026 public Result<?> mayChange() {
3028 RoleDAO.Data r = RoleDAO.Data.decode(userRole);
3029 nsd = ques.mayUser(trans, trans.user(), r, Access.write);
3034 Result<NsDAO.Data> nsr = ques.deriveNs(trans, userRole.role);
3035 if (nsr.notOKorIsEmpty()) {
3036 return Result.err(nsr);
3041 Result<String> rfc = func.createFuture(trans, fd.value, userRole.user+'|'+userRole.ns + '.' + userRole.rname,
3042 userRole.user, nsr.value, FUTURE_OP.C);
3044 return Result.err(Status.ACC_Future, "UserRole [%s - %s.%s] is saved for future processing",
3049 return Result.err(rfc);
3051 case Status.ACC_Now:
3052 return func.addUserRole(trans, userRole);
3054 return Result.err(fd);
3062 * getUserRolesByRole
3066 path = "/authz/userRoles/role/:role",
3067 params = {"role|string|true"},
3069 errorCodes = {404,406},
3070 text = { "List all Users that are attached to Role specified in :role",
3074 public Result<USERROLES> getUserRolesByRole(AuthzTrans trans, String role) {
3075 final Validator v = new ServiceValidator();
3076 if (v.nullOrBlank("Role",role).err()) {
3077 return Result.err(Status.ERR_BadData,v.errs());
3080 Result<RoleDAO.Data> rrdd;
3081 rrdd = RoleDAO.Data.decode(trans,ques,role);
3083 return Result.err(rrdd);
3085 // May Requester see result?
3086 Result<NsDAO.Data> ns = ques.mayUser(trans,trans.user(), rrdd.value,Access.read);
3088 return Result.err(ns);
3091 // boolean filter = true;
3092 // if (ns.value.isAdmin(trans.user()) || ns.value.isResponsible(trans.user()))
3095 // Get list of roles per user, then add to Roles as we go
3096 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3097 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
3099 for (UserRoleDAO.Data data : rlurd.value) {
3104 @SuppressWarnings("unchecked")
3105 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3106 // Checked for permission
3107 mapper.userRoles(trans, userSet, users);
3108 return Result.ok(users);
3111 * getUserRolesByRole
3115 path = "/authz/userRoles/user/:user",
3116 params = {"role|string|true"},
3118 errorCodes = {404,406},
3119 text = { "List all UserRoles for :user",
3123 public Result<USERROLES> getUserRolesByUser(AuthzTrans trans, String user) {
3124 final Validator v = new ServiceValidator();
3125 if (v.nullOrBlank("User",user).err()) {
3126 return Result.err(Status.ERR_BadData,v.errs());
3129 // Get list of roles per user, then add to Roles as we go
3130 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, user);
3131 if (rlurd.notOK()) {
3132 return Result.err(rlurd);
3137 * 2) is User's Supervisor
3138 * 3) Has special global access =read permission
3140 * If none of the 3, then filter results to NSs in which Calling User has Ns.access * read
3143 String callingUser = trans.getUserPrincipal().getName();
3144 NsDAO.Data ndd = new NsDAO.Data();
3146 if (user.equals(callingUser)) {
3149 Organization org = trans.org();
3151 Identity orgID = org.getIdentity(trans, user);
3152 Identity manager = orgID==null?null:orgID.responsibleTo();
3153 if (orgID!=null && (manager!=null && callingUser.equals(manager.fullID()))) {
3155 } else if (ques.isGranted(trans, callingUser, ROOT_NS, Question.ACCESS, "*", Access.read.name())) {
3160 } catch (OrganizationException e) {
3166 List<UserRoleDAO.Data> content;
3168 content = new ArrayList<>(rlurd.value.size()); // avoid multi-memory redos
3170 for (UserRoleDAO.Data data : rlurd.value) {
3172 Result<Data> mur = ques.mayUser(trans, callingUser, ndd, Access.read);
3179 content = rlurd.value;
3183 @SuppressWarnings("unchecked")
3184 USERROLES users = (USERROLES) mapper.newInstance(API.USER_ROLES);
3185 // Checked for permission
3186 mapper.userRoles(trans, content, users);
3187 return Result.ok(users);
3193 path = "/authz/userRole/user",
3196 errorCodes = {403,404,406},
3197 text = { "Set a User's roles to the roles specified in the UserRoleRequest object.",
3198 "WARNING: Roles supplied will be the ONLY roles attached to this user",
3199 "If no roles are supplied, user's roles are reset."
3203 public Result<Void> resetRolesForUser(AuthzTrans trans, REQUEST rreq) {
3204 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
3205 final ServiceValidator v = new ServiceValidator();
3206 if (rurdd.notOKorIsEmpty()) {
3207 return Result.err(rurdd);
3209 if (v.user(trans.org(), rurdd.value.user).err()) {
3210 return Result.err(Status.ERR_BadData,v.errs());
3213 Set<String> currRoles = new HashSet<>();
3214 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByUser(trans, rurdd.value.user);
3216 for (UserRoleDAO.Data data : rlurd.value) {
3217 currRoles.add(data.role);
3221 Result<Void> rv = null;
3223 if (rurdd.value.role==null) {
3224 roles = new String[0];
3226 roles = rurdd.value.role.split(",");
3229 for (String role : roles) {
3230 if (v.role(role).err()) {
3231 return Result.err(Status.ERR_BadData,v.errs());
3233 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3235 return Result.err(rrdd);
3238 rurdd.value.role(rrdd.value);
3240 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rrdd.value,Access.write);
3242 return Result.err(nsd);
3244 Result<NsDAO.Data> nsr = ques.deriveNs(trans, role);
3245 if (nsr.notOKorIsEmpty()) {
3246 return Result.err(nsr);
3249 if (currRoles.contains(role)) {
3250 currRoles.remove(role);
3252 rv = func.addUserRole(trans, rurdd.value);
3259 for (String role : currRoles) {
3260 rurdd.value.role(trans,ques,role);
3261 rv = ques.userRoleDAO.delete(trans, rurdd.value, false);
3263 trans.info().log(rurdd.value.user,"/",rurdd.value.role, "expected to be deleted, but does not exist");
3264 // return rv; // if it doesn't exist, don't error out
3275 path = "/authz/userRole/role",
3278 errorCodes = {403,404,406},
3279 text = { "Set a Role's users to the users specified in the UserRoleRequest object.",
3280 "WARNING: Users supplied will be the ONLY users attached to this role",
3281 "If no users are supplied, role's users are reset."
3285 public Result<Void> resetUsersForRole(AuthzTrans trans, REQUEST rreq) {
3286 Result<UserRoleDAO.Data> rurdd = mapper.userRole(trans, rreq);
3287 if (rurdd.notOKorIsEmpty()) {
3288 return Result.err(rurdd);
3290 final ServiceValidator v = new ServiceValidator();
3291 if (v.user_role(rurdd.value).err()) {
3292 return Result.err(Status.ERR_BadData,v.errs());
3295 RoleDAO.Data rd = RoleDAO.Data.decode(rurdd.value);
3297 Result<NsDAO.Data> nsd = ques.mayUser(trans, trans.user(), rd, Access.write);
3299 return Result.err(nsd);
3302 Result<NsDAO.Data> nsr = ques.deriveNs(trans, rurdd.value.role);
3303 if (nsr.notOKorIsEmpty()) {
3304 return Result.err(nsr);
3307 Set<String> currUsers = new HashSet<>();
3308 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, rurdd.value.role);
3310 for (UserRoleDAO.Data data : rlurd.value) {
3311 currUsers.add(data.user);
3315 // found when connected remotely to DEVL, can't replicate locally
3316 // inconsistent errors with cmd: role user setTo [nothing]
3317 // deleteUserRole --> read --> get --> cacheIdx(?)
3318 // sometimes returns idx for last added user instead of user passed in
3322 Result<Void> rv = null;
3323 String[] users = {};
3324 if (rurdd.value.user != null) {
3325 users = rurdd.value.user.split(",");
3328 for (String user : users) {
3329 if (v.user(trans.org(), user).err()) {
3330 return Result.err(Status.ERR_BadData,v.errs());
3332 rurdd.value.user = user;
3334 if (currUsers.contains(user)) {
3335 currUsers.remove(user);
3337 rv = func.addUserRole(trans, rurdd.value);
3344 for (String user : currUsers) {
3345 rurdd.value.user = user;
3346 rv = ques.userRoleDAO.delete(trans, rurdd.value, false);
3348 trans.info().log(rurdd.value, "expected to be deleted, but not exists");
3358 path = "/authz/userRole/extend/:user/:role",
3359 params = { "user|string|true",
3363 errorCodes = {403,404,406},
3364 text = { "Extend the Expiration of this User Role by the amount set by Organization",
3365 "Requestor must be allowed to modify the role"
3369 public Result<Void> extendUserRole(AuthzTrans trans, String user, String role) {
3370 Organization org = trans.org();
3371 final ServiceValidator v = new ServiceValidator();
3372 if (v.user(org, user)
3375 return Result.err(Status.ERR_BadData,v.errs());
3378 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3380 return Result.err(rrdd);
3383 Result<NsDAO.Data> rcr = ques.mayUser(trans, trans.user(), rrdd.value, Access.write);
3384 boolean mayNotChange;
3385 if ((mayNotChange = rcr.notOK()) && !trans.requested(future)) {
3386 return Result.err(rcr);
3389 Result<List<UserRoleDAO.Data>> rr = ques.userRoleDAO.read(trans, user,role);
3391 return Result.err(rr);
3393 for (UserRoleDAO.Data userRole : rr.value) {
3394 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3395 FutureDAO.Data fto = new FutureDAO.Data();
3396 fto.target=UserRoleDAO.TABLE;
3397 fto.memo = "Extend User ["+userRole.user+"] in Role ["+userRole.role+"]";
3398 GregorianCalendar now = new GregorianCalendar();
3399 fto.start = now.getTime();
3400 fto.expires = org.expiration(now, Expiration.Future).getTime();
3402 fto.construct = userRole.bytify();
3403 } catch (IOException e) {
3404 trans.error().log(e, "Error while bytifying UserRole for Future");
3405 return Result.err(e);
3408 Result<String> rfc = func.createFuture(trans, fto,
3409 userRole.user+'|'+userRole.role, userRole.user, rcr.value, FUTURE_OP.U);
3411 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3415 return Result.err(rfc);
3418 return func.extendUserRole(trans, userRole, false);
3421 return Result.err(Result.ERR_NotFound,"This user and role doesn't exist");
3426 path = "/authz/userRole/:user/:role",
3427 params = { "user|string|true",
3431 errorCodes = {403,404,406},
3432 text = { "Remove Role :role from User :user."
3436 public Result<Void> deleteUserRole(AuthzTrans trans, String usr, String role) {
3437 Validator val = new ServiceValidator();
3438 if (val.nullOrBlank("User", usr)
3439 .nullOrBlank("Role", role).err()) {
3440 return Result.err(Status.ERR_BadData, val.errs());
3443 boolean mayNotChange;
3444 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans,ques,role);
3446 return Result.err(rrdd);
3449 RoleDAO.Data rdd = rrdd.value;
3450 Result<NsDAO.Data> rns = ques.mayUser(trans, trans.user(), rdd, Access.write);
3452 // Make sure we don't delete the last owner of valid NS
3453 if (rns.isOKhasData() && Question.OWNER.equals(rdd.name) && ques.countOwner(trans,rdd.ns)<=1) {
3454 return Result.err(Status.ERR_Denied,"You may not delete the last Owner of " + rdd.ns );
3457 if (mayNotChange=rns.notOK()) {
3458 if (!trans.requested(future)) {
3459 return Result.err(rns);
3463 Result<List<UserRoleDAO.Data>> rulr;
3464 if ((rulr=ques.userRoleDAO.read(trans, usr, role)).notOKorIsEmpty()) {
3465 return Result.err(Status.ERR_UserRoleNotFound, "User [ "+usr+" ] is not "
3466 + "Assigned to the Role [ " + role + " ]");
3469 UserRoleDAO.Data userRole = rulr.value.get(0);
3470 if (mayNotChange) { // Function exited earlier if !trans.futureRequested
3471 FutureDAO.Data fto = new FutureDAO.Data();
3472 fto.target=UserRoleDAO.TABLE;
3473 fto.memo = "Remove User ["+userRole.user+"] from Role ["+userRole.role+"]";
3474 GregorianCalendar now = new GregorianCalendar();
3475 fto.start = now.getTime();
3476 fto.expires = trans.org().expiration(now, Expiration.Future).getTime();
3478 Result<String> rfc = func.createFuture(trans, fto,
3479 userRole.user+'|'+userRole.role, userRole.user, rns.value, FUTURE_OP.D);
3481 return Result.err(Status.ACC_Future, "UserRole [%s - %s] is saved for future processing",
3485 return Result.err(rfc);
3488 return ques.userRoleDAO.delete(trans, rulr.value.get(0), false);
3494 path = "/authz/userRole/:user/:role",
3495 params = {"user|string|true",
3496 "role|string|true"},
3498 errorCodes = {403,404,406},
3499 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3503 public Result<USERS> getUserInRole(AuthzTrans trans, String user, String role) {
3504 final Validator v = new ServiceValidator();
3505 if (v.role(role).nullOrBlank("User", user).err()) {
3506 return Result.err(Status.ERR_BadData,v.errs());
3509 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3510 // if (ns.notOK()) return Result.err(ns);
3512 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3513 // May calling user see by virtue of the Role
3514 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3516 return Result.err(rrdd);
3518 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3520 return Result.err(rnd);
3523 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3524 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readUserInRole(trans, user, role);
3526 for (UserRoleDAO.Data data : rlurd.value) {
3531 @SuppressWarnings("unchecked")
3532 USERS users = (USERS) mapper.newInstance(API.USERS);
3533 mapper.users(trans, userSet, users);
3534 return Result.ok(users);
3539 path = "/authz/users/role/:role",
3540 params = {"user|string|true",
3541 "role|string|true"},
3543 errorCodes = {403,404,406},
3544 text = { "Returns the User (with Expiration date from listed User/Role) if it exists"
3548 public Result<USERS> getUsersByRole(AuthzTrans trans, String role) {
3549 final Validator v = new ServiceValidator();
3550 if (v.nullOrBlank("Role",role).err()) {
3551 return Result.err(Status.ERR_BadData,v.errs());
3554 // Result<NsDAO.Data> ns = ques.deriveNs(trans, role);
3555 // if (ns.notOK()) return Result.err(ns);
3557 // Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), ns.value, Access.write);
3558 // May calling user see by virtue of the Role
3559 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3561 return Result.err(rrdd);
3564 boolean contactOnly = false;
3565 // Allow the request of any valid user to find the contact of the NS (Owner)
3566 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value,Access.read);
3568 if (Question.OWNER.equals(rrdd.value.name)) {
3571 return Result.err(rnd);
3575 HashSet<UserRoleDAO.Data> userSet = new HashSet<>();
3576 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role);
3578 for (UserRoleDAO.Data data : rlurd.value) {
3579 if (contactOnly) { //scrub data
3580 // Can't change actual object, or will mess up the cache.
3581 UserRoleDAO.Data scrub = new UserRoleDAO.Data();
3583 scrub.rname = data.rname;
3584 scrub.role = data.role;
3585 scrub.user = data.user;
3593 @SuppressWarnings("unchecked")
3594 USERS users = (USERS) mapper.newInstance(API.USERS);
3595 mapper.users(trans, userSet, users);
3596 return Result.ok(users);
3600 * getUsersByPermission
3604 path = "/authz/users/perm/:type/:instance/:action",
3605 params = { "type|string|true",
3606 "instance|string|true",
3607 "action|string|true"
3610 errorCodes = {404,406},
3611 text = { "List all Users that have Permission specified by :type :instance :action",
3615 public Result<USERS> getUsersByPermission(AuthzTrans trans, String type, String instance, String action) {
3616 final Validator v = new ServiceValidator();
3617 if (v.nullOrBlank("Type",type)
3618 .nullOrBlank("Instance",instance)
3619 .nullOrBlank("Action",action)
3621 return Result.err(Status.ERR_BadData,v.errs());
3624 Result<NsSplit> nss = ques.deriveNsSplit(trans, type);
3626 return Result.err(nss);
3629 Result<List<NsDAO.Data>> nsd = ques.nsDAO.read(trans, nss.value.ns);
3631 return Result.err(nsd);
3634 boolean allInstance = ASTERIX.equals(instance);
3635 boolean allAction = ASTERIX.equals(action);
3636 // Get list of roles per Permission,
3637 // Then loop through Roles to get Users
3638 // Note: Use Sets to avoid processing or responding with Duplicates
3639 Set<String> roleUsed = new HashSet<>();
3640 Set<UserRoleDAO.Data> userSet = new HashSet<>();
3642 if (!nss.isEmpty()) {
3643 Result<List<PermDAO.Data>> rlp = ques.permDAO.readByType(trans, nss.value.ns, nss.value.name);
3644 if (rlp.isOKhasData()) {
3645 for (PermDAO.Data pd : rlp.value) {
3646 if ((allInstance || pd.instance.equals(instance)) &&
3647 (allAction || pd.action.equals(action))) {
3648 if (ques.mayUser(trans, trans.user(),pd,Access.read).isOK()) {
3649 for (String role : pd.roles) {
3650 if (!roleUsed.contains(role)) { // avoid evaluating Role many times
3652 Result<List<UserRoleDAO.Data>> rlurd = ques.userRoleDAO.readByRole(trans, role.replace('|', '.'));
3653 if (rlurd.isOKhasData()) {
3654 for (UserRoleDAO.Data urd : rlurd.value) {
3665 @SuppressWarnings("unchecked")
3666 USERS users = (USERS) mapper.newInstance(API.USERS);
3667 mapper.users(trans, userSet, users);
3668 return Result.ok(users);
3671 /***********************************
3673 ***********************************/
3675 public Result<HISTORY> getHistoryByUser(final AuthzTrans trans, String user, final int[] yyyymm, final int sort) {
3676 final Validator v = new ServiceValidator();
3677 if (v.nullOrBlank("User",user).err()) {
3678 return Result.err(Status.ERR_BadData,v.errs());
3681 Result<NsDAO.Data> rnd;
3682 // Users may look at their own data
3683 if (trans.user().equals(user)) {
3684 // Users may look at their own data
3686 int at = user.indexOf('@');
3687 if (at>=0 && trans.org().getRealm().equals(user.substring(at+1))) {
3688 NsDAO.Data nsd = new NsDAO.Data();
3689 nsd.name = Question.domain2ns(user);
3690 rnd = ques.mayUser(trans, trans.user(), nsd, Access.read);
3692 return Result.err(rnd);
3695 rnd = ques.validNSOfDomain(trans, user);
3697 return Result.err(rnd);
3700 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3702 return Result.err(rnd);
3706 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readByUser(trans, user, yyyymm);
3708 return Result.err(resp);
3710 return mapper.history(trans, resp.value,sort);
3714 public Result<HISTORY> getHistoryByRole(AuthzTrans trans, String role, int[] yyyymm, final int sort) {
3715 final Validator v = new ServiceValidator();
3716 if (v.nullOrBlank("Role",role).err()) {
3717 return Result.err(Status.ERR_BadData,v.errs());
3720 Result<RoleDAO.Data> rrdd = RoleDAO.Data.decode(trans, ques, role);
3722 return Result.err(rrdd);
3725 Result<NsDAO.Data> rnd = ques.mayUser(trans, trans.user(), rrdd.value, Access.read);
3727 return Result.err(rnd);
3729 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, role, "role", yyyymm);
3731 return Result.err(resp);
3733 return mapper.history(trans, resp.value,sort);
3737 public Result<HISTORY> getHistoryByPerm(AuthzTrans trans, String type, int[] yyyymm, final int sort) {
3738 final Validator v = new ServiceValidator();
3739 if (v.nullOrBlank("Type",type)
3741 return Result.err(Status.ERR_BadData,v.errs());
3744 // May user see Namespace of Permission (since it's only one piece... we can't check for "is permission part of")
3745 Result<NsDAO.Data> rnd = ques.deriveNs(trans,type);
3747 return Result.err(rnd);
3750 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3752 return Result.err(rnd);
3754 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, type, "perm", yyyymm);
3756 return Result.err(resp);
3758 return mapper.history(trans, resp.value,sort);
3762 public Result<HISTORY> getHistoryByNS(AuthzTrans trans, String ns, int[] yyyymm, final int sort) {
3763 final Validator v = new ServiceValidator();
3764 if (v.nullOrBlank("NS",ns)
3766 return Result.err(Status.ERR_BadData,v.errs());
3769 Result<NsDAO.Data> rnd = ques.deriveNs(trans,ns);
3771 return Result.err(rnd);
3773 rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read);
3775 return Result.err(rnd);
3778 Result<List<HistoryDAO.Data>> resp = ques.historyDAO.readBySubject(trans, ns, "ns", yyyymm);
3780 return Result.err(resp);
3782 return mapper.history(trans, resp.value,sort);
3785 /***********************************
3787 ***********************************/
3789 public Result<Void> createDelegate(final AuthzTrans trans, REQUEST base) {
3790 return createOrUpdateDelegate(trans, base, Question.Access.create);
3794 public Result<Void> updateDelegate(AuthzTrans trans, REQUEST base) {
3795 return createOrUpdateDelegate(trans, base, Question.Access.write);
3799 private Result<Void> createOrUpdateDelegate(final AuthzTrans trans, REQUEST base, final Access access) {
3800 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3801 final ServiceValidator v = new ServiceValidator();
3802 if (v.delegate(trans.org(),rd).err()) {
3803 return Result.err(Status.ERR_BadData,v.errs());
3806 final DelegateDAO.Data dd = rd.value;
3808 Result<List<DelegateDAO.Data>> ddr = ques.delegateDAO.read(trans, dd);
3809 if (access==Access.create && ddr.isOKhasData()) {
3810 return Result.err(Status.ERR_ConflictAlreadyExists, "[%s] already delegates to [%s]", dd.user, ddr.value.get(0).delegate);
3811 } else if (access!=Access.create && ddr.notOKorIsEmpty()) {
3812 return Result.err(Status.ERR_NotFound, "[%s] does not have a Delegate Record to [%s].",dd.user,access.name());
3814 Result<Void> rv = ques.mayUser(trans, dd, access);
3819 Result<FutureDAO.Data> fd = mapper.future(trans,DelegateDAO.TABLE,base, dd, false,
3821 StringBuilder sb = new StringBuilder();
3822 sb.append(access.name());
3823 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
3824 sb.append("Delegate ");
3825 sb.append(access==Access.create?"[":"to [");
3826 sb.append(rd.value.delegate);
3827 sb.append("] for [");
3828 sb.append(rd.value.user);
3830 return sb.toString();
3833 return Result.ok(); // Validate in code above
3838 Result<String> rfc = func.createFuture(trans, fd.value,
3839 dd.user, trans.user(),null, access==Access.create?FUTURE_OP.C:FUTURE_OP.U);
3841 return Result.err(Status.ACC_Future, "Delegate for [%s]",
3844 return Result.err(rfc);
3846 case Status.ACC_Now:
3847 if (access==Access.create) {
3848 Result<DelegateDAO.Data> rdr = ques.delegateDAO.create(trans, dd);
3852 return Result.err(rdr);
3855 return ques.delegateDAO.update(trans, dd);
3858 return Result.err(fd);
3863 public Result<Void> deleteDelegate(AuthzTrans trans, REQUEST base) {
3864 final Result<DelegateDAO.Data> rd = mapper.delegate(trans, base);
3865 final Validator v = new ServiceValidator();
3866 if (v.notOK(rd).nullOrBlank("User", rd.value.user).err()) {
3867 return Result.err(Status.ERR_BadData,v.errs());
3870 Result<List<DelegateDAO.Data>> ddl;
3871 if ((ddl=ques.delegateDAO.read(trans, rd.value)).notOKorIsEmpty()) {
3872 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3874 final DelegateDAO.Data dd = ddl.value.get(0);
3875 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3880 return ques.delegateDAO.delete(trans, dd, false);
3884 public Result<Void> deleteDelegate(AuthzTrans trans, String userName) {
3885 DelegateDAO.Data dd = new DelegateDAO.Data();
3886 final Validator v = new ServiceValidator();
3887 if (v.nullOrBlank("User", userName).err()) {
3888 return Result.err(Status.ERR_BadData,v.errs());
3891 Result<List<DelegateDAO.Data>> ddl;
3892 if ((ddl=ques.delegateDAO.read(trans, dd)).notOKorIsEmpty()) {
3893 return Result.err(Status.ERR_DelegateNotFound,"Cannot delete non-existent Delegate");
3895 dd = ddl.value.get(0);
3896 Result<Void> rv = ques.mayUser(trans, dd, Access.write);
3901 return ques.delegateDAO.delete(trans, dd, false);
3905 public Result<DELGS> getDelegatesByUser(AuthzTrans trans, String user) {
3906 final Validator v = new ServiceValidator();
3907 if (v.nullOrBlank("User", user).err()) {
3908 return Result.err(Status.ERR_BadData,v.errs());
3911 DelegateDAO.Data ddd = new DelegateDAO.Data();
3913 ddd.delegate = null;
3914 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3916 return Result.err(rv);
3919 TimeTaken tt = trans.start("Get delegates for a user", Env.SUB);
3921 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.read(trans, user);
3923 if (dbDelgs.isOKhasData()) {
3924 return mapper.delegate(dbDelgs.value);
3926 return Result.err(Status.ERR_DelegateNotFound,"No Delegate found for [%s]",user);
3934 public Result<DELGS> getDelegatesByDelegate(AuthzTrans trans, String delegate) {
3935 final Validator v = new ServiceValidator();
3936 if (v.nullOrBlank("Delegate", delegate).err()) {
3937 return Result.err(Status.ERR_BadData,v.errs());
3940 DelegateDAO.Data ddd = new DelegateDAO.Data();
3941 ddd.user = delegate;
3942 Result<Void> rv = ques.mayUser(trans, ddd, Access.read);
3944 return Result.err(rv);
3947 TimeTaken tt = trans.start("Get users for a delegate", Env.SUB);
3949 Result<List<DelegateDAO.Data>> dbDelgs = ques.delegateDAO.readByDelegate(trans, delegate);
3951 if (dbDelgs.isOKhasData()) {
3952 return mapper.delegate(dbDelgs.value);
3954 return Result.err(Status.ERR_DelegateNotFound,"Delegate [%s] is not delegating for anyone.",delegate);
3961 /***********************************
3963 ***********************************/
3964 private static final String APPR_FMT = "actor=%s, action=%s, operation=\"%s\", requestor=%s, delegator=%s";
3966 public Result<Void> updateApproval(AuthzTrans trans, APPROVALS approvals) {
3967 Result<List<ApprovalDAO.Data>> rlad = mapper.approvals(approvals);
3969 return Result.err(rlad);
3971 int numApprs = rlad.value.size();
3973 return Result.err(Status.ERR_NoApprovals,"No Approvals sent for Updating");
3975 int numProcessed = 0;
3976 String user = trans.user();
3978 Result<List<ApprovalDAO.Data>> curr;
3979 Lookup<List<ApprovalDAO.Data>> apprByTicket=null;
3980 for (ApprovalDAO.Data updt : rlad.value) {
3981 if (updt.ticket!=null) {
3982 curr = ques.approvalDAO.readByTicket(trans, updt.ticket);
3983 if (curr.isOKhasData()) {
3984 final List<ApprovalDAO.Data> add = curr.value;
3985 // Store a Pre-Lookup
3986 apprByTicket = (trans1, noop) -> add;
3988 } else if (updt.id!=null) {
3989 curr = ques.approvalDAO.read(trans, updt);
3990 } else if (updt.approver!=null) {
3991 curr = ques.approvalDAO.readByApprover(trans, updt.approver);
3993 return Result.err(Status.ERR_BadData,"Approvals need ID, Ticket or Approval data to update");
3996 if (curr.isOKhasData()) {
3997 Map<String, Result<List<DelegateDAO.Data>>> delegateCache = new HashMap<>();
3998 Map<UUID, FutureDAO.Data> futureCache = new HashMap<>();
3999 FutureDAO.Data hasDeleted = new FutureDAO.Data();
4001 for (ApprovalDAO.Data cd : curr.value) {
4002 if ("pending".equals(cd.status)) {
4003 // Check for right record. Need ID, or (Ticket&Trans.User==Appr)
4005 boolean delegatedAction = ques.isDelegated(trans, user, cd.approver, delegateCache);
4006 String delegator = cd.approver;
4007 if (updt.id!=null ||
4008 (updt.ticket!=null && user.equals(cd.approver)) ||
4009 (updt.ticket!=null && delegatedAction)) {
4010 if (updt.ticket.equals(cd.ticket)) {
4011 Changed ch = new Changed();
4012 cd.id = ch.changed(cd.id,updt.id);
4013 // cd.ticket = changed(cd.ticket,updt.ticket);
4014 cd.user = ch.changed(cd.user,updt.user);
4015 cd.approver = ch.changed(cd.approver,updt.approver);
4016 cd.type = ch.changed(cd.type,updt.type);
4017 cd.status = ch.changed(cd.status,updt.status);
4018 cd.memo = ch.changed(cd.memo,updt.memo);
4019 cd.operation = ch.changed(cd.operation,updt.operation);
4020 cd.updated = ch.changed(cd.updated,updt.updated==null?new Date():updt.updated);
4021 if (updt.status.equals("denied")) {
4022 cd.last_notified = null;
4024 if (cd.ticket!=null) {
4025 FutureDAO.Data fdd = futureCache.get(cd.ticket);
4026 if (fdd==null) { // haven't processed ticket yet
4027 Result<FutureDAO.Data> rfdd = ques.futureDAO.readPrimKey(trans, cd.ticket);
4029 fdd = rfdd.value; // null is ok
4033 futureCache.put(cd.ticket, fdd); // processed this Ticket... don't do others on this ticket
4035 if (fdd==hasDeleted) { // YES, by Object
4037 cd.status = "ticketDeleted";
4038 ch.hasChanged(true);
4040 FUTURE_OP fop = FUTURE_OP.toFO(cd.operation);
4042 trans.info().printf("Approval Status %s is not actionable",cd.status);
4043 } else if (apprByTicket!=null) {
4044 Result<OP_STATUS> rv = func.performFutureOp(trans, fop, fdd, apprByTicket,func.urDBLookup);
4048 if (delegatedAction) {
4049 trans.audit().printf(APPR_FMT,user,updt.status,cd.memo,cd.user,delegator);
4051 futureCache.put(cd.ticket, hasDeleted);
4055 ch.hasChanged(true);
4056 trans.audit().printf(APPR_FMT,user,rv.value.desc(),cd.memo,cd.user,delegator);
4057 futureCache.put(cd.ticket, hasDeleted);
4062 trans.info().log(rv.toString());
4069 if (ch.hasChanged()) {
4070 ques.approvalDAO.update(trans, cd, true);
4079 if (numApprs==numProcessed) {
4082 return Result.err(Status.ERR_ActionNotCompleted,numProcessed + " out of " + numApprs + " completed");
4086 private static class Changed {
4087 private boolean hasChanged = false;
4089 public<T> T changed(T src, T proposed) {
4090 if (proposed==null || (src!=null && src.equals(proposed))) {
4097 public void hasChanged(boolean b) {
4101 public boolean hasChanged() {
4107 public Result<APPROVALS> getApprovalsByUser(AuthzTrans trans, String user) {
4108 final Validator v = new ServiceValidator();
4109 if (v.nullOrBlank("User", user).err()) {
4110 return Result.err(Status.ERR_BadData,v.errs());
4113 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByUser(trans, user);
4115 return mapper.approvals(rapd.value);
4117 return Result.err(rapd);
4122 public Result<APPROVALS> getApprovalsByTicket(AuthzTrans trans, String ticket) {
4123 final Validator v = new ServiceValidator();
4124 if (v.nullOrBlank("Ticket", ticket).err()) {
4125 return Result.err(Status.ERR_BadData,v.errs());
4129 uuid = UUID.fromString(ticket);
4130 } catch (IllegalArgumentException e) {
4131 return Result.err(Status.ERR_BadData,e.getMessage());
4134 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByTicket(trans, uuid);
4136 return mapper.approvals(rapd.value);
4138 return Result.err(rapd);
4143 public Result<APPROVALS> getApprovalsByApprover(AuthzTrans trans, String approver) {
4144 final Validator v = new ServiceValidator();
4145 if (v.nullOrBlank("Approver", approver).err()) {
4146 return Result.err(Status.ERR_BadData,v.errs());
4149 List<ApprovalDAO.Data> listRapds = new ArrayList<>();
4151 Result<List<ApprovalDAO.Data>> myRapd = ques.approvalDAO.readByApprover(trans, approver);
4152 if (myRapd.notOK()) {
4153 return Result.err(myRapd);
4156 listRapds.addAll(myRapd.value);
4158 Result<List<DelegateDAO.Data>> delegatedFor = ques.delegateDAO.readByDelegate(trans, approver);
4159 if (delegatedFor.isOK()) {
4160 for (DelegateDAO.Data dd : delegatedFor.value) {
4161 if (dd.expires.after(new Date())) {
4162 String delegator = dd.user;
4163 Result<List<ApprovalDAO.Data>> rapd = ques.approvalDAO.readByApprover(trans, delegator);
4165 for (ApprovalDAO.Data d : rapd.value) {
4166 if (!d.user.equals(trans.user())) {
4175 return mapper.approvals(listRapds);
4179 * @see org.onap.aaf.auth.service.AuthzService#clearCache(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String)
4182 public Result<Void> cacheClear(AuthzTrans trans, String cname) {
4183 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4184 return ques.clearCache(trans,cname);
4186 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4187 trans.user(),ROOT_NS,CACHE,cname);
4191 * @see org.onap.aaf.auth.service.AuthzService#cacheClear(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.Integer)
4194 public Result<Void> cacheClear(AuthzTrans trans, String cname, int[] segment) {
4195 if (ques.isGranted(trans,trans.user(),ROOT_NS,CACHE,cname,"clear")) {
4196 Result<Void> v=null;
4197 for (int i: segment) {
4198 v=ques.cacheClear(trans,cname,i);
4204 return Result.err(Status.ERR_Denied, "%s does not have AAF Permission '%s.%s|%s|clear",
4205 trans.user(),ROOT_NS,CACHE,cname);
4209 * @see org.onap.aaf.auth.service.AuthzService#dbReset(org.onap.aaf.auth.env.test.AuthzTrans)
4212 public void dbReset(AuthzTrans trans) {
4213 ques.historyDAO.reportPerhapsReset(trans, null);